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 296 : struct dns_buffer *dns_create_buffer(TALLOC_CTX *mem_ctx)
27 : {
28 0 : struct dns_buffer *result;
29 :
30 296 : if (!(result = talloc_zero(mem_ctx, struct dns_buffer))) {
31 0 : return NULL;
32 : }
33 :
34 296 : result->offset = 0;
35 296 : result->error = ERROR_DNS_SUCCESS;
36 :
37 : /*
38 : * Small initial size to exercise the realloc code
39 : */
40 296 : result->size = 2;
41 :
42 296 : if (!(result->data = talloc_zero_array(result, uint8_t, result->size))) {
43 0 : TALLOC_FREE(result);
44 0 : return NULL;
45 : }
46 :
47 296 : return result;
48 : }
49 :
50 14402 : void dns_marshall_buffer(struct dns_buffer *buf, const uint8_t *data,
51 : size_t len)
52 : {
53 14402 : if (!ERR_DNS_IS_OK(buf->error)) return;
54 :
55 14402 : if (buf->offset + len < buf->offset) {
56 : /*
57 : * Wraparound!
58 : */
59 0 : buf->error = ERROR_DNS_INVALID_PARAMETER;
60 0 : return;
61 : }
62 :
63 14402 : 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 14402 : if (buf->offset + len > buf->size) {
72 1004 : 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 1004 : new_size += (64 - (new_size % 64));
80 :
81 1004 : 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 1004 : buf->size = new_size;
88 1004 : buf->data = new_data;
89 : }
90 :
91 14402 : if (data != NULL) {
92 14108 : memcpy(buf->data + buf->offset, data, len);
93 : }
94 14402 : buf->offset += len;
95 14402 : return;
96 : }
97 :
98 4159 : void dns_marshall_uint16(struct dns_buffer *buf, uint16_t val)
99 : {
100 4159 : uint16_t n_val = htons(val);
101 4159 : dns_marshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
102 4159 : }
103 :
104 821 : void dns_marshall_uint32(struct dns_buffer *buf, uint32_t val)
105 : {
106 821 : uint32_t n_val = htonl(val);
107 821 : dns_marshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
108 821 : }
109 :
110 10618 : void dns_unmarshall_buffer(struct dns_buffer *buf, uint8_t *data,
111 : size_t len)
112 : {
113 10618 : if (!(ERR_DNS_IS_OK(buf->error))) return;
114 :
115 10618 : if ((len > buf->size) || (buf->offset + len > buf->size)) {
116 0 : buf->error = ERROR_DNS_INVALID_MESSAGE;
117 0 : return;
118 : }
119 :
120 10618 : memcpy((void *)data, (const void *)(buf->data + buf->offset), len);
121 10618 : buf->offset += len;
122 :
123 10618 : return;
124 : }
125 :
126 3025 : void dns_unmarshall_uint16(struct dns_buffer *buf, uint16_t *val)
127 : {
128 0 : uint16_t n_val;
129 :
130 3025 : dns_unmarshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
131 3025 : if (!(ERR_DNS_IS_OK(buf->error))) return;
132 :
133 3025 : *val = ntohs(n_val);
134 : }
135 :
136 597 : void dns_unmarshall_uint32(struct dns_buffer *buf, uint32_t *val)
137 : {
138 0 : uint32_t n_val;
139 :
140 597 : dns_unmarshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
141 597 : if (!(ERR_DNS_IS_OK(buf->error))) return;
142 :
143 597 : *val = ntohl(n_val);
144 : }
145 :
146 991 : 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 991 : char end_char = '\0';
151 :
152 : /*
153 : * TODO: Implement DNS compression
154 : */
155 :
156 4859 : for (label = name->pLabelList; label != NULL; label = label->next) {
157 3868 : uint8_t len = label->len;
158 :
159 3868 : dns_marshall_buffer(buf, (uint8_t *)&len, sizeof(len));
160 3868 : if (!ERR_DNS_IS_OK(buf->error)) return;
161 :
162 3868 : dns_marshall_buffer(buf, (uint8_t *)label->label, len);
163 3868 : if (!ERR_DNS_IS_OK(buf->error)) return;
164 : }
165 :
166 991 : dns_marshall_buffer(buf, (uint8_t *)&end_char, 1);
167 : }
168 :
169 3688 : 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 3688 : if (!ERR_DNS_IS_OK(buf->error)) return;
178 :
179 3688 : if (level > 128) {
180 : /*
181 : * Protect against recursion
182 : */
183 0 : buf->error = ERROR_DNS_INVALID_MESSAGE;
184 0 : return;
185 : }
186 :
187 3688 : dns_unmarshall_buffer(buf, &len, sizeof(len));
188 3688 : if (!ERR_DNS_IS_OK(buf->error)) return;
189 :
190 3688 : if (len == 0) {
191 725 : *plabel = NULL;
192 725 : return;
193 : }
194 :
195 2963 : 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 220 : dns_unmarshall_buffer(buf, &low, sizeof(low));
204 220 : if (!ERR_DNS_IS_OK(buf->error)) return;
205 :
206 220 : new_buf = *buf;
207 220 : new_buf.offset = len & 0x3f;
208 220 : new_buf.offset <<= 8;
209 220 : new_buf.offset |= low;
210 :
211 220 : dns_unmarshall_label(mem_ctx, level+1, &new_buf, plabel);
212 220 : buf->error = new_buf.error;
213 220 : return;
214 : }
215 :
216 2743 : if ((len & 0xc0) != 0) {
217 0 : buf->error = ERROR_DNS_INVALID_NAME;
218 0 : return;
219 : }
220 :
221 2743 : if (!(label = talloc_zero(mem_ctx, struct dns_domain_label))) {
222 0 : buf->error = ERROR_DNS_NO_MEMORY;
223 0 : return;
224 : }
225 :
226 2743 : label->len = len;
227 :
228 2743 : 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 2743 : dns_unmarshall_buffer(buf, (uint8_t *)label->label, len);
234 2743 : if (!ERR_DNS_IS_OK(buf->error)) goto error;
235 :
236 2743 : dns_unmarshall_label(label, level+1, buf, &label->next);
237 2743 : if (!ERR_DNS_IS_OK(buf->error)) goto error;
238 :
239 2743 : *plabel = label;
240 2743 : return;
241 :
242 0 : error:
243 0 : TALLOC_FREE(label);
244 0 : return;
245 : }
246 :
247 725 : 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 725 : if (!ERR_DNS_IS_OK(buf->error)) return;
254 :
255 725 : if (!(name = talloc_zero(mem_ctx, struct dns_domain_name))) {
256 0 : buf->error = ERROR_DNS_NO_MEMORY;
257 0 : return;
258 : }
259 :
260 725 : dns_unmarshall_label(name, 0, buf, &name->pLabelList);
261 :
262 725 : if (!ERR_DNS_IS_OK(buf->error)) {
263 0 : return;
264 : }
265 :
266 725 : *pname = name;
267 725 : return;
268 : }
269 :
270 212 : static void dns_marshall_question(struct dns_buffer *buf,
271 : const struct dns_question *q)
272 : {
273 212 : dns_marshall_domain_name(buf, q->name);
274 212 : dns_marshall_uint16(buf, q->q_type);
275 212 : dns_marshall_uint16(buf, q->q_class);
276 212 : }
277 :
278 170 : 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 170 : if (!(ERR_DNS_IS_OK(buf->error))) return;
285 :
286 170 : if (!(q = talloc_zero(mem_ctx, struct dns_question))) {
287 0 : buf->error = ERROR_DNS_NO_MEMORY;
288 0 : return;
289 : }
290 :
291 170 : dns_unmarshall_domain_name(q, buf, &q->name);
292 170 : dns_unmarshall_uint16(buf, &q->q_type);
293 170 : dns_unmarshall_uint16(buf, &q->q_class);
294 :
295 170 : if (!(ERR_DNS_IS_OK(buf->error))) return;
296 :
297 170 : *pq = q;
298 : }
299 :
300 611 : static void dns_marshall_rr(struct dns_buffer *buf,
301 : const struct dns_rrec *r)
302 : {
303 611 : dns_marshall_domain_name(buf, r->name);
304 611 : dns_marshall_uint16(buf, r->type);
305 611 : dns_marshall_uint16(buf, r->r_class);
306 611 : dns_marshall_uint32(buf, r->ttl);
307 611 : dns_marshall_uint16(buf, r->data_length);
308 611 : dns_marshall_buffer(buf, r->data, r->data_length);
309 611 : }
310 :
311 513 : 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 513 : if (!(ERR_DNS_IS_OK(buf->error))) return;
318 :
319 513 : if (!(r = talloc_zero(mem_ctx, struct dns_rrec))) {
320 0 : buf->error = ERROR_DNS_NO_MEMORY;
321 0 : return;
322 : }
323 :
324 513 : dns_unmarshall_domain_name(r, buf, &r->name);
325 513 : dns_unmarshall_uint16(buf, &r->type);
326 513 : dns_unmarshall_uint16(buf, &r->r_class);
327 513 : dns_unmarshall_uint32(buf, &r->ttl);
328 513 : dns_unmarshall_uint16(buf, &r->data_length);
329 513 : r->data = NULL;
330 :
331 513 : if (!(ERR_DNS_IS_OK(buf->error))) return;
332 :
333 513 : if (r->data_length != 0) {
334 303 : 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 303 : dns_unmarshall_buffer(buf, r->data, r->data_length);
339 : }
340 :
341 513 : if (!(ERR_DNS_IS_OK(buf->error))) return;
342 :
343 513 : *pr = r;
344 : }
345 :
346 212 : 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 212 : if (!(buf = dns_create_buffer(mem_ctx))) {
354 0 : return ERROR_DNS_NO_MEMORY;
355 : }
356 :
357 212 : dns_marshall_uint16(buf, req->id);
358 212 : dns_marshall_uint16(buf, req->flags);
359 212 : dns_marshall_uint16(buf, req->num_questions);
360 212 : dns_marshall_uint16(buf, req->num_answers);
361 212 : dns_marshall_uint16(buf, req->num_auths);
362 212 : dns_marshall_uint16(buf, req->num_additionals);
363 :
364 424 : for (i=0; i<req->num_questions; i++) {
365 212 : dns_marshall_question(buf, req->questions[i]);
366 : }
367 438 : for (i=0; i<req->num_answers; i++) {
368 226 : dns_marshall_rr(buf, req->answers[i]);
369 : }
370 513 : for (i=0; i<req->num_auths; i++) {
371 301 : dns_marshall_rr(buf, req->auths[i]);
372 : }
373 296 : for (i=0; i<req->num_additionals; i++) {
374 84 : dns_marshall_rr(buf, req->additional[i]);
375 : }
376 :
377 212 : 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 212 : *pbuf = buf;
384 212 : return ERROR_DNS_SUCCESS;
385 : }
386 :
387 170 : 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 170 : DNS_ERROR err = ERROR_DNS_NO_MEMORY;
394 :
395 170 : if (!(req = talloc_zero(mem_ctx, struct dns_request))) {
396 0 : return err;
397 : }
398 :
399 170 : dns_unmarshall_uint16(buf, &req->id);
400 170 : dns_unmarshall_uint16(buf, &req->flags);
401 170 : dns_unmarshall_uint16(buf, &req->num_questions);
402 170 : dns_unmarshall_uint16(buf, &req->num_answers);
403 170 : dns_unmarshall_uint16(buf, &req->num_auths);
404 170 : dns_unmarshall_uint16(buf, &req->num_additionals);
405 :
406 170 : if (!ERR_DNS_IS_OK(buf->error)){
407 0 : err = buf->error;
408 0 : goto error;
409 : }
410 :
411 170 : err = ERROR_DNS_NO_MEMORY;
412 :
413 170 : if ((req->num_questions != 0) &&
414 170 : !(req->questions = talloc_zero_array(req, struct dns_question *,
415 : req->num_questions))) {
416 0 : goto error;
417 : }
418 170 : if ((req->num_answers != 0) &&
419 169 : !(req->answers = talloc_zero_array(req, struct dns_rrec *,
420 : req->num_answers))) {
421 0 : goto error;
422 : }
423 170 : if ((req->num_auths != 0) &&
424 86 : !(req->auths = talloc_zero_array(req, struct dns_rrec *,
425 : req->num_auths))) {
426 0 : goto error;
427 : }
428 170 : if ((req->num_additionals != 0) &&
429 84 : !(req->additional = talloc_zero_array(req, struct dns_rrec *,
430 : req->num_additionals))) {
431 0 : goto error;
432 : }
433 :
434 340 : for (i=0; i<req->num_questions; i++) {
435 170 : dns_unmarshall_question(req->questions, buf,
436 170 : &req->questions[i]);
437 : }
438 397 : for (i=0; i<req->num_answers; i++) {
439 227 : dns_unmarshall_rr(req->answers, buf,
440 227 : &req->answers[i]);
441 : }
442 372 : for (i=0; i<req->num_auths; i++) {
443 202 : dns_unmarshall_rr(req->auths, buf,
444 202 : &req->auths[i]);
445 : }
446 254 : for (i=0; i<req->num_additionals; i++) {
447 84 : dns_unmarshall_rr(req->additional, buf,
448 84 : &req->additional[i]);
449 : }
450 :
451 170 : if (!ERR_DNS_IS_OK(buf->error)) {
452 0 : err = buf->error;
453 0 : goto error;
454 : }
455 :
456 170 : *preq = req;
457 170 : return ERROR_DNS_SUCCESS;
458 :
459 0 : error:
460 0 : TALLOC_FREE(req);
461 0 : return err;
462 : }
463 :
464 169 : 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 169 : 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 169 : 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 169 : return req;
501 : }
502 :
503 127 : struct dns_update_request *dns_request2update(struct dns_request *request)
504 : {
505 : /*
506 : * For portability concerns see dns_update2request;
507 : */
508 127 : return (struct dns_update_request *)(void *)request;
509 : }
510 :
511 42 : DNS_ERROR dns_marshall_update_request(TALLOC_CTX *mem_ctx,
512 : struct dns_update_request *update,
513 : struct dns_buffer **pbuf)
514 : {
515 42 : 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 128 : uint16_t dns_response_code(uint16_t flags)
532 : {
533 128 : return flags & 0xF;
534 : }
|