]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/dns-domain.c
shared: replace a few invocations of strcasecmp() for DNS labels with ascii_strcasecm...
[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 p++;
269 l--;
270 }
271
272 *q = 0;
273 return (int) (q - dest);
274 }
275
276 int dns_label_escape_new(const char *p, size_t l, char **ret) {
277 _cleanup_free_ char *s = NULL;
278 int r;
279
280 assert(p);
281 assert(ret);
282
283 if (l <= 0 || l > DNS_LABEL_MAX)
284 return -EINVAL;
285
286 s = new(char, DNS_LABEL_ESCAPED_MAX);
287 if (!s)
288 return -ENOMEM;
289
290 r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX);
291 if (r < 0)
292 return r;
293
294 *ret = s;
295 s = NULL;
296
297 return r;
298 }
299
300 int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
301 #ifdef HAVE_LIBIDN
302 _cleanup_free_ uint32_t *input = NULL;
303 size_t input_size, l;
304 const char *p;
305 bool contains_8bit = false;
306 char buffer[DNS_LABEL_MAX+1];
307
308 assert(encoded);
309 assert(decoded);
310
311 /* Converts an U-label into an A-label */
312
313 if (encoded_size <= 0)
314 return -EINVAL;
315
316 for (p = encoded; p < encoded + encoded_size; p++)
317 if ((uint8_t) *p > 127)
318 contains_8bit = true;
319
320 if (!contains_8bit) {
321 if (encoded_size > DNS_LABEL_MAX)
322 return -EINVAL;
323
324 return 0;
325 }
326
327 input = stringprep_utf8_to_ucs4(encoded, encoded_size, &input_size);
328 if (!input)
329 return -ENOMEM;
330
331 if (idna_to_ascii_4i(input, input_size, buffer, 0) != 0)
332 return -EINVAL;
333
334 l = strlen(buffer);
335
336 /* Verify that the the result is not longer than one DNS label. */
337 if (l <= 0 || l > DNS_LABEL_MAX)
338 return -EINVAL;
339 if (l > decoded_max)
340 return -ENOBUFS;
341
342 memcpy(decoded, buffer, l);
343
344 /* If there's room, append a trailing NUL byte, but only then */
345 if (decoded_max > l)
346 decoded[l] = 0;
347
348 return (int) l;
349 #else
350 return 0;
351 #endif
352 }
353
354 int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max) {
355 #ifdef HAVE_LIBIDN
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 #else
401 return 0;
402 #endif
403 }
404
405 int dns_name_concat(const char *a, const char *b, char **_ret) {
406 _cleanup_free_ char *ret = NULL;
407 size_t n = 0, allocated = 0;
408 const char *p = a;
409 bool first = true;
410 int r;
411
412 assert(a);
413
414 for (;;) {
415 char label[DNS_LABEL_MAX];
416 int k;
417
418 r = dns_label_unescape(&p, label, sizeof(label));
419 if (r < 0)
420 return r;
421 if (r == 0) {
422 if (*p != 0)
423 return -EINVAL;
424
425 if (b) {
426 /* Now continue with the second string, if there is one */
427 p = b;
428 b = NULL;
429 continue;
430 }
431
432 break;
433 }
434
435 k = dns_label_undo_idna(label, r, label, sizeof(label));
436 if (k < 0)
437 return k;
438 if (k > 0)
439 r = k;
440
441 if (_ret) {
442 if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
443 return -ENOMEM;
444
445 r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX);
446 if (r < 0)
447 return r;
448
449 if (!first)
450 ret[n] = '.';
451 } else {
452 char escaped[DNS_LABEL_ESCAPED_MAX];
453
454 r = dns_label_escape(label, r, escaped, sizeof(escaped));
455 if (r < 0)
456 return r;
457 }
458
459 if (!first)
460 n++;
461 else
462 first = false;
463
464 n += r;
465 }
466
467 if (n > DNS_HOSTNAME_MAX)
468 return -EINVAL;
469
470 if (_ret) {
471 if (!GREEDY_REALLOC(ret, allocated, n + 1))
472 return -ENOMEM;
473
474 ret[n] = 0;
475 *_ret = ret;
476 ret = NULL;
477 }
478
479 return 0;
480 }
481
482 void dns_name_hash_func(const void *s, struct siphash *state) {
483 const char *p = s;
484 int r;
485
486 assert(p);
487
488 for (;;) {
489 char label[DNS_LABEL_MAX+1];
490 int k;
491
492 r = dns_label_unescape(&p, label, sizeof(label));
493 if (r < 0)
494 break;
495 if (r == 0)
496 break;
497
498 k = dns_label_undo_idna(label, r, label, sizeof(label));
499 if (k < 0)
500 break;
501 if (k > 0)
502 r = k;
503
504 ascii_strlower_n(label, r);
505 siphash24_compress(label, r, state);
506 siphash24_compress_byte(0, state); /* make sure foobar and foo.bar result in different hashes */
507 }
508
509 /* enforce that all names are terminated by the empty label */
510 string_hash_func("", state);
511 }
512
513 int dns_name_compare_func(const void *a, const void *b) {
514 const char *x, *y;
515 int r, q, k, w;
516
517 assert(a);
518 assert(b);
519
520 x = (const char *) a + strlen(a);
521 y = (const char *) b + strlen(b);
522
523 for (;;) {
524 char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
525
526 if (x == NULL && y == NULL)
527 return 0;
528
529 r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
530 q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
531 if (r < 0 || q < 0)
532 return r - q;
533
534 k = dns_label_undo_idna(la, r, la, sizeof(la));
535 w = dns_label_undo_idna(lb, q, lb, sizeof(lb));
536 if (k < 0 || w < 0)
537 return k - w;
538 if (k > 0)
539 r = k;
540 if (w > 0)
541 q = w;
542
543 la[r] = lb[q] = 0;
544 r = strcasecmp(la, lb);
545 if (r != 0)
546 return r;
547 }
548 }
549
550 const struct hash_ops dns_name_hash_ops = {
551 .hash = dns_name_hash_func,
552 .compare = dns_name_compare_func
553 };
554
555 int dns_name_equal(const char *x, const char *y) {
556 int r, q, k, w;
557
558 assert(x);
559 assert(y);
560
561 for (;;) {
562 char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX];
563
564 r = dns_label_unescape(&x, la, sizeof(la));
565 if (r < 0)
566 return r;
567 if (r > 0) {
568 k = dns_label_undo_idna(la, r, la, sizeof(la));
569 if (k < 0)
570 return k;
571 if (k > 0)
572 r = k;
573 }
574
575 q = dns_label_unescape(&y, lb, sizeof(lb));
576 if (q < 0)
577 return q;
578 if (q > 0) {
579 w = dns_label_undo_idna(lb, q, lb, sizeof(lb));
580 if (w < 0)
581 return w;
582 if (w > 0)
583 q = w;
584 }
585
586 if (r != q)
587 return false;
588 if (r == 0)
589 return true;
590
591 if (ascii_strcasecmp_n(la, lb, r) != 0)
592 return false;
593 }
594 }
595
596 int dns_name_endswith(const char *name, const char *suffix) {
597 const char *n, *s, *saved_n = NULL;
598 int r, q, k, w;
599
600 assert(name);
601 assert(suffix);
602
603 n = name;
604 s = suffix;
605
606 for (;;) {
607 char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
608
609 r = dns_label_unescape(&n, ln, sizeof(ln));
610 if (r < 0)
611 return r;
612 if (r > 0) {
613 k = dns_label_undo_idna(ln, r, ln, sizeof(ln));
614 if (k < 0)
615 return k;
616 if (k > 0)
617 r = k;
618 }
619
620 if (!saved_n)
621 saved_n = n;
622
623 q = dns_label_unescape(&s, ls, sizeof(ls));
624 if (q < 0)
625 return q;
626 if (q > 0) {
627 w = dns_label_undo_idna(ls, q, ls, sizeof(ls));
628 if (w < 0)
629 return w;
630 if (w > 0)
631 q = w;
632 }
633
634 if (r == 0 && q == 0)
635 return true;
636 if (r == 0 && saved_n == n)
637 return false;
638
639 if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) {
640
641 /* Not the same, let's jump back, and try with the next label again */
642 s = suffix;
643 n = saved_n;
644 saved_n = NULL;
645 }
646 }
647 }
648
649 static int dns_label_unescape_undo_idna(const char **name, char *dest, size_t sz) {
650 int r, k;
651
652 /* Clobbers all arguments on failure... */
653
654 r = dns_label_unescape(name, dest, sz);
655 if (r <= 0)
656 return r;
657
658 k = dns_label_undo_idna(dest, r, dest, sz);
659 if (k < 0)
660 return k;
661 if (k == 0) /* not an IDNA name */
662 return r;
663
664 return k;
665 }
666
667 int dns_name_startswith(const char *name, const char *prefix) {
668 const char *n, *p;
669 int r, q;
670
671 assert(name);
672 assert(prefix);
673
674 n = name;
675 p = prefix;
676
677 for (;;) {
678 char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX];
679
680 r = dns_label_unescape_undo_idna(&p, lp, sizeof(lp));
681 if (r < 0)
682 return r;
683 if (r == 0)
684 return true;
685
686 q = dns_label_unescape_undo_idna(&n, ln, sizeof(ln));
687 if (q < 0)
688 return q;
689
690 if (r != q)
691 return false;
692 if (ascii_strcasecmp_n(ln, lp, r) != 0)
693 return false;
694 }
695 }
696
697 int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) {
698 const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix;
699 int r, q, k, w;
700
701 assert(name);
702 assert(old_suffix);
703 assert(new_suffix);
704 assert(ret);
705
706 n = name;
707 s = old_suffix;
708
709 for (;;) {
710 char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX];
711
712 if (!saved_before)
713 saved_before = n;
714
715 r = dns_label_unescape(&n, ln, sizeof(ln));
716 if (r < 0)
717 return r;
718 if (r > 0) {
719 k = dns_label_undo_idna(ln, r, ln, sizeof(ln));
720 if (k < 0)
721 return k;
722 if (k > 0)
723 r = k;
724 }
725
726 if (!saved_after)
727 saved_after = n;
728
729 q = dns_label_unescape(&s, ls, sizeof(ls));
730 if (q < 0)
731 return q;
732 if (q > 0) {
733 w = dns_label_undo_idna(ls, q, ls, sizeof(ls));
734 if (w < 0)
735 return w;
736 if (w > 0)
737 q = w;
738 }
739
740 if (r == 0 && q == 0)
741 break;
742 if (r == 0 && saved_after == n) {
743 *ret = NULL; /* doesn't match */
744 return 0;
745 }
746
747 if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) {
748
749 /* Not the same, let's jump back, and try with the next label again */
750 s = old_suffix;
751 n = saved_after;
752 saved_after = saved_before = NULL;
753 }
754 }
755
756 /* Found it! Now generate the new name */
757 prefix = strndupa(name, saved_before - name);
758
759 r = dns_name_concat(prefix, new_suffix, ret);
760 if (r < 0)
761 return r;
762
763 return 1;
764 }
765
766 int dns_name_between(const char *a, const char *b, const char *c) {
767 int n;
768
769 /* Determine if b is strictly greater than a and strictly smaller than c.
770 We consider the order of names to be circular, so that if a is
771 strictly greater than c, we consider b to be between them if it is
772 either greater than a or smaller than c. This is how the canonical
773 DNS name order used in NSEC records work. */
774
775 n = dns_name_compare_func(a, c);
776 if (n == 0)
777 return -EINVAL;
778 else if (n < 0)
779 /* a<---b--->c */
780 return dns_name_compare_func(a, b) < 0 &&
781 dns_name_compare_func(b, c) < 0;
782 else
783 /* <--b--c a--b--> */
784 return dns_name_compare_func(b, c) < 0 ||
785 dns_name_compare_func(a, b) < 0;
786 }
787
788 int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
789 const uint8_t *p;
790 int r;
791
792 assert(a);
793 assert(ret);
794
795 p = (const uint8_t*) a;
796
797 if (family == AF_INET)
798 r = asprintf(ret, "%u.%u.%u.%u.in-addr.arpa", p[3], p[2], p[1], p[0]);
799 else if (family == AF_INET6)
800 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",
801 hexchar(p[15] & 0xF), hexchar(p[15] >> 4), hexchar(p[14] & 0xF), hexchar(p[14] >> 4),
802 hexchar(p[13] & 0xF), hexchar(p[13] >> 4), hexchar(p[12] & 0xF), hexchar(p[12] >> 4),
803 hexchar(p[11] & 0xF), hexchar(p[11] >> 4), hexchar(p[10] & 0xF), hexchar(p[10] >> 4),
804 hexchar(p[ 9] & 0xF), hexchar(p[ 9] >> 4), hexchar(p[ 8] & 0xF), hexchar(p[ 8] >> 4),
805 hexchar(p[ 7] & 0xF), hexchar(p[ 7] >> 4), hexchar(p[ 6] & 0xF), hexchar(p[ 6] >> 4),
806 hexchar(p[ 5] & 0xF), hexchar(p[ 5] >> 4), hexchar(p[ 4] & 0xF), hexchar(p[ 4] >> 4),
807 hexchar(p[ 3] & 0xF), hexchar(p[ 3] >> 4), hexchar(p[ 2] & 0xF), hexchar(p[ 2] >> 4),
808 hexchar(p[ 1] & 0xF), hexchar(p[ 1] >> 4), hexchar(p[ 0] & 0xF), hexchar(p[ 0] >> 4));
809 else
810 return -EAFNOSUPPORT;
811 if (r < 0)
812 return -ENOMEM;
813
814 return 0;
815 }
816
817 int dns_name_address(const char *p, int *family, union in_addr_union *address) {
818 int r;
819
820 assert(p);
821 assert(family);
822 assert(address);
823
824 r = dns_name_endswith(p, "in-addr.arpa");
825 if (r < 0)
826 return r;
827 if (r > 0) {
828 uint8_t a[4];
829 unsigned i;
830
831 for (i = 0; i < ELEMENTSOF(a); i++) {
832 char label[DNS_LABEL_MAX+1];
833
834 r = dns_label_unescape(&p, label, sizeof(label));
835 if (r < 0)
836 return r;
837 if (r == 0)
838 return -EINVAL;
839 if (r > 3)
840 return -EINVAL;
841
842 r = safe_atou8(label, &a[i]);
843 if (r < 0)
844 return r;
845 }
846
847 r = dns_name_equal(p, "in-addr.arpa");
848 if (r <= 0)
849 return r;
850
851 *family = AF_INET;
852 address->in.s_addr = htobe32(((uint32_t) a[3] << 24) |
853 ((uint32_t) a[2] << 16) |
854 ((uint32_t) a[1] << 8) |
855 (uint32_t) a[0]);
856
857 return 1;
858 }
859
860 r = dns_name_endswith(p, "ip6.arpa");
861 if (r < 0)
862 return r;
863 if (r > 0) {
864 struct in6_addr a;
865 unsigned i;
866
867 for (i = 0; i < ELEMENTSOF(a.s6_addr); i++) {
868 char label[DNS_LABEL_MAX+1];
869 int x, y;
870
871 r = dns_label_unescape(&p, label, sizeof(label));
872 if (r <= 0)
873 return r;
874 if (r != 1)
875 return -EINVAL;
876 x = unhexchar(label[0]);
877 if (x < 0)
878 return -EINVAL;
879
880 r = dns_label_unescape(&p, label, sizeof(label));
881 if (r <= 0)
882 return r;
883 if (r != 1)
884 return -EINVAL;
885 y = unhexchar(label[0]);
886 if (y < 0)
887 return -EINVAL;
888
889 a.s6_addr[ELEMENTSOF(a.s6_addr) - i - 1] = (uint8_t) y << 4 | (uint8_t) x;
890 }
891
892 r = dns_name_equal(p, "ip6.arpa");
893 if (r <= 0)
894 return r;
895
896 *family = AF_INET6;
897 address->in6 = a;
898 return 1;
899 }
900
901 return 0;
902 }
903
904 bool dns_name_is_root(const char *name) {
905
906 assert(name);
907
908 /* There are exactly two ways to encode the root domain name:
909 * as empty string, or with a single dot. */
910
911 return STR_IN_SET(name, "", ".");
912 }
913
914 bool dns_name_is_single_label(const char *name) {
915 char label[DNS_LABEL_MAX+1];
916 int r;
917
918 assert(name);
919
920 r = dns_label_unescape(&name, label, sizeof(label));
921 if (r <= 0)
922 return false;
923
924 return dns_name_is_root(name);
925 }
926
927 /* Encode a domain name according to RFC 1035 Section 3.1, without compression */
928 int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len, bool canonical) {
929 uint8_t *label_length, *out;
930 int r;
931
932 assert(domain);
933 assert(buffer);
934
935 out = buffer;
936
937 do {
938 /* Reserve a byte for label length */
939 if (len <= 0)
940 return -ENOBUFS;
941 len--;
942 label_length = out;
943 out++;
944
945 /* Convert and copy a single label. Note that
946 * dns_label_unescape() returns 0 when it hits the end
947 * of the domain name, which we rely on here to encode
948 * the trailing NUL byte. */
949 r = dns_label_unescape(&domain, (char *) out, len);
950 if (r < 0)
951 return r;
952
953 /* Optionally, output the name in DNSSEC canonical
954 * format, as described in RFC 4034, section 6.2. Or
955 * in other words: in lower-case. */
956 if (canonical)
957 ascii_strlower_n((char*) out, (size_t) r);
958
959 /* Fill label length, move forward */
960 *label_length = r;
961 out += r;
962 len -= r;
963
964 } while (r != 0);
965
966 /* Verify the maximum size of the encoded name. The trailing
967 * dot + NUL byte account are included this time, hence
968 * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
969 * time. */
970 if (out - buffer > DNS_HOSTNAME_MAX + 2)
971 return -EINVAL;
972
973 return out - buffer;
974 }
975
976 static bool srv_type_label_is_valid(const char *label, size_t n) {
977 size_t k;
978
979 assert(label);
980
981 if (n < 2) /* Label needs to be at least 2 chars long */
982 return false;
983
984 if (label[0] != '_') /* First label char needs to be underscore */
985 return false;
986
987 /* Second char must be a letter */
988 if (!(label[1] >= 'A' && label[1] <= 'Z') &&
989 !(label[1] >= 'a' && label[1] <= 'z'))
990 return false;
991
992 /* Third and further chars must be alphanumeric or a hyphen */
993 for (k = 2; k < n; k++) {
994 if (!(label[k] >= 'A' && label[k] <= 'Z') &&
995 !(label[k] >= 'a' && label[k] <= 'z') &&
996 !(label[k] >= '0' && label[k] <= '9') &&
997 label[k] != '-')
998 return false;
999 }
1000
1001 return true;
1002 }
1003
1004 bool dns_srv_type_is_valid(const char *name) {
1005 unsigned c = 0;
1006 int r;
1007
1008 if (!name)
1009 return false;
1010
1011 for (;;) {
1012 char label[DNS_LABEL_MAX];
1013
1014 /* This more or less implements RFC 6335, Section 5.1 */
1015
1016 r = dns_label_unescape(&name, label, sizeof(label));
1017 if (r < 0)
1018 return false;
1019 if (r == 0)
1020 break;
1021
1022 if (c >= 2)
1023 return false;
1024
1025 if (!srv_type_label_is_valid(label, r))
1026 return false;
1027
1028 c++;
1029 }
1030
1031 return c == 2; /* exactly two labels */
1032 }
1033
1034 bool dns_service_name_is_valid(const char *name) {
1035 size_t l;
1036
1037 /* This more or less implements RFC 6763, Section 4.1.1 */
1038
1039 if (!name)
1040 return false;
1041
1042 if (!utf8_is_valid(name))
1043 return false;
1044
1045 if (string_has_cc(name, NULL))
1046 return false;
1047
1048 l = strlen(name);
1049 if (l <= 0)
1050 return false;
1051 if (l > 63)
1052 return false;
1053
1054 return true;
1055 }
1056
1057 int dns_service_join(const char *name, const char *type, const char *domain, char **ret) {
1058 char escaped[DNS_LABEL_ESCAPED_MAX];
1059 _cleanup_free_ char *n = NULL;
1060 int r;
1061
1062 assert(type);
1063 assert(domain);
1064 assert(ret);
1065
1066 if (!dns_srv_type_is_valid(type))
1067 return -EINVAL;
1068
1069 if (!name)
1070 return dns_name_concat(type, domain, ret);
1071
1072 if (!dns_service_name_is_valid(name))
1073 return -EINVAL;
1074
1075 r = dns_label_escape(name, strlen(name), escaped, sizeof(escaped));
1076 if (r < 0)
1077 return r;
1078
1079 r = dns_name_concat(type, domain, &n);
1080 if (r < 0)
1081 return r;
1082
1083 return dns_name_concat(escaped, n, ret);
1084 }
1085
1086 static bool dns_service_name_label_is_valid(const char *label, size_t n) {
1087 char *s;
1088
1089 assert(label);
1090
1091 if (memchr(label, 0, n))
1092 return false;
1093
1094 s = strndupa(label, n);
1095 return dns_service_name_is_valid(s);
1096 }
1097
1098 int dns_service_split(const char *joined, char **_name, char **_type, char **_domain) {
1099 _cleanup_free_ char *name = NULL, *type = NULL, *domain = NULL;
1100 const char *p = joined, *q = NULL, *d = NULL;
1101 char a[DNS_LABEL_MAX], b[DNS_LABEL_MAX], c[DNS_LABEL_MAX];
1102 int an, bn, cn, r;
1103 unsigned x = 0;
1104
1105 assert(joined);
1106
1107 /* Get first label from the full name */
1108 an = dns_label_unescape(&p, a, sizeof(a));
1109 if (an < 0)
1110 return an;
1111
1112 if (an > 0) {
1113 x++;
1114
1115 /* If there was a first label, try to get the second one */
1116 bn = dns_label_unescape(&p, b, sizeof(b));
1117 if (bn < 0)
1118 return bn;
1119
1120 if (bn > 0) {
1121 x++;
1122
1123 /* If there was a second label, try to get the third one */
1124 q = p;
1125 cn = dns_label_unescape(&p, c, sizeof(c));
1126 if (cn < 0)
1127 return cn;
1128
1129 if (cn > 0)
1130 x++;
1131 } else
1132 cn = 0;
1133 } else
1134 an = 0;
1135
1136 if (x >= 2 && srv_type_label_is_valid(b, bn)) {
1137
1138 if (x >= 3 && srv_type_label_is_valid(c, cn)) {
1139
1140 if (dns_service_name_label_is_valid(a, an)) {
1141
1142 /* OK, got <name> . <type> . <type2> . <domain> */
1143
1144 name = strndup(a, an);
1145 if (!name)
1146 return -ENOMEM;
1147
1148 type = new(char, bn+1+cn+1);
1149 if (!type)
1150 return -ENOMEM;
1151 strcpy(stpcpy(stpcpy(type, b), "."), c);
1152
1153 d = p;
1154 goto finish;
1155 }
1156
1157 } else if (srv_type_label_is_valid(a, an)) {
1158
1159 /* OK, got <type> . <type2> . <domain> */
1160
1161 name = NULL;
1162
1163 type = new(char, an+1+bn+1);
1164 if (!type)
1165 return -ENOMEM;
1166 strcpy(stpcpy(stpcpy(type, a), "."), b);
1167
1168 d = q;
1169 goto finish;
1170 }
1171 }
1172
1173 name = NULL;
1174 type = NULL;
1175 d = joined;
1176
1177 finish:
1178 r = dns_name_normalize(d, &domain);
1179 if (r < 0)
1180 return r;
1181
1182 if (_domain) {
1183 *_domain = domain;
1184 domain = NULL;
1185 }
1186
1187 if (_type) {
1188 *_type = type;
1189 type = NULL;
1190 }
1191
1192 if (_name) {
1193 *_name = name;
1194 name = NULL;
1195 }
1196
1197 return 0;
1198 }
1199
1200 int dns_name_suffix(const char *name, unsigned n_labels, const char **ret) {
1201 const char* labels[DNS_N_LABELS_MAX+1];
1202 unsigned n = 0;
1203 const char *p;
1204 int r;
1205
1206 assert(name);
1207 assert(ret);
1208
1209 p = name;
1210 for (;;) {
1211 if (n > DNS_N_LABELS_MAX)
1212 return -EINVAL;
1213
1214 labels[n] = p;
1215
1216 r = dns_name_parent(&p);
1217 if (r < 0)
1218 return r;
1219 if (r == 0)
1220 break;
1221
1222 n++;
1223 }
1224
1225 if (n < n_labels)
1226 return -EINVAL;
1227
1228 *ret = labels[n - n_labels];
1229 return (int) (n - n_labels);
1230 }
1231
1232 int dns_name_count_labels(const char *name) {
1233 unsigned n = 0;
1234 const char *p;
1235 int r;
1236
1237 assert(name);
1238
1239 p = name;
1240 for (;;) {
1241 r = dns_name_parent(&p);
1242 if (r < 0)
1243 return r;
1244 if (r == 0)
1245 break;
1246
1247 if (n >= DNS_N_LABELS_MAX)
1248 return -EINVAL;
1249
1250 n++;
1251 }
1252
1253 return (int) n;
1254 }
1255
1256 int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b) {
1257 int r;
1258
1259 assert(a);
1260 assert(b);
1261
1262 while (n_labels > 0) {
1263
1264 r = dns_name_parent(&a);
1265 if (r <= 0)
1266 return r;
1267
1268 n_labels --;
1269 }
1270
1271 return dns_name_equal(a, b);
1272 }