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
));
497 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
507 ascii_strlower(label
);
509 string_hash_func(label
, state
);
512 /* enforce that all names are terminated by the empty label */
513 string_hash_func("", state
);
516 int dns_name_compare_func(const void *a
, const void *b
) {
523 x
= (const char *) a
+ strlen(a
);
524 y
= (const char *) b
+ strlen(b
);
527 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
529 if (x
== NULL
&& y
== NULL
)
532 r
= dns_label_unescape_suffix(a
, &x
, la
, sizeof(la
));
533 q
= dns_label_unescape_suffix(b
, &y
, lb
, sizeof(lb
));
537 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
538 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
547 r
= strcasecmp(la
, lb
);
553 const struct hash_ops dns_name_hash_ops
= {
554 .hash
= dns_name_hash_func
,
555 .compare
= dns_name_compare_func
558 int dns_name_equal(const char *x
, const char *y
) {
565 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
567 if (*x
== 0 && *y
== 0)
570 r
= dns_label_unescape(&x
, la
, sizeof(la
));
574 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
581 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
585 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
592 /* If one name had fewer labels than the other, this
593 * will show up as empty label here, which the
594 * strcasecmp() below will properly consider different
595 * from a non-empty label. */
598 if (strcasecmp(la
, lb
) != 0)
603 int dns_name_endswith(const char *name
, const char *suffix
) {
604 const char *n
, *s
, *saved_n
= NULL
;
614 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
616 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
620 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
630 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
634 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
641 if (r
== 0 && q
== 0)
643 if (r
== 0 && saved_n
== n
)
648 if (r
!= q
|| strcasecmp(ln
, ls
)) {
650 /* Not the same, let's jump back, and try with the next label again */
658 int dns_name_change_suffix(const char *name
, const char *old_suffix
, const char *new_suffix
, char **ret
) {
659 const char *n
, *s
, *saved_before
= NULL
, *saved_after
= NULL
, *prefix
;
671 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
676 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
680 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
690 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
694 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
701 if (r
== 0 && q
== 0)
703 if (r
== 0 && saved_after
== n
) {
704 *ret
= NULL
; /* doesn't match */
710 if (r
!= q
|| strcasecmp(ln
, ls
)) {
712 /* Not the same, let's jump back, and try with the next label again */
715 saved_after
= saved_before
= NULL
;
719 /* Found it! Now generate the new name */
720 prefix
= strndupa(name
, saved_before
- name
);
722 r
= dns_name_concat(prefix
, new_suffix
, ret
);
729 int dns_name_between(const char *a
, const char *b
, const char *c
) {
732 /* Determine if b is strictly greater than a and strictly smaller than c.
733 We consider the order of names to be circular, so that if a is
734 strictly greater than c, we consider b to be between them if it is
735 either greater than a or smaller than c. This is how the canonical
736 DNS name order used in NSEC records work. */
738 n
= dns_name_compare_func(a
, c
);
743 return dns_name_compare_func(a
, b
) < 0 &&
744 dns_name_compare_func(b
, c
) < 0;
746 /* <--b--c a--b--> */
747 return dns_name_compare_func(b
, c
) < 0 ||
748 dns_name_compare_func(a
, b
) < 0;
751 int dns_name_reverse(int family
, const union in_addr_union
*a
, char **ret
) {
758 p
= (const uint8_t*) a
;
760 if (family
== AF_INET
)
761 r
= asprintf(ret
, "%u.%u.%u.%u.in-addr.arpa", p
[3], p
[2], p
[1], p
[0]);
762 else if (family
== AF_INET6
)
763 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",
764 hexchar(p
[15] & 0xF), hexchar(p
[15] >> 4), hexchar(p
[14] & 0xF), hexchar(p
[14] >> 4),
765 hexchar(p
[13] & 0xF), hexchar(p
[13] >> 4), hexchar(p
[12] & 0xF), hexchar(p
[12] >> 4),
766 hexchar(p
[11] & 0xF), hexchar(p
[11] >> 4), hexchar(p
[10] & 0xF), hexchar(p
[10] >> 4),
767 hexchar(p
[ 9] & 0xF), hexchar(p
[ 9] >> 4), hexchar(p
[ 8] & 0xF), hexchar(p
[ 8] >> 4),
768 hexchar(p
[ 7] & 0xF), hexchar(p
[ 7] >> 4), hexchar(p
[ 6] & 0xF), hexchar(p
[ 6] >> 4),
769 hexchar(p
[ 5] & 0xF), hexchar(p
[ 5] >> 4), hexchar(p
[ 4] & 0xF), hexchar(p
[ 4] >> 4),
770 hexchar(p
[ 3] & 0xF), hexchar(p
[ 3] >> 4), hexchar(p
[ 2] & 0xF), hexchar(p
[ 2] >> 4),
771 hexchar(p
[ 1] & 0xF), hexchar(p
[ 1] >> 4), hexchar(p
[ 0] & 0xF), hexchar(p
[ 0] >> 4));
773 return -EAFNOSUPPORT
;
780 int dns_name_address(const char *p
, int *family
, union in_addr_union
*address
) {
787 r
= dns_name_endswith(p
, "in-addr.arpa");
794 for (i
= 0; i
< ELEMENTSOF(a
); i
++) {
795 char label
[DNS_LABEL_MAX
+1];
797 r
= dns_label_unescape(&p
, label
, sizeof(label
));
805 r
= safe_atou8(label
, &a
[i
]);
810 r
= dns_name_equal(p
, "in-addr.arpa");
815 address
->in
.s_addr
= htobe32(((uint32_t) a
[3] << 24) |
816 ((uint32_t) a
[2] << 16) |
817 ((uint32_t) a
[1] << 8) |
823 r
= dns_name_endswith(p
, "ip6.arpa");
830 for (i
= 0; i
< ELEMENTSOF(a
.s6_addr
); i
++) {
831 char label
[DNS_LABEL_MAX
+1];
834 r
= dns_label_unescape(&p
, label
, sizeof(label
));
839 x
= unhexchar(label
[0]);
843 r
= dns_label_unescape(&p
, label
, sizeof(label
));
848 y
= unhexchar(label
[0]);
852 a
.s6_addr
[ELEMENTSOF(a
.s6_addr
) - i
- 1] = (uint8_t) y
<< 4 | (uint8_t) x
;
855 r
= dns_name_equal(p
, "ip6.arpa");
867 bool dns_name_is_root(const char *name
) {
871 /* There are exactly two ways to encode the root domain name:
872 * as empty string, or with a single dot. */
874 return STR_IN_SET(name
, "", ".");
877 bool dns_name_is_single_label(const char *name
) {
878 char label
[DNS_LABEL_MAX
+1];
883 r
= dns_label_unescape(&name
, label
, sizeof(label
));
887 return dns_name_is_root(name
);
890 /* Encode a domain name according to RFC 1035 Section 3.1, without compression */
891 int dns_name_to_wire_format(const char *domain
, uint8_t *buffer
, size_t len
, bool canonical
) {
892 uint8_t *label_length
, *out
;
901 /* Reserve a byte for label length */
908 /* Convert and copy a single label. Note that
909 * dns_label_unescape() returns 0 when it hits the end
910 * of the domain name, which we rely on here to encode
911 * the trailing NUL byte. */
912 r
= dns_label_unescape(&domain
, (char *) out
, len
);
919 /* Optionally, output the name in DNSSEC
920 * canonical format, as described in RFC 4034,
921 * section 6.2. Or in other words: in
924 for (i
= 0; i
< (size_t) r
; i
++) {
925 if (out
[i
] >= 'A' && out
[i
] <= 'Z')
926 out
[i
] = out
[i
] - 'A' + 'a';
930 /* Fill label length, move forward */
937 /* Verify the maximum size of the encoded name. The trailing
938 * dot + NUL byte account are included this time, hence
939 * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
941 if (out
- buffer
> DNS_HOSTNAME_MAX
+ 2)
947 static bool srv_type_label_is_valid(const char *label
, size_t n
) {
952 if (n
< 2) /* Label needs to be at least 2 chars long */
955 if (label
[0] != '_') /* First label char needs to be underscore */
958 /* Second char must be a letter */
959 if (!(label
[1] >= 'A' && label
[1] <= 'Z') &&
960 !(label
[1] >= 'a' && label
[1] <= 'z'))
963 /* Third and further chars must be alphanumeric or a hyphen */
964 for (k
= 2; k
< n
; k
++) {
965 if (!(label
[k
] >= 'A' && label
[k
] <= 'Z') &&
966 !(label
[k
] >= 'a' && label
[k
] <= 'z') &&
967 !(label
[k
] >= '0' && label
[k
] <= '9') &&
975 bool dns_srv_type_is_valid(const char *name
) {
983 char label
[DNS_LABEL_MAX
];
985 /* This more or less implements RFC 6335, Section 5.1 */
987 r
= dns_label_unescape(&name
, label
, sizeof(label
));
996 if (!srv_type_label_is_valid(label
, r
))
1002 return c
== 2; /* exactly two labels */
1005 bool dns_service_name_is_valid(const char *name
) {
1008 /* This more or less implements RFC 6763, Section 4.1.1 */
1013 if (!utf8_is_valid(name
))
1016 if (string_has_cc(name
, NULL
))
1028 int dns_service_join(const char *name
, const char *type
, const char *domain
, char **ret
) {
1029 char escaped
[DNS_LABEL_ESCAPED_MAX
];
1030 _cleanup_free_
char *n
= NULL
;
1037 if (!dns_srv_type_is_valid(type
))
1041 return dns_name_concat(type
, domain
, ret
);
1043 if (!dns_service_name_is_valid(name
))
1046 r
= dns_label_escape(name
, strlen(name
), escaped
, sizeof(escaped
));
1050 r
= dns_name_concat(type
, domain
, &n
);
1054 return dns_name_concat(escaped
, n
, ret
);
1057 static bool dns_service_name_label_is_valid(const char *label
, size_t n
) {
1062 if (memchr(label
, 0, n
))
1065 s
= strndupa(label
, n
);
1066 return dns_service_name_is_valid(s
);
1069 int dns_service_split(const char *joined
, char **_name
, char **_type
, char **_domain
) {
1070 _cleanup_free_
char *name
= NULL
, *type
= NULL
, *domain
= NULL
;
1071 const char *p
= joined
, *q
= NULL
, *d
= NULL
;
1072 char a
[DNS_LABEL_MAX
], b
[DNS_LABEL_MAX
], c
[DNS_LABEL_MAX
];
1078 /* Get first label from the full name */
1079 an
= dns_label_unescape(&p
, a
, sizeof(a
));
1086 /* If there was a first label, try to get the second one */
1087 bn
= dns_label_unescape(&p
, b
, sizeof(b
));
1094 /* If there was a second label, try to get the third one */
1096 cn
= dns_label_unescape(&p
, c
, sizeof(c
));
1107 if (x
>= 2 && srv_type_label_is_valid(b
, bn
)) {
1109 if (x
>= 3 && srv_type_label_is_valid(c
, cn
)) {
1111 if (dns_service_name_label_is_valid(a
, an
)) {
1113 /* OK, got <name> . <type> . <type2> . <domain> */
1115 name
= strndup(a
, an
);
1119 type
= new(char, bn
+1+cn
+1);
1122 strcpy(stpcpy(stpcpy(type
, b
), "."), c
);
1128 } else if (srv_type_label_is_valid(a
, an
)) {
1130 /* OK, got <type> . <type2> . <domain> */
1134 type
= new(char, an
+1+bn
+1);
1137 strcpy(stpcpy(stpcpy(type
, a
), "."), b
);
1149 r
= dns_name_normalize(d
, &domain
);
1171 int dns_name_suffix(const char *name
, unsigned n_labels
, const char **ret
) {
1172 const char* labels
[DNS_N_LABELS_MAX
+1];
1182 if (n
> DNS_N_LABELS_MAX
)
1187 r
= dns_name_parent(&p
);
1199 *ret
= labels
[n
- n_labels
];
1200 return (int) (n
- n_labels
);
1203 int dns_name_count_labels(const char *name
) {
1212 r
= dns_name_parent(&p
);
1218 if (n
>= DNS_N_LABELS_MAX
)
1227 int dns_name_equal_skip(const char *a
, unsigned n_labels
, const char *b
) {
1233 while (n_labels
> 0) {
1235 r
= dns_name_parent(&a
);
1242 return dns_name_equal(a
, b
);