1 /*
2   Linux DNS client library implementation
3   Copyright (C) 2006 Gerald Carter <jerry@samba.org>
4 
5      ** NOTE! The following LGPL license applies to the libaddns
6      ** library. This does NOT imply that all of Samba is released
7      ** under the LGPL
8 
9   This library is free software; you can redistribute it and/or
10   modify it under the terms of the GNU Lesser General Public
11   License as published by the Free Software Foundation; either
12   version 2.1 of the License, or (at your option) any later version.
13 
14   This library is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17   Lesser General Public License for more details.
18 
19   You should have received a copy of the GNU Lesser General Public
20   License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 */
22 
23 #include "dns.h"
24 #include "assert.h"
25 
dns_create_buffer(TALLOC_CTX * mem_ctx)26 struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx)
27 {
28 	struct dns_buffer *result;
29 
30 	if (!(result = talloc_zero(mem_ctx, struct dns_buffer))) {
31 		return NULL;
32 	}
33 
34 	result->offset = 0;
35 	result->error = ERROR_DNS_SUCCESS;
36 
37 	/*
38 	 * Small initial size to exercise the realloc code
39 	 */
40 	result->size = 2;
41 
42 	if (!(result->data = talloc_zero_array(result, uint8_t, result->size))) {
43 		TALLOC_FREE(result);
44 		return NULL;
45 	}
46 
47 	return result;
48 }
49 
dns_marshall_buffer(struct dns_buffer * buf,const uint8_t * data,size_t len)50 void dns_marshall_buffer(struct dns_buffer *buf, const uint8_t *data,
51 			 size_t len)
52 {
53 	if (!ERR_DNS_IS_OK(buf->error)) return;
54 
55 	if (buf->offset + len < buf->offset) {
56 		/*
57 		 * Wraparound!
58 		 */
59 		buf->error = ERROR_DNS_INVALID_PARAMETER;
60 		return;
61 	}
62 
63 	if ((buf->offset + len) > 0xffff) {
64 		/*
65 		 * Only 64k possible
66 		 */
67 		buf->error = ERROR_DNS_INVALID_PARAMETER;
68 		return;
69 	}
70 
71 	if (buf->offset + len > buf->size) {
72 		size_t new_size = buf->offset + len;
73 		uint8_t *new_data;
74 
75 		/*
76 		 * Don't do too many reallocs, round up to some multiple
77 		 */
78 
79 		new_size += (64 - (new_size % 64));
80 
81 		if (!(new_data = talloc_realloc(buf, buf->data, uint8_t,
82 						      new_size))) {
83 			buf->error = ERROR_DNS_NO_MEMORY;
84 			return;
85 		}
86 
87 		buf->size = new_size;
88 		buf->data = new_data;
89 	}
90 
91 	memcpy(buf->data + buf->offset, data, len);
92 	buf->offset += len;
93 	return;
94 }
95 
dns_marshall_uint16(struct dns_buffer * buf,uint16_t val)96 void dns_marshall_uint16(struct dns_buffer *buf, uint16_t val)
97 {
98 	uint16_t n_val = htons(val);
99 	dns_marshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
100 }
101 
dns_marshall_uint32(struct dns_buffer * buf,uint32_t val)102 void dns_marshall_uint32(struct dns_buffer *buf, uint32_t val)
103 {
104 	uint32_t n_val = htonl(val);
105 	dns_marshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
106 }
107 
dns_unmarshall_buffer(struct dns_buffer * buf,uint8_t * data,size_t len)108 void dns_unmarshall_buffer(struct dns_buffer *buf, uint8_t *data,
109 			   size_t len)
110 {
111 	if (!(ERR_DNS_IS_OK(buf->error))) return;
112 
113 	if ((len > buf->size) || (buf->offset + len > buf->size)) {
114 		buf->error = ERROR_DNS_INVALID_MESSAGE;
115 		return;
116 	}
117 
118 	memcpy((void *)data, (const void *)(buf->data + buf->offset), len);
119 	buf->offset += len;
120 
121 	return;
122 }
123 
dns_unmarshall_uint16(struct dns_buffer * buf,uint16_t * val)124 void dns_unmarshall_uint16(struct dns_buffer *buf, uint16_t *val)
125 {
126 	uint16_t n_val;
127 
128 	dns_unmarshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
129 	if (!(ERR_DNS_IS_OK(buf->error))) return;
130 
131 	*val = ntohs(n_val);
132 }
133 
dns_unmarshall_uint32(struct dns_buffer * buf,uint32_t * val)134 void dns_unmarshall_uint32(struct dns_buffer *buf, uint32_t *val)
135 {
136 	uint32_t n_val;
137 
138 	dns_unmarshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
139 	if (!(ERR_DNS_IS_OK(buf->error))) return;
140 
141 	*val = ntohl(n_val);
142 }
143 
dns_marshall_domain_name(struct dns_buffer * buf,const struct dns_domain_name * name)144 void dns_marshall_domain_name(struct dns_buffer *buf,
145 			      const struct dns_domain_name *name)
146 {
147 	struct dns_domain_label *label;
148 	char end_char = '\0';
149 
150 	/*
151 	 * TODO: Implement DNS compression
152 	 */
153 
154 	for (label = name->pLabelList; label != NULL; label = label->next) {
155 		uint8_t len = label->len;
156 
157 		dns_marshall_buffer(buf, (uint8_t *)&len, sizeof(len));
158 		if (!ERR_DNS_IS_OK(buf->error)) return;
159 
160 		dns_marshall_buffer(buf, (uint8_t *)label->label, len);
161 		if (!ERR_DNS_IS_OK(buf->error)) return;
162 	}
163 
164 	dns_marshall_buffer(buf, (uint8_t *)&end_char, 1);
165 }
166 
dns_unmarshall_label(TALLOC_CTX * mem_ctx,int level,struct dns_buffer * buf,struct dns_domain_label ** plabel)167 static void dns_unmarshall_label(TALLOC_CTX *mem_ctx,
168 				 int level,
169 				 struct dns_buffer *buf,
170 				 struct dns_domain_label **plabel)
171 {
172 	struct dns_domain_label *label;
173 	uint8_t len;
174 
175 	if (!ERR_DNS_IS_OK(buf->error)) return;
176 
177 	if (level > 128) {
178 		/*
179 		 * Protect against recursion
180 		 */
181 		buf->error = ERROR_DNS_INVALID_MESSAGE;
182 		return;
183 	}
184 
185 	dns_unmarshall_buffer(buf, &len, sizeof(len));
186 	if (!ERR_DNS_IS_OK(buf->error)) return;
187 
188 	if (len == 0) {
189 		*plabel = NULL;
190 		return;
191 	}
192 
193 	if ((len & 0xc0) == 0xc0) {
194 		/*
195 		 * We've got a compressed name. Build up a new "fake" buffer
196 		 * and using the calculated offset.
197 		 */
198 		struct dns_buffer new_buf;
199 		uint8_t low;
200 
201 		dns_unmarshall_buffer(buf, &low, sizeof(low));
202 		if (!ERR_DNS_IS_OK(buf->error)) return;
203 
204 		new_buf = *buf;
205 		new_buf.offset = len & 0x3f;
206 		new_buf.offset <<= 8;
207 		new_buf.offset |= low;
208 
209 		dns_unmarshall_label(mem_ctx, level+1, &new_buf, plabel);
210 		buf->error = new_buf.error;
211 		return;
212 	}
213 
214 	if ((len & 0xc0) != 0) {
215 		buf->error = ERROR_DNS_INVALID_NAME;
216 		return;
217 	}
218 
219 	if (!(label = talloc_zero(mem_ctx, struct dns_domain_label))) {
220 		buf->error = ERROR_DNS_NO_MEMORY;
221 		return;
222 	}
223 
224 	label->len = len;
225 
226 	if (!(label->label = talloc_zero_array(label, char, len+1))) {
227 		buf->error = ERROR_DNS_NO_MEMORY;
228 		goto error;
229 	}
230 
231 	dns_unmarshall_buffer(buf, (uint8_t *)label->label, len);
232 	if (!ERR_DNS_IS_OK(buf->error)) goto error;
233 
234 	dns_unmarshall_label(label, level+1, buf, &label->next);
235 	if (!ERR_DNS_IS_OK(buf->error)) goto error;
236 
237 	*plabel = label;
238 	return;
239 
240  error:
241 	TALLOC_FREE(label);
242 	return;
243 }
244 
dns_unmarshall_domain_name(TALLOC_CTX * mem_ctx,struct dns_buffer * buf,struct dns_domain_name ** pname)245 void dns_unmarshall_domain_name(TALLOC_CTX *mem_ctx,
246 				struct dns_buffer *buf,
247 				struct dns_domain_name **pname)
248 {
249 	struct dns_domain_name *name;
250 
251 	if (!ERR_DNS_IS_OK(buf->error)) return;
252 
253 	if (!(name = talloc_zero(mem_ctx, struct dns_domain_name))) {
254 		buf->error = ERROR_DNS_NO_MEMORY;
255 		return;
256 	}
257 
258 	dns_unmarshall_label(name, 0, buf, &name->pLabelList);
259 
260 	if (!ERR_DNS_IS_OK(buf->error)) {
261 		return;
262 	}
263 
264 	*pname = name;
265 	return;
266 }
267 
dns_marshall_question(struct dns_buffer * buf,const struct dns_question * q)268 static void dns_marshall_question(struct dns_buffer *buf,
269 				  const struct dns_question *q)
270 {
271 	dns_marshall_domain_name(buf, q->name);
272 	dns_marshall_uint16(buf, q->q_type);
273 	dns_marshall_uint16(buf, q->q_class);
274 }
275 
dns_unmarshall_question(TALLOC_CTX * mem_ctx,struct dns_buffer * buf,struct dns_question ** pq)276 static void dns_unmarshall_question(TALLOC_CTX *mem_ctx,
277 				    struct dns_buffer *buf,
278 				    struct dns_question **pq)
279 {
280 	struct dns_question *q;
281 
282 	if (!(ERR_DNS_IS_OK(buf->error))) return;
283 
284 	if (!(q = talloc_zero(mem_ctx, struct dns_question))) {
285 		buf->error = ERROR_DNS_NO_MEMORY;
286 		return;
287 	}
288 
289 	dns_unmarshall_domain_name(q, buf, &q->name);
290 	dns_unmarshall_uint16(buf, &q->q_type);
291 	dns_unmarshall_uint16(buf, &q->q_class);
292 
293 	if (!(ERR_DNS_IS_OK(buf->error))) return;
294 
295 	*pq = q;
296 }
297 
dns_marshall_rr(struct dns_buffer * buf,const struct dns_rrec * r)298 static void dns_marshall_rr(struct dns_buffer *buf,
299 			    const struct dns_rrec *r)
300 {
301 	dns_marshall_domain_name(buf, r->name);
302 	dns_marshall_uint16(buf, r->type);
303 	dns_marshall_uint16(buf, r->r_class);
304 	dns_marshall_uint32(buf, r->ttl);
305 	dns_marshall_uint16(buf, r->data_length);
306 	dns_marshall_buffer(buf, r->data, r->data_length);
307 }
308 
dns_unmarshall_rr(TALLOC_CTX * mem_ctx,struct dns_buffer * buf,struct dns_rrec ** pr)309 static void dns_unmarshall_rr(TALLOC_CTX *mem_ctx,
310 			      struct dns_buffer *buf,
311 			      struct dns_rrec **pr)
312 {
313 	struct dns_rrec *r;
314 
315 	if (!(ERR_DNS_IS_OK(buf->error))) return;
316 
317 	if (!(r = talloc_zero(mem_ctx, struct dns_rrec))) {
318 		buf->error = ERROR_DNS_NO_MEMORY;
319 		return;
320 	}
321 
322 	dns_unmarshall_domain_name(r, buf, &r->name);
323 	dns_unmarshall_uint16(buf, &r->type);
324 	dns_unmarshall_uint16(buf, &r->r_class);
325 	dns_unmarshall_uint32(buf, &r->ttl);
326 	dns_unmarshall_uint16(buf, &r->data_length);
327 	r->data = NULL;
328 
329 	if (!(ERR_DNS_IS_OK(buf->error))) return;
330 
331 	if (r->data_length != 0) {
332 		if (!(r->data = talloc_zero_array(r, uint8_t, r->data_length))) {
333 			buf->error = ERROR_DNS_NO_MEMORY;
334 			return;
335 		}
336 		dns_unmarshall_buffer(buf, r->data, r->data_length);
337 	}
338 
339 	if (!(ERR_DNS_IS_OK(buf->error))) return;
340 
341 	*pr = r;
342 }
343 
dns_marshall_request(TALLOC_CTX * mem_ctx,const struct dns_request * req,struct dns_buffer ** pbuf)344 DNS_ERROR dns_marshall_request(TALLOC_CTX *mem_ctx,
345 			       const struct dns_request *req,
346 			       struct dns_buffer **pbuf)
347 {
348 	struct dns_buffer *buf;
349 	uint16_t i;
350 
351 	if (!(buf = dns_create_buffer(mem_ctx))) {
352 		return ERROR_DNS_NO_MEMORY;
353 	}
354 
355 	dns_marshall_uint16(buf, req->id);
356 	dns_marshall_uint16(buf, req->flags);
357 	dns_marshall_uint16(buf, req->num_questions);
358 	dns_marshall_uint16(buf, req->num_answers);
359 	dns_marshall_uint16(buf, req->num_auths);
360 	dns_marshall_uint16(buf, req->num_additionals);
361 
362 	for (i=0; i<req->num_questions; i++) {
363 		dns_marshall_question(buf, req->questions[i]);
364 	}
365 	for (i=0; i<req->num_answers; i++) {
366 		dns_marshall_rr(buf, req->answers[i]);
367 	}
368 	for (i=0; i<req->num_auths; i++) {
369 		dns_marshall_rr(buf, req->auths[i]);
370 	}
371 	for (i=0; i<req->num_additionals; i++) {
372 		dns_marshall_rr(buf, req->additionals[i]);
373 	}
374 
375 	if (!ERR_DNS_IS_OK(buf->error)) {
376 		DNS_ERROR err = buf->error;
377 		TALLOC_FREE(buf);
378 		return err;
379 	}
380 
381 	*pbuf = buf;
382 	return ERROR_DNS_SUCCESS;
383 }
384 
dns_unmarshall_request(TALLOC_CTX * mem_ctx,struct dns_buffer * buf,struct dns_request ** preq)385 DNS_ERROR dns_unmarshall_request(TALLOC_CTX *mem_ctx,
386 				 struct dns_buffer *buf,
387 				 struct dns_request **preq)
388 {
389 	struct dns_request *req;
390 	uint16_t i;
391 	DNS_ERROR err = ERROR_DNS_NO_MEMORY;
392 
393 	if (!(req = talloc_zero(mem_ctx, struct dns_request))) {
394 		return err;
395 	}
396 
397 	dns_unmarshall_uint16(buf, &req->id);
398 	dns_unmarshall_uint16(buf, &req->flags);
399 	dns_unmarshall_uint16(buf, &req->num_questions);
400 	dns_unmarshall_uint16(buf, &req->num_answers);
401 	dns_unmarshall_uint16(buf, &req->num_auths);
402 	dns_unmarshall_uint16(buf, &req->num_additionals);
403 
404 	if (!ERR_DNS_IS_OK(buf->error)){
405 		err = buf->error;
406 		goto error;
407 	}
408 
409 	err = ERROR_DNS_NO_MEMORY;
410 
411 	if ((req->num_questions != 0) &&
412 	    !(req->questions = talloc_zero_array(req, struct dns_question *,
413 					    req->num_questions))) {
414 		goto error;
415 	}
416 	if ((req->num_answers != 0) &&
417 	    !(req->answers = talloc_zero_array(req, struct dns_rrec *,
418 					  req->num_answers))) {
419 		goto error;
420 	}
421 	if ((req->num_auths != 0) &&
422 	    !(req->auths = talloc_zero_array(req, struct dns_rrec *,
423 					req->num_auths))) {
424 		goto error;
425 	}
426 	if ((req->num_additionals != 0) &&
427 	    !(req->additionals = talloc_zero_array(req, struct dns_rrec *,
428 					      req->num_additionals))) {
429 		goto error;
430 	}
431 
432 	for (i=0; i<req->num_questions; i++) {
433 		dns_unmarshall_question(req->questions, buf,
434 					&req->questions[i]);
435 	}
436 	for (i=0; i<req->num_answers; i++) {
437 		dns_unmarshall_rr(req->answers, buf,
438 				  &req->answers[i]);
439 	}
440 	for (i=0; i<req->num_auths; i++) {
441 		dns_unmarshall_rr(req->auths, buf,
442 				  &req->auths[i]);
443 	}
444 	for (i=0; i<req->num_additionals; i++) {
445 		dns_unmarshall_rr(req->additionals, buf,
446 				  &req->additionals[i]);
447 	}
448 
449 	if (!ERR_DNS_IS_OK(buf->error)) {
450 		err = buf->error;
451 		goto error;
452 	}
453 
454 	*preq = req;
455 	return ERROR_DNS_SUCCESS;
456 
457  error:
458 	TALLOC_FREE(req);
459 	return err;
460 }
461 
dns_update2request(struct dns_update_request * update)462 struct dns_request *dns_update2request(struct dns_update_request *update)
463 {
464 	struct dns_request *req;
465 
466 	/*
467 	 * This is a non-specified construct that happens to work on Linux/gcc
468 	 * and I would expect it to work everywhere else. dns_request and
469 	 * dns_update_request are essentially the same structures with
470 	 * different names, so any difference would mean that the compiler
471 	 * applied two different variations of padding given the same types in
472 	 * the structures.
473 	 */
474 
475 	req = (struct dns_request *)(void *)update;
476 
477 	/*
478 	 * The assert statement here looks like we could do the equivalent
479 	 * assignments to get portable, but it would mean that we have to
480 	 * allocate the dns_question record for the dns_zone records. We
481 	 * assume that if this assert works then the same holds true for
482 	 * dns_zone<>dns_question as well.
483 	 */
484 
485 #ifdef DEVELOPER
486 	assert((req->id == update->id) && (req->flags == update->flags) &&
487 	       (req->num_questions == update->num_zones) &&
488 	       (req->num_answers == update->num_preqs) &&
489 	       (req->num_auths == update->num_updates) &&
490 	       (req->num_additionals == update->num_additionals) &&
491 	       (req->questions ==
492 		(struct dns_question **)(void *)update->zones) &&
493 	       (req->answers == update->preqs) &&
494 	       (req->auths == update->updates) &&
495 	       (req->additionals == update->additionals));
496 #endif
497 
498 	return req;
499 }
500 
dns_request2update(struct dns_request * request)501 struct dns_update_request *dns_request2update(struct dns_request *request)
502 {
503 	/*
504 	 * For portability concerns see dns_update2request;
505 	 */
506 	return (struct dns_update_request *)(void *)request;
507 }
508 
dns_marshall_update_request(TALLOC_CTX * mem_ctx,struct dns_update_request * update,struct dns_buffer ** pbuf)509 DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
510 				      struct dns_update_request *update,
511 				      struct dns_buffer **pbuf)
512 {
513 	return dns_marshall_request(mem_ctx, dns_update2request(update), pbuf);
514 }
515 
dns_unmarshall_update_request(TALLOC_CTX * mem_ctx,struct dns_buffer * buf,struct dns_update_request ** pupreq)516 DNS_ERROR dns_unmarshall_update_request(TALLOC_CTX *mem_ctx,
517 					struct dns_buffer *buf,
518 					struct dns_update_request **pupreq)
519 {
520 	/*
521 	 * See comments above about portability. If the above works, this will
522 	 * as well.
523 	 */
524 
525 	return dns_unmarshall_request(mem_ctx, buf,
526 				      (struct dns_request **)(void *)pupreq);
527 }
528 
dns_response_code(uint16_t flags)529 uint16_t dns_response_code(uint16_t flags)
530 {
531 	return flags & 0xF;
532 }
533