]> git.ipfire.org Git - thirdparty/systemd.git/blobdiff - src/shared/dns-domain.c
Merge pull request #1668 from ssahani/net1
[thirdparty/systemd.git] / src / shared / dns-domain.c
index 8a472fbcb431bc04a94e784dd4a0a95acf14093b..d4df9d2acbaeff724530d6906e7d8451b354803d 100644 (file)
@@ -24,6 +24,7 @@
 #include <stringprep.h>
 #endif
 
+#include "string-util.h"
 #include "dns-domain.h"
 
 int dns_label_unescape(const char **name, char *dest, size_t sz) {
@@ -308,14 +309,14 @@ int dns_label_undo_idna(const char *encoded, size_t encoded_size, char *decoded,
 #endif
 }
 
-int dns_name_normalize(const char *s, char **_ret) {
+int dns_name_concat(const char *a, const char *b, char **_ret) {
         _cleanup_free_ char *ret = NULL;
         size_t n = 0, allocated = 0;
-        const char *p = s;
+        const char *p = a;
         bool first = true;
         int r;
 
-        assert(s);
+        assert(a);
 
         for (;;) {
                 _cleanup_free_ char *t = NULL;
@@ -328,6 +329,14 @@ int dns_name_normalize(const char *s, char **_ret) {
                 if (r == 0) {
                         if (*p != 0)
                                 return -EINVAL;
+
+                        if (b) {
+                                /* Now continue with the second string, if there is one */
+                                p = b;
+                                b = NULL;
+                                continue;
+                        }
+
                         break;
                 }
 
@@ -341,27 +350,29 @@ int dns_name_normalize(const char *s, char **_ret) {
                 if (r < 0)
                         return r;
 
-                if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
-                        return -ENOMEM;
+                if (_ret) {
+                        if (!GREEDY_REALLOC(ret, allocated, n + !first + strlen(t) + 1))
+                                return -ENOMEM;
 
-                if (!first)
-                        ret[n++] = '.';
-                else
-                        first = false;
+                        if (!first)
+                                ret[n++] = '.';
+                        else
+                                first = false;
+
+                        memcpy(ret + n, t, r);
+                }
 
-                memcpy(ret + n, t, r);
                 n += r;
         }
 
         if (n > DNS_NAME_MAX)
                 return -EINVAL;
 
-        if (!GREEDY_REALLOC(ret, allocated, n + 1))
-                return -ENOMEM;
-
-        ret[n] = 0;
-
         if (_ret) {
+                if (!GREEDY_REALLOC(ret, allocated, n + 1))
+                        return -ENOMEM;
+
+                ret[n] = 0;
                 *_ret = ret;
                 ret = NULL;
         }
@@ -369,9 +380,8 @@ int dns_name_normalize(const char *s, char **_ret) {
         return 0;
 }
 
-unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_SIZE]) {
+void dns_name_hash_func(const void *s, struct siphash *state) {
         const char *p = s;
-        unsigned long ul = hash_key[0];
         int r;
 
         assert(p);
@@ -390,30 +400,37 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_
                 if (k > 0)
                         r = k;
 
+                if (r == 0)
+                        break;
+
                 label[r] = 0;
                 ascii_strlower(label);
 
-                ul = ul * hash_key[1] + ul + string_hash_func(label, hash_key);
+                string_hash_func(label, state);
         }
 
-        return ul;
+        /* enforce that all names are terminated by the empty label */
+        string_hash_func("", state);
 }
 
 int dns_name_compare_func(const void *a, const void *b) {
-        const char *x = a, *y = b;
+        const char *x, *y;
         int r, q, k, w;
 
         assert(a);
         assert(b);
 
+        x = (const char *) a + strlen(a);
+        y = (const char *) b + strlen(b);
+
         for (;;) {
                 char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
 
-                if (*x == 0 && *y == 0)
+                if (x == NULL && y == NULL)
                         return 0;
 
-                r = dns_label_unescape(&x, la, sizeof(la));
-                q = dns_label_unescape(&y, lb, sizeof(lb));
+                r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
+                q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
                 if (r < 0 || q < 0)
                         return r - q;
 
@@ -526,6 +543,28 @@ int dns_name_endswith(const char *name, const char *suffix) {
         }
 }
 
+int dns_name_between(const char *a, const char *b, const char *c) {
+        int n;
+
+        /* Determine if b is strictly greater than a and strictly smaller than c.
+           We consider the order of names to be circular, so that if a is
+           strictly greater than c, we consider b to be between them if it is
+           either greater than a or smaller than c. This is how the canonical
+           DNS name order used in NSEC records work. */
+
+        n = dns_name_compare_func(a, c);
+        if (n == 0)
+                return -EINVAL;
+        else if (n < 0)
+                /*       a<---b--->c       */
+                return dns_name_compare_func(a, b) < 0 &&
+                       dns_name_compare_func(b, c) < 0;
+        else
+                /* <--b--c         a--b--> */
+                return dns_name_compare_func(b, c) < 0 ||
+                       dns_name_compare_func(a, b) < 0;
+}
+
 int dns_name_reverse(int family, const union in_addr_union *a, char **ret) {
         const uint8_t *p;
         int r;