/src/bind9/lib/dns/name.c
Line | Count | Source |
1 | | /* |
2 | | * Copyright (C) Internet Systems Consortium, Inc. ("ISC") |
3 | | * |
4 | | * SPDX-License-Identifier: MPL-2.0 |
5 | | * |
6 | | * This Source Code Form is subject to the terms of the Mozilla Public |
7 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
8 | | * file, you can obtain one at https://mozilla.org/MPL/2.0/. |
9 | | * |
10 | | * See the COPYRIGHT file distributed with this work for additional |
11 | | * information regarding copyright ownership. |
12 | | */ |
13 | | |
14 | | /*! \file */ |
15 | | |
16 | | #include <ctype.h> |
17 | | #include <inttypes.h> |
18 | | #include <stdbool.h> |
19 | | #include <stdlib.h> |
20 | | #include <unistd.h> |
21 | | |
22 | | #include <isc/ascii.h> |
23 | | #include <isc/attributes.h> |
24 | | #include <isc/buffer.h> |
25 | | #include <isc/hash.h> |
26 | | #include <isc/hex.h> |
27 | | #include <isc/mem.h> |
28 | | #include <isc/once.h> |
29 | | #include <isc/random.h> |
30 | | #include <isc/result.h> |
31 | | #include <isc/string.h> |
32 | | #include <isc/thread.h> |
33 | | #include <isc/util.h> |
34 | | |
35 | | #include <dns/compress.h> |
36 | | #include <dns/fixedname.h> |
37 | | #include <dns/name.h> |
38 | | |
39 | | typedef enum { |
40 | | ft_init = 0, |
41 | | ft_start, |
42 | | ft_ordinary, |
43 | | ft_initialescape, |
44 | | ft_escape, |
45 | | ft_escdecimal, |
46 | | ft_at |
47 | | } ft_state; |
48 | | |
49 | | /*% |
50 | | * Note that the name data must be a char array, not a string |
51 | | * literal, to avoid compiler warnings about discarding |
52 | | * the const attribute of a string. |
53 | | */ |
54 | | static unsigned char root_ndata[] = { "" }; |
55 | | static dns_name_t const root = DNS_NAME_INITABSOLUTE(root_ndata); |
56 | | const dns_name_t *dns_rootname = &root; |
57 | | |
58 | | static unsigned char wild_ndata[] = { "\001*" }; |
59 | | static dns_name_t const wild = DNS_NAME_INITNONABSOLUTE(wild_ndata); |
60 | | const dns_name_t *dns_wildcardname = &wild; |
61 | | |
62 | | static unsigned char ip6arpa_data[] = "\003IP6\004ARPA"; |
63 | | static dns_name_t const ip6arpa = DNS_NAME_INITABSOLUTE(ip6arpa_data); |
64 | | const dns_name_t *dns_ip6arpa = &ip6arpa; |
65 | | |
66 | | static unsigned char ip6int_data[] = "\003IP6\003INT"; |
67 | | static dns_name_t const ip6int = DNS_NAME_INITABSOLUTE(ip6int_data); |
68 | | const dns_name_t *dns_ip6int = &ip6int; |
69 | | |
70 | | static unsigned char inaddrarpa_data[] = "\007IN-ADDR\004ARPA"; |
71 | | static dns_name_t const inaddrarpa = DNS_NAME_INITABSOLUTE(inaddrarpa_data); |
72 | | const dns_name_t *dns_inaddrarpa = &inaddrarpa; |
73 | | |
74 | | /* |
75 | | * dns_name_t to text post-conversion procedure. |
76 | | */ |
77 | | static thread_local dns_name_totextfilter_t *totext_filter_proc = NULL; |
78 | | |
79 | | bool |
80 | 0 | dns_name_isvalid(const dns_name_t *name) { |
81 | 0 | unsigned char *ndata; |
82 | 0 | unsigned int offset, count, length, nlabels; |
83 | |
|
84 | 0 | if (!DNS_NAME_VALID(name)) { |
85 | 0 | return false; |
86 | 0 | } |
87 | | |
88 | 0 | ndata = name->ndata; |
89 | 0 | length = name->length; |
90 | 0 | offset = 0; |
91 | 0 | nlabels = 0; |
92 | |
|
93 | 0 | while (offset != length) { |
94 | 0 | count = *ndata; |
95 | 0 | if (count > DNS_NAME_LABELLEN) { |
96 | 0 | return false; |
97 | 0 | } |
98 | | |
99 | 0 | nlabels++; |
100 | 0 | offset += count + 1; |
101 | 0 | ndata += count + 1; |
102 | 0 | if (offset > length) { |
103 | 0 | return false; |
104 | 0 | } |
105 | | |
106 | 0 | if (count == 0) { |
107 | 0 | break; |
108 | 0 | } |
109 | 0 | } |
110 | | |
111 | 0 | if (nlabels > DNS_NAME_MAXLABELS || offset != name->length) { |
112 | 0 | return false; |
113 | 0 | } |
114 | | |
115 | 0 | return true; |
116 | 0 | } |
117 | | |
118 | | bool |
119 | 190 | dns_name_hasbuffer(const dns_name_t *name) { |
120 | | /* |
121 | | * Does 'name' have a dedicated buffer? |
122 | | */ |
123 | | |
124 | 190 | REQUIRE(DNS_NAME_VALID(name)); |
125 | | |
126 | 190 | if (name->buffer != NULL) { |
127 | 190 | return true; |
128 | 190 | } |
129 | | |
130 | 0 | return false; |
131 | 190 | } |
132 | | |
133 | | bool |
134 | 10.5M | dns_name_isabsolute(const dns_name_t *name) { |
135 | | /* |
136 | | * Does 'name' end in the root label? |
137 | | */ |
138 | | |
139 | 10.5M | REQUIRE(DNS_NAME_VALID(name)); |
140 | | |
141 | 10.5M | return name->attributes.absolute; |
142 | 10.5M | } |
143 | | |
144 | 0 | #define hyphenchar(c) ((c) == 0x2d) |
145 | | #define asterchar(c) ((c) == 0x2a) |
146 | | #define alphachar(c) \ |
147 | 0 | (((c) >= 0x41 && (c) <= 0x5a) || ((c) >= 0x61 && (c) <= 0x7a)) |
148 | 0 | #define digitchar(c) ((c) >= 0x30 && (c) <= 0x39) |
149 | 0 | #define borderchar(c) (alphachar(c) || digitchar(c)) |
150 | 0 | #define middlechar(c) (borderchar(c) || hyphenchar(c)) |
151 | 0 | #define domainchar(c) ((c) > 0x20 && (c) < 0x7f) |
152 | | |
153 | | bool |
154 | 0 | dns_name_ismailbox(const dns_name_t *name) { |
155 | 0 | unsigned char *ndata, ch; |
156 | 0 | unsigned int n; |
157 | 0 | bool first; |
158 | |
|
159 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
160 | 0 | REQUIRE(name->length > 0); |
161 | 0 | REQUIRE(name->attributes.absolute); |
162 | | |
163 | | /* |
164 | | * Root label. |
165 | | */ |
166 | 0 | if (name->length == 1) { |
167 | 0 | return true; |
168 | 0 | } |
169 | | |
170 | 0 | ndata = name->ndata; |
171 | 0 | n = *ndata++; |
172 | 0 | INSIST(n <= DNS_NAME_LABELLEN); |
173 | 0 | while (n--) { |
174 | 0 | ch = *ndata++; |
175 | 0 | if (!domainchar(ch)) { |
176 | 0 | return false; |
177 | 0 | } |
178 | 0 | } |
179 | | |
180 | 0 | if (ndata == name->ndata + name->length) { |
181 | 0 | return false; |
182 | 0 | } |
183 | | |
184 | | /* |
185 | | * RFC952/RFC1123 hostname. |
186 | | */ |
187 | 0 | while (ndata < (name->ndata + name->length)) { |
188 | 0 | n = *ndata++; |
189 | 0 | INSIST(n <= DNS_NAME_LABELLEN); |
190 | 0 | first = true; |
191 | 0 | while (n--) { |
192 | 0 | ch = *ndata++; |
193 | 0 | if (first || n == 0) { |
194 | 0 | if (!borderchar(ch)) { |
195 | 0 | return false; |
196 | 0 | } |
197 | 0 | } else { |
198 | 0 | if (!middlechar(ch)) { |
199 | 0 | return false; |
200 | 0 | } |
201 | 0 | } |
202 | 0 | first = false; |
203 | 0 | } |
204 | 0 | } |
205 | 0 | return true; |
206 | 0 | } |
207 | | |
208 | | bool |
209 | 0 | dns_name_ishostname(const dns_name_t *name, bool wildcard) { |
210 | 0 | unsigned char *ndata, ch; |
211 | 0 | unsigned int n; |
212 | 0 | bool first; |
213 | |
|
214 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
215 | 0 | REQUIRE(name->length > 0); |
216 | 0 | REQUIRE(name->attributes.absolute); |
217 | | |
218 | | /* |
219 | | * Root label. |
220 | | */ |
221 | 0 | if (name->length == 1) { |
222 | 0 | return true; |
223 | 0 | } |
224 | | |
225 | | /* |
226 | | * Skip wildcard if this is a ownername. |
227 | | */ |
228 | 0 | ndata = name->ndata; |
229 | 0 | if (wildcard && ndata[0] == 1 && ndata[1] == '*') { |
230 | 0 | ndata += 2; |
231 | 0 | } |
232 | | |
233 | | /* |
234 | | * RFC952/RFC1123 hostname. |
235 | | */ |
236 | 0 | while (ndata < (name->ndata + name->length)) { |
237 | 0 | n = *ndata++; |
238 | 0 | INSIST(n <= DNS_NAME_LABELLEN); |
239 | 0 | first = true; |
240 | 0 | while (n--) { |
241 | 0 | ch = *ndata++; |
242 | 0 | if (first || n == 0) { |
243 | 0 | if (!borderchar(ch)) { |
244 | 0 | return false; |
245 | 0 | } |
246 | 0 | } else { |
247 | 0 | if (!middlechar(ch)) { |
248 | 0 | return false; |
249 | 0 | } |
250 | 0 | } |
251 | 0 | first = false; |
252 | 0 | } |
253 | 0 | } |
254 | 0 | return true; |
255 | 0 | } |
256 | | |
257 | | bool |
258 | 21.8M | dns_name_iswildcard(const dns_name_t *name) { |
259 | 21.8M | unsigned char *ndata; |
260 | | |
261 | | /* |
262 | | * Is 'name' a wildcard name? |
263 | | */ |
264 | | |
265 | 21.8M | REQUIRE(DNS_NAME_VALID(name)); |
266 | 21.8M | REQUIRE(name->length > 0); |
267 | | |
268 | 21.8M | if (name->length >= 2) { |
269 | 21.6M | ndata = name->ndata; |
270 | 21.6M | if (ndata[0] == 1 && ndata[1] == '*') { |
271 | 2.32M | return true; |
272 | 2.32M | } |
273 | 21.6M | } |
274 | | |
275 | 19.5M | return false; |
276 | 21.8M | } |
277 | | |
278 | | bool |
279 | 0 | dns_name_internalwildcard(const dns_name_t *name) { |
280 | 0 | unsigned char *ndata; |
281 | 0 | unsigned int count; |
282 | 0 | unsigned int label; |
283 | | |
284 | | /* |
285 | | * Does 'name' contain a internal wildcard? |
286 | | */ |
287 | |
|
288 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
289 | | |
290 | | /* |
291 | | * Skip first label. |
292 | | */ |
293 | 0 | ndata = name->ndata; |
294 | 0 | count = *ndata++; |
295 | 0 | INSIST(count <= DNS_NAME_LABELLEN); |
296 | 0 | ndata += count; |
297 | 0 | label = 1; |
298 | |
|
299 | 0 | uint8_t labels = dns_name_countlabels(name); |
300 | 0 | while (label + 1 < labels) { |
301 | 0 | count = *ndata++; |
302 | 0 | INSIST(count <= DNS_NAME_LABELLEN); |
303 | |
|
304 | 0 | if (count == 1 && *ndata == '*') { |
305 | 0 | return true; |
306 | 0 | } |
307 | 0 | ndata += count; |
308 | 0 | label++; |
309 | 0 | } |
310 | 0 | return false; |
311 | 0 | } |
312 | | |
313 | | uint32_t |
314 | 249k | dns_name_hash(const dns_name_t *name) { |
315 | 249k | REQUIRE(DNS_NAME_VALID(name)); |
316 | | |
317 | 249k | return isc_hash32(name->ndata, name->length, false); |
318 | 249k | } |
319 | | |
320 | | dns_namereln_t |
321 | | dns_name_fullcompare(const dns_name_t *name1, const dns_name_t *name2, |
322 | 10.0M | int *orderp, unsigned int *nlabelsp) { |
323 | 10.0M | unsigned int l1, l2, l, count1, count2, count, nlabels; |
324 | 10.0M | int cdiff, ldiff, diff; |
325 | 10.0M | unsigned char *label1, *label2; |
326 | 10.0M | dns_offsets_t offsets1, offsets2; |
327 | 10.0M | dns_namereln_t namereln = dns_namereln_none; |
328 | | |
329 | | /* |
330 | | * Determine the relative ordering under the DNSSEC order relation of |
331 | | * 'name1' and 'name2', and also determine the hierarchical |
332 | | * relationship of the names. |
333 | | * |
334 | | * Note: It makes no sense for one of the names to be relative and the |
335 | | * other absolute. If both names are relative, then to be meaningfully |
336 | | * compared the caller must ensure that they are both relative to the |
337 | | * same domain. |
338 | | */ |
339 | | |
340 | 10.0M | REQUIRE(DNS_NAME_VALID(name1)); |
341 | 10.0M | REQUIRE(DNS_NAME_VALID(name2)); |
342 | 10.0M | REQUIRE(orderp != NULL); |
343 | 10.0M | REQUIRE(nlabelsp != NULL); |
344 | | /* |
345 | | * Either name1 is absolute and name2 is absolute, or neither is. |
346 | | */ |
347 | 10.0M | REQUIRE((name1->attributes.absolute) == (name2->attributes.absolute)); |
348 | | |
349 | 10.0M | if (name1 == name2) { |
350 | 1.31k | *orderp = 0; |
351 | 1.31k | *nlabelsp = dns_name_countlabels(name1); |
352 | | |
353 | 1.31k | return dns_namereln_equal; |
354 | 1.31k | } |
355 | | |
356 | 10.0M | l1 = dns_name_offsets(name1, offsets1); |
357 | 10.0M | l2 = dns_name_offsets(name2, offsets2); |
358 | | |
359 | 10.0M | nlabels = 0; |
360 | 10.0M | if (l2 > l1) { |
361 | 19 | l = l1; |
362 | 19 | ldiff = 0 - (l2 - l1); |
363 | 10.0M | } else { |
364 | 10.0M | l = l2; |
365 | 10.0M | ldiff = l1 - l2; |
366 | 10.0M | } |
367 | | |
368 | 20.0M | while (l-- > 0) { |
369 | 10.0M | l1--; |
370 | 10.0M | l2--; |
371 | 10.0M | label1 = &name1->ndata[offsets1[l1]]; |
372 | 10.0M | label2 = &name2->ndata[offsets2[l2]]; |
373 | 10.0M | count1 = *label1++; |
374 | 10.0M | count2 = *label2++; |
375 | | |
376 | 10.0M | cdiff = (int)count1 - (int)count2; |
377 | 10.0M | if (cdiff < 0) { |
378 | 29 | count = count1; |
379 | 10.0M | } else { |
380 | 10.0M | count = count2; |
381 | 10.0M | } |
382 | | |
383 | 10.0M | diff = isc_ascii_lowercmp(label1, label2, count); |
384 | 10.0M | if (diff != 0) { |
385 | 195 | *orderp = diff; |
386 | 195 | goto done; |
387 | 195 | } |
388 | | |
389 | 10.0M | if (cdiff != 0) { |
390 | 53 | *orderp = cdiff; |
391 | 53 | goto done; |
392 | 53 | } |
393 | 10.0M | nlabels++; |
394 | 10.0M | } |
395 | | |
396 | 10.0M | *orderp = ldiff; |
397 | 10.0M | if (ldiff < 0) { |
398 | 19 | namereln = dns_namereln_contains; |
399 | 10.0M | } else if (ldiff > 0) { |
400 | 9.85M | namereln = dns_namereln_subdomain; |
401 | 9.85M | } else { |
402 | 179k | namereln = dns_namereln_equal; |
403 | 179k | } |
404 | 10.0M | *nlabelsp = nlabels; |
405 | 10.0M | return namereln; |
406 | | |
407 | 248 | done: |
408 | 248 | *nlabelsp = nlabels; |
409 | 248 | if (nlabels > 0) { |
410 | 248 | namereln = dns_namereln_commonancestor; |
411 | 248 | } |
412 | | |
413 | 248 | return namereln; |
414 | 10.0M | } |
415 | | |
416 | | int |
417 | 1.65k | dns_name_compare(const dns_name_t *name1, const dns_name_t *name2) { |
418 | 1.65k | int order; |
419 | 1.65k | unsigned int nlabels; |
420 | | |
421 | | /* |
422 | | * Determine the relative ordering under the DNSSEC order relation of |
423 | | * 'name1' and 'name2'. |
424 | | * |
425 | | * Note: It makes no sense for one of the names to be relative and the |
426 | | * other absolute. If both names are relative, then to be meaningfully |
427 | | * compared the caller must ensure that they are both relative to the |
428 | | * same domain. |
429 | | */ |
430 | | |
431 | 1.65k | (void)dns_name_fullcompare(name1, name2, &order, &nlabels); |
432 | | |
433 | 1.65k | return order; |
434 | 1.65k | } |
435 | | |
436 | | bool |
437 | 262k | dns_name_equal(const dns_name_t *name1, const dns_name_t *name2) { |
438 | 262k | unsigned int length; |
439 | | |
440 | | /* |
441 | | * Are 'name1' and 'name2' equal? |
442 | | * |
443 | | * Note: It makes no sense for one of the names to be relative and the |
444 | | * other absolute. If both names are relative, then to be meaningfully |
445 | | * compared the caller must ensure that they are both relative to the |
446 | | * same domain. |
447 | | */ |
448 | | |
449 | 262k | REQUIRE(DNS_NAME_VALID(name1)); |
450 | 262k | REQUIRE(DNS_NAME_VALID(name2)); |
451 | | /* |
452 | | * Either name1 is absolute and name2 is absolute, or neither is. |
453 | | */ |
454 | 262k | REQUIRE((name1->attributes.absolute) == (name2->attributes.absolute)); |
455 | | |
456 | 262k | if (name1 == name2) { |
457 | 0 | return true; |
458 | 0 | } |
459 | | |
460 | 262k | length = name1->length; |
461 | 262k | if (length != name2->length) { |
462 | 32.8k | return false; |
463 | 32.8k | } |
464 | | |
465 | | /* label lengths are < 64 so tolower() does not affect them */ |
466 | 229k | return isc_ascii_lowerequal(name1->ndata, name2->ndata, length); |
467 | 262k | } |
468 | | |
469 | | bool |
470 | 110k | dns_name_caseequal(const dns_name_t *name1, const dns_name_t *name2) { |
471 | | /* |
472 | | * Are 'name1' and 'name2' equal? |
473 | | * |
474 | | * Note: It makes no sense for one of the names to be relative and the |
475 | | * other absolute. If both names are relative, then to be meaningfully |
476 | | * compared the caller must ensure that they are both relative to the |
477 | | * same domain. |
478 | | */ |
479 | | |
480 | 110k | REQUIRE(DNS_NAME_VALID(name1)); |
481 | 110k | REQUIRE(DNS_NAME_VALID(name2)); |
482 | | /* |
483 | | * Either name1 is absolute and name2 is absolute, or neither is. |
484 | | */ |
485 | 110k | REQUIRE((name1->attributes.absolute) == (name2->attributes.absolute)); |
486 | | |
487 | 110k | if (name1->length != name2->length) { |
488 | 25.4k | return false; |
489 | 25.4k | } |
490 | | |
491 | 85.4k | if (memcmp(name1->ndata, name2->ndata, name1->length) != 0) { |
492 | 9.57k | return false; |
493 | 9.57k | } |
494 | | |
495 | 75.9k | return true; |
496 | 85.4k | } |
497 | | |
498 | | int |
499 | 31.7M | dns_name_rdatacompare(const dns_name_t *name1, const dns_name_t *name2) { |
500 | | /* |
501 | | * Compare two absolute names as rdata. |
502 | | */ |
503 | | |
504 | 31.7M | REQUIRE(DNS_NAME_VALID(name1)); |
505 | 31.7M | REQUIRE(name1->length > 0); |
506 | 31.7M | REQUIRE(name1->attributes.absolute); |
507 | 31.7M | REQUIRE(DNS_NAME_VALID(name2)); |
508 | 31.7M | REQUIRE(name2->length > 0); |
509 | 31.7M | REQUIRE(name2->attributes.absolute); |
510 | | |
511 | | /* label lengths are < 64 so tolower() does not affect them */ |
512 | 31.7M | return isc_ascii_lowercmp(name1->ndata, name2->ndata, |
513 | 31.7M | ISC_MIN(name1->length, name2->length)); |
514 | 31.7M | } |
515 | | |
516 | | bool |
517 | 10.0M | dns_name_issubdomain(const dns_name_t *name1, const dns_name_t *name2) { |
518 | 10.0M | int order; |
519 | 10.0M | unsigned int nlabels; |
520 | 10.0M | dns_namereln_t namereln; |
521 | | |
522 | | /* |
523 | | * Is 'name1' a subdomain of 'name2'? |
524 | | * |
525 | | * Note: It makes no sense for one of the names to be relative and the |
526 | | * other absolute. If both names are relative, then to be meaningfully |
527 | | * compared the caller must ensure that they are both relative to the |
528 | | * same domain. |
529 | | */ |
530 | | |
531 | 10.0M | namereln = dns_name_fullcompare(name1, name2, &order, &nlabels); |
532 | 10.0M | if (namereln == dns_namereln_subdomain || |
533 | 179k | namereln == dns_namereln_equal) |
534 | 10.0M | { |
535 | 10.0M | return true; |
536 | 10.0M | } |
537 | | |
538 | 2 | return false; |
539 | 10.0M | } |
540 | | |
541 | | bool |
542 | 0 | dns_name_matcheswildcard(const dns_name_t *name, const dns_name_t *wname) { |
543 | 0 | int order; |
544 | 0 | unsigned int nlabels, labels; |
545 | 0 | dns_name_t tname; |
546 | |
|
547 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
548 | 0 | REQUIRE(name->length > 0); |
549 | 0 | REQUIRE(DNS_NAME_VALID(wname)); |
550 | 0 | labels = dns_name_countlabels(wname); |
551 | 0 | REQUIRE(labels > 0); |
552 | 0 | REQUIRE(dns_name_iswildcard(wname)); |
553 | |
|
554 | 0 | dns_name_init(&tname); |
555 | 0 | dns_name_getlabelsequence(wname, 1, labels - 1, &tname); |
556 | 0 | if (dns_name_fullcompare(name, &tname, &order, &nlabels) == |
557 | 0 | dns_namereln_subdomain) |
558 | 0 | { |
559 | 0 | return true; |
560 | 0 | } |
561 | 0 | return false; |
562 | 0 | } |
563 | | |
564 | | void |
565 | 4.61k | dns_name_getlabel(const dns_name_t *name, unsigned int n, dns_label_t *label) { |
566 | 4.61k | dns_offsets_t offsets; |
567 | | |
568 | | /* |
569 | | * Make 'label' refer to the 'n'th least significant label of 'name'. |
570 | | */ |
571 | | |
572 | 4.61k | REQUIRE(DNS_NAME_VALID(name)); |
573 | 4.61k | REQUIRE(label != NULL); |
574 | | |
575 | 4.61k | uint8_t labels = dns_name_offsets(name, offsets); |
576 | | |
577 | 4.61k | REQUIRE(labels > 0); |
578 | 4.61k | REQUIRE(n < labels); |
579 | | |
580 | 4.61k | label->base = &name->ndata[offsets[n]]; |
581 | 4.61k | if (n == (unsigned int)labels - 1) { |
582 | 2.55k | label->length = name->length - offsets[n]; |
583 | 2.55k | } else { |
584 | 2.05k | label->length = offsets[n + 1] - offsets[n]; |
585 | 2.05k | } |
586 | 4.61k | } |
587 | | |
588 | | void |
589 | | dns_name_getlabelsequence(const dns_name_t *source, unsigned int first, |
590 | 14.2M | unsigned int n, dns_name_t *target) { |
591 | 14.2M | unsigned char *p, l; |
592 | 14.2M | unsigned int firstoffset, endoffset; |
593 | 14.2M | unsigned int i; |
594 | | |
595 | | /* |
596 | | * Make 'target' refer to the 'n' labels including and following |
597 | | * 'first' in 'source'. |
598 | | */ |
599 | | |
600 | 14.2M | REQUIRE(DNS_NAME_VALID(source)); |
601 | 14.2M | REQUIRE(DNS_NAME_VALID(target)); |
602 | 14.2M | REQUIRE(DNS_NAME_BINDABLE(target)); |
603 | | |
604 | 14.2M | uint8_t labels = dns_name_countlabels(source); |
605 | 14.2M | REQUIRE(first <= labels && n <= labels - first); |
606 | | |
607 | 14.2M | p = source->ndata; |
608 | 14.2M | if (first == labels) { |
609 | 0 | firstoffset = source->length; |
610 | 14.2M | } else { |
611 | 183M | for (i = 0; i < first; i++) { |
612 | 169M | l = *p; |
613 | 169M | p += l + 1; |
614 | 169M | } |
615 | 14.2M | firstoffset = (unsigned int)(p - source->ndata); |
616 | 14.2M | } |
617 | | |
618 | 14.2M | if (first + n == labels) { |
619 | 14.2M | endoffset = source->length; |
620 | 14.2M | } else { |
621 | 0 | for (i = 0; i < n; i++) { |
622 | 0 | l = *p; |
623 | 0 | p += l + 1; |
624 | 0 | } |
625 | 0 | endoffset = (unsigned int)(p - source->ndata); |
626 | 0 | } |
627 | | |
628 | 14.2M | target->ndata = &source->ndata[firstoffset]; |
629 | 14.2M | target->length = endoffset - firstoffset; |
630 | | |
631 | 14.2M | if (first + n == labels && n > 0 && source->attributes.absolute) { |
632 | 14.2M | target->attributes.absolute = true; |
633 | 14.2M | } else { |
634 | 0 | target->attributes.absolute = false; |
635 | 0 | } |
636 | 14.2M | } |
637 | | |
638 | | void |
639 | 2.87k | dns_name_clone(const dns_name_t *source, dns_name_t *target) { |
640 | | /* |
641 | | * Make 'target' refer to the same name as 'source'. |
642 | | */ |
643 | | |
644 | 2.87k | REQUIRE(DNS_NAME_VALID(source)); |
645 | 2.87k | REQUIRE(DNS_NAME_VALID(target)); |
646 | 2.87k | REQUIRE(DNS_NAME_BINDABLE(target)); |
647 | | |
648 | 2.87k | target->ndata = source->ndata; |
649 | 2.87k | target->length = source->length; |
650 | 2.87k | target->attributes = source->attributes; |
651 | 2.87k | target->attributes.readonly = false; |
652 | 2.87k | target->attributes.dynamic = false; |
653 | 2.87k | } |
654 | | |
655 | | void |
656 | 64.0M | dns_name_fromregion(dns_name_t *name, const isc_region_t *r) { |
657 | 64.0M | size_t length; |
658 | 64.0M | isc_region_t r2 = { .base = NULL, .length = 0 }; |
659 | | |
660 | | /* |
661 | | * Make 'name' refer to region 'r'. |
662 | | */ |
663 | | |
664 | 64.0M | REQUIRE(DNS_NAME_VALID(name)); |
665 | 64.0M | REQUIRE(r != NULL); |
666 | 64.0M | REQUIRE(DNS_NAME_BINDABLE(name)); |
667 | | |
668 | 64.0M | name->ndata = r->base; |
669 | 64.0M | if (name->buffer != NULL) { |
670 | 35.0k | isc_buffer_clear(name->buffer); |
671 | 35.0k | isc_buffer_availableregion(name->buffer, &r2); |
672 | 35.0k | length = (r->length < r2.length) ? r->length : r2.length; |
673 | 35.0k | if (length > DNS_NAME_MAXWIRE) { |
674 | 0 | length = DNS_NAME_MAXWIRE; |
675 | 0 | } |
676 | 63.9M | } else { |
677 | 63.9M | length = (r->length <= DNS_NAME_MAXWIRE) ? r->length |
678 | 63.9M | : DNS_NAME_MAXWIRE; |
679 | 63.9M | } |
680 | | |
681 | 64.0M | name->attributes.absolute = false; |
682 | | |
683 | 64.0M | if (length > 0) { |
684 | 64.0M | size_t offset = 0; |
685 | 64.0M | uint8_t nlabels = 0; |
686 | 157M | while (offset != length) { |
687 | 157M | uint8_t count; |
688 | | |
689 | 157M | INSIST(nlabels < DNS_NAME_MAXLABELS); |
690 | 157M | nlabels++; |
691 | | |
692 | 157M | count = name->ndata[offset]; |
693 | 157M | INSIST(count <= DNS_NAME_LABELLEN); |
694 | | |
695 | 157M | offset += count + 1; |
696 | 157M | INSIST(offset <= length); |
697 | | |
698 | 157M | if (count == 0) { |
699 | 64.0M | name->attributes.absolute = true; |
700 | 64.0M | break; |
701 | 64.0M | } |
702 | 157M | } |
703 | 64.0M | name->length = offset; |
704 | 64.0M | } |
705 | | |
706 | 64.0M | if (name->buffer != NULL) { |
707 | | /* |
708 | | * name->length has been updated by set_offsets to the actual |
709 | | * length of the name data so we can now copy the actual name |
710 | | * data and not anything after it. |
711 | | */ |
712 | 35.0k | if (name->length > 0) { |
713 | 35.0k | memmove(r2.base, r->base, name->length); |
714 | 35.0k | } |
715 | 35.0k | name->ndata = r2.base; |
716 | 35.0k | isc_buffer_add(name->buffer, name->length); |
717 | 35.0k | } |
718 | 64.0M | } |
719 | | |
720 | | static isc_result_t |
721 | | convert_text(isc_buffer_t *source, const dns_name_t *origin, |
722 | 19.7M | unsigned int options, dns_name_t *name, isc_buffer_t *target) { |
723 | 19.7M | unsigned char *ndata = NULL, *label = NULL; |
724 | 19.7M | char *tdata = NULL; |
725 | 19.7M | char c; |
726 | 19.7M | ft_state state; |
727 | 19.7M | unsigned int value = 0, count = 0; |
728 | 19.7M | unsigned int n1 = 0, n2 = 0; |
729 | 19.7M | unsigned int tlen, nrem, nused, digits = 0, labels, tused; |
730 | 19.7M | bool done; |
731 | 19.7M | bool downcase; |
732 | | |
733 | 19.7M | REQUIRE(DNS_NAME_VALID(name)); |
734 | 19.7M | REQUIRE(ISC_BUFFER_VALID(source)); |
735 | 19.7M | REQUIRE(ISC_BUFFER_VALID(target)); |
736 | | |
737 | 19.7M | downcase = ((options & DNS_NAME_DOWNCASE) != 0); |
738 | | |
739 | 19.7M | if (target == NULL && name->buffer != NULL) { |
740 | 0 | target = name->buffer; |
741 | 0 | isc_buffer_clear(target); |
742 | 0 | } |
743 | | |
744 | 19.7M | REQUIRE(DNS_NAME_BINDABLE(name)); |
745 | | |
746 | | /* |
747 | | * Set up the state machine. |
748 | | */ |
749 | 19.7M | tdata = (char *)source->base + source->current; |
750 | 19.7M | tlen = isc_buffer_remaininglength(source); |
751 | 19.7M | tused = 0; |
752 | 19.7M | ndata = isc_buffer_used(target); |
753 | 19.7M | nrem = isc_buffer_availablelength(target); |
754 | 19.7M | if (nrem > DNS_NAME_MAXWIRE) { |
755 | 833k | nrem = DNS_NAME_MAXWIRE; |
756 | 833k | } |
757 | 19.7M | nused = 0; |
758 | 19.7M | labels = 0; |
759 | 19.7M | done = false; |
760 | 19.7M | state = ft_init; |
761 | | |
762 | 135M | while (nrem > 0 && tlen > 0 && !done) { |
763 | 115M | c = *tdata++; |
764 | 115M | tlen--; |
765 | 115M | tused++; |
766 | | |
767 | 115M | switch (state) { |
768 | 19.7M | case ft_init: |
769 | | /* |
770 | | * Is this the root name? |
771 | | */ |
772 | 19.7M | if (c == '.') { |
773 | 226k | if (tlen != 0) { |
774 | 70 | return DNS_R_EMPTYLABEL; |
775 | 70 | } |
776 | 226k | labels++; |
777 | 226k | *ndata++ = 0; |
778 | 226k | nrem--; |
779 | 226k | nused++; |
780 | 226k | done = true; |
781 | 226k | break; |
782 | 226k | } |
783 | 19.5M | if (c == '@' && tlen == 0) { |
784 | 158k | state = ft_at; |
785 | 158k | break; |
786 | 158k | } |
787 | | |
788 | 19.3M | FALLTHROUGH; |
789 | 31.1M | case ft_start: |
790 | 31.1M | label = ndata; |
791 | 31.1M | ndata++; |
792 | 31.1M | nrem--; |
793 | 31.1M | nused++; |
794 | 31.1M | count = 0; |
795 | 31.1M | if (c == '\\') { |
796 | 15.9k | state = ft_initialescape; |
797 | 15.9k | break; |
798 | 15.9k | } |
799 | 31.1M | state = ft_ordinary; |
800 | 31.1M | if (nrem == 0) { |
801 | 12 | return ISC_R_NOSPACE; |
802 | 12 | } |
803 | 31.1M | FALLTHROUGH; |
804 | 114M | case ft_ordinary: |
805 | 114M | if (c == '.') { |
806 | 11.7M | if (count == 0) { |
807 | 15 | return DNS_R_EMPTYLABEL; |
808 | 15 | } |
809 | 11.7M | *label = count; |
810 | 11.7M | labels++; |
811 | 11.7M | INSIST(labels < DNS_NAME_MAXLABELS); |
812 | 11.7M | if (tlen == 0) { |
813 | 34.5k | labels++; |
814 | 34.5k | *ndata++ = 0; |
815 | 34.5k | nrem--; |
816 | 34.5k | nused++; |
817 | 34.5k | done = true; |
818 | 34.5k | } |
819 | 11.7M | state = ft_start; |
820 | 103M | } else if (c == '\\') { |
821 | 48.0k | state = ft_escape; |
822 | 103M | } else { |
823 | 103M | if (count >= DNS_NAME_LABELLEN) { |
824 | 65 | return DNS_R_LABELTOOLONG; |
825 | 65 | } |
826 | 103M | count++; |
827 | 103M | if (downcase) { |
828 | 0 | c = isc_ascii_tolower(c); |
829 | 0 | } |
830 | 103M | *ndata++ = c; |
831 | 103M | nrem--; |
832 | 103M | nused++; |
833 | 103M | } |
834 | 114M | break; |
835 | 114M | case ft_initialescape: |
836 | 15.9k | if (c == '[') { |
837 | | /* |
838 | | * This looks like a bitstring label, which |
839 | | * was deprecated. Intentionally drop it. |
840 | | */ |
841 | 3 | return DNS_R_BADLABELTYPE; |
842 | 3 | } |
843 | 15.9k | state = ft_escape; |
844 | 15.9k | POST(state); |
845 | 15.9k | FALLTHROUGH; |
846 | 64.0k | case ft_escape: |
847 | 64.0k | if (!isdigit((unsigned char)c)) { |
848 | 27.1k | if (count >= DNS_NAME_LABELLEN) { |
849 | 5 | return DNS_R_LABELTOOLONG; |
850 | 5 | } |
851 | 27.1k | count++; |
852 | 27.1k | if (downcase) { |
853 | 0 | c = isc_ascii_tolower(c); |
854 | 0 | } |
855 | 27.1k | *ndata++ = c; |
856 | 27.1k | nrem--; |
857 | 27.1k | nused++; |
858 | 27.1k | state = ft_ordinary; |
859 | 27.1k | break; |
860 | 27.1k | } |
861 | 36.9k | digits = 0; |
862 | 36.9k | value = 0; |
863 | 36.9k | state = ft_escdecimal; |
864 | 36.9k | FALLTHROUGH; |
865 | 110k | case ft_escdecimal: |
866 | 110k | if (!isdigit((unsigned char)c)) { |
867 | 19 | return DNS_R_BADESCAPE; |
868 | 19 | } |
869 | 110k | value = 10 * value + c - '0'; |
870 | 110k | digits++; |
871 | 110k | if (digits == 3) { |
872 | 36.8k | if (value > 255) { |
873 | 15 | return DNS_R_BADESCAPE; |
874 | 15 | } |
875 | 36.8k | if (count >= DNS_NAME_LABELLEN) { |
876 | 3 | return DNS_R_LABELTOOLONG; |
877 | 3 | } |
878 | 36.8k | count++; |
879 | 36.8k | if (downcase) { |
880 | 0 | value = isc_ascii_tolower(value); |
881 | 0 | } |
882 | 36.8k | *ndata++ = value; |
883 | 36.8k | nrem--; |
884 | 36.8k | nused++; |
885 | 36.8k | state = ft_ordinary; |
886 | 36.8k | } |
887 | 110k | break; |
888 | 110k | default: |
889 | 0 | FATAL_ERROR("Unexpected state %d", state); |
890 | | /* Does not return. */ |
891 | 115M | } |
892 | 115M | } |
893 | | |
894 | 19.7M | if (!done) { |
895 | 19.5M | if (nrem == 0) { |
896 | 18 | return ISC_R_NOSPACE; |
897 | 18 | } |
898 | 19.5M | INSIST(tlen == 0); |
899 | 19.5M | if (state != ft_ordinary && state != ft_at) { |
900 | 106 | return ISC_R_UNEXPECTEDEND; |
901 | 106 | } |
902 | 19.5M | if (state == ft_ordinary) { |
903 | 19.3M | INSIST(count != 0); |
904 | 19.3M | INSIST(label != NULL); |
905 | 19.3M | *label = count; |
906 | 19.3M | labels++; |
907 | 19.3M | INSIST(labels < DNS_NAME_MAXLABELS); |
908 | 19.3M | } |
909 | 19.5M | if (origin != NULL) { |
910 | 19.5M | if (nrem < origin->length) { |
911 | 6 | return ISC_R_NOSPACE; |
912 | 6 | } |
913 | 19.5M | label = origin->ndata; |
914 | 19.5M | n1 = origin->length; |
915 | 19.5M | nrem -= n1; |
916 | 19.5M | POST(nrem); |
917 | 39.5M | while (n1 > 0) { |
918 | 20.0M | n2 = *label++; |
919 | 20.0M | INSIST(n2 <= DNS_NAME_LABELLEN); |
920 | 20.0M | *ndata++ = n2; |
921 | 20.0M | n1 -= n2 + 1; |
922 | 20.0M | nused += n2 + 1; |
923 | 23.3M | while (n2 > 0) { |
924 | 3.30M | c = *label++; |
925 | 3.30M | if (downcase) { |
926 | 0 | c = isc_ascii_tolower(c); |
927 | 0 | } |
928 | 3.30M | *ndata++ = c; |
929 | 3.30M | n2--; |
930 | 3.30M | } |
931 | 20.0M | labels++; |
932 | 20.0M | if (n1 > 0) { |
933 | 518k | INSIST(labels < DNS_NAME_MAXLABELS); |
934 | 518k | } |
935 | 20.0M | } |
936 | 19.5M | if (origin->attributes.absolute) { |
937 | 19.5M | name->attributes.absolute = true; |
938 | 19.5M | } |
939 | 19.5M | } |
940 | 19.5M | } else { |
941 | 261k | name->attributes.absolute = true; |
942 | 261k | } |
943 | | |
944 | 19.7M | name->ndata = (unsigned char *)target->base + target->used; |
945 | 19.7M | name->length = nused; |
946 | | |
947 | 19.7M | isc_buffer_forward(source, tused); |
948 | 19.7M | isc_buffer_add(target, name->length); |
949 | | |
950 | 19.7M | return ISC_R_SUCCESS; |
951 | 19.7M | } |
952 | | |
953 | | isc_result_t |
954 | | dns_name_wirefromtext(isc_buffer_t *source, const dns_name_t *origin, |
955 | 834k | unsigned int options, isc_buffer_t *target) { |
956 | 834k | dns_name_t name; |
957 | | |
958 | 834k | REQUIRE(ISC_BUFFER_VALID(target)); |
959 | | |
960 | 834k | dns_name_init(&name); |
961 | 834k | return convert_text(source, origin, options, &name, target); |
962 | 834k | } |
963 | | |
964 | | isc_result_t |
965 | | dns_name_fromtext(dns_name_t *name, isc_buffer_t *source, |
966 | 18.9M | const dns_name_t *origin, unsigned int options) { |
967 | 18.9M | REQUIRE(DNS_NAME_VALID(name)); |
968 | 18.9M | REQUIRE(ISC_BUFFER_VALID(name->buffer)); |
969 | | |
970 | 18.9M | isc_buffer_clear(name->buffer); |
971 | 18.9M | return convert_text(source, origin, options, name, name->buffer); |
972 | 18.9M | } |
973 | | |
974 | | isc_result_t |
975 | | dns_name_totext(const dns_name_t *name, unsigned int options, |
976 | 848k | isc_buffer_t *target) { |
977 | 848k | isc_result_t result; |
978 | 848k | unsigned char *ndata = NULL; |
979 | 848k | unsigned int nlen; |
980 | 848k | unsigned int labels; |
981 | 848k | bool saw_root = false; |
982 | 848k | unsigned int oused; |
983 | 848k | bool omit_final_dot = ((options & DNS_NAME_OMITFINALDOT) != 0); |
984 | 848k | bool first = true; |
985 | | |
986 | | /* |
987 | | * This function assumes the name is in proper uncompressed |
988 | | * wire format. |
989 | | */ |
990 | 848k | REQUIRE(DNS_NAME_VALID(name)); |
991 | 848k | REQUIRE(ISC_BUFFER_VALID(target)); |
992 | | |
993 | 848k | oused = target->used; |
994 | | |
995 | 848k | ndata = name->ndata; |
996 | 848k | nlen = name->length; |
997 | 848k | labels = dns_name_countlabels(name); |
998 | | |
999 | 848k | if (labels == 0 && nlen == 0) { |
1000 | | /* |
1001 | | * Special handling for an empty name. |
1002 | | */ |
1003 | 0 | omit_final_dot = true; |
1004 | 0 | CHECK(isc_buffer_reserve(target, 1)); |
1005 | 0 | isc_buffer_putuint8(target, '@'); |
1006 | | |
1007 | | /* |
1008 | | * Skip the while() loop. |
1009 | | */ |
1010 | 0 | nlen = 0; |
1011 | 848k | } else if (nlen == 1 && labels == 1 && *ndata == '\0') { |
1012 | | /* |
1013 | | * Special handling for the root label. |
1014 | | */ |
1015 | 366k | saw_root = true; |
1016 | 366k | omit_final_dot = false; |
1017 | | |
1018 | | /* |
1019 | | * Skip the while() loop. |
1020 | | */ |
1021 | 366k | nlen = 0; |
1022 | 366k | } |
1023 | | |
1024 | 5.69M | while (labels > 0 && nlen > 0) { |
1025 | 5.33M | unsigned int count = *ndata++; |
1026 | 5.33M | labels--; |
1027 | 5.33M | nlen--; |
1028 | 5.33M | if (count == 0) { |
1029 | 481k | saw_root = true; |
1030 | 481k | break; |
1031 | 4.84M | } else if (!first) { |
1032 | 4.36M | CHECK(isc_buffer_reserve(target, 1)); |
1033 | 4.36M | isc_buffer_putuint8(target, '.'); |
1034 | 4.36M | } |
1035 | 4.84M | first = false; |
1036 | | |
1037 | 4.84M | if (count <= DNS_NAME_LABELLEN) { |
1038 | 4.84M | unsigned char c; |
1039 | | |
1040 | 4.84M | INSIST(nlen >= count); |
1041 | | |
1042 | 80.6M | while (count > 0) { |
1043 | 75.7M | uint32_t value; |
1044 | | |
1045 | 75.7M | c = *ndata; |
1046 | 75.7M | switch (c) { |
1047 | | /* Special modifiers in zone files. */ |
1048 | 462k | case 0x40: /* '@' */ |
1049 | 976k | case 0x24: /* '$' */ |
1050 | 976k | if ((options & DNS_NAME_PRINCIPAL) != 0) |
1051 | 0 | { |
1052 | 0 | goto no_escape; |
1053 | 0 | } |
1054 | 976k | FALLTHROUGH; |
1055 | 1.14M | case 0x22: /* '"' */ |
1056 | 1.34M | case 0x28: /* '(' */ |
1057 | 1.54M | case 0x29: /* ')' */ |
1058 | 1.73M | case 0x2E: /* '.' */ |
1059 | 1.93M | case 0x3B: /* ';' */ |
1060 | 1.95M | case 0x5C: /* '\\' */ |
1061 | 1.95M | value = '\\' << 8 | c; |
1062 | 1.95M | CHECK(isc_buffer_reserve(target, 2)); |
1063 | 1.95M | isc_buffer_putuint16(target, value); |
1064 | 1.95M | ndata++; |
1065 | 1.95M | nlen--; |
1066 | 1.95M | break; |
1067 | 0 | no_escape: |
1068 | 73.8M | default: |
1069 | 73.8M | if (c > 0x20 && c < 0x7f) { |
1070 | 5.31M | CHECK(isc_buffer_reserve(target, |
1071 | 5.31M | 1)); |
1072 | 5.31M | isc_buffer_putuint8(target, c); |
1073 | 5.31M | ndata++; |
1074 | 5.31M | nlen--; |
1075 | 68.4M | } else { |
1076 | 68.4M | value = 0x5c << 24; |
1077 | 68.4M | value |= (0x30 + |
1078 | 68.4M | ((c / 100) % 10)) |
1079 | 68.4M | << 16; |
1080 | 68.4M | value |= |
1081 | 68.4M | (0x30 + ((c / 10) % 10)) |
1082 | 68.4M | << 8; |
1083 | 68.4M | value |= 0x30 + (c % 10); |
1084 | 68.4M | CHECK(isc_buffer_reserve(target, |
1085 | 68.4M | 4)); |
1086 | 68.4M | isc_buffer_putuint32(target, |
1087 | 68.4M | value); |
1088 | 68.4M | ndata++; |
1089 | 68.4M | nlen--; |
1090 | 68.4M | } |
1091 | 75.7M | } |
1092 | 75.7M | count--; |
1093 | 75.7M | } |
1094 | 4.84M | } else { |
1095 | 0 | FATAL_ERROR("Unexpected label type %02x", count); |
1096 | 0 | UNREACHABLE(); |
1097 | 0 | } |
1098 | 4.84M | } |
1099 | | |
1100 | 848k | if (saw_root && !omit_final_dot) { |
1101 | 846k | CHECK(isc_buffer_reserve(target, 1)); |
1102 | 846k | isc_buffer_putuint8(target, '.'); |
1103 | 846k | } |
1104 | | |
1105 | 848k | if (isc_buffer_availablelength(target) > 1) { |
1106 | 848k | uint8_t *p = isc_buffer_used(target); |
1107 | 848k | *p = 0; |
1108 | 848k | } |
1109 | | |
1110 | 848k | if (totext_filter_proc != NULL) { |
1111 | 0 | return (totext_filter_proc)(target, oused); |
1112 | 0 | } |
1113 | | |
1114 | 848k | return ISC_R_SUCCESS; |
1115 | | |
1116 | 4 | cleanup: |
1117 | 4 | return result; |
1118 | 848k | } |
1119 | | |
1120 | | isc_result_t |
1121 | | dns_name_tofilenametext(const dns_name_t *name, bool omit_final_dot, |
1122 | 0 | isc_buffer_t *target) { |
1123 | 0 | unsigned char *ndata; |
1124 | 0 | char *tdata; |
1125 | 0 | unsigned int nlen, tlen; |
1126 | 0 | unsigned char c; |
1127 | 0 | unsigned int trem, count; |
1128 | 0 | unsigned int labels; |
1129 | | |
1130 | | /* |
1131 | | * This function assumes the name is in proper uncompressed |
1132 | | * wire format. |
1133 | | */ |
1134 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
1135 | 0 | REQUIRE(name->attributes.absolute); |
1136 | 0 | REQUIRE(ISC_BUFFER_VALID(target)); |
1137 | |
|
1138 | 0 | ndata = name->ndata; |
1139 | 0 | nlen = name->length; |
1140 | 0 | labels = dns_name_countlabels(name); |
1141 | 0 | tdata = isc_buffer_used(target); |
1142 | 0 | tlen = isc_buffer_availablelength(target); |
1143 | |
|
1144 | 0 | trem = tlen; |
1145 | |
|
1146 | 0 | if (nlen == 1 && labels == 1 && *ndata == '\0') { |
1147 | | /* |
1148 | | * Special handling for the root label. |
1149 | | */ |
1150 | 0 | if (trem == 0) { |
1151 | 0 | return ISC_R_NOSPACE; |
1152 | 0 | } |
1153 | | |
1154 | 0 | omit_final_dot = false; |
1155 | 0 | *tdata++ = '.'; |
1156 | 0 | trem--; |
1157 | | |
1158 | | /* |
1159 | | * Skip the while() loop. |
1160 | | */ |
1161 | 0 | nlen = 0; |
1162 | 0 | } |
1163 | | |
1164 | 0 | while (labels > 0 && nlen > 0 && trem > 0) { |
1165 | 0 | labels--; |
1166 | 0 | count = *ndata++; |
1167 | 0 | nlen--; |
1168 | 0 | if (count == 0) { |
1169 | 0 | break; |
1170 | 0 | } |
1171 | 0 | if (count <= DNS_NAME_LABELLEN) { |
1172 | 0 | INSIST(nlen >= count); |
1173 | 0 | while (count > 0) { |
1174 | 0 | c = *ndata; |
1175 | 0 | if ((c >= 0x30 && c <= 0x39) || /* digit */ |
1176 | 0 | (c >= 0x41 && c <= 0x5A) || /* uppercase */ |
1177 | 0 | (c >= 0x61 && c <= 0x7A) || /* lowercase */ |
1178 | 0 | c == 0x2D || /* hyphen */ |
1179 | 0 | c == 0x5F) /* underscore */ |
1180 | 0 | { |
1181 | 0 | if (trem == 0) { |
1182 | 0 | return ISC_R_NOSPACE; |
1183 | 0 | } |
1184 | | /* downcase */ |
1185 | 0 | if (c >= 0x41 && c <= 0x5A) { |
1186 | 0 | c += 0x20; |
1187 | 0 | } |
1188 | 0 | *tdata++ = c; |
1189 | 0 | ndata++; |
1190 | 0 | trem--; |
1191 | 0 | nlen--; |
1192 | 0 | } else { |
1193 | 0 | if (trem < 4) { |
1194 | 0 | return ISC_R_NOSPACE; |
1195 | 0 | } |
1196 | 0 | snprintf(tdata, trem, "%%%02X", c); |
1197 | 0 | tdata += 3; |
1198 | 0 | trem -= 3; |
1199 | 0 | ndata++; |
1200 | 0 | nlen--; |
1201 | 0 | } |
1202 | 0 | count--; |
1203 | 0 | } |
1204 | 0 | } else { |
1205 | 0 | FATAL_ERROR("Unexpected label type %02x", count); |
1206 | 0 | UNREACHABLE(); |
1207 | 0 | } |
1208 | | |
1209 | | /* |
1210 | | * The following assumes names are absolute. If not, we |
1211 | | * fix things up later. Note that this means that in some |
1212 | | * cases one more byte of text buffer is required than is |
1213 | | * needed in the final output. |
1214 | | */ |
1215 | 0 | if (trem == 0) { |
1216 | 0 | return ISC_R_NOSPACE; |
1217 | 0 | } |
1218 | 0 | *tdata++ = '.'; |
1219 | 0 | trem--; |
1220 | 0 | } |
1221 | | |
1222 | 0 | if (nlen != 0 && trem == 0) { |
1223 | 0 | return ISC_R_NOSPACE; |
1224 | 0 | } |
1225 | | |
1226 | 0 | if (omit_final_dot) { |
1227 | 0 | trem++; |
1228 | 0 | } |
1229 | |
|
1230 | 0 | isc_buffer_add(target, tlen - trem); |
1231 | |
|
1232 | 0 | return ISC_R_SUCCESS; |
1233 | 0 | } |
1234 | | |
1235 | | isc_result_t |
1236 | 292 | dns_name_downcase(const dns_name_t *source, dns_name_t *name) { |
1237 | | /* |
1238 | | * Downcase 'source'. |
1239 | | */ |
1240 | | |
1241 | 292 | REQUIRE(DNS_NAME_VALID(source)); |
1242 | 292 | REQUIRE(DNS_NAME_VALID(name)); |
1243 | | |
1244 | 292 | if (source == name) { |
1245 | 292 | REQUIRE(!name->attributes.readonly); |
1246 | 292 | isc_ascii_lowercopy(name->ndata, source->ndata, source->length); |
1247 | 292 | return ISC_R_SUCCESS; |
1248 | 292 | } |
1249 | | |
1250 | 0 | REQUIRE(DNS_NAME_BINDABLE(name)); |
1251 | 0 | REQUIRE(ISC_BUFFER_VALID(name->buffer)); |
1252 | |
|
1253 | 0 | isc_buffer_clear(name->buffer); |
1254 | 0 | name->ndata = (uint8_t *)name->buffer->base + name->buffer->used; |
1255 | | |
1256 | | /* label lengths are < 64 so tolower() does not affect them */ |
1257 | 0 | isc_ascii_lowercopy(name->ndata, source->ndata, source->length); |
1258 | |
|
1259 | 0 | name->length = source->length; |
1260 | 0 | name->attributes = (struct dns_name_attrs){ |
1261 | 0 | .absolute = source->attributes.absolute |
1262 | 0 | }; |
1263 | 0 | isc_buffer_add(name->buffer, name->length); |
1264 | |
|
1265 | 0 | return ISC_R_SUCCESS; |
1266 | 292 | } |
1267 | | |
1268 | | isc_result_t |
1269 | | dns_name_fromwire(dns_name_t *const name, isc_buffer_t *const source, |
1270 | 1.68M | const dns_decompress_t dctx, isc_buffer_t *target) { |
1271 | | /* |
1272 | | * Copy the name at source into target, decompressing it. |
1273 | | * |
1274 | | * *** WARNING *** |
1275 | | * |
1276 | | * dns_name_fromwire() deals with raw network data. An error in this |
1277 | | * routine could result in the failure or hijacking of the server. |
1278 | | * |
1279 | | * The description of name compression in RFC 1035 section 4.1.4 is |
1280 | | * subtle wrt certain edge cases. The first important sentence is: |
1281 | | * |
1282 | | * > In this scheme, an entire domain name or a list of labels at the |
1283 | | * > end of a domain name is replaced with a pointer to a prior |
1284 | | * > occurance of the same name. |
1285 | | * |
1286 | | * The key word is "prior". This says that compression pointers must |
1287 | | * point strictly earlier in the message (before our "marker" variable), |
1288 | | * which is enough to prevent DoS attacks due to compression loops. |
1289 | | * |
1290 | | * The next important sentence is: |
1291 | | * |
1292 | | * > If a domain name is contained in a part of the message subject to a |
1293 | | * > length field (such as the RDATA section of an RR), and compression |
1294 | | * > is used, the length of the compressed name is used in the length |
1295 | | * > calculation, rather than the length of the expanded name. |
1296 | | * |
1297 | | * When decompressing, this means that the amount of the source buffer |
1298 | | * that we consumed (which is checked wrt the container's length field) |
1299 | | * is the length of the compressed name. A compressed name is defined as |
1300 | | * a sequence of labels ending with the root label or a compression |
1301 | | * pointer, that is, the segment of the name that dns_name_fromwire() |
1302 | | * examines first. |
1303 | | * |
1304 | | * This matters when handling names that play dirty tricks, like: |
1305 | | * |
1306 | | * +---+---+---+---+---+---+ |
1307 | | * | 4 | 1 |'a'|192| 0 | 0 | |
1308 | | * +---+---+---+---+---+---+ |
1309 | | * |
1310 | | * We start at octet 1. There is an ordinary single character label "a", |
1311 | | * followed by a compression pointer that refers back to octet zero. |
1312 | | * Here there is a label of length 4, which weirdly re-uses the octets |
1313 | | * we already examined as the data for the label. It is followed by the |
1314 | | * root label, |
1315 | | * |
1316 | | * The specification says that the compressed name ends after the first |
1317 | | * zero octet (after the compression pointer) not the second zero octet, |
1318 | | * even though the second octet is later in the message. This shows the |
1319 | | * correct way to set our "consumed" variable. |
1320 | | */ |
1321 | | |
1322 | 1.68M | REQUIRE(DNS_NAME_VALID(name)); |
1323 | 1.68M | REQUIRE(DNS_NAME_BINDABLE(name)); |
1324 | 1.68M | REQUIRE((target != NULL && ISC_BUFFER_VALID(target)) || |
1325 | 1.68M | (target == NULL && ISC_BUFFER_VALID(name->buffer))); |
1326 | | |
1327 | 1.68M | if (target == NULL && name->buffer != NULL) { |
1328 | 5.26k | target = name->buffer; |
1329 | 5.26k | isc_buffer_clear(target); |
1330 | 5.26k | } |
1331 | | |
1332 | 1.68M | uint8_t *const name_buf = isc_buffer_used(target); |
1333 | 1.68M | const uint32_t name_max = ISC_MIN(DNS_NAME_MAXWIRE, |
1334 | 1.68M | isc_buffer_availablelength(target)); |
1335 | 1.68M | uint32_t name_len = 0; |
1336 | | |
1337 | | /* |
1338 | | * After chasing a compression pointer, these variables refer to the |
1339 | | * source buffer as follows: |
1340 | | * |
1341 | | * sb --- mr --- cr --- st --- cd --- sm |
1342 | | * |
1343 | | * sb = source_buf (const) |
1344 | | * mr = marker |
1345 | | * cr = cursor |
1346 | | * st = start (const) |
1347 | | * cd = consumed |
1348 | | * sm = source_max (const) |
1349 | | * |
1350 | | * The marker hops backwards for each pointer. |
1351 | | * The cursor steps forwards for each label. |
1352 | | * The amount of the source we consumed is set once. |
1353 | | */ |
1354 | 1.68M | const uint8_t *const source_buf = isc_buffer_base(source); |
1355 | 1.68M | const uint8_t *const source_max = isc_buffer_used(source); |
1356 | 1.68M | const uint8_t *const start = isc_buffer_current(source); |
1357 | 1.68M | const uint8_t *marker = start; |
1358 | 1.68M | const uint8_t *cursor = start; |
1359 | 1.68M | const uint8_t *consumed = NULL; |
1360 | | |
1361 | | /* |
1362 | | * One iteration per label. |
1363 | | */ |
1364 | 12.9M | while (cursor < source_max) { |
1365 | 12.9M | const uint8_t label_len = *cursor++; |
1366 | 12.9M | if (label_len <= DNS_NAME_LABELLEN) { |
1367 | | /* |
1368 | | * Normal label: record its offset, and check bounds on |
1369 | | * the name length, which also ensures we don't overrun |
1370 | | * the offsets array. Don't touch any source bytes yet! |
1371 | | * The source bounds check will happen when we loop. |
1372 | | */ |
1373 | | /* and then a step to the ri-i-i-i-i-ight */ |
1374 | 11.5M | cursor += label_len; |
1375 | 11.5M | name_len += label_len + 1; |
1376 | 11.5M | if (name_len > name_max) { |
1377 | 56.3k | return name_max == DNS_NAME_MAXWIRE |
1378 | 56.3k | ? DNS_R_NAMETOOLONG |
1379 | 56.3k | : ISC_R_NOSPACE; |
1380 | 11.4M | } else if (label_len == 0) { |
1381 | 1.62M | goto root_label; |
1382 | 1.62M | } |
1383 | 11.5M | } else if (label_len < 192) { |
1384 | 545 | return DNS_R_BADLABELTYPE; |
1385 | 1.38M | } else if (!dns_decompress_getpermitted(dctx)) { |
1386 | 272 | return DNS_R_DISALLOWED; |
1387 | 1.38M | } else if (cursor < source_max) { |
1388 | | /* |
1389 | | * Compression pointer. Ensure it does not loop. |
1390 | | * |
1391 | | * Copy multiple labels in one go, to make the most of |
1392 | | * memmove() performance. Start at the marker and finish |
1393 | | * just before the pointer's hi+lo bytes, before the |
1394 | | * cursor. Bounds were already checked. |
1395 | | */ |
1396 | 1.38M | const uint32_t hi = label_len & 0x3F; |
1397 | 1.38M | const uint32_t lo = *cursor++; |
1398 | 1.38M | const uint8_t *pointer = source_buf + (256 * hi + lo); |
1399 | 1.38M | if (pointer >= marker) { |
1400 | 93 | return DNS_R_BADPOINTER; |
1401 | 93 | } |
1402 | 1.38M | const uint32_t copy_len = (cursor - 2) - marker; |
1403 | 1.38M | uint8_t *const dest = name_buf + name_len - copy_len; |
1404 | 1.38M | memmove(dest, marker, copy_len); |
1405 | 1.38M | consumed = consumed != NULL ? consumed : cursor; |
1406 | | /* it's just a jump to the left */ |
1407 | 1.38M | cursor = marker = pointer; |
1408 | 1.38M | } |
1409 | 12.9M | } |
1410 | 2.17k | return ISC_R_UNEXPECTEDEND; |
1411 | 1.62M | root_label:; |
1412 | | /* |
1413 | | * Copy labels almost like we do for compression pointers, |
1414 | | * from the marker up to and including the root label. |
1415 | | */ |
1416 | 1.62M | const uint32_t copy_len = cursor - marker; |
1417 | 1.62M | memmove(name_buf + name_len - copy_len, marker, copy_len); |
1418 | 1.62M | consumed = consumed != NULL ? consumed : cursor; |
1419 | 1.62M | isc_buffer_forward(source, consumed - start); |
1420 | | |
1421 | 1.62M | name->attributes.absolute = true; |
1422 | 1.62M | name->ndata = name_buf; |
1423 | 1.62M | name->length = name_len; |
1424 | 1.62M | isc_buffer_add(target, name_len); |
1425 | | |
1426 | 1.62M | return ISC_R_SUCCESS; |
1427 | 1.68M | } |
1428 | | |
1429 | | isc_result_t |
1430 | | dns_name_towire(const dns_name_t *name, dns_compress_t *cctx, |
1431 | 9.19M | isc_buffer_t *target) { |
1432 | 9.19M | bool compress, multi; |
1433 | 9.19M | unsigned int here; |
1434 | 9.19M | unsigned int prefix_length; |
1435 | 9.19M | unsigned int suffix_coff; |
1436 | | |
1437 | | /* |
1438 | | * Convert 'name' into wire format, compressing it as specified by the |
1439 | | * compression context 'cctx' (or without compressing if 'cctx' |
1440 | | * is NULL), and storing the result in 'target'. |
1441 | | */ |
1442 | | |
1443 | 9.19M | REQUIRE(DNS_NAME_VALID(name)); |
1444 | 9.19M | REQUIRE(ISC_BUFFER_VALID(target)); |
1445 | | |
1446 | 9.19M | if (cctx == NULL) { |
1447 | 8.89M | if (isc_buffer_availablelength(target) < name->length) { |
1448 | 0 | return ISC_R_NOSPACE; |
1449 | 0 | } |
1450 | 8.89M | memmove(isc_buffer_used(target), name->ndata, name->length); |
1451 | 8.89M | isc_buffer_add(target, name->length); |
1452 | 8.89M | return ISC_R_SUCCESS; |
1453 | 8.89M | } |
1454 | | |
1455 | 299k | compress = !name->attributes.nocompress && |
1456 | 299k | dns_compress_getpermitted(cctx); |
1457 | 299k | multi = compress && dns_compress_getmultiuse(cctx); |
1458 | | |
1459 | | /* |
1460 | | * Write a compression pointer directly if the caller passed us |
1461 | | * a pointer to this name's offset that we saved previously. |
1462 | | */ |
1463 | 299k | if (multi && cctx->coff < 0x4000) { |
1464 | 0 | if (isc_buffer_availablelength(target) < 2) { |
1465 | 0 | return ISC_R_NOSPACE; |
1466 | 0 | } |
1467 | 0 | isc_buffer_putuint16(target, cctx->coff | 0xc000); |
1468 | 0 | return ISC_R_SUCCESS; |
1469 | 0 | } |
1470 | | |
1471 | | /* |
1472 | | * Always add the name to the compression context; if compression |
1473 | | * is off, reset the return values before writing the name. |
1474 | | */ |
1475 | 299k | prefix_length = name->length; |
1476 | 299k | suffix_coff = 0; |
1477 | 299k | dns_compress_name(cctx, target, name, &prefix_length, &suffix_coff); |
1478 | 299k | if (!compress) { |
1479 | 24.5k | prefix_length = name->length; |
1480 | 24.5k | suffix_coff = 0; |
1481 | 24.5k | } |
1482 | | |
1483 | | /* |
1484 | | * Return this name's compression offset for use next time, provided |
1485 | | * it isn't too short for compression to help (i.e. it's the root) |
1486 | | */ |
1487 | 299k | here = isc_buffer_usedlength(target); |
1488 | 299k | if (multi && here < 0x4000 && prefix_length > 1) { |
1489 | 0 | cctx->coff = (uint16_t)here; |
1490 | 0 | } |
1491 | | |
1492 | 299k | if (prefix_length > 0) { |
1493 | 273k | if (isc_buffer_availablelength(target) < prefix_length) { |
1494 | 102k | return ISC_R_NOSPACE; |
1495 | 102k | } |
1496 | 171k | memmove(isc_buffer_used(target), name->ndata, prefix_length); |
1497 | 171k | isc_buffer_add(target, prefix_length); |
1498 | 171k | } |
1499 | | |
1500 | 196k | if (suffix_coff > 0) { |
1501 | 34.8k | if (multi && prefix_length == 0) { |
1502 | 0 | cctx->coff = suffix_coff; |
1503 | 0 | } |
1504 | 34.8k | if (isc_buffer_availablelength(target) < 2) { |
1505 | 83 | return ISC_R_NOSPACE; |
1506 | 83 | } |
1507 | 34.8k | isc_buffer_putuint16(target, suffix_coff | 0xc000); |
1508 | 34.8k | } |
1509 | | |
1510 | 196k | return ISC_R_SUCCESS; |
1511 | 196k | } |
1512 | | |
1513 | | isc_result_t |
1514 | | dns_name_concatenate(const dns_name_t *prefix, const dns_name_t *suffix, |
1515 | 0 | dns_name_t *name) { |
1516 | 0 | unsigned char *ndata = NULL; |
1517 | 0 | unsigned int nrem, prefix_length, length; |
1518 | 0 | bool copy_prefix = true; |
1519 | 0 | bool copy_suffix = true; |
1520 | 0 | bool absolute = false; |
1521 | 0 | dns_name_t tmp_name; |
1522 | 0 | isc_buffer_t *target = NULL; |
1523 | | |
1524 | | /* |
1525 | | * Concatenate 'prefix' and 'suffix'. |
1526 | | */ |
1527 | |
|
1528 | 0 | REQUIRE(prefix == NULL || DNS_NAME_VALID(prefix)); |
1529 | 0 | REQUIRE(suffix == NULL || DNS_NAME_VALID(suffix)); |
1530 | 0 | REQUIRE(DNS_NAME_VALID(name) && ISC_BUFFER_VALID(name->buffer)); |
1531 | 0 | REQUIRE(DNS_NAME_BINDABLE(name)); |
1532 | |
|
1533 | 0 | if (prefix == NULL || prefix->length == 0) { |
1534 | 0 | copy_prefix = false; |
1535 | 0 | } |
1536 | 0 | if (suffix == NULL || suffix->length == 0) { |
1537 | 0 | copy_suffix = false; |
1538 | 0 | } |
1539 | 0 | if (copy_prefix && prefix->attributes.absolute) { |
1540 | 0 | absolute = true; |
1541 | 0 | REQUIRE(!copy_suffix); |
1542 | 0 | } |
1543 | 0 | if (name == NULL) { |
1544 | 0 | dns_name_init(&tmp_name); |
1545 | 0 | name = &tmp_name; |
1546 | 0 | } |
1547 | |
|
1548 | 0 | target = name->buffer; |
1549 | 0 | isc_buffer_clear(target); |
1550 | | |
1551 | | /* |
1552 | | * Set up. |
1553 | | */ |
1554 | 0 | nrem = target->length - target->used; |
1555 | 0 | ndata = (unsigned char *)target->base + target->used; |
1556 | 0 | if (nrem > DNS_NAME_MAXWIRE) { |
1557 | 0 | nrem = DNS_NAME_MAXWIRE; |
1558 | 0 | } |
1559 | 0 | length = 0; |
1560 | 0 | prefix_length = 0; |
1561 | 0 | if (copy_prefix) { |
1562 | 0 | prefix_length = prefix->length; |
1563 | 0 | length += prefix_length; |
1564 | 0 | } |
1565 | 0 | if (copy_suffix) { |
1566 | 0 | length += suffix->length; |
1567 | 0 | } |
1568 | 0 | if (length > DNS_NAME_MAXWIRE) { |
1569 | 0 | return DNS_R_NAMETOOLONG; |
1570 | 0 | } |
1571 | 0 | if (length > nrem) { |
1572 | 0 | return ISC_R_NOSPACE; |
1573 | 0 | } |
1574 | | |
1575 | 0 | if (copy_suffix) { |
1576 | 0 | if (suffix->attributes.absolute) { |
1577 | 0 | absolute = true; |
1578 | 0 | } |
1579 | 0 | memmove(ndata + prefix_length, suffix->ndata, suffix->length); |
1580 | 0 | } |
1581 | | |
1582 | | /* |
1583 | | * If 'prefix' and 'name' are the same object, we don't have to |
1584 | | * copy anything. |
1585 | | */ |
1586 | 0 | if (copy_prefix && (prefix != name || prefix->buffer != target)) { |
1587 | 0 | memmove(ndata, prefix->ndata, prefix_length); |
1588 | 0 | } |
1589 | |
|
1590 | 0 | name->ndata = ndata; |
1591 | 0 | name->length = length; |
1592 | 0 | name->attributes.absolute = absolute; |
1593 | |
|
1594 | 0 | isc_buffer_add(target, name->length); |
1595 | |
|
1596 | 0 | return ISC_R_SUCCESS; |
1597 | 0 | } |
1598 | | |
1599 | | void |
1600 | 9.84M | dns_name_dup(const dns_name_t *source, isc_mem_t *mctx, dns_name_t *target) { |
1601 | | /* |
1602 | | * Make 'target' a dynamically allocated copy of 'source'. |
1603 | | */ |
1604 | | |
1605 | 9.84M | REQUIRE(DNS_NAME_VALID(source)); |
1606 | 9.84M | REQUIRE(source->length > 0); |
1607 | 9.84M | REQUIRE(DNS_NAME_VALID(target)); |
1608 | 9.84M | REQUIRE(DNS_NAME_BINDABLE(target)); |
1609 | | |
1610 | 9.84M | target->ndata = isc_mem_get(mctx, source->length); |
1611 | | |
1612 | 9.84M | memmove(target->ndata, source->ndata, source->length); |
1613 | | |
1614 | 9.84M | target->length = source->length; |
1615 | 9.84M | target->attributes = (struct dns_name_attrs){ .dynamic = true }; |
1616 | 9.84M | target->attributes.absolute = source->attributes.absolute; |
1617 | 9.84M | } |
1618 | | |
1619 | | void |
1620 | 9.84M | dns_name_free(dns_name_t *name, isc_mem_t *mctx) { |
1621 | 9.84M | size_t size; |
1622 | | |
1623 | | /* |
1624 | | * Free 'name'. |
1625 | | */ |
1626 | | |
1627 | 9.84M | REQUIRE(DNS_NAME_VALID(name)); |
1628 | 9.84M | REQUIRE(name->attributes.dynamic); |
1629 | | |
1630 | 9.84M | size = name->length; |
1631 | 9.84M | isc_mem_put(mctx, name->ndata, size); |
1632 | 9.84M | dns_name_invalidate(name); |
1633 | 9.84M | } |
1634 | | |
1635 | | size_t |
1636 | 0 | dns_name_size(const dns_name_t *name) { |
1637 | 0 | size_t size; |
1638 | |
|
1639 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
1640 | |
|
1641 | 0 | if (!name->attributes.dynamic) { |
1642 | 0 | return 0; |
1643 | 0 | } |
1644 | | |
1645 | 0 | size = name->length; |
1646 | |
|
1647 | 0 | return size; |
1648 | 0 | } |
1649 | | |
1650 | | isc_result_t |
1651 | 0 | dns_name_digest(const dns_name_t *name, dns_digestfunc_t digest, void *arg) { |
1652 | | /* |
1653 | | * Send 'name' in DNSSEC canonical form to 'digest'. |
1654 | | */ |
1655 | |
|
1656 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
1657 | 0 | REQUIRE(digest != NULL); |
1658 | |
|
1659 | 0 | unsigned char ndata[DNS_NAME_MAXWIRE]; |
1660 | 0 | isc_ascii_lowercopy(ndata, name->ndata, name->length); |
1661 | |
|
1662 | 0 | isc_region_t r = { |
1663 | 0 | .base = ndata, |
1664 | 0 | .length = name->length, |
1665 | 0 | }; |
1666 | 0 | return (digest)(arg, &r); |
1667 | 0 | } |
1668 | | |
1669 | | bool |
1670 | 494k | dns_name_dynamic(const dns_name_t *name) { |
1671 | 494k | REQUIRE(DNS_NAME_VALID(name)); |
1672 | | |
1673 | | /* |
1674 | | * Returns whether there is dynamic memory associated with this name. |
1675 | | */ |
1676 | | |
1677 | 494k | return name->attributes.dynamic; |
1678 | 494k | } |
1679 | | |
1680 | | isc_result_t |
1681 | 0 | dns_name_print(const dns_name_t *name, FILE *stream) { |
1682 | 0 | isc_buffer_t b; |
1683 | 0 | isc_region_t r; |
1684 | 0 | char t[1024]; |
1685 | | |
1686 | | /* |
1687 | | * Print 'name' on 'stream'. |
1688 | | */ |
1689 | |
|
1690 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
1691 | |
|
1692 | 0 | isc_buffer_init(&b, t, sizeof(t)); |
1693 | 0 | RETERR(dns_name_totext(name, 0, &b)); |
1694 | 0 | isc_buffer_usedregion(&b, &r); |
1695 | 0 | fprintf(stream, "%.*s", (int)r.length, (char *)r.base); |
1696 | |
|
1697 | 0 | return ISC_R_SUCCESS; |
1698 | 0 | } |
1699 | | |
1700 | | isc_result_t |
1701 | 0 | dns_name_settotextfilter(dns_name_totextfilter_t *proc) { |
1702 | | /* |
1703 | | * If we already have been here set / clear as appropriate. |
1704 | | */ |
1705 | 0 | if (totext_filter_proc != NULL && proc != NULL) { |
1706 | 0 | if (totext_filter_proc == proc) { |
1707 | 0 | return ISC_R_SUCCESS; |
1708 | 0 | } |
1709 | 0 | } |
1710 | 0 | if (proc == NULL && totext_filter_proc != NULL) { |
1711 | 0 | totext_filter_proc = NULL; |
1712 | 0 | return ISC_R_SUCCESS; |
1713 | 0 | } |
1714 | | |
1715 | 0 | totext_filter_proc = proc; |
1716 | |
|
1717 | 0 | return ISC_R_SUCCESS; |
1718 | 0 | } |
1719 | | |
1720 | | void |
1721 | 20.7k | dns_name_format(const dns_name_t *name, char *cp, unsigned int size) { |
1722 | 20.7k | isc_result_t result; |
1723 | 20.7k | isc_buffer_t buf; |
1724 | | |
1725 | 20.7k | REQUIRE(size > 0); |
1726 | | |
1727 | | /* |
1728 | | * Leave room for null termination after buffer. |
1729 | | */ |
1730 | 20.7k | isc_buffer_init(&buf, cp, size - 1); |
1731 | 20.7k | result = dns_name_totext(name, DNS_NAME_OMITFINALDOT, &buf); |
1732 | 20.7k | if (result == ISC_R_SUCCESS) { |
1733 | 20.7k | isc_buffer_putuint8(&buf, (uint8_t)'\0'); |
1734 | 20.7k | } else { |
1735 | 0 | snprintf(cp, size, "<unknown>"); |
1736 | 0 | } |
1737 | 20.7k | } |
1738 | | |
1739 | | /* |
1740 | | * dns_name_tostring() -- similar to dns_name_format() but allocates its own |
1741 | | * memory. |
1742 | | */ |
1743 | | isc_result_t |
1744 | 0 | dns_name_tostring(const dns_name_t *name, char **target, isc_mem_t *mctx) { |
1745 | 0 | isc_buffer_t buf; |
1746 | 0 | isc_region_t reg; |
1747 | 0 | char *p, txt[DNS_NAME_FORMATSIZE]; |
1748 | |
|
1749 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
1750 | 0 | REQUIRE(target != NULL && *target == NULL); |
1751 | |
|
1752 | 0 | isc_buffer_init(&buf, txt, sizeof(txt)); |
1753 | 0 | RETERR(dns_name_totext(name, 0, &buf)); |
1754 | |
|
1755 | 0 | isc_buffer_usedregion(&buf, ®); |
1756 | 0 | p = isc_mem_allocate(mctx, reg.length + 1); |
1757 | 0 | memmove(p, (char *)reg.base, (int)reg.length); |
1758 | 0 | p[reg.length] = '\0'; |
1759 | |
|
1760 | 0 | *target = p; |
1761 | 0 | return ISC_R_SUCCESS; |
1762 | 0 | } |
1763 | | |
1764 | | isc_result_t |
1765 | | dns_name_fromstring(dns_name_t *target, const char *src, |
1766 | | const dns_name_t *origin, unsigned int options, |
1767 | 4 | isc_mem_t *mctx) { |
1768 | 4 | isc_buffer_t buf; |
1769 | 4 | dns_fixedname_t fn; |
1770 | 4 | dns_name_t *name; |
1771 | | |
1772 | 4 | REQUIRE(src != NULL); |
1773 | | |
1774 | 4 | isc_buffer_constinit(&buf, src, strlen(src)); |
1775 | 4 | isc_buffer_add(&buf, strlen(src)); |
1776 | 4 | if (DNS_NAME_BINDABLE(target) && target->buffer != NULL) { |
1777 | 4 | name = target; |
1778 | 4 | } else { |
1779 | 0 | name = dns_fixedname_initname(&fn); |
1780 | 0 | } |
1781 | | |
1782 | 4 | RETERR(dns_name_fromtext(name, &buf, origin, options)); |
1783 | | |
1784 | 4 | if (name != target) { |
1785 | 0 | dns_name_dup(name, mctx, target); |
1786 | 0 | } |
1787 | | |
1788 | 4 | return ISC_R_SUCCESS; |
1789 | 4 | } |
1790 | | |
1791 | | void |
1792 | 314k | dns_name_copy(const dns_name_t *source, dns_name_t *dest) { |
1793 | 314k | isc_buffer_t *target = NULL; |
1794 | 314k | unsigned char *ndata = NULL; |
1795 | | |
1796 | 314k | REQUIRE(DNS_NAME_VALID(source)); |
1797 | 314k | REQUIRE(DNS_NAME_VALID(dest)); |
1798 | 314k | REQUIRE(DNS_NAME_BINDABLE(dest)); |
1799 | | |
1800 | 314k | target = dest->buffer; |
1801 | | |
1802 | 314k | REQUIRE(target != NULL); |
1803 | 314k | REQUIRE(target->length >= source->length); |
1804 | | |
1805 | 314k | isc_buffer_clear(target); |
1806 | | |
1807 | 314k | ndata = (unsigned char *)target->base; |
1808 | 314k | dest->ndata = target->base; |
1809 | | |
1810 | 314k | if (source->length != 0) { |
1811 | 314k | memmove(ndata, source->ndata, source->length); |
1812 | 314k | } |
1813 | | |
1814 | 314k | dest->ndata = ndata; |
1815 | 314k | dest->length = source->length; |
1816 | 314k | dest->attributes.absolute = source->attributes.absolute; |
1817 | | |
1818 | 314k | isc_buffer_add(target, dest->length); |
1819 | 314k | } |
1820 | | |
1821 | | /* |
1822 | | * Service Discovery Prefixes RFC 6763. |
1823 | | */ |
1824 | | static unsigned char b_dns_sd_udp_data[] = "\001b\007_dns-sd\004_udp"; |
1825 | | static unsigned char db_dns_sd_udp_data[] = "\002db\007_dns-sd\004_udp"; |
1826 | | static unsigned char r_dns_sd_udp_data[] = "\001r\007_dns-sd\004_udp"; |
1827 | | static unsigned char dr_dns_sd_udp_data[] = "\002dr\007_dns-sd\004_udp"; |
1828 | | static unsigned char lb_dns_sd_udp_data[] = "\002lb\007_dns-sd\004_udp"; |
1829 | | |
1830 | | static dns_name_t const dns_sd[] = { |
1831 | | DNS_NAME_INITNONABSOLUTE(b_dns_sd_udp_data), |
1832 | | DNS_NAME_INITNONABSOLUTE(db_dns_sd_udp_data), |
1833 | | DNS_NAME_INITNONABSOLUTE(r_dns_sd_udp_data), |
1834 | | DNS_NAME_INITNONABSOLUTE(dr_dns_sd_udp_data), |
1835 | | DNS_NAME_INITNONABSOLUTE(lb_dns_sd_udp_data) |
1836 | | }; |
1837 | | |
1838 | | bool |
1839 | 0 | dns_name_isdnssd(const dns_name_t *name) { |
1840 | 0 | size_t i; |
1841 | 0 | dns_name_t prefix; |
1842 | |
|
1843 | 0 | if (dns_name_countlabels(name) > 3U) { |
1844 | 0 | dns_name_init(&prefix); |
1845 | 0 | dns_name_getlabelsequence(name, 0, 3, &prefix); |
1846 | 0 | for (i = 0; i < (sizeof(dns_sd) / sizeof(dns_sd[0])); i++) { |
1847 | 0 | if (dns_name_equal(&prefix, &dns_sd[i])) { |
1848 | 0 | return true; |
1849 | 0 | } |
1850 | 0 | } |
1851 | 0 | } |
1852 | | |
1853 | 0 | return false; |
1854 | 0 | } |
1855 | | |
1856 | | static unsigned char inaddr10[] = "\00210\007IN-ADDR\004ARPA"; |
1857 | | |
1858 | | static unsigned char inaddr16172[] = "\00216\003172\007IN-ADDR\004ARPA"; |
1859 | | static unsigned char inaddr17172[] = "\00217\003172\007IN-ADDR\004ARPA"; |
1860 | | static unsigned char inaddr18172[] = "\00218\003172\007IN-ADDR\004ARPA"; |
1861 | | static unsigned char inaddr19172[] = "\00219\003172\007IN-ADDR\004ARPA"; |
1862 | | static unsigned char inaddr20172[] = "\00220\003172\007IN-ADDR\004ARPA"; |
1863 | | static unsigned char inaddr21172[] = "\00221\003172\007IN-ADDR\004ARPA"; |
1864 | | static unsigned char inaddr22172[] = "\00222\003172\007IN-ADDR\004ARPA"; |
1865 | | static unsigned char inaddr23172[] = "\00223\003172\007IN-ADDR\004ARPA"; |
1866 | | static unsigned char inaddr24172[] = "\00224\003172\007IN-ADDR\004ARPA"; |
1867 | | static unsigned char inaddr25172[] = "\00225\003172\007IN-ADDR\004ARPA"; |
1868 | | static unsigned char inaddr26172[] = "\00226\003172\007IN-ADDR\004ARPA"; |
1869 | | static unsigned char inaddr27172[] = "\00227\003172\007IN-ADDR\004ARPA"; |
1870 | | static unsigned char inaddr28172[] = "\00228\003172\007IN-ADDR\004ARPA"; |
1871 | | static unsigned char inaddr29172[] = "\00229\003172\007IN-ADDR\004ARPA"; |
1872 | | static unsigned char inaddr30172[] = "\00230\003172\007IN-ADDR\004ARPA"; |
1873 | | static unsigned char inaddr31172[] = "\00231\003172\007IN-ADDR\004ARPA"; |
1874 | | |
1875 | | static unsigned char inaddr168192[] = "\003168\003192\007IN-ADDR\004ARPA"; |
1876 | | |
1877 | | static dns_name_t const rfc1918names[] = { |
1878 | | DNS_NAME_INITABSOLUTE(inaddr10), DNS_NAME_INITABSOLUTE(inaddr16172), |
1879 | | DNS_NAME_INITABSOLUTE(inaddr17172), DNS_NAME_INITABSOLUTE(inaddr18172), |
1880 | | DNS_NAME_INITABSOLUTE(inaddr19172), DNS_NAME_INITABSOLUTE(inaddr20172), |
1881 | | DNS_NAME_INITABSOLUTE(inaddr21172), DNS_NAME_INITABSOLUTE(inaddr22172), |
1882 | | DNS_NAME_INITABSOLUTE(inaddr23172), DNS_NAME_INITABSOLUTE(inaddr24172), |
1883 | | DNS_NAME_INITABSOLUTE(inaddr25172), DNS_NAME_INITABSOLUTE(inaddr26172), |
1884 | | DNS_NAME_INITABSOLUTE(inaddr27172), DNS_NAME_INITABSOLUTE(inaddr28172), |
1885 | | DNS_NAME_INITABSOLUTE(inaddr29172), DNS_NAME_INITABSOLUTE(inaddr30172), |
1886 | | DNS_NAME_INITABSOLUTE(inaddr31172), DNS_NAME_INITABSOLUTE(inaddr168192) |
1887 | | }; |
1888 | | |
1889 | | bool |
1890 | 0 | dns_name_isrfc1918(const dns_name_t *name) { |
1891 | 0 | size_t i; |
1892 | |
|
1893 | 0 | for (i = 0; i < (sizeof(rfc1918names) / sizeof(*rfc1918names)); i++) { |
1894 | 0 | if (dns_name_issubdomain(name, &rfc1918names[i])) { |
1895 | 0 | return true; |
1896 | 0 | } |
1897 | 0 | } |
1898 | 0 | return false; |
1899 | 0 | } |
1900 | | |
1901 | | static unsigned char ip6fc[] = "\001c\001f\003ip6\004ARPA"; |
1902 | | static unsigned char ip6fd[] = "\001d\001f\003ip6\004ARPA"; |
1903 | | |
1904 | | static dns_name_t const ulanames[] = { DNS_NAME_INITABSOLUTE(ip6fc), |
1905 | | DNS_NAME_INITABSOLUTE(ip6fd) }; |
1906 | | |
1907 | | bool |
1908 | 0 | dns_name_isula(const dns_name_t *name) { |
1909 | 0 | size_t i; |
1910 | |
|
1911 | 0 | for (i = 0; i < (sizeof(ulanames) / sizeof(*ulanames)); i++) { |
1912 | 0 | if (dns_name_issubdomain(name, &ulanames[i])) { |
1913 | 0 | return true; |
1914 | 0 | } |
1915 | 0 | } |
1916 | 0 | return false; |
1917 | 0 | } |
1918 | | |
1919 | | bool |
1920 | 0 | dns_name_istat(const dns_name_t *name) { |
1921 | 0 | unsigned char len; |
1922 | 0 | const unsigned char *ndata; |
1923 | |
|
1924 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
1925 | |
|
1926 | 0 | if (name->length == 0) { |
1927 | 0 | return false; |
1928 | 0 | } |
1929 | | |
1930 | 0 | ndata = name->ndata; |
1931 | 0 | len = ndata[0]; |
1932 | 0 | INSIST(len <= name->length); |
1933 | 0 | ndata++; |
1934 | | |
1935 | | /* |
1936 | | * Is there at least one trust anchor reported and is the |
1937 | | * label length consistent with a trust-anchor-telemetry label. |
1938 | | */ |
1939 | 0 | if ((len < 8) || (len - 3) % 5 != 0) { |
1940 | 0 | return false; |
1941 | 0 | } |
1942 | | |
1943 | 0 | if (ndata[0] != '_' || isc_ascii_tolower(ndata[1]) != 't' || |
1944 | 0 | isc_ascii_tolower(ndata[2]) != 'a') |
1945 | 0 | { |
1946 | 0 | return false; |
1947 | 0 | } |
1948 | 0 | ndata += 3; |
1949 | 0 | len -= 3; |
1950 | |
|
1951 | 0 | while (len > 0) { |
1952 | 0 | INSIST(len >= 5); |
1953 | 0 | if (ndata[0] != '-' || !isc_hex_char(ndata[1]) || |
1954 | 0 | !isc_hex_char(ndata[2]) || !isc_hex_char(ndata[3]) || |
1955 | 0 | !isc_hex_char(ndata[4])) |
1956 | 0 | { |
1957 | 0 | return false; |
1958 | 0 | } |
1959 | 0 | ndata += 5; |
1960 | 0 | len -= 5; |
1961 | 0 | } |
1962 | 0 | return true; |
1963 | 0 | } |
1964 | | |
1965 | | bool |
1966 | 0 | dns_name_isdnssvcb(const dns_name_t *name) { |
1967 | 0 | unsigned char len, len1; |
1968 | 0 | const unsigned char *ndata; |
1969 | |
|
1970 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
1971 | |
|
1972 | 0 | if (name->length < 5) { |
1973 | 0 | return false; |
1974 | 0 | } |
1975 | | |
1976 | 0 | ndata = name->ndata; |
1977 | 0 | len = len1 = ndata[0]; |
1978 | 0 | INSIST(len <= name->length); |
1979 | 0 | ndata++; |
1980 | |
|
1981 | 0 | if (len < 2 || ndata[0] != '_') { |
1982 | 0 | return false; |
1983 | 0 | } |
1984 | 0 | if (isdigit(ndata[1]) && name->length > len + 1) { |
1985 | 0 | char buf[sizeof("65000")]; |
1986 | 0 | long port; |
1987 | 0 | char *endp; |
1988 | | |
1989 | | /* |
1990 | | * Do we have a valid _port label? |
1991 | | */ |
1992 | 0 | if (len > 6U || (ndata[1] == '0' && len != 2)) { |
1993 | 0 | return false; |
1994 | 0 | } |
1995 | 0 | memcpy(buf, ndata + 1, len - 1); |
1996 | 0 | buf[len - 1] = 0; |
1997 | 0 | port = strtol(buf, &endp, 10); |
1998 | 0 | if (*endp != 0 || port < 0 || port > 0xffff) { |
1999 | 0 | return false; |
2000 | 0 | } |
2001 | | |
2002 | | /* |
2003 | | * Move to next label. |
2004 | | */ |
2005 | 0 | ndata += len; |
2006 | 0 | INSIST(len1 + 1U < name->length); |
2007 | 0 | len = *ndata; |
2008 | 0 | INSIST(len + len1 + 1U <= name->length); |
2009 | 0 | ndata++; |
2010 | 0 | } |
2011 | | |
2012 | 0 | if (len == 4U && strncasecmp((const char *)ndata, "_dns", 4) == 0) { |
2013 | 0 | return true; |
2014 | 0 | } |
2015 | | |
2016 | 0 | return false; |
2017 | 0 | } |
2018 | | |
2019 | | bool |
2020 | 0 | dns_name_israd(const dns_name_t *name, const dns_name_t *rad) { |
2021 | 0 | dns_name_t suffix; |
2022 | 0 | char labelbuf[64]; |
2023 | 0 | unsigned long v, last = ULONG_MAX; |
2024 | 0 | char *end, *l; |
2025 | |
|
2026 | 0 | REQUIRE(DNS_NAME_VALID(name)); |
2027 | 0 | REQUIRE(DNS_NAME_VALID(rad)); |
2028 | |
|
2029 | 0 | uint8_t name_labels = dns_name_countlabels(name); |
2030 | 0 | uint8_t rad_labels = dns_name_countlabels(rad); |
2031 | |
|
2032 | 0 | if (name_labels < rad_labels + 4U || name->length < 4U) { |
2033 | 0 | return false; |
2034 | 0 | } |
2035 | | |
2036 | 0 | if (name->ndata[0] != 3 || name->ndata[1] != '_' || |
2037 | 0 | tolower(name->ndata[2]) != 'e' || tolower(name->ndata[3]) != 'r') |
2038 | 0 | { |
2039 | 0 | return false; |
2040 | 0 | } |
2041 | | |
2042 | 0 | dns_name_init(&suffix); |
2043 | 0 | dns_name_split(name, rad_labels + 1, NULL, &suffix); |
2044 | |
|
2045 | 0 | if (suffix.ndata[0] != 3 || suffix.ndata[1] != '_' || |
2046 | 0 | tolower(suffix.ndata[2]) != 'e' || tolower(suffix.ndata[3]) != 'r') |
2047 | 0 | { |
2048 | 0 | return false; |
2049 | 0 | } |
2050 | | |
2051 | | /* type list */ |
2052 | 0 | dns_name_split(name, name_labels - 1, NULL, &suffix); |
2053 | 0 | INSIST(*suffix.ndata < sizeof(labelbuf)); |
2054 | 0 | memmove(labelbuf, suffix.ndata + 1, *suffix.ndata); |
2055 | 0 | labelbuf[*suffix.ndata] = 0; |
2056 | 0 | if (strlen(labelbuf) != *suffix.ndata) { |
2057 | 0 | return false; |
2058 | 0 | } |
2059 | 0 | l = labelbuf; |
2060 | 0 | do { |
2061 | 0 | v = strtoul(l, &end, 10); |
2062 | 0 | if (v > 0xffff || (*end != 0 && *end != '-') || end == l) { |
2063 | 0 | return false; |
2064 | 0 | } |
2065 | 0 | if (last != ULONG_MAX && v <= last) { |
2066 | 0 | return false; |
2067 | 0 | } |
2068 | 0 | last = v; |
2069 | 0 | if (*end == '-') { |
2070 | 0 | l = end + 1; |
2071 | 0 | } |
2072 | 0 | } while (*end != 0); |
2073 | | |
2074 | | /* extended error code */ |
2075 | 0 | dns_name_split(name, rad_labels + 2, NULL, &suffix); |
2076 | 0 | INSIST(*suffix.ndata < sizeof(labelbuf)); |
2077 | 0 | memmove(labelbuf, suffix.ndata + 1, *suffix.ndata); |
2078 | 0 | labelbuf[*suffix.ndata] = 0; |
2079 | 0 | if (strlen(labelbuf) != *suffix.ndata) { |
2080 | 0 | return false; |
2081 | 0 | } |
2082 | 0 | v = strtoul(labelbuf, &end, 10); |
2083 | 0 | if (v > 0xfff || *end != 0) { |
2084 | 0 | return false; |
2085 | 0 | } |
2086 | | |
2087 | 0 | return dns_name_issubdomain(name, rad); |
2088 | 0 | } |
2089 | | |
2090 | | uint8_t |
2091 | 94.0M | dns_name_offsets(const dns_name_t *name, dns_offsets_t offsets) { |
2092 | 94.0M | REQUIRE(DNS_NAME_VALID(name)); |
2093 | 94.0M | unsigned int offset, count, length, nlabels; |
2094 | 94.0M | unsigned char *ndata; |
2095 | | |
2096 | 94.0M | ndata = name->ndata; |
2097 | 94.0M | length = name->length; |
2098 | 94.0M | offset = 0; |
2099 | 94.0M | nlabels = 0; |
2100 | 797M | while (offset != length) { |
2101 | 797M | INSIST(nlabels < DNS_NAME_MAXLABELS); |
2102 | 797M | if (offsets != NULL) { |
2103 | 273M | offsets[nlabels] = offset; |
2104 | 273M | } |
2105 | 797M | nlabels++; |
2106 | 797M | count = *ndata; |
2107 | 797M | INSIST(count <= DNS_NAME_LABELLEN); |
2108 | 797M | offset += count + 1; |
2109 | 797M | ndata += count + 1; |
2110 | 797M | INSIST(offset <= length); |
2111 | 797M | if (count == 0) { |
2112 | | /* Final root label */ |
2113 | 94.0M | break; |
2114 | 94.0M | } |
2115 | 797M | } |
2116 | 94.0M | INSIST(offset == name->length); |
2117 | | |
2118 | 94.0M | return nlabels; |
2119 | 94.0M | } |