diff options
author | Simon Kelley <simon@thekelleys.org.uk> | 2012-03-21 21:39:48 +0000 |
---|---|---|
committer | Simon Kelley <simon@thekelleys.org.uk> | 2012-03-21 21:39:48 +0000 |
commit | 52d4abf2f965574c5d135e0b43d027e553a31fa0 (patch) | |
tree | f5ccde468cc3e0ceadc82b053ebe8036ff0ea330 | |
parent | a9530964859fa901380e523a6c1c2fe5a8b75afd (diff) | |
download | dnsmasq-52d4abf2f965574c5d135e0b43d027e553a31fa0.tar.gz |
Make --listen-address work for all 127.0.0.0/8 addresses.
-rw-r--r-- | CHANGELOG | 11 | ||||
-rw-r--r-- | src/dnsmasq.c | 35 | ||||
-rw-r--r-- | src/dnsmasq.h | 2 | ||||
-rw-r--r-- | src/forward.c | 2 | ||||
-rw-r--r-- | src/network.c | 20 | ||||
-rw-r--r-- | src/tftp.c | 40 |
6 files changed, 76 insertions, 34 deletions
@@ -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) @@ -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) { |