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