2 Linux DNS client library implementation
3 Copyright (C) 2006 Gerald Carter <jerry@samba.org>
5 ** NOTE! The following LGPL license applies to the libaddns
6 ** library. This does NOT imply that all of Samba is released
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.
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.
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/>.
26 struct dns_buffer
*dns_create_buffer(TALLOC_CTX
*mem_ctx
)
28 struct dns_buffer
*result
;
30 if (!(result
= talloc_zero(mem_ctx
, struct dns_buffer
))) {
35 result
->error
= ERROR_DNS_SUCCESS
;
38 * Small initial size to exercise the realloc code
42 if (!(result
->data
= talloc_zero_array(result
, uint8_t, result
->size
))) {
50 void dns_marshall_buffer(struct dns_buffer
*buf
, const uint8_t *data
,
53 if (!ERR_DNS_IS_OK(buf
->error
)) return;
55 if (buf
->offset
+ len
< buf
->offset
) {
59 buf
->error
= ERROR_DNS_INVALID_PARAMETER
;
63 if ((buf
->offset
+ len
) > 0xffff) {
67 buf
->error
= ERROR_DNS_INVALID_PARAMETER
;
71 if (buf
->offset
+ len
> buf
->size
) {
72 size_t new_size
= buf
->offset
+ len
;
76 * Don't do too many reallocs, round up to some multiple
79 new_size
+= (64 - (new_size
% 64));
81 if (!(new_data
= talloc_realloc(buf
, buf
->data
, uint8_t,
83 buf
->error
= ERROR_DNS_NO_MEMORY
;
92 memcpy(buf
->data
+ buf
->offset
, data
, len
);
98 void dns_marshall_uint16(struct dns_buffer
*buf
, uint16_t val
)
100 uint16_t n_val
= htons(val
);
101 dns_marshall_buffer(buf
, (uint8_t *)&n_val
, sizeof(n_val
));
104 void dns_marshall_uint32(struct dns_buffer
*buf
, uint32_t val
)
106 uint32_t n_val
= htonl(val
);
107 dns_marshall_buffer(buf
, (uint8_t *)&n_val
, sizeof(n_val
));
110 void dns_unmarshall_buffer(struct dns_buffer
*buf
, uint8_t *data
,
113 if (!(ERR_DNS_IS_OK(buf
->error
))) return;
115 if ((len
> buf
->size
) || (buf
->offset
+ len
> buf
->size
)) {
116 buf
->error
= ERROR_DNS_INVALID_MESSAGE
;
120 memcpy((void *)data
, (const void *)(buf
->data
+ buf
->offset
), len
);
126 void dns_unmarshall_uint16(struct dns_buffer
*buf
, uint16_t *val
)
130 dns_unmarshall_buffer(buf
, (uint8_t *)&n_val
, sizeof(n_val
));
131 if (!(ERR_DNS_IS_OK(buf
->error
))) return;
136 void dns_unmarshall_uint32(struct dns_buffer
*buf
, uint32_t *val
)
140 dns_unmarshall_buffer(buf
, (uint8_t *)&n_val
, sizeof(n_val
));
141 if (!(ERR_DNS_IS_OK(buf
->error
))) return;
146 void dns_marshall_domain_name(struct dns_buffer
*buf
,
147 const struct dns_domain_name
*name
)
149 struct dns_domain_label
*label
;
150 char end_char
= '\0';
153 * TODO: Implement DNS compression
156 for (label
= name
->pLabelList
; label
!= NULL
; label
= label
->next
) {
157 uint8_t len
= label
->len
;
159 dns_marshall_buffer(buf
, (uint8_t *)&len
, sizeof(len
));
160 if (!ERR_DNS_IS_OK(buf
->error
)) return;
162 dns_marshall_buffer(buf
, (uint8_t *)label
->label
, len
);
163 if (!ERR_DNS_IS_OK(buf
->error
)) return;
166 dns_marshall_buffer(buf
, (uint8_t *)&end_char
, 1);
169 static void dns_unmarshall_label(TALLOC_CTX
*mem_ctx
,
171 struct dns_buffer
*buf
,
172 struct dns_domain_label
**plabel
)
174 struct dns_domain_label
*label
;
177 if (!ERR_DNS_IS_OK(buf
->error
)) return;
181 * Protect against recursion
183 buf
->error
= ERROR_DNS_INVALID_MESSAGE
;
187 dns_unmarshall_buffer(buf
, &len
, sizeof(len
));
188 if (!ERR_DNS_IS_OK(buf
->error
)) return;
195 if ((len
& 0xc0) == 0xc0) {
197 * We've got a compressed name. Build up a new "fake" buffer
198 * and using the calculated offset.
200 struct dns_buffer new_buf
;
203 dns_unmarshall_buffer(buf
, &low
, sizeof(low
));
204 if (!ERR_DNS_IS_OK(buf
->error
)) return;
207 new_buf
.offset
= len
& 0x3f;
208 new_buf
.offset
<<= 8;
209 new_buf
.offset
|= low
;
211 dns_unmarshall_label(mem_ctx
, level
+1, &new_buf
, plabel
);
212 buf
->error
= new_buf
.error
;
216 if ((len
& 0xc0) != 0) {
217 buf
->error
= ERROR_DNS_INVALID_NAME
;
221 if (!(label
= talloc_zero(mem_ctx
, struct dns_domain_label
))) {
222 buf
->error
= ERROR_DNS_NO_MEMORY
;
228 if (!(label
->label
= talloc_zero_array(label
, char, len
+1))) {
229 buf
->error
= ERROR_DNS_NO_MEMORY
;
233 dns_unmarshall_buffer(buf
, (uint8_t *)label
->label
, len
);
234 if (!ERR_DNS_IS_OK(buf
->error
)) goto error
;
236 dns_unmarshall_label(label
, level
+1, buf
, &label
->next
);
237 if (!ERR_DNS_IS_OK(buf
->error
)) goto error
;
247 void dns_unmarshall_domain_name(TALLOC_CTX
*mem_ctx
,
248 struct dns_buffer
*buf
,
249 struct dns_domain_name
**pname
)
251 struct dns_domain_name
*name
;
253 if (!ERR_DNS_IS_OK(buf
->error
)) return;
255 if (!(name
= talloc_zero(mem_ctx
, struct dns_domain_name
))) {
256 buf
->error
= ERROR_DNS_NO_MEMORY
;
260 dns_unmarshall_label(name
, 0, buf
, &name
->pLabelList
);
262 if (!ERR_DNS_IS_OK(buf
->error
)) {
270 static void dns_marshall_question(struct dns_buffer
*buf
,
271 const struct dns_question
*q
)
273 dns_marshall_domain_name(buf
, q
->name
);
274 dns_marshall_uint16(buf
, q
->q_type
);
275 dns_marshall_uint16(buf
, q
->q_class
);
278 static void dns_unmarshall_question(TALLOC_CTX
*mem_ctx
,
279 struct dns_buffer
*buf
,
280 struct dns_question
**pq
)
282 struct dns_question
*q
;
284 if (!(ERR_DNS_IS_OK(buf
->error
))) return;
286 if (!(q
= talloc_zero(mem_ctx
, struct dns_question
))) {
287 buf
->error
= ERROR_DNS_NO_MEMORY
;
291 dns_unmarshall_domain_name(q
, buf
, &q
->name
);
292 dns_unmarshall_uint16(buf
, &q
->q_type
);
293 dns_unmarshall_uint16(buf
, &q
->q_class
);
295 if (!(ERR_DNS_IS_OK(buf
->error
))) return;
300 static void dns_marshall_rr(struct dns_buffer
*buf
,
301 const struct dns_rrec
*r
)
303 dns_marshall_domain_name(buf
, r
->name
);
304 dns_marshall_uint16(buf
, r
->type
);
305 dns_marshall_uint16(buf
, r
->r_class
);
306 dns_marshall_uint32(buf
, r
->ttl
);
307 dns_marshall_uint16(buf
, r
->data_length
);
308 dns_marshall_buffer(buf
, r
->data
, r
->data_length
);
311 static void dns_unmarshall_rr(TALLOC_CTX
*mem_ctx
,
312 struct dns_buffer
*buf
,
313 struct dns_rrec
**pr
)
317 if (!(ERR_DNS_IS_OK(buf
->error
))) return;
319 if (!(r
= talloc_zero(mem_ctx
, struct dns_rrec
))) {
320 buf
->error
= ERROR_DNS_NO_MEMORY
;
324 dns_unmarshall_domain_name(r
, buf
, &r
->name
);
325 dns_unmarshall_uint16(buf
, &r
->type
);
326 dns_unmarshall_uint16(buf
, &r
->r_class
);
327 dns_unmarshall_uint32(buf
, &r
->ttl
);
328 dns_unmarshall_uint16(buf
, &r
->data_length
);
331 if (!(ERR_DNS_IS_OK(buf
->error
))) return;
333 if (r
->data_length
!= 0) {
334 if (!(r
->data
= talloc_zero_array(r
, uint8_t, r
->data_length
))) {
335 buf
->error
= ERROR_DNS_NO_MEMORY
;
338 dns_unmarshall_buffer(buf
, r
->data
, r
->data_length
);
341 if (!(ERR_DNS_IS_OK(buf
->error
))) return;
346 DNS_ERROR
dns_marshall_request(TALLOC_CTX
*mem_ctx
,
347 const struct dns_request
*req
,
348 struct dns_buffer
**pbuf
)
350 struct dns_buffer
*buf
;
353 if (!(buf
= dns_create_buffer(mem_ctx
))) {
354 return ERROR_DNS_NO_MEMORY
;
357 dns_marshall_uint16(buf
, req
->id
);
358 dns_marshall_uint16(buf
, req
->flags
);
359 dns_marshall_uint16(buf
, req
->num_questions
);
360 dns_marshall_uint16(buf
, req
->num_answers
);
361 dns_marshall_uint16(buf
, req
->num_auths
);
362 dns_marshall_uint16(buf
, req
->num_additionals
);
364 for (i
=0; i
<req
->num_questions
; i
++) {
365 dns_marshall_question(buf
, req
->questions
[i
]);
367 for (i
=0; i
<req
->num_answers
; i
++) {
368 dns_marshall_rr(buf
, req
->answers
[i
]);
370 for (i
=0; i
<req
->num_auths
; i
++) {
371 dns_marshall_rr(buf
, req
->auths
[i
]);
373 for (i
=0; i
<req
->num_additionals
; i
++) {
374 dns_marshall_rr(buf
, req
->additional
[i
]);
377 if (!ERR_DNS_IS_OK(buf
->error
)) {
378 DNS_ERROR err
= buf
->error
;
384 return ERROR_DNS_SUCCESS
;
387 DNS_ERROR
dns_unmarshall_request(TALLOC_CTX
*mem_ctx
,
388 struct dns_buffer
*buf
,
389 struct dns_request
**preq
)
391 struct dns_request
*req
;
393 DNS_ERROR err
= ERROR_DNS_NO_MEMORY
;
395 if (!(req
= talloc_zero(mem_ctx
, struct dns_request
))) {
399 dns_unmarshall_uint16(buf
, &req
->id
);
400 dns_unmarshall_uint16(buf
, &req
->flags
);
401 dns_unmarshall_uint16(buf
, &req
->num_questions
);
402 dns_unmarshall_uint16(buf
, &req
->num_answers
);
403 dns_unmarshall_uint16(buf
, &req
->num_auths
);
404 dns_unmarshall_uint16(buf
, &req
->num_additionals
);
406 if (!ERR_DNS_IS_OK(buf
->error
)){
411 err
= ERROR_DNS_NO_MEMORY
;
413 if ((req
->num_questions
!= 0) &&
414 !(req
->questions
= talloc_zero_array(req
, struct dns_question
*,
415 req
->num_questions
))) {
418 if ((req
->num_answers
!= 0) &&
419 !(req
->answers
= talloc_zero_array(req
, struct dns_rrec
*,
420 req
->num_answers
))) {
423 if ((req
->num_auths
!= 0) &&
424 !(req
->auths
= talloc_zero_array(req
, struct dns_rrec
*,
428 if ((req
->num_additionals
!= 0) &&
429 !(req
->additional
= talloc_zero_array(req
, struct dns_rrec
*,
430 req
->num_additionals
))) {
434 for (i
=0; i
<req
->num_questions
; i
++) {
435 dns_unmarshall_question(req
->questions
, buf
,
438 for (i
=0; i
<req
->num_answers
; i
++) {
439 dns_unmarshall_rr(req
->answers
, buf
,
442 for (i
=0; i
<req
->num_auths
; i
++) {
443 dns_unmarshall_rr(req
->auths
, buf
,
446 for (i
=0; i
<req
->num_additionals
; i
++) {
447 dns_unmarshall_rr(req
->additional
, buf
,
448 &req
->additional
[i
]);
451 if (!ERR_DNS_IS_OK(buf
->error
)) {
457 return ERROR_DNS_SUCCESS
;
464 struct dns_request
*dns_update2request(struct dns_update_request
*update
)
466 struct dns_request
*req
;
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
477 req
= (struct dns_request
*)(void *)update
;
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.
488 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
) &&
494 (struct dns_question
**)(void *)update
->zones
) &&
495 (req
->answers
== update
->preqs
) &&
496 (req
->auths
== update
->updates
) &&
497 (req
->additional
== update
->additional
));
503 struct dns_update_request
*dns_request2update(struct dns_request
*request
)
506 * For portability concerns see dns_update2request;
508 return (struct dns_update_request
*)(void *)request
;
511 DNS_ERROR
dns_marshall_update_request(TALLOC_CTX
*mem_ctx
,
512 struct dns_update_request
*update
,
513 struct dns_buffer
**pbuf
)
515 return dns_marshall_request(mem_ctx
, dns_update2request(update
), pbuf
);
518 DNS_ERROR
dns_unmarshall_update_request(TALLOC_CTX
*mem_ctx
,
519 struct dns_buffer
*buf
,
520 struct dns_update_request
**pupreq
)
523 * See comments above about portability. If the above works, this will
527 return dns_unmarshall_request(mem_ctx
, buf
,
528 (struct dns_request
**)(void *)pupreq
);
531 uint16_t dns_response_code(uint16_t flags
)