]> git.saurik.com Git - apple/mdnsresponder.git/blob - ServiceRegistration/fromwire.c
mDNSResponder-1096.100.3.tar.gz
[apple/mdnsresponder.git] / ServiceRegistration / fromwire.c
1 /* fromwire.c
2 *
3 * Copyright (c) 2018 Apple Computer, Inc. All rights reserved.
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 *
17 * DNS wire-format functions.
18 *
19 * These are really simple functions for constructing DNS messages wire format.
20 * The flow is that there is a transaction structure which contains pointers to both
21 * a message output buffer and a response input buffer. The structure is initialized,
22 * and then the various wire format functions are called repeatedly to store data.
23 * If an error occurs during this process, it's okay to just keep going, because the
24 * error is recorded in the transaction; once all of the copy-in functions have been
25 * called, the error status can be checked once at the end.
26 */
27
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <string.h>
31 #include <sys/errno.h>
32 #include <sys/socket.h>
33 #include <arpa/inet.h>
34 #include <stdlib.h>
35 #include <ctype.h>
36 #include "srp.h"
37 #include "dns-msg.h"
38
39 bool
40 dns_opt_parse(dns_edns0_t *NONNULL *NULLABLE ret, dns_rr_t *rr)
41 {
42 return true;
43 }
44
45 dns_label_t * NULLABLE
46 dns_label_parse(const uint8_t *buf, unsigned mlen, unsigned *NONNULL offp)
47 {
48 uint8_t llen = buf[*offp];
49 dns_label_t *rv;
50
51 // Make sure that we got the data this label claims to encompass.
52 if (*offp + llen + 1 > mlen) {
53 DEBUG("claimed length of label is too long: %u > %u.\n", *offp + llen + 1, mlen);
54 return NULL;
55 }
56
57 rv = calloc(llen + 1 - DNS_MAX_LABEL_SIZE + sizeof *rv, 1);
58 if (rv == NULL) {
59 DEBUG("memory allocation for %u byte label (%.*s) failed.\n",
60 *offp + llen + 1, *offp + llen + 1, &buf[*offp + 1]);
61 return NULL;
62 }
63
64 rv->len = llen;
65 memcpy(rv->data, &buf[*offp + 1], llen);
66 rv->data[llen] = 0; // We NUL-terminate the label for convenience
67 *offp += llen + 1;
68 return rv;
69 }
70
71 bool
72 dns_name_parse(dns_label_t *NONNULL *NULLABLE ret, const uint8_t *buf, unsigned len,
73 unsigned *NONNULL offp, unsigned base)
74 {
75 dns_label_t *rv;
76
77 if (*offp == len) {
78 return false;
79 }
80
81 // A pointer?
82 if ((buf[*offp] & 0xC0) == 0xC0) {
83 unsigned pointer;
84 if (*offp + 2 > len) {
85 DEBUG("incomplete compression pointer: %u > %u", *offp + 2, len);
86 return false;
87 }
88 pointer = (((unsigned)buf[*offp] & 0x3f) << 8) | (unsigned)buf[*offp + 1];
89 *offp += 2;
90 if (pointer >= base) {
91 // Don't allow a pointer forward, or to a pointer we've already visited.
92 DEBUG("compression pointer points forward: %u >= %u.\n", pointer, base);
93 return false;
94 }
95 if (pointer < DNS_HEADER_SIZE) {
96 // Don't allow pointers into the header.
97 DEBUG("compression pointer points into header: %u.\n", pointer);
98 return false;
99 }
100 pointer -= DNS_HEADER_SIZE;
101 if (buf[pointer] & 0xC0) {
102 // If this is a pointer to a pointer, it's not valid.
103 DEBUG("compression pointer points into pointer: %u %02x%02x.\n", pointer,
104 buf[pointer], pointer + 1 < len ? buf[pointer + 1] : 0xFF);
105 return false;
106 }
107 if (buf[pointer] + pointer >= base || buf[pointer] + pointer >= *offp) {
108 // Possibly this isn't worth checking.
109 DEBUG("compression pointer points to something that goes past current position: %u %u\n",
110 pointer, buf[pointer]);
111 return false;
112 }
113 return dns_name_parse(ret, buf, len, &pointer, pointer);
114 }
115 // We don't support binary labels, which are historical, and at this time there are no other valid
116 // DNS label types.
117 if (buf[*offp] & 0xC0) {
118 DEBUG("invalid label type: %x\n", buf[*offp]);
119 return false;
120 }
121
122 rv = dns_label_parse(buf, len, offp);
123 if (rv == NULL) {
124 return false;
125 }
126
127 *ret = rv;
128
129 if (rv->len == 0) {
130 return true;
131 }
132 return dns_name_parse(&rv->next, buf, len, offp, base);
133 }
134
135 bool
136 dns_u8_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint8_t *NONNULL ret)
137 {
138 uint8_t rv;
139 if (*offp + 1 > len) {
140 DEBUG("dns_u8_parse: not enough room: %u > %u.\n", *offp + 1, len);
141 return false;
142 }
143
144 rv = buf[*offp];
145 *offp += 1;
146 *ret = rv;
147 return true;
148 }
149
150 bool
151 dns_u16_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint16_t *NONNULL ret)
152 {
153 uint16_t rv;
154 if (*offp + 2 > len) {
155 DEBUG("dns_u16_parse: not enough room: %u > %u.\n", *offp + 2, len);
156 return false;
157 }
158
159 rv = ((uint16_t)(buf[*offp]) << 8) | (uint16_t)(buf[*offp + 1]);
160 *offp += 2;
161 *ret = rv;
162 return true;
163 }
164
165 bool
166 dns_u32_parse(const uint8_t *buf, unsigned len, unsigned *NONNULL offp, uint32_t *NONNULL ret)
167 {
168 uint32_t rv;
169 if (*offp + 4 > len) {
170 DEBUG("dns_u32_parse: not enough room: %u > %u.\n", *offp + 4, len);
171 return false;
172 }
173
174 rv = (((uint32_t)(buf[*offp]) << 24) | ((uint32_t)(buf[*offp + 1]) << 16) |
175 ((uint32_t)(buf[*offp + 2]) << 8) | (uint32_t)(buf[*offp + 3]));
176 *offp += 4;
177 *ret = rv;
178 return true;
179 }
180
181 static void
182 dns_name_dump(FILE *outfile, dns_label_t *name)
183 {
184 char buf[DNS_MAX_NAME_SIZE_ESCAPED + 1];
185
186 dns_name_print(name, buf, sizeof buf);
187 fputs(buf, outfile);
188 }
189
190 static void
191 dns_rrdata_dump(FILE *outfile, dns_rr_t *rr)
192 {
193 int i;
194 char nbuf[80];
195 dns_txt_element_t *txt;
196
197 switch(rr->type) {
198 case dns_rrtype_key:
199 fprintf(outfile, "KEY <AC %d> <Z %d> <XT %d> <ZZ %d> <NAMTYPE %d> <ZZZZ %d> <ORY %d> %d %d ",
200 ((rr->data.key.flags & 0xC000) >> 14 & 3), ((rr->data.key.flags & 0x2000) >> 13) & 1,
201 ((rr->data.key.flags & 0x1000) >> 12) & 1, ((rr->data.key.flags & 0xC00) >> 10) & 3,
202 ((rr->data.key.flags & 0x300) >> 8) & 3, ((rr->data.key.flags & 0xF0) >> 4) & 15, rr->data.key.flags & 15,
203 rr->data.key.protocol, rr->data.key.algorithm);
204 for (i = 0; i < rr->data.key.len; i++) {
205 if (i == 0) {
206 fprintf(outfile, "%d [%02x", rr->data.key.len, rr->data.key.key[i]);
207 } else {
208 fprintf(outfile, " %02x", rr->data.key.key[i]);
209 }
210 }
211 fputc(']', outfile);
212 break;
213
214 case dns_rrtype_sig:
215 fprintf(outfile, "SIG %d %d %d %lu %lu %lu %d ",
216 rr->data.sig.type, rr->data.sig.algorithm, rr->data.sig.label,
217 (unsigned long)rr->data.sig.rrttl, (unsigned long)rr->data.sig.expiry,
218 (unsigned long)rr->data.sig.inception, rr->data.sig.key_tag);
219 dns_name_dump(outfile, rr->data.sig.signer);
220 for (i = 0; i < rr->data.sig.len; i++) {
221 if (i == 0) {
222 fprintf(outfile, "%d [%02x", rr->data.sig.len, rr->data.sig.signature[i]);
223 } else {
224 fprintf(outfile, " %02x", rr->data.sig.signature[i]);
225 }
226 }
227 fputc(']', outfile);
228 break;
229
230 case dns_rrtype_srv:
231 fprintf(outfile, "SRV %d %d %d ", rr->data.srv.priority, rr->data.srv.weight, rr->data.srv.port);
232 dns_name_dump(outfile, rr->data.ptr.name);
233 break;
234
235 case dns_rrtype_ptr:
236 fputs("PTR ", outfile);
237 dns_name_dump(outfile, rr->data.ptr.name);
238 break;
239
240 case dns_rrtype_cname:
241 fputs("CNAME ", outfile);
242 dns_name_dump(outfile, rr->data.ptr.name);
243 break;
244
245 case dns_rrtype_a:
246 fputs("A", outfile);
247 for (i = 0; i < rr->data.a.num; i++) {
248 inet_ntop(AF_INET, &rr->data.a.addrs[i], nbuf, sizeof nbuf);
249 putc(' ', outfile);
250 fputs(nbuf, outfile);
251 }
252 break;
253
254 case dns_rrtype_aaaa:
255 fputs("AAAA", outfile);
256 for (i = 0; i < rr->data.aaaa.num; i++) {
257 inet_ntop(AF_INET6, &rr->data.aaaa.addrs[i], nbuf, sizeof nbuf);
258 putc(' ', outfile);
259 fputs(nbuf, outfile);
260 }
261 break;
262
263 case dns_rrtype_txt:
264 fputs("TXT", outfile);
265 for (txt = rr->data.txt; txt; txt = txt->next) {
266 putc(' ', outfile);
267 putc('"', outfile);
268 for (i = 0; i < txt->len; i++) {
269 if (isascii(txt->data[i]) && isprint(txt->data[i])) {
270 putc(txt->data[i], outfile);
271 } else {
272 fprintf(outfile, "<%x>", txt->data[i]);
273 }
274 }
275 putc('"', outfile);
276 }
277 break;
278
279 default:
280 fprintf(outfile, "<rrtype %d>:", rr->type);
281 if (rr->data.unparsed.len == 0) {
282 fputs(" <none>", outfile);
283 } else {
284 for (i = 0; i < rr->data.unparsed.len; i++) {
285 fprintf(outfile, " %02x", rr->data.unparsed.data[i]);
286 }
287 }
288 break;
289 }
290 }
291
292 bool
293 dns_rdata_parse_data(dns_rr_t *NONNULL rr, const uint8_t *buf, unsigned *NONNULL offp, unsigned target, unsigned rdlen, unsigned rrstart)
294 {
295 uint16_t addrlen;
296 dns_txt_element_t *txt, **ptxt;
297
298 switch(rr->type) {
299 case dns_rrtype_key:
300 if (!dns_u16_parse(buf, target, offp, &rr->data.key.flags) ||
301 !dns_u8_parse(buf, target, offp, &rr->data.key.protocol) ||
302 !dns_u8_parse(buf, target, offp, &rr->data.key.algorithm)) {
303 return false;
304 }
305 rr->data.key.len = target - *offp;
306 rr->data.key.key = malloc(rr->data.key.len);
307 if (!rr->data.key.key) {
308 return false;
309 }
310 memcpy(rr->data.key.key, &buf[*offp], rr->data.key.len);
311 *offp += rr->data.key.len;
312 break;
313
314 case dns_rrtype_sig:
315 rr->data.sig.start = rrstart;
316 if (!dns_u16_parse(buf, target, offp, &rr->data.sig.type) ||
317 !dns_u8_parse(buf, target, offp, &rr->data.sig.algorithm) ||
318 !dns_u8_parse(buf, target, offp, &rr->data.sig.label) ||
319 !dns_u32_parse(buf, target, offp, &rr->data.sig.rrttl) ||
320 !dns_u32_parse(buf, target, offp, &rr->data.sig.expiry) ||
321 !dns_u32_parse(buf, target, offp, &rr->data.sig.inception) ||
322 !dns_u16_parse(buf, target, offp, &rr->data.sig.key_tag) ||
323 !dns_name_parse(&rr->data.sig.signer, buf, target, offp, *offp)) {
324 return false;
325 }
326 // The signature is what's left of the RRDATA. It covers the message up to the signature, so we
327 // remember where it starts so as to know what memory to cover to validate it.
328 rr->data.sig.len = target - *offp;
329 rr->data.sig.signature = malloc(rr->data.sig.len);
330 if (!rr->data.sig.signature) {
331 return false;
332 }
333 memcpy(rr->data.sig.signature, &buf[*offp], rr->data.sig.len);
334 *offp += rr->data.sig.len;
335 break;
336
337 case dns_rrtype_srv:
338 if (!dns_u16_parse(buf, target, offp, &rr->data.srv.priority) ||
339 !dns_u16_parse(buf, target, offp, &rr->data.srv.weight) ||
340 !dns_u16_parse(buf, target, offp, &rr->data.srv.port)) {
341 return false;
342 }
343 // This fallthrough assumes that the first element in the srv, ptr and cname structs is
344 // a pointer to a domain name.
345
346 case dns_rrtype_ptr:
347 case dns_rrtype_cname:
348 if (!dns_name_parse(&rr->data.ptr.name, buf, target, offp, *offp)) {
349 return false;
350 }
351 break;
352
353 // We assume below that the a and aaaa structures in the data union are exact aliases of
354 // each another.
355 case dns_rrtype_a:
356 addrlen = 4;
357 goto addr_parse;
358
359 case dns_rrtype_aaaa:
360 addrlen = 16;
361 addr_parse:
362 if (rdlen & (addrlen - 1)) {
363 DEBUG("dns_rdata_parse: %s rdlen not an even multiple of %u: %u",
364 addrlen == 4 ? "A" : "AAAA", addrlen, rdlen);
365 return false;
366 }
367 rr->data.a.addrs = malloc(rdlen);
368 if (rr->data.a.addrs == NULL) {
369 return false;
370 }
371 rr->data.a.num = rdlen / addrlen;
372 memcpy(rr->data.a.addrs, &buf[*offp], rdlen);
373 *offp = target;
374 break;
375
376 case dns_rrtype_txt:
377 ptxt = &rr->data.txt;
378 while (*offp < target) {
379 unsigned tlen = buf[*offp];
380 if (*offp + tlen + 1 > target) {
381 DEBUG("dns_rdata_parse: TXT RR length is larger than available space: %u %u",
382 *offp + tlen + 1, target);
383 *ptxt = NULL;
384 return false;
385 }
386 txt = malloc(tlen + 1 + sizeof *txt);
387 if (txt == NULL) {
388 DEBUG("dns_rdata_parse: no memory for TXT RR");
389 return false;
390 }
391 txt->len = tlen;
392 ++*offp;
393 memcpy(txt->data, &buf[*offp], tlen);
394 *offp += tlen;
395 txt->data[tlen] = 0;
396 *ptxt = txt;
397 ptxt = &txt->next;
398 }
399 break;
400
401 default:
402 if (rdlen > 0) {
403 rr->data.unparsed.data = malloc(rdlen);
404 if (rr->data.unparsed.data == NULL) {
405 return false;
406 }
407 memcpy(rr->data.unparsed.data, &buf[*offp], rdlen);
408 }
409 rr->data.unparsed.len = rdlen;
410 *offp = target;
411 break;
412 }
413 if (*offp != target) {
414 DEBUG("dns_rdata_parse: parse for rrtype %d not fully contained: %u %u", rr->type, target, *offp);
415 return false;
416 }
417 return true;
418 }
419
420 static bool
421 dns_rdata_parse(dns_rr_t *NONNULL rr,
422 const uint8_t *buf, unsigned len, unsigned *NONNULL offp, unsigned rrstart)
423 {
424 uint16_t rdlen;
425 unsigned target;
426
427 if (!dns_u16_parse(buf, len, offp, &rdlen)) {
428 return false;
429 }
430 target = *offp + rdlen;
431 if (target > len) {
432 return false;
433 }
434 return dns_rdata_parse_data(rr, buf, offp, target, rdlen, rrstart);
435 }
436
437 bool
438 dns_rr_parse(dns_rr_t *NONNULL rr,
439 const uint8_t *buf, unsigned len, unsigned *NONNULL offp, bool rrdata_expected)
440 {
441 int rrstart = *offp; // Needed to mark the start of the SIG RR for SIG(0).
442 memset(rr, 0, sizeof *rr);
443 if (!dns_name_parse(&rr->name, buf, len, offp, *offp)) {
444 return false;
445 }
446
447 if (!dns_u16_parse(buf, len, offp, &rr->type)) {
448 return false;
449 }
450
451 if (!dns_u16_parse(buf, len, offp, &rr->qclass)) {
452 return false;
453 }
454
455 if (rrdata_expected) {
456 if (!dns_u32_parse(buf, len, offp, &rr->ttl)) {
457 return false;
458 }
459 if (!dns_rdata_parse(rr, buf, len, offp, rrstart)) {
460 return false;
461 }
462 }
463
464 printf("rrtype: %u qclass: %u name: ", rr->type, rr->qclass);
465 dns_name_dump(stdout, rr->name);
466 if (rrdata_expected) {
467 printf(" rrdata: ");
468 dns_rrdata_dump(stdout, rr);
469 }
470 printf("\n");
471 return true;
472 }
473
474 void dns_name_free(dns_label_t *name)
475 {
476 dns_label_t *next;
477 if (name == NULL) {
478 return;
479 }
480 next = name->next;
481 free(name);
482 return dns_name_free(next);
483 }
484
485 void
486 dns_rrdata_free(dns_rr_t *rr)
487 {
488 switch(rr->type) {
489 case dns_rrtype_key:
490 free(rr->data.key.key);
491 break;
492
493 case dns_rrtype_sig:
494 dns_name_free(rr->data.sig.signer);
495 free(rr->data.sig.signature);
496 break;
497
498 case dns_rrtype_srv:
499 case dns_rrtype_ptr:
500 case dns_rrtype_cname:
501 dns_name_free(rr->data.ptr.name);
502 rr->data.ptr.name = NULL;
503 break;
504
505 case dns_rrtype_a:
506 case dns_rrtype_aaaa:
507 free(rr->data.a.addrs);
508 rr->data.a.addrs = NULL;
509 break;
510
511 case dns_rrtype_txt:
512 default:
513 free(rr->data.unparsed.data);
514 rr->data.unparsed.data = NULL;
515 break;
516 }
517 }
518
519 void
520 dns_message_free(dns_message_t *message)
521 {
522 int i;
523
524 #define FREE(count, sets) \
525 for (i = 0; i < message->count; i++) { \
526 dns_rr_t *set = &message->sets[i]; \
527 if (set->name) { \
528 dns_name_free(set->name); \
529 set->name = NULL; \
530 } \
531 dns_rrdata_free(set); \
532 } \
533 if (message->sets) { \
534 free(message->sets); \
535 }
536 FREE(qdcount, questions);
537 FREE(ancount, answers);
538 FREE(nscount, authority);
539 FREE(arcount, additional);
540 #undef FREE
541 }
542
543 bool
544 dns_wire_parse(dns_message_t *NONNULL *NULLABLE ret, dns_wire_t *message, unsigned len)
545 {
546 unsigned offset = 0;
547 dns_message_t *rv = calloc(sizeof *rv, 1);
548 int i;
549
550 if (rv == NULL) {
551 return false;
552 }
553
554 #define PARSE(count, sets, name, rrdata_expected) \
555 rv->count = ntohs(message->count); \
556 if (rv->count > 50) { \
557 dns_message_free(rv); \
558 return false; \
559 } \
560 \
561 if (rv->qdcount != 0) { \
562 rv->sets = calloc(sizeof *rv->sets, rv->count); \
563 if (rv->sets == NULL) { \
564 dns_message_free(rv); \
565 return false; \
566 } \
567 } \
568 \
569 for (i = 0; i < rv->count; i++) { \
570 if (!dns_rr_parse(&rv->sets[i], message->data, len, &offset, rrdata_expected)) { \
571 dns_message_free(rv); \
572 fprintf(stderr, name " %d RR parse failed.\n", i); \
573 return false; \
574 } \
575 }
576 PARSE(qdcount, questions, "question", false);
577 PARSE(ancount, answers, "answers", true);
578 PARSE(nscount, authority, "authority", true);
579 PARSE(arcount, additional, "additional", true);
580 #undef PARSE
581
582 for (i = 0; i < rv->ancount; i++) {
583 // Parse EDNS(0)
584 if (rv->additional[i].type == dns_rrtype_opt) {
585 if (!dns_opt_parse(&rv->edns0, &rv->additional[i])) {
586 dns_message_free(rv);
587 return false;
588 }
589 }
590 }
591 *ret = rv;
592 return true;
593 }
594
595 const char *NONNULL
596 dns_name_print(dns_name_t *NONNULL name, char *buf, int bufmax)
597 {
598 dns_label_t *lp;
599 int ix = 0;
600 int i;
601
602 // Copy the labels in one at a time, putting a dot between each one; if there isn't room
603 // in the buffer (shouldn't be the case), copy as much as will fit, leaving room for a NUL
604 // termination.
605 for (lp = name; lp; lp = lp->next) {
606 if (ix != 0) {
607 if (ix + 2 >= bufmax) {
608 break;
609 }
610 buf[ix++] = '.';
611 }
612 for (i = 0; i < lp->len; i++) {
613 if (isascii(lp->data[i]) && isprint(lp->data[i])) {
614 if (ix + 2 >= bufmax) {
615 break;
616 }
617 buf[ix++] = lp->data[i];
618 } else {
619 if (ix + 5 >= bufmax) {
620 break;
621 }
622 buf[ix++] = '\\';
623 buf[ix++] = '0' + (lp->data[i] >> 6);
624 buf[ix++] = '0' + (lp->data[i] >> 3) & 3;
625 buf[ix++] = '0' + lp->data[i] & 3;
626 }
627 }
628 if (i != lp->len) {
629 break;
630 }
631 }
632 buf[ix++] = 0;
633 return buf;
634 }
635
636 bool
637 labeleq(const char *label1, const char *label2, size_t len)
638 {
639 int i;
640 for (i = 0; i < len; i++) {
641 if (isascii(label1[i]) && isascii(label2[i])) {
642 if (tolower(label1[i]) != tolower(label2[i])) {
643 return false;
644 }
645 }
646 else {
647 if (label1[i] != label2[i]) {
648 return false;
649 }
650 }
651 }
652 return true;
653 }
654
655 bool
656 dns_names_equal(dns_label_t *NONNULL name1, dns_label_t *NONNULL name2)
657 {
658 if (name1->len != name2->len) {
659 return false;
660 }
661 if (name1->len != 0 && !labeleq(name1->data, name2->data, name1->len) != 0) {
662 return false;
663 }
664 if (name1->next != NULL && name2->next != NULL) {
665 return dns_names_equal(name1->next, name2->next);
666 }
667 if (name1->next == NULL && name2->next == NULL) {
668 return true;
669 }
670 return false;
671 }
672
673 // Note that "foo.arpa" is not the same as "foo.arpa."
674 bool
675 dns_names_equal_text(dns_label_t *NONNULL name1, const char *NONNULL name2)
676 {
677 const char *ndot;
678 ndot = strchr(name2, '.');
679 if (ndot == NULL) {
680 ndot = name2 + strlen(name2);
681 }
682 if (name1->len != ndot - name2) {
683 return false;
684 }
685 if (name1->len != 0 && !labeleq(name1->data, name2, name1->len) != 0) {
686 return false;
687 }
688 if (name1->next != NULL && *ndot == '.') {
689 return dns_names_equal_text(name1->next, ndot + 1);
690 }
691 if (name1->next == NULL && *ndot == 0) {
692 return true;
693 }
694 return false;
695 }
696
697 // Find the length of a name in uncompressed wire format.
698 // This is in fromwire because we use it for validating signatures, and don't need it for
699 // sending.
700 static size_t
701 dns_name_wire_length_in(dns_label_t *NONNULL name, size_t ret)
702 {
703 // Root label.
704 if (name == NULL)
705 return ret;
706 return dns_name_wire_length_in(name->next, ret + name->len + 1);
707 }
708
709 size_t
710 dns_name_wire_length(dns_label_t *NONNULL name)
711 {
712 return dns_name_wire_length_in(name, 0);
713 }
714
715 // Copy a name we've parsed from a message out in canonical wire format so that we can
716 // use it to verify a signature. As above, not actually needed for copying to a message
717 // we're going to send, since in that case we want to try to compress.
718 static size_t
719 dns_name_to_wire_canonical_in(uint8_t *NONNULL buf, size_t max, size_t ret, dns_label_t *NONNULL name)
720 {
721 INFO("dns_name_to_wire_canonical_in: buf %p max %zd ret %zd name = %p '%.*s'",
722 buf, max, ret, name, name ? name->len : 0, name ? name->data : "");
723 if (name == NULL) {
724 return ret;
725 }
726 if (max < name->len + 1) {
727 return 0;
728 }
729 *buf = name->len;
730 memcpy(buf + 1, name->data, name->len);
731 return dns_name_to_wire_canonical_in(buf + name->len + 1,
732 max - name->len - 1, ret + name->len + 1, name->next);
733 }
734
735 size_t
736 dns_name_to_wire_canonical(uint8_t *NONNULL buf, size_t max, dns_label_t *NONNULL name)
737 {
738 return dns_name_to_wire_canonical_in(buf, max, 0, name);
739 }
740
741
742
743 // Local Variables:
744 // mode: C
745 // tab-width: 4
746 // c-file-style: "bsd"
747 // c-basic-offset: 4
748 // fill-column: 108
749 // indent-tabs-mode: nil
750 // End: