]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/dns-domain.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / shared / dns-domain.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2014 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #if HAVE_LIBIDN2
22 # include <idn2.h>
23 #elif HAVE_LIBIDN
24 # include <idna.h>
25 # include <stringprep.h>
26 #endif
27
28 #include <endian.h>
29 #include <netinet/in.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <sys/socket.h>
33
34 #include "alloc-util.h"
35 #include "dns-domain.h"
36 #include "hashmap.h"
37 #include "hexdecoct.h"
38 #include "in-addr-util.h"
39 #include "macro.h"
40 #include "parse-util.h"
41 #include "string-util.h"
42 #include "strv.h"
43 #include "utf8.h"
44
45 int dns_label_unescape(const char **name, char *dest, size_t sz) {
46 const char *n;
47 char *d;
48 int r = 0;
49
50 assert(name);
51 assert(*name);
52
53 n = *name;
54 d = dest;
55
56 for (;;) {
57 if (*n == '.') {
58 n++;
59 break;
60 }
61
62 if (*n == 0)
63 break;
64
65 if (r >= DNS_LABEL_MAX)
66 return -EINVAL;
67
68 if (sz <= 0)
69 return -ENOBUFS;
70
71 if (*n == '\\') {
72 /* Escaped character */
73
74 n++;
75
76 if (*n == 0)
77 /* Ending NUL */
78 return -EINVAL;
79
80 else if (IN_SET(*n, '\\', '.')) {
81 /* Escaped backslash or dot */
82
83 if (d)
84 *(d++) = *n;
85 sz--;
86 r++;
87 n++;
88
89 } else if (n[0] >= '0' && n[0] <= '9') {
90 unsigned k;
91
92 /* Escaped literal ASCII character */
93
94 if (!(n[1] >= '0' && n[1] <= '9') ||
95 !(n[2] >= '0' && n[2] <= '9'))
96 return -EINVAL;
97
98 k = ((unsigned) (n[0] - '0') * 100) +
99 ((unsigned) (n[1] - '0') * 10) +
100 ((unsigned) (n[2] - '0'));
101
102 /* Don't allow anything that doesn't
103 * fit in 8bit. Note that we do allow
104 * control characters, as some servers
105 * (e.g. cloudflare) are happy to
106 * generate labels with them
107 * inside. */
108 if (k > 255)
109 return -EINVAL;
110
111 if (d)
112 *(d++) = (char) k;
113 sz--;
114 r++;
115
116 n += 3;
117 } else
118 return -EINVAL;
119
120 } else if ((uint8_t) *n >= (uint8_t) ' ' && *n != 127) {
121
122 /* Normal character */
123
124 if (d)
125 *(d++) = *n;
126 sz--;
127 r++;
128 n++;
129 } else
130 return -EINVAL;
131 }
132
133 /* Empty label that is not at the end? */
134 if (r == 0 && *n)
135 return -EINVAL;
136
137 /* More than one trailing dot? */
138 if (*n == '.')
139 return -EINVAL;
140
141 if (sz >= 1 && d)
142 *d = 0;
143
144 *name = n;
145 return r;
146 }
147
148 /* @label_terminal: terminal character of a label, updated to point to the terminal character of
149 * the previous label (always skipping one dot) or to NULL if there are no more
150 * labels. */
151 int dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) {
152 const char *terminal;
153 int r;
154
155 assert(name);
156 assert(label_terminal);
157 assert(dest);
158
159 /* no more labels */
160 if (!*label_terminal) {
161 if (sz >= 1)
162 *dest = 0;
163
164 return 0;
165 }
166
167 terminal = *label_terminal;
168 assert(IN_SET(*terminal, 0, '.'));
169
170 /* Skip current terminal character (and accept domain names ending it ".") */
171 if (*terminal == 0)
172 terminal--;
173 if (terminal >= name && *terminal == '.')
174 terminal--;
175
176 /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
177 for (;;) {
178 if (terminal < name) {
179 /* Reached the first label, so indicate that there are no more */
180 terminal = NULL;
181 break;
182 }
183
184 /* Find the start of the last label */
185 if (*terminal == '.') {
186 const char *y;
187 unsigned slashes = 0;
188
189 for (y = terminal - 1; y >= name && *y == '\\'; y--)
190 slashes++;
191
192 if (slashes % 2 == 0) {
193 /* The '.' was not escaped */
194 name = terminal + 1;
195 break;
196 } else {
197 terminal = y;
198 continue;
199 }
200 }
201
202 terminal--;
203 }
204
205 r = dns_label_unescape(&name, dest, sz);
206 if (r < 0)
207 return r;
208
209 *label_terminal = terminal;
210
211 return r;
212 }
213
214 int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) {
215 char *q;
216
217 /* DNS labels must be between 1 and 63 characters long. A
218 * zero-length label does not exist. See RFC 2182, Section
219 * 11. */
220
221 if (l <= 0 || l > DNS_LABEL_MAX)
222 return -EINVAL;
223 if (sz < 1)
224 return -ENOBUFS;
225
226 assert(p);
227 assert(dest);
228
229 q = dest;
230 while (l > 0) {
231
232 if (IN_SET(*p, '.', '\\')) {
233
234 /* Dot or backslash */
235
236 if (sz < 3)
237 return -ENOBUFS;
238
239 *(q++) = '\\';
240 *(q++) = *p;
241
242 sz -= 2;
243
244 } else if (IN_SET(*p, '_', '-') ||
245 (*p >= '0' && *p <= '9') ||
246 (*p >= 'a' && *p <= 'z') ||
247 (*p >= 'A' && *p <= 'Z')) {
248
249 /* Proper character */
250
251 if (sz < 2)
252 return -ENOBUFS;
253
254 *(q++) = *p;
255 sz -= 1;
256
257 } else {
258
259 /* Everything else */
260
261 if (sz < 5)
262 return -ENOBUFS;
263
264 *(q++) = '\\';
265 *(q++) = '0' + (char) ((uint8_t) *p / 100);
266 *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10);
267 *(q++) = '0' + (char) ((uint8_t) *p % 10);
268
269 sz -= 4;
270 }
271
272 p++;
273 l--;
274 }
275
276 *q = 0;
277 return (int) (q - dest);
278 }
279
280 int dns_label_escape_new(const char *p, size_t l, char **ret) {
281 _cleanup_free_ char *s = NULL;
282 int r;
283
284 assert(p);
285 assert(ret);
286
287 if (l <= 0 || l > DNS_LABEL_MAX)
288 return -EINVAL;
289
290 s = new(char, DNS_LABEL_ESCAPED_MAX);
291 if (!s)
292 return -ENOMEM;
293
294 r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX);
295 if (r < 0)
296 return r;
297
298 *ret = s;
299 s = NULL;
300
301 return r;
302 }
303
304 #if HAVE_LIBIDN
305 int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
306 _cleanup_free_ uint32_t *input = NULL;
307 size_t input_size, l;
308 const char *p;
309 bool contains_8bit = false;
310 char buffer[DNS_LABEL_MAX+1];
311
312 assert(encoded);
313 assert(decoded);
314
315 /* Converts an U-label into an A-label */
316
317 if (encoded_size <= 0)
318 return -EINVAL;
319
320 for (p = encoded; p < encoded + encoded_size; p++)
321 if ((uint8_t) *p > 127)
322 contains_8bit = true;
323
324 if (!contains_8bit) {
325 if (encoded_size > DNS_LABEL_MAX)
326 return -EINVAL;
327
328 return 0;
329 }
330
331 input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
332 if (!input)
333 return -ENOMEM;
334
335 if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
336 return -EINVAL;
337
338 l = strlen(buffer);
339
340 /* Verify that the result is not longer than one DNS label. */
341 if (l <= 0 || l > DNS_LABEL_MAX)
342 return -EINVAL;
343 if (l > decoded_max)
344 return -ENOBUFS;
345
346 memcpy(decoded, buffer, l);
347
348 /* If there's room, append a trailing NUL byte, but only then */
349 if (decoded_max > l)
350 decoded[l] = 0;
351
352 return (int) l;
353 }
354
355 int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
356 size_t input_size, output_size;
357 _cleanup_free_ uint32_t *input = NULL;
358 _cleanup_free_ char *result = NULL;
359 uint32_t *output = NULL;
360 size_t w;
361
362 /* To be invoked after unescaping. Converts an A-label into an U-label. */
363
364 assert(encoded);
365 assert(decoded);
366
367 if (encoded_size <= 0 || encoded_size > DNS_LABEL_MAX)
368 return -EINVAL;
369
370 if (encoded_size < sizeof(IDNA_ACE_PREFIX)-1)
371 return 0;
372
373 if (memcmp(encoded, IDNA_ACE_PREFIX, sizeof(IDNA_ACE_PREFIX) -1) != 0)
374 return 0;
375
376 input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
377 if (!input)
378 return -ENOMEM;
379
380 output_size = input_size;
381 output = newa(uint32_t, output_size);
382
383 idna_to_unicode_44i(input, input_size, output, &output_size, 0);
384
385 result = stringprep_ucs4_to_utf8(output, output_size, NULL, &w);
386 if (!result)
387 return -ENOMEM;
388 if (w <= 0)
389 return -EINVAL;
390 if (w > decoded_max)
391 return -ENOBUFS;
392
393 memcpy(decoded, result, w);
394
395 /* Append trailing NUL byte if there's space, but only then. */
396 if (decoded_max > w)
397 decoded[w] = 0;
398
399 return w;
400 }
401 #endif
402
403 int dns_name_concat(const char *a, const char *b, char **_ret) {
404 _cleanup_free_ char *ret = NULL;
405 size_t n = 0, allocated = 0;
406 const char *p;
407 bool first = true;
408 int r;
409
410 if (a)
411 p = a;
412 else if (b) {
413 p = b;
414 b = NULL;
415 } else
416 goto finish;
417
418 for (;;) {
419 char label[DNS_LABEL_MAX];
420
421 r = dns_label_unescape(&p, label, sizeof(label));
422 if (r < 0)
423 return r;
424 if (r == 0) {
425 if (*p != 0)
426 return -EINVAL;
427
428 if (b) {
429 /* Now continue with the second string, if there is one */
430 p = b;
431 b = NULL;
432 continue;
433 }
434
435 break;
436 }
437
438 if (_ret) {
439 if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
440 return -ENOMEM;
441
442 r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
443 if (r < 0)
444 return r;
445
446 if (!first)
447 ret[n] = '.';
448 } else {
449 char escaped[DNS_LABEL_ESCAPED_MAX];
450
451 r = dns_label_escape(label, r, escaped, sizeof(escaped));
452 if (r < 0)
453 return r;
454 }
455
456 if (!first)
457 n++;
458 else
459 first = false;
460
461 n += r;
462 }
463
464 finish:
465 if (n > DNS_HOSTNAME_MAX)
466 return -EINVAL;
467
468 if (_ret) {
469 if (n == 0) {
470 /* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
471 if (!GREEDY_REALLOC(ret, allocated, 2))
472 return -ENOMEM;
473
474 ret[n++] = '.';
475 } else {
476 if (!GREEDY_REALLOC(ret, allocated, n + 1))
477 return -ENOMEM;
478 }
479
480 ret[n] = 0;
481 *_ret = ret;
482 ret = NULL;
483 }
484
485 return 0;
486 }
487
488 void dns_name_hash_func(const void *s, struct siphash *state) {
489 const char *p = s;
490 int r;
491
492 assert(p);
493
494 for (;;) {
495 char label[DNS_LABEL_MAX+1];
496
497 r = dns_label_unescape(&p, label, sizeof(label));
498 if (r < 0)
499 break;
500 if (r == 0)
501 break;
502
503 ascii_strlower_n(label, r);
504 siphash24_compress(label, r, state);
505 siphash24_compress_byte(0, state); /* make sure foobar and foo.bar result in different hashes */
506 }
507
508 /* enforce that all names are terminated by the empty label */
509 string_hash_func("", state);
510 }
511
512 int dns_name_compare_func(const void *a, const void *b) {
513 const char *x, *y;
514 int r, q;
515
516 assert(a);
517 assert(b);
518
519 x = (const char *) a + strlen(a);
520 y = (const char *) b + strlen(b);
521
522 for (;;) {
523 char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
524
525 if (x == NULL && y == NULL)
526 return 0;
527
528 r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
529 q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
530 if (r < 0 || q < 0)
531 return r - q;
532
533 r = ascii_strcasecmp_nn(la, r, lb, q);
534 if (r != 0)
535 return r;
536 }
537 }
538
539 const struct hash_ops dns_name_hash_ops = {
540 .hash = dns_name_hash_func,
541 .compare = dns_name_compare_func
542 };
543
544 int dns_name_equal(const char *x, const char *y) {
545 int r, q;
546
547 assert(x);
548 assert(y);
549
550 for (;;) {
551 char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
552
553 r = dns_label_unescape(&x, la, sizeof(la));
554 if (r < 0)
555 return r;
556
557 q = dns_label_unescape(&y, lb, sizeof(lb));
558 if (q < 0)
559 return q;
560
561 if (r != q)
562 return false;
563 if (r == 0)
564 return true;
565
566 if (ascii_strcasecmp_n(la, lb, r) != 0)
567 return false;
568 }
569 }
570
571 int dns_name_endswith(const char *name, const char *suffix) {
572 const char *n, *s, *saved_n = NULL;
573 int r, q;
574
575 assert(name);
576 assert(suffix);
577
578 n = name;
579 s = suffix;
580
581 for (;;) {
582 char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
583
584 r = dns_label_unescape(&n, ln, sizeof(ln));
585 if (r < 0)
586 return r;
587
588 if (!saved_n)
589 saved_n = n;
590
591 q = dns_label_unescape(&s, ls, sizeof(ls));
592 if (q < 0)
593 return q;
594
595 if (r == 0 && q == 0)
596 return true;
597 if (r == 0 && saved_n == n)
598 return false;
599
600 if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) {
601
602 /* Not the same, let's jump back, and try with the next label again */
603 s = suffix;
604 n = saved_n;
605 saved_n = NULL;
606 }
607 }
608 }
609
610 int dns_name_startswith(const char *name, const char *prefix) {
611 const char *n, *p;
612 int r, q;
613
614 assert(name);
615 assert(prefix);
616
617 n = name;
618 p = prefix;
619
620 for (;;) {
621 char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX];
622
623 r = dns_label_unescape(&p, lp, sizeof(lp));
624 if (r < 0)
625 return r;
626 if (r == 0)
627 return true;
628
629 q = dns_label_unescape(&n, ln, sizeof(ln));
630 if (q < 0)
631 return q;
632
633 if (r != q)
634 return false;
635 if (ascii_strcasecmp_n(ln, lp, r) != 0)
636 return false;
637 }
638 }
639
640 int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) {
641 const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix;
642 int r, q;
643
644 assert(name);
645 assert(old_suffix);
646 assert(new_suffix);
647 assert(ret);
648
649 n = name;
650 s = old_suffix;
651
652 for (;;) {
653 char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
654
655 if (!saved_before)
656 saved_before = n;
657
658 r = dns_label_unescape(&n, ln, sizeof(ln));
659 if (r < 0)
660 return r;
661
662 if (!saved_after)
663 saved_after = n;
664
665 q = dns_label_unescape(&s, ls, sizeof(ls));
666 if (q < 0)
667 return q;
668
669 if (r == 0 && q == 0)
670 break;
671 if (r == 0 && saved_after == n) {
672 *ret = NULL; /* doesn't match */
673 return 0;
674 }
675
676 if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) {
677
678 /* Not the same, let's jump back, and try with the next label again */
679 s = old_suffix;
680 n = saved_after;
681 saved_after = saved_before = NULL;
682 }
683 }
684
685 /* Found it! Now generate the new name */
686 prefix = strndupa(name, saved_before - name);
687
688 r = dns_name_concat(prefix, new_suffix, ret);
689 if (r < 0)
690 return r;
691
692 return 1;
693 }
694
695 int dns_name_between(const char *a, const char *b, const char *c) {
696 int n;
697
698 /* Determine if b is strictly greater than a and strictly smaller than c.
699 We consider the order of names to be circular, so that if a is
700 strictly greater than c, we consider b to be between them if it is
701 either greater than a or smaller than c. This is how the canonical
702 DNS name order used in NSEC records work. */
703
704 n = dns_name_compare_func(a, c);
705 if (n == 0)
706 return -EINVAL;
707 else if (n < 0)
708 /* a<---b--->c */
709 return dns_name_compare_func(a, b) < 0 &&
710 dns_name_compare_func(b, c) < 0;
711 else
712 /* <--b--c a--b--> */
713 return dns_name_compare_func(b, c) < 0 ||
714 dns_name_compare_func(a, b) < 0;
715 }
716
717 int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
718 const uint8_t *p;
719 int r;
720
721 assert(a);
722 assert(ret);
723
724 p = (const uint8_t*) a;
725
726 if (family == AF_INET)
727 r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]);
728 else if (family == AF_INET6)
729 r = asprintf(ret, "%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.%c.ip6.arpa",
730 hexchar(p[15] & 0xF), hexchar(p[15] >> 4), hexchar(p[14] & 0xF), hexchar(p[14] >> 4),
731 hexchar(p[13] & 0xF), hexchar(p[13] >> 4), hexchar(p[12] & 0xF), hexchar(p[12] >> 4),
732 hexchar(p[11] & 0xF), hexchar(p[11] >> 4), hexchar(p[10] & 0xF), hexchar(p[10] >> 4),
733 hexchar(p[ 9] & 0xF), hexchar(p[ 9] >> 4), hexchar(p[ 8] & 0xF), hexchar(p[ 8] >> 4),
734 hexchar(p[ 7] & 0xF), hexchar(p[ 7] >> 4), hexchar(p[ 6] & 0xF), hexchar(p[ 6] >> 4),
735 hexchar(p[ 5] & 0xF), hexchar(p[ 5] >> 4), hexchar(p[ 4] & 0xF), hexchar(p[ 4] >> 4),
736 hexchar(p[ 3] & 0xF), hexchar(p[ 3] >> 4), hexchar(p[ 2] & 0xF), hexchar(p[ 2] >> 4),
737 hexchar(p[ 1] & 0xF), hexchar(p[ 1] >> 4), hexchar(p[ 0] & 0xF), hexchar(p[ 0] >> 4));
738 else
739 return -EAFNOSUPPORT;
740 if (r < 0)
741 return -ENOMEM;
742
743 return 0;
744 }
745
746 int dns_name_address(const char *p, int *family, union in_addr_union *address) {
747 int r;
748
749 assert(p);
750 assert(family);
751 assert(address);
752
753 r = dns_name_endswith(p, "in-addr.arpa");
754 if (r < 0)
755 return r;
756 if (r > 0) {
757 uint8_t a[4];
758 unsigned i;
759
760 for (i = 0; i < ELEMENTSOF(a); i++) {
761 char label[DNS_LABEL_MAX+1];
762
763 r = dns_label_unescape(&p, label, sizeof(label));
764 if (r < 0)
765 return r;
766 if (r == 0)
767 return -EINVAL;
768 if (r > 3)
769 return -EINVAL;
770
771 r = safe_atou8(label, &a[i]);
772 if (r < 0)
773 return r;
774 }
775
776 r = dns_name_equal(p, "in-addr.arpa");
777 if (r <= 0)
778 return r;
779
780 *family = AF_INET;
781 address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
782 ((uint32_t) a[2] << 16) |
783 ((uint32_t) a[1] << 8) |
784 (uint32_t) a[0]);
785
786 return 1;
787 }
788
789 r = dns_name_endswith(p, "ip6.arpa");
790 if (r < 0)
791 return r;
792 if (r > 0) {
793 struct in6_addr a;
794 unsigned i;
795
796 for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
797 char label[DNS_LABEL_MAX+1];
798 int x, y;
799
800 r = dns_label_unescape(&p, label, sizeof(label));
801 if (r <= 0)
802 return r;
803 if (r != 1)
804 return -EINVAL;
805 x = unhexchar(label[0]);
806 if (x < 0)
807 return -EINVAL;
808
809 r = dns_label_unescape(&p, label, sizeof(label));
810 if (r <= 0)
811 return r;
812 if (r != 1)
813 return -EINVAL;
814 y = unhexchar(label[0]);
815 if (y < 0)
816 return -EINVAL;
817
818 a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x;
819 }
820
821 r = dns_name_equal(p, "ip6.arpa");
822 if (r <= 0)
823 return r;
824
825 *family = AF_INET6;
826 address->in6 = a;
827 return 1;
828 }
829
830 return 0;
831 }
832
833 bool dns_name_is_root(const char *name) {
834
835 assert(name);
836
837 /* There are exactly two ways to encode the root domain name:
838 * as empty string, or with a single dot. */
839
840 return STR_IN_SET(name, "", ".");
841 }
842
843 bool dns_name_is_single_label(const char *name) {
844 int r;
845
846 assert(name);
847
848 r = dns_name_parent(&name);
849 if (r <= 0)
850 return false;
851
852 return dns_name_is_root(name);
853 }
854
855 /* Encode a domain name according to RFC 1035 Section 3.1, without compression */
856 int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical) {
857 uint8_t *label_length, *out;
858 int r;
859
860 assert(domain);
861 assert(buffer);
862
863 out = buffer;
864
865 do {
866 /* Reserve a byte for label length */
867 if (len <= 0)
868 return -ENOBUFS;
869 len--;
870 label_length = out;
871 out++;
872
873 /* Convert and copy a single label. Note that
874 * dns_label_unescape() returns 0 when it hits the end
875 * of the domain name, which we rely on here to encode
876 * the trailing NUL byte. */
877 r = dns_label_unescape(&domain, (char *) out, len);
878 if (r < 0)
879 return r;
880
881 /* Optionally, output the name in DNSSEC canonical
882 * format, as described in RFC 4034, section 6.2. Or
883 * in other words: in lower-case. */
884 if (canonical)
885 ascii_strlower_n((char*) out, (size_t) r);
886
887 /* Fill label length, move forward */
888 *label_length = r;
889 out += r;
890 len -= r;
891
892 } while (r != 0);
893
894 /* Verify the maximum size of the encoded name. The trailing
895 * dot + NUL byte account are included this time, hence
896 * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
897 * time. */
898 if (out - buffer > DNS_HOSTNAME_MAX + 2)
899 return -EINVAL;
900
901 return out - buffer;
902 }
903
904 static bool srv_type_label_is_valid(const char *label, size_t n) {
905 size_t k;
906
907 assert(label);
908
909 if (n < 2) /* Label needs to be at least 2 chars long */
910 return false;
911
912 if (label[0] != '_') /* First label char needs to be underscore */
913 return false;
914
915 /* Second char must be a letter */
916 if (!(label[1] >= 'A' && label[1] <= 'Z') &&
917 !(label[1] >= 'a' && label[1] <= 'z'))
918 return false;
919
920 /* Third and further chars must be alphanumeric or a hyphen */
921 for (k = 2; k < n; k++) {
922 if (!(label[k] >= 'A' && label[k] <= 'Z') &&
923 !(label[k] >= 'a' && label[k] <= 'z') &&
924 !(label[k] >= '0' && label[k] <= '9') &&
925 label[k] != '-')
926 return false;
927 }
928
929 return true;
930 }
931
932 bool dns_srv_type_is_valid(const char *name) {
933 unsigned c = 0;
934 int r;
935
936 if (!name)
937 return false;
938
939 for (;;) {
940 char label[DNS_LABEL_MAX];
941
942 /* This more or less implements RFC 6335, Section 5.1 */
943
944 r = dns_label_unescape(&name, label, sizeof(label));
945 if (r < 0)
946 return false;
947 if (r == 0)
948 break;
949
950 if (c >= 2)
951 return false;
952
953 if (!srv_type_label_is_valid(label, r))
954 return false;
955
956 c++;
957 }
958
959 return c == 2; /* exactly two labels */
960 }
961
962 bool dns_service_name_is_valid(const char *name) {
963 size_t l;
964
965 /* This more or less implements RFC 6763, Section 4.1.1 */
966
967 if (!name)
968 return false;
969
970 if (!utf8_is_valid(name))
971 return false;
972
973 if (string_has_cc(name, NULL))
974 return false;
975
976 l = strlen(name);
977 if (l <= 0)
978 return false;
979 if (l > 63)
980 return false;
981
982 return true;
983 }
984
985 int dns_service_join(const char *name, const char *type, const char *domain, char **ret) {
986 char escaped[DNS_LABEL_ESCAPED_MAX];
987 _cleanup_free_ char *n = NULL;
988 int r;
989
990 assert(type);
991 assert(domain);
992 assert(ret);
993
994 if (!dns_srv_type_is_valid(type))
995 return -EINVAL;
996
997 if (!name)
998 return dns_name_concat(type, domain, ret);
999
1000 if (!dns_service_name_is_valid(name))
1001 return -EINVAL;
1002
1003 r = dns_label_escape(name, strlen(name), escaped, sizeof(escaped));
1004 if (r < 0)
1005 return r;
1006
1007 r = dns_name_concat(type, domain, &n);
1008 if (r < 0)
1009 return r;
1010
1011 return dns_name_concat(escaped, n, ret);
1012 }
1013
1014 static bool dns_service_name_label_is_valid(const char *label, size_t n) {
1015 char *s;
1016
1017 assert(label);
1018
1019 if (memchr(label, 0, n))
1020 return false;
1021
1022 s = strndupa(label, n);
1023 return dns_service_name_is_valid(s);
1024 }
1025
1026 int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) {
1027 _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
1028 const char *p = joined, *q = NULL, *d = NULL;
1029 char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX];
1030 int an, bn, cn, r;
1031 unsigned x = 0;
1032
1033 assert(joined);
1034
1035 /* Get first label from the full name */
1036 an = dns_label_unescape(&p, a, sizeof(a));
1037 if (an < 0)
1038 return an;
1039
1040 if (an > 0) {
1041 x++;
1042
1043 /* If there was a first label, try to get the second one */
1044 bn = dns_label_unescape(&p, b, sizeof(b));
1045 if (bn < 0)
1046 return bn;
1047
1048 if (bn > 0) {
1049 x++;
1050
1051 /* If there was a second label, try to get the third one */
1052 q = p;
1053 cn = dns_label_unescape(&p, c, sizeof(c));
1054 if (cn < 0)
1055 return cn;
1056
1057 if (cn > 0)
1058 x++;
1059 } else
1060 cn = 0;
1061 } else
1062 an = 0;
1063
1064 if (x >= 2 && srv_type_label_is_valid(b, bn)) {
1065
1066 if (x >= 3 && srv_type_label_is_valid(c, cn)) {
1067
1068 if (dns_service_name_label_is_valid(a, an)) {
1069 /* OK, got <name> . <type> . <type2> . <domain> */
1070
1071 name = strndup(a, an);
1072 if (!name)
1073 return -ENOMEM;
1074
1075 type = strjoin(b, ".", c);
1076 if (!type)
1077 return -ENOMEM;
1078
1079 d = p;
1080 goto finish;
1081 }
1082
1083 } else if (srv_type_label_is_valid(a, an)) {
1084
1085 /* OK, got <type> . <type2> . <domain> */
1086
1087 name = NULL;
1088
1089 type = strjoin(a, ".", b);
1090 if (!type)
1091 return -ENOMEM;
1092
1093 d = q;
1094 goto finish;
1095 }
1096 }
1097
1098 name = NULL;
1099 type = NULL;
1100 d = joined;
1101
1102 finish:
1103 r = dns_name_normalize(d, &domain);
1104 if (r < 0)
1105 return r;
1106
1107 if (_domain) {
1108 *_domain = domain;
1109 domain = NULL;
1110 }
1111
1112 if (_type) {
1113 *_type = type;
1114 type = NULL;
1115 }
1116
1117 if (_name) {
1118 *_name = name;
1119 name = NULL;
1120 }
1121
1122 return 0;
1123 }
1124
1125 static int dns_name_build_suffix_table(const char *name, const char*table[]) {
1126 const char *p;
1127 unsigned n = 0;
1128 int r;
1129
1130 assert(name);
1131 assert(table);
1132
1133 p = name;
1134 for (;;) {
1135 if (n > DNS_N_LABELS_MAX)
1136 return -EINVAL;
1137
1138 table[n] = p;
1139 r = dns_name_parent(&p);
1140 if (r < 0)
1141 return r;
1142 if (r == 0)
1143 break;
1144
1145 n++;
1146 }
1147
1148 return (int) n;
1149 }
1150
1151 int dns_name_suffix(const char *name, unsigned n_labels, const char **ret) {
1152 const char* labels[DNS_N_LABELS_MAX+1];
1153 int n;
1154
1155 assert(name);
1156 assert(ret);
1157
1158 n = dns_name_build_suffix_table(name, labels);
1159 if (n < 0)
1160 return n;
1161
1162 if ((unsigned) n < n_labels)
1163 return -EINVAL;
1164
1165 *ret = labels[n - n_labels];
1166 return (int) (n - n_labels);
1167 }
1168
1169 int dns_name_skip(const char *a, unsigned n_labels, const char **ret) {
1170 int r;
1171
1172 assert(a);
1173 assert(ret);
1174
1175 for (; n_labels > 0; n_labels--) {
1176 r = dns_name_parent(&a);
1177 if (r < 0)
1178 return r;
1179 if (r == 0) {
1180 *ret = "";
1181 return 0;
1182 }
1183 }
1184
1185 *ret = a;
1186 return 1;
1187 }
1188
1189 int dns_name_count_labels(const char *name) {
1190 unsigned n = 0;
1191 const char *p;
1192 int r;
1193
1194 assert(name);
1195
1196 p = name;
1197 for (;;) {
1198 r = dns_name_parent(&p);
1199 if (r < 0)
1200 return r;
1201 if (r == 0)
1202 break;
1203
1204 if (n >= DNS_N_LABELS_MAX)
1205 return -EINVAL;
1206
1207 n++;
1208 }
1209
1210 return (int) n;
1211 }
1212
1213 int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b) {
1214 int r;
1215
1216 assert(a);
1217 assert(b);
1218
1219 r = dns_name_skip(a, n_labels, &a);
1220 if (r <= 0)
1221 return r;
1222
1223 return dns_name_equal(a, b);
1224 }
1225
1226 int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
1227 const char *a_labels[DNS_N_LABELS_MAX+1], *b_labels[DNS_N_LABELS_MAX+1];
1228 int n = 0, m = 0, k = 0, r, q;
1229
1230 assert(a);
1231 assert(b);
1232 assert(ret);
1233
1234 /* Determines the common suffix of domain names a and b */
1235
1236 n = dns_name_build_suffix_table(a, a_labels);
1237 if (n < 0)
1238 return n;
1239
1240 m = dns_name_build_suffix_table(b, b_labels);
1241 if (m < 0)
1242 return m;
1243
1244 for (;;) {
1245 char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
1246 const char *x, *y;
1247
1248 if (k >= n || k >= m) {
1249 *ret = a_labels[n - k];
1250 return 0;
1251 }
1252
1253 x = a_labels[n - 1 - k];
1254 r = dns_label_unescape(&x, la, sizeof(la));
1255 if (r < 0)
1256 return r;
1257
1258 y = b_labels[m - 1 - k];
1259 q = dns_label_unescape(&y, lb, sizeof(lb));
1260 if (q < 0)
1261 return q;
1262
1263 if (r != q || ascii_strcasecmp_n(la, lb, r) != 0) {
1264 *ret = a_labels[n - k];
1265 return 0;
1266 }
1267
1268 k++;
1269 }
1270 }
1271
1272 int dns_name_apply_idna(const char *name, char **ret) {
1273 /* Return negative on error, 0 if not implemented, positive on success. */
1274
1275 #if HAVE_LIBIDN2
1276 int r;
1277 _cleanup_free_ char *t = NULL;
1278
1279 assert(name);
1280 assert(ret);
1281
1282 r = idn2_lookup_u8((uint8_t*) name, (uint8_t**) &t,
1283 IDN2_NFC_INPUT | IDN2_NONTRANSITIONAL);
1284 log_debug("idn2_lookup_u8: %s → %s", name, t);
1285 if (r == IDN2_OK) {
1286 if (!startswith(name, "xn--")) {
1287 _cleanup_free_ char *s = NULL;
1288
1289 r = idn2_to_unicode_8z8z(t, &s, 0);
1290 if (r != IDN2_OK) {
1291 log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
1292 t, r, idn2_strerror(r));
1293 return 0;
1294 }
1295
1296 if (!streq_ptr(name, s)) {
1297 log_debug("idn2 roundtrip failed: \"%s\" \"%s\" \"%s\", ignoring.",
1298 name, t, s);
1299 return 0;
1300 }
1301 }
1302
1303 *ret = t;
1304 t = NULL;
1305 return 1; /* *ret has been written */
1306 }
1307
1308 log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name, r, idn2_strerror(r));
1309 if (r == IDN2_2HYPHEN)
1310 /* The name has two hypens — forbidden by IDNA2008 in some cases */
1311 return 0;
1312 if (IN_SET(r, IDN2_TOO_BIG_DOMAIN, IDN2_TOO_BIG_LABEL))
1313 return -ENOSPC;
1314 return -EINVAL;
1315 #elif HAVE_LIBIDN
1316 _cleanup_free_ char *buf = NULL;
1317 size_t n = 0, allocated = 0;
1318 bool first = true;
1319 int r, q;
1320
1321 assert(name);
1322 assert(ret);
1323
1324 for (;;) {
1325 char label[DNS_LABEL_MAX];
1326
1327 r = dns_label_unescape(&name, label, sizeof(label));
1328 if (r < 0)
1329 return r;
1330 if (r == 0)
1331 break;
1332
1333 q = dns_label_apply_idna(label, r, label, sizeof(label));
1334 if (q < 0)
1335 return q;
1336 if (q > 0)
1337 r = q;
1338
1339 if (!GREEDY_REALLOC(buf, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
1340 return -ENOMEM;
1341
1342 r = dns_label_escape(label, r, buf + n + !first, DNS_LABEL_ESCAPED_MAX);
1343 if (r < 0)
1344 return r;
1345
1346 if (first)
1347 first = false;
1348 else
1349 buf[n++] = '.';
1350
1351 n += r;
1352 }
1353
1354 if (n > DNS_HOSTNAME_MAX)
1355 return -EINVAL;
1356
1357 if (!GREEDY_REALLOC(buf, allocated, n + 1))
1358 return -ENOMEM;
1359
1360 buf[n] = 0;
1361 *ret = buf;
1362 buf = NULL;
1363
1364 return 1;
1365 #else
1366 return 0;
1367 #endif
1368 }
1369
1370 int dns_name_is_valid_or_address(const char *name) {
1371 /* Returns > 0 if the specified name is either a valid IP address formatted as string or a valid DNS name */
1372
1373 if (isempty(name))
1374 return 0;
1375
1376 if (in_addr_from_string_auto(name, NULL, NULL) >= 0)
1377 return 1;
1378
1379 return dns_name_is_valid(name);
1380 }