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
) {
698 /* Determine if b is strictly greater than a and strictly smaller than c.
699 We consider the order of names to be circular, so that if a is
700 strictly greater than c, we consider b to be between them if it is
701 either greater than a or smaller than c. This is how the canonical
702 DNS name order used in NSEC records work. */
704 n
= dns_name_compare_func(a
, c
);
709 return dns_name_compare_func(a
, b
) < 0 &&
710 dns_name_compare_func(b
, c
) < 0;
712 /* <--b--c a--b--> */
713 return dns_name_compare_func(b
, c
) < 0 ||
714 dns_name_compare_func(a
, b
) < 0;
717 int dns_name_reverse(int family
, const union in_addr_union
*a
, char **ret
) {
724 p
= (const uint8_t*) a
;
726 if (family
== AF_INET
)
727 r
= asprintf(ret
, "%u.%u.%u.%u.in-addr.arpa", p
[3], p
[2], p
[1], p
[0]);
728 else if (family
== AF_INET6
)
729 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",
730 hexchar(p
[15] & 0xF), hexchar(p
[15] >> 4), hexchar(p
[14] & 0xF), hexchar(p
[14] >> 4),
731 hexchar(p
[13] & 0xF), hexchar(p
[13] >> 4), hexchar(p
[12] & 0xF), hexchar(p
[12] >> 4),
732 hexchar(p
[11] & 0xF), hexchar(p
[11] >> 4), hexchar(p
[10] & 0xF), hexchar(p
[10] >> 4),
733 hexchar(p
[ 9] & 0xF), hexchar(p
[ 9] >> 4), hexchar(p
[ 8] & 0xF), hexchar(p
[ 8] >> 4),
734 hexchar(p
[ 7] & 0xF), hexchar(p
[ 7] >> 4), hexchar(p
[ 6] & 0xF), hexchar(p
[ 6] >> 4),
735 hexchar(p
[ 5] & 0xF), hexchar(p
[ 5] >> 4), hexchar(p
[ 4] & 0xF), hexchar(p
[ 4] >> 4),
736 hexchar(p
[ 3] & 0xF), hexchar(p
[ 3] >> 4), hexchar(p
[ 2] & 0xF), hexchar(p
[ 2] >> 4),
737 hexchar(p
[ 1] & 0xF), hexchar(p
[ 1] >> 4), hexchar(p
[ 0] & 0xF), hexchar(p
[ 0] >> 4));
739 return -EAFNOSUPPORT
;
746 int dns_name_address(const char *p
, int *family
, union in_addr_union
*address
) {
753 r
= dns_name_endswith(p
, "in-addr.arpa");
760 for (i
= 0; i
< ELEMENTSOF(a
); i
++) {
761 char label
[DNS_LABEL_MAX
+1];
763 r
= dns_label_unescape(&p
, label
, sizeof(label
));
771 r
= safe_atou8(label
, &a
[i
]);
776 r
= dns_name_equal(p
, "in-addr.arpa");
781 address
->in
.s_addr
= htobe32(((uint32_t) a
[3] << 24) |
782 ((uint32_t) a
[2] << 16) |
783 ((uint32_t) a
[1] << 8) |
789 r
= dns_name_endswith(p
, "ip6.arpa");
796 for (i
= 0; i
< ELEMENTSOF(a
.s6_addr
); i
++) {
797 char label
[DNS_LABEL_MAX
+1];
800 r
= dns_label_unescape(&p
, label
, sizeof(label
));
805 x
= unhexchar(label
[0]);
809 r
= dns_label_unescape(&p
, label
, sizeof(label
));
814 y
= unhexchar(label
[0]);
818 a
.s6_addr
[ELEMENTSOF(a
.s6_addr
) - i
- 1] = (uint8_t) y
<< 4 | (uint8_t) x
;
821 r
= dns_name_equal(p
, "ip6.arpa");
833 bool dns_name_is_root(const char *name
) {
837 /* There are exactly two ways to encode the root domain name:
838 * as empty string, or with a single dot. */
840 return STR_IN_SET(name
, "", ".");
843 bool dns_name_is_single_label(const char *name
) {
848 r
= dns_name_parent(&name
);
852 return dns_name_is_root(name
);
855 /* Encode a domain name according to RFC 1035 Section 3.1, without compression */
856 int dns_name_to_wire_format(const char *domain
, uint8_t *buffer
, size_t len
, bool canonical
) {
857 uint8_t *label_length
, *out
;
866 /* Reserve a byte for label length */
873 /* Convert and copy a single label. Note that
874 * dns_label_unescape() returns 0 when it hits the end
875 * of the domain name, which we rely on here to encode
876 * the trailing NUL byte. */
877 r
= dns_label_unescape(&domain
, (char *) out
, len
);
881 /* Optionally, output the name in DNSSEC canonical
882 * format, as described in RFC 4034, section 6.2. Or
883 * in other words: in lower-case. */
885 ascii_strlower_n((char*) out
, (size_t) r
);
887 /* Fill label length, move forward */
894 /* Verify the maximum size of the encoded name. The trailing
895 * dot + NUL byte account are included this time, hence
896 * compare against DNS_HOSTNAME_MAX + 2 (which is 255) this
898 if (out
- buffer
> DNS_HOSTNAME_MAX
+ 2)
904 static bool srv_type_label_is_valid(const char *label
, size_t n
) {
909 if (n
< 2) /* Label needs to be at least 2 chars long */
912 if (label
[0] != '_') /* First label char needs to be underscore */
915 /* Second char must be a letter */
916 if (!(label
[1] >= 'A' && label
[1] <= 'Z') &&
917 !(label
[1] >= 'a' && label
[1] <= 'z'))
920 /* Third and further chars must be alphanumeric or a hyphen */
921 for (k
= 2; k
< n
; k
++) {
922 if (!(label
[k
] >= 'A' && label
[k
] <= 'Z') &&
923 !(label
[k
] >= 'a' && label
[k
] <= 'z') &&
924 !(label
[k
] >= '0' && label
[k
] <= '9') &&
932 bool dns_srv_type_is_valid(const char *name
) {
940 char label
[DNS_LABEL_MAX
];
942 /* This more or less implements RFC 6335, Section 5.1 */
944 r
= dns_label_unescape(&name
, label
, sizeof(label
));
953 if (!srv_type_label_is_valid(label
, r
))
959 return c
== 2; /* exactly two labels */
962 bool dns_service_name_is_valid(const char *name
) {
965 /* This more or less implements RFC 6763, Section 4.1.1 */
970 if (!utf8_is_valid(name
))
973 if (string_has_cc(name
, NULL
))
985 int dns_service_join(const char *name
, const char *type
, const char *domain
, char **ret
) {
986 char escaped
[DNS_LABEL_ESCAPED_MAX
];
987 _cleanup_free_
char *n
= NULL
;
994 if (!dns_srv_type_is_valid(type
))
998 return dns_name_concat(type
, domain
, ret
);
1000 if (!dns_service_name_is_valid(name
))
1003 r
= dns_label_escape(name
, strlen(name
), escaped
, sizeof(escaped
));
1007 r
= dns_name_concat(type
, domain
, &n
);
1011 return dns_name_concat(escaped
, n
, ret
);
1014 static bool dns_service_name_label_is_valid(const char *label
, size_t n
) {
1019 if (memchr(label
, 0, n
))
1022 s
= strndupa(label
, n
);
1023 return dns_service_name_is_valid(s
);
1026 int dns_service_split(const char *joined
, char **_name
, char **_type
, char **_domain
) {
1027 _cleanup_free_
char *name
= NULL
, *type
= NULL
, *domain
= NULL
;
1028 const char *p
= joined
, *q
= NULL
, *d
= NULL
;
1029 char a
[DNS_LABEL_MAX
], b
[DNS_LABEL_MAX
], c
[DNS_LABEL_MAX
];
1035 /* Get first label from the full name */
1036 an
= dns_label_unescape(&p
, a
, sizeof(a
));
1043 /* If there was a first label, try to get the second one */
1044 bn
= dns_label_unescape(&p
, b
, sizeof(b
));
1051 /* If there was a second label, try to get the third one */
1053 cn
= dns_label_unescape(&p
, c
, sizeof(c
));
1064 if (x
>= 2 && srv_type_label_is_valid(b
, bn
)) {
1066 if (x
>= 3 && srv_type_label_is_valid(c
, cn
)) {
1068 if (dns_service_name_label_is_valid(a
, an
)) {
1069 /* OK, got <name> . <type> . <type2> . <domain> */
1071 name
= strndup(a
, an
);
1075 type
= strjoin(b
, ".", c
);
1083 } else if (srv_type_label_is_valid(a
, an
)) {
1085 /* OK, got <type> . <type2> . <domain> */
1089 type
= strjoin(a
, ".", b
);
1103 r
= dns_name_normalize(d
, &domain
);
1125 static int dns_name_build_suffix_table(const char *name
, const char*table
[]) {
1135 if (n
> DNS_N_LABELS_MAX
)
1139 r
= dns_name_parent(&p
);
1151 int dns_name_suffix(const char *name
, unsigned n_labels
, const char **ret
) {
1152 const char* labels
[DNS_N_LABELS_MAX
+1];
1158 n
= dns_name_build_suffix_table(name
, labels
);
1162 if ((unsigned) n
< n_labels
)
1165 *ret
= labels
[n
- n_labels
];
1166 return (int) (n
- n_labels
);
1169 int dns_name_skip(const char *a
, unsigned n_labels
, const char **ret
) {
1175 for (; n_labels
> 0; n_labels
--) {
1176 r
= dns_name_parent(&a
);
1189 int dns_name_count_labels(const char *name
) {
1198 r
= dns_name_parent(&p
);
1204 if (n
>= DNS_N_LABELS_MAX
)
1213 int dns_name_equal_skip(const char *a
, unsigned n_labels
, const char *b
) {
1219 r
= dns_name_skip(a
, n_labels
, &a
);
1223 return dns_name_equal(a
, b
);
1226 int dns_name_common_suffix(const char *a
, const char *b
, const char **ret
) {
1227 const char *a_labels
[DNS_N_LABELS_MAX
+1], *b_labels
[DNS_N_LABELS_MAX
+1];
1228 int n
= 0, m
= 0, k
= 0, r
, q
;
1234 /* Determines the common suffix of domain names a and b */
1236 n
= dns_name_build_suffix_table(a
, a_labels
);
1240 m
= dns_name_build_suffix_table(b
, b_labels
);
1245 char la
[DNS_LABEL_MAX
], lb
[DNS_LABEL_MAX
];
1248 if (k
>= n
|| k
>= m
) {
1249 *ret
= a_labels
[n
- k
];
1253 x
= a_labels
[n
- 1 - k
];
1254 r
= dns_label_unescape(&x
, la
, sizeof(la
));
1258 y
= b_labels
[m
- 1 - k
];
1259 q
= dns_label_unescape(&y
, lb
, sizeof(lb
));
1263 if (r
!= q
|| ascii_strcasecmp_n(la
, lb
, r
) != 0) {
1264 *ret
= a_labels
[n
- k
];
1272 int dns_name_apply_idna(const char *name
, char **ret
) {
1273 /* Return negative on error, 0 if not implemented, positive on success. */
1277 _cleanup_free_
char *t
= NULL
;
1282 r
= idn2_lookup_u8((uint8_t*) name
, (uint8_t**) &t
,
1283 IDN2_NFC_INPUT
| IDN2_NONTRANSITIONAL
);
1284 log_debug("idn2_lookup_u8: %s → %s", name
, t
);
1286 if (!startswith(name
, "xn--")) {
1287 _cleanup_free_
char *s
= NULL
;
1289 r
= idn2_to_unicode_8z8z(t
, &s
, 0);
1291 log_debug("idn2_to_unicode_8z8z(\"%s\") failed: %d/%s",
1292 t
, r
, idn2_strerror(r
));
1296 if (!streq_ptr(name
, s
)) {
1297 log_debug("idn2 roundtrip failed: \"%s\" → \"%s\" → \"%s\", ignoring.",
1305 return 1; /* *ret has been written */
1308 log_debug("idn2_lookup_u8(\"%s\") failed: %d/%s", name
, r
, idn2_strerror(r
));
1309 if (r
== IDN2_2HYPHEN
)
1310 /* The name has two hypens — forbidden by IDNA2008 in some cases */
1312 if (IN_SET(r
, IDN2_TOO_BIG_DOMAIN
, IDN2_TOO_BIG_LABEL
))
1316 _cleanup_free_
char *buf
= NULL
;
1317 size_t n
= 0, allocated
= 0;
1325 char label
[DNS_LABEL_MAX
];
1327 r
= dns_label_unescape(&name
, label
, sizeof(label
));
1333 q
= dns_label_apply_idna(label
, r
, label
, sizeof(label
));
1339 if (!GREEDY_REALLOC(buf
, allocated
, n
+ !first
+ DNS_LABEL_ESCAPED_MAX
))
1342 r
= dns_label_escape(label
, r
, buf
+ n
+ !first
, DNS_LABEL_ESCAPED_MAX
);
1354 if (n
> DNS_HOSTNAME_MAX
)
1357 if (!GREEDY_REALLOC(buf
, allocated
, n
+ 1))
1370 int dns_name_is_valid_or_address(const char *name
) {
1371 /* Returns > 0 if the specified name is either a valid IP address formatted as string or a valid DNS name */
1376 if (in_addr_from_string_auto(name
, NULL
, NULL
) >= 0)
1379 return dns_name_is_valid(name
);