From: Dmitry V. Levin Date: Sun, 9 Jul 2023 08:00:00 +0000 (+0000) Subject: resolved: keep track of first names listed for each address in /etc/hosts X-Git-Tag: v254-rc2~11^2~2 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=1bd76a6217c0cd81972cd50b360cd5b8aa27f0ff;p=thirdparty%2Fsystemd.git resolved: keep track of first names listed for each address in /etc/hosts These names will be used later in responses as canonical names. --- diff --git a/src/resolve/resolved-etc-hosts.c b/src/resolve/resolved-etc-hosts.c index 6acae48c2ba..aac7d986ba0 100644 --- a/src/resolve/resolved-etc-hosts.c +++ b/src/resolve/resolved-etc-hosts.c @@ -189,9 +189,18 @@ static int parse_line(EtcHosts *hosts, unsigned nr, const char *line) { return log_oom(); } - r = set_ensure_consume(&item->names, &dns_name_hash_ops_free, TAKE_PTR(name)); + r = set_ensure_put(&item->names, &dns_name_hash_ops_free, name); if (r < 0) return log_oom(); + if (r == 0) /* the name is already listed */ + continue; + /* + * Keep track of the first name listed for this address. + * This name will be used in responses as the canonical name. + */ + if (!item->canonical_name) + item->canonical_name = name; + TAKE_PTR(name); } if (!found) diff --git a/src/resolve/resolved-etc-hosts.h b/src/resolve/resolved-etc-hosts.h index e1a7249f298..805a09bb6d6 100644 --- a/src/resolve/resolved-etc-hosts.h +++ b/src/resolve/resolved-etc-hosts.h @@ -8,6 +8,7 @@ typedef struct EtcHostsItemByAddress { struct in_addr_data address; Set *names; + const char *canonical_name; } EtcHostsItemByAddress; typedef struct EtcHostsItemByName { diff --git a/src/resolve/test-resolved-etc-hosts.c b/src/resolve/test-resolved-etc-hosts.c index d46dbd30009..75f7db34828 100644 --- a/src/resolve/test-resolved-etc-hosts.c +++ b/src/resolve/test-resolved-etc-hosts.c @@ -27,11 +27,17 @@ TEST(parse_etc_hosts_system) { assert_se(etc_hosts_parse(&hosts, f) == 0); } +#define in_addr_4(_address_str) \ + (&(struct in_addr_data) { .family = AF_INET, .address.in = { .s_addr = inet_addr(_address_str) } }) + +#define in_addr_6(...) \ + (&(struct in_addr_data) { .family = AF_INET6, .address.in6 = { .s6_addr = __VA_ARGS__ } }) + #define has_4(_set, _address_str) \ - set_contains(_set, &(struct in_addr_data) { .family = AF_INET, .address.in = { .s_addr = inet_addr(_address_str) } }) + set_contains(_set, in_addr_4(_address_str)) #define has_6(_set, ...) \ - set_contains(_set, &(struct in_addr_data) { .family = AF_INET6, .address.in6 = { .s6_addr = __VA_ARGS__ } }) + set_contains(_set, in_addr_6(__VA_ARGS__)) TEST(parse_etc_hosts) { _cleanup_(unlink_tempfilep) char @@ -110,6 +116,20 @@ TEST(parse_etc_hosts) { assert_se(set_size(bn->addresses) == 1); assert_se(has_6(bn->addresses, {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5})); + EtcHostsItemByAddress *ba; + assert_se(ba = hashmap_get(hosts.by_address, in_addr_4("1.2.3.6"))); + assert_se(set_size(ba->names) == 2); + assert_se(set_contains(ba->names, "dash")); + assert_se(set_contains(ba->names, "dash-dash.where-dash")); + assert_se(streq(ba->canonical_name, "dash")); + + assert_se(ba = hashmap_get(hosts.by_address, in_addr_6({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5}))); + assert_se(set_size(ba->names) == 3); + assert_se(set_contains(ba->names, "some.where")); + assert_se(set_contains(ba->names, "some.other")); + assert_se(set_contains(ba->names, "foobar.foo.foo")); + assert_se(streq(ba->canonical_name, "some.where")); + assert_se( set_contains(hosts.no_address, "some.where")); assert_se( set_contains(hosts.no_address, "some.other")); assert_se( set_contains(hosts.no_address, "deny.listed"));