]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
dhcpcd: remove advertisement of addresses
authorRoy Marples <roy@marples.name>
Fri, 4 Oct 2024 15:36:01 +0000 (15:36 +0000)
committerRoy Marples <roy@marples.name>
Fri, 4 Oct 2024 15:36:01 +0000 (15:36 +0000)
Address advertisemnt was used to allow IP address sharing to work.
It also required the DHCP server to allow the same IP for many
hosts, which modern DHCP servers deny you from doing.
Lastly, there are niggles with the implementation that are
impossible to fully fix due to how the various protocols work,
especially ARP.

All platforms dhcpcd supports allow better ways of doing this,
such as bonding (Linux), trunk(4) (OpenBSD), lagg(4) (Other BSDs).

ARP advertisements will only be made when addresses are added
OR defended against for kernels without RFC 5227 support.

src/arp.c
src/dhcp.c
src/dhcp6.c
src/ipv4.c
src/ipv4ll.c
src/ipv6.c
src/ipv6.h
src/ipv6nd.c

index 7d0c8558faef5f17204d984bd708023f17f1a0a3..b1c7952de6fbf693a2ba6e672a58974faab9821b 100644 (file)
--- a/src/arp.c
+++ b/src/arp.c
@@ -238,7 +238,6 @@ arp_packet(struct interface *ifp, uint8_t *data, size_t len,
     unsigned int bpf_flags)
 {
        size_t fl = bpf_frame_header_len(ifp), falen;
-       const struct interface *ifn;
        struct arphdr ar;
        struct arp_msg arm;
        const struct iarp_state *state;
@@ -282,12 +281,9 @@ arp_packet(struct interface *ifp, uint8_t *data, size_t len,
        if ((size_t)((hw_t + ar.ar_hln + ar.ar_pln) - data) > len)
                return;
        /* Ignore messages from ourself */
-       TAILQ_FOREACH(ifn, ifp->ctx->ifaces, next) {
-               if (ar.ar_hln == ifn->hwlen &&
-                   memcmp(hw_s, ifn->hwaddr, ifn->hwlen) == 0)
-                       break;
-       }
-       if (ifn) {
+       if (ar.ar_hln == ifp->hwlen &&
+           memcmp(hw_s, ifp->hwaddr, ifp->hwlen) == 0)
+       {
 #ifdef ARP_DEBUG
                logdebugx("%s: ignoring ARP from self", ifp->name);
 #endif
@@ -424,6 +420,7 @@ out:
        return NULL;
 }
 
+#ifndef KERNEL_RFC5227
 static void
 arp_announced(void *arg)
 {
@@ -559,6 +556,7 @@ arp_announceaddr(struct dhcpcd_ctx *ctx, const struct in_addr *ia)
 
        return arp_ifannounceaddr(iff, ia);
 }
+#endif
 
 struct arp_state *
 arp_new(struct interface *ifp, const struct in_addr *addr)
index 262dfa89db2cb16074aefe9a721a42e1d483f810..2dbdfe5fab0490dd0528793b66cf772c8d731f1c 100644 (file)
@@ -2670,43 +2670,11 @@ dhcp_reboot_newopts(struct interface *ifp, unsigned long long oldopts)
        }
 }
 
-#ifdef ARP
-static int
-dhcp_activeaddr(const struct interface *ifp, const struct in_addr *addr)
-{
-       const struct interface *ifp1;
-       const struct dhcp_state *state;
-
-       TAILQ_FOREACH(ifp1, ifp->ctx->ifaces, next) {
-               if (ifp1 == ifp)
-                       continue;
-               if ((state = D_CSTATE(ifp1)) == NULL)
-                       continue;
-               switch(state->state) {
-               case DHS_REBOOT:
-               case DHS_RENEW:
-               case DHS_REBIND:
-               case DHS_BOUND:
-               case DHS_INFORM:
-                       break;
-               default:
-                       continue;
-               }
-               if (state->lease.addr.s_addr == addr->s_addr)
-                       return 1;
-       }
-       return 0;
-}
-#endif
-
 static void
 dhcp_reboot(struct interface *ifp)
 {
        struct if_options *ifo;
        struct dhcp_state *state = D_STATE(ifp);
-#ifdef ARP
-       struct ipv4_addr *ia;
-#endif
 
        if (state == NULL || state->state == DHS_NONE)
                return;
@@ -2738,25 +2706,11 @@ dhcp_reboot(struct interface *ifp)
        loginfox("%s: rebinding lease of %s",
            ifp->name, inet_ntoa(state->lease.addr));
 
-#ifdef ARP
-#ifndef KERNEL_RFC5227
+#if defined(ARP) && !defined(KERNEL_RFC5227)
        /* Create the DHCP ARP state so we can defend it. */
        (void)dhcp_arp_new(ifp, &state->lease.addr);
 #endif
 
-       /* If the address exists on the interface and no other interface
-        * is currently using it then announce it to ensure this
-        * interface gets the reply. */
-       ia = ipv4_iffindaddr(ifp, &state->lease.addr, NULL);
-       if (ia != NULL &&
-           !(ifp->ctx->options & DHCPCD_TEST) &&
-#ifdef IN_IFF_NOTUSEABLE
-           !(ia->addr_flags & IN_IFF_NOTUSEABLE) &&
-#endif
-           dhcp_activeaddr(ifp, &state->lease.addr) == 0)
-               arp_ifannounceaddr(ifp, &state->lease.addr);
-#endif
-
        dhcp_new_xid(ifp);
        state->lease.server.s_addr = INADDR_ANY;
        eloop_timeout_delete(ifp->ctx->eloop, NULL, ifp);
@@ -4233,13 +4187,8 @@ dhcp_abort(struct interface *ifp)
 
        eloop_timeout_delete(ifp->ctx->eloop, dhcp_start1, ifp);
 
-       if (state != NULL && state->added) {
+       if (state != NULL && state->added)
                rt_build(ifp->ctx, AF_INET);
-#ifdef ARP
-               if (ifp->options->options & DHCPCD_ARP)
-                       arp_announceaddr(ifp->ctx, &state->addr->addr);
-#endif
-       }
 }
 
 struct ipv4_addr *
index 61acd994baefe8ef1f7a2b35ae803c6fc9982a3f..ee24b23312c68eee219d9c0de2108ba84078e55a 100644 (file)
@@ -1573,10 +1573,6 @@ dhcp6_dadcallback(void *arg)
        if (ia->addr_flags & IN6_IFF_DUPLICATED)
                logwarnx("%s: DAD detected %s", ia->iface->name, ia->saddr);
 
-#ifdef ND6_ADVERTISE
-       else
-               ipv6nd_advertise(ia);
-#endif
        if (completed)
                return;
 
@@ -4194,21 +4190,12 @@ void
 dhcp6_abort(struct interface *ifp)
 {
        struct dhcp6_state *state;
-#ifdef ND6_ADVERTISE
-       struct ipv6_addr *ia;
-#endif
 
        eloop_timeout_delete(ifp->ctx->eloop, dhcp6_start1, ifp);
        state = D6_STATE(ifp);
        if (state == NULL)
                return;
 
-#ifdef ND6_ADVERTISE
-       TAILQ_FOREACH(ia, &state->addrs, next) {
-               ipv6nd_advertise(ia);
-       }
-#endif
-
        eloop_timeout_delete(ifp->ctx->eloop, dhcp6_startdiscover, ifp);
        eloop_timeout_delete(ifp->ctx->eloop, dhcp6_senddiscover, ifp);
        eloop_timeout_delete(ifp->ctx->eloop, dhcp6_startinform, ifp);
index 4cd24a7d2543a96807a73280c1a80cbfd9ab1aac..69e0dab8a3f198a3f2354e4a06bc9a6121db9c1a 100644 (file)
@@ -757,11 +757,6 @@ ipv4_applyaddr(void *arg)
                        if (state->added) {
                                ipv4_deladdr(state->addr, 0);
                                rt_build(ifp->ctx, AF_INET);
-#ifdef ARP
-                               /* Announce the preferred address to
-                                * kick ARP caches. */
-                               arp_announceaddr(ifp->ctx,&lease->addr);
-#endif
                        }
                        script_runreason(ifp, state->reason);
                } else
@@ -822,10 +817,6 @@ ipv4_applyaddr(void *arg)
 
        rt_build(ifp->ctx, AF_INET);
 
-#ifdef ARP
-       arp_announceaddr(ifp->ctx, &state->addr->addr);
-#endif
-
        if (state->state == DHS_BOUND) {
                script_runreason(ifp, state->reason);
                dhcpcd_daemonise(ifp->ctx);
index 0744447a7d4fdfab773d07f45c8c5e14fc02e4f9..ebe8aae06083a1cef1351847db359b8fd0dd5c6f 100644 (file)
@@ -175,6 +175,7 @@ ipv4ll_env(FILE *fp, const char *prefix, const struct interface *ifp)
        return 5;
 }
 
+#ifndef KERNEL_RFC5227
 static void
 ipv4ll_announced_arp(struct arp_state *astate)
 {
@@ -186,7 +187,6 @@ ipv4ll_announced_arp(struct arp_state *astate)
 #endif
 }
 
-#ifndef KERNEL_RFC5227
 /* This is the callback by ARP freeing */
 static void
 ipv4ll_free_arp(struct arp_state *astate)
@@ -221,7 +221,9 @@ ipv4ll_not_found(struct interface *ifp)
 {
        struct ipv4ll_state *state;
        struct ipv4_addr *ia;
+#ifndef KERNEL_RFC5227
        struct arp_state *astate;
+#endif
 
        state = IPV4LL_STATE(ifp);
        ia = ipv4_iffindaddr(ifp, &state->pickedaddr, &inaddr_llmask);
@@ -265,9 +267,11 @@ ipv4ll_not_found(struct interface *ifp)
        }
        rt_build(ifp->ctx, AF_INET);
 
+#ifndef KERNEL_RFC5227
        astate = arp_announceaddr(ifp->ctx, &ia->addr);
        if (astate != NULL)
                astate->announced_cb = ipv4ll_announced_arp;
+#endif
        script_runreason(ifp, "IPV4LL");
        dhcpcd_daemonise(ifp->ctx);
 }
