summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2013-05-23 10:04:25 +0100
committerSimon Kelley <simon@thekelleys.org.uk>2013-05-23 10:04:25 +0100
commit76dd75de777cb7fee388bd61315686322c9862ab (patch)
tree0ba5b07ff6b118d2606092493ce4e4c0bf97a358
parent63fd27e35f85a1f535efc73734165917190f387e (diff)
downloaddnsmasq-76dd75de777cb7fee388bd61315686322c9862ab.tar.gz
Fix hang from new interface-name code, when using TCP.
-rw-r--r--src/dnsmasq.c106
-rw-r--r--src/network.c4
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;