summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2015-11-20 17:52:36 +0100
committerLennart Poettering <lennart@poettering.net>2015-11-23 21:31:28 +0100
commit0a49b6b6dce3a756bd8c4d458a34c2d8035ae99d (patch)
tree5d898be726a9560f44184a9d0af43d7de2c09cd7
parente429762faaac0c49353d35144a9d45d283e91213 (diff)
dns-domain: add code for verifying validity of DNS-SD service names and types
-rw-r--r--src/shared/dns-domain.c67
-rw-r--r--src/shared/dns-domain.h4
-rw-r--r--src/test/test-dns-domain.c36
3 files changed, 107 insertions, 0 deletions
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 423ccca9cc..014e0bd70d 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -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;
+}
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index b214897440..22c394443b 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -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);
diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c
index 407c7d8ef7..a23d5dee05 100644
--- a/src/test/test-dns-domain.c
+++ b/src/test/test-dns-domain.c
@@ -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;
}