summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/shared/dns-domain.c22
-rw-r--r--src/shared/dns-domain.h1
-rw-r--r--src/test/test-dns-domain.c33
3 files changed, 56 insertions, 0 deletions
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c
index 20a44ce4e..e716d333e 100644
--- a/src/shared/dns-domain.c
+++ b/src/shared/dns-domain.c
@@ -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;
diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h
index 516d244f7..4d9a54e59 100644
--- a/src/shared/dns-domain.h
+++ b/src/shared/dns-domain.h
@@ -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);
diff --git a/src/test/test-dns-domain.c b/src/test/test-dns-domain.c
index 527cdd3b5..567c1f6f1 100644
--- a/src/test/test-dns-domain.c
+++ b/src/test/test-dns-domain.c
@@ -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();