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