]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
dns-domain: add code for verifying validity of DNS-SD service names and types
authorLennart Poettering <lennart@poettering.net>
Fri, 20 Nov 2015 16:52:36 +0000 (17:52 +0100)
committerLennart Poettering <lennart@poettering.net>
Mon, 23 Nov 2015 20:31:28 +0000 (21:31 +0100)
src/shared/dns-domain.c
src/shared/dns-domain.h
src/test/test-dns-domain.c

index 423ccca9cc99c7ca3252e888e25a76357c5f47d7..014e0bd70db00b0f7c6592acde54dd522f930895 100644 (file)
@@ -29,6 +29,7 @@
 #include "hexdecoct.h"
 #include "parse-util.h"
 #include "string-util.h"
+#include "utf8.h"
 
 int dns_label_unescape(const char **name, char *dest, size_t sz) {
         const char *n;
@@ -749,3 +750,69 @@ int dns_name_to_wire_format(const char *domain, uint8_t *buffer, size_t len) {
 
         return out - buffer;
 }
+
+int dns_srv_type_verify(const char *name) {
+        unsigned c = 0;
+        int r;
+
+        if (!name)
+                return 0;
+
+        for (;;) {
+                char label[DNS_LABEL_MAX];
+                int k;
+
+                /* 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;
+                if (r == 0)
+                        return c >= 2; /* At least two labels */
+                if (r < 2) /* Label needs to be at least 2 chars long */
+                        return 0;
+                if (label[0] != '_') /* First label char needs to be underscore */
+                        return 0;
+
+                /* Second char must be a letter */
+                if (!(label[1] >= 'A' && label[1] <= 'Z') &&
+                    !(label[1] >= 'a' && label[1] <= 'z'))
+                        return 0;
+
+                /* Third and further chars must be alphanumeric or a hyphen */
+                for (k = 2; k < r; k++) {
+                        if (!(label[k] >= 'A' && label[k] <= 'Z') &&
+                            !(label[k] >= 'a' && label[k] <= 'z') &&
+                            !(label[k] >= '0' && label[k] <= '9') &&
+                            label[k] != '-')
+                                return 0;
+                }
+
+                c++;
+        }
+}
+
+bool dns_service_name_is_valid(const char *name) {
+        size_t l;
+
+        /* This more or less implements RFC 6763, Section 4.1.1 */
+
+        if (!name)
+                return false;
+
+        if (!utf8_is_valid(name))
+                return false;
+
+        if (string_has_cc(name, NULL))
+                return false;
+
+        l = strlen(name);
+        if (l <= 0)
+                return false;
+        if (l > 63)
+                return false;
+
+        return true;
+}
index b2148974409678398f9d962a73837b9ab80b5599..22c394443b61c4c80ed79e2d2d2f7561c75ae425 100644 (file)
@@ -69,3 +69,7 @@ int dns_name_root(const char *name);
 int dns_name_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_service_name_is_valid(const char *name);
index 407c7d8ef792a736443d61c4302b06bfc2502160..a23d5dee05843caa3f8171a68e13a0b755dc752c 100644 (file)
@@ -316,6 +316,40 @@ static void test_dns_name_is_valid(void) {
         test_dns_name_is_valid_one("\n", 0);
 }
 
+static void test_dns_service_name_is_valid(void) {
+        assert_se(dns_service_name_is_valid("Lennart's Compüter"));
+        assert_se(dns_service_name_is_valid("piff.paff"));
+
+        assert_se(!dns_service_name_is_valid(NULL));
+        assert_se(!dns_service_name_is_valid(""));
+        assert_se(!dns_service_name_is_valid("foo\nbar"));
+        assert_se(!dns_service_name_is_valid("foo\201bar"));
+        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("_piep._sub._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);
+}
+
 int main(int argc, char *argv[]) {
 
         test_dns_label_unescape();
@@ -331,6 +365,8 @@ int main(int argc, char *argv[]) {
         test_dns_name_concat();
         test_dns_name_is_valid();
         test_dns_name_to_wire_format();
+        test_dns_service_name_is_valid();
+        test_dns_srv_type_verify();
 
         return 0;
 }