From 97f1b2f35478fe8aee5d18dac1a1aa2bb16e6fec Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Tue, 24 Nov 2015 16:45:12 +0100 Subject: dns-domain: remove prototype for function that doesn't exist --- src/shared/dns-domain.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'src/shared') diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index a68df330e6..e7e471e8a6 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -78,5 +78,3 @@ bool dns_service_name_is_valid(const char *name); int dns_service_join(const char *name, const char *type, const char *domain, char **ret); int dns_service_split(const char *joined, char **name, char **type, char **domain); - -int dns_name_replace_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret); -- cgit v1.2.3-54-g00ecf From dc477e7385e8ab29efb8fadb72ec994077a105c6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 25 Nov 2015 21:07:17 +0100 Subject: dns-domain: simplify dns_name_is_root() and dns_name_is_single_label() Let's change the return value to bool. If we encounter an error while parsing, return "false" instead of the actual parsing error, after all the specified hostname does not qualify for what the function is supposed to test. Dealing with the additional error codes was always cumbersome, and easily misused, like for example in the DHCP code. Let's also rename the functions from dns_name_root() to dns_name_is_root(), to indicate that this function checks something and returns a bool. Similar for dns_name_is_signal_label(). --- src/libsystemd-network/sd-dhcp-client.c | 4 ++-- src/resolve/resolved-dns-rr.c | 5 +---- src/resolve/resolved-dns-scope.c | 19 ++++++++----------- src/resolve/resolved-dns-scope.h | 2 +- src/resolve/resolved-dns-search-domain.c | 5 +---- src/shared/dns-domain.c | 26 +++++++++----------------- src/shared/dns-domain.h | 4 ++-- src/test/test-dns-domain.c | 30 +++++++++++++++--------------- 8 files changed, 39 insertions(+), 56 deletions(-) (limited to 'src/shared') diff --git a/src/libsystemd-network/sd-dhcp-client.c b/src/libsystemd-network/sd-dhcp-client.c index 5ec0e661f7..f689c59a1a 100644 --- a/src/libsystemd-network/sd-dhcp-client.c +++ b/src/libsystemd-network/sd-dhcp-client.c @@ -604,7 +604,7 @@ static int client_send_discover(sd_dhcp_client *client) { their messages MUST NOT also send the Host Name option". Just send one of the two depending on the hostname type. */ - if (dns_name_single_label(client->hostname)) { + if (dns_name_is_single_label(client->hostname)) { /* it is unclear from RFC 2131 if client should send hostname in DHCPDISCOVER but dhclient does and so we do as well */ @@ -719,7 +719,7 @@ static int client_send_request(sd_dhcp_client *client) { } if (client->hostname) { - if (dns_name_single_label(client->hostname)) + if (dns_name_is_single_label(client->hostname)) r = dhcp_option_append(&request->dhcp, optlen, &optoffset, 0, DHCP_OPTION_HOST_NAME, strlen(client->hostname), client->hostname); diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index 4f896b05af..4a1abb0cdc 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -95,10 +95,7 @@ int dns_resource_key_new_append_suffix(DnsResourceKey **ret, DnsResourceKey *key assert(key); assert(name); - r = dns_name_root(name); - if (r < 0) - return r; - if (r > 0) { + if (dns_name_is_root(name)) { *ret = dns_resource_key_ref(key); return 0; } diff --git a/src/resolve/resolved-dns-scope.c b/src/resolve/resolved-dns-scope.c index daeab9b9ee..20db1fbd81 100644 --- a/src/resolve/resolved-dns-scope.c +++ b/src/resolve/resolved-dns-scope.c @@ -342,7 +342,7 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co if ((SD_RESOLVED_FLAGS_MAKE(s->protocol, s->family) & flags) == 0) return DNS_SCOPE_NO; - if (dns_name_root(domain) != 0) + if (dns_name_is_root(domain)) return DNS_SCOPE_NO; /* Never resolve any loopback hostname or IP address via DNS, @@ -362,19 +362,16 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co return DNS_SCOPE_YES; switch (s->protocol) { - case DNS_PROTOCOL_DNS: { - int is_single_label; - is_single_label = dns_name_single_label(domain); + case DNS_PROTOCOL_DNS: - if ((is_single_label == 0 || - (is_single_label > 0 && !(flags & SD_RESOLVED_NO_SEARCH) && dns_scope_has_search_domains(s))) && + if ((!dns_name_is_single_label(domain) || + (!(flags & SD_RESOLVED_NO_SEARCH) && dns_scope_has_search_domains(s))) && dns_name_endswith(domain, "254.169.in-addr.arpa") == 0 && dns_name_endswith(domain, "0.8.e.f.ip6.arpa") == 0) return DNS_SCOPE_MAYBE; return DNS_SCOPE_NO; - } case DNS_PROTOCOL_MDNS: if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) || @@ -389,7 +386,7 @@ DnsScopeMatch dns_scope_good_domain(DnsScope *s, int ifindex, uint64_t flags, co case DNS_PROTOCOL_LLMNR: if ((s->family == AF_INET && dns_name_endswith(domain, "in-addr.arpa") > 0) || (s->family == AF_INET6 && dns_name_endswith(domain, "ip6.arpa") > 0) || - (dns_name_single_label(domain) > 0 && /* only resolve single label names via LLMNR */ + (dns_name_is_single_label(domain) && /* only resolve single label names via LLMNR */ !is_gateway_hostname(domain) && /* don't resolve "gateway" with LLMNR, let nss-myhostname handle this */ manager_is_own_hostname(s->manager, domain) <= 0)) /* never resolve the local hostname via LLMNR */ return DNS_SCOPE_MAYBE; @@ -902,11 +899,11 @@ bool dns_scope_has_search_domains(DnsScope *s) { return false; } -int dns_scope_name_needs_search_domain(DnsScope *s, const char *name) { +bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name) { assert(s); if (s->protocol != DNS_PROTOCOL_DNS) - return 0; + return false; - return dns_name_single_label(name); + return dns_name_is_single_label(name); } diff --git a/src/resolve/resolved-dns-scope.h b/src/resolve/resolved-dns-scope.h index 244bb41314..32e6961757 100644 --- a/src/resolve/resolved-dns-scope.h +++ b/src/resolve/resolved-dns-scope.h @@ -94,4 +94,4 @@ void dns_scope_dump(DnsScope *s, FILE *f); DnsSearchDomain *dns_scope_get_search_domains(DnsScope *s); bool dns_scope_has_search_domains(DnsScope *s); -int dns_scope_name_needs_search_domain(DnsScope *s, const char *name); +bool dns_scope_name_needs_search_domain(DnsScope *s, const char *name); diff --git a/src/resolve/resolved-dns-search-domain.c b/src/resolve/resolved-dns-search-domain.c index d8a0648aab..f9d966abb1 100644 --- a/src/resolve/resolved-dns-search-domain.c +++ b/src/resolve/resolved-dns-search-domain.c @@ -42,10 +42,7 @@ int dns_search_domain_new( if (r < 0) return r; - r = dns_name_root(normalized); - if (r < 0) - return r; - if (r > 0) + if (dns_name_is_root(normalized)) return -EINVAL; if (l) { diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index e6aad39c74..31b5891435 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -29,6 +29,7 @@ #include "hexdecoct.h" #include "parse-util.h" #include "string-util.h" +#include "strv.h" #include "utf8.h" int dns_label_unescape(const char **name, char *dest, size_t sz) { @@ -752,36 +753,27 @@ int dns_name_address(const char *p, int *family, union in_addr_union *address) { return 0; } -int dns_name_root(const char *name) { - char label[DNS_LABEL_MAX+1]; - int r; +bool dns_name_is_root(const char *name) { assert(name); - r = dns_label_unescape(&name, label, sizeof(label)); - if (r < 0) - return r; + /* There are exactly two ways to encode the root domain name: + * as empty string, or with a single dot. */ - return r == 0 && *name == 0; + return STR_IN_SET(name, "", "."); } -int dns_name_single_label(const char *name) { +bool dns_name_is_single_label(const char *name) { char label[DNS_LABEL_MAX+1]; int r; assert(name); r = dns_label_unescape(&name, label, sizeof(label)); - if (r < 0) - return r; - if (r == 0) - return 0; - - r = dns_label_unescape(&name, label, sizeof(label)); - if (r < 0) - return r; + if (r <= 0) + return false; - return r == 0 && *name == 0; + return dns_name_is_root(name); } /* Encode a domain name according to RFC 1035 Section 3.1 */ diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index e7e471e8a6..84be17425b 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -67,8 +67,8 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char int dns_name_reverse(int family, const union in_addr_union *a, char **ret); int dns_name_address(const char *p, int *family, union in_addr_union *a); -int dns_name_root(const char *name); -int dns_name_single_label(const char *name); +bool dns_name_is_root(const char *name); +bool dns_name_is_single_label(const char *name); int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len); diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index b76a31a549..cefe8698c8 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -246,21 +246,21 @@ static void test_dns_name_endswith(void) { test_dns_name_endswith_one("x.y\001.z", "waldo", -EINVAL); } -static void test_dns_name_root(void) { - assert_se(dns_name_root("") == true); - assert_se(dns_name_root(".") == true); - assert_se(dns_name_root("xxx") == false); - assert_se(dns_name_root("xxx.") == false); - assert_se(dns_name_root("..") == -EINVAL); +static void test_dns_name_is_root(void) { + assert_se(dns_name_is_root("")); + assert_se(dns_name_is_root(".")); + assert_se(!dns_name_is_root("xxx")); + assert_se(!dns_name_is_root("xxx.")); + assert_se(!dns_name_is_root("..")); } -static void test_dns_name_single_label(void) { - assert_se(dns_name_single_label("") == false); - assert_se(dns_name_single_label(".") == false); - assert_se(dns_name_single_label("..") == -EINVAL); - assert_se(dns_name_single_label("x") == true); - assert_se(dns_name_single_label("x.") == true); - assert_se(dns_name_single_label("xx.yy") == false); +static void test_dns_name_is_single_label(void) { + assert_se(!dns_name_is_single_label("")); + assert_se(!dns_name_is_single_label(".")); + assert_se(!dns_name_is_single_label("..")); + assert_se(dns_name_is_single_label("x")); + assert_se(dns_name_is_single_label("x.")); + assert_se(!dns_name_is_single_label("xx.yy")); } static void test_dns_name_reverse_one(const char *address, const char *name) { @@ -436,8 +436,8 @@ int main(int argc, char *argv[]) { test_dns_name_equal(); test_dns_name_endswith(); test_dns_name_between(); - test_dns_name_root(); - test_dns_name_single_label(); + test_dns_name_is_root(); + test_dns_name_is_single_label(); test_dns_name_reverse(); test_dns_name_concat(); test_dns_name_is_valid(); -- cgit v1.2.3-54-g00ecf From 7e8131e9c6c150732503899a092206578fdc13de Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 25 Nov 2015 21:15:07 +0100 Subject: dns-domain: change dns_srv_type_is_valid() return value to bool For similar reasons as dns_name_is_root() got changed in the previous commit. --- src/resolve/resolved-bus.c | 9 ++------- src/shared/dns-domain.c | 14 ++++++-------- src/shared/dns-domain.h | 3 +-- src/test/test-dns-domain.c | 44 ++++++++++++++++++++++---------------------- 4 files changed, 31 insertions(+), 39 deletions(-) (limited to 'src/shared') diff --git a/src/resolve/resolved-bus.c b/src/resolve/resolved-bus.c index 8885b83101..1fd8e78f92 100644 --- a/src/resolve/resolved-bus.c +++ b/src/resolve/resolved-bus.c @@ -1041,13 +1041,8 @@ static int bus_method_resolve_service(sd_bus_message *message, void *userdata, s if (isempty(type)) type = NULL; - else { - r = dns_srv_type_verify(type); - if (r < 0) - return r; - if (r == 0) - return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SRV service type '%s'", type); - } + else if (!dns_srv_type_is_valid(type)) + return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid SRV service type '%s'", type); r = dns_name_is_valid(domain); if (r < 0) diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 31b5891435..5a9b091ac4 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -838,12 +838,12 @@ static bool srv_type_label_is_valid(const char *label, size_t n) { return true; } -int dns_srv_type_verify(const char *name) { +bool dns_srv_type_is_valid(const char *name) { unsigned c = 0; int r; if (!name) - return 0; + return false; for (;;) { char label[DNS_LABEL_MAX]; @@ -851,18 +851,16 @@ int dns_srv_type_verify(const char *name) { /* This more or less implements RFC 6335, Section 5.1 */ r = dns_label_unescape(&name, label, sizeof(label)); - if (r == -EINVAL) - return 0; if (r < 0) - return r; + return false; if (r == 0) break; if (c >= 2) - return 0; + return false; if (!srv_type_label_is_valid(label, r)) - return 0; + return false; c++; } @@ -901,7 +899,7 @@ int dns_service_join(const char *name, const char *type, const char *domain, cha assert(domain); assert(ret); - if (!dns_srv_type_verify(type)) + if (!dns_srv_type_is_valid(type)) return -EINVAL; if (!name) diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 84be17425b..2f557d618e 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -72,8 +72,7 @@ bool dns_name_is_single_label(const char *name); int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len); -int dns_srv_type_verify(const char *name); - +bool dns_srv_type_is_valid(const char *name); bool dns_service_name_is_valid(const char *name); int dns_service_join(const char *name, const char *type, const char *domain, char **ret); diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index cefe8698c8..df34b72ab6 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -327,27 +327,27 @@ static void test_dns_service_name_is_valid(void) { assert_se(!dns_service_name_is_valid("this is an overly long string that is certainly longer than 63 characters")); } -static void test_dns_srv_type_verify(void) { - - assert_se(dns_srv_type_verify("_http._tcp") > 0); - assert_se(dns_srv_type_verify("_foo-bar._tcp") > 0); - assert_se(dns_srv_type_verify("_w._udp") > 0); - assert_se(dns_srv_type_verify("_a800._tcp") > 0); - assert_se(dns_srv_type_verify("_a-800._tcp") > 0); - - assert_se(dns_srv_type_verify(NULL) == 0); - assert_se(dns_srv_type_verify("") == 0); - assert_se(dns_srv_type_verify("x") == 0); - assert_se(dns_srv_type_verify("_foo") == 0); - assert_se(dns_srv_type_verify("_tcp") == 0); - assert_se(dns_srv_type_verify("_") == 0); - assert_se(dns_srv_type_verify("_foo.") == 0); - assert_se(dns_srv_type_verify("_föo._tcp") == 0); - assert_se(dns_srv_type_verify("_f\no._tcp") == 0); - assert_se(dns_srv_type_verify("_800._tcp") == 0); - assert_se(dns_srv_type_verify("_-800._tcp") == 0); - assert_se(dns_srv_type_verify("_-foo._tcp") == 0); - assert_se(dns_srv_type_verify("_piep._foo._udp") == 0); +static void test_dns_srv_type_is_valid(void) { + + assert_se(dns_srv_type_is_valid("_http._tcp")); + assert_se(dns_srv_type_is_valid("_foo-bar._tcp")); + assert_se(dns_srv_type_is_valid("_w._udp")); + assert_se(dns_srv_type_is_valid("_a800._tcp")); + assert_se(dns_srv_type_is_valid("_a-800._tcp")); + + assert_se(!dns_srv_type_is_valid(NULL)); + assert_se(!dns_srv_type_is_valid("")); + assert_se(!dns_srv_type_is_valid("x")); + assert_se(!dns_srv_type_is_valid("_foo")); + assert_se(!dns_srv_type_is_valid("_tcp")); + assert_se(!dns_srv_type_is_valid("_")); + assert_se(!dns_srv_type_is_valid("_foo.")); + assert_se(!dns_srv_type_is_valid("_föo._tcp")); + assert_se(!dns_srv_type_is_valid("_f\no._tcp")); + assert_se(!dns_srv_type_is_valid("_800._tcp")); + assert_se(!dns_srv_type_is_valid("_-800._tcp")); + assert_se(!dns_srv_type_is_valid("_-foo._tcp")); + assert_se(!dns_srv_type_is_valid("_piep._foo._udp")); } static void test_dns_service_join_one(const char *a, const char *b, const char *c, int r, const char *d) { @@ -443,7 +443,7 @@ int main(int argc, char *argv[]) { test_dns_name_is_valid(); test_dns_name_to_wire_format(); test_dns_service_name_is_valid(); - test_dns_srv_type_verify(); + test_dns_srv_type_is_valid(); test_dns_service_join(); test_dns_service_split(); test_dns_name_change_suffix(); -- cgit v1.2.3-54-g00ecf From 422baca0f230913158078fddf884e06c8c64a316 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 25 Nov 2015 21:56:48 +0100 Subject: dns-domain: rework dns_label_escape() to not imply memory allocation The new dns_label_escape() call now operates on a buffer passed in, similar to dns_label_unescape(). This should make decoding a bit faster, and nicer. --- src/libsystemd-network/dhcp6-option.c | 18 ++++--- src/resolve/resolved-dns-packet.c | 18 ++++--- src/resolve/resolved-manager.c | 2 +- src/shared/dns-domain.c | 88 +++++++++++++++++++++++++---------- src/shared/dns-domain.h | 5 +- src/test/test-dns-domain.c | 2 +- 6 files changed, 84 insertions(+), 49 deletions(-) (limited to 'src/shared') diff --git a/src/libsystemd-network/dhcp6-option.c b/src/libsystemd-network/dhcp6-option.c index 62023a9e49..850212aea1 100644 --- a/src/libsystemd-network/dhcp6-option.c +++ b/src/libsystemd-network/dhcp6-option.c @@ -360,7 +360,6 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * /* End of name */ break; else if (c <= 63) { - _cleanup_free_ char *t = NULL; const char *label; /* Literal label */ @@ -369,21 +368,20 @@ int dhcp6_option_parse_domainname(const uint8_t *optval, uint16_t optlen, char * if (pos > optlen) return -EMSGSIZE; - r = dns_label_escape(label, c, &t); - if (r < 0) - goto fail; - - if (!GREEDY_REALLOC0(ret, allocated, n + !first + strlen(t) + 1)) { + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) { r = -ENOMEM; goto fail; } - if (!first) - ret[n++] = '.'; - else + if (first) first = false; + else + ret[n++] = '.'; + + r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + goto fail; - memcpy(ret + n, t, r); n += r; continue; } else { diff --git a/src/resolve/resolved-dns-packet.c b/src/resolve/resolved-dns-packet.c index 472486777c..aeff3138d7 100644 --- a/src/resolve/resolved-dns-packet.c +++ b/src/resolve/resolved-dns-packet.c @@ -1145,7 +1145,6 @@ int dns_packet_read_name( /* End of name */ break; else if (c <= 63) { - _cleanup_free_ char *t = NULL; const char *label; /* Literal label */ @@ -1153,21 +1152,20 @@ int dns_packet_read_name( if (r < 0) goto fail; - r = dns_label_escape(label, c, &t); - if (r < 0) - goto fail; - - if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) { + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) { r = -ENOMEM; goto fail; } - if (!first) - ret[n++] = '.'; - else + if (first) first = false; + else + ret[n++] = '.'; + + r = dns_label_escape(label, c, ret + n, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + goto fail; - memcpy(ret + n, t, r); n += r; continue; } else if (allow_compression && (c & 0xc0) == 0xc0) { diff --git a/src/resolve/resolved-manager.c b/src/resolve/resolved-manager.c index 64703ab713..f1f454c786 100644 --- a/src/resolve/resolved-manager.c +++ b/src/resolve/resolved-manager.c @@ -351,7 +351,7 @@ static int determine_hostname(char **llmnr_hostname, char **mdns_hostname) { return -EINVAL; } - r = dns_label_escape(label, r, &n); + r = dns_label_escape_new(label, r, &n); if (r < 0) return log_error_errno(r, "Failed to escape host name: %m"); diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 5a9b091ac4..4cf6355b71 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -182,30 +182,31 @@ int dns_label_unescape_suffix(const char *name, const char **label_terminal, cha return r; } -int dns_label_escape(const char *p, size_t l, char **ret) { - _cleanup_free_ char *s = NULL; +int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) { char *q; - int r; - - assert(p); - assert(ret); if (l > DNS_LABEL_MAX) return -EINVAL; + if (sz < 1) + return -ENOSPC; - s = malloc(l * 4 + 1); - if (!s) - return -ENOMEM; + assert(p); + assert(dest); - q = s; + q = dest; while (l > 0) { if (*p == '.' || *p == '\\') { + if (sz < 3) + return -ENOSPC; + /* Dot or backslash */ *(q++) = '\\'; *(q++) = *p; + sz -= 2; + } else if (*p == '_' || *p == '-' || (*p >= '0' && *p <= '9') || @@ -213,15 +214,27 @@ int dns_label_escape(const char *p, size_t l, char **ret) { (*p >= 'A' && *p <= 'Z')) { /* Proper character */ + + if (sz < 2) + return -ENOSPC; + *(q++) = *p; + sz -= 1; + } else if ((uint8_t) *p >= (uint8_t) ' ' && *p != 127) { /* Everything else */ + + if (sz < 5) + return -ENOSPC; + *(q++) = '\\'; *(q++) = '0' + (char) ((uint8_t) *p / 100); *(q++) = '0' + (char) (((uint8_t) *p / 10) % 10); *(q++) = '0' + (char) ((uint8_t) *p % 10); + sz -= 4; + } else return -EINVAL; @@ -230,8 +243,28 @@ int dns_label_escape(const char *p, size_t l, char **ret) { } *q = 0; + return (int) (q - dest); +} + +int dns_label_escape_new(const char *p, size_t l, char **ret) { + _cleanup_free_ char *s = NULL; + int r; + + assert(p); + assert(ret); + + if (l > DNS_LABEL_MAX) + return -EINVAL; + + s = new(char, DNS_LABEL_ESCAPED_MAX); + if (!s) + return -ENOMEM; + + r = dns_label_escape(p, l, s, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; + *ret = s; - r = q - s; s = NULL; return r; @@ -351,28 +384,32 @@ int dns_name_concat(const char *a, const char *b, char **_ret) { if (k > 0) r = k; - r = dns_label_escape(label, r, &t); - if (r < 0) - return r; - if (_ret) { - if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1)) + if (!GREEDY_REALLOC(ret, allocated, n + !first + DNS_LABEL_ESCAPED_MAX)) return -ENOMEM; + r = dns_label_escape(label, r, ret + n + !first, DNS_LABEL_ESCAPED_MAX); + if (r < 0) + return r; + if (!first) - ret[n++] = '.'; - else - first = false; + ret[n] = '.'; + } else { + char escaped[DNS_LABEL_ESCAPED_MAX]; - memcpy(ret + n, t, r); + r = dns_label_escape(label, r, escaped, sizeof(escaped)); + if (r < 0) + return r; } + if (!first) + n++; + else + first = false; + n += r; } - if (n > DNS_NAME_MAX) - return -EINVAL; - if (_ret) { if (!GREEDY_REALLOC(ret, allocated, n + 1)) return -ENOMEM; @@ -892,7 +929,8 @@ bool dns_service_name_is_valid(const char *name) { } int dns_service_join(const char *name, const char *type, const char *domain, char **ret) { - _cleanup_free_ char *escaped = NULL, *n = NULL; + char escaped[DNS_LABEL_ESCAPED_MAX]; + _cleanup_free_ char *n = NULL; int r; assert(type); @@ -908,7 +946,7 @@ int dns_service_join(const char *name, const char *type, const char *domain, cha if (!dns_service_name_is_valid(name)) return -EINVAL; - r = dns_label_escape(name, strlen(name), &escaped); + r = dns_label_escape(name, strlen(name), escaped, sizeof(escaped)); if (r < 0) return r; diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index 2f557d618e..99c72574db 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -26,11 +26,12 @@ #include "in-addr-util.h" #define DNS_LABEL_MAX 63 -#define DNS_NAME_MAX 255 +#define DNS_LABEL_ESCAPED_MAX (DNS_LABEL_MAX*4+1) int dns_label_unescape(const char **name, char *dest, size_t sz); int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz); -int dns_label_escape(const char *p, size_t l, char **ret); +int dns_label_escape(const char *p, size_t l, char *dest, size_t sz); +int dns_label_escape_new(const char *p, size_t l, char **ret); int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max); int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max); diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c index df34b72ab6..f010e4e19a 100644 --- a/src/test/test-dns-domain.c +++ b/src/test/test-dns-domain.c @@ -126,7 +126,7 @@ static void test_dns_label_escape_one(const char *what, size_t l, const char *ex _cleanup_free_ char *t = NULL; int r; - r = dns_label_escape(what, l, &t); + r = dns_label_escape_new(what, l, &t); assert_se(r == ret); if (r < 0) -- cgit v1.2.3-54-g00ecf