resolved: fix "in-between" logic when boundaries are equal (#7590)

This changes dns_name_between() to deal properly with checking whether B
is between A and C if A and C are equal. Previously we simply returned
-EINVAL in this case, refusing checking. With this change we correct
behaviour: if A and C are equal, then B is "between" both if it is
different from them. That's logical, since we do < and > comparisons, not
<= and >=, and that means that anything "right of A" and "left of C"
lies in between with wrap-around at the ends. And if A and C are equal
that means everything lies between, except for A itself.

This fixes handling of domains using NSEC3 "white lies", for example the
.it TLD.

Fixes: #7421
This commit is contained in:
Lennart Poettering 2017-12-14 06:08:21 +01:00 committed by Yu Watanabe
parent 1bb8d1fce8
commit 59f2725cc8
2 changed files with 14 additions and 10 deletions

View File

@ -693,23 +693,26 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char
}
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 */
if (dns_name_compare_func(a, c) < 0)
/*
a and c are properly ordered:
a<---b--->c
*/
return dns_name_compare_func(a, b) < 0 &&
dns_name_compare_func(b, c) < 0;
else
/* <--b--c a--b--> */
/*
a and c are equal or 'reversed':
<--b--c a----->
or:
<-----c a--b-->
*/
return dns_name_compare_func(b, c) < 0 ||
dns_name_compare_func(a, b) < 0;
}

View File

@ -230,7 +230,7 @@ static void test_dns_name_between_one(const char *a, const char *b, const char *
r = dns_name_between(c, b, a);
if (ret >= 0)
assert_se(r == 0);
assert_se(r == 0 || dns_name_equal(a, c) > 0);
else
assert_se(r == ret);
}
@ -249,7 +249,8 @@ static void test_dns_name_between(void) {
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", "a.example", "example", true);
test_dns_name_between_one("example", "example", "example", false);
test_dns_name_between_one("example", "example", "yljkjljk.a.example", false);
test_dns_name_between_one("example", "yljkjljk.a.example", "yljkjljk.a.example", false);
}