dns-domain: add call for concatenating two domain names
authorLennart Poettering <lennart@poettering.net>
Mon, 17 Aug 2015 22:05:41 +0000 (00:05 +0200)
committerLennart Poettering <lennart@poettering.net>
Fri, 21 Aug 2015 10:41:07 +0000 (12:41 +0200)
This is specifically useful for appending the mDNS ".local" suffix to a
single-label hostname in the most correct way. (used in later commit)

src/shared/dns-domain.c
src/shared/dns-domain.h
src/test/test-dns-domain.c

index 8a0dec1..6dc04d5 100644 (file)
@@ -308,14 +308,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 +328,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 +349,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;
         }
index bd50ad3..8e73d9c 100644 (file)
@@ -35,9 +35,17 @@ int dns_label_escape(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);
 
-int dns_name_normalize(const char *s, char **_ret);
+int dns_name_concat(const char *a, const char *b, char **ret);
+
+static inline int dns_name_normalize(const char *s, char **ret) {
+        /* dns_name_concat() normalizes as a side-effect */
+        return dns_name_concat(s, NULL, ret);
+}
+
 static inline int dns_name_is_valid(const char *s) {
         int r;
+
+        /* dns_name_normalize() verifies as a side effect */
         r = dns_name_normalize(s, NULL);
         if (r == -EINVAL)
                 return 0;
index 0042722..2193eb6 100644 (file)
@@ -251,6 +251,39 @@ static void test_dns_name_reverse(void) {
         test_dns_name_reverse_one("::1", "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa");
 }
 
+static void test_dns_name_concat_one(const char *a, const char *b, int r, const char *result) {
+        _cleanup_free_ char *p = NULL;
+
+        assert_se(dns_name_concat(a, b, &p) == r);
+        assert_se(streq_ptr(p, result));
+}
+
+static void test_dns_name_concat(void) {
+        test_dns_name_concat_one("foo", "bar", 0, "foo.bar");
+        test_dns_name_concat_one("foo.foo", "bar.bar", 0, "foo.foo.bar.bar");
+        test_dns_name_concat_one("foo", NULL, 0, "foo");
+        test_dns_name_concat_one("foo.", "bar.", 0, "foo.bar");
+}
+
+static void test_dns_name_is_valid_one(const char *s, int ret) {
+        assert_se(dns_name_is_valid(s) == ret);
+}
+
+static void test_dns_name_is_valid(void) {
+        test_dns_name_is_valid_one("foo", 1);
+        test_dns_name_is_valid_one("foo.", 1);
+        test_dns_name_is_valid_one("Foo", 1);
+        test_dns_name_is_valid_one("foo.bar", 1);
+        test_dns_name_is_valid_one("foo.bar.baz", 1);
+        test_dns_name_is_valid_one("", 1);
+        test_dns_name_is_valid_one("foo..bar", 0);
+        test_dns_name_is_valid_one(".foo.bar", 0);
+        test_dns_name_is_valid_one("foo.bar.", 1);
+        test_dns_name_is_valid_one("\\zbar", 0);
+        test_dns_name_is_valid_one("รค", 1);
+        test_dns_name_is_valid_one("\n", 0);
+}
+
 int main(int argc, char *argv[]) {
 
         test_dns_label_unescape();
@@ -263,6 +296,8 @@ int main(int argc, char *argv[]) {
         test_dns_name_root();
         test_dns_name_single_label();
         test_dns_name_reverse();
+        test_dns_name_concat();
+        test_dns_name_is_valid();
 
         return 0;
 }