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