Compare commits

...
18 Commits
Author SHA1 Message Date
Simon Kelley e2ba0df2d4 Don't BIND DHCP socket if more interfaces may come along later. 2013-05-31 17:04:25 +01:00
Simon Kelley 921360ce62 Add constructor-noauth: keyword 2013-05-31 14:07:22 +01:00
Simon Kelley 429805dbbc Allow constructed ranges from interface address at end of range.
Also make man page on this clearer, as it's been confusing many.
2013-05-31 13:47:26 +01:00
Marcelo Salhab Brogliato 0da5e8979b Log forwarding table overflows. 2013-05-31 11:49:06 +01:00
Simon Kelley baa80ae512 Remove limit in prefix length in --auth-zone. 2013-05-29 16:32:07 +01:00
Simon Kelley 3e8ed78bf1 Fix option parsing for --dhcp-host. 2013-05-29 14:31:33 +01:00
Simon Kelley 48493329d6 Update Debian resolvconf script for dnscrypt-proxy integration. 2013-05-28 14:49:54 +01:00
Simon Kelley 76dd75de77 Fix hang from new interface-name code, when using TCP. 2013-05-23 10:04:25 +01:00
Simon Kelley 63fd27e35f Debian changelog update. 2013-05-20 11:50:33 +01:00
Simon Kelley 115ac3e4d7 Generalise --interface-name to cope with IPv6 addresses. 2013-05-20 11:28:32 +01:00
Simon Kelley cfcad42ff1 Fix failure to start with ENOTSOCK 2013-05-17 11:32:03 +01:00
Simon Kelley 3f2873d42c Handle IPv4 interface-address labels in Linux. 2013-05-14 11:28:47 +01:00
Simon Kelley ab915f837c Only use ourselves as default DNS server for RA if we're doing DNS.
This makes RA the same as DHCP4/6
2013-04-30 10:43:09 +01:00
Simon Kelley ddd9a6b499 replace inet_addr with inet_pton() in src/option.c 2013-04-29 17:00:21 +01:00
Simon Kelley 7abb69b5dc Tighten checks in legal_hostname(). 2013-04-29 10:52:16 +01:00
Simon Kelley d5052fb24f Fix FTBFS in ipset.c with old kernel headers. 2013-04-25 12:44:20 +01:00
Simon Kelley b5a7ff42bb Check length of synth-domain prefix. 2013-04-25 11:03:47 +01:00
Simon Kelley 48fd1c4dd6 Allow option prefix in --synth-domain. 2013-04-25 09:49:38 +01:00
24 changed files with 738 additions and 354 deletions

No files matched your search

