resolved: keep track of first names listed for each address in /etc/hosts

These names will be used later in responses as canonical names.
This commit is contained in:
Dmitry V. Levin 2023-07-09 08:00:00 +00:00
parent 0865c465ca
commit 1bd76a6217
3 changed files with 33 additions and 3 deletions

View File

@ -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)

View File

@ -8,6 +8,7 @@
typedef struct EtcHostsItemByAddress {
struct in_addr_data address;
Set *names;
const char *canonical_name;
} EtcHostsItemByAddress;
typedef struct EtcHostsItemByName {

View File

@ -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"));