diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-11-24 00:18:49 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-11-24 00:20:39 +0100 |
commit | 58db254ade4fb2ef77de68f28c4f13814819f6a1 (patch) | |
tree | 597cc7eb7ec7822f62b91e25558e3e9d490b655c /src/shared | |
parent | 5ce1946f4def03e0ab7127dd5729949a32e060ac (diff) |
resolved: implement client-side DNAME resolution
Most servers apparently always implicitly convert DNAME to CNAME, but
some servers don't, hence implement this properly, as this is required
by edns0.
Diffstat (limited to 'src/shared')
-rw-r--r-- | src/shared/dns-domain.c | 67 | ||||
-rw-r--r-- | src/shared/dns-domain.h | 4 |
2 files changed, 71 insertions, 0 deletions
diff --git a/src/shared/dns-domain.c b/src/shared/dns-domain.c index e08143c3be..e6aad39c74 100644 --- a/src/shared/dns-domain.c +++ b/src/shared/dns-domain.c @@ -547,6 +547,73 @@ int dns_name_endswith(const char *name, const char *suffix) { } } +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; + + assert(name); + assert(old_suffix); + assert(new_suffix); + assert(ret); + + n = name; + s = old_suffix; + + for (;;) { + char ln[DNS_LABEL_MAX+1], ls[DNS_LABEL_MAX+1]; + + if (!saved_before) + saved_before = n; + + r = dns_label_unescape(&n, ln, sizeof(ln)); + if (r < 0) + return r; + 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)); + if (q < 0) + return q; + 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; + if (r == 0 && saved_after == n) { + *ret = NULL; /* doesn't match */ + return 0; + } + + ln[r] = ls[q] = 0; + + if (r != q || strcasecmp(ln, ls)) { + + /* Not the same, let's jump back, and try with the next label again */ + s = old_suffix; + n = saved_after; + saved_after = saved_before = NULL; + } + } + + /* Found it! Now generate the new name */ + prefix = strndupa(name, saved_before - name); + + r = dns_name_concat(prefix, new_suffix, ret); + if (r < 0) + return r; + + return 1; +} + int dns_name_between(const char *a, const char *b, const char *c) { int n; diff --git a/src/shared/dns-domain.h b/src/shared/dns-domain.h index c6d7623e09..a68df330e6 100644 --- a/src/shared/dns-domain.h +++ b/src/shared/dns-domain.h @@ -62,6 +62,8 @@ 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_change_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret); + int dns_name_reverse(int family, const union in_addr_union *a, char **ret); int dns_name_address(const char *p, int *family, union in_addr_union *a); @@ -76,3 +78,5 @@ bool dns_service_name_is_valid(const char *name); int dns_service_join(const char *name, const char *type, const char *domain, char **ret); int dns_service_split(const char *joined, char **name, char **type, char **domain); + +int dns_name_replace_suffix(const char *name, const char *old_suffix, const char *new_suffix, char **ret); |