]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: keep track of first names listed for each address in /etc/hosts
authorDmitry V. Levin <ldv@strace.io>
Sun, 9 Jul 2023 08:00:00 +0000 (08:00 +0000)
committerDmitry V. Levin <ldv@strace.io>
Fri, 14 Jul 2023 13:13:53 +0000 (13:13 +0000)
These names will be used later in responses as canonical names.

src/resolve/resolved-etc-hosts.c
src/resolve/resolved-etc-hosts.h
src/resolve/test-resolved-etc-hosts.c

index 6acae48c2ba2e947ffaa73ac000df066844f8e2b..aac7d986ba028e86a1aaf26ba0a56123c322a33b 100644 (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)
index e1a7249f29866344239e35b8da353e50cbec3e29..805a09bb6d6fa80dc3f447fd0d62abae395e984a 100644 (file)
@@ -8,6 +8,7 @@
 typedef struct EtcHostsItemByAddress {
         struct in_addr_data address;
         Set *names;
+        const char *canonical_name;
 } EtcHostsItemByAddress;
 
 typedef struct EtcHostsItemByName {
index d46dbd30009d5dc831946ef94c46c7af6b9d7e9b..75f7db34828db360f1dc0d8c506008a2652fd846 100644 (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"));