samba-tool: add `samba-tool domain kds root_key list`
[samba.git] / lib / addns / dnsmarshall.c
blobc95420304f07fe004e5d8ad9a25227bbea6bad53
1 /*
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
7 ** under the LGPL
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/>.
23 #include "dns.h"
24 #include "assert.h"
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))) {
31 return NULL;
34 result->offset = 0;
35 result->error = ERROR_DNS_SUCCESS;
38 * Small initial size to exercise the realloc code
40 result->size = 2;
42 if (!(result->data = talloc_zero_array(result, uint8_t, result->size))) {
43 TALLOC_FREE(result);
44 return NULL;
47 return result;
50 void dns_marshall_buffer(struct dns_buffer *buf, const uint8_t *data,
51 size_t len)
53 if (!ERR_DNS_IS_OK(buf->error)) return;
55 if (buf->offset + len < buf->offset) {
57 * Wraparound!
59 buf->error = ERROR_DNS_INVALID_PARAMETER;
60 return;
63 if ((buf->offset + len) > 0xffff) {
65 * Only 64k possible
67 buf->error = ERROR_DNS_INVALID_PARAMETER;
68 return;
71 if (buf->offset + len > buf->size) {
72 size_t new_size = buf->offset + len;
73 uint8_t *new_data;
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,
82 new_size))) {
83 buf->error = ERROR_DNS_NO_MEMORY;
84 return;
87 buf->size = new_size;
88 buf->data = new_data;
91 if (data != NULL) {
92 memcpy(buf->data + buf->offset, data, len);
94 buf->offset += len;
95 return;
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,
111 size_t len)
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;
117 return;
120 memcpy((void *)data, (const void *)(buf->data + buf->offset), len);
121 buf->offset += len;
123 return;
126 void dns_unmarshall_uint16(struct dns_buffer *buf, uint16_t *val)
128 uint16_t n_val;
130 dns_unmarshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
131 if (!(ERR_DNS_IS_OK(buf->error))) return;
133 *val = ntohs(n_val);
136 void dns_unmarshall_uint32(struct dns_buffer *buf, uint32_t *val)
138 uint32_t n_val;
140 dns_unmarshall_buffer(buf, (uint8_t *)&n_val, sizeof(n_val));
141 if (!(ERR_DNS_IS_OK(buf->error))) return;
143 *val = ntohl(n_val);
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,
170 int level,
171 struct dns_buffer *buf,
172 struct dns_domain_label **plabel)
174 struct dns_domain_label *label;
175 uint8_t len;
177 if (!ERR_DNS_IS_OK(buf->error)) return;
179 if (level > 128) {
181 * Protect against recursion
183 buf->error = ERROR_DNS_INVALID_MESSAGE;
184 return;
187 dns_unmarshall_buffer(buf, &len, sizeof(len));
188 if (!ERR_DNS_IS_OK(buf->error)) return;
190 if (len == 0) {
191 *plabel = NULL;
192 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;
201 uint8_t low;
203 dns_unmarshall_buffer(buf, &low, sizeof(low));
204 if (!ERR_DNS_IS_OK(buf->error)) return;
206 new_buf = *buf;
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;
213 return;
216 if ((len & 0xc0) != 0) {
217 buf->error = ERROR_DNS_INVALID_NAME;
218 return;
221 if (!(label = talloc_zero(mem_ctx, struct dns_domain_label))) {
222 buf->error = ERROR_DNS_NO_MEMORY;
223 return;
226 label->len = len;
228 if (!(label->label = talloc_zero_array(label, char, len+1))) {
229 buf->error = ERROR_DNS_NO_MEMORY;
230 goto error;
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;
239 *plabel = label;
240 return;
242 error:
243 TALLOC_FREE(label);
244 return;
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;
257 return;
260 dns_unmarshall_label(name, 0, buf, &name->pLabelList);
262 if (!ERR_DNS_IS_OK(buf->error)) {
263 return;
266 *pname = name;
267 return;
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;
288 return;
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;
297 *pq = q;
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)
315 struct dns_rrec *r;
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;
321 return;
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);
329 r->data = NULL;
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;
336 return;
338 dns_unmarshall_buffer(buf, r->data, r->data_length);
341 if (!(ERR_DNS_IS_OK(buf->error))) return;
343 *pr = r;
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;
351 uint16_t i;
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;
379 TALLOC_FREE(buf);
380 return err;
383 *pbuf = buf;
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;
392 uint16_t i;
393 DNS_ERROR err = ERROR_DNS_NO_MEMORY;
395 if (!(req = talloc_zero(mem_ctx, struct dns_request))) {
396 return err;
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)){
407 err = buf->error;
408 goto 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))) {
416 goto error;
418 if ((req->num_answers != 0) &&
419 !(req->answers = talloc_zero_array(req, struct dns_rrec *,
420 req->num_answers))) {
421 goto error;
423 if ((req->num_auths != 0) &&
424 !(req->auths = talloc_zero_array(req, struct dns_rrec *,
425 req->num_auths))) {
426 goto error;
428 if ((req->num_additionals != 0) &&
429 !(req->additional = talloc_zero_array(req, struct dns_rrec *,
430 req->num_additionals))) {
431 goto error;
434 for (i=0; i<req->num_questions; i++) {
435 dns_unmarshall_question(req->questions, buf,
436 &req->questions[i]);
438 for (i=0; i<req->num_answers; i++) {
439 dns_unmarshall_rr(req->answers, buf,
440 &req->answers[i]);
442 for (i=0; i<req->num_auths; i++) {
443 dns_unmarshall_rr(req->auths, buf,
444 &req->auths[i]);
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)) {
452 err = buf->error;
453 goto error;
456 *preq = req;
457 return ERROR_DNS_SUCCESS;
459 error:
460 TALLOC_FREE(req);
461 return err;
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
474 * the structures.
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.
487 #ifdef DEVELOPER
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) &&
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
500 return req;
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
524 * as well.
527 return dns_unmarshall_request(mem_ctx, buf,
528 (struct dns_request **)(void *)pupreq);
531 uint16_t dns_response_code(uint16_t flags)
533 return flags & 0xF;