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