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);
273 return (int) (q
- dest
);
276 int dns_label_escape_new(const char *p
, size_t l
, char **ret
) {
277 _cleanup_free_
char *s
= NULL
;
283 if (l
<= 0 || l
> DNS_LABEL_MAX
)
286 s
= new(char, DNS_LABEL_ESCAPED_MAX
);
290 r
= dns_label_escape(p
, l
, s
, DNS_LABEL_ESCAPED_MAX
);
300 int dns_label_apply_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
302 _cleanup_free_
uint32_t *input
= NULL
;
303 size_t input_size
, l
;
305 bool contains_8bit
= false;
306 char buffer
[DNS_LABEL_MAX
+1];
311 /* Converts an U-label into an A-label */
313 if (encoded_size
<= 0)
316 for (p
= encoded
; p
< encoded
+ encoded_size
; p
++)
317 if ((uint8_t) *p
> 127)
318 contains_8bit
= true;
320 if (!contains_8bit
) {
321 if (encoded_size
> DNS_LABEL_MAX
)
327 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
331 if (idna_to_ascii_4i(input
, input_size
, buffer
, 0) != 0)
336 /* Verify that the the result is not longer than one DNS label. */
337 if (l
<= 0 || l
> DNS_LABEL_MAX
)
342 memcpy(decoded
, buffer
, l
);
344 /* If there's room, append a trailing NUL byte, but only then */
354 int dns_label_undo_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
356 size_t input_size
, output_size
;
357 _cleanup_free_
uint32_t *input
= NULL
;
358 _cleanup_free_
char *result
= NULL
;
359 uint32_t *output
= NULL
;
362 /* To be invoked after unescaping. Converts an A-label into an U-label. */
367 if (encoded_size
<= 0 || encoded_size
> DNS_LABEL_MAX
)
370 if (encoded_size
< sizeof(IDNA_ACE_PREFIX
)-1)
373 if (memcmp(encoded
, IDNA_ACE_PREFIX
, sizeof(IDNA_ACE_PREFIX
) -1) != 0)
376 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
380 output_size
= input_size
;
381 output
= newa(uint32_t, output_size
);
383 idna_to_unicode_44i(input
, input_size
, output
, &output_size
, 0);
385 result
= stringprep_ucs4_to_utf8(output
, output_size
, NULL
, &w
);
393 memcpy(decoded
, result
, w
);
395 /* Append trailing NUL byte if there's space, but only then. */
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;
415 char label
[DNS_LABEL_MAX
];
418 r
= dns_label_unescape(&p
, label
, sizeof(label
));
426 /* Now continue with the second string, if there is one */
435 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
442 if (!GREEDY_REALLOC(ret
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
))
445 r
= dns_label_escape(label
, r
, ret
+ n
+ !first
, DNS_LABEL_ESCAPED_MAX
);
452 char escaped
[DNS_LABEL_ESCAPED_MAX
];
454 r
= dns_label_escape(label
, r
, escaped
, sizeof(escaped
));
467 if (n
> DNS_HOSTNAME_MAX
)
471 if (!GREEDY_REALLOC(ret
, allocated
, n
+ 1))
482 void dns_name_hash_func(const void *s
, struct siphash
*state
) {
489 char label
[DNS_LABEL_MAX
+1];
492 r
= dns_label_unescape(&p
, label
, sizeof(label
));
498 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
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 */
509 /* enforce that all names are terminated by the empty label */
510 string_hash_func("", state
);
513 int dns_name_compare_func(const void *a
, const void *b
) {
520 x
= (const char *) a
+ strlen(a
);
521 y
= (const char *) b
+ strlen(b
);
524 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
526 if (x
== NULL
&& y
== NULL
)
529 r
= dns_label_unescape_suffix(a
, &x
, la
, sizeof(la
));
530 q
= dns_label_unescape_suffix(b
, &y
, lb
, sizeof(lb
));
534 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
535 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
544 r
= strcasecmp(la
, lb
);
550 const struct hash_ops dns_name_hash_ops
= {
551 .hash
= dns_name_hash_func
,
552 .compare
= dns_name_compare_func
555 int dns_name_equal(const char *x
, const char *y
) {
562 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
564 if (*x
== 0 && *y
== 0)
567 r
= dns_label_unescape(&x
, la
, sizeof(la
));
571 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
578 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
582 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
589 /* If one name had fewer labels than the other, this
590 * will show up as empty label here, which the
591 * strcasecmp() below will properly consider different
592 * from a non-empty label. */
595 if (strcasecmp(la
, lb
) != 0)
600 int dns_name_endswith(const char *name
, const char *suffix
) {
601 const char *n
, *s
, *saved_n
= NULL
;
611 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
613 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
617 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
627 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
631 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
638 if (r
== 0 && q
== 0)
640 if (r
== 0 && saved_n
== n
)
645 if (r
!= q
|| strcasecmp(ln
, ls
)) {
647 /* Not the same, let's jump back, and try with the next label again */
655 static int dns_label_unescape_undo_idna(const char **name
, char *dest
, size_t sz
) {
658 /* Clobbers all arguments on failure... */
660 r
= dns_label_unescape(name
, dest
, sz
);
664 k
= dns_label_undo_idna(dest
, r
, dest
, sz
);
667 if (k
== 0) /* not an IDNA name */
673 int dns_name_startswith(const char *name
, const char *prefix
) {
684 char ln
[DNS_LABEL_MAX
], lp
[DNS_LABEL_MAX
];
686 r
= dns_label_unescape_undo_idna(&p
, lp
, sizeof(lp
));
692 q
= dns_label_unescape_undo_idna(&n
, ln
, sizeof(ln
));
698 if (ascii_strcasecmp_n(ln
, lp
, r
) != 0)
703 int dns_name_change_suffix(const char *name
, const char *old_suffix
, const char *new_suffix
, char **ret
) {
704 const char *n
, *s
, *saved_before
= NULL
, *saved_after
= NULL
, *prefix
;
716 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
721 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
725 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
735 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
739 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
746 if (r
== 0 && q
== 0)
748 if (r
== 0 && saved_after
== n
) {
749 *ret
= NULL
; /* doesn't match */
755 if (r
!= q
|| strcasecmp(ln
, ls
)) {
757 /* Not the same, let's jump back, and try with the next label again */
760 saved_after
= saved_before
= NULL
;
764 /* Found it! Now generate the new name */
765 prefix
= strndupa(name
, saved_before
- name
);
767 r
= dns_name_concat(prefix
, new_suffix
, ret
);
774 int dns_name_between(const char *a
, const char *b
, const char *c
) {
777 /* Determine if b is strictly greater than a and strictly smaller than c.
778 We consider the order of names to be circular, so that if a is
779 strictly greater than c, we consider b to be between them if it is
780 either greater than a or smaller than c. This is how the canonical
781 DNS name order used in NSEC records work. */
783 n
= dns_name_compare_func(a
, c
);
788 return dns_name_compare_func(a
, b
) < 0 &&
789 dns_name_compare_func(b
, c
) < 0;
791 /* <--b--c a--b--> */
792 return dns_name_compare_func(b
, c
) < 0 ||
793 dns_name_compare_func(a
, b
) < 0;
796 int dns_name_reverse(int family
, const union in_addr_union
*a
, char **ret
) {
803 p
= (const uint8_t*) a
;
805 if (family
== AF_INET
)
806 r
= asprintf(ret
, "%u.%u.%u.%u.in-addr.arpa", p
[3], p
[2], p
[1], p
[0]);
807 else if (family
== AF_INET6
)
808 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",
809 hexchar(p
[15] & 0xF), hexchar(p
[15] >> 4), hexchar(p
[14] & 0xF), hexchar(p
[14] >> 4),
810 hexchar(p
[13] & 0xF), hexchar(p
[13] >> 4), hexchar(p
[12] & 0xF), hexchar(p
[12] >> 4),
811 hexchar(p
[11] & 0xF), hexchar(p
[11] >> 4), hexchar(p
[10] & 0xF), hexchar(p
[10] >> 4),
812 hexchar(p
[ 9] & 0xF), hexchar(p
[ 9] >> 4), hexchar(p
[ 8] & 0xF), hexchar(p
[ 8] >> 4),
813 hexchar(p
[ 7] & 0xF), hexchar(p
[ 7] >> 4), hexchar(p
[ 6] & 0xF), hexchar(p
[ 6] >> 4),
814 hexchar(p
[ 5] & 0xF), hexchar(p
[ 5] >> 4), hexchar(p
[ 4] & 0xF), hexchar(p
[ 4] >> 4),
815 hexchar(p
[ 3] & 0xF), hexchar(p
[ 3] >> 4), hexchar(p
[ 2] & 0xF), hexchar(p
[ 2] >> 4),
816 hexchar(p
[ 1] & 0xF), hexchar(p
[ 1] >> 4), hexchar(p
[ 0] & 0xF), hexchar(p
[ 0] >> 4));
818 return -EAFNOSUPPORT
;
825 int dns_name_address(const char *p
, int *family
, union in_addr_union
*address
) {
832 r
= dns_name_endswith(p
, "in-addr.arpa");
839 for (i
= 0; i
< ELEMENTSOF(a
); i
++) {
840 char label
[DNS_LABEL_MAX
+1];
842 r
= dns_label_unescape(&p
, label
, sizeof(label
));
850 r
= safe_atou8(label
, &a
[i
]);
855 r
= dns_name_equal(p
, "in-addr.arpa");
860 address
->in
.s_addr
= htobe32(((uint32_t) a
[3] << 24) |
861 ((uint32_t) a
[2] << 16) |
862 ((uint32_t) a
[1] << 8) |
868 r
= dns_name_endswith(p
, "ip6.arpa");
875 for (i
= 0; i
< ELEMENTSOF(a
.s6_addr
); i
++) {
876 char label
[DNS_LABEL_MAX
+1];
879 r
= dns_label_unescape(&p
, label
, sizeof(label
));
884 x
= unhexchar(label
[0]);
888 r
= dns_label_unescape(&p
, label
, sizeof(label
));
893 y
= unhexchar(label
[0]);
897 a
.s6_addr
[ELEMENTSOF(a
.s6_addr
) - i
- 1] = (uint8_t) y
<< 4 | (uint8_t) x
;
900 r
= dns_name_equal(p
, "ip6.arpa");
912 bool dns_name_is_root(const char *name
) {
916 /* There are exactly two ways to encode the root domain name:
917 * as empty string, or with a single dot. */
919 return STR_IN_SET(name
, "", ".");
922 bool dns_name_is_single_label(const char *name
) {
923 char label
[DNS_LABEL_MAX
+1];
928 r
= dns_label_unescape(&name
, label
, sizeof(label
));
932 return dns_name_is_root(name
);
935 /* Encode a domain name according to RFC 1035 Section 3.1, without compression */
936 int dns_name_to_wire_format(const char *domain
, uint8_t *buffer
, size_t len
, bool canonical
) {
937 uint8_t *label_length
, *out
;
946 /* Reserve a byte for label length */
953 /* Convert and copy a single label. Note that
954 * dns_label_unescape() returns 0 when it hits the end
955 * of the domain name, which we rely on here to encode
956 * the trailing NUL byte. */
957 r
= dns_label_unescape(&domain
, (char *) out
, len
);
961 /* Optionally, output the name in DNSSEC canonical
962 * format, as described in RFC 4034, section 6.2. Or
963 * in other words: in lower-case. */
965 ascii_strlower_n((char*) out
, (size_t) r
);
967 /* Fill label length, move forward */
974 /* Verify the maximum size of the encoded name. The trailing
975 * dot + NUL byte account are included this time, hence
976 * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
978 if (out
- buffer
> DNS_HOSTNAME_MAX
+ 2)
984 static bool srv_type_label_is_valid(const char *label
, size_t n
) {
989 if (n
< 2) /* Label needs to be at least 2 chars long */
992 if (label
[0] != '_') /* First label char needs to be underscore */
995 /* Second char must be a letter */
996 if (!(label
[1] >= 'A' && label
[1] <= 'Z') &&
997 !(label
[1] >= 'a' && label
[1] <= 'z'))
1000 /* Third and further chars must be alphanumeric or a hyphen */
1001 for (k
= 2; k
< n
; k
++) {
1002 if (!(label
[k
] >= 'A' && label
[k
] <= 'Z') &&
1003 !(label
[k
] >= 'a' && label
[k
] <= 'z') &&
1004 !(label
[k
] >= '0' && label
[k
] <= '9') &&
1012 bool dns_srv_type_is_valid(const char *name
) {
1020 char label
[DNS_LABEL_MAX
];
1022 /* This more or less implements RFC 6335, Section 5.1 */
1024 r
= dns_label_unescape(&name
, label
, sizeof(label
));
1033 if (!srv_type_label_is_valid(label
, r
))
1039 return c
== 2; /* exactly two labels */
1042 bool dns_service_name_is_valid(const char *name
) {
1045 /* This more or less implements RFC 6763, Section 4.1.1 */
1050 if (!utf8_is_valid(name
))
1053 if (string_has_cc(name
, NULL
))
1065 int dns_service_join(const char *name
, const char *type
, const char *domain
, char **ret
) {
1066 char escaped
[DNS_LABEL_ESCAPED_MAX
];
1067 _cleanup_free_
char *n
= NULL
;
1074 if (!dns_srv_type_is_valid(type
))
1078 return dns_name_concat(type
, domain
, ret
);
1080 if (!dns_service_name_is_valid(name
))
1083 r
= dns_label_escape(name
, strlen(name
), escaped
, sizeof(escaped
));
1087 r
= dns_name_concat(type
, domain
, &n
);
1091 return dns_name_concat(escaped
, n
, ret
);
1094 static bool dns_service_name_label_is_valid(const char *label
, size_t n
) {
1099 if (memchr(label
, 0, n
))
1102 s
= strndupa(label
, n
);
1103 return dns_service_name_is_valid(s
);
1106 int dns_service_split(const char *joined
, char **_name
, char **_type
, char **_domain
) {
1107 _cleanup_free_
char *name
= NULL
, *type
= NULL
, *domain
= NULL
;
1108 const char *p
= joined
, *q
= NULL
, *d
= NULL
;
1109 char a
[DNS_LABEL_MAX
], b
[DNS_LABEL_MAX
], c
[DNS_LABEL_MAX
];
1115 /* Get first label from the full name */
1116 an
= dns_label_unescape(&p
, a
, sizeof(a
));
1123 /* If there was a first label, try to get the second one */
1124 bn
= dns_label_unescape(&p
, b
, sizeof(b
));
1131 /* If there was a second label, try to get the third one */
1133 cn
= dns_label_unescape(&p
, c
, sizeof(c
));
1144 if (x
>= 2 && srv_type_label_is_valid(b
, bn
)) {
1146 if (x
>= 3 && srv_type_label_is_valid(c
, cn
)) {
1148 if (dns_service_name_label_is_valid(a
, an
)) {
1150 /* OK, got <name> . <type> . <type2> . <domain> */
1152 name
= strndup(a
, an
);
1156 type
= new(char, bn
+1+cn
+1);
1159 strcpy(stpcpy(stpcpy(type
, b
), "."), c
);
1165 } else if (srv_type_label_is_valid(a
, an
)) {
1167 /* OK, got <type> . <type2> . <domain> */
1171 type
= new(char, an
+1+bn
+1);
1174 strcpy(stpcpy(stpcpy(type
, a
), "."), b
);
1186 r
= dns_name_normalize(d
, &domain
);
1208 int dns_name_suffix(const char *name
, unsigned n_labels
, const char **ret
) {
1209 const char* labels
[DNS_N_LABELS_MAX
+1];
1219 if (n
> DNS_N_LABELS_MAX
)
1224 r
= dns_name_parent(&p
);
1236 *ret
= labels
[n
- n_labels
];
1237 return (int) (n
- n_labels
);
1240 int dns_name_count_labels(const char *name
) {
1249 r
= dns_name_parent(&p
);
1255 if (n
>= DNS_N_LABELS_MAX
)
1264 int dns_name_equal_skip(const char *a
, unsigned n_labels
, const char *b
) {
1270 while (n_labels
> 0) {
1272 r
= dns_name_parent(&a
);
1279 return dns_name_equal(a
, b
);