From: Roy Marples Date: Fri, 4 Oct 2024 08:16:59 +0000 (+0000) Subject: IPv4: Remember if we advertised an address X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fip_share;p=thirdparty%2Fdhcpcd.git IPv4: Remember if we advertised an address 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. --- diff --git a/src/arp.c b/src/arp.c index 7d0c8558..1a566f19 100644 --- 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 * diff --git a/src/ipv4.c b/src/ipv4.c index 4cd24a7d..3d5086f7 100644 --- a/src/ipv4.c +++ b/src/ipv4.c @@ -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) { diff --git a/src/ipv4.h b/src/ipv4.h index bce7a0cf..85bbdd28 100644 --- a/src/ipv4.h +++ b/src/ipv4.h @@ -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) diff --git a/src/ipv6nd.c b/src/ipv6nd.c index 49f425b7..f198079c 100644 --- a/src/ipv6nd.c +++ b/src/ipv6nd.c @@ -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. */