]> git.ipfire.org Git - thirdparty/dhcpcd.git/commitdiff
Add route removal detection to Linux.
authorRoy Marples <roy@marples.name>
Tue, 27 Jan 2009 18:09:02 +0000 (18:09 +0000)
committerRoy Marples <roy@marples.name>
Tue, 27 Jan 2009 18:09:02 +0000 (18:09 +0000)
This involved a rejig of the socket code so we can detect
if we removed the route or not.

configure.c
configure.h
dhcpcd.c
dhcpcd.h
if-bsd.c
if-linux.c
net.h

index 96d8d886f26c38bf300de7bee9e362ba9b66d35d..a5af5a2acf498d9209a07e21438c91e94477b347 100644 (file)
@@ -392,22 +392,14 @@ desc_route(const char *cmd, const struct rt *rt, const char *ifname)
 /* If something other than dhcpcd removes a route,
  * we need to remove it from our internal table. */
 int
-route_deleted(const struct in_addr *dst,
-             const struct in_addr *net,
-             const struct in_addr *gate)
+route_deleted(const struct rt *rt)
 {
-       struct rt rt, *f, *l;
+       struct rt *f, *l;
 
-       rt.dest.s_addr = dst->s_addr;
-       rt.net.s_addr = net->s_addr;
-       rt.gate.s_addr = gate->s_addr;
-       rt.iface = NULL;
-       rt.next = NULL;
-
-       f = find_route(routes, &rt, &l, NULL);
+       f = find_route(routes, rt, &l, NULL);
        if (f == NULL)
                return 0;
-       desc_route("removing", f, f->iface->name);
+       desc_route("removing", f, rt->iface->name);
        if (l)
                l->next = f->next;
        else
index 5d0124de1163802662ee6203245c8e43957b489f..d103b6e5ae9cf4fab5bc19af27c635381a530929 100644 (file)
@@ -33,8 +33,5 @@
 int send_interface(int, const struct interface *);
 int run_script(const struct interface *);
 int configure(struct interface *);
-int route_deleted(const struct in_addr *,
-                 const struct in_addr *,
-                 const struct in_addr *);
-
+int route_deleted(const struct rt *);
 #endif
index 96ce2bece5d35d41aff6dab419e0ee601c0e86f8..4832f186a855418216f37a78e44e329b780e01ef 100644 (file)
--- a/dhcpcd.c
+++ b/dhcpcd.c
@@ -78,9 +78,9 @@ static char **margv;
 static int margc;
 static char **ifv;
 static int ifc;
-static int linkfd = -1;
 static char *cffile;
 static char *pidfile;
+static int linkfd = -1;
 
 struct dhcp_op {
        uint8_t value;
@@ -214,6 +214,16 @@ close_sockets(struct interface *iface)
        }
 }
 
+struct interface *
+find_interface(const char *ifname)
+{
+       struct interface *ifp;
+       
+       for (ifp = ifaces; ifp; ifp = ifp->next)
+               if (strcmp(ifp->name, ifname) == 0)
+                       return ifp;
+       return NULL;
+}
 
 static void
 stop_interface(struct interface *iface)
@@ -1024,11 +1034,11 @@ handle_new_interface(const char *ifname)
                        if (ifn)
                                continue;
                        init_state(ifp, 2, UNCONST(argv));
-                       start_interface(ifp);
                        if (ifl)
                                ifl->next = ifp;
                        else
                                ifaces = ifp;
+                       start_interface(ifp);
                }
        }
 }
@@ -1038,11 +1048,9 @@ handle_remove_interface(const char *ifname)
 {
        struct interface *iface;
 
-       for (iface = ifaces; iface; iface = iface->next)
-               if (strcmp(iface->name, ifname) == 0) {
-                       stop_interface(iface);
-                       break;
-               }
+       iface = find_interface(ifname);
+       if (iface != NULL)
+               stop_interface(iface);
 }
 
 /* ARGSUSED */
@@ -1395,7 +1403,7 @@ main(int argc, char **argv)
 
        syslog(LOG_INFO, "version " VERSION " starting");
 
-       if ((signal_fd =signal_init()) == -1)
+       if ((signal_fd = signal_init()) == -1)
                exit(EXIT_FAILURE);
        if (signal_setup() == -1)
                exit(EXIT_FAILURE);
