]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Add IPv4 address selection from route code so platform handlers don't
authorRoy Marples <roy@marples.name>
Thu, 10 Sep 2015 08:32:37 +0000 (08:32 +0000)
committerRoy Marples <roy@marples.name>
Thu, 10 Sep 2015 08:32:37 +0000 (08:32 +0000)
have to work it out.

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

index 8b8cfb6aba0d22035754d234a503c38ecc08fd6c..239b55b124a8cd8efba921b360b7a60a8d4fd4e6 100644 (file)
--- 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;
index 2b94b59a728267a53e30191bbe6eb021ff078dd1..565bed8b0f8f3874167e1828659269ffc6a03905 100644 (file)
@@ -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 949ef8e58c365f9218a97292b426d907ef429a5a..021d51efa47758b7ba42e8234ec99cbcfb21b933 100644 (file)
--- 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 913aa46d3340ecbdc926d0c04d8dd551ee89ebf9..ba062364486dd1b681428ef4f4b740913818bfc6 100644 (file)
--- 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);