3 * Copyright (c) 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 utility functions.
19 * Functions that are neither necessary for very simple DNS packet generation, nor required for parsing
20 * a message, e.g. compression, name printing, etc.
27 #include <sys/socket.h>
28 #include <arpa/inet.h>
34 #include "mDNSEmbeddedAPI.h"
35 #include "DNSCommon.h"
40 // We need the compression routines from DNSCommon.c, but we can't link to it because that
41 // pulls in a _lot_ of stuff we don't want. The solution? Define STANDALONE (this is done
42 // in the Makefile, and include DNSCommon.c.
44 // The only functions that aren't excluded by STANDALONE are FindCompressionPointer and
45 // putDomainNameAsLabels.
48 #include "../mDNSCore/DNSCommon.c"
50 void dns_name_free(dns_label_t
*name
)
59 return dns_name_free(next
);
64 dns_name_copy(dns_name_t
*original
)
66 dns_name_t
*ret
= NULL
, **cur
= &ret
;
69 for (next
= original
; next
; next
= next
->next
) {
70 *cur
= calloc(1, 1 + next
->len
+ (sizeof (dns_name_t
)) - DNS_MAX_LABEL_SIZE
);
78 memcpy((*cur
)->data
, next
->data
, next
->len
+ 1);
80 (*cur
)->len
= next
->len
;
81 cur
= &((*cur
)->next
);
86 // Needed for TSIG (RFC2845).
88 dns_u48_to_wire_(dns_towire_state_t
*NONNULL txn
,
89 uint64_t val
, int line
)
92 if (txn
->p
+ 6 >= txn
->lim
) {
94 txn
->truncated
= true;
98 *txn
->p
++ = (val
>> 40) & 0xff;
99 *txn
->p
++ = (val
>> 32) & 0xff;
100 *txn
->p
++ = (val
>> 24) & 0xff;
101 *txn
->p
++ = (val
>> 16) & 0xff;
102 *txn
->p
++ = (val
>> 8) & 0xff;
103 *txn
->p
++ = val
& 0xff;
108 dns_concatenate_name_to_wire_(dns_towire_state_t
*towire
, dns_name_t
*labels_prefix
, const char *prefix
,
109 const char *suffix
, int line
)
112 dns_towire_state_t namewire
;
116 // Don't do all this work if we're already past an error.
120 memset(&namewire
, 0, sizeof namewire
);
121 namewire
.message
= &namebuf
;
122 namewire
.lim
= &namebuf
.data
[DNS_DATA_SIZE
];
123 namewire
.p
= namebuf
.data
;
124 if (prefix
!= NULL
) {
125 dns_name_to_wire(NULL
, &namewire
, prefix
);
126 } else if (labels_prefix
!= NULL
) {
127 size_t bytes_written
;
129 if (!namewire
.error
) {
130 bytes_written
= namewire
.lim
- namewire
.p
;
131 if (bytes_written
> INT16_MAX
) {
132 towire
->error
= true;
133 towire
->line
= __LINE__
;
136 bytes_written
= dns_name_to_wire_canonical(namewire
.p
, (int)bytes_written
, labels_prefix
);
137 // This can never occur with a valid name.
138 if (bytes_written
== 0) {
139 namewire
.truncated
= true;
141 namewire
.p
+= bytes_written
;
145 if (suffix
!= NULL
) {
146 dns_full_name_to_wire(NULL
, &namewire
, suffix
);
148 if (namewire
.error
) {
149 towire
->truncated
= namewire
.truncated
;
150 towire
->error
= namewire
.error
;
154 ret
= putDomainNameAsLabels((DNSMessage
*)towire
->message
, towire
->p
, towire
->lim
, (domainname
*)namebuf
.data
);
156 towire
->error
= ENOBUFS
;
157 towire
->truncated
= true;
163 if (ret
> towire
->lim
) {
164 towire
->error
= ENOBUFS
;
165 towire
->truncated
= true;
172 // Convert a dns_name_t to presentation format. Stop conversion at the specified limit.
173 // A trailing dot is only written if a null label is present.
175 dns_name_print_to_limit(dns_name_t
*NONNULL name
, dns_name_t
*NULLABLE limit
, char *buf
, int bufmax
)
181 // Copy the labels in one at a time, putting a dot between each one; if there isn't room
182 // in the buffer (shouldn't be the case), copy as much as will fit, leaving room for a NUL
184 for (lp
= name
; lp
!= limit
&& lp
!= NULL
; lp
= lp
->next
) {
186 if (ix
+ 2 >= bufmax
) {
191 for (i
= 0; i
< lp
->len
; i
++) {
192 if (isascii(lp
->data
[i
]) && (lp
->data
[i
] == ' ' || isprint(lp
->data
[i
]))) {
193 if (ix
+ 2 >= bufmax
) {
196 buf
[ix
++] = lp
->data
[i
];
198 if (ix
+ 5 >= bufmax
) {
202 buf
[ix
++] = '0' + (lp
->data
[i
] / 100);
203 buf
[ix
++] = '0' + (lp
->data
[i
] / 10) % 10;
204 buf
[ix
++] = '0' + lp
->data
[i
] % 10;
216 dns_name_print(dns_name_t
*NONNULL name
, char *buf
, int bufmax
)
218 return dns_name_print_to_limit(name
, NULL
, buf
, bufmax
);
222 dns_labels_equal(const char *label1
, const char *label2
, size_t len
)
225 for (i
= 0; i
< len
; i
++) {
226 if (isascii(label1
[i
]) && isascii(label2
[i
])) {
227 if (tolower(label1
[i
]) != tolower(label2
[i
])) {
232 if (label1
[i
] != label2
[i
]) {
241 dns_names_equal(dns_label_t
*NONNULL name1
, dns_label_t
*NONNULL name2
)
243 if (name1
->len
!= name2
->len
) {
246 if (name1
->len
!= 0 && !dns_labels_equal(name1
->data
, name2
->data
, name1
->len
) != 0) {
249 if (name1
->next
!= NULL
&& name2
->next
!= NULL
) {
250 return dns_names_equal(name1
->next
, name2
->next
);
252 if (name1
->next
== NULL
&& name2
->next
== NULL
) {
258 // Note that "foo.arpa" is not the same as "foo.arpa."
260 dns_names_equal_text(dns_label_t
*NONNULL name1
, const char *NONNULL name2
)
265 ndot
= strchr(name2
, '.');
267 ndot
= name2
+ strlen(name2
);
269 for (s
= name2
; s
< ndot
; s
++) {
275 return false; // An invalid name can't be equal to anything.
281 if (name1
->len
!= tlen
) {
284 if (name1
->len
!= 0) {
286 for (s
= name2
; s
< ndot
; s
++, t
++) {
287 if (*s
== '\\') { // already bounds checked
291 int val
= v0
* 100 + v1
* 10 + v2
;
294 } else if (isascii(*s
) && isascii(*t
)) {
295 if (tolower(*s
) != tolower(*t
)) {
298 } else if (val
!= *t
) {
309 if (name1
->next
!= NULL
&& *ndot
== '.') {
310 return dns_names_equal_text(name1
->next
, ndot
+ 1);
312 if (name1
->next
== NULL
&& *ndot
== 0) {
318 // Find the length of a name in uncompressed wire format.
320 dns_name_wire_length_in(dns_label_t
*NONNULL name
, size_t ret
)
325 return dns_name_wire_length_in(name
->next
, ret
+ name
->len
+ 1);
329 dns_name_wire_length(dns_label_t
*NONNULL name
)
331 return dns_name_wire_length_in(name
, 0);
334 // Copy a name we've parsed from a message out in canonical wire format so that we can
335 // use it to verify a signature. As above, not actually needed for copying to a message
336 // we're going to send, since in that case we want to try to compress.
338 dns_name_to_wire_canonical_in(uint8_t *NONNULL buf
, size_t max
, size_t ret
, dns_label_t
*NONNULL name
)
343 if (max
< name
->len
+ 1) {
347 memcpy(buf
+ 1, name
->data
, name
->len
);
348 return dns_name_to_wire_canonical_in(buf
+ name
->len
+ 1,
349 max
- name
->len
- 1, ret
+ name
->len
+ 1, name
->next
);
353 dns_name_to_wire_canonical(uint8_t *NONNULL buf
, size_t max
, dns_label_t
*NONNULL name
)
355 return dns_name_to_wire_canonical_in(buf
, max
, 0, name
);
358 // Parse a NUL-terminated text string into a sequence of labels.
360 dns_pres_name_parse(const char *pname
)
362 const char *dot
, *s
, *label
;
363 dns_label_t
*next
, *ret
, **prev
= &ret
;
366 char buf
[DNS_MAX_LABEL_SIZE
];
370 dot
= strchr(label
, '.');
373 dot
= label
+ strlen(label
);
378 for (s
= label
; s
< dot
; s
++) {
379 if (*s
== '\\') { // already bounds checked
383 int val
= v0
* 100 + v1
* 10 + v2
;
395 next
= calloc(1, len
+ 1 + (sizeof *next
) - DNS_MAX_LABEL_SIZE
);
403 memcpy(next
->data
, buf
, next
->len
);
405 next
->data
[next
->len
] = 0;
406 if (dot
[0] == '.' && len
> 0) {
417 dot
= strchr(label
, '.');
429 // See if name is a subdomain of domain. If so, return a pointer to the label in name
430 // where the match to domain begins.
432 dns_name_subdomain_of(dns_name_t
*name
, dns_name_t
*domain
)
434 int dnum
= 0, nnum
= 0;
437 for (dp
= domain
; dp
; dp
= dp
->next
) {
440 for (np
= name
; np
; np
= np
->next
) {
446 for (np
= name
; np
; np
= np
->next
) {
447 if (nnum
-- == dnum
) {
451 if (np
!= NULL
&& dns_names_equal(np
, domain
)) {
458 dns_rcode_name(int rcode
)
461 case dns_rcode_noerror
:
463 case dns_rcode_formerr
:
464 return "Format Error";
465 case dns_rcode_servfail
:
466 return "Server Failure";
467 case dns_rcode_nxdomain
:
468 return "Non-Existent Domain";
469 case dns_rcode_notimp
:
470 return "Not Implemented";
471 case dns_rcode_refused
:
472 return "Query Refused";
473 case dns_rcode_yxdomain
:
474 return "RFC6672] Name Exists when it should not";
475 case dns_rcode_yxrrset
:
476 return "RR Set Exists when it should not";
477 case dns_rcode_nxrrset
:
478 return "RR Set that should exist does not";
479 case dns_rcode_notauth
:
480 return "Not Authorized";
481 case dns_rcode_notzone
:
482 return "Name not contained in zone";
483 case dns_rcode_dsotypeni
:
484 return "DSO-Type Not Implemented";
485 case dns_rcode_badvers
:
486 return "TSIG Signature Failure";
487 case dns_rcode_badkey
:
488 return "Key not recognized";
489 case dns_rcode_badtime
:
490 return "Signature out of time window";
491 case dns_rcode_badmode
:
492 return "Bad TKEY Mode";
493 case dns_rcode_badname
:
494 return "Duplicate key name";
495 case dns_rcode_badalg
:
496 return "Algorithm not supported";
497 case dns_rcode_badtrunc
:
498 return "Bad Truncation";
499 case dns_rcode_badcookie
:
500 return "Bad/missing Server Cookie";
502 return "Unknown rcode.";
507 dns_keys_rdata_equal(dns_rr_t
*key1
, dns_rr_t
*key2
)
509 if ((key1
->type
== dns_rrtype_key
&& key2
->type
== dns_rrtype_key
) &&
510 key1
->data
.key
.flags
== key2
->data
.key
.flags
&&
511 key1
->data
.key
.protocol
== key2
->data
.key
.protocol
&&
512 key1
->data
.key
.algorithm
== key2
->data
.key
.algorithm
&&
513 key1
->data
.key
.len
== key2
->data
.key
.len
&&
514 !memcmp(key1
->data
.key
.key
, key2
->data
.key
.key
, key1
->data
.key
.len
))
524 // c-file-style: "bsd"
527 // indent-tabs-mode: nil