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