]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
inet: Rework prior incase DHCP uses an IPv4LL address
authorRoy Marples <roy@marples.name>
Wed, 2 Oct 2019 16:01:02 +0000 (17:01 +0100)
committerRoy Marples <roy@marples.name>
Wed, 2 Oct 2019 16:01:02 +0000 (17:01 +0100)
Highly unlikely, but still technically possible.

src/dhcp.c
src/dhcp.h
src/ipv4.c
src/ipv4ll.c
src/ipv4ll.h

index 6145ce9ceb9e84d7c518bfefc4d12f40d83a2838..fd4ee9f428f23e9a688c2bc66847279367905475 100644 (file)
@@ -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;
 }
index 4b6311a38bb536544f95dd6392e3acb0f0c5e779..98a8b1e48992cf5ca392928dad02ed8ec1054b27 100644 (file)
@@ -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 *);
index ff30fda0dd72b9650b4fbb13c24457734d405167..8c89dc73ef73a65abcc256016b09c0478a9cfe5f 100644 (file)
@@ -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);
 }
 
index 2524a02f59e5e65569bcd9529cfd4b6bc1d5d3f5..09d1166f50b4cf5e00d7076407b6275c0176f7cc 100644 (file)
@@ -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;
 }
index dd68d30a1df28e829f17a4a81b51ee9c0641251f..d955d1e06c3a1b7d4eb915b0b47920b673c672fb 100644 (file)
@@ -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