From: Roy Marples Date: Thu, 10 Sep 2015 08:32:37 +0000 (+0000) Subject: Add IPv4 address selection from route code so platform handlers don't X-Git-Tag: v6.9.4~59 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=641cce43784d620df9a644c5ea7b8f5ae734281e;p=thirdparty%2Fdhcpcd.git Add IPv4 address selection from route code so platform handlers don't have to work it out. --- diff --git a/if-bsd.c b/if-bsd.c index 8b8cfb6a..239b55b1 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -508,8 +508,6 @@ if_copyrt(struct dhcpcd_ctx *ctx, struct rt *rt, struct rt_msghdr *rtm) int if_route(unsigned char cmd, const struct rt *rt) { - const struct dhcp_state *state; - const struct ipv4ll_state *istate; union sockunion { struct sockaddr sa; struct sockaddr_in sin; @@ -522,6 +520,7 @@ if_route(unsigned char cmd, const struct rt *rt) } rtm; char *bp = rtm.buffer; size_t l; + struct in_addr src_addr; #define ADDSU { \ l = RT_ROUNDUP(su.sa.sa_len); \ @@ -536,47 +535,35 @@ if_route(unsigned char cmd, const struct rt *rt) ADDSU; \ } - if (cmd != RTM_DELETE) { - state = D_CSTATE(rt->iface); - istate = IPV4LL_CSTATE(rt->iface); - } else { - /* appease GCC */ - state = NULL; - istate = NULL; - } memset(&rtm, 0, sizeof(rtm)); rtm.hdr.rtm_version = RTM_VERSION; rtm.hdr.rtm_seq = 1; rtm.hdr.rtm_type = cmd; rtm.hdr.rtm_addrs = RTA_DST; - if (cmd == RTM_ADD || cmd == RTM_CHANGE) - rtm.hdr.rtm_addrs |= RTA_GATEWAY; rtm.hdr.rtm_flags = RTF_UP; #ifdef RTF_PINNED if (cmd != RTM_ADD) rtm.hdr.rtm_flags |= RTF_PINNED; #endif - if (cmd != RTM_DELETE) { - rtm.hdr.rtm_addrs |= RTA_IFA | RTA_IFP; - /* None interface subnet routes are static. */ - if ((rt->gate.s_addr != INADDR_ANY || - rt->net.s_addr != state->net.s_addr || - rt->dest.s_addr != - (state->addr.s_addr & state->net.s_addr)) && - (istate == NULL || - rt->dest.s_addr != - (istate->addr.s_addr & inaddr_llmask.s_addr) || - rt->net.s_addr != inaddr_llmask.s_addr)) - rtm.hdr.rtm_flags |= RTF_STATIC; - else { + if (cmd == RTM_ADD || cmd == RTM_CHANGE) { + int subnet; + + rtm.hdr.rtm_addrs |= RTA_GATEWAY | RTA_IFA | RTA_IFP; + /* Subnet routes are clonning or connected if supported. + * All other routes are static. */ + subnet = ipv4_srcaddr(rt, &src_addr); + if (subnet == 1) { #ifdef RTF_CLONING rtm.hdr.rtm_flags |= RTF_CLONING; #endif #ifdef RTP_CONNECTED rtm.hdr.rtm_priority = RTP_CONNECTED; #endif - } + } else + rtm.hdr.rtm_flags |= RTF_STATIC; + if (subnet == -1) /* unikely */ + rtm.hdr.rtm_addrs &= ~RTA_IFA; } if (rt->net.s_addr == htonl(INADDR_BROADCAST) && rt->gate.s_addr == htonl(INADDR_ANY)) @@ -607,7 +594,7 @@ if_route(unsigned char cmd, const struct rt *rt) } if ((cmd == RTM_ADD || cmd == RTM_CHANGE) && !(rtm.hdr.rtm_flags & RTF_GATEWAY)) - rtm.hdr.rtm_addrs |= RTA_IFA | RTA_IFP; + rtm.hdr.rtm_addrs |= RTA_IFP; ADDADDR(&rt->dest); if (rtm.hdr.rtm_addrs & RTA_GATEWAY) { @@ -638,7 +625,7 @@ if_route(unsigned char cmd, const struct rt *rt) } if (rtm.hdr.rtm_addrs & RTA_IFA) - ADDADDR(istate == NULL ? &state->addr : &istate->addr); + ADDADDR(&src_addr); if (rt->mtu) { rtm.hdr.rtm_inits |= RTV_MTU; diff --git a/if-linux.c b/if-linux.c index 2b94b59a..565bed8b 100644 --- a/if-linux.c +++ b/if-linux.c @@ -1329,9 +1329,8 @@ int if_route(unsigned char cmd, const struct rt *rt) { struct nlmr nlm; - int retval = 0; - const struct dhcp_state *state; - const struct ipv4ll_state *istate; + struct in_addr src_addr; + int subnet; memset(&nlm, 0, sizeof(nlm)); nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); @@ -1352,18 +1351,12 @@ if_route(unsigned char cmd, const struct rt *rt) nlm.rt.rtm_family = AF_INET; nlm.rt.rtm_table = RT_TABLE_MAIN; - state = D_CSTATE(rt->iface); - istate = IPV4LL_CSTATE(rt->iface); - if (cmd == RTM_DELETE) + if (cmd == RTM_DELETE) { nlm.rt.rtm_scope = RT_SCOPE_NOWHERE; - else { - /* We only change route metrics for kernel routes */ - if ((rt->dest.s_addr == - (state->addr.s_addr & state->net.s_addr) && - rt->net.s_addr == state->net.s_addr) || - (istate && rt->dest.s_addr == - (istate->addr.s_addr & inaddr_llmask.s_addr) && - rt->net.s_addr == inaddr_llmask.s_addr)) + subnet = -1; + } else { + /* Subnet routes are RTPROT_KERNEL otherwise RTPROT_BOOT */ + if ((subnet = ipv4_srcaddr(rt, &src_addr)) == 1) nlm.rt.rtm_protocol = RTPROT_KERNEL; else nlm.rt.rtm_protocol = RTPROT_BOOT; @@ -1381,37 +1374,37 @@ if_route(unsigned char cmd, const struct rt *rt) nlm.rt.rtm_dst_len = inet_ntocidr(rt->net); add_attr_l(&nlm.hdr, sizeof(nlm), RTA_DST, &rt->dest.s_addr, sizeof(rt->dest.s_addr)); - if (nlm.rt.rtm_protocol == RTPROT_KERNEL) { - add_attr_l(&nlm.hdr, sizeof(nlm), RTA_PREFSRC, - istate == NULL ? &state->addr.s_addr : &istate->addr.s_addr, - sizeof(state->addr.s_addr)); - } /* If a host route then don't add the gateway */ - if ((cmd == RTM_ADD || cmd == RTM_CHANGE) && - rt->net.s_addr != INADDR_BROADCAST) - add_attr_l(&nlm.hdr, sizeof(nlm), RTA_GATEWAY, - &rt->gate.s_addr, sizeof(rt->gate.s_addr)); + if (cmd == RTM_ADD || cmd == RTM_CHANGE) { + if (rt->net.s_addr != INADDR_BROADCAST) + 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)); + } + if (rt->mtu) { + char metricsbuf[32]; + struct rtattr *metrics = (void *)metricsbuf; + + metrics->rta_type = RTA_METRICS; + metrics->rta_len = RTA_LENGTH(0); + rta_add_attr_32(metrics, sizeof(metricsbuf), + RTAX_MTU, rt->mtu); + add_attr_l(&nlm.hdr, sizeof(nlm), RTA_METRICS, + RTA_DATA(metrics), + (unsigned short)RTA_PAYLOAD(metrics)); + } + } - 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); - if (cmd != RTM_DELETE && rt->mtu) { - char metricsbuf[32]; - struct rtattr *metrics = (void *)metricsbuf; - - metrics->rta_type = RTA_METRICS; - metrics->rta_len = RTA_LENGTH(0); - rta_add_attr_32(metrics, sizeof(metricsbuf), RTAX_MTU, rt->mtu); - add_attr_l(&nlm.hdr, sizeof(nlm), RTA_METRICS, - RTA_DATA(metrics), (unsigned short)RTA_PAYLOAD(metrics)); - } - - if (send_netlink(rt->iface->ctx, NULL, - NETLINK_ROUTE, &nlm.hdr, NULL) == -1) - retval = -1; - return retval; + return send_netlink(rt->iface->ctx, NULL, + NETLINK_ROUTE, &nlm.hdr, NULL); } static int @@ -1461,7 +1454,6 @@ if_address6(const struct ipv6_addr *ia, int action) { struct nlma nlm; struct ifa_cacheinfo cinfo; - int retval = 0; /* IFA_FLAGS is not a define, but is was added at the same time * IFA_F_NOPREFIXROUTE was do use that. */ #if defined(IFA_F_NOPREFIXROUTE) || defined(IFA_F_MANAGETEMPADDR) @@ -1517,17 +1509,14 @@ if_address6(const struct ipv6_addr *ia, int action) add_attr_32(&nlm.hdr, sizeof(nlm), IFA_FLAGS, flags); #endif - if (send_netlink(ia->iface->ctx, NULL, NETLINK_ROUTE, &nlm.hdr, - NULL) == -1) - retval = -1; - return retval; + return send_netlink(ia->iface->ctx, NULL, + NETLINK_ROUTE, &nlm.hdr, NULL); } int if_route6(unsigned char cmd, const struct rt6 *rt) { struct nlmr nlm; - int retval = 0; memset(&nlm, 0, sizeof(nlm)); nlm.hdr.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)); @@ -1590,10 +1579,8 @@ if_route6(unsigned char cmd, const struct rt6 *rt) RTA_DATA(metrics), (unsigned short)RTA_PAYLOAD(metrics)); } - if (send_netlink(rt->iface->ctx, NULL, - NETLINK_ROUTE, &nlm.hdr, NULL) == -1) - retval = -1; - return retval; + return send_netlink(rt->iface->ctx, NULL, + NETLINK_ROUTE, &nlm.hdr, NULL); } static int diff --git a/ipv4.c b/ipv4.c index 949ef8e5..021d51ef 100644 --- a/ipv4.c +++ b/ipv4.c @@ -159,6 +159,51 @@ ipv4_findaddr(struct dhcpcd_ctx *ctx, const struct in_addr *addr) return NULL; } +int +ipv4_srcaddr(const struct rt *rt, struct in_addr *addr) +{ + const struct dhcp_state *dstate; + const struct ipv4ll_state *istate; + + if (rt->iface == NULL) { + errno = ENOENT; + return -1; + } + + /* Prefer DHCP source address if matching */ + dstate = D_CSTATE(rt->iface); + if (dstate && + rt->net.s_addr == dstate->net.s_addr && + rt->dest.s_addr == (dstate->addr.s_addr & dstate->net.s_addr)) + { + *addr = dstate->addr; + return 1; + } + + /* Then IPv4LL source address if matching */ + istate = IPV4LL_CSTATE(rt->iface); + if (istate && + rt->net.s_addr == inaddr_llmask.s_addr && + rt->dest.s_addr == (istate->addr.s_addr & inaddr_llmask.s_addr)) + { + *addr = istate->addr; + return 1; + } + + /* If neither match, return DHCP then IPv4LL */ + if (dstate) { + *addr = dstate->addr; + return 0; + } + if (istate) { + *addr = istate->addr; + return 0; + } + + errno = ESRCH; + return -1; +} + int ipv4_hasaddr(const struct interface *ifp) { @@ -434,7 +479,7 @@ nc_route(struct rt *ort, struct rt *nrt) #endif if (change) { - if (if_route(RTM_CHANGE, nrt) == 0) + if (if_route(RTM_CHANGE, nrt) != -1) return 0; if (errno != ESRCH) logger(nrt->iface->ctx, LOG_ERR, "if_route (CHG): %m"); @@ -448,7 +493,7 @@ nc_route(struct rt *ort, struct rt *nrt) #ifdef HAVE_ROUTE_METRIC /* With route metrics, we can safely add the new route before * deleting the old route. */ - if (if_route(RTM_ADD, nrt) == 0) { + if (if_route(RTM_ADD, nrt) != -1) { if (ort && if_route(RTM_DELETE, ort) == -1 && errno != ESRCH) logger(nrt->iface->ctx, LOG_ERR, "if_route (DEL): %m"); return 0; @@ -464,7 +509,7 @@ nc_route(struct rt *ort, struct rt *nrt) * adding the new one. */ if (ort && if_route(RTM_DELETE, ort) == -1 && errno != ESRCH) logger(nrt->iface->ctx, LOG_ERR, "if_route (DEL): %m"); - if (if_route(RTM_ADD, nrt) == 0) + if (if_route(RTM_ADD, nrt) != -1) return 0; #ifdef HAVE_ROUTE_METRIC logerr: @@ -479,8 +524,8 @@ d_route(struct rt *rt) int retval; desc_route("deleting", rt); - retval = if_route(RTM_DELETE, rt); - if (retval != 0 && errno != ENOENT && errno != ESRCH) + retval = if_route(RTM_DELETE, rt) == -1 ? -1 : 0; + if (retval == -1 && errno != ENOENT && errno != ESRCH) logger(rt->iface->ctx, LOG_ERR, "%s: if_delroute: %m", rt->iface->name); return retval; diff --git a/ipv4.h b/ipv4.h index 913aa46d..ba062364 100644 --- a/ipv4.h +++ b/ipv4.h @@ -121,6 +121,7 @@ struct ipv4_addr *ipv4_iffindaddr(struct interface *, const struct in_addr *, const struct in_addr *); struct ipv4_addr *ipv4_iffindlladdr(struct interface *); struct ipv4_addr *ipv4_findaddr(struct dhcpcd_ctx *, const struct in_addr *); +int ipv4_srcaddr(const struct rt *, struct in_addr *); void ipv4_handleifa(struct dhcpcd_ctx *, int, struct if_head *, const char *, const struct in_addr *, const struct in_addr *, const struct in_addr *, int);