From: Roy Marples Date: Wed, 2 Oct 2019 16:01:02 +0000 (+0100) Subject: inet: Rework prior incase DHCP uses an IPv4LL address X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cd016919a0cd4265f99750b5f8100b1d6db48cca;p=thirdparty%2Fdhcpcd.git inet: Rework prior incase DHCP uses an IPv4LL address Highly unlikely, but still technically possible. --- diff --git a/src/dhcp.c b/src/dhcp.c index 6145ce9c..fd4ee9f4 100644 --- a/src/dhcp.c +++ b/src/dhcp.c @@ -2013,19 +2013,20 @@ dhcp_finish_dad(struct interface *ifp, struct in_addr *ia) } -static void +static bool dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia) { struct dhcp_state *state = D_STATE(ifp); unsigned long long opts = ifp->options->options; struct dhcpcd_ctx *ctx = ifp->ctx; + bool deleted = false; #ifdef IN_IFF_DUPLICATED struct ipv4_addr *iap; #endif if ((state->offer == NULL || state->offer->yiaddr != ia->s_addr) && !IN_ARE_ADDR_EQUAL(ia, &state->lease.addr)) - return; + return deleted; /* RFC 2131 3.1.5, Client-server interaction */ logerrx("%s: DAD detected %s", ifp->name, inet_ntoa(*ia)); @@ -2033,8 +2034,10 @@ dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia) if (!(opts & DHCPCD_STATIC) && !state->lease.frominfo) dhcp_decline(ifp); #ifdef IN_IFF_DUPLICATED - if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL) + if ((iap = ipv4_iffindaddr(ifp, ia, NULL)) != NULL) { ipv4_deladdr(iap, 0); + deleted = true; + } #endif eloop_timeout_delete(ctx->eloop, NULL, ifp); if (opts & (DHCPCD_STATIC | DHCPCD_INFORM)) { @@ -2042,10 +2045,11 @@ dhcp_addr_duplicated(struct interface *ifp, struct in_addr *ia) script_runreason(ifp, state->reason); if (!(ctx->options & DHCPCD_MASTER)) eloop_exit(ifp->ctx->eloop, EXIT_FAILURE); - return; + return deleted; } eloop_timeout_add_sec(ifp->ctx->eloop, DHCP_RAND_MAX, dhcp_discover, ifp); + return deleted; } #endif @@ -3963,7 +3967,7 @@ dhcp_abort(struct interface *ifp) } } -void +struct ipv4_addr * dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) { struct interface *ifp; @@ -3974,7 +3978,7 @@ dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) ifp = ia->iface; state = D_STATE(ifp); if (state == NULL || state->state == DHS_NONE) - return; + return ia; if (cmd == RTM_DELADDR) { if (state->addr == ia) { @@ -3985,37 +3989,37 @@ dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) * to drop the lease. */ dhcp_drop(ifp, "EXPIRE"); dhcp_start1(ifp); + return NULL; } - return; } if (cmd != RTM_NEWADDR) - return; + return ia; #ifdef IN_IFF_NOTUSEABLE if (!(ia->addr_flags & IN_IFF_NOTUSEABLE)) dhcp_finish_dad(ifp, &ia->addr); else if (ia->addr_flags & IN_IFF_DUPLICATED) - dhcp_addr_duplicated(ifp, &ia->addr); + return dhcp_addr_duplicated(ifp, &ia->addr) ? NULL : ia; #endif ifo = ifp->options; if (ifo->options & DHCPCD_INFORM) { if (state->state != DHS_INFORM) dhcp_inform(ifp); - return; + return ia; } if (!(ifo->options & DHCPCD_STATIC)) - return; + return ia; if (ifo->req_addr.s_addr != INADDR_ANY) - return; + return ia; free(state->old); state->old = state->new; state->new_len = dhcp_message_new(&state->new, &ia->addr, &ia->mask); if (state->new == NULL) - return; + return ia; if (ifp->flags & IFF_POINTOPOINT) { for (i = 1; i < 255; i++) if (i != DHO_ROUTER && has_option_mask(ifo->dstmask,i)) @@ -4031,4 +4035,6 @@ dhcp_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) state->addr = ia; dhcp_inform(ifp); } + + return ia; } diff --git a/src/dhcp.h b/src/dhcp.h index 4b6311a3..98a8b1e4 100644 --- a/src/dhcp.h +++ b/src/dhcp.h @@ -260,7 +260,7 @@ int dhcp_get_routes(rb_tree_t *, struct interface *); ssize_t dhcp_env(FILE *, const char *, const struct interface *, const struct bootp *, size_t); -void dhcp_handleifa(int, struct ipv4_addr *, pid_t pid); +struct ipv4_addr *dhcp_handleifa(int, struct ipv4_addr *, pid_t pid); void dhcp_drop(struct interface *, const char *); void dhcp_start(struct interface *); void dhcp_abort(struct interface *); diff --git a/src/ipv4.c b/src/ipv4.c index ff30fda0..8c89dc73 100644 --- a/src/ipv4.c +++ b/src/ipv4.c @@ -936,19 +936,14 @@ ipv4_handleifa(struct dhcpcd_ctx *ctx, } if (addr->s_addr != INADDR_ANY && addr->s_addr != INADDR_BROADCAST) { - /* If the handler deletes the address, the other might crash. - * So only call one handler based on the address type. */ - if (IN_LINKLOCAL(ntohl(addr->s_addr))) + ia = dhcp_handleifa(cmd, ia, pid); #ifdef IPV4LL + if (ia != NULL) ipv4ll_handleifa(cmd, ia, pid); -#else - ; #endif - else - dhcp_handleifa(cmd, ia, pid); } - if (cmd == RTM_DELADDR) + if (cmd == RTM_DELADDR && ia != NULL) free(ia); } diff --git a/src/ipv4ll.c b/src/ipv4ll.c index 2524a02f..09d1166f 100644 --- a/src/ipv4ll.c +++ b/src/ipv4ll.c @@ -546,7 +546,7 @@ ipv4ll_recvrt(__unused int cmd, const struct rt *rt) } #endif -void +struct ipv4_addr * ipv4ll_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) { struct interface *ifp; @@ -555,7 +555,7 @@ ipv4ll_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) ifp = ia->iface; state = IPV4LL_STATE(ifp); if (state == NULL) - return; + return ia; if (cmd == RTM_DELADDR && state->addr != NULL && @@ -564,20 +564,23 @@ ipv4ll_handleifa(int cmd, struct ipv4_addr *ia, pid_t pid) loginfox("%s: pid %d deleted IP address %s", ifp->name, pid, ia->saddr); ipv4ll_defend_failed(ifp); - return; + return ia; } #ifdef IN_IFF_DUPLICATED if (cmd != RTM_NEWADDR) - return; + return ia; if (!IN_ARE_ADDR_EQUAL(&state->pickedaddr, &ia->addr)) - return; + return ia; if (!(ia->addr_flags & IN_IFF_NOTUSEABLE)) ipv4ll_not_found(ifp); else if (ia->addr_flags & IN_IFF_DUPLICATED) { logerrx("%s: DAD detected %s", ifp->name, ia->saddr); ipv4_deladdr(ia, 1); ipv4ll_found(ifp); + return NULL; } #endif + + return ia; } diff --git a/src/ipv4ll.h b/src/ipv4ll.h index dd68d30a..d955d1e0 100644 --- a/src/ipv4ll.h +++ b/src/ipv4ll.h @@ -64,7 +64,7 @@ ssize_t ipv4ll_env(FILE *, const char *, const struct interface *); void ipv4ll_start(void *); void ipv4ll_claimed(void *); void ipv4ll_handle_failure(void *); -void ipv4ll_handleifa(int, struct ipv4_addr *, pid_t pid); +struct ipv4_addr *ipv4ll_handleifa(int, struct ipv4_addr *, pid_t pid); #ifdef HAVE_ROUTE_METRIC int ipv4ll_recvrt(int, const struct rt *); #endif