Merge branch 'bind'

This commit is contained in:
Simon Kelley
2012-03-23 10:02:30 +00:00
8 changed files with 88 additions and 35 deletions

View File

@@ -40,7 +40,20 @@ version 2.61
Set the environment variable DNSMASQ_LOG_DHCP when running Set the environment variable DNSMASQ_LOG_DHCP when running
the script id --log-dhcp is in effect, so that script can 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.
Fix crash, introduced in 2.60, when a DHCPINFORM is
received from a network which has no valid dhcp-range.
Thanks to Stephane Glondu for the bug report.
version 2.60 version 2.60

6
debian/changelog vendored
View File

@@ -1,3 +1,9 @@
dnsmasq (2.60-2) unstable; urgency=high
* Fix DHCPv4 segfault. (closes: #665008)
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 23 Mar 2012 09:37:23 +0000
dnsmasq (2.61-1) unstable; urgency=low dnsmasq (2.61-1) unstable; urgency=low
* New upstream. * New upstream.

View File

@@ -209,13 +209,6 @@ int main (int argc, char **argv)
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next) for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && !if_tmp->used) if (if_tmp->name && !if_tmp->used)
die(_("unknown interface %s"), if_tmp->name, EC_BADNET); 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 else
create_wildcard_listeners(); create_wildcard_listeners();
@@ -1284,18 +1277,19 @@ static void check_dns_listeners(fd_set *set, time_t now)
int confd; int confd;
struct irec *iface = NULL; struct irec *iface = NULL;
pid_t p; 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; continue;
if (option_bool(OPT_NOWILD)) if (option_bool(OPT_NOWILD))
iface = listener->iface; iface = listener->iface; /* May be NULL */
else else
{ {
union mysockaddr tcp_addr;
socklen_t tcp_len = sizeof(union mysockaddr);
/* Check for allowed interfaces when binding the wildcard address: /* Check for allowed interfaces when binding the wildcard address:
we do this by looking for an interface with the same address as 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 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 too, for localisation. */
/* interface may be new since startup */ /* interface may be new since startup */
if (enumerate_interfaces() && if (enumerate_interfaces())
getsockname(confd, (struct sockaddr *)&tcp_addr, &tcp_len) != -1)
for (iface = daemon->interfaces; iface; iface = iface->next) for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, &tcp_addr)) if (sockaddr_isequal(&iface->addr, &tcp_addr))
break; break;
} }
if (!iface) if (!iface && !option_bool(OPT_NOWILD))
{ {
shutdown(confd, SHUT_RDWR); shutdown(confd, SHUT_RDWR);
close(confd); close(confd);
@@ -1336,6 +1329,12 @@ static void check_dns_listeners(fd_set *set, time_t now)
unsigned char *buff; unsigned char *buff;
struct server *s; struct server *s;
int flags; int flags;
struct in_addr netmask;
if (iface)
netmask = iface->netmask;
else
netmask.s_addr = 0;
#ifndef NO_FORK #ifndef NO_FORK
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
@@ -1354,7 +1353,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
if ((flags = fcntl(confd, F_GETFL, 0)) != -1) if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK); 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); shutdown(confd, SHUT_RDWR);
close(confd); close(confd);

View File

@@ -395,7 +395,7 @@ struct irec {
struct listener { struct listener {
int fd, tcpfd, tftpfd, family; 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; struct listener *next;
}; };

View File

@@ -667,7 +667,7 @@ void receive_query(struct listener *listen, time_t now)
/* packet buffer overwritten */ /* packet buffer overwritten */
daemon->srv_save = NULL; 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; dst_addr_4 = listen->iface->addr.in.sin_addr;
netmask = listen->iface->netmask; netmask = listen->iface->netmask;

View File

@@ -511,6 +511,7 @@ void create_bound_listeners(int dienow)
{ {
struct listener *new; struct listener *new;
struct irec *iface; struct irec *iface;
struct iname *if_tmp;
for (iface = daemon->interfaces; iface; iface = iface->next) for (iface = daemon->interfaces; iface; iface = iface->next)
if (!iface->done && !iface->dad && if (!iface->done && !iface->dad &&
@@ -521,6 +522,25 @@ void create_bound_listeners(int dienow)
daemon->listeners = new; daemon->listeners = new;
iface->done = 1; 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) int is_dad_listeners(void)

View File

@@ -2095,7 +2095,8 @@ static void do_options(struct dhcp_context *context,
struct dhcp_netid_list *id_list; struct dhcp_netid_list *id_list;
/* filter options based on tags, those we want get DHOPT_TAGOK bit set */ /* filter options based on tags, those we want get DHOPT_TAGOK bit set */
context->netid.next = NULL; if (context)
context->netid.next = NULL;
tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts); tagif = option_filter(netid, context && context->netid.net ? &context->netid : NULL, config_opts);
/* logging */ /* logging */

View File

@@ -57,7 +57,7 @@ void tftp_request(struct listener *listen, time_t now)
int mtuflag = IP_PMTUDISC_DONT; int mtuflag = IP_PMTUDISC_DONT;
#endif #endif
char namebuff[IF_NAMESIZE]; char namebuff[IF_NAMESIZE];
char *name; char *name = NULL;
char *prefix = daemon->tftp_prefix; char *prefix = daemon->tftp_prefix;
struct tftp_prefix *pref; struct tftp_prefix *pref;
struct interface_list *ir; struct interface_list *ir;
@@ -95,9 +95,20 @@ void tftp_request(struct listener *listen, time_t now)
if (option_bool(OPT_NOWILD)) if (option_bool(OPT_NOWILD))
{ {
addr = listen->iface->addr; if (listen->iface)
mtu = listen->iface->mtu; {
name = listen->iface->name; 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 else
{ {
@@ -211,15 +222,18 @@ void tftp_request(struct listener *listen, time_t now)
mtu = ifr.ifr_mtu; mtu = ifr.ifr_mtu;
} }
/* check for per-interface prefix */ if (name)
for (pref = daemon->if_prefix; pref; pref = pref->next) {
if (strcmp(pref->interface, name) == 0) /* check for per-interface prefix */
prefix = pref->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. */ /* wierd TFTP interfaces disable special options. */
for (ir = daemon->tftp_interfaces; ir; ir = ir->next) for (ir = daemon->tftp_interfaces; ir; ir = ir->next)
if (strcmp(ir->interface, name) == 0) if (strcmp(ir->interface, name) == 0)
special = 1; special = 1;
}
if (listen->family == AF_INET) if (listen->family == AF_INET)
{ {