]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dns-domain: rework dns_label_escape() to not imply memory allocation 2031/head
authorLennart Poettering <lennart@poettering.net>
Wed, 25 Nov 2015 20:56:48 +0000 (21:56 +0100)
committerLennart Poettering <lennart@poettering.net>
Wed, 25 Nov 2015 21:00:07 +0000 (22:00 +0100)
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
src/resolve/resolved-dns-packet.c
src/resolve/resolved-manager.c
src/shared/dns-domain.c
src/shared/dns-domain.h
src/test/test-dns-domain.c

index 62023a9e490354b7f6d3704603aae8f82268547f..850212aea1e3f1621ecdccf2d1321e291b151986 100644 (file)
@@ -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 {
index 472486777c1e3d7482dc87561a6d18239fd4cbfc..aeff3138d73e08a183971e87e7e3977c5bb5bb31 100644 (file)
@@ -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) {
index 64703ab713e4ea81b7333fd11e7018ff736e8812..f1f454c7868b56eed077ab060ac1b135946436fe 100644 (file)
@@ -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");
 
index 5a9b091ac41601f777ffc62037772f58f88626dc..4cf6355b7155f16d4f48e254c59e6443529463c5 100644 (file)
@@ -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;
 
index 2f557d618e6e55413a04f0b9cd70a014202774b3..99c72574dbb9ef8bfbe4e11ce88c0eec50f7f9e9 100644 (file)
 #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);
index df34b72ab67f85316231d9e6386ebd5c8a174535..f010e4e19ac4a26ba4e46e5c4b427bf61821dbda 100644 (file)
@@ -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)