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 assert(**label_terminal
== '.' || **label_terminal
== 0);
159 /* skip current terminal character */
160 terminal
= *label_terminal
- 1;
162 /* point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
164 if (terminal
< name
) {
165 /* reached the first label, so indicate that there are no more */
170 /* find the start of the last label */
171 if (*terminal
== '.') {
173 unsigned slashes
= 0;
175 for (y
= terminal
- 1; y
>= name
&& *y
== '\\'; y
--)
178 if (slashes
% 2 == 0) {
179 /* the '.' was not escaped */
191 r
= dns_label_unescape(&name
, dest
, sz
);
195 *label_terminal
= terminal
;
200 int dns_label_escape(const char *p
, size_t l
, char *dest
, size_t sz
) {
203 /* DNS labels must be between 1 and 63 characters long. A
204 * zero-length label does not exist. See RFC 2182, Section
207 if (l
<= 0 || l
> DNS_LABEL_MAX
)
218 if (*p
== '.' || *p
== '\\') {
220 /* Dot or backslash */
230 } else if (*p
== '_' ||
232 (*p
>= '0' && *p
<= '9') ||
233 (*p
>= 'a' && *p
<= 'z') ||
234 (*p
>= 'A' && *p
<= 'Z')) {
236 /* Proper character */
244 } else if ((uint8_t) *p
>= (uint8_t) ' ' && *p
!= 127) {
246 /* Everything else */
252 *(q
++) = '0' + (char) ((uint8_t) *p
/ 100);
253 *(q
++) = '0' + (char) (((uint8_t) *p
/ 10) % 10);
254 *(q
++) = '0' + (char) ((uint8_t) *p
% 10);
266 return (int) (q
- dest
);
269 int dns_label_escape_new(const char *p
, size_t l
, char **ret
) {
270 _cleanup_free_
char *s
= NULL
;
276 if (l
<= 0 || l
> DNS_LABEL_MAX
)
279 s
= new(char, DNS_LABEL_ESCAPED_MAX
);
283 r
= dns_label_escape(p
, l
, s
, DNS_LABEL_ESCAPED_MAX
);
293 int dns_label_apply_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
295 _cleanup_free_
uint32_t *input
= NULL
;
296 size_t input_size
, l
;
298 bool contains_8bit
= false;
299 char buffer
[DNS_LABEL_MAX
+1];
304 /* Converts an U-label into an A-label */
306 if (encoded_size
<= 0)
309 for (p
= encoded
; p
< encoded
+ encoded_size
; p
++)
310 if ((uint8_t) *p
> 127)
311 contains_8bit
= true;
313 if (!contains_8bit
) {
314 if (encoded_size
> DNS_LABEL_MAX
)
320 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
324 if (idna_to_ascii_4i(input
, input_size
, buffer
, 0) != 0)
329 /* Verify that the the result is not longer than one DNS label. */
330 if (l
<= 0 || l
> DNS_LABEL_MAX
)
335 memcpy(decoded
, buffer
, l
);
337 /* If there's room, append a trailing NUL byte, but only then */
347 int dns_label_undo_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
349 size_t input_size
, output_size
;
350 _cleanup_free_
uint32_t *input
= NULL
;
351 _cleanup_free_
char *result
= NULL
;
352 uint32_t *output
= NULL
;
355 /* To be invoked after unescaping. Converts an A-label into an U-label. */
360 if (encoded_size
<= 0 || encoded_size
> DNS_LABEL_MAX
)
363 if (encoded_size
< sizeof(IDNA_ACE_PREFIX
)-1)
366 if (memcmp(encoded
, IDNA_ACE_PREFIX
, sizeof(IDNA_ACE_PREFIX
) -1) != 0)
369 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
373 output_size
= input_size
;
374 output
= newa(uint32_t, output_size
);
376 idna_to_unicode_44i(input
, input_size
, output
, &output_size
, 0);
378 result
= stringprep_ucs4_to_utf8(output
, output_size
, NULL
, &w
);
386 memcpy(decoded
, result
, w
);
388 /* Append trailing NUL byte if there's space, but only then. */
398 int dns_name_concat(const char *a
, const char *b
, char **_ret
) {
399 _cleanup_free_
char *ret
= NULL
;
400 size_t n
= 0, allocated
= 0;
408 char label
[DNS_LABEL_MAX
];
411 r
= dns_label_unescape(&p
, label
, sizeof(label
));
419 /* Now continue with the second string, if there is one */
428 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
435 if (!GREEDY_REALLOC(ret
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
))
438 r
= dns_label_escape(label
, r
, ret
+ n
+ !first
, DNS_LABEL_ESCAPED_MAX
);
445 char escaped
[DNS_LABEL_ESCAPED_MAX
];
447 r
= dns_label_escape(label
, r
, escaped
, sizeof(escaped
));
460 if (n
> DNS_HOSTNAME_MAX
)
464 if (!GREEDY_REALLOC(ret
, allocated
, n
+ 1))
475 void dns_name_hash_func(const void *s
, struct siphash
*state
) {
482 char label
[DNS_LABEL_MAX
+1];
485 r
= dns_label_unescape(&p
, label
, sizeof(label
));
489 k
= dns_label_undo_idna(label
, r
, label
, sizeof(label
));
499 ascii_strlower(label
);
501 string_hash_func(label
, state
);
504 /* enforce that all names are terminated by the empty label */
505 string_hash_func("", state
);
508 int dns_name_compare_func(const void *a
, const void *b
) {
515 x
= (const char *) a
+ strlen(a
);
516 y
= (const char *) b
+ strlen(b
);
519 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
521 if (x
== NULL
&& y
== NULL
)
524 r
= dns_label_unescape_suffix(a
, &x
, la
, sizeof(la
));
525 q
= dns_label_unescape_suffix(b
, &y
, lb
, sizeof(lb
));
529 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
530 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
539 r
= strcasecmp(la
, lb
);
545 const struct hash_ops dns_name_hash_ops
= {
546 .hash
= dns_name_hash_func
,
547 .compare
= dns_name_compare_func
550 int dns_name_equal(const char *x
, const char *y
) {
557 char la
[DNS_LABEL_MAX
+1], lb
[DNS_LABEL_MAX
+1];
559 if (*x
== 0 && *y
== 0)
562 r
= dns_label_unescape(&x
, la
, sizeof(la
));
566 k
= dns_label_undo_idna(la
, r
, la
, sizeof(la
));
573 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
577 w
= dns_label_undo_idna(lb
, q
, lb
, sizeof(lb
));
584 /* If one name had fewer labels than the other, this
585 * will show up as empty label here, which the
586 * strcasecmp() below will properly consider different
587 * from a non-empty label. */
590 if (strcasecmp(la
, lb
) != 0)
595 int dns_name_endswith(const char *name
, const char *suffix
) {
596 const char *n
, *s
, *saved_n
= NULL
;
606 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
608 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
612 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
622 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
626 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
633 if (r
== 0 && q
== 0)
635 if (r
== 0 && saved_n
== n
)
640 if (r
!= q
|| strcasecmp(ln
, ls
)) {
642 /* Not the same, let's jump back, and try with the next label again */
650 int dns_name_change_suffix(const char *name
, const char *old_suffix
, const char *new_suffix
, char **ret
) {
651 const char *n
, *s
, *saved_before
= NULL
, *saved_after
= NULL
, *prefix
;
663 char ln
[DNS_LABEL_MAX
+1], ls
[DNS_LABEL_MAX
+1];
668 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
672 k
= dns_label_undo_idna(ln
, r
, ln
, sizeof(ln
));
682 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
686 w
= dns_label_undo_idna(ls
, q
, ls
, sizeof(ls
));
693 if (r
== 0 && q
== 0)
695 if (r
== 0 && saved_after
== n
) {
696 *ret
= NULL
; /* doesn't match */
702 if (r
!= q
|| strcasecmp(ln
, ls
)) {
704 /* Not the same, let's jump back, and try with the next label again */
707 saved_after
= saved_before
= NULL
;
711 /* Found it! Now generate the new name */
712 prefix
= strndupa(name
, saved_before
- name
);
714 r
= dns_name_concat(prefix
, new_suffix
, ret
);
721 int dns_name_between(const char *a
, const char *b
, const char *c
) {
724 /* Determine if b is strictly greater than a and strictly smaller than c.
725 We consider the order of names to be circular, so that if a is
726 strictly greater than c, we consider b to be between them if it is
727 either greater than a or smaller than c. This is how the canonical
728 DNS name order used in NSEC records work. */
730 n
= dns_name_compare_func(a
, c
);
735 return dns_name_compare_func(a
, b
) < 0 &&
736 dns_name_compare_func(b
, c
) < 0;
738 /* <--b--c a--b--> */
739 return dns_name_compare_func(b
, c
) < 0 ||
740 dns_name_compare_func(a
, b
) < 0;
743 int dns_name_reverse(int family
, const union in_addr_union
*a
, char **ret
) {
750 p
= (const uint8_t*) a
;
752 if (family
== AF_INET
)
753 r
= asprintf(ret
, "%u.%u.%u.%u.in-addr.arpa", p
[3], p
[2], p
[1], p
[0]);
754 else if (family
== AF_INET6
)
755 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",
756 hexchar(p
[15] & 0xF), hexchar(p
[15] >> 4), hexchar(p
[14] & 0xF), hexchar(p
[14] >> 4),
757 hexchar(p
[13] & 0xF), hexchar(p
[13] >> 4), hexchar(p
[12] & 0xF), hexchar(p
[12] >> 4),
758 hexchar(p
[11] & 0xF), hexchar(p
[11] >> 4), hexchar(p
[10] & 0xF), hexchar(p
[10] >> 4),
759 hexchar(p
[ 9] & 0xF), hexchar(p
[ 9] >> 4), hexchar(p
[ 8] & 0xF), hexchar(p
[ 8] >> 4),
760 hexchar(p
[ 7] & 0xF), hexchar(p
[ 7] >> 4), hexchar(p
[ 6] & 0xF), hexchar(p
[ 6] >> 4),
761 hexchar(p
[ 5] & 0xF), hexchar(p
[ 5] >> 4), hexchar(p
[ 4] & 0xF), hexchar(p
[ 4] >> 4),
762 hexchar(p
[ 3] & 0xF), hexchar(p
[ 3] >> 4), hexchar(p
[ 2] & 0xF), hexchar(p
[ 2] >> 4),
763 hexchar(p
[ 1] & 0xF), hexchar(p
[ 1] >> 4), hexchar(p
[ 0] & 0xF), hexchar(p
[ 0] >> 4));
765 return -EAFNOSUPPORT
;
772 int dns_name_address(const char *p
, int *family
, union in_addr_union
*address
) {
779 r
= dns_name_endswith(p
, "in-addr.arpa");
786 for (i
= 0; i
< ELEMENTSOF(a
); i
++) {
787 char label
[DNS_LABEL_MAX
+1];
789 r
= dns_label_unescape(&p
, label
, sizeof(label
));
797 r
= safe_atou8(label
, &a
[i
]);
802 r
= dns_name_equal(p
, "in-addr.arpa");
807 address
->in
.s_addr
= htobe32(((uint32_t) a
[3] << 24) |
808 ((uint32_t) a
[2] << 16) |
809 ((uint32_t) a
[1] << 8) |
815 r
= dns_name_endswith(p
, "ip6.arpa");
822 for (i
= 0; i
< ELEMENTSOF(a
.s6_addr
); i
++) {
823 char label
[DNS_LABEL_MAX
+1];
826 r
= dns_label_unescape(&p
, label
, sizeof(label
));
831 x
= unhexchar(label
[0]);
835 r
= dns_label_unescape(&p
, label
, sizeof(label
));
840 y
= unhexchar(label
[0]);
844 a
.s6_addr
[ELEMENTSOF(a
.s6_addr
) - i
- 1] = (uint8_t) y
<< 4 | (uint8_t) x
;
847 r
= dns_name_equal(p
, "ip6.arpa");
859 bool dns_name_is_root(const char *name
) {
863 /* There are exactly two ways to encode the root domain name:
864 * as empty string, or with a single dot. */
866 return STR_IN_SET(name
, "", ".");
869 bool dns_name_is_single_label(const char *name
) {
870 char label
[DNS_LABEL_MAX
+1];
875 r
= dns_label_unescape(&name
, label
, sizeof(label
));
879 return dns_name_is_root(name
);
882 /* Encode a domain name according to RFC 1035 Section 3.1, without compression */
883 int dns_name_to_wire_format(const char *domain
, uint8_t *buffer
, size_t len
, bool canonical
) {
884 uint8_t *label_length
, *out
;
893 /* Reserve a byte for label length */
900 /* Convert and copy a single label. Note that
901 * dns_label_unescape() returns 0 when it hits the end
902 * of the domain name, which we rely on here to encode
903 * the trailing NUL byte. */
904 r
= dns_label_unescape(&domain
, (char *) out
, len
);
911 /* Optionally, output the name in DNSSEC
912 * canonical format, as described in RFC 4034,
913 * section 6.2. Or in other words: in
916 for (i
= 0; i
< (size_t) r
; i
++) {
917 if (out
[i
] >= 'A' && out
[i
] <= 'Z')
918 out
[i
] = out
[i
] - 'A' + 'a';
922 /* Fill label length, move forward */
929 /* Verify the maximum size of the encoded name. The trailing
930 * dot + NUL byte account are included this time, hence
931 * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
933 if (out
- buffer
> DNS_HOSTNAME_MAX
+ 2)
939 static bool srv_type_label_is_valid(const char *label
, size_t n
) {
944 if (n
< 2) /* Label needs to be at least 2 chars long */
947 if (label
[0] != '_') /* First label char needs to be underscore */
950 /* Second char must be a letter */
951 if (!(label
[1] >= 'A' && label
[1] <= 'Z') &&
952 !(label
[1] >= 'a' && label
[1] <= 'z'))
955 /* Third and further chars must be alphanumeric or a hyphen */
956 for (k
= 2; k
< n
; k
++) {
957 if (!(label
[k
] >= 'A' && label
[k
] <= 'Z') &&
958 !(label
[k
] >= 'a' && label
[k
] <= 'z') &&
959 !(label
[k
] >= '0' && label
[k
] <= '9') &&
967 bool dns_srv_type_is_valid(const char *name
) {
975 char label
[DNS_LABEL_MAX
];
977 /* This more or less implements RFC 6335, Section 5.1 */
979 r
= dns_label_unescape(&name
, label
, sizeof(label
));
988 if (!srv_type_label_is_valid(label
, r
))
994 return c
== 2; /* exactly two labels */
997 bool dns_service_name_is_valid(const char *name
) {
1000 /* This more or less implements RFC 6763, Section 4.1.1 */
1005 if (!utf8_is_valid(name
))
1008 if (string_has_cc(name
, NULL
))
1020 int dns_service_join(const char *name
, const char *type
, const char *domain
, char **ret
) {
1021 char escaped
[DNS_LABEL_ESCAPED_MAX
];
1022 _cleanup_free_
char *n
= NULL
;
1029 if (!dns_srv_type_is_valid(type
))
1033 return dns_name_concat(type
, domain
, ret
);
1035 if (!dns_service_name_is_valid(name
))
1038 r
= dns_label_escape(name
, strlen(name
), escaped
, sizeof(escaped
));
1042 r
= dns_name_concat(type
, domain
, &n
);
1046 return dns_name_concat(escaped
, n
, ret
);
1049 static bool dns_service_name_label_is_valid(const char *label
, size_t n
) {
1054 if (memchr(label
, 0, n
))
1057 s
= strndupa(label
, n
);
1058 return dns_service_name_is_valid(s
);
1061 int dns_service_split(const char *joined
, char **_name
, char **_type
, char **_domain
) {
1062 _cleanup_free_
char *name
= NULL
, *type
= NULL
, *domain
= NULL
;
1063 const char *p
= joined
, *q
= NULL
, *d
= NULL
;
1064 char a
[DNS_LABEL_MAX
], b
[DNS_LABEL_MAX
], c
[DNS_LABEL_MAX
];
1070 /* Get first label from the full name */
1071 an
= dns_label_unescape(&p
, a
, sizeof(a
));
1078 /* If there was a first label, try to get the second one */
1079 bn
= dns_label_unescape(&p
, b
, sizeof(b
));
1086 /* If there was a second label, try to get the third one */
1088 cn
= dns_label_unescape(&p
, c
, sizeof(c
));
1099 if (x
>= 2 && srv_type_label_is_valid(b
, bn
)) {
1101 if (x
>= 3 && srv_type_label_is_valid(c
, cn
)) {
1103 if (dns_service_name_label_is_valid(a
, an
)) {
1105 /* OK, got <name> . <type> . <type2> . <domain> */
1107 name
= strndup(a
, an
);
1111 type
= new(char, bn
+1+cn
+1);
1114 strcpy(stpcpy(stpcpy(type
, b
), "."), c
);
1120 } else if (srv_type_label_is_valid(a
, an
)) {
1122 /* OK, got <type> . <type2> . <domain> */
1126 type
= new(char, an
+1+bn
+1);
1129 strcpy(stpcpy(stpcpy(type
, a
), "."), b
);
1141 r
= dns_name_normalize(d
, &domain
);
1163 int dns_name_suffix(const char *name
, unsigned n_labels
, const char **ret
) {
1164 const char* labels
[DNS_N_LABELS_MAX
+1];
1174 if (n
> DNS_N_LABELS_MAX
)
1179 r
= dns_name_parent(&p
);
1191 *ret
= labels
[n
- n_labels
];
1192 return (int) (n
- n_labels
);
1195 int dns_name_count_labels(const char *name
) {
1204 r
= dns_name_parent(&p
);
1210 if (n
>= DNS_N_LABELS_MAX
)
1219 int dns_name_equal_skip(const char *a
, unsigned n_labels
, const char *b
) {
1225 while (n_labels
> 0) {
1227 r
= dns_name_parent(&a
);
1234 return dns_name_equal(a
, b
);