]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
IPv4: Remember if we advertised an address ip_share
authorRoy Marples <roy@marples.name>
Fri, 4 Oct 2024 08:16:59 +0000 (08:16 +0000)
committerRoy Marples <roy@marples.name>
Fri, 4 Oct 2024 08:16:59 +0000 (08:16 +0000)
Similar to IPv6.

However, this code will just live in this branch and go no futher
because it's not tennable. Modern DHCP servers won't let you
assign the same IP to different hardware addresses.
Some kernels announce ARP after a link flap giving a large window
where requests could goto a valid address but the wrong one.

What IP address sharing set out to achieve was a poor mans link
aggregation for OSs that lacked another way of doing it ....
Well, with NetBSD finally getting lagg(4), all supported OS's
now have this so there is no more need for it in dhcpcd.

src/arp.c
src/ipv4.c
src/ipv4.h
src/ipv6nd.c

index 7d0c8558faef5f17204d984bd708023f17f1a0a3..1a566f19d3261d6b8b019df55ba649c810db523d 100644 (file)
--- a/src/arp.c
+++ b/src/arp.c
@@ -519,9 +519,13 @@ struct arp_state *
 arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia)
 {
        struct arp_state *astate;
+       struct ipv4_addr *ia4;
 
        if (ifp->flags & IFF_NOARP || !(ifp->options->options & DHCPCD_ARP))
                return NULL;
+       ia4 = ipv4_iffindaddr(ifp, ia, NULL);
+       if (ia4->flags & IPV4_AF_ADVERTISED)
+               return NULL;
 
        astate = arp_find(ifp, ia);
        if (astate == NULL) {
@@ -530,6 +534,7 @@ arp_ifannounceaddr(struct interface *ifp, const struct in_addr *ia)
                        return NULL;
                astate->announced_cb = arp_free;
        }
+       ia4->flags |= IPV4_AF_ADVERTISED;
        arp_announce(astate);
        return astate;
 }
@@ -538,14 +543,15 @@ struct arp_state *
 arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
 {
        struct interface *ifp, *iff = NULL;
-       struct ipv4_addr *iap;
+       struct ipv4_addr *iap, *iaf = NULL;
 
        TAILQ_FOREACH(ifp, ctx->ifaces, next) {
-               if (!ifp->active || !if_is_link_up(ifp))
-                       continue;
                iap = ipv4_iffindaddr(ifp, ia, NULL);
                if (iap == NULL)
                        continue;
+
+               if (!ifp->active || !if_is_link_up(ifp))
+                       continue;
 #ifdef IN_IFF_NOTUSEABLE
                if (iap->addr_flags & IN_IFF_NOTUSEABLE)
                        continue;
@@ -553,11 +559,19 @@ arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
                if (iff != NULL && iff->metric < ifp->metric)
                        continue;
                iff = ifp;
+               iaf = iap;
        }
-       if (iff == NULL)
+       if (iaf == NULL || iaf->flags & IPV4_AF_ADVERTISED)
                return NULL;
 
-       return arp_ifannounceaddr(iff, ia);
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+               iap = ipv4_iffindaddr(ifp, ia, NULL);
+               if (iap == NULL)
+                       continue;
+               iap->flags &= ~IPV4_AF_ADVERTISED;
+       }
+
+       return arp_ifannounceaddr(iff, &iaf->addr);
 }
 
 struct arp_state *
index 4cd24a7d2543a96807a73280c1a80cbfd9ab1aac..3d5086f7041fe6a1bd8fa685ccbd30461c30beab 100644 (file)
@@ -760,7 +760,7 @@ ipv4_applyaddr(void *arg)
 #ifdef ARP
                                /* Announce the preferred address to
                                 * kick ARP caches. */
-                               arp_announceaddr(ifp->ctx,&lease->addr);
+                               arp_announceaddr(ifp->ctx, &lease->addr);
 #endif
                        }
                        script_runreason(ifp, state->reason);
