Merge pull request #748 from teg/dns-name-between-4
basic: dns-name - between()
This commit is contained in:
@@ -69,8 +69,6 @@ Features:
|
||||
|
||||
* log accumulated resource usage after each service invocation
|
||||
|
||||
* networkd: dhcp server: try to assign stable IP addresses based on client's MAC address
|
||||
|
||||
* nspawn: a nice way to boot up without machine id set, so that it is set at boot automatically for supporting --ephemeral. Maybe hash the host machine id together with the machine name to generate the machine id for the container
|
||||
|
||||
* logind: rename session scope so that it includes the UID. THat way
|
||||
@@ -96,8 +94,6 @@ Features:
|
||||
|
||||
* nspawn: as soon as networkd has a bus interface, hook up --network-interface=, --network-bridge= with networkd, to trigger netdev creation should an interface be missing
|
||||
|
||||
* networkd: make DHCP server IP range configurable, including only with a single IP address
|
||||
|
||||
* rework C11 utf8.[ch] to use char32_t instead of uint32_t when referring
|
||||
to unicode chars, to make things more expressive.
|
||||
|
||||
@@ -316,6 +312,8 @@ Features:
|
||||
(throughout the codebase, not only PID1)
|
||||
|
||||
* networkd:
|
||||
- make DHCP server IP range configurable, including only with a single IP address
|
||||
- dhcp server: try to assign stable IP addresses based on client's MAC address
|
||||
- add LLDP client side support
|
||||
- the DHCP lease data (such as NTP/DNS) is still made available when
|
||||
a carrier is lost on a link. It should be removed instantly.
|
||||
@@ -333,6 +331,7 @@ Features:
|
||||
- allow Name= to be specified repeatedly in the [Match] section. Maybe also
|
||||
support Name=foo*|bar*|baz ?
|
||||
- duplicate address check for static IPs (like ARPCHECK in network-scripts)
|
||||
- allow DUID/IAID to be customized, see issue #394.
|
||||
|
||||
* resolved:
|
||||
- put networkd events and rtnl events at a higher priority, so that
|
||||
|
||||
+91
-4
@@ -114,6 +114,68 @@ int dns_label_unescape(const char **name, char *dest, size_t sz) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* @label_terminal: terminal character of a label, updated to point to the terminal character of
|
||||
* the previous label (always skipping one dot) or to NULL if there are no more
|
||||
* labels. */
|
||||
int dns_label_unescape_suffix(const char *name, const char **label_terminal, char *dest, size_t sz) {
|
||||
const char *terminal;
|
||||
int r;
|
||||
|
||||
assert(name);
|
||||
assert(label_terminal);
|
||||
assert(dest);
|
||||
|
||||
/* no more labels */
|
||||
if (!*label_terminal) {
|
||||
if (sz >= 1)
|
||||
*dest = 0;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(**label_terminal == '.' || **label_terminal == 0);
|
||||
|
||||
/* skip current terminal character */
|
||||
terminal = *label_terminal - 1;
|
||||
|
||||
/* point name to the last label, and terminal to the preceding terminal symbol (or make it a NULL pointer) */
|
||||
for (;;) {
|
||||
if (terminal < name) {
|
||||
/* reached the first label, so indicate that there are no more */
|
||||
terminal = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
/* find the start of the last label */
|
||||
if (*terminal == '.') {
|
||||
const char *y;
|
||||
unsigned slashes = 0;
|
||||
|
||||
for (y = terminal - 1; y >= name && *y == '\\'; y--)
|
||||
slashes ++;
|
||||
|
||||
if (slashes % 2 == 0) {
|
||||
/* the '.' was not escaped */
|
||||
name = terminal + 1;
|
||||
break;
|
||||
} else {
|
||||
terminal = y;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
terminal --;
|
||||
}
|
||||
|
||||
r = dns_label_unescape(&name, dest, sz);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
*label_terminal = terminal;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
int dns_label_escape(const char *p, size_t l, char **ret) {
|
||||
_cleanup_free_ char *s = NULL;
|
||||
char *q;
|
||||
@@ -338,20 +400,23 @@ 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) {
|
||||
const char *x = a, *y = b;
|
||||
const char *x, *y;
|
||||
int r, q, k, w;
|
||||
|
||||
assert(a);
|
||||
assert(b);
|
||||
|
||||
x = (const char *) a + strlen(a);
|
||||
y = (const char *) b + strlen(b);
|
||||
|
||||
for (;;) {
|
||||
char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1];
|
||||
|
||||
if (*x == 0 && *y == 0)
|
||||
if (x == NULL && y == NULL)
|
||||
return 0;
|
||||
|
||||
r = dns_label_unescape(&x, la, sizeof(la));
|
||||
q = dns_label_unescape(&y, lb, sizeof(lb));
|
||||
r = dns_label_unescape_suffix(a, &x, la, sizeof(la));
|
||||
q = dns_label_unescape_suffix(b, &y, lb, sizeof(lb));
|
||||
if (r < 0 || q < 0)
|
||||
return r - q;
|
||||
|
||||
@@ -464,6 +529,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;
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#define DNS_NAME_MAX 255
|
||||
|
||||
int dns_label_unescape(const char **name, char *dest, size_t sz);
|
||||
int dns_label_unescape_suffix(const char *name, const char **label_end, char *dest, size_t sz);
|
||||
int dns_label_escape(const char *p, size_t l, char **ret);
|
||||
|
||||
int dns_label_apply_idna(const char *encoded, size_t encoded_size, char *decoded, size_t decoded_max);
|
||||
@@ -49,6 +50,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);
|
||||
|
||||
|
||||
@@ -50,6 +50,46 @@ static void test_dns_label_unescape(void) {
|
||||
test_dns_label_unescape_one("foobar.", "foobar", 20, 6);
|
||||
}
|
||||
|
||||
static void test_dns_label_unescape_suffix_one(const char *what, const char *expect1, const char *expect2, size_t buffer_sz, int ret1, int ret2) {
|
||||
char buffer[buffer_sz];
|
||||
const char *label;
|
||||
int r;
|
||||
|
||||
label = what + strlen(what);
|
||||
|
||||
r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz);
|
||||
assert_se(r == ret1);
|
||||
if (r >= 0)
|
||||
assert_se(streq(buffer, expect1));
|
||||
|
||||
r = dns_label_unescape_suffix(what, &label, buffer, buffer_sz);
|
||||
assert_se(r == ret2);
|
||||
if (r >= 0)
|
||||
assert_se(streq(buffer, expect2));
|
||||
}
|
||||
|
||||
static void test_dns_label_unescape_suffix(void) {
|
||||
test_dns_label_unescape_suffix_one("hallo", "hallo", "", 6, 5, 0);
|
||||
test_dns_label_unescape_suffix_one("hallo", "hallo", "", 4, -ENOSPC, -ENOSPC);
|
||||
test_dns_label_unescape_suffix_one("", "", "", 10, 0, 0);
|
||||
test_dns_label_unescape_suffix_one("hallo\\.foobar", "hallo.foobar", "", 20, 12, 0);
|
||||
test_dns_label_unescape_suffix_one("hallo.foobar", "foobar", "hallo", 10, 6, 5);
|
||||
test_dns_label_unescape_suffix_one("hallo.foobar\n", "foobar", "foobar", 20, -EINVAL, -EINVAL);
|
||||
test_dns_label_unescape_suffix_one("hallo\\", "hallo", "hallo", 20, -EINVAL, -EINVAL);
|
||||
test_dns_label_unescape_suffix_one("hallo\\032 ", "hallo ", "", 20, 7, 0);
|
||||
test_dns_label_unescape_suffix_one(".", "", "", 20, 0, 0);
|
||||
test_dns_label_unescape_suffix_one("..", "", "", 20, 0, 0);
|
||||
test_dns_label_unescape_suffix_one(".foobar", "foobar", "", 20, 6, -EINVAL);
|
||||
test_dns_label_unescape_suffix_one("foobar.", "", "foobar", 20, 0, 6);
|
||||
test_dns_label_unescape_suffix_one("foo\\\\bar", "foo\\bar", "", 20, 7, 0);
|
||||
test_dns_label_unescape_suffix_one("foo.bar", "bar", "foo", 20, 3, 3);
|
||||
test_dns_label_unescape_suffix_one("foo..bar", "bar", "", 20, 3, -EINVAL);
|
||||
test_dns_label_unescape_suffix_one("foo...bar", "bar", "", 20, 3, -EINVAL);
|
||||
test_dns_label_unescape_suffix_one("foo\\.bar", "foo.bar", "", 20, 7, 0);
|
||||
test_dns_label_unescape_suffix_one("foo\\\\.bar", "bar", "foo\\", 20, 3, 4);
|
||||
test_dns_label_unescape_suffix_one("foo\\\\\\.bar", "foo\\.bar", "", 20, 8, 0);
|
||||
}
|
||||
|
||||
static void test_dns_label_escape_one(const char *what, size_t l, const char *expect, int ret) {
|
||||
_cleanup_free_ char *t = NULL;
|
||||
int r;
|
||||
@@ -120,6 +160,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);
|
||||
}
|
||||
@@ -180,10 +252,12 @@ static void test_dns_name_reverse(void) {
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
test_dns_label_unescape();
|
||||
test_dns_label_unescape_suffix();
|
||||
test_dns_label_escape();
|
||||
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();
|
||||
|
||||
Reference in New Issue
Block a user