]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
When parsing the routing table, create an interface for any interfaces dhcpcd
authorRoy Marples <roy@marples.name>
Thu, 17 Dec 2015 00:25:03 +0000 (00:25 +0000)
committerRoy Marples <roy@marples.name>
Thu, 17 Dec 2015 00:25:03 +0000 (00:25 +0000)
is not directly controling in ctx->oifaces.
This allows dhcpcd to manipulate the correct route at all times.

Fixes [ebdb4b447a].

dhcpcd.c
dhcpcd.h
if-bsd.c
if-linux.c
if.c
if.h
ipv4.c
ipv6.c

index f895ad63b31479e7629832b1cec5e47ed6d67feb..a32a99d0c4b29e304558df26ba7c3d4c14ab538c 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -1932,6 +1932,13 @@ exit1:
                }
                free(ctx.ifaces);
        }
+       if (ctx.oifaces) {
+               while ((ifp = TAILQ_FIRST(ctx.oifaces))) {
+                       TAILQ_REMOVE(ctx.oifaces, ifp, next);
+                       if_free(ifp);
+               }
+               free(ctx.oifaces);
+       }
        free(ctx.duid);
        if (ctx.link_fd != -1) {
                eloop_event_delete(ctx.eloop, ctx.link_fd);
index 6f6620239aa68552bd1c129bdebc778a7b2b6f8c..cea23af644efe28ab413520ed52765cb7b063ad3 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -111,6 +111,7 @@ struct dhcpcd_ctx {
        unsigned char *duid;
        size_t duid_len;
        struct if_head *ifaces;
+       struct if_head *oifaces;        /* interfaces not directly controlled */
 
        int pf_inet_fd;
 #if defined(INET6) && defined(BSD)
index c0c806939b8802045ad76873ccbc23eb84ad0e5f..a76f32dc8f71917cc999fd027b3a597398bd26c9 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
@@ -58,6 +58,7 @@
 #  include <net80211/ieee80211_ioctl.h>
 #endif
 
+#include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <fnmatch.h>
@@ -482,9 +483,11 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct rt_msghdr *rtm)
        if (rtm->rtm_inits & RTV_MTU)
                rt->mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu;
 
-       if (rtm->rtm_index)
+       if (rtm->rtm_index) {
                rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);
-       else if (rtm->rtm_addrs & RTA_IFP) {
+               if (rt->iface == NULL)
+                       rt->iface = if_newoif(ctx, rtm->rtm_index);
+       } else if (rtm->rtm_addrs & RTA_IFP) {
                struct sockaddr_dl *sdl;
 
                sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_IFP];
@@ -502,6 +505,8 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct rt_msghdr *rtm)
                        rt->iface = ia->iface;
        }
 
+       assert(rt->iface != NULL);
+
        return 0;
 }
 
@@ -863,9 +868,11 @@ if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct rt_msghdr *rtm)
        if (rtm->rtm_inits & RTV_MTU)
                rt->mtu = (unsigned int)rtm->rtm_rmx.rmx_mtu;
 
-       if (rtm->rtm_index)
+       if (rtm->rtm_index) {
                rt->iface = if_findindex(ctx->ifaces, rtm->rtm_index);
-       else if (rtm->rtm_addrs & RTA_IFP) {
+               if (rt->iface == NULL)
+                       rt->iface = if_newoif(ctx, rtm->rtm_index);
+       } else if (rtm->rtm_addrs & RTA_IFP) {
                struct sockaddr_dl *sdl;
 
                sdl = (struct sockaddr_dl *)(void *)rti_info[RTAX_IFP];
@@ -882,6 +889,8 @@ if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct rt_msghdr *rtm)
                        rt->iface = ia->iface;
        }
 
+       assert(rt->iface != NULL);
+
        return 0;
 }
 
index 64dee7c3a2226ccf1da4e659bc14e9a7e1b5dc10..b3baf07d0649beea2a18e52052a2c9c60c59cfce 100644 (file)
@@ -46,6 +46,7 @@
 #include <netinet/in.h>
 #include <net/route.h>
 