index 52a3c88a014f0c0b08f34db9df7cd0f58861d850..7e2f0bb1c826fd0d19bc9bf16b734eb5cd8aa521 100644 (file)
@@ -653,11 +653,6 @@ ipv6_deleteaddr(struct ipv6_addr *ia)
                        break;
                }
        }
-
-#ifdef ND6_ADVERTISE
-       /* Advertise the address if it exists on another interface. */
-       ipv6nd_advertise(ia);
-#endif
 }
 
 static int
@@ -668,9 +663,6 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
        int loglevel;
        struct ipv6_state *state;
        struct ipv6_addr *ia2;
-#ifdef ND6_ADVERTISE
-       bool vltime_was_zero = ia->prefix_vltime == 0;
-#endif
 
 #ifdef __sun
        /* If we re-add then address on Solaris then the prefix
@@ -679,11 +671,7 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
        if (ia->flags & IPV6_AF_DADCOMPLETED) {
                logdebugx("%s: IP address %s already exists",
                    ia->iface->name, ia->saddr);
-#ifdef ND6_ADVERTISE
-               goto advertise;
-#else
                return 0;
-#endif
        }
 #endif
 
@@ -805,19 +793,12 @@ ipv6_addaddr1(struct ipv6_addr *ia, const struct timespec *now)
        if (ia2 == NULL) {
                if ((ia2 = malloc(sizeof(*ia2))) == NULL) {
                        logerr(__func__);
-                       goto advertise; /* Well, we did add the address */
+                       return 0; /* Well, we did add the address */
                }
                memcpy(ia2, ia, sizeof(*ia2));
                TAILQ_INSERT_TAIL(&state->addrs, ia2, next);
        }
 
