diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2013-05-23 10:04:25 +0100 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2013-05-23 10:04:25 +0100 |
commit | 76dd75de777cb7fee388bd61315686322c9862ab (patch) | |
tree | 0ba5b07ff6b118d2606092493ce4e4c0bf97a358 | |
parent | 63fd27e35f85a1f535efc73734165917190f387e (diff) | |
download | dnsmasq-76dd75de777cb7fee388bd61315686322c9862ab.tar.gz |
Fix hang from new interface-name code, when using TCP.
-rw-r--r-- | src/dnsmasq.c | 106 | ||||
-rw-r--r-- | src/network.c | 4 |
2 files changed, 60 insertions, 50 deletions
diff --git a/src/dnsmasq.c b/src/dnsmasq.c index 62e65a9..71d4412 100644 --- a/src/dnsmasq.c +++ b/src/dnsmasq.c @@ -1355,63 +1355,71 @@ static void check_dns_listeners(fd_set *set, time_t now) if (confd == -1) continue; - + if (getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1) { close(confd); continue; } - - if (option_bool(OPT_NOWILD)) - iface = listener->iface; /* May be NULL */ - else - { - int if_index; - char intr_name[IF_NAMESIZE]; + + /* Make sure that the interface list is up-to-date. + + We do this here as we may need the results below, and + the DNS code needs them for --interface-name stuff. + + Multiple calls to enumerate_interfaces() per select loop are + inhibited, so calls to it in the child process (which doesn't select()) + have no effect. This avoids two processes reading from the same + netlink fd and screwing the pooch entirely. + */ - /* In full wildcard mode, need to refresh interface list. - This happens automagically in CLEVERBIND */ - if (!option_bool(OPT_CLEVERBIND)) - enumerate_interfaces(0); - - /* if we can find the arrival interface, check it's one that's allowed */ - if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 && - indextoname(listener->tcpfd, if_index, intr_name)) - { - struct all_addr addr; - addr.addr.addr4 = tcp_addr.in.sin_addr; + enumerate_interfaces(0); + + if (option_bool(OPT_NOWILD)) + iface = listener->iface; /* May be NULL */ + else + { + int if_index; + char intr_name[IF_NAMESIZE]; + + /* if we can find the arrival interface, check it's one that's allowed */ + if ((if_index = tcp_interface(confd, tcp_addr.sa.sa_family)) != 0 && + indextoname(listener->tcpfd, if_index, intr_name)) + { + struct all_addr addr; + addr.addr.addr4 = tcp_addr.in.sin_addr; #ifdef HAVE_IPV6 - if (tcp_addr.sa.sa_family == AF_INET6) - addr.addr.addr6 = tcp_addr.in6.sin6_addr; + if (tcp_addr.sa.sa_family == AF_INET6) + addr.addr.addr6 = tcp_addr.in6.sin6_addr; #endif - - for (iface = daemon->interfaces; iface; iface = iface->next) - if (iface->index == if_index) - break; - - if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name)) - client_ok = 0; - } - - if (option_bool(OPT_CLEVERBIND)) - iface = listener->iface; /* May be NULL */ - else - { - /* Check for allowed interfaces when binding the wildcard address: - we do this by looking for an interface with the same address as - the local address of the TCP connection, then looking to see if that's - an allowed interface. As a side effect, we get the netmask of the - interface too, for localisation. */ - - for (iface = daemon->interfaces; iface; iface = iface->next) - if (sockaddr_isequal(&iface->addr, &tcp_addr)) - break; - - if (!iface) - client_ok = 0; - } - } - + + for (iface = daemon->interfaces; iface; iface = iface->next) + if (iface->index == if_index) + break; + + if (!iface && !loopback_exception(listener->tcpfd, tcp_addr.sa.sa_family, &addr, intr_name)) + client_ok = 0; + } + + if (option_bool(OPT_CLEVERBIND)) + iface = listener->iface; /* May be NULL */ + else + { + /* Check for allowed interfaces when binding the wildcard address: + we do this by looking for an interface with the same address as + the local address of the TCP connection, then looking to see if that's + an allowed interface. As a side effect, we get the netmask of the + interface too, for localisation. */ + + for (iface = daemon->interfaces; iface; iface = iface->next) + if (sockaddr_isequal(&iface->addr, &tcp_addr)) + break; + + if (!iface) + client_ok = 0; + } + } + if (!client_ok) { shutdown(confd, SHUT_RDWR); diff --git a/src/network.c b/src/network.c index 575af32..19f7b37 100644 --- a/src/network.c +++ b/src/network.c @@ -438,7 +438,9 @@ int enumerate_interfaces(int reset) struct addrlist *addr, *tmp; struct interface_name *intname; - /* DO this max once per select cycle */ + /* Do this max once per select cycle - also inhibits netlink socket use + in TCP child processes. */ + if (reset) { done = 0; |