From: Roy Marples Date: Fri, 15 Feb 2013 20:33:13 +0000 (+0000) Subject: Instead of opening link, ipv6, ipv6rs and ipv6ns sockets globally, X-Git-Tag: v5.99.6~74 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fbbb0875dd748a22dcf6d91a7d3cdaed5a90dc58;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 2db1924c..d2a7b875 100644 --- a/dhcpcd.c +++ b/dhcpcd.c @@ -453,16 +453,45 @@ start_interface(void *arg) dhcp_start(ifp); } +/* 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 *ifp, int argc, char **argv) { + struct if_options *ifo; const char *reason = NULL; configure_interface(ifp, argc, argv); + ifo = ifp->options; + + if (if_options->options & DHCPCD_LINK && linkfd == -1) { + linkfd = open_link_socket(); + if (linkfd == -1) { + syslog(LOG_ERR, "open_link_socket: %m"); + ifo->options &= ~DHCPCD_LINK; + } else + eloop_event_add(linkfd, handle_link, NULL); + } + + if (ifo->options & DHCPCD_IPV6RS && !check_ipv6(NULL)) + ifo->options &= ~DHCPCD_IPV6RS; + if (ifo->options & DHCPCD_IPV6RS && ipv6_init() == -1) { + ifo->options &= ~DHCPCD_IPV6RS; + syslog(LOG_ERR, "ipv6_init: %m"); + } + + if (!(options & DHCPCD_TEST)) script_runreason(ifp, "PREINIT"); - if (ifp->options->options & DHCPCD_LINK) { + if (ifo->options & DHCPCD_LINK) { switch (carrier_status(ifp)) { case 0: ifp->carrier = LINK_DOWN; @@ -573,15 +602,6 @@ handle_hwaddr(const char *ifname, unsigned char *hwaddr, size_t hwlen) } #endif -/* 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 *ifp, int argc, char **argv) { @@ -1105,13 +1125,6 @@ main(int argc, char **argv) syslog(LOG_ERR, "open_sockets: %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 - eloop_event_add(linkfd, handle_link, NULL); - } #if 0 if (options & DHCPCD_IPV6RS && disable_rtadv() == -1) { @@ -1120,15 +1133,6 @@ main(int argc, char **argv) } #endif - if (options & DHCPCD_IPV6 && ipv6_init() == -1) { - options &= ~DHCPCD_IPV6; - syslog(LOG_ERR, "ipv6_init: %m"); - } - if (options & DHCPCD_IPV6RS && !check_ipv6(NULL)) - options &= ~DHCPCD_IPV6RS; - if (options & DHCPCD_IPV6RS) - ipv6rs_init(); - ifc = argc - optind; ifv = argv + optind; diff --git a/ipv6.c b/ipv6.c index 03a8dc16..fc15883d 100644 --- a/ipv6.c +++ b/ipv6.c @@ -35,6 +35,7 @@ #include #include #include +#include #include "common.h" #include "dhcpcd.h" @@ -66,14 +67,15 @@ ipv6_cleanup() int ipv6_init(void) { - routes = malloc(sizeof(*routes)); - if (routes == NULL) - return -1; - - TAILQ_INIT(routes); + if (routes == NULL) { + routes = malloc(sizeof(*routes)); + if (routes == NULL) + return -1; + TAILQ_INIT(routes); #ifdef DEBUG_MEMORY - atexit(ipv6_cleanup); + atexit(ipv6_cleanup); #endif + } return 0; } diff --git a/ipv6ns.c b/ipv6ns.c index 62dde878..c98a2cfa 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]; @@ -70,6 +71,8 @@ static unsigned char *rcvbuf; static unsigned char ansbuf[1500]; static char ntopbuf[INET6_ADDRSTRLEN]; +static void ipv6ns_handledata(_unused void *arg); + #if DEBUG_MEMORY static void ipv6ns_cleanup(void) @@ -92,19 +95,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 +115,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 +135,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 +154,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 +194,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; + } + eloop_event_add(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 +240,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 == 0 ? RETRANS_TIMER : rap->retrans); diff --git a/ipv6rs.c b/ipv6rs.c index 8193fa00..ac30346c 100644 --- a/ipv6rs.c +++ b/ipv6rs.c @@ -43,6 +43,7 @@ #include #include #include +#include #define ELOOP_QUEUE 1 #include "common.h" @@ -104,7 +105,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]; @@ -132,31 +133,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 @@ -164,17 +166,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; @@ -184,6 +186,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 @@ -786,8 +797,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->options->options & DHCPCD_IPV6RA_OWN || + ifp->options->options & DHCPCD_IPV6RA_OWN_DEFAULT) { rap->nsprobes = 0; ipv6ns_sendprobe(rap); @@ -1085,19 +1096,33 @@ ipv6rs_start(struct interface *ifp) { struct rs_state *state; - eloop_timeout_delete(NULL, ifp); - - state = RS_STATE(ifp); - if (state == NULL) { - ifp->if_data[IF_DATA_IPV6RS] = xzalloc(sizeof(*state)); - state = RS_STATE(ifp); + if (sock == -1) { + if (ipv6rs_open() == -1) { + syslog(LOG_ERR, "%s: ipv6rs_open: %m", __func__); + return -1; + } + eloop_event_add(sock, ipv6rs_handledata, NULL); } - /* Always make a new probe as the underlying hardware - * address could have changed. */ - ipv6rs_makeprobe(ifp); - if (state->rs == NULL) - return -1; + eloop_timeout_delete(NULL, ifp); + + state = RS_STATE(ifp); + if (state == NULL) { + 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) { + syslog(LOG_ERR, "%s: ipv6rs_makeprobe: %m", __func__); + return -1; + } state->rsprobes = 0; ipv6rs_sendprobe(ifp);