1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2014 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
25 # include <stringprep.h>
29 #include <netinet/in.h>
32 #include <sys/socket.h>
34 #include "alloc-util.h"
35 #include "dns-domain.h"
37 #include "hexdecoct.h"
38 #include "in-addr-util.h"
40 #include "parse-util.h"
41 #include "string-util.h"
45 int dns_label_unescape(const char **name
, char *dest
, size_t sz
) {
65 if (r
>= DNS_LABEL_MAX
)
72 /* Escaped character */
80 else if (IN_SET(*n
, '\\', '.')) {
81 /* Escaped backslash or dot */
89 } else if (n
[0] >= '0' && n
[0] <= '9') {
92 /* Escaped literal ASCII character */
94 if (!(n
[1] >= '0' && n
[1] <= '9') ||
95 !(n
[2] >= '0' && n
[2] <= '9'))
98 k
= ((unsigned) (n
[0] - '0') * 100) +
99 ((unsigned) (n
[1] - '0') * 10) +
100 ((unsigned) (n
[2] - '0'));
102 /* Don't allow anything that doesn't
103 * fit in 8bit. Note that we do allow
104 * control characters, as some servers
105 * (e.g. cloudflare) are happy to
106 * generate labels with them
120 } else if ((uint8_t) *n
>= (uint8_t) ' ' && *n
!= 127) {
122 /* Normal character */
133 /* Empty label that is not at the end? */
137 /* More than one trailing dot? */
148 /* @label_terminal: terminal character of a label, updated to point to the terminal character of
149 * the previous label (always skipping one dot) or to NULL if there are no more
151 int dns_label_unescape_suffix(const char *name
, const char **label_terminal
, char *dest
, size_t sz
) {
152 const char *terminal
;
156 assert(label_terminal
);
160 if (!*label_terminal
) {
167 terminal
= *label_terminal
;
168 assert(IN_SET(*terminal
, 0, '.'));
170 /* Skip current terminal character (and accept domain names ending it ".") */
173 if (terminal
>= name
&& *terminal
== '.')
176 /* Point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
178 if (terminal
< name
) {
179 /* Reached the first label, so indicate that there are no more */
184 /* Find the start of the last label */
185 if (*terminal
== '.') {
187 unsigned slashes
= 0;
189 for (y
= terminal
- 1; y
>= name
&& *y
== '\\'; y
--)
192 if (slashes
% 2 == 0) {
193 /* The '.' was not escaped */
205 r
= dns_label_unescape(&name
, dest
, sz
);
209 *label_terminal
= terminal
;
214 int dns_label_escape(const char *p
, size_t l
, char *dest
, size_t sz
) {
217 /* DNS labels must be between 1 and 63 characters long. A
218 * zero-length label does not exist. See RFC 2182, Section
221 if (l
<= 0 || l
> DNS_LABEL_MAX
)
232 if (IN_SET(*p
, '.', '\\')) {
234 /* Dot or backslash */
244 } else if (IN_SET(*p
, '_', '-') ||
245 (*p
>= '0' && *p
<= '9') ||
246 (*p
>= 'a' && *p
<= 'z') ||
247 (*p
>= 'A' && *p
<= 'Z')) {
249 /* Proper character */
259 /* Everything else */
265 *(q
++) = '0' + (char) ((uint8_t) *p
/ 100);
266 *(q
++) = '0' + (char) (((uint8_t) *p
/ 10) % 10);
267 *(q
++) = '0' + (char) ((uint8_t) *p
% 10);
277 return (int) (q
- dest
);
280 int dns_label_escape_new(const char *p
, size_t l
, char **ret
) {
281 _cleanup_free_
char *s
= NULL
;
287 if (l
<= 0 || l
> DNS_LABEL_MAX
)
290 s
= new(char, DNS_LABEL_ESCAPED_MAX
);
294 r
= dns_label_escape(p
, l
, s
, DNS_LABEL_ESCAPED_MAX
);
305 int dns_label_apply_idna(const char *encoded
, size_t encoded_size
, char *decoded
, size_t decoded_max
) {
306 _cleanup_free_
uint32_t *input
= NULL
;
307 size_t input_size
, l
;
309 bool contains_8bit
= false;
310 char buffer
[DNS_LABEL_MAX
+1];
315 /* Converts an U-label into an A-label */
317 if (encoded_size
<= 0)
320 for (p
= encoded
; p
< encoded
+ encoded_size
; p
++)
321 if ((uint8_t) *p
> 127)
322 contains_8bit
= true;
324 if (!contains_8bit
) {
325 if (encoded_size
> DNS_LABEL_MAX
)
331 input
= stringprep_utf8_to_ucs4(encoded
, encoded_size
, &input_size
);
335 if (idna_to_ascii_4i(input
, input_size
, buffer
, 0) != 0)
340 /* Verify that the result is not longer than one DNS label. */
341 if (l
<= 0 || l
> DNS_LABEL_MAX
)
346 memcpy(decoded
, buffer
, l
);
348 /* 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
) {
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. */
403 int dns_name_concat(const char *a
, const char *b
, char **_ret
) {
404 _cleanup_free_
char *ret
= NULL
;
405 size_t n
= 0, allocated
= 0;
419 char label
[DNS_LABEL_MAX
];
421 r
= dns_label_unescape(&p
, label
, sizeof(label
));
429 /* Now continue with the second string, if there is one */
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
));
465 if (n
> DNS_HOSTNAME_MAX
)
470 /* Nothing appended? If so, generate at least a single dot, to indicate the DNS root domain */
471 if (!GREEDY_REALLOC(ret
, allocated
, 2))
476 if (!GREEDY_REALLOC(ret
, allocated
, n
+ 1))
488 void dns_name_hash_func(const void *s
, struct siphash
*state
) {
495 char label
[DNS_LABEL_MAX
+1];
497 r
= dns_label_unescape(&p
, label
, sizeof(label
));
503 ascii_strlower_n(label
, r
);
504 siphash24_compress(label
, r
, state
);
505 siphash24_compress_byte(0, state
); /* make sure foobar and foo.bar result in different hashes */
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
], lb
[DNS_LABEL_MAX
];
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 r
= ascii_strcasecmp_nn(la
, r
, lb
, q
);
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
], lb
[DNS_LABEL_MAX
];
553 r
= dns_label_unescape(&x
, la
, sizeof(la
));
557 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
566 if (ascii_strcasecmp_n(la
, lb
, r
) != 0)
571 int dns_name_endswith(const char *name
, const char *suffix
) {
572 const char *n
, *s
, *saved_n
= NULL
;
582 char ln
[DNS_LABEL_MAX
], ls
[DNS_LABEL_MAX
];
584 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
591 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
595 if (r
== 0 && q
== 0)
597 if (r
== 0 && saved_n
== n
)
600 if (r
!= q
|| ascii_strcasecmp_n(ln
, ls
, r
) != 0) {
602 /* Not the same, let's jump back, and try with the next label again */
610 int dns_name_startswith(const char *name
, const char *prefix
) {
621 char ln
[DNS_LABEL_MAX
], lp
[DNS_LABEL_MAX
];
623 r
= dns_label_unescape(&p
, lp
, sizeof(lp
));
629 q
= dns_label_unescape(&n
, ln
, sizeof(ln
));
635 if (ascii_strcasecmp_n(ln
, lp
, r
) != 0)
640 int dns_name_change_suffix(const char *name
, const char *old_suffix
, const char *new_suffix
, char **ret
) {
641 const char *n
, *s
, *saved_before
= NULL
, *saved_after
= NULL
, *prefix
;
653 char ln
[DNS_LABEL_MAX
], ls
[DNS_LABEL_MAX
];
658 r
= dns_label_unescape(&n
, ln
, sizeof(ln
));
665 q
= dns_label_unescape(&s
, ls
, sizeof(ls
));
669 if (r
== 0 && q
== 0)
671 if (r
== 0 && saved_after
== n
) {
672 *ret
= NULL
; /* doesn't match */
676 if (r
!= q
|| ascii_strcasecmp_n(ln
, ls
, r
) != 0) {
678 /* Not the same, let's jump back, and try with the next label again */
681 saved_after
= saved_before
= NULL
;
685 /* Found it! Now generate the new name */
686 prefix
= strndupa(name
, saved_before
- name
);
688 r
= dns_name_concat(prefix
, new_suffix
, ret
);
695 int dns_name_between(const char *a
, const char *b
, const char *c
) {
696 /* Determine if b is strictly greater than a and strictly smaller than c.
697 We consider the order of names to be circular, so that if a is
698 strictly greater than c, we consider b to be between them if it is
699 either greater than a or smaller than c. This is how the canonical
700 DNS name order used in NSEC records work. */
702 if (dns_name_compare_func(a
, c
) < 0)
704 a and c are properly ordered:
707 return dns_name_compare_func(a
, b
) < 0 &&
708 dns_name_compare_func(b
, c
) < 0;
711 a and c are equal or 'reversed':
716 return dns_name_compare_func(b
, c
) < 0 ||
717 dns_name_compare_func(a
, b
) < 0;
720 int dns_name_reverse(int family
, const union in_addr_union
*a
, char **ret
) {
727 p
= (const uint8_t*) a
;
729 if (family
== AF_INET
)
730 r
= asprintf(ret
, "%u.%u.%u.%u.in-addr.arpa", p
[3], p
[2], p
[1], p
[0]);
731 else if (family
== AF_INET6
)
732 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",
733 hexchar(p
[15] & 0xF), hexchar(p
[15] >> 4), hexchar(p
[14] & 0xF), hexchar(p
[14] >> 4),
734 hexchar(p
[13] & 0xF), hexchar(p
[13] >> 4), hexchar(p
[12] & 0xF), hexchar(p
[12] >> 4),
735 hexchar(p
[11] & 0xF), hexchar(p
[11] >> 4), hexchar(p
[10] & 0xF), hexchar(p
[10] >> 4),
736 hexchar(p
[ 9] & 0xF), hexchar(p
[ 9] >> 4), hexchar(p
[ 8] & 0xF), hexchar(p
[ 8] >> 4),
737 hexchar(p
[ 7] & 0xF), hexchar(p
[ 7] >> 4), hexchar(p
[ 6] & 0xF), hexchar(p
[ 6] >> 4),
738 hexchar(p
[ 5] & 0xF), hexchar(p
[ 5] >> 4), hexchar(p
[ 4] & 0xF), hexchar(p
[ 4] >> 4),
739 hexchar(p
[ 3] & 0xF), hexchar(p
[ 3] >> 4), hexchar(p
[ 2] & 0xF), hexchar(p
[ 2] >> 4),
740 hexchar(p
[ 1] & 0xF), hexchar(p
[ 1] >> 4), hexchar(p
[ 0] & 0xF), hexchar(p
[ 0] >> 4));
742 return -EAFNOSUPPORT
;
749 int dns_name_address(const char *p
, int *family
, union in_addr_union
*address
) {
756 r
= dns_name_endswith(p
, "in-addr.arpa");
763 for (i
= 0; i
< ELEMENTSOF(a
); i
++) {
764 char label
[DNS_LABEL_MAX
+1];
766 r
= dns_label_unescape(&p
, label
, sizeof(label
));
774 r
= safe_atou8(label
, &a
[i
]);
779 r
= dns_name_equal(p
, "in-addr.arpa");
784 address
->in
.s_addr
= htobe32(((uint32_t) a
[3] << 24) |
785 ((uint32_t) a
[2] << 16) |
786 ((uint32_t) a
[1] << 8) |
792 r
= dns_name_endswith(p
, "ip6.arpa");
799 for (i
= 0; i
< ELEMENTSOF(a
.s6_addr
); i
++) {
800 char label
[DNS_LABEL_MAX
+1];
803 r
= dns_label_unescape(&p
, label
, sizeof(label
));
808 x
= unhexchar(label
[0]);
812 r
= dns_label_unescape(&p
, label
, sizeof(label
));
817 y
= unhexchar(label
[0]);
821 a
.s6_addr
[ELEMENTSOF(a
.s6_addr
) - i
- 1] = (uint8_t) y
<< 4 | (uint8_t) x
;
824 r
= dns_name_equal(p
, "ip6.arpa");
836 bool dns_name_is_root(const char *name
) {
840 /* There are exactly two ways to encode the root domain name:
841 * as empty string, or with a single dot. */
843 return STR_IN_SET(name
, "", ".");
846 bool dns_name_is_single_label(const char *name
) {
851 r
= dns_name_parent(&name
);
855 return dns_name_is_root(name
);
858 /* Encode a domain name according to RFC 1035 Section 3.1, without compression */
859 int dns_name_to_wire_format(const char *domain
, uint8_t *buffer
, size_t len
, bool canonical
) {
860 uint8_t *label_length
, *out
;
869 /* Reserve a byte for label length */
876 /* Convert and copy a single label. Note that
877 * dns_label_unescape() returns 0 when it hits the end
878 * of the domain name, which we rely on here to encode
879 * the trailing NUL byte. */
880 r
= dns_label_unescape(&domain
, (char *) out
, len
);
884 /* Optionally, output the name in DNSSEC canonical
885 * format, as described in RFC 4034, section 6.2. Or
886 * in other words: in lower-case. */
888 ascii_strlower_n((char*) out
, (size_t) r
);
890 /* Fill label length, move forward */
897 /* Verify the maximum size of the encoded name. The trailing
898 * dot + NUL byte account are included this time, hence
899 * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
901 if (out
- buffer
> DNS_HOSTNAME_MAX
+ 2)
907 static bool srv_type_label_is_valid(const char *label
, size_t n
) {
912 if (n
< 2) /* Label needs to be at least 2 chars long */
915 if (label
[0] != '_') /* First label char needs to be underscore */
918 /* Second char must be a letter */
919 if (!(label
[1] >= 'A' && label
[1] <= 'Z') &&
920 !(label
[1] >= 'a' && label
[1] <= 'z'))
923 /* Third and further chars must be alphanumeric or a hyphen */
924 for (k
= 2; k
< n
; k
++) {
925 if (!(label
[k
] >= 'A' && label
[k
] <= 'Z') &&
926 !(label
[k
] >= 'a' && label
[k
] <= 'z') &&
927 !(label
[k
] >= '0' && label
[k
] <= '9') &&
935 bool dns_srv_type_is_valid(const char *name
) {
943 char label
[DNS_LABEL_MAX
];
945 /* This more or less implements RFC 6335, Section 5.1 */
947 r
= dns_label_unescape(&name
, label
, sizeof(label
));
956 if (!srv_type_label_is_valid(label
, r
))
962 return c
== 2; /* exactly two labels */
965 bool dnssd_srv_type_is_valid(const char *name
) {
966 return dns_srv_type_is_valid(name
) &&
967 ((dns_name_endswith(name
, "_tcp") > 0) ||
968 (dns_name_endswith(name
, "_udp") > 0)); /* Specific to DNS-SD. RFC 6763, Section 7 */
971 bool dns_service_name_is_valid(const char *name
) {
974 /* This more or less implements RFC 6763, Section 4.1.1 */
979 if (!utf8_is_valid(name
))
982 if (string_has_cc(name
, NULL
))
994 int dns_service_join(const char *name
, const char *type
, const char *domain
, char **ret
) {
995 char escaped
[DNS_LABEL_ESCAPED_MAX
];
996 _cleanup_free_
char *n
= NULL
;
1003 if (!dns_srv_type_is_valid(type
))
1007 return dns_name_concat(type
, domain
, ret
);
1009 if (!dns_service_name_is_valid(name
))
1012 r
= dns_label_escape(name
, strlen(name
), escaped
, sizeof(escaped
));
1016 r
= dns_name_concat(type
, domain
, &n
);
1020 return dns_name_concat(escaped
, n
, ret
);
1023 static bool dns_service_name_label_is_valid(const char *label
, size_t n
) {
1028 if (memchr(label
, 0, n
))
1031 s
= strndupa(label
, n
);
1032 return dns_service_name_is_valid(s
);
1035 int dns_service_split(const char *joined
, char **_name
, char **_type
, char **_domain
) {
1036 _cleanup_free_
char *name
= NULL
, *type
= NULL
, *domain
= NULL
;
1037 const char *p
= joined
, *q
= NULL
, *d
= NULL
;
1038 char a
[DNS_LABEL_MAX
], b
[DNS_LABEL_MAX
], c
[DNS_LABEL_MAX
];
1044 /* Get first label from the full name */
1045 an
= dns_label_unescape(&p
, a
, sizeof(a
));
1052 /* If there was a first label, try to get the second one */
1053 bn
= dns_label_unescape(&p
, b
, sizeof(b
));
1060 /* If there was a second label, try to get the third one */
1062 cn
= dns_label_unescape(&p
, c
, sizeof(c
));
1073 if (x
>= 2 && srv_type_label_is_valid(b
, bn
)) {
1075 if (x
>= 3 && srv_type_label_is_valid(c
, cn
)) {
1077 if (dns_service_name_label_is_valid(a
, an
)) {
1078 /* OK, got <name> . <type> . <type2> . <domain> */
1080 name
= strndup(a
, an
);
1084 type
= strjoin(b
, ".", c
);
1092 } else if (srv_type_label_is_valid(a
, an
)) {
1094 /* OK, got <type> . <type2> . <domain> */
1098 type
= strjoin(a
, ".", b
);
1112 r
= dns_name_normalize(d
, &domain
);
1134 static int dns_name_build_suffix_table(const char *name
, const char*table
[]) {
1144 if (n
> DNS_N_LABELS_MAX
)
1148 r
= dns_name_parent(&p
);
1160 int dns_name_suffix(const char *name
, unsigned n_labels
, const char **ret
) {
1161 const char* labels
[DNS_N_LABELS_MAX
+1];
1167 n
= dns_name_build_suffix_table(name
, labels
);
1171 if ((unsigned) n
< n_labels
)
1174 *ret
= labels
[n
- n_labels
];
1175 return (int) (n
- n_labels
);
1178 int dns_name_skip(const char *a
, unsigned n_labels
, const char **ret
) {
1184 for (; n_labels
> 0; n_labels
--) {
1185 r
= dns_name_parent(&a
);
1198 int dns_name_count_labels(const char *name
) {
1207 r
= dns_name_parent(&p
);
1213 if (n
>= DNS_N_LABELS_MAX
)
1222 int dns_name_equal_skip(const char *a
, unsigned n_labels
, const char *b
) {
1228 r
= dns_name_skip(a
, n_labels
, &a
);
1232 return dns_name_equal(a
, b
);
1235 int dns_name_common_suffix(const char *a
, const char *b
, const char **ret
) {
1236 const char *a_labels
[DNS_N_LABELS_MAX
+1], *b_labels
[DNS_N_LABELS_MAX
+1];
1237 int n
= 0, m
= 0, k
= 0, r
, q
;
1243 /* Determines the common suffix of domain names a and b */
1245 n
= dns_name_build_suffix_table(a
, a_labels
);
1249 m
= dns_name_build_suffix_table(b
, b_labels
);
1254 char la
[DNS_LABEL_MAX
], lb
[DNS_LABEL_MAX
];
1257 if (k
>= n
|| k
>= m
) {
1258 *ret
= a_labels
[n
- k
];
1262 x
= a_labels
[n
- 1 - k
];
1263 r
= dns_label_unescape(&x
, la
, sizeof(la
));
1267 y
= b_labels
[m
- 1 - k
];
1268 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
1272 if (r
!= q
|| ascii_strcasecmp_n(la
, lb
, r
) != 0) {
1273 *ret
= a_labels
[n
- k
];
1281 int dns_name_apply_idna(const char *name
, char **ret
) {
1282 /* Return negative on error, 0 if not implemented, positive on success. */
1286 _cleanup_free_
char *t
= NULL
;
1291 r
= idn2_lookup_u8((uint8_t*) name
, (uint8_t**) &t
,
1292 IDN2_NFC_INPUT
| IDN2_NONTRANSITIONAL
);
1293 log_debug("idn2_lookup_u8: %s → %s", name
, t
);
1295 if (!startswith(name
, "xn--")) {
1296 _cleanup_free_
char *s
= NULL
;
1298 r
= idn2_to_unicode_8z8z(t
, &s
, 0);
1300 log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
1301 t
, r
, idn2_strerror(r
));
1305 if (!streq_ptr(name
, s
)) {
1306 log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.",
1314 return 1; /* *ret has been written */
1317 log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name
, r
, idn2_strerror(r
));
1318 if (r
== IDN2_2HYPHEN
)
1319 /* The name has two hypens — forbidden by IDNA2008 in some cases */
1321 if (IN_SET(r
, IDN2_TOO_BIG_DOMAIN
, IDN2_TOO_BIG_LABEL
))
1325 _cleanup_free_
char *buf
= NULL
;
1326 size_t n
= 0, allocated
= 0;
1334 char label
[DNS_LABEL_MAX
];
1336 r
= dns_label_unescape(&name
, label
, sizeof(label
));
1342 q
= dns_label_apply_idna(label
, r
, label
, sizeof(label
));
1348 if (!GREEDY_REALLOC(buf
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
))
1351 r
= dns_label_escape(label
, r
, buf
+ n
+ !first
, DNS_LABEL_ESCAPED_MAX
);
1363 if (n
> DNS_HOSTNAME_MAX
)
1366 if (!GREEDY_REALLOC(buf
, allocated
, n
+ 1))
1379 int dns_name_is_valid_or_address(const char *name
) {
1380 /* Returns > 0 if the specified name is either a valid IP address formatted as string or a valid DNS name */
1385 if (in_addr_from_string_auto(name
, NULL
, NULL
) >= 0)
1388 return dns_name_is_valid(name
);