chiark / gitweb /
shared: dns-name - add dns_name_between()
authorTom Gundersen <teg@jklm.no>
Mon, 20 Jul 2015 00:02:45 +0000 (02:02 +0200)
committerSven Eden <yamakuzure@gmx.net>
Tue, 14 Mar 2017 09:07:02 +0000 (10:07 +0100)
Given three DNS names this function indicates if the second argument lies
strictly between the first and the third according to the canonical DNS
name order. Note that the order is circular, so the last name is
considered to be before the first.

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

index 20a44ce4e11bf4ba84ffd6446ad193c095cae370..e716d333e4b031b60b989c6699af5b7581e1992e 100644 (file)
@@ -464,6 +464,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;
index 516d244f7a3962a7c17352c2fc4e9f1d72612814..4d9a54e5955567e3a01bff00a9ad2b9064dfbd99 100644 (file)
@@ -40,6 +40,7 @@ unsigned long dns_name_hash_func(const void *s, const uint8_t hash_key[HASH_KEY_
 int dns_name_compare_func(const void *a, const void *b);
 extern const struct hash_ops dns_name_hash_ops;
 
+int dns_name_between(const char *a, const char *b, const char *c);
 int dns_name_equal(const char *x, const char *y);
 int dns_name_endswith(const char *name, const char *suffix);
 
index 527cdd3b549bb1d58714f16b2b6edc61fe9d439b..567c1f6f1b500f0325dcdeec81c8863db526dc21 100644 (file)
@@ -120,6 +120,38 @@ static void test_dns_name_equal(void) {
         test_dns_name_equal_one("..", "..", -EINVAL);
 }
 
+static void test_dns_name_between_one(const char *a, const char *b, const char *c, int ret) {
+        int r;
+
+        r = dns_name_between(a, b, c);
+        assert_se(r == ret);
+
+        r = dns_name_between(c, b, a);
+        if (ret >= 0)
+                assert_se(r == 0);
+        else
+                assert_se(r == ret);
+}
+
+static void test_dns_name_between(void) {
+        /* see https://tools.ietf.org/html/rfc4034#section-6.1
+           Note that we use "\033.z.example" in stead of "\001.z.example" as we
+           consider the latter invalid */
+        test_dns_name_between_one("example", "a.example", "yljkjljk.a.example", true);
+        test_dns_name_between_one("a.example", "yljkjljk.a.example", "Z.a.example", true);
+        test_dns_name_between_one("yljkjljk.a.example", "Z.a.example", "zABC.a.EXAMPLE", true);
+        test_dns_name_between_one("Z.a.example", "zABC.a.EXAMPLE", "z.example", true);
+        test_dns_name_between_one("zABC.a.EXAMPLE", "z.example", "\\033.z.example", true);
+        test_dns_name_between_one("z.example", "\\033.z.example", "*.z.example", true);
+        test_dns_name_between_one("\\033.z.example", "*.z.example", "\\200.z.example", true);
+        test_dns_name_between_one("*.z.example", "\\200.z.example", "example", true);
+        test_dns_name_between_one("\\200.z.example", "example", "a.example", true);
+
+        test_dns_name_between_one("example", "a.example", "example", -EINVAL);
+        test_dns_name_between_one("example", "example", "yljkjljk.a.example", false);
+        test_dns_name_between_one("example", "yljkjljk.a.example", "yljkjljk.a.example", false);
+}
+
 static void test_dns_name_endswith_one(const char *a, const char *b, int ret) {
         assert_se(dns_name_endswith(a, b) == ret);
 }
@@ -184,6 +216,7 @@ int main(int argc, char *argv[]) {
         test_dns_name_normalize();
         test_dns_name_equal();
         test_dns_name_endswith();
+        test_dns_name_between();
         test_dns_name_root();
         test_dns_name_single_label();
         test_dns_name_reverse();