@@ -1408,6 +1416,7 @@ main(int argc, char **argv)
                }
        }
 
+       init_socket();
        if (ifo->options & DHCPCD_LINK) {
                linkfd = open_link_socket();
                if (linkfd == -1)
index 085550e8d7e22dd5304c812b264df3f3abc324f0..7c33b22cc03fe6a229a8e94e8c815f86a7047d35 100644 (file)
--- a/dhcpcd.h
+++ b/dhcpcd.h
@@ -116,6 +116,7 @@ extern int ifdc;
 extern char **ifdv;
 extern struct interface *ifaces;
 
+struct interface *find_interface(const char *);
 int handle_args(struct fd_list *, int, char **);
 void handle_exit_timeout(void *);
 void start_interface(void *);
index 46a87acaf2f267084b72252270a8472adaf21ee4..8648a1a1e4250ab818bedc5c25538df3ef552b5b 100644 (file)
--- a/if-bsd.c
+++ b/if-bsd.c
           1 + ( (((struct sockaddr *)(sa))->sa_len - 1) | (sizeof(long) - 1) ) )
 #endif
 
+static int a_fd = -1;
+static int r_fd = -1;
+
+int
+init_socket(void)
+{
+       if ((a_fd = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
+               return -1;
+       set_cloexec(a_fd);
+       if ((r_fd = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
+               return -1;
+       set_cloexec(a_fd);
+       return 0;
+}
+
 int
 getifssid(const char *ifname, char *ssid)
 {
-       int s, retval = -1;
+       int retval = -1;
 #if defined(SIOCG80211NWID)
        struct ifreq ifr;
        struct ieee80211_nwid nwid;
@@ -79,14 +94,12 @@ getifssid(const char *ifname, char *ssid)
        char nwid[IEEE80211_NWID_LEN + 1];
 #endif
 
-       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
-               return retval;
 #if defined(SIOCG80211NWID) /* NetBSD */
        memset(&ifr, 0, sizeof(ifr));
        strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name));
        memset(&nwid, 0, sizeof(nwid));
        ifr.ifr_data = (void *)&nwid;
-       if (ioctl(s, SIOCG80211NWID, &ifr) == 0) {
+       if (ioctl(a_fd, SIOCG80211NWID, &ifr) == 0) {
                retval = nwid.i_len;
                memcpy(ssid, nwid.i_nwid, nwid.i_len);
                ssid[nwid.i_len] = '\0';
@@ -97,13 +110,12 @@ getifssid(const char *ifname, char *ssid)
        ireq.i_type = IEEE80211_IOC_SSID;
        ireq.i_val = -1;
        ireq.i_data = &nwid;
-       if (ioctl(s, SIOCG80211, &ireq) == 0) {
+       if (ioctl(a_fd, SIOCG80211, &ireq) == 0) {
                retval = ireq.i_len;
                memcpy(ssid, nwid, ireq.i_len);
                ssid[ireq.i_len] = '\0';
        }
 #endif
-       close(s);
        return retval;
 }
 
@@ -112,7 +124,6 @@ if_address(const struct interface *iface, const struct in_addr *address,
           const struct in_addr *netmask, const struct in_addr *broadcast,
           int action)
 {
-       int s;
        int retval;
        struct ifaliasreq ifa;
        union {
@@ -120,9 +131,6 @@ if_address(const struct interface *iface, const struct in_addr *address,
                struct sockaddr_in *sin;
        } _s;
 
-       if ((s = socket(AF_INET, SOCK_DGRAM, 0)) == -1)
-               return -1;
-
        memset(&ifa, 0, sizeof(ifa));
        strlcpy(ifa.ifra_name, iface->name, sizeof(ifa.ifra_name));
 
@@ -141,10 +149,9 @@ if_address(const struct interface *iface, const struct in_addr *address,
 #undef ADDADDR
 
        if (action < 0)
-               retval = ioctl(s, SIOCDIFADDR, &ifa);
+               retval = ioctl(a_fd, SIOCDIFADDR, &ifa);
        else
-               retval = ioctl(s, SIOCAIFADDR, &ifa);
-       close(s);
+               retval = ioctl(a_fd, SIOCAIFADDR, &ifa);
        return retval;
 }
 
@@ -154,7 +161,6 @@ if_route(const struct interface *iface, const struct in_addr *dest,
         const struct in_addr *net, const struct in_addr *gate,
         _unused int metric, int action)
 {
-       int s;
        union sockunion {
                struct sockaddr sa;
                struct sockaddr_in sin;
@@ -186,9 +192,6 @@ if_route(const struct interface *iface, const struct in_addr *dest,
        ADDSU(su); \
 }
 
-       if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
-               return -1;
-
        memset(&rtm, 0, sizeof(rtm));
        rtm.hdr.rtm_version = RTM_VERSION;
        rtm.hdr.rtm_seq = 1;
@@ -244,22 +247,19 @@ if_route(const struct interface *iface, const struct in_addr *dest,
                ADDADDR(&iface->addr);
 
        rtm.hdr.rtm_msglen = l = bp - (char *)&rtm;
-       if (write(s, &rtm, l) == -1)
+       if (write(r_fd, &rtm, l) == -1)
                retval = -1;
-       close(s);
        return retval;
 }
 
 int
 arp_flush(void)
 {
-       int s, mib[6], retval = 0;
+       int mib[6], retval = 0;
        size_t buffer_len = 0;
        char *buffer, *e, *p;
        struct rt_msghdr *rtm;
 
-       if ((s = socket(PF_ROUTE, SOCK_RAW, 0)) == -1)
-               return -1;
        mib[0] = CTL_NET;
        mib[1] = PF_ROUTE;
        mib[2] = 0;
@@ -280,13 +280,12 @@ arp_flush(void)
                if (rtm->rtm_flags & RTF_STATIC)
                        continue;
                rtm->rtm_type = RTM_DELETE;
-               if (write(s, rtm, rtm->rtm_msglen) == -1) {
+               if (write(r_fd, rtm, rtm->rtm_msglen) == -1) {
                        retval = -1;
                        break;
                }
        }
        free(buffer);
-       close(s);
        return retval;
 }
 
index 6763c2b88fca89a4ee485898f8496c92d7618814..71723e92a553d79de4445d7f5f46628a36fc540f 100644 (file)
@@ -66,6 +66,7 @@
 
 #include "config.h"
 #include "common.h"
+#include "configure.h"
 #include "dhcp.h"
 #include "net.h"
 
@@ -75,6 +76,9 @@ static void (*nl_carrier)(const char *);
 static void (*nl_add)(const char *);
 static void (*nl_remove)(const char *);
 
+static int sock_fd;
+static struct sockaddr_nl sock_nl;
+
 int
 getifssid(const char *ifname, char *ssid)
 {
@@ -96,23 +100,37 @@ getifssid(const char *ifname, char *ssid)
        return retval;
 }
 
-int
-open_link_socket(void)
+static int
+_open_link_socket(struct sockaddr_nl *nl)
 {
        int fd;
-       struct sockaddr_nl nl;
 
        if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
                return -1;
-       memset(&nl, 0, sizeof(nl));
-       nl.nl_family = AF_NETLINK;
-       nl.nl_groups = RTMGRP_LINK;
-       if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1)
+       nl->nl_family = AF_NETLINK;
+       if (bind(fd, (struct sockaddr *)nl, sizeof(*nl)) == -1)
                return -1;
        set_cloexec(fd);
        return fd;
 }
 
+int
+init_socket(void)
+{
+       sock_fd = _open_link_socket(&sock_nl);
+       return sock_fd;
+}
+
+int
+open_link_socket(void)
+{
+       struct sockaddr_nl snl;
+
+       memset(&snl, 0, sizeof(snl));
+       snl.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_ROUTE;
+       return _open_link_socket(&snl);
+}
+
 static int
 get_netlink(int fd, int flags,
            int (*callback)(struct nlmsghdr *))
@@ -169,6 +187,63 @@ err_netlink(struct nlmsghdr *nlm)
        return -1;
 }
 
+static int
+link_delroute(struct nlmsghdr *nlm)
+{
+       int len, idx, metric;
+       struct rtattr *rta;
+       struct rtmsg *rtm;
+       struct rt rt;
+       char ifn[IF_NAMESIZE + 1];
+
+       len = nlm->nlmsg_len - sizeof(*nlm);
+       if ((size_t)len < sizeof(*rtm)) {
+               errno = EBADMSG;
+               return -1;
+       }
+       rtm = NLMSG_DATA(nlm);
+       if (rtm->rtm_type != RTN_UNICAST ||
+           rtm->rtm_table != RT_TABLE_MAIN ||
+           rtm->rtm_family != AF_INET ||
+           nlm->nlmsg_pid == (uint32_t)getpid())
+               return 1;
+       rta = (struct rtattr *) ((char *)rtm + NLMSG_ALIGN(sizeof(*rtm)));
+       len = NLMSG_PAYLOAD(nlm, sizeof(*rtm));
+       rt.iface = NULL;
+       rt.next = NULL;
+       metric = 0;
+       while (RTA_OK(rta, len)) {
+               switch (rta->rta_type) {
+               case RTA_DST:
+                       memcpy(&rt.dest.s_addr, RTA_DATA(rta),
+                              sizeof(rt.dest.s_addr));
+                       break;
+               case RTA_GATEWAY:
+                       memcpy(&rt.gate.s_addr, RTA_DATA(rta),
+                              sizeof(rt.gate.s_addr));
+                       break;
+               case RTA_OIF:
+                       idx = *(int *)RTA_DATA(rta);
+                       if (if_indextoname(idx, ifn))
+                               rt.iface = find_interface(ifn);
+                       break;
+               case RTA_PRIORITY:
+                       metric = *(int *)RTA_DATA(rta);
+                       break;
+               }
+               rta = RTA_NEXT(rta, len);
+       }
+       if (rt.iface != NULL) {
+               if (metric == rt.iface->metric) {
+                       if (rt.dest.s_addr == INADDR_BROADCAST)
+                               rt.dest.s_addr = INADDR_ANY;
+                       inet_cidrtoaddr(rtm->rtm_dst_len, &rt.net);
+                       route_deleted(&rt);
+               }
+       }
+       return 1;
+}
+
 static int
 link_netlink(struct nlmsghdr *nlm)
 {
@@ -177,6 +252,9 @@ link_netlink(struct nlmsghdr *nlm)
        struct ifinfomsg *ifi;
        char ifn[IF_NAMESIZE + 1];
 
+       if (nlm->nlmsg_type == RTM_DELROUTE)
+               return link_delroute(nlm);
+
        if (nlm->nlmsg_type != RTM_NEWLINK && nlm->nlmsg_type != RTM_DELLINK)
                return 0;
        len = nlm->nlmsg_len - sizeof(*nlm);
@@ -234,37 +312,27 @@ manage_link(int fd,
 static int
 send_netlink(struct nlmsghdr *hdr)
 {
-       int fd, r;
-       struct sockaddr_nl nl;
+       int r;
        struct iovec iov;
        struct msghdr msg;
        static unsigned int seq;
 
-       if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1)
-               return -1;
-       memset(&nl, 0, sizeof(nl));
-       nl.nl_family = AF_NETLINK;
-       if (bind(fd, (struct sockaddr *)&nl, sizeof(nl)) == -1) {
-               close(fd);
-               return -1;
-       }
        memset(&iov, 0, sizeof(iov));
        iov.iov_base = hdr;
        iov.iov_len = hdr->nlmsg_len;
        memset(&msg, 0, sizeof(msg));
-       msg.msg_name = &nl;
-       msg.msg_namelen = sizeof(nl);
+       msg.msg_name = &sock_nl;
+       msg.msg_namelen = sizeof(sock_nl);
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        /* Request a reply */
        hdr->nlmsg_flags |= NLM_F_ACK;
        hdr->nlmsg_seq = ++seq;
 
-       if (sendmsg(fd, &msg, 0) != -1)
-               r = get_netlink(fd, 0, &err_netlink);
+       if (sendmsg(sock_fd, &msg, 0) != -1)
+               r = get_netlink(sock_fd, 0, &err_netlink);
        else
                r = -1;
-       close(fd);
        return r;
 }
 
diff --git a/net.h b/net.h
index b65dc7ee10cd3757a26e9c82ff30bb4cdb010784..a8ede771a13a1656032b5909d436f5c83e598305 100644 (file)
--- a/net.h
+++ b/net.h
@@ -145,6 +145,7 @@ ssize_t send_raw_packet(const struct interface *, int,
                        const void *, ssize_t);
 ssize_t get_raw_packet(struct interface *, int, void *, ssize_t);
 
+int init_socket(void);
 int open_link_socket(void);
 int manage_link(int,
                void (*)(const char *),