+38 -1
View File
@@ -18,8 +18,45 @@ version 2.67
Add --synth-domain. Thanks to Vishvananda Ishaya for
suggesting this.
Fix failure to compile ipset.c if old kernel headers are
in use. Thanks to Eugene Rudoy for pointing this out.
Handle IPv4 interface-address labels in Linux. These are
often used to emulate the old IP-alias addresses. Before,
using --interface=eth0 would service all the addresses of
eth0, including ones configured as aliases, which appear
in ifconfig as eth0:0. Now, only addresses with the label
eth0 are active. This is not backwards compatible: if you
want to continue to bind the aliases too, you need to add
eg. --interface=eth0:0 to the config.
Fix "failed to set SO_BINDTODEVICE on DHCP socket: Socket
operation on non-socket" error on startup with
configurations which have exactly one --interface option
and do RA but _not_ DHCPv6. Thanks to Trever Adams for the
bug report.
Generalise --interface-name to cope with IPv6 addresses
and multiple addresses per interface per address family.
Fix option parsing for --dhcp-host, which was generating a
spurious error when all seven possible items were
included. Thanks to Zhiqiang Wang for the bug report.
Remove restriction on prefix-length in --auth-zone. Thanks
to Toke Hoiland-Jorgensen for suggesting this.
Log when the maximum number of concurrent DNS queries is
reached. Thanks to Marcelo Salhab Brogliato for the patch.
If wildcards are used in --interface, don't assume that
there will only ever be one available interface for DHCP
just because there is one at start-up. More may appear, so
we can't use SO_BINDTODEVICE. Thanks to Natrio for the bug
report.
version 2.66
Add the ability to act as an authoritative DNS
server. Dnsmasq can now answer queries from the wider 'net
+13 -1
View File
@@ -2,7 +2,19 @@ dnsmasq (2.67-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 19 Apr 2013 10:23:31 +0000
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 May 2013 14:50:22 +0000
dnsmasq (2.66-3) unstable; urgency=low
* Update resolvconf script for dnscrypt-proxy integration. (closes: #709179)
-- Simon Kelley <simon@thekelleys.org.uk> Tue, 28 May 2013 14:39:51 +0000
dnsmasq (2.66-2) unstable; urgency=low
* Fix error on startup with some configs. (closes: #709010)
-- Simon Kelley <simon@thekelleys.org.uk> Mon, 20 May 2013 11:46:11 +0000
dnsmasq (2.66-1) unstable; urgency=low
+27 -12
View File
@@ -1,16 +1,14 @@
#!/bin/bash
#!/bin/sh
#
# Script to update the resolver list for dnsmasq
#
# N.B. Resolvconf may run us even if dnsmasq is not running.
# If dnsmasq is installed then we go ahead and update
# the resolver list in case dnsmasq is started later.
# N.B. Resolvconf may run us even if dnsmasq is not (yet) running.
# If dnsmasq is installed then we go ahead and update the resolver list
# in case dnsmasq is started later.
#
# Assumption: On entry, PWD contains the resolv.conf-type files
# Assumption: On entry, PWD contains the resolv.conf-type files.
#
# Requires bash because it uses a non-POSIX printf extension.
#
# Licensed under the GNU GPL. See /usr/share/common-licenses/GPL.
# This file is part of the dnsmasq package.
#
set -e
@@ -18,6 +16,8 @@ set -e
RUN_DIR="/var/run/dnsmasq"
RSLVRLIST_FILE="${RUN_DIR}/resolv.conf"
TMP_FILE="${RSLVRLIST_FILE}_new.$$"
MY_RECORD_NAME="lo.dnsmasq"
DNSCRYPT_RECORD_NAME="lo.dnscrypt"
[ -x /usr/sbin/dnsmasq ] || exit 0
[ -x /lib/resolvconf/list-records ] || exit 1
@@ -27,7 +27,7 @@ PATH=/bin:/sbin
report_err() { echo "$0: Error: $*" >&2 ; }
# Stores arguments (minus duplicates) in RSLT, separated by spaces
# Doesn't work properly if an argument itself contain whitespace
# Doesn't work properly if an argument itself contains whitespace
uniquify()
{
RSLT=""
@@ -45,7 +45,22 @@ if [ ! -d "$RUN_DIR" ] && ! mkdir --parents --mode=0755 "$RUN_DIR" ; then
exit 1
fi
RSLVCNFFILES="$(/lib/resolvconf/list-records | sed -e '/^lo.dnsmasq$/d')"
RSLVCNFFILES=""
for F in $(/lib/resolvconf/list-records) ; do
case "$F" in
"$MY_RECORD_NAME")
# Omit
;;
"$DNSCRYPT_RECORD_NAME")
# Dnscrypt, I only have eyes for you
RSLVCNFFILES="$DNSCRYPT_RECORD_NAME"
break
;;
*)
RSLVCNFFILES="${RSLVCNFFILES:+$RSLVCNFFILES }$F"
;;
esac
done
NMSRVRS=""
if [ "$RSLVCNFFILES" ] ; then
@@ -56,8 +71,8 @@ fi
# Dnsmasq uses the mtime of $RSLVRLIST_FILE, with a resolution of one second,
# to detect changes in the file. This means that if a resolvconf update occurs
# within one second of the previous one then dnsmasq may fail to notice the
# more recent change. To work around this problem we sleep here to ensure
# that the new mtime is different.
# more recent change. To work around this problem we sleep one second here
# if necessary in order to ensure that the new mtime is different.
if [ -f "$RSLVRLIST_FILE" ] && [ "$(ls -go --time-style='+%s' "$RSLVRLIST_FILE" | { read p h s t n ; echo "$t" ; })" = "$(date +%s)" ] ; then
sleep 1
fi
+33 -12
View File
@@ -519,17 +519,18 @@ the name. More than one name may be associated with an interface
address by repeating the flag; in that case the first instance is used
for the reverse address-to-name mapping.
.TP
.B --synth-domain=<domain>,<address range>
.B --synth-domain=<domain>,<address range>[,<prefix>]
Create artificial A/AAAA and PTR records for an address range. The
records use the address, with periods (or colons for IPv6) replaced
with dashes.
An example should make this clearer.
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24
will result in a query for 192-168-0-56.thekelleys.org.uk returning
192.168.0.56 and a reverse query vice versa. The same applies to IPv6, but IPv6 addresses may start with '::'
but DNS labels may not start with '-' so in this case a zero is added
in front of the label. ::1 becomes 0--1.
.B --synth-domain=thekelleys.org.uk,192.168.0.0/24,internal-
will result in a query for internal-192-168-0-56.thekelleys.org.uk returning
192.168.0.56 and a reverse query vice versa. The same applies to IPv6,
but IPv6 addresses may start with '::'
but DNS labels may not start with '-' so in this case if no prefix is
configured a zero is added in front of the label. ::1 becomes 0--1.
The address range can be of the form
<ip address>,<ip address> or <ip address>/<netmask>
@@ -571,13 +572,18 @@ If you use the first DNSSEC mode, validating resolvers in clients,
this option is not required. Dnsmasq always returns all the data
needed for a client to do validation itself.
.TP
.B --auth-zone=<domain>[,<subnet>[,<subnet>.....]]
.B --auth-zone=<domain>[,<subnet>[/<prefix length>][,<subnet>[/<prefix length>].....]]
Define a DNS zone for which dnsmasq acts as authoritative server. Locally defined DNS records which are in the domain
will be served, except that A and AAAA records must be in one of the
will be served. A and AAAA records must be in one of the
specified subnets, or in a subnet corresponding to a constructed DHCP
range. The subnet(s) are also used to define in-addr.arpa and
ipv6.arpa domains which are served for reverse-DNS queries. For IPv4
subnets, the prefix length is limited to the values 8, 16 or 24.
range. (This can be overridden with
.B constructor-noauth:
) The subnet(s) are also used to define in-addr.arpa and
ipv6.arpa domains which are served for reverse-DNS queries. If not
specified, the prefix length defaults to 24 for IPv4 and 64 for IPv6.
For IPv4 subnets, the prefix length should be have the value 8, 16 or 24
unless you are familiar with RFC 2317 and have arranged the
in-addr.arpa delegation accordingly.
.TP
.B --auth-soa=<serial>[,<hostmaster>[,<refresh>[,<retry>[,<expiry>]]]]
Specify fields in the SOA record associated with authoritative
@@ -645,7 +651,22 @@ This forms a template which describes how to create ranges, based on the address
.B --dhcp-range=::1,::400,constructor:eth0
will look for addresses of the form <network>::1 on eth0 and then create a range from <network>::1 to <network>::400. If the interface is assigned more than one network, then the corresponding ranges will be automatically created, and then deprecated and finally removed again as the address is deprecated and then deleted. The interface name may have a final "*" wildcard.
will look for addresses of the form <network>::1 or <network>:400 on
eth0 and then create a range from <network>::1 to <network>::400. If
the interface is assigned more than one network, then the
corresponding ranges will be automatically created, and then
deprecated and finally removed again as the address is deprecated and
then deleted. The interface name may have a final "*" wildcard. Note
that just any address on eth0 will not do: the non-prefix part must be
equal either the start or end address given in the dhcp-range. This is
to prevent prefixes becoming perpetual if the interface
gains a SLAAC address for the prefix when it is advertised by dnsmasq.
There is a variant of the constructor: syntax using the keyword
.B constructor-noauth.
See
.B --auth-zone
for an explanation of this.
The optional
.B set:<tag>
+93 -48
View File
@@ -54,6 +54,7 @@ static int filter_constructed_dhcp(struct auth_zone *zone, int flag, struct all_
if (flag & F_IPV6)
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_CONSTRUCTED) &&
!(context->flags & CONTEXT_NOAUTH) &&
is_same_net6(&(addr_u->addr.addr6), &context->start6, context->prefix))
return 1;
#endif
@@ -152,32 +153,55 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
auth = 0;
continue;
}
if (flag == F_IPV4)
{
for (intr = daemon->int_names; intr; intr = intr->next)
{
if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
break;
else
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
intr = intr->next;
}
intr = NULL;
if (intr)
{
if (in_zone(zone, intr->name, NULL))
{
found = 1;
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", intr->name))
anscount++;
}
if (flag == F_IPV4)
for (intr = daemon->int_names; intr; intr = intr->next)
{
struct addrlist *addrlist;
for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
if (addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
break;
if (addrlist)
break;
else
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
intr = intr->next;
}
#ifdef HAVE_IPV6
else if (flag == F_IPV6)
for (intr = daemon->int_names; intr; intr = intr->next)
{
struct addrlist *addrlist;
for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
if (IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
break;
if (addrlist)
break;
else
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
intr = intr->next;
}
#endif
if (intr)
{
if (in_zone(zone, intr->name, NULL))
{
found = 1;
log_query(flag| F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", intr->name))
anscount++;
}
}
if ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
do {
strcpy(name, cache_get_name(crecp));
@@ -321,20 +345,37 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
anscount++;
}
}
if (qtype == T_A)
flag = F_IPV4;
#ifdef HAVE_IPV6
if (qtype == T_AAAA)
flag = F_IPV6;
#endif
for (intr = daemon->int_names; intr; intr = intr->next)
if (hostname_isequal(name, intr->name))
{
struct addrlist *addrlist;
addrlist = intr->addr4;
#ifdef HAVE_IPV6
if (qtype == T_AAAA)
addrlist = intr->addr6;
#endif
nxdomain = 0;
if (qtype == T_A && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
{
found = 1;
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, T_A, C_IN, "4", &addr))
anscount++;
}
for (; addrlist; addrlist = addrlist->next)
if (filter_constructed_dhcp(zone, flag, &addrlist->addr))
{
found = 1;
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &addrlist->addr))
anscount++;
}
}
for (a = daemon->cnames; a; a = a->next)
@@ -356,14 +397,6 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
goto cname_restart;
}
if (qtype == T_A)
flag = F_IPV4;
#ifdef HAVE_IPV6
if (qtype == T_AAAA)
flag = F_IPV6;
#endif
if (!cut)
{
nxdomain = 0;
@@ -488,10 +521,10 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
in_addr_t a = ntohl(subnet->addr4.s_addr) >> 8;
char *p = name;
if (subnet->prefixlen == 24)
if (subnet->prefixlen >= 24)
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
if (subnet->prefixlen != 8)
if (subnet->prefixlen >= 16 )
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
@@ -634,20 +667,32 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
}
for (intr = daemon->int_names; intr; intr = intr->next)
if (in_zone(zone, intr->name, &cut) && (addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr != (in_addr_t) -1)
if (in_zone(zone, intr->name, &cut))
{
struct addrlist *addrlist;
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addr))
anscount++;
for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
if (filter_constructed_dhcp(zone, F_IPV4, &addrlist->addr) &&
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, T_A, C_IN, "4", cut ? intr->name : NULL, &addrlist->addr))
anscount++;
#ifdef HAVE_IPV6
for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
if (filter_constructed_dhcp(zone, F_IPV6, &addrlist->addr) &&
add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, T_AAAA, C_IN, "6", cut ? intr->name : NULL, &addrlist->addr))
anscount++;
#endif
/* restore config data */
if (cut)
*cut = '.';
}
for (a = daemon->cnames; a; a = a->next)
if (in_zone(zone, a->alias, &cut))
{
+1 -1
View File
@@ -123,7 +123,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
broadcast = ((struct sockaddr_in *) addrs->ifa_broadaddr)->sin_addr;
else
broadcast.s_addr = 0;
if (!((*callback)(addr, iface_index, netmask, broadcast, parm)))
if (!((*callback)(addr, iface_index, NULL, netmask, broadcast, parm)))
goto err;
}
#ifdef HAVE_IPV6
+4 -4
View File
@@ -279,12 +279,12 @@ HAVE_SOCKADDR_SA_LEN
#if defined(INET6_ADDRSTRLEN) && defined(IPV6_V6ONLY)
# define HAVE_IPV6
# define ADDRSTRLEN INET6_ADDRSTRLEN
#elif defined(INET_ADDRSTRLEN)
#else
# if !defined(INET_ADDRSTRLEN)
# define INET_ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
# endif
# undef HAVE_IPV6
# define ADDRSTRLEN INET_ADDRSTRLEN
#else
# undef HAVE_IPV6
# define ADDRSTRLEN 16 /* 4*3 + 3 dots + NULL */
#endif
+13 -7
View File
@@ -347,21 +347,27 @@ void bindtodevice(int fd)
to that device. This is for the use case of (eg) OpenStack, which runs a new
dnsmasq instance for each VLAN interface it creates. Without the BINDTODEVICE,
individual processes don't always see the packets they should.
SO_BINDTODEVICE is only available Linux. */
SO_BINDTODEVICE is only available Linux.
Note that if wildcards are used in --interface, or a configured interface doesn't
yet exist, then more interfaces may arrive later, so we can't safely assert there
is only one interface and proceed.
*/
struct irec *iface, *found;
struct iname *if_tmp;
for (if_tmp = daemon->if_names; if_tmp; if_tmp = if_tmp->next)
if (if_tmp->name && (!if_tmp->used || strchr(if_tmp->name, '*')))
return;
for (found = NULL, iface = daemon->interfaces; iface; iface = iface->next)
if (iface->dhcp_ok)
{
if (!found)
found = iface;
else if (strcmp(found->name, iface->name) != 0)
{
/* more than one. */
found = NULL;
break;
}
return; /* more than one. */
}
if (found)
+9 -5
View File
@@ -28,9 +28,9 @@ struct match_param {
struct in_addr netmask, broadcast, addr;
};
static int complete_context(struct in_addr local, int if_index,
static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int check_listen_addrs(struct in_addr local, int if_index,
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam);
static int make_fd(int port)
@@ -287,7 +287,7 @@ void dhcp_packet(time_t now, int pxe_fd)
iface_addr = match.addr;
/* make sure secondary address gets priority in case
there is more than one address on the interface in the same subnet */
complete_context(match.addr, iface_index, match.netmask, match.broadcast, &parm);
complete_context(match.addr, iface_index, NULL, match.netmask, match.broadcast, &parm);
}
if (!iface_enumerate(AF_INET, &parm, complete_context))
@@ -411,12 +411,14 @@ void dhcp_packet(time_t now, int pxe_fd)
}
/* check against secondary interface addresses */
static int check_listen_addrs(struct in_addr local, int if_index,
static int check_listen_addrs(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct match_param *param = vparam;
struct iname *tmp;
(void) label;
if (if_index == param->ind)
{
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
@@ -444,11 +446,13 @@ static int check_listen_addrs(struct in_addr local, int if_index,
Note that the current chain may be superceded later for configured hosts or those coming via gateways. */
static int complete_context(struct in_addr local, int if_index,
static int complete_context(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct dhcp_context *context;
struct iface_param *param = vparam;
(void)label;
for (context = daemon->dhcp; context; context = context->next)
{
+3 -1
View File
@@ -538,7 +538,9 @@ static int construct_worker(struct in6_addr *local, int prefix,
}
}
else if (addr6part(local) == addr6part(&template->start6) && wildcard_match(template->template_interface, ifrn_name))
else if ((addr6part(local) == addr6part(&template->start6) ||
addr6part(local) == addr6part(&template->end6)) &&
wildcard_match(template->template_interface, ifrn_name))
{
start6 = *local;
setaddr6part(&start6, addr6part(&template->start6));
+63 -52
View File
@@ -225,7 +225,7 @@ int main (int argc, char **argv)
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
#endif
if (!enumerate_interfaces())
if (!enumerate_interfaces(1) || !enumerate_interfaces(0))
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
if (option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND))
@@ -248,7 +248,7 @@ int main (int argc, char **argv)
#endif
#if defined(HAVE_LINUX_NETWORK) && defined(HAVE_DHCP6)
if (daemon->dhcp6)
if (daemon->doing_dhcp6)
bindtodevice(daemon->dhcp6fd);
#endif
}
@@ -820,12 +820,15 @@ int main (int argc, char **argv)
now = dnsmasq_time();
check_log_writer(&wset);
/* prime. */
enumerate_interfaces(1);
/* Check the interfaces to see if any have exited DAD state
and if so, bind the address. */
if (is_dad_listeners())
{
enumerate_interfaces();
enumerate_interfaces(0);
/* NB, is_dad_listeners() == 1 --> we're binding interfaces */
create_bound_listeners(0);
}
@@ -1352,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;
}
/* 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.
if (option_bool(OPT_NOWILD))
iface = listener->iface; /* May be NULL */
else
{
int if_index;
char intr_name[IF_NAMESIZE];
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();
/* 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);
+11 -3
View File
@@ -307,6 +307,13 @@ struct host_record {
struct interface_name {
char *name; /* domain name */
char *intr; /* interface name */
struct addrlist {
struct all_addr addr;
struct addrlist *next;
} *addr4;
#ifdef HAVE_IPV6
struct addrlist *addr6;
#endif
struct interface_name *next;
};
@@ -673,7 +680,7 @@ struct dhcp_bridge {
};
struct cond_domain {
char *domain;
char *domain, *prefix;
struct in_addr start, end;
#ifdef HAVE_IPV6
struct in6_addr start6, end6;
@@ -724,6 +731,7 @@ struct dhcp_context {
#define CONTEXT_RA 8192
#define CONTEXT_CONF_USED 16384
#define CONTEXT_USED 32768
#define CONTEXT_NOAUTH 65536
struct ping_result {
struct in_addr addr;
@@ -1024,15 +1032,15 @@ int random_sock(int family);
void pre_allocate_sfds(void);
int reload_servers(char *fname);
void check_servers(void);
int enumerate_interfaces();
int enumerate_interfaces(int reset);
void create_wildcard_listeners(void);
void create_bound_listeners(int die);
int is_dad_listeners(void);
int iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
int loopback_exception(int fd, int family, struct all_addr *addr, char *name);
int label_exception(int index, int family, struct all_addr *addr);
int fix_fd(int fd);
int tcp_interface(int fd, int af);
struct in_addr get_ifaddr(char *intr);
#ifdef HAVE_IPV6
int set_ipv6pktinfo(int fd);
#endif
+74 -42
View File
@@ -34,48 +34,69 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr)
prot = AF_INET6;
#endif
/* NB, must not alter name if we return zero */
for (p = name; *p; p++)
for (c = daemon->synth_domains; c; c = c->next)
{
char c = *p;
int found = 0;
char *tail, *pref;
if ((c >='0' && c <= '9') || c == '-')
for (tail = name, pref = c->prefix; *tail != 0 && pref && *pref != 0; tail++, pref++)
{
unsigned int c1 = (unsigned char) *pref;
unsigned int c2 = (unsigned char) *tail;
if (c1 >= 'A' && c1 <= 'Z')
c1 += 'a' - 'A';
if (c2 >= 'A' && c2 <= 'Z')
c2 += 'a' - 'A';
if (c1 != c2)
break;
}
if (pref && *pref != 0)
continue; /* prefix match fail */
/* NB, must not alter name if we return zero */
for (p = tail; *p; p++)
{
char c = *p;
if ((c >='0' && c <= '9') || c == '-')
continue;
#ifdef HAVE_IPV6
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
continue;
#endif
break;
}
if (*p != '.')
continue;
#ifdef HAVE_IPV6
if (prot == AF_INET6 && ((c >='A' && c <= 'F') || (c >='a' && c <= 'f')))
continue;
#endif
*p = 0;
break;
}
if (*p != '.')
return 0;
*p = 0;
for (p = name; *p; p++)
if (*p == '-')
{
if (prot == AF_INET)
*p = '.';
/* swap . or : for - */
for (p = tail; *p; p++)
if (*p == '-')
{
if (prot == AF_INET)
*p = '.';
#ifdef HAVE_IPV6
else
*p = ':';
else
*p = ':';
#endif
}
if (inet_pton(prot, name, addr))
for (c = daemon->synth_domains; c; c = c->next)
if (hostname_isequal(c->domain, p+1))
}
if (hostname_isequal(c->domain, p+1) && inet_pton(prot, tail, addr))
{
if (prot == AF_INET)
{
if (!c->is6 &&
ntohl(addr->addr.addr4.s_addr) >= ntohl(c->start.s_addr) &&
ntohl(addr->addr.addr4.s_addr) <= ntohl(c->end.s_addr))
break;
found = 1;
}
#ifdef HAVE_IPV6
else
@@ -86,20 +107,23 @@ int is_name_synthetic(int flags, char *name, struct all_addr *addr)
is_same_net6(&addr->addr.addr6, &c->start6, 64) &&
addrpart >= addr6part(&c->start6) &&
addrpart <= addr6part(&c->end6))
break;
found = 1;
}
#endif
}
/* restore name */
for (p = tail; *p; p++)
if (*p == '.' || *p == ':')
*p = '-';
*p = '.';
if (found)
return 1;
}
/* restore name */
for (p = name; *p; p++)
if (*p == '.' || *p == ':')
*p = '-';
*p = '.';
return (c != NULL);
return 0;
}
@@ -111,7 +135,11 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
{
char *p;
inet_ntop(AF_INET, &addr->addr.addr4, name, ADDRSTRLEN);
*name = 0;
if (c->prefix)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
inet_ntop(AF_INET, &addr->addr.addr4, name + strlen(name), ADDRSTRLEN);
for (p = name; *p; p++)
if (*p == '.')
*p = '-';
@@ -127,11 +155,15 @@ int is_rev_synth(int flag, struct all_addr *addr, char *name)
{
char *p;
inet_ntop(AF_INET6, &addr->addr.addr6, name, ADDRSTRLEN);
*name = 0;
if (c->prefix)
strncpy(name, c->prefix, MAXDNAME - ADDRSTRLEN);
inet_ntop(AF_INET6, &addr->addr.addr6, name + strlen(name), ADDRSTRLEN);
/* IPv6 presentation address can start with ":", but valid domain names
cannot start with "-" so prepend a zero in that case. */
if (*name == ':')
if (!c->prefix && *name == ':')
{
*name = '0';
inet_ntop(AF_INET6, &addr->addr.addr6, name+1, ADDRSTRLEN);
+13 -3
View File
@@ -788,8 +788,9 @@ void receive_query(struct listener *listen, time_t now)
if (!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
{
if (!option_bool(OPT_CLEVERBIND))
enumerate_interfaces();
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name))
enumerate_interfaces(0);
if (!loopback_exception(listen->fd, listen->family, &dst_addr, ifr.ifr_name) &&
!label_exception(if_index, listen->family, &dst_addr))
return;
}
@@ -807,7 +808,7 @@ void receive_query(struct listener *listen, time_t now)
/* interface may be new */
if (!iface && !option_bool(OPT_CLEVERBIND))
enumerate_interfaces();
enumerate_interfaces(0);
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->addr.sa.sa_family == AF_INET &&
@@ -1204,8 +1205,17 @@ struct frec *get_new_frec(time_t now, int *wait)
/* none available, calculate time 'till oldest record expires */
if (count > daemon->ftabsize)
{
static time_t last_log = 0;
if (oldest && wait)
*wait = oldest->time + (time_t)TIMEOUT - now;
if ((int)difftime(now, last_log) > 5)
{
last_log = now;
my_syslog(LOG_WARNING, _("Maximum number of concurrent DNS queries reached (max: %d)"), daemon->ftabsize);
}
return NULL;
}
+39 -15
View File
@@ -26,9 +26,12 @@
#include <arpa/inet.h>
#include <linux/version.h>
#include <linux/netlink.h>
#include <linux/netfilter/nfnetlink.h>
#ifndef NFNL_SUBSYS_IPSET
/* We want to be able to compile against old header files
Kernel version is handled at run-time. */
#define NFNL_SUBSYS_IPSET 6
#define IPSET_ATTR_DATA 7
#define IPSET_ATTR_IP 1
#define IPSET_ATTR_IPADDR_IPV4 1
@@ -39,10 +42,31 @@
#define IPSET_CMD_DEL 10
#define IPSET_MAXNAMELEN 32
#define IPSET_PROTOCOL 6
#else
#include <linux/netfilter/ipset/ip_set.h>
#ifndef NFNETLINK_V0
#define NFNETLINK_V0 0
#endif
#ifndef NLA_F_NESTED
#define NLA_F_NESTED (1 << 15)
#endif
#ifndef NLA_F_NET_BYTEORDER
#define NLA_F_NET_BYTEORDER (1 << 14)
#endif
struct my_nlattr {
__u16 nla_len;
__u16 nla_type;
};
struct my_nfgenmsg {
__u8 nfgen_family; /* AF_xxx */
__u8 version; /* nfnetlink version */
__be16 res_id; /* resource id */
};
/* data structure size in here is fixed */
#define BUFF_SZ 256
@@ -53,11 +77,11 @@ static char *buffer;
static inline void add_attr(struct nlmsghdr *nlh, uint16_t type, size_t len, const void *data)
{
struct nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
uint16_t payload_len = NL_ALIGN(sizeof(struct nlattr)) + len;
struct my_nlattr *attr = (void *)nlh + NL_ALIGN(nlh->nlmsg_len);
uint16_t payload_len = NL_ALIGN(sizeof(struct my_nlattr)) + len;
attr->nla_type = type;
attr->nla_len = payload_len;
memcpy((void *)attr + NL_ALIGN(sizeof(struct nlattr)), data, len);
memcpy((void *)attr + NL_ALIGN(sizeof(struct my_nlattr)), data, len);
nlh->nlmsg_len += NL_ALIGN(payload_len);
}
@@ -93,8 +117,8 @@ void ipset_init(void)
static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr, int af, int remove)
{
struct nlmsghdr *nlh;
struct nfgenmsg *nfg;
struct nlattr *nested[2];
struct my_nfgenmsg *nfg;
struct my_nlattr *nested[2];
uint8_t proto;
int addrsz = INADDRSZ;
ssize_t rc;
@@ -117,8 +141,8 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
nlh->nlmsg_type = (remove ? IPSET_CMD_DEL : IPSET_CMD_ADD) | (NFNL_SUBSYS_IPSET << 8);
nlh->nlmsg_flags = NLM_F_REQUEST;
nfg = (struct nfgenmsg *)(buffer + nlh->nlmsg_len);
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nfgenmsg));
nfg = (struct my_nfgenmsg *)(buffer + nlh->nlmsg_len);
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nfgenmsg));
nfg->nfgen_family = af;
nfg->version = NFNETLINK_V0;
nfg->res_id = htons(0);
@@ -126,11 +150,11 @@ static int new_add_to_ipset(const char *setname, const struct all_addr *ipaddr,
proto = IPSET_PROTOCOL;
add_attr(nlh, IPSET_ATTR_PROTOCOL, sizeof(proto), &proto);
add_attr(nlh, IPSET_ATTR_SETNAME, strlen(setname) + 1, setname);
nested[0] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr));
nested[0] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
nested[0]->nla_type = NLA_F_NESTED | IPSET_ATTR_DATA;
nested[1] = (struct nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
nlh->nlmsg_len += NL_ALIGN(sizeof(struct nlattr));
nested[1] = (struct my_nlattr *)(buffer + NL_ALIGN(nlh->nlmsg_len));
nlh->nlmsg_len += NL_ALIGN(sizeof(struct my_nlattr));
nested[1]->nla_type = NLA_F_NESTED | IPSET_ATTR_IP;
add_attr(nlh,
(af == AF_INET ? IPSET_ATTR_IPADDR_IPV4 : IPSET_ATTR_IPADDR_IPV6) | NLA_F_NET_BYTEORDER,
+2 -1
View File
@@ -345,11 +345,12 @@ void lease_update_file(time_t now)
}
static int find_interface_v4(struct in_addr local, int if_index,
static int find_interface_v4(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
struct dhcp_lease *lease;
(void) label;
(void) broadcast;
(void) vparam;
+10 -4
View File
@@ -193,7 +193,10 @@ int iface_enumerate(int family, void *parm, int (*callback)())
{
/* May be multicast arriving async */
if (nl_async(h))
newaddr = 1;
{
newaddr = 1;
enumerate_interfaces(1); /* reset */
}
}
else if (h->nlmsg_type == NLMSG_DONE)
{
@@ -215,7 +218,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (ifa->ifa_family == AF_INET)
{
struct in_addr netmask, addr, broadcast;
char *label = NULL;
netmask.s_addr = htonl(0xffffffff << (32 - ifa->ifa_prefixlen));
addr.s_addr = 0;
broadcast.s_addr = 0;
@@ -226,12 +230,14 @@ int iface_enumerate(int family, void *parm, int (*callback)())
addr = *((struct in_addr *)(rta+1));
else if (rta->rta_type == IFA_BROADCAST)
broadcast = *((struct in_addr *)(rta+1));
else if (rta->rta_type == IFA_LABEL)
label = RTA_DATA(rta);
rta = RTA_NEXT(rta, len1);
}
if (addr.s_addr && callback_ok)
if (!((*callback)(addr, ifa->ifa_index, netmask, broadcast, parm)))
if (!((*callback)(addr, ifa->ifa_index, label, netmask, broadcast, parm)))
callback_ok = 0;
}
#ifdef HAVE_IPV6
@@ -394,7 +400,7 @@ static int nl_async(struct nlmsghdr *h)
static void nl_newaddress(time_t now)
{
if (option_bool(OPT_CLEVERBIND) || daemon->doing_dhcp6 || daemon->doing_ra)
enumerate_interfaces();
enumerate_interfaces(0);
if (option_bool(OPT_CLEVERBIND))
create_bound_listeners(0);
+157 -59
View File
@@ -99,6 +99,8 @@ int indextoname(int fd, int index, char *name)
int indextoname(int fd, int index, char *name)
{
(void)fd;
if (index == 0 || !if_indextoname(index, name))
return 0;
@@ -204,11 +206,36 @@ int loopback_exception(int fd, int family, struct all_addr *addr, char *name)
return 0;
}
static int iface_allowed(struct irec **irecp, int if_index,
/* If we're configured with something like --interface=eth0:0 then we'll listen correctly
on the relevant address, but the name of the arrival interface, derived from the
index won't match the config. Check that we found an interface address for the arrival
interface: daemon->interfaces must be up-to-date. */
int label_exception(int index, int family, struct all_addr *addr)
{
struct irec *iface;
/* labels only supported on IPv4 addresses. */
if (family != AF_INET)
return 0;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->index == index && iface->addr.sa.sa_family == AF_INET &&
iface->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
return 1;
return 0;
}
struct iface_param {
struct addrlist *spare;
int fd;
};
static int iface_allowed(struct iface_param *param, int if_index, char *label,
union mysockaddr *addr, struct in_addr netmask, int dad)
{
struct irec *iface;
int fd, mtu = 0, loopback;
int mtu = 0, loopback;
struct ifreq ifr;
int tftp_ok = !!option_bool(OPT_TFTP);
int dhcp_ok = 1;
@@ -217,39 +244,72 @@ static int iface_allowed(struct irec **irecp, int if_index,
struct iname *tmp;
#endif
if (!indextoname(param->fd, if_index, ifr.ifr_name) ||
ioctl(param->fd, SIOCGIFFLAGS, &ifr) == -1)
return 0;
loopback = ifr.ifr_flags & IFF_LOOPBACK;
if (loopback)
dhcp_ok = 0;
if (ioctl(param->fd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
if (!label)
label = ifr.ifr_name;
/* Update addresses from interface_names. These are a set independent
of the set we're listening on. */
#ifdef HAVE_IPV6
if (addr->sa.sa_family != AF_INET6 || !IN6_IS_ADDR_LINKLOCAL(&addr->in6.sin6_addr))
#endif
{
struct interface_name *int_name;
struct addrlist *al;
for (int_name = daemon->int_names; int_name; int_name = int_name->next)
if (strncmp(label, int_name->intr, IF_NAMESIZE) == 0)
{
if (param->spare)
{
al = param->spare;
param->spare = al->next;
}
else
al = whine_malloc(sizeof(struct addrlist));
if (al)
{
if (addr->sa.sa_family == AF_INET)
{
al->addr.addr.addr4 = addr->in.sin_addr;
al->next = int_name->addr4;
int_name->addr4 = al;
}
#ifdef HAVE_IPV6
else
{
al->addr.addr.addr6 = addr->in6.sin6_addr;
al->next = int_name->addr6;
int_name->addr6 = al;
}
#endif
}
}
}
/* check whether the interface IP has been added already
we call this routine multiple times. */
for (iface = *irecp; iface; iface = iface->next)
for (iface = daemon->interfaces; iface; iface = iface->next)
if (sockaddr_isequal(&iface->addr, addr))
{
iface->dad = dad;
return 1;
}
if ((fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1 ||
!indextoname(fd, if_index, ifr.ifr_name) ||
ioctl(fd, SIOCGIFFLAGS, &ifr) == -1)
{
if (fd != -1)
{
int errsave = errno;
close(fd);
errno = errsave;
}
return 0;
}
loopback = ifr.ifr_flags & IFF_LOOPBACK;
if (loopback)
dhcp_ok = 0;
if (ioctl(fd, SIOCGIFMTU, &ifr) != -1)
mtu = ifr.ifr_mtu;
close(fd);
/* If we are restricting the set of interfaces to use, make
/* If we are restricting the set of interfaces to use, make
sure that loopback interfaces are in that set. */
if (daemon->if_names && loopback)
{
@@ -273,12 +333,12 @@ static int iface_allowed(struct irec **irecp, int if_index,
}
if (addr->sa.sa_family == AF_INET &&
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns))
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, label, &auth_dns))
return 1;
#ifdef HAVE_IPV6
if (addr->sa.sa_family == AF_INET6 &&
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns))
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, label, &auth_dns))
return 1;
#endif
@@ -313,8 +373,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
{
strcpy(iface->name, ifr.ifr_name);
iface->next = *irecp;
*irecp = iface;
iface->next = daemon->interfaces;
daemon->interfaces = iface;
return 1;
}
free(iface);
@@ -348,11 +408,11 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
addr.in6.sin6_port = htons(daemon->port);
addr.in6.sin6_scope_id = if_index;
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE));
return iface_allowed((struct iface_param *)vparam, if_index, NULL, &addr, netmask, !!(flags & IFACE_TENTATIVE));
}
#endif
static int iface_allowed_v4(struct in_addr local, int if_index,
static int iface_allowed_v4(struct in_addr local, int if_index, char *label,
struct in_addr netmask, struct in_addr broadcast, void *vparam)
{
union mysockaddr addr;
@@ -366,17 +426,75 @@ static int iface_allowed_v4(struct in_addr local, int if_index,
addr.in.sin_addr = local;
addr.in.sin_port = htons(daemon->port);
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, 0);
return iface_allowed((struct iface_param *)vparam, if_index, label, &addr, netmask, 0);
}
int enumerate_interfaces(void)
int enumerate_interfaces(int reset)
{
static struct addrlist *spare = NULL;
static int done = 0;
struct iface_param param;
int errsave, ret = 1;
struct addrlist *addr, *tmp;
struct interface_name *intname;
/* Do this max once per select cycle - also inhibits netlink socket use
in TCP child processes. */
if (reset)
{
done = 0;
return 1;
}
if (done)
return 1;
done = 1;
if ((param.fd = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
return 0;
/* remove addresses stored against interface_names */
for (intname = daemon->int_names; intname; intname = intname->next)
{
for (addr = intname->addr4; addr; addr = tmp)
{
tmp = addr->next;
addr->next = spare;
spare = addr;
}
intname->addr4 = NULL;
#ifdef HAVE_IPV6
if (!iface_enumerate(AF_INET6, &daemon->interfaces, iface_allowed_v6))
return 0;
for (addr = intname->addr6; addr; addr = tmp)
{
tmp = addr->next;
addr->next = spare;
spare = addr;
}
intname->addr6 = NULL;
#endif
}
param.spare = spare;
#ifdef HAVE_IPV6
ret = iface_enumerate(AF_INET6, &param, iface_allowed_v6);
#endif
return iface_enumerate(AF_INET, &daemon->interfaces, iface_allowed_v4);
if (ret)
ret = iface_enumerate(AF_INET, &param, iface_allowed_v4);
errsave = errno;
close(param.fd);
errno = errsave;
spare = param.spare;
return ret;
}
/* set NONBLOCK bit on fd: See Stevens 16.6 */
@@ -948,7 +1066,7 @@ void check_servers(void)
/* interface may be new since startup */
if (!option_bool(OPT_NOWILD))
enumerate_interfaces();
enumerate_interfaces(0);
for (new = daemon->servers; new; new = tmp)
{
@@ -1156,27 +1274,7 @@ int reload_servers(char *fname)
}
/* Use an IPv4 listener socket for ioctling */
struct in_addr get_ifaddr(char *intr)
{
struct listener *l;
struct ifreq ifr;
struct sockaddr_in ret;
ret.sin_addr.s_addr = -1;
for (l = daemon->listeners;
l && (l->family != AF_INET || l->fd == -1);
l = l->next);
strncpy(ifr.ifr_name, intr, IF_NAMESIZE);
ifr.ifr_addr.sa_family = AF_INET;
if (l && ioctl(l->fd, SIOCGIFADDR, &ifr) != -1)
memcpy(&ret, &ifr.ifr_addr, sizeof(ret));
return ret.sin_addr;
}
+66 -50
View File
@@ -408,7 +408,7 @@ static struct {
{ LOPT_AUTHSFS, ARG_DUP, "<NS>[,<NS>...]", gettext_noop("Secondary authoritative nameservers for forward domains"), NULL },
{ LOPT_AUTHPEER, ARG_DUP, "<ipaddr>[,<ipaddr>...]", gettext_noop("Peers which are allowed to do zone transfer"), NULL },
{ LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>", gettext_noop("Specify a domain and address range for sythesised names"), NULL },
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for sythesised names"), NULL },
#ifdef OPTION6_PREFIX_CLASS
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
#endif
@@ -660,7 +660,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
scope_id = split_chr(arg, '%');
#endif
if ((addr->in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t) -1)
if (inet_pton(AF_INET, arg, &addr->in.sin_addr) > 0)
{
addr->in.sin_port = htons(serv_port);
addr->sa.sa_family = source_addr->sa.sa_family = AF_INET;
@@ -675,7 +675,7 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
if (flags)
*flags |= SERV_HAS_SOURCE;
source_addr->in.sin_port = htons(source_port);
if ((source_addr->in.sin_addr.s_addr = inet_addr(source)) == (in_addr_t) -1)
if (!(inet_pton(AF_INET, source, &source_addr->in.sin_addr) > 0))
{
#if defined(SO_BINDTODEVICE)
source_addr->in.sin_addr.s_addr = INADDR_ANY;
@@ -1031,7 +1031,7 @@ static int parse_dhcp_opt(char *errstr, char *arg, int flags)
cp = comma;
comma = split(cp);
slash = split_chr(cp, '/');
in.s_addr = inet_addr(cp);
inet_pton(AF_INET, cp, &in);
if (!slash)
{
memcpy(op, &in, INADDRSZ);
@@ -1576,7 +1576,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
comma = split(arg);
new->name = NULL;
unhide_metas(arg);
if ((new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
if (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0)
new->addr.sa.sa_family = AF_INET;
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
@@ -1637,8 +1637,6 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (inet_pton(AF_INET, arg, &subnet->addr4))
{
if ((prefixlen & 0x07) != 0 || prefixlen > 24)
ret_err(_("bad prefix"));
subnet->prefixlen = (prefixlen == 0) ? 24 : prefixlen;
subnet->is6 = 0;
}
@@ -1707,6 +1705,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
char *netpart;
new->prefix = NULL;
unhide_metas(comma);
if ((netpart = split_chr(comma, '/')))
{
@@ -1723,26 +1723,30 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->end.s_addr = new->start.s_addr | htonl(mask);
if (arg)
{
/* generate the equivalent of
local=/<domain>/
local=/xxx.yyy.zzz.in-addr.arpa/ */
if (strcmp(arg, "local") != 0 ||
option != 's' ||
(msize != 8 && msize != 16 && msize != 24))
if (option != 's')
{
if (!(new->prefix = canonicalise_opt(arg)) ||
strlen(new->prefix) > MAXLABEL - INET_ADDRSTRLEN)
ret_err(_("bad prefix"));
}
else if (strcmp(arg, "local") != 0 ||
(msize != 8 && msize != 16 && msize != 24))
ret_err(gen_err);
else
{
/* generate the equivalent of
local=/<domain>/
local=/xxx.yyy.zzz.in-addr.arpa/ */
struct server *serv = opt_malloc(sizeof(struct server));
in_addr_t a = ntohl(new->start.s_addr) >> 8;
char *p;
memset(serv, 0, sizeof(struct server));
serv->domain = d;
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
serv->next = daemon->servers;
daemon->servers = serv;
serv = opt_malloc(sizeof(struct server));
memset(serv, 0, sizeof(struct server));
p = serv->domain = opt_malloc(25); /* strlen("xxx.yyy.zzz.in-addr.arpa")+1 */
@@ -1754,7 +1758,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
serv->flags = SERV_HAS_DOMAIN | SERV_NO_ADDR;
serv->next = daemon->servers;
daemon->servers = serv;
@@ -1767,11 +1771,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
u64 mask = (1LLU << (128 - msize)) - 1LLU;
u64 addrpart = addr6part(&new->start6);
new->is6 = 1;
/* prefix==64 overflows the mask calculation above */
if (msize == 64)
mask = (u64)-1LL;
new->end6 = new->start6;
setaddr6part(&new->start6, addrpart & ~mask);
setaddr6part(&new->end6, addrpart | mask);
@@ -1780,16 +1784,19 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(gen_err);
else if (arg)
{
/* generate the equivalent of
local=/<domain>/
local=/xxx.yyy.zzz.ip6.arpa/ */
if (strcmp(arg, "local") != 0 ||
option != 's' ||
((msize & 4) != 0))
if (option != 's')
{
if (!(new->prefix = canonicalise_opt(arg)) ||
strlen(new->prefix) > MAXLABEL - INET6_ADDRSTRLEN)
ret_err(_("bad prefix"));
}
else if (strcmp(arg, "local") != 0 || ((msize & 4) != 0))
ret_err(gen_err);
else
{
/* generate the equivalent of
local=/<domain>/
local=/xxx.yyy.zzz.ip6.arpa/ */
struct server *serv = opt_malloc(sizeof(struct server));
char *p;
@@ -1918,7 +1925,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
struct in_addr addr;
unhide_metas(arg);
if (arg && (addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
if (arg && (inet_pton(AF_INET, arg, &addr) > 0))
{
struct bogus_addr *baddr = opt_malloc(sizeof(struct bogus_addr));
baddr->next = daemon->bogus_addr;
@@ -1936,7 +1943,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
struct iname *new = opt_malloc(sizeof(struct iname));
comma = split(arg);
unhide_metas(arg);
if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
if (arg && (inet_pton(AF_INET, arg, &new->addr.in.sin_addr) > 0))
{
new->addr.sa.sa_family = AF_INET;
new->addr.in.sin_port = 0;
@@ -2360,7 +2367,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
if (k >= 3 && strchr(a[2], '.') &&
((new->netmask.s_addr = inet_addr(a[2])) != (in_addr_t)-1))
(inet_pton(AF_INET, a[2], &new->netmask) > 0))
{
new->flags |= CONTEXT_NETMASK;
leasepos = 3;
@@ -2369,7 +2376,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
if (k >= 4 && strchr(a[3], '.') &&
((new->broadcast.s_addr = inet_addr(a[3])) != (in_addr_t)-1))
(inet_pton(AF_INET, a[3], &new->broadcast) > 0))
{
new->flags |= CONTEXT_BRDCAST;
leasepos = 4;
@@ -2402,6 +2409,11 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->template_interface = opt_string_alloc(a[leasepos] + 12);
new->flags |= CONTEXT_TEMPLATE;
}
else if (strstr(a[leasepos], "constructor-noauth:") == a[leasepos])
{
new->template_interface = opt_string_alloc(a[leasepos] + 19);
new->flags |= CONTEXT_TEMPLATE | CONTEXT_NOAUTH;
}
else
break;
}
@@ -2501,7 +2513,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'G': /* --dhcp-host */
{
int j, k = 0;
char *a[6] = { NULL, NULL, NULL, NULL, NULL, NULL };
char *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
struct dhcp_config *new;
struct in_addr in;
@@ -2513,7 +2525,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->netid = NULL;
if ((a[0] = arg))
for (k = 1; k < 6; k++)
for (k = 1; k < 7; k++)
if (!(a[k] = split(a[k-1])))
break;
@@ -2599,7 +2611,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
}
}
else if (strchr(a[j], '.') && (in.s_addr = inet_addr(a[j])) != (in_addr_t)-1)
else if (strchr(a[j], '.') && (inet_pton(AF_INET, a[j], &in) > 0))
{
struct dhcp_config *configs;
@@ -2796,17 +2808,17 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (comma)
{
unhide_metas(comma);
if ((dhcp_next_server.s_addr = inet_addr(comma)) == (in_addr_t)-1) {
/*
* The user may have specified the tftp hostname here.
* save it so that it can be resolved/looked up during
* actual dhcp_reply().
*/
tftp_sname = opt_string_alloc(comma);
dhcp_next_server.s_addr = 0;
}
if (!(inet_pton(AF_INET, comma, &dhcp_next_server) > 0))
{
/*
* The user may have specified the tftp hostname here.
* save it so that it can be resolved/looked up during
* actual dhcp_reply().
*/
tftp_sname = opt_string_alloc(comma);
dhcp_next_server.s_addr = 0;
}
}
}
@@ -2819,7 +2831,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->next = daemon->boot_config;
daemon->boot_config = new;
}
break;
}
@@ -3135,7 +3147,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
while (arg) {
struct addr_list *new = opt_malloc(sizeof(struct addr_list));
comma = split(arg);
if ((new->addr.s_addr = inet_addr(arg)) == (in_addr_t)-1)
if (!(inet_pton(AF_INET, arg, &new->addr) > 0))
ret_err(_("bad dhcp-proxy address"));
new->next = daemon->override_relays;
daemon->override_relays = new;
@@ -3178,15 +3190,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
dash = split_chr(a[0], '-');
if ((k < 2) ||
((new->in.s_addr = inet_addr(a[0])) == (in_addr_t)-1) ||
((new->out.s_addr = inet_addr(a[1])) == (in_addr_t)-1))
(!(inet_pton(AF_INET, a[0], &new->in) > 0)) ||
(!(inet_pton(AF_INET, a[1], &new->out) > 0)))
option = '?';
if (k == 3)
new->mask.s_addr = inet_addr(a[2]);
inet_pton(AF_INET, a[2], &new->mask);
if (dash &&
((new->end.s_addr = inet_addr(dash)) == (in_addr_t)-1 ||
(!(inet_pton(AF_INET, dash, &new->end) > 0) ||
!is_same_net(new->in, new->end, new->mask) ||
ntohl(new->in.s_addr) > ntohl(new->end.s_addr)))
ret_err(_("invalid alias range"));
@@ -3206,6 +3218,10 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new = opt_malloc(sizeof(struct interface_name));
new->next = NULL;
new->addr4 = NULL;
#ifdef HAVE_IPV6
new->addr6 = NULL;
#endif
/* Add to the end of the list, so that first name
of an interface is used for PTR lookups. */
for (up = &daemon->int_names; *up; up = &((*up)->next));
+2 -2
View File
@@ -300,9 +300,9 @@ static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *de
}
}
if (!done_dns)
if (daemon->port == NAMESERVER_PORT && !done_dns)
{
/* default == us. */
/* default == us, as long as we are supplying DNS service. */
put_opt6_char(ICMP6_OPT_RDNSS);
put_opt6_char(3);
put_opt6_short(0);
+54 -23
View File
@@ -1450,19 +1450,42 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (is_arpa == F_IPV4)
for (intr = daemon->int_names; intr; intr = intr->next)
{
if (addr.addr.addr4.s_addr == get_ifaddr(intr->intr).s_addr)
struct addrlist *addrlist;
for (addrlist = intr->addr4; addrlist; addrlist = addrlist->next)
if (addr.addr.addr4.s_addr == addrlist->addr.addr.addr4.s_addr)
break;
if (addrlist)
break;
else
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
intr = intr->next;
}
#ifdef HAVE_IPV6
else if (is_arpa == F_IPV6)
for (intr = daemon->int_names; intr; intr = intr->next)
{
struct addrlist *addrlist;
for (addrlist = intr->addr6; addrlist; addrlist = addrlist->next)
if (IN6_ARE_ADDR_EQUAL(&addr.addr.addr6, &addrlist->addr.addr.addr6))
break;
if (addrlist)
break;
else
while (intr->next && strcmp(intr->intr, intr->next->intr) == 0)
intr = intr->next;
}
#endif
if (intr)
{
ans = 1;
if (!dryrun)
{
log_query(F_IPV4 | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
log_query(is_arpa | F_REVERSE | F_CONFIG, intr->name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL,
T_PTR, C_IN, "d", intr->name))
@@ -1546,7 +1569,8 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
for (flag = F_IPV4; flag; flag = (flag == F_IPV4) ? F_IPV6 : 0)
{
unsigned short type = T_A;
struct interface_name *intr;
if (flag == F_IPV6)
#ifdef HAVE_IPV6
type = T_AAAA;
@@ -1595,31 +1619,38 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
}
/* interface name stuff */
if (qtype == T_A)
for (intr = daemon->int_names; intr; intr = intr->next)
if (hostname_isequal(name, intr->name))
break;
if (intr)
{
struct interface_name *intr;
struct addrlist *addrlist;
for (intr = daemon->int_names; intr; intr = intr->next)
if (hostname_isequal(name, intr->name))
break;
enumerate_interfaces(0);
if (intr)
addrlist = intr->addr4;
#ifdef HAVE_IPV6
if (type == T_AAAA)
addrlist = intr->addr6;
#endif
ans = 1;
if (!dryrun)
{
ans = 1;
if (!dryrun)
{
if ((addr.addr.addr4 = get_ifaddr(intr->intr)).s_addr == (in_addr_t) -1)
log_query(F_FORWARD | F_CONFIG | F_IPV4 | F_NEG, name, NULL, NULL);
else
{
log_query(F_FORWARD | F_CONFIG | F_IPV4, name, &addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN, "4", &addr))
anscount++;
}
}
continue;
if (!addrlist)
log_query(F_FORWARD | F_CONFIG | flag | F_NEG, name, NULL, NULL);
else
for (; addrlist; addrlist = addrlist->next)
{
log_query(F_FORWARD | F_CONFIG | flag, name, &addrlist->addr, NULL);
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->local_ttl, NULL, type, C_IN,
type == T_A ? "4" : "6", &addrlist->addr))
anscount++;
}
}
continue;
}
cname_restart:
+1 -1
View File
@@ -1072,7 +1072,7 @@ size_t dhcp_reply(struct dhcp_context *context, char *iface_name, int int_index,
Have to set override to make sure we echo back the correct server-id */
struct irec *intr;
enumerate_interfaces();
enumerate_interfaces(0);
for (intr = daemon->interfaces; intr; intr = intr->next)
if (intr->addr.sa.sa_family == AF_INET &&
+3 -2
View File
@@ -201,8 +201,9 @@ void tftp_request(struct listener *listen, time_t now)
if (!iface_check(listen->family, &addra, name, NULL))
{
if (!option_bool(OPT_CLEVERBIND))
enumerate_interfaces();
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name))
enumerate_interfaces(0);
if (!loopback_exception(listen->tftpfd, listen->family, &addra, name) &&
!label_exception(if_index, listen->family, &addra) )
return;
}
+9 -5
View File
@@ -142,19 +142,23 @@ static int check_name(char *in)
int legal_hostname(char *name)
{
char c;
int first;
if (!check_name(name))
return 0;
for (; (c = *name); name++)
for (first = 1; (c = *name); name++, first = 0)
/* check for legal char a-z A-Z 0-9 - _ . */
{
if ((c >= 'A' && c <= 'Z') ||
(c >= 'a' && c <= 'z') ||
(c >= '0' && c <= '9') ||
c == '-' || c == '_')
(c >= 'a' && c <= 'z'))
continue;
if (!first &&
((c >= '0' && c <= '9') ||
c == '-' || c == '_'))
continue;
/* end of hostname part */
if (c == '.')
return 1;