]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
network: read peer address, label, broadcast from rtnl message
authorYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 13 Oct 2020 05:53:46 +0000 (14:53 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 13 Oct 2020 11:30:35 +0000 (20:30 +0900)
Then, Address objects in Network and Link can be easily compared by
address_equal().

src/network/networkd-address.c
src/network/networkd-address.h
src/network/networkd-ndisc.c
src/network/test-network.c

index 5146aade714a8ac7d212139fe2014db38aab4c4d..930b6f1353f10d86718792b49d8eee4ce9f001ff 100644 (file)
@@ -135,20 +135,6 @@ Address *address_free(Address *address) {
         return mfree(address);
 }
 
-static uint32_t address_prefix(const Address *a) {
-        assert(a);
-
-        /* make sure we don't try to shift by 32.
-         * See ISO/IEC 9899:TC3 ยง 6.5.7.3. */
-        if (a->prefixlen == 0)
-                return 0;
-
-        if (a->in_addr_peer.in.s_addr != 0)
-                return be32toh(a->in_addr_peer.in.s_addr) >> (32 - a->prefixlen);
-        else
-                return be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
-}
-
 void address_hash_func(const Address *a, struct siphash *state) {
         assert(a);
 
@@ -156,16 +142,16 @@ void address_hash_func(const Address *a, struct siphash *state) {
 
         switch (a->family) {
         case AF_INET:
-                siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
-
-                /* peer prefix */
-                uint32_t prefix = address_prefix(a);
-                siphash24_compress(&prefix, sizeof(prefix), state);
+                siphash24_compress(&a->broadcast, sizeof(a->broadcast), state);
+                siphash24_compress_string(a->label, state);
 
                 _fallthrough_;
         case AF_INET6:
+                siphash24_compress(&a->prefixlen, sizeof(a->prefixlen), state);
                 /* local address */
                 siphash24_compress(&a->in_addr, FAMILY_ADDRESS_SIZE(a->family), state);
+                /* peer address */
+                siphash24_compress(&a->in_addr_peer, FAMILY_ADDRESS_SIZE(a->family), state);
 
                 break;
         default:
@@ -184,19 +170,25 @@ int address_compare_func(const Address *a1, const Address *a2) {
         switch (a1->family) {
         /* use the same notion of equality as the kernel does */
         case AF_INET:
-                r = CMP(a1->prefixlen, a2->prefixlen);
+                r = CMP(a1->broadcast.s_addr, a2->broadcast.s_addr);
                 if (r != 0)
                         return r;
 
-                uint32_t prefix1 = address_prefix(a1);
-                uint32_t prefix2 = address_prefix(a2);
-                r = CMP(prefix1, prefix2);
+                r = strcmp_ptr(a1->label, a2->label);
                 if (r != 0)
                         return r;
 
                 _fallthrough_;
         case AF_INET6:
-                return memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
+                r = CMP(a1->prefixlen, a2->prefixlen);
+                if (r != 0)
+                        return r;
+
+                r = memcmp(&a1->in_addr, &a2->in_addr, FAMILY_ADDRESS_SIZE(a1->family));
+                if (r != 0)
+                        return r;
+
+                return memcmp(&a1->in_addr_peer, &a2->in_addr_peer, FAMILY_ADDRESS_SIZE(a1->family));
         default:
                 /* treat any other address family as AF_UNSPEC */
                 return 0;
@@ -274,25 +266,22 @@ static int address_set_masquerade(Address *address, bool add) {
         return 0;
 }
 
-static int address_add_internal(Link *link, Set **addresses,
-                                int family,
-                                const union in_addr_union *in_addr,
-                                unsigned char prefixlen,
-                                Address **ret) {
+static int address_add_internal(Link *link, Set **addresses, const Address *in, Address **ret) {
         _cleanup_(address_freep) Address *address = NULL;
         int r;
 
         assert(link);
         assert(addresses);
-        assert(in_addr);
+        assert(in);
 
         r = address_new(&address);
         if (r < 0)
                 return r;
 
-        address->family = family;
-        address->in_addr = *in_addr;
-        address->prefixlen = prefixlen;
+        r = address_copy(address, in);
+        if (r < 0)
+                return r;
+
         /* Consider address tentative until we get the real flags from the kernel */
         address->flags = IFA_F_TENTATIVE;
 
@@ -310,18 +299,21 @@ static int address_add_internal(Link *link, Set **addresses,
         return 0;
 }
 
-static int address_add_foreign(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
-        return address_add_internal(link, &link->addresses_foreign, family, in_addr, prefixlen, ret);
+static int address_add_foreign(Link *link, const Address *in, Address **ret) {
+        return address_add_internal(link, &link->addresses_foreign, in, ret);
 }
 
-static int address_add(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret) {
+static int address_add(Link *link, const Address *in, Address **ret) {
         Address *address;
         int r;
 
-        r = address_get(link, family, in_addr, prefixlen, &address);
+        assert(link);
+        assert(in);
+
+        r = address_get(link, in, &address);
         if (r == -ENOENT) {
                 /* Address does not exist, create a new one */
-                r = address_add_internal(link, &link->addresses, family, in_addr, prefixlen, &address);
+                r = address_add_internal(link, &link->addresses, in, &address);
                 if (r < 0)
                         return r;
         } else if (r == 0) {
@@ -343,24 +335,19 @@ static int address_add(Link *link, int family, const union in_addr_union *in_add
         return 0;
 }
 
-static int address_update(
-                Address *address,
-                unsigned char flags,
-                unsigned char scope,
-                const struct ifa_cacheinfo *cinfo) {
-
+static int address_update(Address *address, const Address *src) {
         bool ready;
         int r;
 
         assert(address);
         assert(address->link);
-        assert(cinfo);
+        assert(src);
 
         ready = address_is_ready(address);
 
-        address->flags = flags;
-        address->scope = scope;
-        address->cinfo = *cinfo;
+        address->flags = src->flags;
+        address->scope = src->scope;
+        address->cinfo = src->cinfo;
 
         if (IN_SET(address->link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
                 return 0;
@@ -412,31 +399,20 @@ static int address_drop(Address *address) {
         return 0;
 }
 
-int address_get(Link *link,
-                int family,
-                const union in_addr_union *in_addr,
-                unsigned char prefixlen,
-                Address **ret) {
-
-        Address address, *existing;
+int address_get(Link *link, const Address *in, Address **ret) {
+        Address *existing;
 
         assert(link);
-        assert(in_addr);
-
-        address = (Address) {
-                .family = family,
-                .in_addr = *in_addr,
-                .prefixlen = prefixlen,
-        };
+        assert(in);
 
-        existing = set_get(link->addresses, &address);
+        existing = set_get(link->addresses, in);
         if (existing) {
                 if (ret)
                         *ret = existing;
                 return 1;
         }
 
-        existing = set_get(link->addresses_foreign, &address);
+        existing = set_get(link->addresses_foreign, in);
         if (existing) {
                 if (ret)
                         *ret = existing;
@@ -548,18 +524,6 @@ static bool link_is_static_address_configured(Link *link, Address *address) {
         ORDERED_HASHMAP_FOREACH(net_address, link->network->addresses_by_section)
                 if (address_equal(net_address, address))
                         return true;
-                else if (address->family == AF_INET6 && net_address->family == AF_INET6 &&
-                         in_addr_equal(AF_INET6, &address->in_addr, &net_address->in_addr_peer) > 0)
-                        /* When Peer= is set, then address_equal() in the above returns false, as
-                         * address->in_addr is the peer address. */
-                        return true;
-                else if (address->family == AF_INET && net_address->family == AF_INET &&
-                         in_addr_equal(AF_INET, &address->in_addr, &net_address->in_addr) > 0)
-                        /* Even if both in_addr elements are equivalent, address_equal() may return
-                         * false when Peer= is set, as Address object in Network contains the peer
-                         * address but Address stored in Link does not, and address_prefix() in
-                         * address_compare_func() may provide different prefix. */
-                        return true;
 
         return false;
 }
@@ -658,7 +622,7 @@ int link_drop_foreign_addresses(Link *link) {
                         continue;
 
                 if (link_is_static_address_configured(link, address)) {
-                        k = address_add(link, address->family, &address->in_addr, address->prefixlen, NULL);
+                        k = address_add(link, address, NULL);
                         if (k < 0) {
                                 log_link_error_errno(link, k, "Failed to add address: %m");
                                 if (r >= 0)
@@ -813,7 +777,7 @@ int address_configure(
         assert(callback);
 
         /* If this is a new address, then refuse adding more than the limit */
-        if (address_get(link, address->family, &address->in_addr, address->prefixlen, NULL) <= 0 &&
+        if (address_get(link, address, NULL) <= 0 &&
             set_size(link->addresses) >= ADDRESSES_PER_LINK_MAX)
                 return log_link_error_errno(link, SYNTHETIC_ERRNO(E2BIG),
                                             "Too many addresses are configured, refusing: %m");
@@ -883,14 +847,10 @@ int address_configure(
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not append IFA_CACHEINFO attribute: %m");
 
-        if (address->family == AF_INET6 && !in_addr_is_null(address->family, &address->in_addr_peer))
-                r = address_add(link, address->family, &address->in_addr_peer, address->prefixlen, &a);
-        else
-                r = address_add(link, address->family, &address->in_addr, address->prefixlen, &a);
+        r = address_add(link, address, &a);
         if (r < 0)
                 return log_link_error_errno(link, r, "Could not add address: %m");
 
-        a->scope = address->scope;
         r = address_set_masquerade(a, true);
         if (r < 0)
                 log_link_warning_errno(link, r, "Could not enable IP masquerading, ignoring: %m");
@@ -1034,11 +994,7 @@ int link_set_addresses(Link *link) {
         ORDERED_HASHMAP_FOREACH(ad, link->network->addresses_by_section) {
                 bool update;
 
-                if (ad->family == AF_INET6 && !in_addr_is_null(ad->family, &ad->in_addr_peer))
-                        update = address_get(link, ad->family, &ad->in_addr_peer, ad->prefixlen, NULL) > 0;
-                else
-                        update = address_get(link, ad->family, &ad->in_addr, ad->prefixlen, NULL) > 0;
-
+                update = address_get(link, ad, NULL) > 0;
                 r = static_address_configure(ad, link, update);
                 if (r < 0)
                         return r;
@@ -1087,16 +1043,16 @@ int link_set_addresses(Link *link) {
 }
 
 int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message, Manager *m) {
-        _cleanup_free_ char *buf = NULL;
+        _cleanup_(address_freep) Address *tmp = NULL;
+        _cleanup_free_ char *buf = NULL, *buf_peer = NULL;
         Link *link = NULL;
         uint16_t type;
-        unsigned char flags, prefixlen, scope;
-        union in_addr_union in_addr = IN_ADDR_NULL;
-        struct ifa_cacheinfo cinfo;
+        unsigned char flags;
         Address *address = NULL;
         char valid_buf[FORMAT_TIMESPAN_MAX];
         const char *valid_str = NULL;
-        int ifindex, family, r;
+        int ifindex, r;
+        bool has_peer = false;
 
         assert(rtnl);
         assert(message);
@@ -1137,22 +1093,26 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
                 return 0;
         }
 
-        r = sd_rtnl_message_addr_get_family(message, &family);
+        r = address_new(&tmp);
+        if (r < 0)
+                return log_oom();
+
+        r = sd_rtnl_message_addr_get_family(message, &tmp->family);
         if (r < 0) {
                 log_link_warning(link, "rtnl: received address message without family, ignoring.");
                 return 0;
-        } else if (!IN_SET(family, AF_INET, AF_INET6)) {
-                log_link_debug(link, "rtnl: received address message with invalid family '%i', ignoring.", family);
+        } else if (!IN_SET(tmp->family, AF_INET, AF_INET6)) {
+                log_link_debug(link, "rtnl: received address message with invalid family '%i', ignoring.", tmp->family);
                 return 0;
         }
 
-        r = sd_rtnl_message_addr_get_prefixlen(message, &prefixlen);
+        r = sd_rtnl_message_addr_get_prefixlen(message, &tmp->prefixlen);
         if (r < 0) {
                 log_link_warning_errno(link, r, "rtnl: received address message without prefixlen, ignoring: %m");
                 return 0;
         }
 
-        r = sd_rtnl_message_addr_get_scope(message, &scope);
+        r = sd_rtnl_message_addr_get_scope(message, &tmp->scope);
         if (r < 0) {
                 log_link_warning_errno(link, r, "rtnl: received address message without scope, ignoring: %m");
                 return 0;
@@ -1163,21 +1123,61 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
                 log_link_warning_errno(link, r, "rtnl: received address message without flags, ignoring: %m");
                 return 0;
         }
+        tmp->flags = flags;
 
-        switch (family) {
+        switch (tmp->family) {
         case AF_INET:
-                r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &in_addr.in);
+                r = sd_netlink_message_read_in_addr(message, IFA_LOCAL, &tmp->in_addr.in);
                 if (r < 0) {
                         log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
                         return 0;
                 }
 
+                r = sd_netlink_message_read_in_addr(message, IFA_ADDRESS, &tmp->in_addr_peer.in);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: could not get peer address from address message, ignoring: %m");
+                        return 0;
+                } else if (r >= 0) {
+                        if (in4_addr_equal(&tmp->in_addr.in, &tmp->in_addr_peer.in))
+                                tmp->in_addr_peer = IN_ADDR_NULL;
+                        else
+                                has_peer = true;
+                }
+
+                r = sd_netlink_message_read_in_addr(message, IFA_BROADCAST, &tmp->broadcast);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: could not get broadcast from address message, ignoring: %m");
+                        return 0;
+                }
+
+                r = sd_netlink_message_read_string_strdup(message, IFA_LABEL, &tmp->label);
+                if (r < 0 && r != -ENODATA) {
+                        log_link_warning_errno(link, r, "rtnl: could not get label from address message, ignoring: %m");
+                        return 0;
+                } else if (r >= 0 && streq_ptr(tmp->label, link->ifname))
+                        tmp->label = mfree(tmp->label);
+
                 break;
 
         case AF_INET6:
-                r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &in_addr.in6);
-                if (r < 0) {
-                        log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
+                r = sd_netlink_message_read_in6_addr(message, IFA_LOCAL, &tmp->in_addr.in6);
+                if (r >= 0) {
+                        /* Have peer address. */
+                        r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &tmp->in_addr_peer.in6);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "rtnl: could not get peer address from address message, ignoring: %m");
+                                return 0;
+                        }
+                        has_peer = true;
+                } else if (r == -ENODATA) {
+                        /* Does not have peer address. */
+                        r = sd_netlink_message_read_in6_addr(message, IFA_ADDRESS, &tmp->in_addr.in6);
+                        if (r < 0) {
+                                log_link_warning_errno(link, r, "rtnl: received address message without valid address, ignoring: %m");
+                                return 0;
+                        }
+                } else {
+                        log_link_warning_errno(link, r, "rtnl: could not get local address from address message, ignoring: %m");
                         return 0;
                 }
 
@@ -1187,40 +1187,43 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
                 assert_not_reached("Received unsupported address family");
         }
 
-        (void) in_addr_to_string(family, &in_addr, &buf);
+        (void) in_addr_to_string(tmp->family, &tmp->in_addr, &buf);
+        (void) in_addr_to_string(tmp->family, &tmp->in_addr_peer, &buf_peer);
 
-        r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &cinfo);
+        r = sd_netlink_message_read_cache_info(message, IFA_CACHEINFO, &tmp->cinfo);
         if (r < 0 && r != -ENODATA) {
                 log_link_warning_errno(link, r, "rtnl: cannot get IFA_CACHEINFO attribute, ignoring: %m");
                 return 0;
-        } else if (r >= 0 && cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
+        } else if (r >= 0 && tmp->cinfo.ifa_valid != CACHE_INFO_INFINITY_LIFE_TIME)
                 valid_str = format_timespan(valid_buf, FORMAT_TIMESPAN_MAX,
-                                            cinfo.ifa_valid * USEC_PER_SEC,
+                                            tmp->cinfo.ifa_valid * USEC_PER_SEC,
                                             USEC_PER_SEC);
 
-        (void) address_get(link, family, &in_addr, prefixlen, &address);
+        (void) address_get(link, tmp, &address);
 
         switch (type) {
         case RTM_NEWADDR:
                 if (address)
-                        log_link_debug(link, "Remembering updated address: %s/%u (valid %s%s)",
-                                       strnull(buf), prefixlen,
+                        log_link_debug(link, "Remembering updated address: %s%s%s/%u (valid %s%s)",
+                                       strnull(buf), has_peer ? " peer " : "",
+                                       has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
                                        valid_str ? "for " : "forever", strempty(valid_str));
                 else {
                         /* An address appeared that we did not request */
-                        r = address_add_foreign(link, family, &in_addr, prefixlen, &address);
+                        r = address_add_foreign(link, tmp, &address);
                         if (r < 0) {
                                 log_link_warning_errno(link, r, "Failed to remember foreign address %s/%u, ignoring: %m",
-                                                       strnull(buf), prefixlen);
+                                                       strnull(buf), tmp->prefixlen);
                                 return 0;
                         } else
-                                log_link_debug(link, "Remembering foreign address: %s/%u (valid %s%s)",
-                                               strnull(buf), prefixlen,
+                                log_link_debug(link, "Remembering foreign address: %s%s%s/%u (valid %s%s)",
+                                               strnull(buf), has_peer ? " peer " : "",
+                                               has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
                                                valid_str ? "for " : "forever", strempty(valid_str));
                 }
 
                 /* address_update() logs internally, so we don't need to here. */
-                r = address_update(address, flags, scope, &cinfo);
+                r = address_update(address, tmp);
                 if (r < 0)
                         link_enter_failed(link);
 
@@ -1228,13 +1231,15 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
 
         case RTM_DELADDR:
                 if (address) {
-                        log_link_debug(link, "Forgetting address: %s/%u (valid %s%s)",
-                                       strnull(buf), prefixlen,
+                        log_link_debug(link, "Forgetting address: %s%s%s/%u (valid %s%s)",
+                                       strnull(buf), has_peer ? " peer " : "",
+                                       has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
                                        valid_str ? "for " : "forever", strempty(valid_str));
                         (void) address_drop(address);
                 } else
-                        log_link_debug(link, "Kernel removed an address we don't remember: %s/%u (valid %s%s), ignoring.",
-                                       strnull(buf), prefixlen,
+                        log_link_debug(link, "Kernel removed an address we don't remember: %s%s%s/%u (valid %s%s), ignoring.",
+                                       strnull(buf), has_peer ? " peer " : "",
+                                       has_peer ? strnull(buf_peer) : "", tmp->prefixlen,
                                        valid_str ? "for " : "forever", strempty(valid_str));
 
                 break;
@@ -1273,11 +1278,8 @@ int link_deserialize_addresses(Link *link, const char *addresses) {
         assert(link);
 
         for (const char *p = addresses;; ) {
+                _cleanup_(address_freep) Address *tmp = NULL;
                 _cleanup_free_ char *address_str = NULL;
-                union in_addr_union address;
-                unsigned char prefixlen;
-                char *prefixlen_str;
-                int family;
 
                 r = extract_first_word(&p, &address_str, NULL, 0);
                 if (r < 0)
@@ -1285,28 +1287,19 @@ int link_deserialize_addresses(Link *link, const char *addresses) {
                 if (r == 0)
                         return 0;
 
-                prefixlen_str = strchr(address_str, '/');
-                if (!prefixlen_str) {
-                        log_link_debug(link, "Failed to parse address and prefix length, ignoring: %s", address_str);
-                        continue;
-                }
-                *prefixlen_str++ = '\0';
-
-                r = sscanf(prefixlen_str, "%hhu", &prefixlen);
-                if (r != 1) {
-                        log_link_debug(link, "Failed to parse prefixlen: %s", prefixlen_str);
-                        continue;
-                }
+                r = address_new(&tmp);
+                if (r < 0)
+                        return log_oom();
 
-                r = in_addr_from_string_auto(address_str, &family, &address);
+                r = in_addr_prefix_from_string_auto(address_str, &tmp->family, &tmp->in_addr, &tmp->prefixlen);
                 if (r < 0) {
-                        log_link_debug_errno(link, r, "Failed to parse address: %s", address_str);
+                        log_link_debug_errno(link, r, "Failed to parse address, ignoring: %s", address_str);
                         continue;
                 }
 
-                r = address_add(link, family, &address, prefixlen, NULL);
+                r = address_add(link, tmp, NULL);
                 if (r < 0)
-                        log_link_debug_errno(link, r, "Failed to add address: %m");
+                        log_link_debug_errno(link, r, "Failed to add address %s, ignoring: %m", address_str);
         }
 
         return 0;
@@ -1589,9 +1582,6 @@ int config_parse_address(
         else
                 n->in_addr_peer = buffer;
 
-        if (n->family == AF_INET && n->broadcast.s_addr == 0 && n->prefixlen <= 30)
-                n->broadcast.s_addr = n->in_addr.in.s_addr | htobe32(0xfffffffflu >> n->prefixlen);
-
         n = NULL;
 
         return 0;
@@ -1863,6 +1853,25 @@ static int address_section_verify(Address *address) {
                                          address->section->filename, address->section->line);
         }
 
+        if (address->family == AF_INET && in_addr_is_null(address->family, &address->in_addr_peer) &&
+            address->broadcast.s_addr == 0 && address->prefixlen <= 30)
+                address->broadcast.s_addr = address->in_addr.in.s_addr | htobe32(0xfffffffflu >> address->prefixlen);
+        else if (address->broadcast.s_addr != 0) {
+                log_warning("%s: broadcast address is set for IPv6 address or IPv4 address with prefixlength larger than 30. "
+                            "Ignoring Broadcast= setting in the [Address] section from line %u.",
+                            address->section->filename, address->section->line);
+
+                address->broadcast.s_addr = 0;
+        }
+
+        if (address->family == AF_INET6 && address->label) {
+                log_warning("%s: address label is set for IPv6 address in the [Address] section from line %u. "
+                            "Ignoring Label= setting.",
+                            address->section->filename, address->section->line);
+
+                address->label = mfree(address->label);
+        }
+
         if (in_addr_is_localhost(address->family, &address->in_addr) > 0 &&
             (address->family == AF_INET || !address->scope_set)) {
                 /* For IPv4, scope must be always RT_SCOPE_HOST.
index d12120f00d2aad215224068ff26f814d2ddde500..dbbfb50fd7ece2862d57aecf25e38babbd9957e2 100644 (file)
@@ -48,7 +48,7 @@ typedef struct Address {
 
 int address_new(Address **ret);
 Address *address_free(Address *address);
-int address_get(Link *link, int family, const union in_addr_union *in_addr, unsigned char prefixlen, Address **ret);
+int address_get(Link *link, const Address *in, Address **ret);
 bool address_exists(Link *link, int family, const union in_addr_union *in_addr);
 int address_configure(Address *address, Link *link, link_netlink_message_handler_t callback, bool update, Address **ret);
 int address_remove(Address *address, Link *link, link_netlink_message_handler_t callback);
index d0e426f2315ff7be4c89cc3a57a07b203ea1606a..c67dd7d88ed5ad012b9bc108c64c49d65d87801e 100644 (file)
@@ -725,8 +725,10 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
         SET_FOREACH(a, addresses) {
                 Address *existing_address;
 
+                address->in_addr.in6 = *a;
+
                 /* see RFC4862 section 5.5.3.e */
-                r = address_get(link, AF_INET6, (union in_addr_union *) a, prefixlen, &existing_address);
+                r = address_get(link, address, &existing_address);
                 if (r > 0) {
                         lifetime_remaining = existing_address->cinfo.tstamp / 100 + existing_address->cinfo.ifa_valid - time_now / USEC_PER_SEC;
                         if (lifetime_valid > NDISC_PREFIX_LFT_MIN || lifetime_valid > lifetime_remaining)
@@ -743,8 +745,6 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
                 if (address->cinfo.ifa_valid == 0)
                         continue;
 
-                address->in_addr.in6 = *a;
-
                 r = ndisc_address_configure(address, link, rt);
                 if (r < 0)
                         return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
index e93e8c0cc094089cd7ba6ce6695fa17be53f3f2e..f6168fc3fa47484fd38ff78a1aad212838b7e07c 100644 (file)
@@ -159,8 +159,10 @@ static void test_address_equality(void) {
         assert_se(in_addr_from_string(AF_INET, "192.168.3.9", &a2->in_addr) >= 0);
         assert_se(address_equal(a1, a2));
         assert_se(in_addr_from_string(AF_INET, "192.168.3.10", &a1->in_addr_peer) >= 0);
-        assert_se(address_equal(a1, a2));
+        assert_se(!address_equal(a1, a2));
         assert_se(in_addr_from_string(AF_INET, "192.168.3.11", &a2->in_addr_peer) >= 0);
+        assert_se(!address_equal(a1, a2));
+        a2->in_addr_peer = a1->in_addr_peer;
         assert_se(address_equal(a1, a2));
         a1->prefixlen = 10;
         assert_se(!address_equal(a1, a2));
@@ -171,10 +173,13 @@ static void test_address_equality(void) {
         assert_se(!address_equal(a1, a2));
 
         a2->family = AF_INET6;
+        a1->in_addr_peer = a2->in_addr_peer = IN_ADDR_NULL;
         assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::2", &a1->in_addr) >= 0);
         assert_se(in_addr_from_string(AF_INET6, "2001:4ca0:4f01::2", &a2->in_addr) >= 0);
         assert_se(address_equal(a1, a2));
 
+        a1->prefixlen = 8;
+        assert_se(!address_equal(a1, a2));
         a2->prefixlen = 8;
         assert_se(address_equal(a1, a2));