1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2014 Lennart Poettering
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.
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.
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/>.
24 #include <stringprep.h>
28 #include <netinet/in.h>
31 #include <sys/socket.h>
33 #include "alloc-util.h"
34 #include "dns-domain.h"
36 #include "hexdecoct.h"
37 #include "in-addr-util.h"
39 #include "parse-util.h"
40 #include "string-util.h"
44 int dns_label_unescape(const char **name
, char *dest
, size_t sz
) {
64 if (r
>= DNS_LABEL_MAX
)
71 /* Escaped character */
79 else if (*n
== '\\' || *n
== '.') {
80 /* Escaped backslash or dot */
88 } else if (n
[0] >= '0' && n
[0] <= '9') {
91 /* Escaped literal ASCII character */
93 if (!(n
[1] >= '0' && n
[1] <= '9') ||
94 !(n
[2] >= '0' && n
[2] <= '9'))
97 k
= ((unsigned) (n
[0] - '0') * 100) +
98 ((unsigned) (n
[1] - '0') * 10) +
99 ((unsigned) (n
[2] - '0'));
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
119 } else if ((uint8_t) *n
>= (uint8_t) ' ' && *n
!= 127) {
121 /* Normal character */
132 /* Empty label that is not at the end? */
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
146 int dns_label_unescape_suffix(const char *name
, const char **label_terminal
, char *dest
, size_t sz
) {
147 const char *terminal
;
151 assert(label_terminal
);
155 if (!*label_terminal
) {
162 terminal
= *label_terminal
;
163 assert(*terminal
== '.' || *terminal
== 0);
165 /* Skip current terminal character (and accept domain names ending it ".") */
168 if (terminal
>= name
&& *terminal
== '.')
171 /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
173 if (terminal
< name
) {
174 /* Reached the first label, so indicate that there are no more */
179 /* Find the start of the last label */
180 if (*terminal
== '.') {
182 unsigned slashes
= 0;
184 for (y
= terminal
- 1; y
>= name
&& *y
== '\\'; y
--)
187 if (slashes
% 2 == 0) {
188 /* The '.' was not escaped */
200 r
= dns_label_unescape(&name
, dest
, sz
);
204 *label_terminal
= terminal
;
209 int dns_label_escape(const char *p
, size_t l
, char *dest
, size_t sz
) {
212 /* DNS labels must be between 1 and 63 characters long. A
213 * zero-length label does not exist. See RFC 2182, Section
216 if (l
<= 0 || l
> DNS_LABEL_MAX
)
227 if (*p
== '.' || *p
== '\\') {
229 /* Dot or backslash */
239 } else if (*p
== '_' ||
241 (*p
>= '0' && *p
<= '9') ||
242 (*p
>= 'a' && *p
<= 'z') ||
243 (*p
>= 'A' && *p
<= 'Z')) {
245 /* Proper character */
255 /* Everything else */
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);
274 return (int) (q
- dest
);
277 int dns_label_escape_new(const char *p
, size_t l
, char **ret
) {
278 _cleanup_free_
char *s
= NULL
;
284 if (l
<= 0 || l
> DNS_LABEL_MAX
)
287 s
= new(char, DNS_LABEL_ESCAPED_MAX
);
291 r
= dns_label_escape(p
, l
, s
, DNS_LABEL_ESCAPED_MAX
);
301 int dns_label_apply_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
303 _cleanup_free_
uint32_t *input
= NULL
;
304 size_t input_size
, l
;
306 bool contains_8bit
= false;
307 char buffer
[DNS_LABEL_MAX
+1];
312 /* Converts an U-label into an A-label */
314 if (encoded_size
<= 0)
317 for (p
= encoded
; p
< encoded
+ encoded_size
; p
++)
318 if ((uint8_t) *p
> 127)
319 contains_8bit
= true;
321 if (!contains_8bit
) {
322 if (encoded_size
> DNS_LABEL_MAX
)
328 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
332 if (idna_to_ascii_4i(input
, input_size
, buffer
, 0) != 0)
337 /* Verify that the the result is not longer than one DNS label. */
338 if (l
<= 0 || l
> DNS_LABEL_MAX
)
343 memcpy(decoded
, buffer
, l
);
345 /* If there's room, append a trailing NUL byte, but only then */
355 int dns_label_undo_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
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
;
363 /* To be invoked after unescaping. Converts an A-label into an U-label. */
368 if (encoded_size
<= 0 || encoded_size
> DNS_LABEL_MAX
)
371 if (encoded_size
< sizeof(IDNA_ACE_PREFIX
)-1)
374 if (memcmp(encoded
, IDNA_ACE_PREFIX
, sizeof(IDNA_ACE_PREFIX
) -1) != 0)
377 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
381 output_size
= input_size
;
382 output
= newa(uint32_t, output_size
);
384 idna_to_unicode_44i(input
, input_size
, output
, &output_size
, 0);
386 result
= stringprep_ucs4_to_utf8(output
, output_size
, NULL
, &w
);
394 memcpy(decoded
, result
, w
);
396 /* Append trailing NUL byte if there's space, but only then. */
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;
416 char label
[DNS_LABEL_MAX
];
419 r
= dns_label_unescape(&p
, label
, sizeof(label
));
427 /* Now continue with the second string, if there is one */
436 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
443 if (!GREEDY_REALLOC(ret
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
))
446 r
= dns_label_escape(label
, r
, ret
+ n
+ !first
, DNS_LABEL_ESCAPED_MAX
);
453 char escaped
[DNS_LABEL_ESCAPED_MAX
];
455 r
= dns_label_escape(label
, r
, escaped
, sizeof(escaped
));
468 if (n
> DNS_HOSTNAME_MAX
)
472 if (!GREEDY_REALLOC(ret
, allocated
, n
+ 1))
483 void dns_name_hash_func(const void *s
, struct siphash
*state
) {
490 char label
[DNS_LABEL_MAX
+1];
493 r
= dns_label_unescape(&p
, label
, sizeof(label
));
499 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
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 */
510 /* enforce that all names are terminated by the empty label */
511 string_hash_func("", state
);
514 int dns_name_compare_func(const void *a
, const void *b
) {
521 x
= (const char *) a
+ strlen(a
);
522 y
= (const char *) b
+ strlen(b
);
525 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
527 if (x
== NULL
&& y
== NULL
)
530 r
= dns_label_unescape_suffix(a
, &x
, la
, sizeof(la
));
531 q
= dns_label_unescape_suffix(b
, &y
, lb
, sizeof(lb
));
535 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
536 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
545 r
= strcasecmp(la
, lb
);
551 const struct hash_ops dns_name_hash_ops
= {
552 .hash
= dns_name_hash_func
,
553 .compare
= dns_name_compare_func
556 int dns_name_equal(const char *x
, const char *y
) {
563 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
565 if (*x
== 0 && *y
== 0)
568 r
= dns_label_unescape(&x
, la
, sizeof(la
));
572 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
579 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
583 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
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. */
596 if (strcasecmp(la
, lb
) != 0)
601 int dns_name_endswith(const char *name
, const char *suffix
) {
602 const char *n
, *s
, *saved_n
= NULL
;
612 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
614 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
618 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
628 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
632 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
639 if (r
== 0 && q
== 0)
641 if (r
== 0 && saved_n
== n
)
646 if (r
!= q
|| strcasecmp(ln
, ls
)) {
648 /* Not the same, let's jump back, and try with the next label again */
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
;
669 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
674 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
678 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
688 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
692 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
699 if (r
== 0 && q
== 0)
701 if (r
== 0 && saved_after
== n
) {
702 *ret
= NULL
; /* doesn't match */
708 if (r
!= q
|| strcasecmp(ln
, ls
)) {
710 /* Not the same, let's jump back, and try with the next label again */
713 saved_after
= saved_before
= NULL
;
717 /* Found it! Now generate the new name */
718 prefix
= strndupa(name
, saved_before
- name
);
720 r
= dns_name_concat(prefix
, new_suffix
, ret
);
727 int dns_name_between(const char *a
, const char *b
, const char *c
) {
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. */
736 n
= dns_name_compare_func(a
, c
);
741 return dns_name_compare_func(a
, b
) < 0 &&
742 dns_name_compare_func(b
, c
) < 0;
744 /* <--b--c a--b--> */
745 return dns_name_compare_func(b
, c
) < 0 ||
746 dns_name_compare_func(a
, b
) < 0;
749 int dns_name_reverse(int family
, const union in_addr_union
*a
, char **ret
) {
756 p
= (const uint8_t*) a
;
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));
771 return -EAFNOSUPPORT
;
778 int dns_name_address(const char *p
, int *family
, union in_addr_union
*address
) {
785 r
= dns_name_endswith(p
, "in-addr.arpa");
792 for (i
= 0; i
< ELEMENTSOF(a
); i
++) {
793 char label
[DNS_LABEL_MAX
+1];
795 r
= dns_label_unescape(&p
, label
, sizeof(label
));
803 r
= safe_atou8(label
, &a
[i
]);
808 r
= dns_name_equal(p
, "in-addr.arpa");
813 address
->in
.s_addr
= htobe32(((uint32_t) a
[3] << 24) |
814 ((uint32_t) a
[2] << 16) |
815 ((uint32_t) a
[1] << 8) |
821 r
= dns_name_endswith(p
, "ip6.arpa");
828 for (i
= 0; i
< ELEMENTSOF(a
.s6_addr
); i
++) {
829 char label
[DNS_LABEL_MAX
+1];
832 r
= dns_label_unescape(&p
, label
, sizeof(label
));
837 x
= unhexchar(label
[0]);
841 r
= dns_label_unescape(&p
, label
, sizeof(label
));
846 y
= unhexchar(label
[0]);
850 a
.s6_addr
[ELEMENTSOF(a
.s6_addr
) - i
- 1] = (uint8_t) y
<< 4 | (uint8_t) x
;
853 r
= dns_name_equal(p
, "ip6.arpa");
865 bool dns_name_is_root(const char *name
) {
869 /* There are exactly two ways to encode the root domain name:
870 * as empty string, or with a single dot. */
872 return STR_IN_SET(name
, "", ".");
875 bool dns_name_is_single_label(const char *name
) {
876 char label
[DNS_LABEL_MAX
+1];
881 r
= dns_label_unescape(&name
, label
, sizeof(label
));
885 return dns_name_is_root(name
);
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
;
899 /* Reserve a byte for label length */
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
);
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. */
918 ascii_strlower_n((char*) out
, (size_t) r
);
920 /* Fill label length, move forward */
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
931 if (out
- buffer
> DNS_HOSTNAME_MAX
+ 2)
937 static bool srv_type_label_is_valid(const char *label
, size_t n
) {
942 if (n
< 2) /* Label needs to be at least 2 chars long */
945 if (label
[0] != '_') /* First label char needs to be underscore */
948 /* Second char must be a letter */
949 if (!(label
[1] >= 'A' && label
[1] <= 'Z') &&
950 !(label
[1] >= 'a' && label
[1] <= 'z'))
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') &&
965 bool dns_srv_type_is_valid(const char *name
) {
973 char label
[DNS_LABEL_MAX
];
975 /* This more or less implements RFC 6335, Section 5.1 */
977 r
= dns_label_unescape(&name
, label
, sizeof(label
));
986 if (!srv_type_label_is_valid(label
, r
))
992 return c
== 2; /* exactly two labels */
995 bool dns_service_name_is_valid(const char *name
) {
998 /* This more or less implements RFC 6763, Section 4.1.1 */
1003 if (!utf8_is_valid(name
))
1006 if (string_has_cc(name
, NULL
))
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
;
1027 if (!dns_srv_type_is_valid(type
))
1031 return dns_name_concat(type
, domain
, ret
);
1033 if (!dns_service_name_is_valid(name
))
1036 r
= dns_label_escape(name
, strlen(name
), escaped
, sizeof(escaped
));
1040 r
= dns_name_concat(type
, domain
, &n
);
1044 return dns_name_concat(escaped
, n
, ret
);
1047 static bool dns_service_name_label_is_valid(const char *label
, size_t n
) {
1052 if (memchr(label
, 0, n
))
1055 s
= strndupa(label
, n
);
1056 return dns_service_name_is_valid(s
);
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
];
1068 /* Get first label from the full name */
1069 an
= dns_label_unescape(&p
, a
, sizeof(a
));
1076 /* If there was a first label, try to get the second one */
1077 bn
= dns_label_unescape(&p
, b
, sizeof(b
));
1084 /* If there was a second label, try to get the third one */
1086 cn
= dns_label_unescape(&p
, c
, sizeof(c
));
1097 if (x
>= 2 && srv_type_label_is_valid(b
, bn
)) {
1099 if (x
>= 3 && srv_type_label_is_valid(c
, cn
)) {
1101 if (dns_service_name_label_is_valid(a
, an
)) {
1103 /* OK, got <name> . <type> . <type2> . <domain> */
1105 name
= strndup(a
, an
);
1109 type
= new(char, bn
+1+cn
+1);
1112 strcpy(stpcpy(stpcpy(type
, b
), "."), c
);
1118 } else if (srv_type_label_is_valid(a
, an
)) {
1120 /* OK, got <type> . <type2> . <domain> */
1124 type
= new(char, an
+1+bn
+1);
1127 strcpy(stpcpy(stpcpy(type
, a
), "."), b
);
1139 r
= dns_name_normalize(d
, &domain
);
1161 int dns_name_suffix(const char *name
, unsigned n_labels
, const char **ret
) {
1162 const char* labels
[DNS_N_LABELS_MAX
+1];
1172 if (n
> DNS_N_LABELS_MAX
)
1177 r
= dns_name_parent(&p
);
1189 *ret
= labels
[n
- n_labels
];
1190 return (int) (n
- n_labels
);
1193 int dns_name_count_labels(const char *name
) {
1202 r
= dns_name_parent(&p
);
1208 if (n
>= DNS_N_LABELS_MAX
)
1217 int dns_name_equal_skip(const char *a
, unsigned n_labels
, const char *b
) {
1223 while (n_labels
> 0) {
1225 r
= dns_name_parent(&a
);
1232 return dns_name_equal(a
, b
);