From eb241cdbeea092d891137c018cacf919a895e6a6 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Jan 2016 02:23:08 +0100 Subject: shared: add new dns_name_startswith() call dns_name_startswith() is to dns_name_endswith() as startswith() is to endswith(). --- src/shared/dns-domain.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++++- src/shared/dns-domain.h | 1 + 2 files changed, 49 insertions(+), 1 deletion(-) (limited to 'src/shared') diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 59475115ba..e777badb6b 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -263,7 +263,6 @@ int dns_label_escape(const char *p, size_t l, char *dest, size_t sz) { *(q++) = '0' + (char) ((uint8_t) *p % 10); sz -= 4; - } p++; @@ -653,6 +652,54 @@ int dns_name_endswith(const char *name, const char *suffix) { } } +static int dns_label_unescape_undo_idna(const char **name, char *dest, size_t sz) { + int r, k; + + /* Clobbers all arguments on failure... */ + + r = dns_label_unescape(name, dest, sz); + if (r <= 0) + return r; + + k = dns_label_undo_idna(dest, r, dest, sz); + if (k < 0) + return k; + if (k == 0) /* not an IDNA name */ + return r; + + return k; +} + +int dns_name_startswith(const char *name, const char *prefix) { + const char *n, *p; + int r, q; + + assert(name); + assert(prefix); + + n = name; + p = prefix; + + for (;;) { + char ln[DNS_LABEL_MAX], lp[DNS_LABEL_MAX]; + + r = dns_label_unescape_undo_idna(&p, lp, sizeof(lp)); + if (r < 0) + return r; + if (r == 0) + return true; + + q = dns_label_unescape_undo_idna(&n, ln, sizeof(ln)); + if (q < 0) + return q; + + if (r != q) + return false; + if (ascii_strcasecmp_n(ln, lp, r) != 0) + return false; + } +} + int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) { const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix; int r, q, k, w; diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index dd8ae3ac98..4fbe0a618f 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -83,6 +83,7 @@ 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); +int dns_name_startswith(const char *name, const char *prefix); int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret); -- cgit v1.2.3-54-g00ecf From 3095011d15e03a5d724fa0141463434c8bf8380c Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Jan 2016 03:03:26 +0100 Subject: shared: replace a few invocations of strcasecmp() for DNS labels with ascii_strcasecmp_n() This makes our code compatible with embedded NUL bytes, as we don't care about NUL bytes anymore. --- src/shared/dns-domain.c | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) (limited to 'src/shared') diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index e777badb6b..a127e594ac 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -559,10 +559,7 @@ int dns_name_equal(const char *x, const char *y) { assert(y); for (;;) { - char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1]; - - if (*x == 0 && *y == 0) - return true; + char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX]; r = dns_label_unescape(&x, la, sizeof(la)); if (r < 0) @@ -586,13 +583,12 @@ int dns_name_equal(const char *x, const char *y) { q = w; } - /* If one name had fewer labels than the other, this - * will show up as empty label here, which the - * strcasecmp() below will properly consider different - * from a non-empty label. */ + if (r != q) + return false; + if (r == 0) + return true; - la[r] = lb[q] = 0; - if (strcasecmp(la, lb) != 0) + if (ascii_strcasecmp_n(la, lb, r) != 0) return false; } } @@ -608,7 +604,7 @@ int dns_name_endswith(const char *name, const char *suffix) { s = suffix; for (;;) { - char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1]; + char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX]; r = dns_label_unescape(&n, ln, sizeof(ln)); if (r < 0) @@ -640,9 +636,7 @@ int dns_name_endswith(const char *name, const char *suffix) { if (r == 0 && saved_n == n) return false; - ln[r] = ls[q] = 0; - - if (r != q || strcasecmp(ln, ls)) { + if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) { /* Not the same, let's jump back, and try with the next label again */ s = suffix; @@ -713,7 +707,7 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char s = old_suffix; for (;;) { - char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1]; + char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX]; if (!saved_before) saved_before = n; @@ -750,9 +744,7 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char return 0; } - ln[r] = ls[q] = 0; - - if (r != q || strcasecmp(ln, ls)) { + if (r != q || ascii_strcasecmp_n(ln, ls, r) != 0) { /* Not the same, let's jump back, and try with the next label again */ s = old_suffix; -- cgit v1.2.3-54-g00ecf From f6fbd9c21ff4906c0bbd9ab95281658a9d1307b3 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Jan 2016 19:51:09 +0100 Subject: shared: simplify dns_name_is_single_label() by using dns_name_parent() to skip first label --- src/shared/dns-domain.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'src/shared') diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index a127e594ac..ef81341eca 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -912,12 +912,11 @@ bool dns_name_is_root(const char *name) { } bool dns_name_is_single_label(const char *name) { - char label[DNS_LABEL_MAX+1]; int r; assert(name); - r = dns_label_unescape(&name, label, sizeof(label)); + r = dns_name_parent(&name); if (r <= 0) return false; -- cgit v1.2.3-54-g00ecf From 34361485a8ff397be06a3875df0c5331ad45c845 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Jan 2016 20:20:52 +0100 Subject: shared: port dns_name_compare_func() to make use of ascii_strcasecmp_nn() This way we become compatible with DNS names with embedded NUL bytes. --- src/shared/dns-domain.c | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) (limited to 'src/shared') diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index ef81341eca..d36eb5056f 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -521,7 +521,7 @@ int dns_name_compare_func(const void *a, const void *b) { y = (const char *) b + strlen(b); for (;;) { - char la[DNS_LABEL_MAX+1], lb[DNS_LABEL_MAX+1]; + char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX]; if (x == NULL && y == NULL) return 0; @@ -531,8 +531,15 @@ int dns_name_compare_func(const void *a, const void *b) { if (r < 0 || q < 0) return r - q; - k = dns_label_undo_idna(la, r, la, sizeof(la)); - w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); + if (r > 0) + k = dns_label_undo_idna(la, r, la, sizeof(la)); + else + k = 0; + if (q > 0) + w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); + else + w = 0; + if (k < 0 || w < 0) return k - w; if (k > 0) @@ -540,8 +547,7 @@ int dns_name_compare_func(const void *a, const void *b) { if (w > 0) q = w; - la[r] = lb[q] = 0; - r = strcasecmp(la, lb); + r = ascii_strcasecmp_nn(la, r, lb, q); if (r != 0) return r; } -- cgit v1.2.3-54-g00ecf From 45c4210ed606b1e3318bba7edb5c1b962764a1c2 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Jan 2016 20:45:20 +0100 Subject: shared: simplify string concatenation with strjoin() --- src/shared/dns-domain.c | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) (limited to 'src/shared') diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index d36eb5056f..1235ff109b 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -1143,17 +1143,15 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do if (x >= 3 && srv_type_label_is_valid(c, cn)) { if (dns_service_name_label_is_valid(a, an)) { - /* OK, got . . . */ name = strndup(a, an); if (!name) return -ENOMEM; - type = new(char, bn+1+cn+1); + type = strjoin(b, ".", c, NULL); if (!type) return -ENOMEM; - strcpy(stpcpy(stpcpy(type, b), "."), c); d = p; goto finish; @@ -1165,10 +1163,9 @@ int dns_service_split(const char *joined, char **_name, char **_type, char **_do name = NULL; - type = new(char, an+1+bn+1); + type = strjoin(a, ".", b, NULL); if (!type) return -ENOMEM; - strcpy(stpcpy(stpcpy(type, a), "."), b); d = q; goto finish; -- cgit v1.2.3-54-g00ecf From 81ec9e0887ef12bebd36d48f10372cf003df5d38 Mon Sep 17 00:00:00 2001 From: Lennart Poettering Date: Wed, 13 Jan 2016 20:45:56 +0100 Subject: shared: reuse dns_label_unescape_undo_idna() in more places We frequently unescape DNS label follwed by IDNA undoing. We now have a function that does that in one step, hence use it everywhere. --- src/shared/dns-domain.c | 96 ++++++++++++++----------------------------------- 1 file changed, 27 insertions(+), 69 deletions(-) (limited to 'src/shared') diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index 1235ff109b..d1fb97fe92 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -558,8 +558,26 @@ const struct hash_ops dns_name_hash_ops = { .compare = dns_name_compare_func }; +static int dns_label_unescape_undo_idna(const char **name, char *dest, size_t sz) { + int r, k; + + /* Clobbers all arguments on failure... */ + + r = dns_label_unescape(name, dest, sz); + if (r <= 0) + return r; + + k = dns_label_undo_idna(dest, r, dest, sz); + if (k < 0) + return k; + if (k == 0) /* not an IDNA name */ + return r; + + return k; +} + int dns_name_equal(const char *x, const char *y) { - int r, q, k, w; + int r, q; assert(x); assert(y); @@ -567,27 +585,13 @@ int dns_name_equal(const char *x, const char *y) { for (;;) { char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX]; - r = dns_label_unescape(&x, la, sizeof(la)); + r = dns_label_unescape_undo_idna(&x, la, sizeof(la)); if (r < 0) return r; - if (r > 0) { - k = dns_label_undo_idna(la, r, la, sizeof(la)); - if (k < 0) - return k; - if (k > 0) - r = k; - } - q = dns_label_unescape(&y, lb, sizeof(lb)); + q = dns_label_unescape_undo_idna(&y, lb, sizeof(lb)); if (q < 0) return q; - if (q > 0) { - w = dns_label_undo_idna(lb, q, lb, sizeof(lb)); - if (w < 0) - return w; - if (w > 0) - q = w; - } if (r != q) return false; @@ -601,7 +605,7 @@ int dns_name_equal(const char *x, const char *y) { int dns_name_endswith(const char *name, const char *suffix) { const char *n, *s, *saved_n = NULL; - int r, q, k, w; + int r, q; assert(name); assert(suffix); @@ -612,30 +616,16 @@ int dns_name_endswith(const char *name, const char *suffix) { for (;;) { char ln[DNS_LABEL_MAX], ls[DNS_LABEL_MAX]; - r = dns_label_unescape(&n, ln, sizeof(ln)); + r = dns_label_unescape_undo_idna(&n, ln, sizeof(ln)); if (r < 0) return r; - if (r > 0) { - k = dns_label_undo_idna(ln, r, ln, sizeof(ln)); - if (k < 0) - return k; - if (k > 0) - r = k; - } if (!saved_n) saved_n = n; - q = dns_label_unescape(&s, ls, sizeof(ls)); + q = dns_label_unescape_undo_idna(&s, ls, sizeof(ls)); if (q < 0) return q; - if (q > 0) { - w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); - if (w < 0) - return w; - if (w > 0) - q = w; - } if (r == 0 && q == 0) return true; @@ -652,24 +642,6 @@ int dns_name_endswith(const char *name, const char *suffix) { } } -static int dns_label_unescape_undo_idna(const char **name, char *dest, size_t sz) { - int r, k; - - /* Clobbers all arguments on failure... */ - - r = dns_label_unescape(name, dest, sz); - if (r <= 0) - return r; - - k = dns_label_undo_idna(dest, r, dest, sz); - if (k < 0) - return k; - if (k == 0) /* not an IDNA name */ - return r; - - return k; -} - int dns_name_startswith(const char *name, const char *prefix) { const char *n, *p; int r, q; @@ -702,7 +674,7 @@ int dns_name_startswith(const char *name, const char *prefix) { int dns_name_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret) { const char *n, *s, *saved_before = NULL, *saved_after = NULL, *prefix; - int r, q, k, w; + int r, q; assert(name); assert(old_suffix); @@ -718,30 +690,16 @@ int dns_name_change_suffix(const char *name, const char *old_suffix, const char if (!saved_before) saved_before = n; - r = dns_label_unescape(&n, ln, sizeof(ln)); + r = dns_label_unescape_undo_idna(&n, ln, sizeof(ln)); if (r < 0) return r; - if (r > 0) { - k = dns_label_undo_idna(ln, r, ln, sizeof(ln)); - if (k < 0) - return k; - if (k > 0) - r = k; - } if (!saved_after) saved_after = n; - q = dns_label_unescape(&s, ls, sizeof(ls)); + q = dns_label_unescape_undo_idna(&s, ls, sizeof(ls)); if (q < 0) return q; - if (q > 0) { - w = dns_label_undo_idna(ls, q, ls, sizeof(ls)); - if (w < 0) - return w; - if (w > 0) - q = w; - } if (r == 0 && q == 0) break; -- cgit v1.2.3-54-g00ecf