3 * Copyright (c) 2018, 2019 Apple Computer, Inc. All rights reserved.
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * DNS wire-format functions.
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.
32 #include <sys/socket.h>
33 #include <arpa/inet.h>
40 dns_opt_parse(dns_edns0_t
*NONNULL
*NULLABLE ret
, dns_rr_t
*rr
)
42 dns_edns0_t
*edns0
, **p_edns0
= ret
;
44 dns_rdata_unparsed_t opt
;
46 // This would be a weird coding error.
47 if (rr
->type
!= dns_rrtype_opt
) {
50 opt
= rr
->data
.unparsed
;
52 // RDATA is a series of TLVs
53 while (offset
< opt
.len
) {
54 uint16_t tlv_type
, tlv_len
;
56 // Parse the TLV type and length.
57 if (!dns_u16_parse(opt
.data
, opt
.len
, &offset
, &tlv_type
) ||
58 !dns_u16_parse(opt
.data
, opt
.len
, &offset
, &tlv_len
))
63 // Range check the contents.
64 if (offset
+ tlv_len
> opt
.len
) {
68 edns0
= calloc(1, tlv_len
+ sizeof(*edns0
));
73 edns0
->length
= tlv_len
;
74 edns0
->type
= tlv_type
;
75 memcpy(edns0
->data
, &opt
.data
[offset
], tlv_len
);
77 p_edns0
= &edns0
->next
;
83 dns_label_t
* NULLABLE
84 dns_label_parse(const uint8_t *buf
, unsigned mlen
, unsigned *NONNULL offp
)
86 uint8_t llen
= buf
[*offp
];
89 // Make sure that we got the data this label claims to encompass.
90 if (*offp
+ llen
+ 1 > mlen
) {
91 DEBUG("claimed length of label is too long: %u > %u.\n", *offp
+ llen
+ 1, mlen
);
95 rv
= calloc(1, (sizeof(*rv
) - DNS_MAX_LABEL_SIZE
) + llen
+ 1);
97 DEBUG("memory allocation for %u byte label (%.*s) failed.\n",
98 *offp
+ llen
+ 1, *offp
+ llen
+ 1, &buf
[*offp
+ 1]);
103 memcpy(rv
->data
, &buf
[*offp
+ 1], llen
);
104 rv
->data
[llen
] = 0; // We NUL-terminate the label for convenience
110 dns_name_parse_in(dns_label_t
*NONNULL
*NULLABLE ret
, const uint8_t *buf
, unsigned len
,
111 unsigned *NONNULL offp
, unsigned base
)
120 if ((buf
[*offp
] & 0xC0) == 0xC0) {
122 if (*offp
+ 2 > len
) {
123 DEBUG("incomplete compression pointer: %u > %u", *offp
+ 2, len
);
126 pointer
= (((unsigned)buf
[*offp
] & 0x3f) << 8) | (unsigned)buf
[*offp
+ 1];
128 if (pointer
< DNS_HEADER_SIZE
) {
129 // Don't allow pointers into the header.
130 DEBUG("compression pointer points into header: %u.\n", pointer
);
133 pointer
-= DNS_HEADER_SIZE
;
134 if (pointer
>= base
) {
135 // Don't allow a pointer forward, or to a pointer we've already visited.
136 DEBUG("compression pointer points forward: %u >= %u.\n", pointer
, base
);
139 if (buf
[pointer
] & 0xC0) {
140 // If this is a pointer to a pointer, it's not valid.
141 DEBUG("compression pointer points into pointer: %u %02x%02x.\n", pointer
,
142 buf
[pointer
], pointer
+ 1 < len
? buf
[pointer
+ 1] : 0xFF);
145 if (buf
[pointer
] + pointer
>= base
|| buf
[pointer
] + pointer
>= *offp
) {
146 // Possibly this isn't worth checking.
147 DEBUG("compression pointer points to something that goes past current position: %u %u\n",
148 pointer
, buf
[pointer
]);
151 return dns_name_parse_in(ret
, buf
, len
, &pointer
, pointer
);
153 // We don't support binary labels, which are historical, and at this time there are no other valid
155 if (buf
[*offp
] & 0xC0) {
156 DEBUG("invalid label type: %x\n", buf
[*offp
]);
160 rv
= dns_label_parse(buf
, len
, offp
);
170 return dns_name_parse_in(&rv
->next
, buf
, len
, offp
, base
);
174 dns_name_parse(dns_label_t
*NONNULL
*NULLABLE ret
, const uint8_t *buf
,
175 unsigned len
, unsigned *NONNULL offp
, unsigned base
)
177 dns_label_t
*rv
= NULL
, *next
;
179 if (!dns_name_parse_in(&rv
, buf
, len
, offp
, base
)) {
180 for (; rv
!= NULL
; rv
= next
) {
191 dns_u8_parse(const uint8_t *buf
, unsigned len
, unsigned *NONNULL offp
, uint8_t *NONNULL ret
)
194 if (*offp
+ 1 > len
) {
195 DEBUG("dns_u8_parse: not enough room: %u > %u.\n", *offp
+ 1, len
);
206 dns_u16_parse(const uint8_t *buf
, unsigned len
, unsigned *NONNULL offp
, uint16_t *NONNULL ret
)
209 if (*offp
+ 2 > len
) {
210 DEBUG("dns_u16_parse: not enough room: %u > %u.\n", *offp
+ 2, len
);
214 rv
= ((uint16_t)(buf
[*offp
]) << 8) | (uint16_t)(buf
[*offp
+ 1]);
221 dns_u32_parse(const uint8_t *buf
, unsigned len
, unsigned *NONNULL offp
, uint32_t *NONNULL ret
)
224 if (*offp
+ 4 > len
) {
225 DEBUG("dns_u32_parse: not enough room: %u > %u.\n", *offp
+ 4, len
);
229 rv
= (((uint32_t)(buf
[*offp
]) << 24) | ((uint32_t)(buf
[*offp
+ 1]) << 16) |
230 ((uint32_t)(buf
[*offp
+ 2]) << 8) | (uint32_t)(buf
[*offp
+ 3]));
237 dns_rrdata_dump(dns_rr_t
*rr
)
240 char nbuf
[INET6_ADDRSTRLEN
];
241 char buf
[DNS_MAX_NAME_SIZE_ESCAPED
+ 1];
244 ssize_t output_len
, avail
= 2048;
246 #define ADVANCE(result, start, remaining) \
247 output_len = strlen(start); \
248 result = start + output_len; \
249 avail = (remaining) - output_len
250 #define DEPCHAR(ch) \
262 snprintf(outbuf
, sizeof(outbuf
),
263 "KEY <AC %d> <Z %d> <XT %d> <ZZ %d> <NAMTYPE %d> <ZZZZ %d> <ORY %d> %d %d ",
264 ((rr
->data
.key
.flags
& 0xC000) >> 14 & 3), ((rr
->data
.key
.flags
& 0x2000) >> 13) & 1,
265 ((rr
->data
.key
.flags
& 0x1000) >> 12) & 1, ((rr
->data
.key
.flags
& 0xC00) >> 10) & 3,
266 ((rr
->data
.key
.flags
& 0x300) >> 8) & 3, ((rr
->data
.key
.flags
& 0xF0) >> 4) & 15,
267 rr
->data
.key
.flags
& 15, rr
->data
.key
.protocol
, rr
->data
.key
.algorithm
);
268 ADVANCE(obp
, outbuf
, sizeof outbuf
);
270 for (i
= 0; i
< rr
->data
.key
.len
; i
++) {
272 snprintf(obp
, avail
, "%d [%02x", rr
->data
.key
.len
, rr
->data
.key
.key
[i
]);
273 ADVANCE(obp
, obp
, avail
);
275 snprintf(obp
, avail
, " %02x", rr
->data
.key
.key
[i
]);
276 ADVANCE(obp
, obp
, avail
);
283 dns_name_print(rr
->data
.sig
.signer
, buf
, sizeof(buf
));
284 snprintf(outbuf
, sizeof(outbuf
), "SIG %d %d %d %lu %lu %lu %d %s",
285 rr
->data
.sig
.type
, rr
->data
.sig
.algorithm
, rr
->data
.sig
.label
,
286 (unsigned long)rr
->data
.sig
.rrttl
, (unsigned long)rr
->data
.sig
.expiry
,
287 (unsigned long)rr
->data
.sig
.inception
, rr
->data
.sig
.key_tag
, buf
);
288 ADVANCE(obp
, outbuf
, sizeof outbuf
);
289 for (i
= 0; i
< rr
->data
.sig
.len
; i
++) {
291 snprintf(obp
, avail
, "%d [%02x", rr
->data
.sig
.len
, rr
->data
.sig
.signature
[i
]);
292 ADVANCE(obp
, obp
, avail
);
294 snprintf(obp
, avail
, " %02x", rr
->data
.sig
.signature
[i
]);
295 ADVANCE(obp
, obp
, avail
);
302 dns_name_print(rr
->data
.srv
.name
, buf
, sizeof(buf
));
303 snprintf(outbuf
, sizeof(outbuf
), "SRV %d %d %d %s", rr
->data
.srv
.priority
, rr
->data
.srv
.weight
,
304 rr
->data
.srv
.port
, buf
);
305 ADVANCE(obp
, outbuf
, sizeof(outbuf
));
309 dns_name_print(rr
->data
.ptr
.name
, buf
, sizeof(buf
));
310 snprintf(outbuf
, sizeof(outbuf
), "PTR %s", buf
);
311 ADVANCE(obp
, outbuf
, sizeof(outbuf
));
314 case dns_rrtype_cname
:
315 dns_name_print(rr
->data
.cname
.name
, buf
, sizeof(buf
));
316 snprintf(outbuf
, sizeof(outbuf
), "CNAME %s", buf
);
317 ADVANCE(obp
, outbuf
, sizeof(outbuf
));
321 inet_ntop(AF_INET
, &rr
->data
.a
, nbuf
, sizeof(nbuf
));
322 snprintf(outbuf
, sizeof(outbuf
), "A %s", nbuf
);
323 ADVANCE(obp
, outbuf
, sizeof(outbuf
));
326 case dns_rrtype_aaaa
:
327 inet_ntop(AF_INET6
, &rr
->data
.aaaa
, nbuf
, sizeof(nbuf
));
328 snprintf(outbuf
, sizeof(outbuf
), "AAAA %s", nbuf
);
329 ADVANCE(obp
, outbuf
, sizeof(outbuf
));
333 strcpy(outbuf
, "TXT ");
334 ADVANCE(obp
, outbuf
, sizeof(outbuf
));
335 for (i
= 0; i
< rr
->data
.txt
.len
; i
++) {
336 if (isascii(rr
->data
.txt
.data
[i
]) && isprint(rr
->data
.txt
.data
[i
])) {
337 DEPCHAR(rr
->data
.txt
.data
[i
]);
339 snprintf(obp
, avail
, "<%x>", rr
->data
.txt
.data
[i
]);
340 ADVANCE(obp
, obp
, avail
);
347 snprintf(outbuf
, sizeof(outbuf
), "<rrtype %d>:", rr
->type
);
348 ADVANCE(obp
, outbuf
, sizeof(outbuf
));
349 if (rr
->data
.unparsed
.len
== 0) {
350 snprintf(obp
, avail
, " <none>");
351 ADVANCE(obp
, obp
, avail
);
353 for (i
= 0; i
< rr
->data
.unparsed
.len
; i
++) {
354 snprintf(obp
, avail
, " %02x", rr
->data
.unparsed
.data
[i
]);
355 ADVANCE(obp
, obp
, avail
);
360 DEBUG(PUB_S_SRP
, outbuf
);
364 dns_rdata_parse_data(dns_rr_t
*NONNULL rr
, const uint8_t *buf
, unsigned *NONNULL offp
, unsigned target
, unsigned rdlen
,
369 if (!dns_u16_parse(buf
, target
, offp
, &rr
->data
.key
.flags
) ||
370 !dns_u8_parse(buf
, target
, offp
, &rr
->data
.key
.protocol
) ||
371 !dns_u8_parse(buf
, target
, offp
, &rr
->data
.key
.algorithm
)) {
374 rr
->data
.key
.len
= target
- *offp
;
375 rr
->data
.key
.key
= malloc(rr
->data
.key
.len
);
376 if (!rr
->data
.key
.key
) {
379 memcpy(rr
->data
.key
.key
, &buf
[*offp
], rr
->data
.key
.len
);
380 *offp
+= rr
->data
.key
.len
;
384 rr
->data
.sig
.start
= rrstart
;
385 if (!dns_u16_parse(buf
, target
, offp
, &rr
->data
.sig
.type
) ||
386 !dns_u8_parse(buf
, target
, offp
, &rr
->data
.sig
.algorithm
) ||
387 !dns_u8_parse(buf
, target
, offp
, &rr
->data
.sig
.label
) ||
388 !dns_u32_parse(buf
, target
, offp
, &rr
->data
.sig
.rrttl
) ||
389 !dns_u32_parse(buf
, target
, offp
, &rr
->data
.sig
.expiry
) ||
390 !dns_u32_parse(buf
, target
, offp
, &rr
->data
.sig
.inception
) ||
391 !dns_u16_parse(buf
, target
, offp
, &rr
->data
.sig
.key_tag
) ||
392 !dns_name_parse(&rr
->data
.sig
.signer
, buf
, target
, offp
, *offp
)) {
395 // The signature is what's left of the RRDATA. It covers the message up to the signature, so we
396 // remember where it starts so as to know what memory to cover to validate it.
397 rr
->data
.sig
.len
= target
- *offp
;
398 rr
->data
.sig
.signature
= malloc(rr
->data
.sig
.len
);
399 if (!rr
->data
.sig
.signature
) {
402 memcpy(rr
->data
.sig
.signature
, &buf
[*offp
], rr
->data
.sig
.len
);
403 *offp
+= rr
->data
.sig
.len
;
407 if (!dns_u16_parse(buf
, target
, offp
, &rr
->data
.srv
.priority
) ||
408 !dns_u16_parse(buf
, target
, offp
, &rr
->data
.srv
.weight
) ||
409 !dns_u16_parse(buf
, target
, offp
, &rr
->data
.srv
.port
)) {
412 // This fallthrough assumes that the first element in the srv, ptr and cname structs is
413 // a pointer to a domain name.
417 case dns_rrtype_cname
:
418 if (!dns_name_parse(&rr
->data
.ptr
.name
, buf
, target
, offp
, *offp
)) {
425 DEBUG("dns_rdata_parse: A rdlen is not 4: %u", rdlen
);
428 memcpy(&rr
->data
.a
, &buf
[*offp
], rdlen
);
432 case dns_rrtype_aaaa
:
434 DEBUG("dns_rdata_parse: AAAA rdlen is not 16: %u", rdlen
);
437 memcpy(&rr
->data
.aaaa
, &buf
[*offp
], rdlen
);
442 rr
->data
.txt
.len
= target
- *offp
;
443 rr
->data
.txt
.data
= malloc(rr
->data
.txt
.len
);
444 if (rr
->data
.txt
.data
== NULL
) {
445 DEBUG("dns_rdata_parse: no memory for TXT RR");
448 memcpy(rr
->data
.txt
.data
, &buf
[*offp
], rr
->data
.txt
.len
);
454 rr
->data
.unparsed
.data
= malloc(rdlen
);
455 if (rr
->data
.unparsed
.data
== NULL
) {
458 memcpy(rr
->data
.unparsed
.data
, &buf
[*offp
], rdlen
);
460 rr
->data
.unparsed
.len
= rdlen
;
464 if (*offp
!= target
) {
465 DEBUG("dns_rdata_parse: parse for rrtype %d not fully contained: %u %u", rr
->type
, target
, *offp
);
472 dns_rdata_parse(dns_rr_t
*NONNULL rr
,
473 const uint8_t *buf
, unsigned len
, unsigned *NONNULL offp
, unsigned rrstart
)
478 if (!dns_u16_parse(buf
, len
, offp
, &rdlen
)) {
481 target
= *offp
+ rdlen
;
485 return dns_rdata_parse_data(rr
, buf
, offp
, target
, rdlen
, rrstart
);
489 dns_rr_parse(dns_rr_t
*NONNULL rr
,
490 const uint8_t *buf
, unsigned len
, unsigned *NONNULL offp
, bool rrdata_expected
)
492 int rrstart
= *offp
; // Needed to mark the start of the SIG RR for SIG(0).
494 memset(rr
, 0, sizeof(*rr
));
495 if (!dns_name_parse(&rr
->name
, buf
, len
, offp
, *offp
)) {
499 if (!dns_u16_parse(buf
, len
, offp
, &rr
->type
)) {
503 if (!dns_u16_parse(buf
, len
, offp
, &rr
->qclass
)) {
507 if (rrdata_expected
) {
508 if (!dns_u32_parse(buf
, len
, offp
, &rr
->ttl
)) {
511 if (!dns_rdata_parse(rr
, buf
, len
, offp
, rrstart
)) {
516 DNS_NAME_GEN_SRP(rr
->name
, name_buf
);
517 DEBUG("rrtype: %u qclass: %u name: " PRI_DNS_NAME_SRP PUB_S_SRP
,
518 rr
->type
, rr
->qclass
, DNS_NAME_PARAM_SRP(rr
->name
, name_buf
), rrdata_expected
? " rrdata:" : "");
519 if (rrdata_expected
) {
526 dns_rrdata_free(dns_rr_t
*rr
)
530 case dns_rrtype_aaaa
:
534 free(rr
->data
.key
.key
);
538 dns_name_free(rr
->data
.sig
.signer
);
539 free(rr
->data
.sig
.signature
);
544 case dns_rrtype_cname
:
545 dns_name_free(rr
->data
.ptr
.name
);
546 #ifndef __clang_analyzer__
547 rr
->data
.ptr
.name
= NULL
;
552 free(rr
->data
.txt
.data
);
553 #ifndef __clang_analyzer__
554 rr
->data
.txt
.data
= NULL
;
559 if (rr
->data
.unparsed
.len
> 0 && rr
->data
.unparsed
.data
!= NULL
) {
560 free(rr
->data
.unparsed
.data
);
562 rr
->data
.unparsed
.data
= NULL
;
567 dns_message_free(dns_message_t
*message
)
570 dns_edns0_t
*edns0
, *next
;
572 #define FREE(count, sets) \
573 if (message->sets) { \
574 for (i = 0; i < message->count; i++) { \
575 dns_rr_t *set = &message->sets[i]; \
577 dns_name_free(set->name); \
579 dns_rrdata_free(set); \
581 free(message->sets); \
583 FREE(qdcount
, questions
);
584 FREE(ancount
, answers
);
585 FREE(nscount
, authority
);
586 FREE(arcount
, additional
);
588 for (edns0
= message
->edns0
; edns0
!= NULL
; edns0
= next
) {
596 dns_wire_parse(dns_message_t
*NONNULL
*NULLABLE ret
, dns_wire_t
*message
, unsigned len
)
599 unsigned data_len
= len
- DNS_HEADER_SIZE
;
600 dns_message_t
*rv
= calloc(1, sizeof(*rv
));
607 #define PARSE(count, sets, name, rrdata_expected) \
608 rv->count = ntohs(message->count); \
609 if (rv->count > 50) { \
611 dns_message_free(rv); \
614 DEBUG("Section %s, %d records", name, rv->count); \
616 if (rv->count != 0) { \
617 rv->sets = calloc(rv->count, sizeof(*rv->sets)); \
618 if (rv->sets == NULL) { \
619 dns_message_free(rv); \
624 for (i = 0; i < rv->count; i++) { \
625 if (!dns_rr_parse(&rv->sets[i], message->data, data_len, &offset, rrdata_expected)) { \
626 dns_message_free(rv); \
627 ERROR(name " %d RR parse failed.\n", i); \
631 PARSE(qdcount
, questions
, "question", false);
632 PARSE(ancount
, answers
, "answers", true);
633 PARSE(nscount
, authority
, "authority", true);
634 PARSE(arcount
, additional
, "additional", true);
637 for (i
= 0; i
< rv
->arcount
; i
++) {
639 if (rv
->additional
[i
].type
== dns_rrtype_opt
) {
640 if (!dns_opt_parse(&rv
->edns0
, &rv
->additional
[i
])) {
641 dns_message_free(rv
);
653 // c-file-style: "bsd"
656 // indent-tabs-mode: nil