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
) {
65 if (r
>= DNS_LABEL_MAX
)
72 /* Escaped character */
80 else if (*n
== '\\' || *n
== '.') {
81 /* Escaped backslash or dot */
86 } else if (n
[0] >= '0' && n
[0] <= '9') {
89 /* Escaped literal ASCII character */
91 if (!(n
[1] >= '0' && n
[1] <= '9') ||
92 !(n
[2] >= '0' && n
[2] <= '9'))
95 k
= ((unsigned) (n
[0] - '0') * 100) +
96 ((unsigned) (n
[1] - '0') * 10) +
97 ((unsigned) (n
[2] - '0'));
99 /* Don't allow CC characters or anything that doesn't fit in 8bit */
100 if (k
< ' ' || k
> 255 || k
== 127)
111 } else if ((uint8_t) *n
>= (uint8_t) ' ' && *n
!= 127) {
113 /* Normal character */
121 /* Empty label that is not at the end? */
132 /* @label_terminal: terminal character of a label, updated to point to the terminal character of
133 * the previous label (always skipping one dot) or to NULL if there are no more
135 int dns_label_unescape_suffix(const char *name
, const char **label_terminal
, char *dest
, size_t sz
) {
136 const char *terminal
;
140 assert(label_terminal
);
144 if (!*label_terminal
) {
151 assert(**label_terminal
== '.' || **label_terminal
== 0);
153 /* skip current terminal character */
154 terminal
= *label_terminal
- 1;
156 /* point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
158 if (terminal
< name
) {
159 /* reached the first label, so indicate that there are no more */
164 /* find the start of the last label */
165 if (*terminal
== '.') {
167 unsigned slashes
= 0;
169 for (y
= terminal
- 1; y
>= name
&& *y
== '\\'; y
--)
172 if (slashes
% 2 == 0) {
173 /* the '.' was not escaped */
185 r
= dns_label_unescape(&name
, dest
, sz
);
189 *label_terminal
= terminal
;
194 int dns_label_escape(const char *p
, size_t l
, char *dest
, size_t sz
) {
197 /* DNS labels must be between 1 and 63 characters long. A
198 * zero-length label does not exist. See RFC 2182, Section
201 if (l
<= 0 || l
> DNS_LABEL_MAX
)
212 if (*p
== '.' || *p
== '\\') {
214 /* Dot or backslash */
224 } else if (*p
== '_' ||
226 (*p
>= '0' && *p
<= '9') ||
227 (*p
>= 'a' && *p
<= 'z') ||
228 (*p
>= 'A' && *p
<= 'Z')) {
230 /* Proper character */
238 } else if ((uint8_t) *p
>= (uint8_t) ' ' && *p
!= 127) {
240 /* Everything else */
246 *(q
++) = '0' + (char) ((uint8_t) *p
/ 100);
247 *(q
++) = '0' + (char) (((uint8_t) *p
/ 10) % 10);
248 *(q
++) = '0' + (char) ((uint8_t) *p
% 10);
260 return (int) (q
- dest
);
263 int dns_label_escape_new(const char *p
, size_t l
, char **ret
) {
264 _cleanup_free_
char *s
= NULL
;
270 if (l
<= 0 || l
> DNS_LABEL_MAX
)
273 s
= new(char, DNS_LABEL_ESCAPED_MAX
);
277 r
= dns_label_escape(p
, l
, s
, DNS_LABEL_ESCAPED_MAX
);
287 int dns_label_apply_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
289 _cleanup_free_
uint32_t *input
= NULL
;
290 size_t input_size
, l
;
292 bool contains_8bit
= false;
293 char buffer
[DNS_LABEL_MAX
+1];
298 /* Converts an U-label into an A-label */
300 if (encoded_size
<= 0)
303 for (p
= encoded
; p
< encoded
+ encoded_size
; p
++)
304 if ((uint8_t) *p
> 127)
305 contains_8bit
= true;
307 if (!contains_8bit
) {
308 if (encoded_size
> DNS_LABEL_MAX
)
314 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
318 if (idna_to_ascii_4i(input
, input_size
, buffer
, 0) != 0)
323 /* Verify that the the result is not longer than one DNS label. */
324 if (l
<= 0 || l
> DNS_LABEL_MAX
)
329 memcpy(decoded
, buffer
, l
);
331 /* If there's room, append a trailing NUL byte, but only then */
341 int dns_label_undo_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
343 size_t input_size
, output_size
;
344 _cleanup_free_
uint32_t *input
= NULL
;
345 _cleanup_free_
char *result
= NULL
;
346 uint32_t *output
= NULL
;
349 /* To be invoked after unescaping. Converts an A-label into an U-label. */
354 if (encoded_size
<= 0 || encoded_size
> DNS_LABEL_MAX
)
357 if (encoded_size
< sizeof(IDNA_ACE_PREFIX
)-1)
360 if (memcmp(encoded
, IDNA_ACE_PREFIX
, sizeof(IDNA_ACE_PREFIX
) -1) != 0)
363 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
367 output_size
= input_size
;
368 output
= newa(uint32_t, output_size
);
370 idna_to_unicode_44i(input
, input_size
, output
, &output_size
, 0);
372 result
= stringprep_ucs4_to_utf8(output
, output_size
, NULL
, &w
);
380 memcpy(decoded
, result
, w
);
382 /* Append trailing NUL byte if there's space, but only then. */
392 int dns_name_concat(const char *a
, const char *b
, char **_ret
) {
393 _cleanup_free_
char *ret
= NULL
;
394 size_t n
= 0, allocated
= 0;
402 char label
[DNS_LABEL_MAX
];
405 r
= dns_label_unescape(&p
, label
, sizeof(label
));
413 /* Now continue with the second string, if there is one */
422 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
429 if (!GREEDY_REALLOC(ret
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
))
432 r
= dns_label_escape(label
, r
, ret
+ n
+ !first
, DNS_LABEL_ESCAPED_MAX
);
439 char escaped
[DNS_LABEL_ESCAPED_MAX
];
441 r
= dns_label_escape(label
, r
, escaped
, sizeof(escaped
));
454 if (n
> DNS_HOSTNAME_MAX
)
458 if (!GREEDY_REALLOC(ret
, allocated
, n
+ 1))
469 void dns_name_hash_func(const void *s
, struct siphash
*state
) {
476 char label
[DNS_LABEL_MAX
+1];
479 r
= dns_label_unescape(&p
, label
, sizeof(label
));
483 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
493 ascii_strlower(label
);
495 string_hash_func(label
, state
);
498 /* enforce that all names are terminated by the empty label */
499 string_hash_func("", state
);
502 int dns_name_compare_func(const void *a
, const void *b
) {
509 x
= (const char *) a
+ strlen(a
);
510 y
= (const char *) b
+ strlen(b
);
513 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
515 if (x
== NULL
&& y
== NULL
)
518 r
= dns_label_unescape_suffix(a
, &x
, la
, sizeof(la
));
519 q
= dns_label_unescape_suffix(b
, &y
, lb
, sizeof(lb
));
523 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
524 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
533 r
= strcasecmp(la
, lb
);
539 const struct hash_ops dns_name_hash_ops
= {
540 .hash
= dns_name_hash_func
,
541 .compare
= dns_name_compare_func
544 int dns_name_equal(const char *x
, const char *y
) {
551 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
553 if (*x
== 0 && *y
== 0)
556 r
= dns_label_unescape(&x
, la
, sizeof(la
));
560 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
567 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
571 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
578 /* If one name had fewer labels than the other, this
579 * will show up as empty label here, which the
580 * strcasecmp() below will properly consider different
581 * from a non-empty label. */
584 if (strcasecmp(la
, lb
) != 0)
589 int dns_name_endswith(const char *name
, const char *suffix
) {
590 const char *n
, *s
, *saved_n
= NULL
;
600 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
602 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
606 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
616 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
620 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
627 if (r
== 0 && q
== 0)
629 if (r
== 0 && saved_n
== n
)
634 if (r
!= q
|| strcasecmp(ln
, ls
)) {
636 /* Not the same, let's jump back, and try with the next label again */
644 int dns_name_change_suffix(const char *name
, const char *old_suffix
, const char *new_suffix
, char **ret
) {
645 const char *n
, *s
, *saved_before
= NULL
, *saved_after
= NULL
, *prefix
;
657 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
662 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
666 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
676 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
680 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
687 if (r
== 0 && q
== 0)
689 if (r
== 0 && saved_after
== n
) {
690 *ret
= NULL
; /* doesn't match */
696 if (r
!= q
|| strcasecmp(ln
, ls
)) {
698 /* Not the same, let's jump back, and try with the next label again */
701 saved_after
= saved_before
= NULL
;
705 /* Found it! Now generate the new name */
706 prefix
= strndupa(name
, saved_before
- name
);
708 r
= dns_name_concat(prefix
, new_suffix
, ret
);
715 int dns_name_between(const char *a
, const char *b
, const char *c
) {
718 /* Determine if b is strictly greater than a and strictly smaller than c.
719 We consider the order of names to be circular, so that if a is
720 strictly greater than c, we consider b to be between them if it is
721 either greater than a or smaller than c. This is how the canonical
722 DNS name order used in NSEC records work. */
724 n
= dns_name_compare_func(a
, c
);
729 return dns_name_compare_func(a
, b
) < 0 &&
730 dns_name_compare_func(b
, c
) < 0;
732 /* <--b--c a--b--> */
733 return dns_name_compare_func(b
, c
) < 0 ||
734 dns_name_compare_func(a
, b
) < 0;
737 int dns_name_reverse(int family
, const union in_addr_union
*a
, char **ret
) {
744 p
= (const uint8_t*) a
;
746 if (family
== AF_INET
)
747 r
= asprintf(ret
, "%u.%u.%u.%u.in-addr.arpa", p
[3], p
[2], p
[1], p
[0]);
748 else if (family
== AF_INET6
)
749 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",
750 hexchar(p
[15] & 0xF), hexchar(p
[15] >> 4), hexchar(p
[14] & 0xF), hexchar(p
[14] >> 4),
751 hexchar(p
[13] & 0xF), hexchar(p
[13] >> 4), hexchar(p
[12] & 0xF), hexchar(p
[12] >> 4),
752 hexchar(p
[11] & 0xF), hexchar(p
[11] >> 4), hexchar(p
[10] & 0xF), hexchar(p
[10] >> 4),
753 hexchar(p
[ 9] & 0xF), hexchar(p
[ 9] >> 4), hexchar(p
[ 8] & 0xF), hexchar(p
[ 8] >> 4),
754 hexchar(p
[ 7] & 0xF), hexchar(p
[ 7] >> 4), hexchar(p
[ 6] & 0xF), hexchar(p
[ 6] >> 4),
755 hexchar(p
[ 5] & 0xF), hexchar(p
[ 5] >> 4), hexchar(p
[ 4] & 0xF), hexchar(p
[ 4] >> 4),
756 hexchar(p
[ 3] & 0xF), hexchar(p
[ 3] >> 4), hexchar(p
[ 2] & 0xF), hexchar(p
[ 2] >> 4),
757 hexchar(p
[ 1] & 0xF), hexchar(p
[ 1] >> 4), hexchar(p
[ 0] & 0xF), hexchar(p
[ 0] >> 4));
759 return -EAFNOSUPPORT
;
766 int dns_name_address(const char *p
, int *family
, union in_addr_union
*address
) {
773 r
= dns_name_endswith(p
, "in-addr.arpa");
780 for (i
= 0; i
< ELEMENTSOF(a
); i
++) {
781 char label
[DNS_LABEL_MAX
+1];
783 r
= dns_label_unescape(&p
, label
, sizeof(label
));
791 r
= safe_atou8(label
, &a
[i
]);
796 r
= dns_name_equal(p
, "in-addr.arpa");
801 address
->in
.s_addr
= htobe32(((uint32_t) a
[3] << 24) |
802 ((uint32_t) a
[2] << 16) |
803 ((uint32_t) a
[1] << 8) |
809 r
= dns_name_endswith(p
, "ip6.arpa");
816 for (i
= 0; i
< ELEMENTSOF(a
.s6_addr
); i
++) {
817 char label
[DNS_LABEL_MAX
+1];
820 r
= dns_label_unescape(&p
, label
, sizeof(label
));
825 x
= unhexchar(label
[0]);
829 r
= dns_label_unescape(&p
, label
, sizeof(label
));
834 y
= unhexchar(label
[0]);
838 a
.s6_addr
[ELEMENTSOF(a
.s6_addr
) - i
- 1] = (uint8_t) y
<< 4 | (uint8_t) x
;
841 r
= dns_name_equal(p
, "ip6.arpa");
853 bool dns_name_is_root(const char *name
) {
857 /* There are exactly two ways to encode the root domain name:
858 * as empty string, or with a single dot. */
860 return STR_IN_SET(name
, "", ".");
863 bool dns_name_is_single_label(const char *name
) {
864 char label
[DNS_LABEL_MAX
+1];
869 r
= dns_label_unescape(&name
, label
, sizeof(label
));
873 return dns_name_is_root(name
);
876 /* Encode a domain name according to RFC 1035 Section 3.1, without compression */
877 int dns_name_to_wire_format(const char *domain
, uint8_t *buffer
, size_t len
, bool canonical
) {
878 uint8_t *label_length
, *out
;
887 /* Reserve a byte for label length */
894 /* Convert and copy a single label. Note that
895 * dns_label_unescape() returns 0 when it hits the end
896 * of the domain name, which we rely on here to encode
897 * the trailing NUL byte. */
898 r
= dns_label_unescape(&domain
, (char *) out
, len
);
905 /* Optionally, output the name in DNSSEC
906 * canonical format, as described in RFC 4034,
907 * section 6.2. Or in other words: in
910 for (i
= 0; i
< (size_t) r
; i
++) {
911 if (out
[i
] >= 'A' && out
[i
] <= 'Z')
912 out
[i
] = out
[i
] - 'A' + 'a';
916 /* Fill label length, move forward */
923 /* Verify the maximum size of the encoded name. The trailing
924 * dot + NUL byte account are included this time, hence
925 * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
927 if (out
- buffer
> DNS_HOSTNAME_MAX
+ 2)
933 static bool srv_type_label_is_valid(const char *label
, size_t n
) {
938 if (n
< 2) /* Label needs to be at least 2 chars long */
941 if (label
[0] != '_') /* First label char needs to be underscore */
944 /* Second char must be a letter */
945 if (!(label
[1] >= 'A' && label
[1] <= 'Z') &&
946 !(label
[1] >= 'a' && label
[1] <= 'z'))
949 /* Third and further chars must be alphanumeric or a hyphen */
950 for (k
= 2; k
< n
; k
++) {
951 if (!(label
[k
] >= 'A' && label
[k
] <= 'Z') &&
952 !(label
[k
] >= 'a' && label
[k
] <= 'z') &&
953 !(label
[k
] >= '0' && label
[k
] <= '9') &&
961 bool dns_srv_type_is_valid(const char *name
) {
969 char label
[DNS_LABEL_MAX
];
971 /* This more or less implements RFC 6335, Section 5.1 */
973 r
= dns_label_unescape(&name
, label
, sizeof(label
));
982 if (!srv_type_label_is_valid(label
, r
))
988 return c
== 2; /* exactly two labels */
991 bool dns_service_name_is_valid(const char *name
) {
994 /* This more or less implements RFC 6763, Section 4.1.1 */
999 if (!utf8_is_valid(name
))
1002 if (string_has_cc(name
, NULL
))
1014 int dns_service_join(const char *name
, const char *type
, const char *domain
, char **ret
) {
1015 char escaped
[DNS_LABEL_ESCAPED_MAX
];
1016 _cleanup_free_
char *n
= NULL
;
1023 if (!dns_srv_type_is_valid(type
))
1027 return dns_name_concat(type
, domain
, ret
);
1029 if (!dns_service_name_is_valid(name
))
1032 r
= dns_label_escape(name
, strlen(name
), escaped
, sizeof(escaped
));
1036 r
= dns_name_concat(type
, domain
, &n
);
1040 return dns_name_concat(escaped
, n
, ret
);
1043 static bool dns_service_name_label_is_valid(const char *label
, size_t n
) {
1048 if (memchr(label
, 0, n
))
1051 s
= strndupa(label
, n
);
1052 return dns_service_name_is_valid(s
);
1055 int dns_service_split(const char *joined
, char **_name
, char **_type
, char **_domain
) {
1056 _cleanup_free_
char *name
= NULL
, *type
= NULL
, *domain
= NULL
;
1057 const char *p
= joined
, *q
= NULL
, *d
= NULL
;
1058 char a
[DNS_LABEL_MAX
], b
[DNS_LABEL_MAX
], c
[DNS_LABEL_MAX
];
1064 /* Get first label from the full name */
1065 an
= dns_label_unescape(&p
, a
, sizeof(a
));
1072 /* If there was a first label, try to get the second one */
1073 bn
= dns_label_unescape(&p
, b
, sizeof(b
));
1080 /* If there was a second label, try to get the third one */
1082 cn
= dns_label_unescape(&p
, c
, sizeof(c
));
1093 if (x
>= 2 && srv_type_label_is_valid(b
, bn
)) {
1095 if (x
>= 3 && srv_type_label_is_valid(c
, cn
)) {
1097 if (dns_service_name_label_is_valid(a
, an
)) {
1099 /* OK, got <name> . <type> . <type2> . <domain> */
1101 name
= strndup(a
, an
);
1105 type
= new(char, bn
+1+cn
+1);
1108 strcpy(stpcpy(stpcpy(type
, b
), "."), c
);
1114 } else if (srv_type_label_is_valid(a
, an
)) {
1116 /* OK, got <type> . <type2> . <domain> */
1120 type
= new(char, an
+1+bn
+1);
1123 strcpy(stpcpy(stpcpy(type
, a
), "."), b
);
1135 r
= dns_name_normalize(d
, &domain
);