+#include <assert.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <ctype.h>
@@ -377,6 +378,7 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct nlmsghdr *nlm)
        size_t len;
        struct rtmsg *rtm;
        struct rtattr *rta;
+       unsigned int ifindex;
 
        len = nlm->nlmsg_len - sizeof(*nlm);
        if (len < sizeof(*rtm)) {
@@ -395,6 +397,7 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct nlmsghdr *nlm)
 
        rta = (struct rtattr *)RTM_RTA(rtm);
        len = RTM_PAYLOAD(nlm);
+       ifindex = 0;
        while (RTA_OK(rta, len)) {
                switch (rta->rta_type) {
                case RTA_DST:
@@ -410,8 +413,8 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct nlmsghdr *nlm)
                            sizeof(rt->src.s_addr));
                        break;
                case RTA_OIF:
-                       rt->iface = if_findindex(ctx->ifaces,
-                           *(unsigned int *)RTA_DATA(rta));
+                       ifindex = *(unsigned int *)RTA_DATA(rta);
+                       rt->iface = if_findindex(ctx->ifaces, ifindex);
                        break;
                case RTA_PRIORITY:
                        rt->metric = *(unsigned int *)RTA_DATA(rta);
@@ -448,6 +451,11 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct nlmsghdr *nlm)
                if ((ap = ipv4_findaddr(ctx, &rt->src)))
                        rt->iface = ap->iface;
        }
+       /* If we still don't have an interface, create a temporary one */
+       if (rt->iface == NULL) {
+               rt->iface = if_newoif(ctx, ifindex);
+               assert(rt->iface != NULL);
+       }
        return 0;
 }
 #endif
@@ -459,6 +467,7 @@ if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct nlmsghdr *nlm)
        size_t len;
        struct rtmsg *rtm;
        struct rtattr *rta;
+       unsigned int ifindex;
 
        len = nlm->nlmsg_len - sizeof(*nlm);
        if (len < sizeof(*rtm)) {
@@ -489,8 +498,10 @@ if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct nlmsghdr *nlm)
                            sizeof(rt->gate.s6_addr));
                        break;
                case RTA_OIF:
-                       rt->iface = if_findindex(ctx->ifaces,
-                           *(unsigned int *)RTA_DATA(rta));
+                       ifindex = *(unsigned int *)RTA_DATA(rta);
+                       rt->iface = if_findindex(ctx->ifaces, ifindex);
+                       if (rt->iface == NULL)
+                               rt->iface = if_newoif(ctx, ifindex);
                        break;
                case RTA_PRIORITY:
                        rt->metric = *(unsigned int *)RTA_DATA(rta);
@@ -516,6 +527,7 @@ if_copyrt6(struct dhcpcd_ctx *ctx, struct rt6 *rt, struct nlmsghdr *nlm)
                rta = RTA_NEXT(rta, len);
        }
 
+       assert(rt->iface != NULL);
        return 0;
 }
 #endif
@@ -1378,9 +1390,6 @@ if_route(unsigned char cmd, const struct rt *rt)
                if (rt->gate.s_addr != htonl(INADDR_ANY))
                        add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY,
                            &rt->gate.s_addr, sizeof(rt->gate.s_addr));
-               if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
-                       add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF,
-                           rt->iface->index);
                if (subnet != -1) {
                        add_attr_l(&nlm.hdr, sizeof(nlm), RTA_PREFSRC,
                            &src_addr.s_addr, sizeof(src_addr.s_addr));
@@ -1399,6 +1408,9 @@ if_route(unsigned char cmd, const struct rt *rt)
                }
        }
 
+       if (rt->gate.s_addr != htonl(INADDR_LOOPBACK))
+               add_attr_32(&nlm.hdr, sizeof(nlm), RTA_OIF, rt->iface->index);
+
        if (rt->metric)
                add_attr_32(&nlm.hdr, sizeof(nlm), RTA_PRIORITY, rt->metric);
 
