diff options
Diffstat (limited to 'src/shared/dns-domain.c')
-rw-r--r-- | src/shared/dns-domain.c | 99 |
1 files changed, 86 insertions, 13 deletions
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index d1fb97fe92..04624734dc 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -1157,22 +1157,20 @@ finish: return 0; } -int dns_name_suffix(const char *name, unsigned n_labels, const char **ret) { - const char* labels[DNS_N_LABELS_MAX+1]; - unsigned n = 0; +static int dns_name_build_suffix_table(const char *name, const char*table[]) { const char *p; + unsigned n = 0; int r; assert(name); - assert(ret); + assert(table); p = name; for (;;) { if (n > DNS_N_LABELS_MAX) return -EINVAL; - labels[n] = p; - + table[n] = p; r = dns_name_parent(&p); if (r < 0) return r; @@ -1182,13 +1180,47 @@ int dns_name_suffix(const char *name, unsigned n_labels, const char **ret) { n++; } - if (n < n_labels) + return (int) n; +} + +int dns_name_suffix(const char *name, unsigned n_labels, const char **ret) { + const char* labels[DNS_N_LABELS_MAX+1]; + int n; + + assert(name); + assert(ret); + + n = dns_name_build_suffix_table(name, labels); + if (n < 0) + return n; + + if ((unsigned) n < n_labels) return -EINVAL; *ret = labels[n - n_labels]; return (int) (n - n_labels); } +int dns_name_skip(const char *a, unsigned n_labels, const char **ret) { + int r; + + assert(a); + assert(ret); + + for (; n_labels > 0; n_labels --) { + r = dns_name_parent(&a); + if (r < 0) + return r; + if (r == 0) { + *ret = ""; + return 0; + } + } + + *ret = a; + return 1; +} + int dns_name_count_labels(const char *name) { unsigned n = 0; const char *p; @@ -1219,14 +1251,55 @@ int dns_name_equal_skip(const char *a, unsigned n_labels, const char *b) { assert(a); assert(b); - while (n_labels > 0) { + r = dns_name_skip(a, n_labels, &a); + if (r <= 0) + return r; - r = dns_name_parent(&a); - if (r <= 0) + return dns_name_equal(a, b); +} + +int dns_name_common_suffix(const char *a, const char *b, const char **ret) { + const char *a_labels[DNS_N_LABELS_MAX+1], *b_labels[DNS_N_LABELS_MAX+1]; + int n = 0, m = 0, k = 0, r, q; + + assert(a); + assert(b); + assert(ret); + + /* Determines the common suffix of domain names a and b */ + + n = dns_name_build_suffix_table(a, a_labels); + if (n < 0) + return n; + + m = dns_name_build_suffix_table(b, b_labels); + if (m < 0) + return m; + + for (;;) { + char la[DNS_LABEL_MAX], lb[DNS_LABEL_MAX]; + const char *x, *y; + + if (k >= n || k >= m) { + *ret = a_labels[n - k]; + return 0; + } + + x = a_labels[n - 1 - k]; + r = dns_label_unescape_undo_idna(&x, la, sizeof(la)); + if (r < 0) return r; - n_labels --; - } + y = b_labels[m - 1 - k]; + q = dns_label_unescape_undo_idna(&y, lb, sizeof(lb)); + if (q < 0) + return q; - return dns_name_equal(a, b); + if (r != q || ascii_strcasecmp_n(la, lb, r) != 0) { + *ret = a_labels[n - k]; + return 0; + } + + k++; + } } |