From: Roy Marples Date: Thu, 17 Dec 2015 00:25:03 +0000 (+0000) Subject: When parsing the routing table, create an interface for any interfaces dhcpcd X-Git-Tag: v6.10.0~40 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=363c200a57af680f43327706f70c2297ea85303c;p=thirdparty%2Fdhcpcd.git When parsing the routing table, create an interface for any interfaces dhcpcd is not directly controling in ctx->oifaces. This allows dhcpcd to manipulate the correct route at all times. Fixes [ebdb4b447a]. --- diff --git a/dhcpcd.c b/dhcpcd.c index f895ad63..a32a99d0 100644 --- 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); diff --git a/dhcpcd.h b/dhcpcd.h index 6f662023..cea23af6 100644 --- 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) diff --git a/if-bsd.c b/if-bsd.c index c0c80693..a76f32dc 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -58,6 +58,7 @@ # include #endif +#include #include #include #include @@ -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; } diff --git a/if-linux.c b/if-linux.c index 64dee7c3..b3baf07d 100644 --- a/if-linux.c +++ b/if-linux.c @@ -46,6 +46,7 @@ #include #include +#include #include #include #include @@ -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 13734adc..43199a8e 100644 --- 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 7dd52645..7684afa2 100644 --- 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 fcc9b2e0..50de28f0 100644 --- 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 22b80ddd..49e36773 100644 --- 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. */