summaryrefslogtreecommitdiff
path: root/src/network.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/network.c')
-rw-r--r--src/network.c15
1 files changed, 12 insertions, 3 deletions
diff --git a/src/network.c b/src/network.c
index d542c94..1bc3c21 100644
--- a/src/network.c
+++ b/src/network.c
@@ -360,7 +360,6 @@ void create_bound_listener(struct listener** listeners, struct irec* iface) {
new->next = *listeners;
new->tcpfd = -1;
new->fd = -1;
- *listeners = new;
if (daemon->port != 0) {
if ((new->tcpfd = socket(iface->addr.sa.sa_family, SOCK_STREAM, 0)) == -1 ||
@@ -378,12 +377,17 @@ void create_bound_listener(struct listener** listeners, struct irec* iface) {
}
#endif
+ /* Unless the IPv6 address is added with IFA_F_NODAD, bind() can fail even if DAD
+ is disabled on the interface. This is because without IFA_F_NODAD the IPv6
+ address creation call moves the IPv6 address to tentative. A timer will
+ fire to immediately remove the tentative flag, but this is not sufficient to
+ avoid a race condition (see comments in tun_interface.cpp and iproute.py). */
while (1) {
if ((rc = bind(new->fd, &iface->addr.sa, sa_len(&iface->addr))) != -1) break;
#ifdef HAVE_IPV6
/* An interface may have an IPv6 address which is still undergoing DAD.
- If so, the bind will fail until the DAD completes, so we try over 20 seconds
+ If so, the bind will fail until the DAD completes, so we try again
before failing. */
/* TODO: What to do here? 20 seconds is way too long. We use optimistic addresses, so
bind() will only fail if the address has already failed DAD, in which case retrying
@@ -399,7 +403,11 @@ void create_bound_listener(struct listener** listeners, struct irec* iface) {
if (rc == -1 || bind(new->tcpfd, &iface->addr.sa, sa_len(&iface->addr)) == -1) {
prettyprint_addr(&iface->addr, daemon->namebuff);
- die(_("failed to bind listening socket for %s: %s"), daemon->namebuff, EC_BADNET);
+ close(new->fd);
+ close(new->tcpfd);
+ free(new);
+ syslog(LOG_ERR, _("failed to bind listening socket for %s"), daemon->namebuff);
+ return;
}
uint32_t mark = daemon->listen_mark;
@@ -409,6 +417,7 @@ void create_bound_listener(struct listener** listeners, struct irec* iface) {
if (listen(new->tcpfd, 5) == -1) die(_("failed to listen on socket: %s"), NULL, EC_BADNET);
}
+ *listeners = new;
}
/**