diff --git a/if.c b/if.c
index 13734adcce385e1f6cf4b71bdf6b8967999b9280..43199a8eac9001e28bfe3cbc2094014172dfea1c 100644 (file)
--- a/if.c
+++ b/if.c
@@ -579,6 +579,43 @@ if_findindex(struct if_head *ifaces, unsigned int idx)
        return if_findindexname(ifaces, idx, NULL);
 }
 
+/* Creates a new interface just for handling route messages to the kernel
+ * if we ever need to change a route on an interface dhcpcd is NOT running on. */
+struct interface *
+if_newoif(struct dhcpcd_ctx *ctx, unsigned int idx)
+{
+       struct interface *ifp;
+
+       if (ctx->oifaces == NULL) {
+               if ((ctx->oifaces = malloc(sizeof(*ctx->oifaces))) == NULL) {
+                       logger(ctx, LOG_ERR, "%s: malloc: %m", __func__);
+                       return NULL;
+               }
+               TAILQ_INIT(ctx->oifaces);
+       } else {
+               TAILQ_FOREACH(ifp, ctx->oifaces, next) {
+                       if (ifp->index == idx)
+                               return ifp;
+               }
+       }
+
+       if ((ifp = calloc(1, sizeof(*ifp))) == NULL) {
+               logger(ctx, LOG_ERR, "%s: calloc: %m", __func__);
+               return NULL;
+       }
+
+       if (if_indextoname(idx, ifp->name) == NULL) {
+               logger(ctx, LOG_ERR, "%s: if_indextoname: %m", __func__);
+               free(ifp);
+               return NULL;
+       }
+
+       ifp->ctx = ctx;
+       ifp->index = idx;
+       TAILQ_INSERT_TAIL(ctx->oifaces, ifp, next);
+       return ifp;
+}
+
 int
 if_domtu(const struct interface *ifp, short int mtu)
 {
diff --git a/if.h b/if.h
index 7dd526451b42a07b108c95cbb838be1f27a30d0f..7684afa27e6aebc89c5b5d4ae452ba696e55d705 100644 (file)
--- a/if.h
+++ b/if.h
@@ -101,6 +101,7 @@ int if_carrier(struct interface *);
 /* The below functions are provided by if-KERNEL.c */
 int if_conf(struct interface *);
 int if_init(struct interface *);
+struct interface *if_newoif(struct dhcpcd_ctx *, unsigned int);
 int if_getssid(struct interface *);
 int if_vimaster(const struct dhcpcd_ctx *ctx, const char *);
 int if_opensockets(struct dhcpcd_ctx *);
diff --git a/ipv4.c b/ipv4.c
index fcc9b2e00e6ca066f0368a4b247d18ce1ff301af..50de28f04e2eec0c33547886c17ea76daf06419a 100644 (file)
--- a/ipv4.c
+++ b/ipv4.c
@@ -485,11 +485,6 @@ nc_route(struct rt *ort, struct rt *nrt)
                        logger(nrt->iface->ctx, LOG_ERR, "if_route (CHG): %m");
        }
 
-       /* If the old route does not have an interface, give it the
-        * interface of the new route for context. */
-       if (ort && ort->iface == NULL)
-               ort->iface = nrt->iface;
-
 #ifdef HAVE_ROUTE_METRIC
        /* With route metrics, we can safely add the new route before
         * deleting the old route. */
diff --git a/ipv6.c b/ipv6.c
index 22b80ddd8ab45eb204fbf1d61cf0d8ec3660143d..49e3677315c42603ceef935ea903800620aa9d14 100644 (file)
--- a/ipv6.c
+++ b/ipv6.c
@@ -1927,11 +1927,6 @@ nc_route(struct rt6 *ort, struct rt6 *nrt)
                        logger(nrt->iface->ctx, LOG_ERR, "if_route6 (CHG): %m");
        }
 
-       /* If the old route does not have an interface, give it the
-        * interface of the new route for context. */
-       if (ort && ort->iface == NULL)
-               ort->iface = nrt->iface;
-
 #ifdef HAVE_ROUTE_METRIC
        /* With route metrics, we can safely add the new route before
         * deleting the old route. */