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 CC characters or anything that doesn't fit in 8bit */
102 if (k
< ' ' || k
> 255 || k
== 127)
114 } else if ((uint8_t) *n
>= (uint8_t) ' ' && *n
!= 127) {
116 /* Normal character */
127 /* Empty label that is not at the end? */
138 /* @label_terminal: terminal character of a label, updated to point to the terminal character of
139 * the previous label (always skipping one dot) or to NULL if there are no more
141 int dns_label_unescape_suffix(const char *name
, const char **label_terminal
, char *dest
, size_t sz
) {
142 const char *terminal
;
146 assert(label_terminal
);
150 if (!*label_terminal
) {
157 terminal
= *label_terminal
;
158 assert(*terminal
== '.' || *terminal
== 0);
160 /* Skip current terminal character (and accept domain names ending it ".") */
163 if (terminal
>= name
&& *terminal
== '.')
166 /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
168 if (terminal
< name
) {
169 /* Reached the first label, so indicate that there are no more */
174 /* Find the start of the last label */
175 if (*terminal
== '.') {
177 unsigned slashes
= 0;
179 for (y
= terminal
- 1; y
>= name
&& *y
== '\\'; y
--)
182 if (slashes
% 2 == 0) {
183 /* The '.' was not escaped */
195 r
= dns_label_unescape(&name
, dest
, sz
);
199 *label_terminal
= terminal
;
204 int dns_label_escape(const char *p
, size_t l
, char *dest
, size_t sz
) {
207 /* DNS labels must be between 1 and 63 characters long. A
208 * zero-length label does not exist. See RFC 2182, Section
211 if (l
<= 0 || l
> DNS_LABEL_MAX
)
222 if (*p
== '.' || *p
== '\\') {
224 /* Dot or backslash */
234 } else if (*p
== '_' ||
236 (*p
>= '0' && *p
<= '9') ||
237 (*p
>= 'a' && *p
<= 'z') ||
238 (*p
>= 'A' && *p
<= 'Z')) {
240 /* Proper character */
248 } else if ((uint8_t) *p
>= (uint8_t) ' ' && *p
!= 127) {
250 /* Everything else */
256 *(q
++) = '0' + (char) ((uint8_t) *p
/ 100);
257 *(q
++) = '0' + (char) (((uint8_t) *p
/ 10) % 10);
258 *(q
++) = '0' + (char) ((uint8_t) *p
% 10);
270 return (int) (q
- dest
);
273 int dns_label_escape_new(const char *p
, size_t l
, char **ret
) {
274 _cleanup_free_
char *s
= NULL
;
280 if (l
<= 0 || l
> DNS_LABEL_MAX
)
283 s
= new(char, DNS_LABEL_ESCAPED_MAX
);
287 r
= dns_label_escape(p
, l
, s
, DNS_LABEL_ESCAPED_MAX
);
297 int dns_label_apply_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
299 _cleanup_free_
uint32_t *input
= NULL
;
300 size_t input_size
, l
;
302 bool contains_8bit
= false;
303 char buffer
[DNS_LABEL_MAX
+1];
308 /* Converts an U-label into an A-label */
310 if (encoded_size
<= 0)
313 for (p
= encoded
; p
< encoded
+ encoded_size
; p
++)
314 if ((uint8_t) *p
> 127)
315 contains_8bit
= true;
317 if (!contains_8bit
) {
318 if (encoded_size
> DNS_LABEL_MAX
)
324 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
328 if (idna_to_ascii_4i(input
, input_size
, buffer
, 0) != 0)
333 /* Verify that the the result is not longer than one DNS label. */
334 if (l
<= 0 || l
> DNS_LABEL_MAX
)
339 memcpy(decoded
, buffer
, l
);
341 /* If there's room, append a trailing NUL byte, but only then */
351 int dns_label_undo_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
353 size_t input_size
, output_size
;
354 _cleanup_free_
uint32_t *input
= NULL
;
355 _cleanup_free_
char *result
= NULL
;
356 uint32_t *output
= NULL
;
359 /* To be invoked after unescaping. Converts an A-label into an U-label. */
364 if (encoded_size
<= 0 || encoded_size
> DNS_LABEL_MAX
)
367 if (encoded_size
< sizeof(IDNA_ACE_PREFIX
)-1)
370 if (memcmp(encoded
, IDNA_ACE_PREFIX
, sizeof(IDNA_ACE_PREFIX
) -1) != 0)
373 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
377 output_size
= input_size
;
378 output
= newa(uint32_t, output_size
);
380 idna_to_unicode_44i(input
, input_size
, output
, &output_size
, 0);
382 result
= stringprep_ucs4_to_utf8(output
, output_size
, NULL
, &w
);
390 memcpy(decoded
, result
, w
);
392 /* Append trailing NUL byte if there's space, but only then. */
402 int dns_name_concat(const char *a
, const char *b
, char **_ret
) {
403 _cleanup_free_
char *ret
= NULL
;
404 size_t n
= 0, allocated
= 0;
412 char label
[DNS_LABEL_MAX
];
415 r
= dns_label_unescape(&p
, label
, sizeof(label
));
423 /* Now continue with the second string, if there is one */
432 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
439 if (!GREEDY_REALLOC(ret
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
))
442 r
= dns_label_escape(label
, r
, ret
+ n
+ !first
, DNS_LABEL_ESCAPED_MAX
);
449 char escaped
[DNS_LABEL_ESCAPED_MAX
];
451 r
= dns_label_escape(label
, r
, escaped
, sizeof(escaped
));
464 if (n
> DNS_HOSTNAME_MAX
)
468 if (!GREEDY_REALLOC(ret
, allocated
, n
+ 1))
479 void dns_name_hash_func(const void *s
, struct siphash
*state
) {
486 char label
[DNS_LABEL_MAX
+1];
489 r
= dns_label_unescape(&p
, label
, sizeof(label
));
493 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
503 ascii_strlower(label
);
505 string_hash_func(label
, state
);
508 /* enforce that all names are terminated by the empty label */
509 string_hash_func("", state
);
512 int dns_name_compare_func(const void *a
, const void *b
) {
519 x
= (const char *) a
+ strlen(a
);
520 y
= (const char *) b
+ strlen(b
);
523 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
525 if (x
== NULL
&& y
== NULL
)
528 r
= dns_label_unescape_suffix(a
, &x
, la
, sizeof(la
));
529 q
= dns_label_unescape_suffix(b
, &y
, lb
, sizeof(lb
));
533 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
534 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
543 r
= strcasecmp(la
, lb
);
549 const struct hash_ops dns_name_hash_ops
= {
550 .hash
= dns_name_hash_func
,
551 .compare
= dns_name_compare_func
554 int dns_name_equal(const char *x
, const char *y
) {
561 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
563 if (*x
== 0 && *y
== 0)
566 r
= dns_label_unescape(&x
, la
, sizeof(la
));
570 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
577 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
581 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
588 /* If one name had fewer labels than the other, this
589 * will show up as empty label here, which the
590 * strcasecmp() below will properly consider different
591 * from a non-empty label. */
594 if (strcasecmp(la
, lb
) != 0)
599 int dns_name_endswith(const char *name
, const char *suffix
) {
600 const char *n
, *s
, *saved_n
= NULL
;
610 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
612 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
616 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
626 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
630 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
637 if (r
== 0 && q
== 0)
639 if (r
== 0 && saved_n
== n
)
644 if (r
!= q
|| strcasecmp(ln
, ls
)) {
646 /* Not the same, let's jump back, and try with the next label again */
654 int dns_name_change_suffix(const char *name
, const char *old_suffix
, const char *new_suffix
, char **ret
) {
655 const char *n
, *s
, *saved_before
= NULL
, *saved_after
= NULL
, *prefix
;
667 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
672 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
676 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
686 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
690 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
697 if (r
== 0 && q
== 0)
699 if (r
== 0 && saved_after
== n
) {
700 *ret
= NULL
; /* doesn't match */
706 if (r
!= q
|| strcasecmp(ln
, ls
)) {
708 /* Not the same, let's jump back, and try with the next label again */
711 saved_after
= saved_before
= NULL
;
715 /* Found it! Now generate the new name */
716 prefix
= strndupa(name
, saved_before
- name
);
718 r
= dns_name_concat(prefix
, new_suffix
, ret
);
725 int dns_name_between(const char *a
, const char *b
, const char *c
) {
728 /* Determine if b is strictly greater than a and strictly smaller than c.
729 We consider the order of names to be circular, so that if a is
730 strictly greater than c, we consider b to be between them if it is
731 either greater than a or smaller than c. This is how the canonical
732 DNS name order used in NSEC records work. */
734 n
= dns_name_compare_func(a
, c
);
739 return dns_name_compare_func(a
, b
) < 0 &&
740 dns_name_compare_func(b
, c
) < 0;
742 /* <--b--c a--b--> */
743 return dns_name_compare_func(b
, c
) < 0 ||
744 dns_name_compare_func(a
, b
) < 0;
747 int dns_name_reverse(int family
, const union in_addr_union
*a
, char **ret
) {
754 p
= (const uint8_t*) a
;
756 if (family
== AF_INET
)
757 r
= asprintf(ret
, "%u.%u.%u.%u.in-addr.arpa", p
[3], p
[2], p
[1], p
[0]);
758 else if (family
== AF_INET6
)
759 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",
760 hexchar(p
[15] & 0xF), hexchar(p
[15] >> 4), hexchar(p
[14] & 0xF), hexchar(p
[14] >> 4),
761 hexchar(p
[13] & 0xF), hexchar(p
[13] >> 4), hexchar(p
[12] & 0xF), hexchar(p
[12] >> 4),
762 hexchar(p
[11] & 0xF), hexchar(p
[11] >> 4), hexchar(p
[10] & 0xF), hexchar(p
[10] >> 4),
763 hexchar(p
[ 9] & 0xF), hexchar(p
[ 9] >> 4), hexchar(p
[ 8] & 0xF), hexchar(p
[ 8] >> 4),
764 hexchar(p
[ 7] & 0xF), hexchar(p
[ 7] >> 4), hexchar(p
[ 6] & 0xF), hexchar(p
[ 6] >> 4),
765 hexchar(p
[ 5] & 0xF), hexchar(p
[ 5] >> 4), hexchar(p
[ 4] & 0xF), hexchar(p
[ 4] >> 4),
766 hexchar(p
[ 3] & 0xF), hexchar(p
[ 3] >> 4), hexchar(p
[ 2] & 0xF), hexchar(p
[ 2] >> 4),
767 hexchar(p
[ 1] & 0xF), hexchar(p
[ 1] >> 4), hexchar(p
[ 0] & 0xF), hexchar(p
[ 0] >> 4));
769 return -EAFNOSUPPORT
;
776 int dns_name_address(const char *p
, int *family
, union in_addr_union
*address
) {
783 r
= dns_name_endswith(p
, "in-addr.arpa");
790 for (i
= 0; i
< ELEMENTSOF(a
); i
++) {
791 char label
[DNS_LABEL_MAX
+1];
793 r
= dns_label_unescape(&p
, label
, sizeof(label
));
801 r
= safe_atou8(label
, &a
[i
]);
806 r
= dns_name_equal(p
, "in-addr.arpa");
811 address
->in
.s_addr
= htobe32(((uint32_t) a
[3] << 24) |
812 ((uint32_t) a
[2] << 16) |
813 ((uint32_t) a
[1] << 8) |
819 r
= dns_name_endswith(p
, "ip6.arpa");
826 for (i
= 0; i
< ELEMENTSOF(a
.s6_addr
); i
++) {
827 char label
[DNS_LABEL_MAX
+1];
830 r
= dns_label_unescape(&p
, label
, sizeof(label
));
835 x
= unhexchar(label
[0]);
839 r
= dns_label_unescape(&p
, label
, sizeof(label
));
844 y
= unhexchar(label
[0]);
848 a
.s6_addr
[ELEMENTSOF(a
.s6_addr
) - i
- 1] = (uint8_t) y
<< 4 | (uint8_t) x
;
851 r
= dns_name_equal(p
, "ip6.arpa");
863 bool dns_name_is_root(const char *name
) {
867 /* There are exactly two ways to encode the root domain name:
868 * as empty string, or with a single dot. */
870 return STR_IN_SET(name
, "", ".");
873 bool dns_name_is_single_label(const char *name
) {
874 char label
[DNS_LABEL_MAX
+1];
879 r
= dns_label_unescape(&name
, label
, sizeof(label
));
883 return dns_name_is_root(name
);
886 /* Encode a domain name according to RFC 1035 Section 3.1, without compression */
887 int dns_name_to_wire_format(const char *domain
, uint8_t *buffer
, size_t len
, bool canonical
) {
888 uint8_t *label_length
, *out
;
897 /* Reserve a byte for label length */
904 /* Convert and copy a single label. Note that
905 * dns_label_unescape() returns 0 when it hits the end
906 * of the domain name, which we rely on here to encode
907 * the trailing NUL byte. */
908 r
= dns_label_unescape(&domain
, (char *) out
, len
);
915 /* Optionally, output the name in DNSSEC
916 * canonical format, as described in RFC 4034,
917 * section 6.2. Or in other words: in
920 for (i
= 0; i
< (size_t) r
; i
++) {
921 if (out
[i
] >= 'A' && out
[i
] <= 'Z')
922 out
[i
] = out
[i
] - 'A' + 'a';
926 /* Fill label length, move forward */
933 /* Verify the maximum size of the encoded name. The trailing
934 * dot + NUL byte account are included this time, hence
935 * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
937 if (out
- buffer
> DNS_HOSTNAME_MAX
+ 2)
943 static bool srv_type_label_is_valid(const char *label
, size_t n
) {
948 if (n
< 2) /* Label needs to be at least 2 chars long */
951 if (label
[0] != '_') /* First label char needs to be underscore */
954 /* Second char must be a letter */
955 if (!(label
[1] >= 'A' && label
[1] <= 'Z') &&
956 !(label
[1] >= 'a' && label
[1] <= 'z'))
959 /* Third and further chars must be alphanumeric or a hyphen */
960 for (k
= 2; k
< n
; k
++) {
961 if (!(label
[k
] >= 'A' && label
[k
] <= 'Z') &&
962 !(label
[k
] >= 'a' && label
[k
] <= 'z') &&
963 !(label
[k
] >= '0' && label
[k
] <= '9') &&
971 bool dns_srv_type_is_valid(const char *name
) {
979 char label
[DNS_LABEL_MAX
];
981 /* This more or less implements RFC 6335, Section 5.1 */
983 r
= dns_label_unescape(&name
, label
, sizeof(label
));
992 if (!srv_type_label_is_valid(label
, r
))
998 return c
== 2; /* exactly two labels */
1001 bool dns_service_name_is_valid(const char *name
) {
1004 /* This more or less implements RFC 6763, Section 4.1.1 */
1009 if (!utf8_is_valid(name
))
1012 if (string_has_cc(name
, NULL
))
1024 int dns_service_join(const char *name
, const char *type
, const char *domain
, char **ret
) {
1025 char escaped
[DNS_LABEL_ESCAPED_MAX
];
1026 _cleanup_free_
char *n
= NULL
;
1033 if (!dns_srv_type_is_valid(type
))
1037 return dns_name_concat(type
, domain
, ret
);
1039 if (!dns_service_name_is_valid(name
))
1042 r
= dns_label_escape(name
, strlen(name
), escaped
, sizeof(escaped
));
1046 r
= dns_name_concat(type
, domain
, &n
);
1050 return dns_name_concat(escaped
, n
, ret
);
1053 static bool dns_service_name_label_is_valid(const char *label
, size_t n
) {
1058 if (memchr(label
, 0, n
))
1061 s
= strndupa(label
, n
);
1062 return dns_service_name_is_valid(s
);
1065 int dns_service_split(const char *joined
, char **_name
, char **_type
, char **_domain
) {
1066 _cleanup_free_
char *name
= NULL
, *type
= NULL
, *domain
= NULL
;
1067 const char *p
= joined
, *q
= NULL
, *d
= NULL
;
1068 char a
[DNS_LABEL_MAX
], b
[DNS_LABEL_MAX
], c
[DNS_LABEL_MAX
];
1074 /* Get first label from the full name */
1075 an
= dns_label_unescape(&p
, a
, sizeof(a
));
1082 /* If there was a first label, try to get the second one */
1083 bn
= dns_label_unescape(&p
, b
, sizeof(b
));
1090 /* If there was a second label, try to get the third one */
1092 cn
= dns_label_unescape(&p
, c
, sizeof(c
));
1103 if (x
>= 2 && srv_type_label_is_valid(b
, bn
)) {
1105 if (x
>= 3 && srv_type_label_is_valid(c
, cn
)) {
1107 if (dns_service_name_label_is_valid(a
, an
)) {
1109 /* OK, got <name> . <type> . <type2> . <domain> */
1111 name
= strndup(a
, an
);
1115 type
= new(char, bn
+1+cn
+1);
1118 strcpy(stpcpy(stpcpy(type
, b
), "."), c
);
1124 } else if (srv_type_label_is_valid(a
, an
)) {
1126 /* OK, got <type> . <type2> . <domain> */
1130 type
= new(char, an
+1+bn
+1);
1133 strcpy(stpcpy(stpcpy(type
, a
), "."), b
);
1145 r
= dns_name_normalize(d
, &domain
);
1167 int dns_name_suffix(const char *name
, unsigned n_labels
, const char **ret
) {
1168 const char* labels
[DNS_N_LABELS_MAX
+1];
1178 if (n
> DNS_N_LABELS_MAX
)
1183 r
= dns_name_parent(&p
);
1195 *ret
= labels
[n
- n_labels
];
1196 return (int) (n
- n_labels
);
1199 int dns_name_count_labels(const char *name
) {
1208 r
= dns_name_parent(&p
);
1214 if (n
>= DNS_N_LABELS_MAX
)
1223 int dns_name_equal_skip(const char *a
, unsigned n_labels
, const char *b
) {
1229 while (n_labels
> 0) {
1231 r
= dns_name_parent(&a
);
1238 return dns_name_equal(a
, b
);