From: Lennart Poettering Date: Mon, 22 Feb 2021 22:07:01 +0000 (+0100) Subject: resolved: add dns_resource_record_get_cname_target() helper X-Git-Tag: v248-rc1~3^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=d1f8fbea9fcba048338aeb3c26f57593b96021b5;p=thirdparty%2Fsystemd.git resolved: add dns_resource_record_get_cname_target() helper This determines the redirection target from a CNAME or DNAME RR given it matches some given RR key. --- diff --git a/src/resolve/resolved-dns-rr.c b/src/resolve/resolved-dns-rr.c index d844f7c9aa9..9b94ab59eab 100644 --- a/src/resolve/resolved-dns-rr.c +++ b/src/resolve/resolved-dns-rr.c @@ -1722,6 +1722,7 @@ int dns_resource_record_clamp_ttl(DnsResourceRecord **rr, uint32_t max_ttl) { } bool dns_resource_record_is_link_local_address(DnsResourceRecord *rr) { + assert(rr); if (rr->key->class != DNS_CLASS_IN) return false; @@ -1735,6 +1736,47 @@ bool dns_resource_record_is_link_local_address(DnsResourceRecord *rr) { return false; } +int dns_resource_record_get_cname_target(DnsResourceKey *key, DnsResourceRecord *cname, char **ret) { + _cleanup_free_ char *d = NULL; + int r; + + assert(key); + assert(cname); + + if (key->class != cname->key->class && key->class != DNS_CLASS_ANY) + return -EUNATCH; + + if (cname->key->type == DNS_TYPE_CNAME) { + r = dns_name_equal(dns_resource_key_name(key), + dns_resource_key_name(cname->key)); + if (r < 0) + return r; + if (r == 0) + return -EUNATCH; /* CNAME RR key doesn't actually match the original key */ + + d = strdup(cname->cname.name); + if (!d) + return -ENOMEM; + + } else if (cname->key->type == DNS_TYPE_DNAME) { + + r = dns_name_change_suffix( + dns_resource_key_name(key), + dns_resource_key_name(cname->key), + cname->dname.name, + &d); + if (r < 0) + return r; + if (r == 0) + return -EUNATCH; /* DNAME RR key doesn't actually match the original key */ + + } else + return -EUNATCH; /* Not a CNAME/DNAME RR, hence doesn't match the proposition either */ + + *ret = TAKE_PTR(d); + return 0; +} + DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i) { DnsTxtItem *n; diff --git a/src/resolve/resolved-dns-rr.h b/src/resolve/resolved-dns-rr.h index d788d797fc8..d3edcadf675 100644 --- a/src/resolve/resolved-dns-rr.h +++ b/src/resolve/resolved-dns-rr.h @@ -326,6 +326,8 @@ int dns_resource_record_clamp_ttl(DnsResourceRecord **rr, uint32_t max_ttl); bool dns_resource_record_is_link_local_address(DnsResourceRecord *rr); +int dns_resource_record_get_cname_target(DnsResourceKey *key, DnsResourceRecord *cname, char **ret); + DnsTxtItem *dns_txt_item_free_all(DnsTxtItem *i); bool dns_txt_item_equal(DnsTxtItem *a, DnsTxtItem *b); DnsTxtItem *dns_txt_item_copy(DnsTxtItem *i); diff --git a/src/resolve/test-dns-packet.c b/src/resolve/test-dns-packet.c index 47c7d671cd3..72b6d4a6576 100644 --- a/src/resolve/test-dns-packet.c +++ b/src/resolve/test-dns-packet.c @@ -90,6 +90,39 @@ static void test_packet_from_file(const char* filename, bool canonical) { } } +static void test_dns_resource_record_get_cname_target(void) { + _cleanup_(dns_resource_record_unrefp) DnsResourceRecord *cname = NULL; + _cleanup_free_ char *target = NULL; + + assert_se(cname = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_CNAME, "quux.foobar")); + assert_se(cname->cname.name = strdup("wuff.wuff")); + + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "waldo"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "foobar"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "quux"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, ""), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "."), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "nope.quux.foobar"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "quux.foobar"), cname, &target) == 0); + assert_se(streq(target, "wuff.wuff")); + target = mfree(target); + + assert_se(cname = dns_resource_record_new_full(DNS_CLASS_IN, DNS_TYPE_DNAME, "quux.foobar")); + assert_se(cname->dname.name = strdup("wuff.wuff")); + + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "waldo"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "foobar"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "quux"), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, ""), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "."), cname, &target) == -EUNATCH); + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "yupp.quux.foobar"), cname, &target) == 0); + assert_se(streq(target, "yupp.wuff.wuff")); + target = mfree(target); + + assert_se(dns_resource_record_get_cname_target(&DNS_RESOURCE_KEY_CONST(DNS_CLASS_IN, DNS_TYPE_A, "quux.foobar"), cname, &target) == 0); + assert_se(streq(target, "wuff.wuff")); +} + int main(int argc, char **argv) { int i, N; _cleanup_globfree_ glob_t g = {}; @@ -116,5 +149,7 @@ int main(int argc, char **argv) { puts(""); } + test_dns_resource_record_get_cname_target(); + return EXIT_SUCCESS; }