From: Roy Marples Date: Fri, 4 Oct 2024 15:36:01 +0000 (+0000) Subject: dhcpcd: remove advertisement of addresses X-Git-Tag: v10.1.0~4 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=acbac1216988cbb13db8456b621a0b84465471e3;p=thirdparty%2Fdhcpcd.git dhcpcd: remove advertisement of addresses 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. --- diff --git a/src/arp.c b/src/arp.c index 7d0c8558..b1c7952d 100644 --- 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) diff --git a/src/dhcp.c b/src/dhcp.c index 262dfa89..2dbdfe5f 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -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 * diff --git a/src/dhcp6.c b/src/dhcp6.c index 61acd994..ee24b233 100644 --- a/src/dhcp6.c +++ b/src/dhcp6.c @@ -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); diff --git a/src/ipv4.c b/src/ipv4.c index 4cd24a7d..69e0dab8 100644 --- a/src/ipv4.c +++ b/src/ipv4.c @@ -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); diff --git a/src/ipv4ll.c b/src/ipv4ll.c index 0744447a..ebe8aae0 100644 --- a/src/ipv4ll.c +++ b/src/ipv4ll.c @@ -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); } diff --git a/src/ipv6.c b/src/ipv6.c index 52a3c88a..7e2f0bb1 100644 --- a/src/ipv6.c +++ b/src/ipv6.c @@ -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 diff --git a/src/ipv6.h b/src/ipv6.h index 2a93727a..6351cd4c 100644 --- a/src/ipv6.h +++ b/src/ipv6.h @@ -158,20 +158,6 @@ # 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 { diff --git a/src/ipv6nd.c b/src/ipv6nd.c index 49f425b7..cc42c569 100644 --- a/src/ipv6nd.c +++ b/src/ipv6nd.c @@ -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 } }