From: Roy Marples Date: Fri, 15 Feb 2013 20:14:32 +0000 (+0000) Subject: Instead of opening link, ipv6, ipv6rs and ipv6ns sockets globally, X-Git-Tag: v5.6.8~7 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=09421f5aa94a143388d96002b5a99ae09b53eb05;p=thirdparty%2Fdhcpcd.git Instead of opening link, ipv6, ipv6rs and ipv6ns sockets globally, only open when the first link wanting this features needs it. Hopefully fixes #263 and #264. --- diff --git a/dhcpcd.c b/dhcpcd.c index 7046a4dc..669eb959 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -96,7 +96,7 @@ static char **ifv; static int ifc; static char *cffile; static char *pidfile; -static int linkfd = -1, ipv6rsfd = -1, ipv6nsfd = -1; +static int linkfd = -1; static uint8_t *packet; struct dhcp_op { @@ -1268,10 +1268,19 @@ start_interface(void *arg) start_reboot(iface); } +/* ARGSUSED */ +static void +handle_link(_unused void *arg) +{ + if (manage_link(linkfd) == -1) + syslog(LOG_ERR, "manage_link: %m"); +} + static void init_state(struct interface *iface, int argc, char **argv) { struct if_state *ifs; + struct if_options *ifo; if (iface->state) ifs = iface->state; @@ -1282,6 +1291,23 @@ init_state(struct interface *iface, int argc, char **argv) ifs->reason = "PREINIT"; ifs->nakoff = 0; configure_interface(iface, argc, argv); + ifo = ifs->options; + + if (if_options->options & DHCPCD_LINK && linkfd == -1) { + linkfd = open_link_socket(); + if (linkfd == -1) + syslog(LOG_ERR, "open_link_socket: %m"); + else + add_event(linkfd, handle_link, NULL); + } + + if (ifo->options & DHCPCD_IPV6RS && !check_ipv6(NULL)) + options &= ~DHCPCD_IPV6RS; + if (ifo->options & DHCPCD_IPV6RS && ipv6_open() == -1) { + options &= ~DHCPCD_IPV6RS; + syslog(LOG_ERR, "ipv6_open: %m"); + } + if (!(options & DHCPCD_TEST)) run_script(iface); /* We need to drop the leasefile so that start_interface @@ -1452,14 +1478,6 @@ handle_ifa(int type, const char *ifname, } } -/* ARGSUSED */ -static void -handle_link(_unused void *arg) -{ - if (manage_link(linkfd) == -1) - syslog(LOG_ERR, "manage_link: %m"); -} - static void if_reboot(struct interface *iface, int argc, char **argv) { @@ -2023,13 +2041,6 @@ main(int argc, char **argv) syslog(LOG_ERR, "init_socket: %m"); exit(EXIT_FAILURE); } - if (if_options->options & DHCPCD_LINK) { - linkfd = open_link_socket(); - if (linkfd == -1) - syslog(LOG_ERR, "open_link_socket: %m"); - else - add_event(linkfd, handle_link, NULL); - } #if 0 if (options & DHCPCD_IPV6RS && disable_rtadv() == -1) { @@ -2038,32 +2049,6 @@ main(int argc, char **argv) } #endif - if (options & DHCPCD_IPV6RS && !check_ipv6(NULL)) - options &= ~DHCPCD_IPV6RS; - if (options & DHCPCD_IPV6RS && ipv6_open() == -1) { - options &= ~DHCPCD_IPV6RS; - syslog(LOG_ERR, "ipv6_open: %m"); - } - if (options & DHCPCD_IPV6RS) { - ipv6rsfd = ipv6rs_open(); - if (ipv6rsfd == -1) { - syslog(LOG_ERR, "ipv6rs: %m"); - options &= ~DHCPCD_IPV6RS; - } else { - add_event(ipv6rsfd, ipv6rs_handledata, NULL); -// atexit(restore_rtadv); - } - if (options & DHCPCD_IPV6RA_OWN || - options & DHCPCD_IPV6RA_OWN_DEFAULT) - { - ipv6nsfd = ipv6ns_open(); - if (ipv6nsfd == -1) - syslog(LOG_ERR, "ipv6nd: %m"); - else - add_event(ipv6nsfd, ipv6ns_handledata, NULL); - } - } - ifc = argc - optind; ifv = argv + optind; diff --git a/ipv6.c b/ipv6.c index c20d98ad..971f84da 100644 --- a/ipv6.c +++ b/ipv6.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "common.h" #include "configure.h" @@ -47,7 +48,7 @@ # define s6_addr32 __u6_addr.__u6_addr32 #endif -int socket_afnet6; +int socket_afnet6 = -1; static struct rt6head *routes; #ifdef DEBUG_MEMORY @@ -67,11 +68,21 @@ ipv6_cleanup() int ipv6_open(void) { + + if (socket_afnet6 != -1) + return socket_afnet6; + socket_afnet6 = socket(AF_INET6, SOCK_DGRAM, 0); if (socket_afnet6 == -1) return -1; set_cloexec(socket_afnet6); - routes = xmalloc(sizeof(*routes)); + routes = malloc(sizeof(*routes)); + if (routes == NULL) { + close(socket_afnet6); + socket_afnet6 = -1; + return -1; + } + TAILQ_INIT(routes); #ifdef DEBUG_MEMORY atexit(ipv6_cleanup); diff --git a/ipv6ns.c b/ipv6ns.c index c66770c2..8bfac4c8 100644 --- a/ipv6ns.c +++ b/ipv6ns.c @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef __linux__ # define _LINUX_IN6_H @@ -59,7 +60,7 @@ /* Debugging Neighbor Solicitations is a lot of spam, so disable it */ //#define DEBUG_NS -static int sock; +static int sock = -1; static struct sockaddr_in6 from; static struct msghdr sndhdr; static struct iovec sndiov[2]; @@ -92,19 +93,19 @@ ipv6ns_open(void) return -1; on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, - &on, sizeof(on)) == -1) - return -1; + &on, sizeof(on)) == -1) + goto eexit; on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, - &on, sizeof(on)) == -1) - return -1; + &on, sizeof(on)) == -1) + goto eexit; ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_NEIGHBOR_ADVERT, &filt); if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, - &filt, sizeof(filt)) == -1) - return -1; + &filt, sizeof(filt)) == -1) + goto eexit; set_cloexec(sock); #if DEBUG_MEMORY @@ -112,17 +113,17 @@ ipv6ns_open(void) #endif len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); - sndbuf = xzalloc(len); + sndbuf = calloc(1, len); if (sndbuf == NULL) - return -1; + goto eexit; sndhdr.msg_namelen = sizeof(struct sockaddr_in6); sndhdr.msg_iov = sndiov; sndhdr.msg_iovlen = 1; sndhdr.msg_control = sndbuf; sndhdr.msg_controllen = len; - rcvbuf = xzalloc(len); + rcvbuf = calloc(1, len); if (rcvbuf == NULL) - return -1; + goto eexit; rcvhdr.msg_name = &from; rcvhdr.msg_namelen = sizeof(from); rcvhdr.msg_iov = rcviov; @@ -132,6 +133,15 @@ ipv6ns_open(void) rcviov[0].iov_base = ansbuf; rcviov[0].iov_len = sizeof(ansbuf); return sock; + +eexit: + close(sock); + sock = -1; + free(sndbuf); + sndbuf = NULL; + free(rcvbuf); + rcvbuf = NULL; + return -1; } static int @@ -142,7 +152,7 @@ ipv6ns_makeprobe(struct ra *rap) free(rap->ns); rap->nslen = sizeof(*ns) + ROUNDUP8(rap->iface->hwlen + 2); - rap->ns = xzalloc(rap->nslen); + rap->ns = calloc(1, rap->nslen); if (rap->ns == NULL) return -1; ns = (struct nd_neighbor_solicit *)(void *)rap->ns; @@ -182,9 +192,17 @@ ipv6ns_sendprobe(void *arg) int hoplimit = HOPLIMIT; struct timeval tv, rtv; - if (!rap->ns) { - if (ipv6ns_makeprobe(rap) == -1) + if (sock == -1) { + if (ipv6ns_open() == -1) { + syslog(LOG_ERR, "%s: ipv6ns_open: %m", __func__); return; + } + add_event(sock, ipv6ns_handledata, NULL); + } + + if (!rap->ns && ipv6ns_makeprobe(rap) == -1) { + syslog(LOG_ERR, "%s: ipv6ns_makeprobe: %m", __func__); + return; } memset(&dst, 0, sizeof(dst)); @@ -220,7 +238,8 @@ ipv6ns_sendprobe(void *arg) rap->iface->name, rap->sfrom); #endif if (sendmsg(sock, &sndhdr, 0) == -1) - syslog(LOG_ERR, "%s: sendmsg: %m", rap->iface->name); + syslog(LOG_ERR, "%s: %s: sendmsg: %m", + __func__, rap->iface->name); ms_to_tv(&tv, rap->retrans ? rap->retrans : RETRANS_TIMER); diff --git a/ipv6rs.c b/ipv6rs.c index 8e371a8f..c6b4102a 100644 --- a/ipv6rs.c +++ b/ipv6rs.c @@ -38,6 +38,7 @@ #include #include #include +#include #ifdef __linux__ # define _LINUX_IN6_H @@ -101,7 +102,7 @@ struct nd_opt_dnssl { /* DNSSL option RFC 6106 */ struct rahead ipv6_routers = TAILQ_HEAD_INITIALIZER(ipv6_routers); -static int sock; +static int sock = -1; static struct sockaddr_in6 allrouters, from; static struct msghdr sndhdr; static struct iovec sndiov[2]; @@ -129,31 +130,32 @@ ipv6rs_open(void) int len; struct icmp6_filter filt; + sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); + if (sock == -1) + return -1; + memset(&allrouters, 0, sizeof(allrouters)); allrouters.sin6_family = AF_INET6; #ifdef SIN6_LEN allrouters.sin6_len = sizeof(allrouters); #endif if (inet_pton(AF_INET6, ALLROUTERS, &allrouters.sin6_addr.s6_addr) != 1) - return -1; - sock = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6); - if (sock == -1) - return -1; + goto eexit; on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on)) == -1) - return -1; + goto eexit; on = 1; if (setsockopt(sock, IPPROTO_IPV6, IPV6_RECVHOPLIMIT, &on, sizeof(on)) == -1) - return -1; + goto eexit; ICMP6_FILTER_SETBLOCKALL(&filt); ICMP6_FILTER_SETPASS(ND_ROUTER_ADVERT, &filt); if (setsockopt(sock, IPPROTO_ICMPV6, ICMP6_FILTER, &filt, sizeof(filt)) == -1) - return -1; + goto eexit; set_cloexec(sock); #if DEBUG_MEMORY @@ -161,17 +163,17 @@ ipv6rs_open(void) #endif len = CMSG_SPACE(sizeof(struct in6_pktinfo)) + CMSG_SPACE(sizeof(int)); - sndbuf = xzalloc(len); + sndbuf = calloc(1, len); if (sndbuf == NULL) - return -1; + goto eexit; sndhdr.msg_namelen = sizeof(struct sockaddr_in6); sndhdr.msg_iov = sndiov; sndhdr.msg_iovlen = 1; sndhdr.msg_control = sndbuf; sndhdr.msg_controllen = len; - rcvbuf = xzalloc(len); + rcvbuf = calloc(1, len); if (rcvbuf == NULL) - return -1; + goto eexit; rcvhdr.msg_name = &from; rcvhdr.msg_namelen = sizeof(from); rcvhdr.msg_iov = rcviov; @@ -181,6 +183,15 @@ ipv6rs_open(void) rcviov[0].iov_base = ansbuf; rcviov[0].iov_len = sizeof(ansbuf); return sock; + +eexit: + close(sock); + sock = -1; + free(sndbuf); + sndbuf = NULL; + free(rcvbuf); + rcvbuf = NULL; + return -1; } static int @@ -462,7 +473,7 @@ ipv6rs_handledata(_unused void *arg) syslog(LOG_ERR, "RA for unexpected interface from %s", sfrom); return; } - if (!(ifp->options->options & DHCPCD_IPV6RS)) { + if (!(ifp->state->options->options & DHCPCD_IPV6RS)) { #ifdef DEBUG_RS syslog(LOG_DEBUG, "%s: unexpected RA from %s", ifp->name, sfrom); @@ -798,8 +809,8 @@ ipv6rs_handledata(_unused void *arg) /* If we're owning the RA then we need to try and ensure the * router is actually reachable */ - if (options & DHCPCD_IPV6RA_OWN || - options & DHCPCD_IPV6RA_OWN_DEFAULT) + if (ifp->state->options->options & DHCPCD_IPV6RA_OWN || + ifp->state->options->options & DHCPCD_IPV6RA_OWN_DEFAULT) { rap->nsprobes = 0; ipv6ns_sendprobe(rap); @@ -1067,19 +1078,33 @@ ipv6rs_start(struct interface *ifp) { struct rs_state *state; + if (sock == -1) { + if (ipv6rs_open() == -1) { + syslog(LOG_ERR, "%s: ipv6rs_open: %m", __func__); + return -1; + } + add_event(sock, ipv6rs_handledata, NULL); + } + delete_timeout(NULL, ifp); state = RS_STATE(ifp); if (state == NULL) { - ifp->if_data[IF_DATA_IPV6RS] = xzalloc(sizeof(*state)); + ifp->if_data[IF_DATA_IPV6RS] = calloc(1, sizeof(*state)); state = RS_STATE(ifp); + if (state == NULL) { + syslog(LOG_ERR, "%s: %m", __func__); + return -1; + } } /* Always make a new probe as the underlying hardware * address could have changed. */ ipv6rs_makeprobe(ifp); - if (state->rs == NULL) + if (state->rs == NULL) { + syslog(LOG_ERR, "%s: ipv6rs_makeprobe: %m", __func__); return -1; + } state->rsprobes = 0; ipv6rs_sendprobe(ifp);