diff --git a/configure.c b/configure.c index 96d8d886..a5af5a2a 100644 --- a/configure.c +++ b/configure.c @@ -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 diff --git a/configure.h b/configure.h index 5d0124de..d103b6e5 100644 --- a/configure.h +++ b/configure.h @@ -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 diff --git a/dhcpcd.c b/dhcpcd.c index 96ce2bec..4832f186 100644 --- 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) diff --git a/dhcpcd.h b/dhcpcd.h index 085550e8..7c33b22c 100644 --- 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 *); diff --git a/if-bsd.c b/if-bsd.c index 46a87aca..8648a1a1 100644 --- a/if-bsd.c +++ b/if-bsd.c @@ -67,10 +67,25 @@ 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; } diff --git a/if-linux.c b/if-linux.c index 6763c2b8..71723e92 100644 --- a/if-linux.c +++ b/if-linux.c @@ -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 b65dc7ee..a8ede771 100644 --- 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 *),