summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Kelley <simon@thekelleys.org.uk>2012-03-21 21:39:48 +0000
committerSimon Kelley <simon@thekelleys.org.uk>2012-03-21 21:39:48 +0000
commit52d4abf2f965574c5d135e0b43d027e553a31fa0 (patch)
treef5ccde468cc3e0ceadc82b053ebe8036ff0ea330
parenta9530964859fa901380e523a6c1c2fe5a8b75afd (diff)
downloaddnsmasq-52d4abf2f965574c5d135e0b43d027e553a31fa0.tar.gz
Make --listen-address work for all 127.0.0.0/8 addresses.
-rw-r--r--CHANGELOG11
-rw-r--r--src/dnsmasq.c35
-rw-r--r--src/dnsmasq.h2
-rw-r--r--src/forward.c2
-rw-r--r--src/network.c20
-rw-r--r--src/tftp.c40
6 files changed, 76 insertions, 34 deletions
diff --git a/CHANGELOG b/CHANGELOG
index a08d25b..6c1c07b 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -40,7 +40,16 @@ version 2.61
Set the environment variable DNSMASQ_LOG_DHCP when running
the script id --log-dhcp is in effect, so that script can
- taylor their logging verbosity. Suggestion from Malte Forkel.
+ taylor their logging verbosity. Suggestion from Malte
+ Forkel.
+
+ Arrange that addresses specified with --listen-address
+ work even if there is no interface carrying the
+ address. This is chiefly useful for IPv4 loopback
+ addresses, where any address in 127.0.0.0/8 is a valid
+ loopback address, but normally only 127.0.0.1 appears on
+ the lo interface. Thanks to Mathieu Trudel-Lapierre for
+ the idea and initial patch.
version 2.60
diff --git a/src/dnsmasq.c b/src/dnsmasq.c
index efe63d1..8663aa3 100644
--- a/src/dnsmasq.c
+++ b/src/dnsmasq.c
@@ -209,13 +209,6 @@ int main (int argc, char **argv)
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && !if_tmp->used)
die(_("unknown interface %s"), if_tmp->name, EC_BADNET);
-
- for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
- if (!if_tmp->used)
- {
- prettyprint_addr(&if_tmp->addr, daemon->namebuff);
- die(_("no interface with address %s"), daemon->namebuff, EC_BADNET);
- }
}
else
create_wildcard_listeners();
@@ -1284,18 +1277,19 @@ static void check_dns_listeners(fd_set *set, time_t now)
int confd;
struct irec *iface = NULL;
pid_t p;
+ union mysockaddr tcp_addr;
+ socklen_t tcp_len = sizeof(union mysockaddr);
+
+ while ((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
- while((confd = accept(listener->tcpfd, NULL, NULL)) == -1 && errno == EINTR);
-
- if (confd == -1)
+ if (confd == -1 ||
+ getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) == -1)
continue;
if (option_bool(OPT_NOWILD))
- iface = listener->iface;
+ iface = listener->iface; /* May be NULL */
else
{
- union mysockaddr tcp_addr;
- socklen_t tcp_len = sizeof(union mysockaddr);
/* 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
@@ -1303,14 +1297,13 @@ static void check_dns_listeners(fd_set *set, time_t now)
interface too, for localisation. */
/* interface may be new since startup */
- if (enumerate_interfaces() &&
- getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
+ if (enumerate_interfaces())
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, &tcp_addr))
break;
}
- if (!iface)
+ if (!iface && !option_bool(OPT_NOWILD))
{
shutdown(confd, SHUT_RDWR);
close(confd);
@@ -1336,7 +1329,13 @@ static void check_dns_listeners(fd_set *set, time_t now)
unsigned char *buff;
struct server *s;
int flags;
-
+ struct in_addr netmask;
+
+ if (iface)
+ netmask = iface->netmask;
+ else
+ netmask.s_addr = 0;
+
#ifndef NO_FORK
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
terminate the process. */
@@ -1354,7 +1353,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
- buff = tcp_request(confd, now, &iface->addr, iface->netmask);
+ buff = tcp_request(confd, now, &tcp_addr, netmask);
shutdown(confd, SHUT_RDWR);
close(confd);
diff --git a/src/dnsmasq.h b/src/dnsmasq.h
index f2a6f36..0a3e66f 100644
--- a/src/dnsmasq.h
+++ b/src/dnsmasq.h
@@ -395,7 +395,7 @@ struct irec {
struct listener {
int fd, tcpfd, tftpfd, family;
- struct irec *iface; /* only valid for non-wildcard */
+ struct irec *iface; /* only sometimes valid for non-wildcard */
struct listener *next;
};
diff --git a/src/forward.c b/src/forward.c
index e3bf7d7..f999dc6 100644
--- a/src/forward.c
+++ b/src/forward.c
@@ -660,7 +660,7 @@ void receive_query(struct listener *listen, time_t now)
/* packet buffer overwritten */
daemon->srv_save = NULL;
- if (listen->family == AF_INET && option_bool(OPT_NOWILD))
+ if (listen->iface && listen->family == AF_INET && option_bool(OPT_NOWILD))
{
dst_addr_4 = listen->iface->addr.in.sin_addr;
netmask = listen->iface->netmask;
diff --git a/src/network.c b/src/network.c
index 32bd517..f5dcf97 100644
--- a/src/network.c
+++ b/src/network.c
@@ -511,6 +511,7 @@ void create_bound_listeners(int dienow)
{
struct listener *new;
struct irec *iface;
+ struct iname *if_tmp;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (!iface->done && !iface->dad &&
@@ -521,6 +522,25 @@ void create_bound_listeners(int dienow)
daemon->listeners = new;
iface->done = 1;
}
+
+ /* Check for --listen-address options that haven't been used because there's
+ no interface with a matching address. These may be valid: eg it's possible
+ to listen on 127.0.1.1 even if the loopback interface is 127.0.0.1
+
+ If the address isn't valid the bind() will fail and we'll die().
+
+ The resulting listeners have the ->iface field NULL, and this has to be
+ handled by the DNS and TFTP code. It disables --localise-queries processing
+ (no netmask) and some MTU login the tftp code. */
+
+ for (if_tmp = daemon->if_addrs; if_tmp; if_tmp = if_tmp->next)
+ if (!if_tmp->used &&
+ (new = create_listeners(&if_tmp->addr, 1, dienow)))
+ {
+ new->iface = NULL;
+ new->next = daemon->listeners;
+ daemon->listeners = new;
+ }
}
int is_dad_listeners(void)
diff --git a/src/tftp.c b/src/tftp.c
index 3ef6545..f6c0e21 100644
--- a/src/tftp.c
+++ b/src/tftp.c
@@ -57,7 +57,7 @@ void tftp_request(struct listener *listen, time_t now)
int mtuflag = IP_PMTUDISC_DONT;
#endif
char namebuff[IF_NAMESIZE];
- char *name;
+ char *name = NULL;
char *prefix = daemon->tftp_prefix;
struct tftp_prefix *pref;
struct interface_list *ir;
@@ -95,9 +95,20 @@ void tftp_request(struct listener *listen, time_t now)
if (option_bool(OPT_NOWILD))
{
- addr = listen->iface->addr;
- mtu = listen->iface->mtu;
- name = listen->iface->name;
+ if (listen->iface)
+ {
+ addr = listen->iface->addr;
+ mtu = listen->iface->mtu;
+ name = listen->iface->name;
+ }
+ else
+ {
+ /* we're listening on an address that doesn't appear on an interface,
+ ask the kernel what the socket is bound to */
+ socklen_t tcp_len = sizeof(union mysockaddr);
+ if (getsockname(listen->tftpfd, (struct sockaddr *)&addr, &tcp_len) == -1)
+ return;
+ }
}
else
{
@@ -211,15 +222,18 @@ void tftp_request(struct listener *listen, time_t now)
mtu = ifr.ifr_mtu;
}
- /* check for per-interface prefix */
- for (pref = daemon->if_prefix; pref; pref = pref->next)
- if (strcmp(pref->interface, name) == 0)
- prefix = pref->prefix;
-
- /* wierd TFTP interfaces disable special options. */
- for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
- if (strcmp(ir->interface, name) == 0)
- special = 1;
+ if (name)
+ {
+ /* check for per-interface prefix */
+ for (pref = daemon->if_prefix; pref; pref = pref->next)
+ if (strcmp(pref->interface, name) == 0)
+ prefix = pref->prefix;
+
+ /* wierd TFTP interfaces disable special options. */
+ for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
+ if (strcmp(ir->interface, name) == 0)
+ special = 1;
+ }
if (listen->family == AF_INET)
{