-advertise:
-#ifdef ND6_ADVERTISE
-       /* Re-advertise the preferred address to be safe. */
-       if (!vltime_was_zero)
-               ipv6nd_advertise(ia);
-#endif
-
        return 0;
 }
 
@@ -1224,11 +1205,6 @@ ipv6_handleifa(struct dhcpcd_ctx *ctx,
        case RTM_DELADDR:
                if (ia != NULL) {
                        TAILQ_REMOVE(&state->addrs, ia, next);
-#ifdef ND6_ADVERTISE
-                       /* Advertise the address if it exists on
-                        * another interface. */
-                       ipv6nd_advertise(ia);
-#endif
                        /* We'll free it at the end of the function. */
                }
                break;
@@ -1832,19 +1808,16 @@ ipv6_startstatic(struct interface *ifp)
 int
 ipv6_start(struct interface *ifp)
 {
-#if defined(ND6_ADVERTISE) || defined(IPV6_POLLADDRFLAG)
+#ifdef IPV6_POLLADDRFLAG
        struct ipv6_state *state;
 
        /* We need to update the address flags. */
        if ((state = IPV6_STATE(ifp)) != NULL) {
                struct ipv6_addr *ia;
-#ifdef IPV6_POLLADDRFLAG
                const char *alias;
                int flags;
-#endif
 
                TAILQ_FOREACH(ia, &state->addrs, next) {
-#ifdef IPV6_POLLADDRFLAG
 #ifdef ALIAS_ADDR
                        alias = ia->alias;
 #else
@@ -1853,9 +1826,6 @@ ipv6_start(struct interface *ifp)
                        flags = if_addrflags6(ia->iface, &ia->addr, alias);
                        if (flags != -1)
                                ia->addr_flags = flags;
-#endif
-                       /* hwaddr could have changed */
-                       ia->flags &= ~IPV6_AF_ADVERTISED;
                }
        }
 #endif
index 2a93727a00e7f9a789dceced3ed7a08fe95748f1..6351cd4c01461fb50ef4504db78ca53d3853159e 100644 (file)
 #  define IN6_IFF_DETACHED     0
 #endif
 
-/*
- * ND6 Advertising is only used for IP address sharing to prefer
- * the address on a specific interface or when the hardware address
- * of the interface changes.
- * This just fails to work on OpenBSD and causes erroneous duplicate
- * address messages on BSD's other then DragonFly and NetBSD.
- */
-#if !defined(SMALL) && \
-    ((defined(__DragonFly_version) && __DragonFly_version >= 500703) || \
-    (defined(__NetBSD_Version__) && __NetBSD_Version__ >= 899002800) || \
-    defined(__linux__) || defined(__sun))
-#  define ND6_ADVERTISE
-#endif
-
 #ifdef INET6
 TAILQ_HEAD(ipv6_addrhead, ipv6_addr);
 struct ipv6_addr {
index 49f425b765b96fa3cce02d0ec276f73333a391e7..cc42c5695eb1440f9b024617e2526407c544dd0f 100644 (file)
@@ -434,191 +434,6 @@ sent:
                logwarnx("%s: no IPv6 Routers available", ifp->name);
 }
 
-#ifdef ND6_ADVERTISE
-static void
-ipv6nd_sendadvertisement(void *arg)
-{
-       struct ipv6_addr *ia = arg;
-       struct interface *ifp = ia->iface;
-       struct dhcpcd_ctx *ctx = ifp->ctx;
-       struct sockaddr_in6 dst = {
-           .sin6_family = AF_INET6,
-           .sin6_addr = IN6ADDR_LINKLOCAL_ALLNODES_INIT,
-           .sin6_scope_id = ifp->index,
-       };
-       struct iovec iov = { .iov_base = ia->na, .iov_len = ia->na_len };
-       union {
-               struct cmsghdr hdr;
-               uint8_t buf[CMSG_SPACE(sizeof(struct in6_pktinfo))];
-       } cmsgbuf = { .buf = { 0 } };
-       struct msghdr msg = {
-           .msg_name = &dst, .msg_namelen = sizeof(dst),
-           .msg_iov = &iov, .msg_iovlen = 1,
-           .msg_control = cmsgbuf.buf, .msg_controllen = sizeof(cmsgbuf.buf),
-       };
-       struct cmsghdr *cm;
-       struct in6_pktinfo pi = { .ipi6_ifindex = ifp->index };
-       const struct rs_state *state = RS_CSTATE(ifp);
-       int s;
-
-       if (state == NULL || !if_is_link_up(ifp))
-               goto freeit;
-
-#ifdef SIN6_LEN
-       dst.sin6_len = sizeof(dst);
-#endif
-
-       /* Set the outbound interface. */
-       cm = CMSG_FIRSTHDR(&msg);
-       assert(cm != NULL);
-       cm->cmsg_level = IPPROTO_IPV6;
-       cm->cmsg_type = IPV6_PKTINFO;
-       cm->cmsg_len = CMSG_LEN(sizeof(pi));
-       memcpy(CMSG_DATA(cm), &pi, sizeof(pi));
-       logdebugx("%s: sending NA for %s", ifp->name, ia->saddr);
-
-#ifdef PRIVSEP
-       if (IN_PRIVSEP(ifp->ctx)) {
-               if (ps_inet_sendnd(ifp, &msg) == -1)
-                       logerr(__func__);
-               goto sent;
-       }
-#endif
-#ifdef __sun
-       s = state->nd_fd;
-#else
-       s = ctx->nd_fd;
-#endif
-       if (sendmsg(s, &msg, 0) == -1)
-               logerr(__func__);
-
-#ifdef PRIVSEP
-sent:
-#endif
-       if (++ia->na_count < MAX_NEIGHBOR_ADVERTISEMENT) {
-               eloop_timeout_add_sec(ctx->eloop,
-                   state->retrans / 1000, ipv6nd_sendadvertisement, ia);
-               return;
-       }
-
-freeit:
-       free(ia->na);
-       ia->na = NULL;
-       ia->na_count = 0;
-}
-
-void
-ipv6nd_advertise(struct ipv6_addr *ia)
-{
-       struct dhcpcd_ctx *ctx;
-       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))
-               return;
-
-#ifdef __sun
-       if (!(ia->flags & IPV6_AF_AUTOCONF) && ia->flags & IPV6_AF_RAPFX)
-               return;
-#endif
-
-       ctx = ia->iface->ctx;
-       /* Find the most preferred address to advertise. */
-       iaf = NULL;
-       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;
-
-                       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 ||
-                           !if_is_link_up(ifp))
-                               continue;
-
-                       if (iaf == NULL ||
-                           iaf->iface->metric > iap->iface->metric)
-                               iaf = iap;
-               }
-       }
-
-       /* If we have already advertised the address, return. */
-       if (iaf == NULL || iaf->flags & IPV6_AF_ADVERTISED)
-               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(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);
-                       }
-               }
-       } else {
-               eloop_timeout_delete(ctx->eloop,
-                   ipv6nd_sendadvertisement, iaf);
-       }
-
-       /* Make the packet. */
-       ifp = iaf->iface;
-       iaf->na_len = sizeof(*na);
-       if (ifp->hwlen != 0)
-               iaf->na_len += (size_t)ROUNDUP8(ifp->hwlen + 2);
-       na = calloc(1, iaf->na_len);
-       if (na == NULL) {
-               logerr(__func__);
-               return;
-       }
-
-       na->nd_na_type = ND_NEIGHBOR_ADVERT;
-       na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE;
-#ifdef PRIVSEP_SYSCTL
-       if (IN_PRIVSEP(ctx)) {
-               if (ps_root_ip6forwarding(ctx, ifp->name) != 0)
-                       na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
-       } else
-#endif
-       if (ip6_forwarding(ifp->name) > 0)
-               na->nd_na_flags_reserved |= ND_NA_FLAG_ROUTER;
-       na->nd_na_target = ia->addr;
-
-       if (ifp->hwlen != 0) {
-               struct nd_opt_hdr *opt;
-
-               opt = (struct nd_opt_hdr *)(na + 1);
-               opt->nd_opt_type = ND_OPT_TARGET_LINKADDR;
-               opt->nd_opt_len = (uint8_t)((ROUNDUP8(ifp->hwlen + 2)) >> 3);
-               memcpy(opt + 1, ifp->hwaddr, ifp->hwlen);
-       }
-
-       iaf->na_count = 0;
-       free(iaf->na);
-       iaf->na = na;
-       iaf->flags |= IPV6_AF_ADVERTISED;
-       ipv6nd_sendadvertisement(iaf);
-}
-#elif !defined(SMALL)
-#warning kernel does not support userland sending ND6 advertisements
-#endif /* ND6_ADVERTISE */
-
 static void
 ipv6nd_expire(void *arg)
 {
@@ -1089,9 +904,6 @@ try_script:
                                ipv6nd_scriptrun(rap);
                        }
                }
-#ifdef ND6_ADVERTISE
-               ipv6nd_advertise(ia);
-#endif
        }
 }