]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved add dns_name_apply_idna() to convert a domain name into its IDNA equivalent
authorLennart Poettering <lennart@poettering.net>
Mon, 18 Jan 2016 19:18:28 +0000 (20:18 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 18 Jan 2016 22:31:15 +0000 (23:31 +0100)
src/shared/dns-domain.c
src/shared/dns-domain.h
src/test/test-dns-domain.c

index 04624734dc9fb1862994e6d60043e2c52374ee90..33bc26ad7d5d6cb95737120b88482cfc29722f4f 100644 (file)
@@ -1303,3 +1303,55 @@ int dns_name_common_suffix(const char *a, const char *b, const char **ret) {
                 k++;
         }
 }
+
+int dns_name_apply_idna(const char *name, char **ret) {
+        _cleanup_free_ char *buf = NULL;
+        size_t n = 0, allocated = 0;
+        bool first = true;
+        int r, q;
+
+        assert(name);
+        assert(ret);
+
+        for (;;) {
+                char label[DNS_LABEL_MAX];
+
+                r = dns_label_unescape(&name, label, sizeof(label));
+                if (r < 0)
+                        return r;
+                if (r == 0)
+                        break;
+
+                q = dns_label_apply_idna(label, r, label, sizeof(label));
+                if (q < 0)
+                        return q;
+                if (q > 0)
+                        r = q;
+
+                if (!GREEDY_REALLOC(buf, allocated, n + !first + DNS_LABEL_ESCAPED_MAX))
+                        return -ENOMEM;
+
+                r = dns_label_escape(label, r, buf + n + !first, DNS_LABEL_ESCAPED_MAX);
+                if (r < 0)
+                        return r;
+
+                if (first)
+                        first = false;
+                else
+                        buf[n++] = '.';
+
+                n +=r;
+        }
+
+        if (n > DNS_HOSTNAME_MAX)
+                return -EINVAL;
+
+        if (!GREEDY_REALLOC(buf, allocated, n + 1))
+                return -ENOMEM;
+
+        buf[n] = 0;
+        *ret = buf;
+        buf = NULL;
+
+        return (int) n;
+}
index 5f9542ef98dcc9ffc8a808df120a6098788fe883..40c9ee5f278b067f9d69a88f2ceeb72c62ba463b 100644 (file)
@@ -108,3 +108,5 @@ int dns_name_skip(const char *a, unsigned n_labels, const char **ret);
 int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b);
 
 int dns_name_common_suffix(const char *a, const char *b, const char **ret);
+
+int dns_name_apply_idna(const char *name, char **ret);
index 987f1fc887aef812b013d35b4d481977e6c2addb..3b260ee75de8b21a2146a9ab49deb773ae2ec4fd 100644 (file)
@@ -598,6 +598,26 @@ static void test_dns_name_common_suffix(void) {
         test_dns_name_common_suffix_one("FOO.BAR", "tEST.bAR", "BAR");
 }
 
+static void test_dns_name_apply_idna_one(const char *s, const char *result) {
+#ifdef HAVE_LIBIDN
+        _cleanup_free_ char *buf = NULL;
+        assert_se(dns_name_apply_idna(s, &buf) >= 0);
+        assert_se(dns_name_equal(buf, result) > 0);
+#endif
+}
+
+static void test_dns_name_apply_idna(void) {
+        test_dns_name_apply_idna_one("", "");
+        test_dns_name_apply_idna_one("foo", "foo");
+        test_dns_name_apply_idna_one("foo.", "foo");
+        test_dns_name_apply_idna_one("foo.bar", "foo.bar");
+        test_dns_name_apply_idna_one("foo.bar.", "foo.bar");
+        test_dns_name_apply_idna_one("föö", "xn--f-1gaa");
+        test_dns_name_apply_idna_one("föö.", "xn--f-1gaa");
+        test_dns_name_apply_idna_one("föö.bär", "xn--f-1gaa.xn--br-via");
+        test_dns_name_apply_idna_one("föö.bär.", "xn--f-1gaa.xn--br-via");
+}
+
 int main(int argc, char *argv[]) {
 
         test_dns_label_unescape();
@@ -624,6 +644,7 @@ int main(int argc, char *argv[]) {
         test_dns_name_equal_skip();
         test_dns_name_compare_func();
         test_dns_name_common_suffix();
+        test_dns_name_apply_idna();
 
         return 0;
 }