@@ -965,6 +965,23 @@ ipv4_handleifa(struct dhcpcd_ctx *ctx,
                free(ia);
 }
 
+void
+ipv4_start(struct interface *ifp)
+{
+#ifdef ARP
+       struct ipv4_state *state;
+       struct ipv4_addr *ia;
+
+       if (ifp == NULL || (state = IPV4_STATE(ifp)) == NULL)
+               return;
+
+       /* Clear advertised */
+       TAILQ_FOREACH(ia, &state->addrs, next) {
+               ia->flags &= ~IPV4_AF_ADVERTISED;
+       }
+#endif
+}
+
 void
 ipv4_free(struct interface *ifp)
 {
index bce7a0cf18298aa7a2cc44bba23f5836e879c1b3..85bbdd28d6f64cc0cdd097f132fc8e99dc4cce7d 100644 (file)
@@ -105,6 +105,7 @@ TAILQ_HEAD(ipv4_addrhead, ipv4_addr);
 
 #define        IPV4_AF_STALE           (1U << 0)
 #define        IPV4_AF_NEW             (1U << 1)
+#define        IPV4_AF_ADVERTISED      (1U << 2)
 
 #define        IPV4_ADDR_EQ(a1, a2)    ((a1) && (a1)->addr.s_addr == (a2)->addr.s_addr)
 #define        IPV4_MASK1_EQ(a1, a2)   ((a1) && (a1)->mask.s_addr == (a2)->mask.s_addr)
index 49f425b765b96fa3cce02d0ec276f73333a391e7..f198079cf78820cc40464de0af6fe0ba53b9eff7 100644 (file)
@@ -514,7 +514,6 @@ ipv6nd_advertise(struct ipv6_addr *ia)
        struct interface *ifp;
        struct ipv6_state *state;
        struct ipv6_addr *iap, *iaf;
-       bool found_another = false;
        struct nd_neighbor_advert *na;
 
        if (IN6_IS_ADDR_MULTICAST(&ia->addr))
@@ -537,12 +536,10 @@ ipv6nd_advertise(struct ipv6_addr *ia)
                        if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
                                continue;
 
-                       if (iaf != NULL)
-                               found_another = true;
-
                        /* Don't advertise what we can't use. */
                        if (iap->prefix_vltime == 0 ||
                            iap->addr_flags & IN6_IFF_NOTUSEABLE ||
+                           !ifp->active ||
                            !if_is_link_up(ifp))
                                continue;
 
@@ -557,24 +554,19 @@ ipv6nd_advertise(struct ipv6_addr *ia)
                return;
 
        /* Now cancel any other advertisements for the same address. */
-       if (found_another) {
-               TAILQ_FOREACH(ifp, ctx->ifaces, next) {
-                       state = IPV6_STATE(ifp);
-                       if (state == NULL)
-                               continue;
+       TAILQ_FOREACH(ifp, ctx->ifaces, next) {
+               state = IPV6_STATE(ifp);
+               if (state == NULL)
+                       continue;
 
-                       TAILQ_FOREACH(iap, &state->addrs, next) {
-                               if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
-                                       continue;
+               TAILQ_FOREACH(iap, &state->addrs, next) {
+                       if (!IN6_ARE_ADDR_EQUAL(&iap->addr, &ia->addr))
+                               continue;
 
-                               iap->flags &= ~IPV6_AF_ADVERTISED;
-                               eloop_timeout_delete(ctx->eloop,
-                                   ipv6nd_sendadvertisement, iap);
-                       }
+                       iap->flags &= ~IPV6_AF_ADVERTISED;
+                       eloop_timeout_delete(ctx->eloop,
+                           ipv6nd_sendadvertisement, iap);
                }
-       } else {
-               eloop_timeout_delete(ctx->eloop,
-                   ipv6nd_sendadvertisement, iaf);
        }
 
        /* Make the packet. */