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;
421 char label
[DNS_LABEL_MAX
];
423 r
= dns_label_unescape(&p
, label
, sizeof(label
));
431 /* Now continue with the second string, if there is one */
441 if (!GREEDY_REALLOC(ret
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
))
444 r
= dns_label_escape(label
, r
, ret
+ n
+ !first
, DNS_LABEL_ESCAPED_MAX
);
451 char escaped
[DNS_LABEL_ESCAPED_MAX
];
453 r
= dns_label_escape(label
, r
, escaped
, sizeof(escaped
));
467 if (n
> DNS_HOSTNAME_MAX
)
472 /* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
473 if (!GREEDY_REALLOC(ret
, allocated
, 2))
478 if (!GREEDY_REALLOC(ret
, allocated
, n
+ 1))
490 void dns_name_hash_func(const void *s
, struct siphash
*state
) {
497 char label
[DNS_LABEL_MAX
+1];
499 r
= dns_label_unescape(&p
, 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
], lb
[DNS_LABEL_MAX
];
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 r
= ascii_strcasecmp_nn(la
, r
, lb
, q
);
541 const struct hash_ops dns_name_hash_ops
= {
542 .hash
= dns_name_hash_func
,
543 .compare
= dns_name_compare_func
546 int dns_name_equal(const char *x
, const char *y
) {
553 char la
[DNS_LABEL_MAX
], lb
[DNS_LABEL_MAX
];
555 r
= dns_label_unescape(&x
, la
, sizeof(la
));
559 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
568 if (ascii_strcasecmp_n(la
, lb
, r
) != 0)
573 int dns_name_endswith(const char *name
, const char *suffix
) {
574 const char *n
, *s
, *saved_n
= NULL
;
584 char ln
[DNS_LABEL_MAX
], ls
[DNS_LABEL_MAX
];
586 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
593 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
597 if (r
== 0 && q
== 0)
599 if (r
== 0 && saved_n
== n
)
602 if (r
!= q
|| ascii_strcasecmp_n(ln
, ls
, r
) != 0) {
604 /* Not the same, let's jump back, and try with the next label again */
612 int dns_name_startswith(const char *name
, const char *prefix
) {
623 char ln
[DNS_LABEL_MAX
], lp
[DNS_LABEL_MAX
];
625 r
= dns_label_unescape(&p
, lp
, sizeof(lp
));
631 q
= dns_label_unescape(&n
, ln
, sizeof(ln
));
637 if (ascii_strcasecmp_n(ln
, lp
, r
) != 0)
642 int dns_name_change_suffix(const char *name
, const char *old_suffix
, const char *new_suffix
, char **ret
) {
643 const char *n
, *s
, *saved_before
= NULL
, *saved_after
= NULL
, *prefix
;
655 char ln
[DNS_LABEL_MAX
], ls
[DNS_LABEL_MAX
];
660 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
667 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
671 if (r
== 0 && q
== 0)
673 if (r
== 0 && saved_after
== n
) {
674 *ret
= NULL
; /* doesn't match */
678 if (r
!= q
|| ascii_strcasecmp_n(ln
, ls
, r
) != 0) {
680 /* Not the same, let's jump back, and try with the next label again */
683 saved_after
= saved_before
= NULL
;
687 /* Found it! Now generate the new name */
688 prefix
= strndupa(name
, saved_before
- name
);
690 r
= dns_name_concat(prefix
, new_suffix
, ret
);
697 int dns_name_between(const char *a
, const char *b
, const char *c
) {
700 /* Determine if b is strictly greater than a and strictly smaller than c.
701 We consider the order of names to be circular, so that if a is
702 strictly greater than c, we consider b to be between them if it is
703 either greater than a or smaller than c. This is how the canonical
704 DNS name order used in NSEC records work. */
706 n
= dns_name_compare_func(a
, c
);
711 return dns_name_compare_func(a
, b
) < 0 &&
712 dns_name_compare_func(b
, c
) < 0;
714 /* <--b--c a--b--> */
715 return dns_name_compare_func(b
, c
) < 0 ||
716 dns_name_compare_func(a
, b
) < 0;
719 int dns_name_reverse(int family
, const union in_addr_union
*a
, char **ret
) {
726 p
= (const uint8_t*) a
;
728 if (family
== AF_INET
)
729 r
= asprintf(ret
, "%u.%u.%u.%u.in-addr.arpa", p
[3], p
[2], p
[1], p
[0]);
730 else if (family
== AF_INET6
)
731 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",
732 hexchar(p
[15] & 0xF), hexchar(p
[15] >> 4), hexchar(p
[14] & 0xF), hexchar(p
[14] >> 4),
733 hexchar(p
[13] & 0xF), hexchar(p
[13] >> 4), hexchar(p
[12] & 0xF), hexchar(p
[12] >> 4),
734 hexchar(p
[11] & 0xF), hexchar(p
[11] >> 4), hexchar(p
[10] & 0xF), hexchar(p
[10] >> 4),
735 hexchar(p
[ 9] & 0xF), hexchar(p
[ 9] >> 4), hexchar(p
[ 8] & 0xF), hexchar(p
[ 8] >> 4),
736 hexchar(p
[ 7] & 0xF), hexchar(p
[ 7] >> 4), hexchar(p
[ 6] & 0xF), hexchar(p
[ 6] >> 4),
737 hexchar(p
[ 5] & 0xF), hexchar(p
[ 5] >> 4), hexchar(p
[ 4] & 0xF), hexchar(p
[ 4] >> 4),
738 hexchar(p
[ 3] & 0xF), hexchar(p
[ 3] >> 4), hexchar(p
[ 2] & 0xF), hexchar(p
[ 2] >> 4),
739 hexchar(p
[ 1] & 0xF), hexchar(p
[ 1] >> 4), hexchar(p
[ 0] & 0xF), hexchar(p
[ 0] >> 4));
741 return -EAFNOSUPPORT
;
748 int dns_name_address(const char *p
, int *family
, union in_addr_union
*address
) {
755 r
= dns_name_endswith(p
, "in-addr.arpa");
762 for (i
= 0; i
< ELEMENTSOF(a
); i
++) {
763 char label
[DNS_LABEL_MAX
+1];
765 r
= dns_label_unescape(&p
, label
, sizeof(label
));
773 r
= safe_atou8(label
, &a
[i
]);
778 r
= dns_name_equal(p
, "in-addr.arpa");
783 address
->in
.s_addr
= htobe32(((uint32_t) a
[3] << 24) |
784 ((uint32_t) a
[2] << 16) |
785 ((uint32_t) a
[1] << 8) |
791 r
= dns_name_endswith(p
, "ip6.arpa");
798 for (i
= 0; i
< ELEMENTSOF(a
.s6_addr
); i
++) {
799 char label
[DNS_LABEL_MAX
+1];
802 r
= dns_label_unescape(&p
, label
, sizeof(label
));
807 x
= unhexchar(label
[0]);
811 r
= dns_label_unescape(&p
, label
, sizeof(label
));
816 y
= unhexchar(label
[0]);
820 a
.s6_addr
[ELEMENTSOF(a
.s6_addr
) - i
- 1] = (uint8_t) y
<< 4 | (uint8_t) x
;
823 r
= dns_name_equal(p
, "ip6.arpa");
835 bool dns_name_is_root(const char *name
) {
839 /* There are exactly two ways to encode the root domain name:
840 * as empty string, or with a single dot. */
842 return STR_IN_SET(name
, "", ".");
845 bool dns_name_is_single_label(const char *name
) {
850 r
= dns_name_parent(&name
);
854 return dns_name_is_root(name
);
857 /* Encode a domain name according to RFC 1035 Section 3.1, without compression */
858 int dns_name_to_wire_format(const char *domain
, uint8_t *buffer
, size_t len
, bool canonical
) {
859 uint8_t *label_length
, *out
;
868 /* Reserve a byte for label length */
875 /* Convert and copy a single label. Note that
876 * dns_label_unescape() returns 0 when it hits the end
877 * of the domain name, which we rely on here to encode
878 * the trailing NUL byte. */
879 r
= dns_label_unescape(&domain
, (char *) out
, len
);
883 /* Optionally, output the name in DNSSEC canonical
884 * format, as described in RFC 4034, section 6.2. Or
885 * in other words: in lower-case. */
887 ascii_strlower_n((char*) out
, (size_t) r
);
889 /* Fill label length, move forward */
896 /* Verify the maximum size of the encoded name. The trailing
897 * dot + NUL byte account are included this time, hence
898 * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
900 if (out
- buffer
> DNS_HOSTNAME_MAX
+ 2)
906 static bool srv_type_label_is_valid(const char *label
, size_t n
) {
911 if (n
< 2) /* Label needs to be at least 2 chars long */
914 if (label
[0] != '_') /* First label char needs to be underscore */
917 /* Second char must be a letter */
918 if (!(label
[1] >= 'A' && label
[1] <= 'Z') &&
919 !(label
[1] >= 'a' && label
[1] <= 'z'))
922 /* Third and further chars must be alphanumeric or a hyphen */
923 for (k
= 2; k
< n
; k
++) {
924 if (!(label
[k
] >= 'A' && label
[k
] <= 'Z') &&
925 !(label
[k
] >= 'a' && label
[k
] <= 'z') &&
926 !(label
[k
] >= '0' && label
[k
] <= '9') &&
934 bool dns_srv_type_is_valid(const char *name
) {
942 char label
[DNS_LABEL_MAX
];
944 /* This more or less implements RFC 6335, Section 5.1 */
946 r
= dns_label_unescape(&name
, label
, sizeof(label
));
955 if (!srv_type_label_is_valid(label
, r
))
961 return c
== 2; /* exactly two labels */
964 bool dns_service_name_is_valid(const char *name
) {
967 /* This more or less implements RFC 6763, Section 4.1.1 */
972 if (!utf8_is_valid(name
))
975 if (string_has_cc(name
, NULL
))
987 int dns_service_join(const char *name
, const char *type
, const char *domain
, char **ret
) {
988 char escaped
[DNS_LABEL_ESCAPED_MAX
];
989 _cleanup_free_
char *n
= NULL
;
996 if (!dns_srv_type_is_valid(type
))
1000 return dns_name_concat(type
, domain
, ret
);
1002 if (!dns_service_name_is_valid(name
))
1005 r
= dns_label_escape(name
, strlen(name
), escaped
, sizeof(escaped
));
1009 r
= dns_name_concat(type
, domain
, &n
);
1013 return dns_name_concat(escaped
, n
, ret
);
1016 static bool dns_service_name_label_is_valid(const char *label
, size_t n
) {
1021 if (memchr(label
, 0, n
))
1024 s
= strndupa(label
, n
);
1025 return dns_service_name_is_valid(s
);
1028 int dns_service_split(const char *joined
, char **_name
, char **_type
, char **_domain
) {
1029 _cleanup_free_
char *name
= NULL
, *type
= NULL
, *domain
= NULL
;
1030 const char *p
= joined
, *q
= NULL
, *d
= NULL
;
1031 char a
[DNS_LABEL_MAX
], b
[DNS_LABEL_MAX
], c
[DNS_LABEL_MAX
];
1037 /* Get first label from the full name */
1038 an
= dns_label_unescape(&p
, a
, sizeof(a
));
1045 /* If there was a first label, try to get the second one */
1046 bn
= dns_label_unescape(&p
, b
, sizeof(b
));
1053 /* If there was a second label, try to get the third one */
1055 cn
= dns_label_unescape(&p
, c
, sizeof(c
));
1066 if (x
>= 2 && srv_type_label_is_valid(b
, bn
)) {
1068 if (x
>= 3 && srv_type_label_is_valid(c
, cn
)) {
1070 if (dns_service_name_label_is_valid(a
, an
)) {
1071 /* OK, got <name> . <type> . <type2> . <domain> */
1073 name
= strndup(a
, an
);
1077 type
= strjoin(b
, ".", c
, NULL
);
1085 } else if (srv_type_label_is_valid(a
, an
)) {
1087 /* OK, got <type> . <type2> . <domain> */
1091 type
= strjoin(a
, ".", b
, NULL
);
1105 r
= dns_name_normalize(d
, &domain
);
1127 static int dns_name_build_suffix_table(const char *name
, const char*table
[]) {
1137 if (n
> DNS_N_LABELS_MAX
)
1141 r
= dns_name_parent(&p
);
1153 int dns_name_suffix(const char *name
, unsigned n_labels
, const char **ret
) {
1154 const char* labels
[DNS_N_LABELS_MAX
+1];
1160 n
= dns_name_build_suffix_table(name
, labels
);
1164 if ((unsigned) n
< n_labels
)
1167 *ret
= labels
[n
- n_labels
];
1168 return (int) (n
- n_labels
);
1171 int dns_name_skip(const char *a
, unsigned n_labels
, const char **ret
) {
1177 for (; n_labels
> 0; n_labels
--) {
1178 r
= dns_name_parent(&a
);
1191 int dns_name_count_labels(const char *name
) {
1200 r
= dns_name_parent(&p
);
1206 if (n
>= DNS_N_LABELS_MAX
)
1215 int dns_name_equal_skip(const char *a
, unsigned n_labels
, const char *b
) {
1221 r
= dns_name_skip(a
, n_labels
, &a
);
1225 return dns_name_equal(a
, b
);
1228 int dns_name_common_suffix(const char *a
, const char *b
, const char **ret
) {
1229 const char *a_labels
[DNS_N_LABELS_MAX
+1], *b_labels
[DNS_N_LABELS_MAX
+1];
1230 int n
= 0, m
= 0, k
= 0, r
, q
;
1236 /* Determines the common suffix of domain names a and b */
1238 n
= dns_name_build_suffix_table(a
, a_labels
);
1242 m
= dns_name_build_suffix_table(b
, b_labels
);
1247 char la
[DNS_LABEL_MAX
], lb
[DNS_LABEL_MAX
];
1250 if (k
>= n
|| k
>= m
) {
1251 *ret
= a_labels
[n
- k
];
1255 x
= a_labels
[n
- 1 - k
];
1256 r
= dns_label_unescape(&x
, la
, sizeof(la
));
1260 y
= b_labels
[m
- 1 - k
];
1261 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
1265 if (r
!= q
|| ascii_strcasecmp_n(la
, lb
, r
) != 0) {
1266 *ret
= a_labels
[n
- k
];
1274 int dns_name_apply_idna(const char *name
, char **ret
) {
1275 _cleanup_free_
char *buf
= NULL
;
1276 size_t n
= 0, allocated
= 0;
1284 char label
[DNS_LABEL_MAX
];
1286 r
= dns_label_unescape(&name
, label
, sizeof(label
));
1292 q
= dns_label_apply_idna(label
, r
, label
, sizeof(label
));
1298 if (!GREEDY_REALLOC(buf
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
))
1301 r
= dns_label_escape(label
, r
, buf
+ n
+ !first
, DNS_LABEL_ESCAPED_MAX
);
1313 if (n
> DNS_HOSTNAME_MAX
)
1316 if (!GREEDY_REALLOC(buf
, allocated
, n
+ 1))