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.
This commit is contained in:
Roy Marples 2013-02-15 20:33:13 +00:00
parent cebe222c56
commit fbbb0875dd
4 changed files with 124 additions and 72 deletions

View File

@ -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;

14
ipv6.c
View File

@ -35,6 +35,7 @@
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#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;
}

View File

@ -39,6 +39,7 @@
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#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);

View File

@ -43,6 +43,7 @@
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
#include <unistd.h>
#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);