Compare commits

...

36 Commits

Author SHA1 Message Date
Simon Kelley
55b42f6de3 Default to global, not link-local address in RA DNS field. 2012-12-21 16:53:15 +00:00
Simon Kelley
ed8b68ad06 Simplify and fix RA lifetime calculation. 2012-12-21 16:23:26 +00:00
Simon Kelley
bad7b875eb add general flag param to iface_enumerate IPv6 callback 2012-12-20 22:00:39 +00:00
Simon Kelley
5d162f20a9 Rationalise join_multicast() 2012-12-20 14:55:46 +00:00
Simon Kelley
9d29949440 typo 2012-12-18 21:48:15 +00:00
Simon Kelley
1b75c1e61f Per-context control over ra short period. 2012-12-18 19:55:25 +00:00
Simon Kelley
293fd0f700 Missed interface re-read path in netlink.c 2012-12-18 18:31:11 +00:00
Simon Kelley
c1be917782 DHCP context logging, more tweaks 2012-12-18 18:31:11 +00:00
Simon Kelley
bb86e858b6 Error dhcp constructors on platforms where no interface detection. 2012-12-18 18:31:11 +00:00
Simon Kelley
8445f5d2e2 Fix initialisation order. 2012-12-18 18:31:11 +00:00
Simon Kelley
72c9c3b11b complicated DHCP context logging. 2012-12-18 18:31:11 +00:00
Simon Kelley
6e3dba3fde Ignore template contexts where appropriate. 2012-12-18 18:31:11 +00:00
Simon Kelley
7558ecd9ac Fix periodic loop 2012-12-18 18:31:11 +00:00
Simon Kelley
1f776932a1 First checkin of interface-address constructor mode for DHCPv6 and RA. 2012-12-18 18:31:11 +00:00
Simon Kelley
4820dce97a Make authoritative stuff a compile-time option. 2012-12-18 18:30:30 +00:00
Simon Kelley
f8abe0c566 Fix crash in auth code for queries where class != C_IN 2012-12-15 11:59:25 +00:00
Simon Kelley
9def963c65 Bump debian version. 2012-12-14 11:58:56 +00:00
Simon Kelley
990123a937 Fix regexp foobar. 2012-12-14 11:56:15 +00:00
Simon Kelley
1d6c639310 Fix broken cache. 2012-12-14 11:19:36 +00:00
Simon Kelley
429798fd08 Allow addresses as well as interface names in --auth-server. 2012-12-10 20:45:53 +00:00
Simon Kelley
b5a8dd1dec Fix FTBFS with NO_DHCP. 2012-12-10 11:37:25 +00:00
Simon Kelley
95a0bd3701 Add .gitignore file. 2012-12-10 11:29:03 +00:00
Simon Kelley
8ff556739e SOA serial tweak. 2012-12-09 21:09:01 +00:00
Simon Kelley
496787677e Zone-transfer peer restriction option. 2012-12-09 18:31:10 +00:00
Simon Kelley
e1ff419cf9 Complete AXFR support 2012-12-09 17:08:47 +00:00
Simon Kelley
ee86ce68fc Fix TCP query forwarding to non-default servers. 2012-12-07 11:54:46 +00:00
Simon Kelley
b75e936372 First cut at zone transfer. 2012-12-07 11:50:41 +00:00
Simon Kelley
aa79235194 zero arcount. 2012-12-06 19:41:35 +00:00
Simon Kelley
7c305be1bd Bump Debian version. 2012-12-04 20:59:06 +00:00
Simon Kelley
f7fe362721 Tidy merge. 2012-12-04 20:55:54 +00:00
Simon Kelley
36bec089f7 Merge branch 'auth' 2012-12-04 20:50:38 +00:00
Simon Kelley
45dd1fece4 Correct NS and SOA records in auth mode for PTR queries. 2012-12-04 20:49:24 +00:00
Simon Kelley
5c0bd5b112 CNAME auth support. 2012-12-01 16:42:47 +00:00
Simon Kelley
86e3b9a026 Post-test fixes. 2012-11-30 13:46:48 +00:00
Simon Kelley
8273ea5a19 Add MX support. 2012-11-29 21:12:33 +00:00
Simon Kelley
4f7b304f53 Initial code to do authoritative DNS. 2012-11-28 21:27:02 +00:00
25 changed files with 1902 additions and 639 deletions

13
.gitignore vendored Normal file
View File

@@ -0,0 +1,13 @@
src/*.o
src/*.mo
src/dnsmasq.pot
src/dnsmasq
src/.configured
contrib/wrt/dhcp_lease_time
contrib/wrt/dhcp_release
debian/base/
debian/daemon/
debian/files
debian/substvars
debian/utils-substvars
debian/utils/

View File

@@ -1,3 +1,14 @@
version 2.65
Fix regression which broke forwarding of queries sent via
TCP which are not for A and AAAA and which were directed to
non-default servers. Thanks to Niax for the bug report.
Fix failure to build with DHCP support excluded. Thanks to
Gustavo Zacarias for the patch.
Fix nasty regression in 2.64 which completely broke cacheing.
version 2.64
Handle DHCP FQDN options with all flag bits zero and
--dhcp-client-update set. Thanks to Bernd Krumbroeck for

View File

@@ -65,7 +65,7 @@ version = -DVERSION='\"`$(top)/bld/get-version $(top)`\"'
objs = cache.o rfc1035.o util.o option.o forward.o network.o \
dnsmasq.o dhcp.o lease.o rfc2131.o netlink.o dbus.o bpf.o \
helper.o tftp.o log.o conntrack.o dhcp6.o rfc3315.o \
dhcp-common.o outpacket.o radv.o slaac.o
dhcp-common.o outpacket.o radv.o slaac.o auth.o
hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-protocol.h

View File

@@ -8,7 +8,7 @@ LOCAL_SRC_FILES := bpf.c cache.c dbus.c dhcp.c dnsmasq.c \
netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c
radv.c slaac.c auth.c
LOCAL_MODULE := dnsmasq

View File

@@ -17,7 +17,7 @@ elif grep '\$Format:%d\$' $1/VERSION >/dev/null 2>&1; then
# unsubstituted VERSION, but no git available.
echo UNKNOWN
else
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep $v[0-9]`
vers=`cat $1/VERSION | sed 's/[(), ]/,/ g' | tr ',' '\n' | grep ^v[0-9]`
if [ $? -eq 0 ]; then
echo "${vers}" | sort | head -n 1 | sed 's/^v//'

12
debian/changelog vendored
View File

@@ -1,3 +1,15 @@
dnsmasq (2.66-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 14 Dec 2012 11:58:41 +0000
dnsmasq (2.65-1) unstable; urgency=low
* New upstream.
-- Simon Kelley <simon@thekelleys.org.uk> Fri, 14 Dec 2012 11:34:12 +0000
dnsmasq (2.64-1) unstable; urgency=low
* New upstream.

742
src/auth.c Normal file
View File

@@ -0,0 +1,742 @@
/* dnsmasq is Copyright (c) 2000-2012 Simon Kelley
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; version 2 dated June, 1991, or
(at your option) version 3 dated 29 June, 2007.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "dnsmasq.h"
#ifdef HAVE_AUTH
static struct subnet *filter_zone(struct auth_zone *zone, int flag, struct all_addr *addr_u)
{
struct subnet *subnet;
for (subnet = zone->subnet; subnet; subnet = subnet->next)
{
if (subnet->is6 && (flag & F_IPV4))
continue;
if (!subnet->is6)
{
struct in_addr addr = addr_u->addr.addr4;
struct in_addr mask;
mask.s_addr = htonl(~((1 << (32 - subnet->prefixlen)) - 1));
if (is_same_net(addr, subnet->addr4, mask))
return subnet;
}
#ifdef HAVE_IPV6
else if (is_same_net6(&(addr_u->addr.addr6), &subnet->addr6, subnet->prefixlen))
return subnet;
#endif
}
return NULL;
}
static int in_zone(struct auth_zone *zone, char *name, char **cut)
{
size_t namelen = strlen(name);
size_t domainlen = strlen(zone->domain);
if (cut)
*cut = NULL;
if (namelen >= domainlen &&
hostname_isequal(zone->domain, &name[namelen - domainlen]))
{
if (namelen == domainlen)
return 1;
if (name[namelen - domainlen - 1] == '.')
{
if (cut)
*cut = &name[namelen - domainlen - 1];
return 1;
}
}
return 0;
}
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr)
{
char *name = daemon->namebuff;
unsigned char *p, *ansp;
int qtype, qclass;
int nameoffset, axfroffset = 0;
int q, anscount = 0, authcount = 0;
struct crec *crecp;
int auth = 1, trunc = 0, nxdomain = 1, soa = 0, ns = 0, axfr = 0;
struct auth_zone *zone = NULL;
struct subnet *subnet = NULL;
char *cut;
struct mx_srv_record *rec, *move, **up;
struct txt_record *txt;
struct interface_name *intr;
struct naptr *na;
struct all_addr addr;
struct cname *a;
if (ntohs(header->qdcount) == 0 || OPCODE(header) != QUERY )
return 0;
/* determine end of question section (we put answers there) */
if (!(ansp = skip_questions(header, qlen)))
return 0; /* bad packet */
/* now process each question, answers go in RRs after the question */
p = (unsigned char *)(header+1);
for (q = ntohs(header->qdcount); q != 0; q--)
{
unsigned short flag = 0;
int found = 0;
/* save pointer to name for copying into answers */
nameoffset = p - (unsigned char *)header;
/* now extract name as .-concatenated string into name */
if (!extract_name(header, qlen, &p, name, 1, 4))
return 0; /* bad packet */
GETSHORT(qtype, p);
GETSHORT(qclass, p);
if (qclass != C_IN)
{
auth = 0;
continue;
}
if (qtype == T_PTR)
{
if (!(flag = in_arpa_name_2_addr(name, &addr)))
continue;
for (zone = daemon->auth_zones; zone; zone = zone->next)
if ((subnet = filter_zone(zone, flag, &addr)))
break;
if (!zone)
{
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;
}
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 ((crecp = cache_find_by_addr(NULL, &addr, now, flag)))
do {
strcpy(name, cache_get_name(crecp));
if (crecp->flags & F_DHCP && !option_bool(OPT_DHCP_FQDN))
{
char *p = strchr(name, '.');
if (p)
*p = 0; /* must be bare name */
/* add external domain */
strcat(name, ".");
strcat(name, zone->domain);
log_query(flag | F_DHCP | F_REVERSE, name, &addr, record_source(crecp->uid));
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", name))
anscount++;
}
else if (crecp->flags & (F_DHCP | F_HOSTS) && in_zone(zone, name, NULL))
{
log_query(crecp->flags & ~F_FORWARD, name, &addr, record_source(crecp->uid));
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_PTR, C_IN, "d", name))
anscount++;
}
else
continue;
} while ((crecp = cache_find_by_addr(crecp, &addr, now, flag)));
if (!found)
log_query(flag | F_NEG | F_NXDOMAIN | F_REVERSE | F_AUTH, NULL, &addr, NULL);
continue;
}
cname_restart:
for (zone = daemon->auth_zones; zone; zone = zone->next)
if (in_zone(zone, name, &cut))
break;
if (!zone)
{
auth = 0;
continue;
}
for (rec = daemon->mxnames; rec; rec = rec->next)
if (!rec->issrv && hostname_isequal(name, rec->name))
{
nxdomain = 0;
if (qtype == T_MX)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_MX, C_IN, "sd", rec->weight, rec->target))
anscount++;
}
}
for (move = NULL, up = &daemon->mxnames, rec = daemon->mxnames; rec; rec = rec->next)
if (rec->issrv && hostname_isequal(name, rec->name))
{
nxdomain = 0;
if (qtype == T_SRV)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_SRV, C_IN, "sssd",
rec->priority, rec->weight, rec->srvport, rec->target))
anscount++;
}
/* unlink first SRV record found */
if (!move)
{
move = rec;
*up = rec->next;
}
else
up = &rec->next;
}
else
up = &rec->next;
/* put first SRV record back at the end. */
if (move)
{
*up = move;
move->next = NULL;
}
for (txt = daemon->rr; txt; txt = txt->next)
if (hostname_isequal(name, txt->name))
{
nxdomain = 0;
if (txt->class == qtype)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<RR>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, txt->class, C_IN, "t", txt->len, txt->txt))
anscount++;
}
}
for (txt = daemon->txt; txt; txt = txt->next)
if (txt->class == C_IN && hostname_isequal(name, txt->name))
{
nxdomain = 0;
if (qtype == T_TXT)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<TXT>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_TXT, C_IN, "t", txt->len, txt->txt))
anscount++;
}
}
for (na = daemon->naptr; na; na = na->next)
if (hostname_isequal(name, na->name))
{
nxdomain = 0;
if (qtype == T_NAPTR)
{
found = 1;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<NAPTR>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->auth_ttl,
NULL, T_NAPTR, C_IN, "sszzzd",
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
anscount++;
}
}
for (intr = daemon->int_names; intr; intr = intr->next)
if (hostname_isequal(name, intr->name))
{
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 (a = daemon->cnames; a; a = a->next)
if (hostname_isequal(name, a->alias) )
{
log_query(F_CONFIG | F_CNAME, name, NULL, NULL);
strcpy(name, a->target);
if (!strchr(name, '.'))
{
strcat(name, ".");
strcat(name, zone->domain);
}
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL,
T_CNAME, C_IN, "d", name))
anscount++;
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;
if (qtype == T_SOA)
{
soa = 1; /* inhibits auth section */
found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
}
else if (qtype == T_AXFR)
{
if (daemon->auth_peers)
{
struct iname *peers;
if (peer_addr->sa.sa_family == AF_INET)
peer_addr->in.sin_port = 0;
#ifdef HAVE_IPV6
else
peer_addr->in6.sin6_port = 0;
#endif
for (peers = daemon->auth_peers; peers; peers = peers->next)
if (sockaddr_isequal(peer_addr, &peers->addr))
break;
if (!peers)
{
if (peer_addr->sa.sa_family == AF_INET)
inet_ntop(AF_INET, &peer_addr->in.sin_addr, daemon->addrbuff, ADDRSTRLEN);
#ifdef HAVE_IPV6
else
inet_ntop(AF_INET6, &peer_addr->in6.sin6_addr, daemon->addrbuff, ADDRSTRLEN);
#endif
my_syslog(LOG_WARNING, _("ignoring zone transfer request from %s"), daemon->addrbuff);
return 0;
}
}
soa = 1; /* inhibits auth section */
ns = 1; /* ensure we include NS records! */
axfr = 1;
found = 1;
axfroffset = nameoffset;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<AXFR>");
}
else if (qtype == T_NS)
{
ns = 1; /* inhibits auth section */
found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
}
}
if (!option_bool(OPT_DHCP_FQDN) && cut)
{
*cut = 0; /* remove domain part */
if (!strchr(name, '.') && (crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
{
if (crecp->flags & F_DHCP)
do
{
nxdomain = 0;
if ((crecp->flags & flag) && filter_zone(zone, flag, &(crecp->addr.addr)))
{
*cut = '.'; /* restore domain part */
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
*cut = 0; /* remove domain part */
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &crecp->addr))
anscount++;
}
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
}
*cut = '.'; /* restore domain part */
}
if ((crecp = cache_find_by_name(NULL, name, now, F_IPV4 | F_IPV6)))
{
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
do
{
nxdomain = 0;
if ((crecp->flags & flag) && filter_zone(zone, flag, &(crecp->addr.addr)))
{
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
found = 1;
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
qtype == T_A ? "4" : "6", &crecp->addr))
anscount++;
}
} while ((crecp = cache_find_by_name(crecp, name, now, F_IPV4 | F_IPV6)));
}
if (!found)
log_query(flag | F_NEG | (nxdomain ? F_NXDOMAIN : 0) | F_FORWARD | F_AUTH, name, NULL, NULL);
}
/* Add auth section */
if (auth)
{
char *authname;
int newoffset, offset = 0;
if (!subnet)
authname = zone->domain;
else
{
/* handle NS and SOA for PTR records */
authname = name;
if (!subnet->is6)
{
in_addr_t a = ntohl(subnet->addr4.s_addr) >> 8;
char *p = name;
if (subnet->prefixlen == 24)
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
if (subnet->prefixlen != 8)
p += sprintf(p, "%d.", a & 0xff);
a = a >> 8;
p += sprintf(p, "%d.in-addr.arpa", a & 0xff);
}
#ifdef HAVE_IPV6
else
{
char *p = name;
int i;
for (i = subnet->prefixlen-1; i >= 0; i -= 4)
{
int dig = ((unsigned char *)&subnet->addr6)[i>>3];
p += sprintf(p, "%.1x.", (i>>2) & 1 ? dig & 15 : dig >> 4);
}
p += sprintf(p, "ip6.arpa");
}
#endif
}
/* handle NS and SOA in auth section or for explicit queries */
newoffset = ansp - (unsigned char *)header;
if (((anscount == 0 && !ns) || soa) &&
add_resource_record(header, limit, &trunc, 0, &ansp,
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
authname, daemon->authserver, daemon->hostmaster,
daemon->soa_sn, daemon->soa_refresh,
daemon->soa_retry, daemon->soa_expiry,
daemon->auth_ttl))
{
offset = newoffset;
if (soa)
anscount++;
else
authcount++;
}
if (anscount != 0 || ns)
{
struct name_list *secondary;
newoffset = ansp - (unsigned char *)header;
if (add_resource_record(header, limit, &trunc, -offset, &ansp,
daemon->auth_ttl, NULL, T_NS, C_IN, "d", offset == 0 ? authname : NULL, daemon->authserver))
{
if (offset == 0)
offset = newoffset;
if (ns)
anscount++;
else
authcount++;
}
if (!subnet)
for (secondary = daemon->secondary_forward_server; secondary; secondary = secondary->next)
if (add_resource_record(header, limit, &trunc, offset, &ansp,
daemon->auth_ttl, NULL, T_NS, C_IN, "d", secondary->name))
{
if (ns)
anscount++;
else
authcount++;
}
}
if (axfr)
{
for (rec = daemon->mxnames; rec; rec = rec->next)
if (in_zone(zone, rec->name, &cut))
{
if (cut)
*cut = 0;
if (rec->issrv)
{
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_SRV, C_IN, "sssd", cut ? rec->name : NULL,
rec->priority, rec->weight, rec->srvport, rec->target))
anscount++;
}
else
{
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_MX, C_IN, "sd", cut ? rec->name : NULL, rec->weight, rec->target))
anscount++;
}
/* restore config data */
if (cut)
*cut = '.';
}
for (txt = daemon->rr; txt; txt = txt->next)
if (in_zone(zone, txt->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, txt->class, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (txt = daemon->txt; txt; txt = txt->next)
if (txt->class == C_IN && in_zone(zone, txt->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_TXT, C_IN, "t", cut ? txt->name : NULL, txt->len, txt->txt))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
for (na = daemon->naptr; na; na = na->next)
if (in_zone(zone, na->name, &cut))
{
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp, daemon->auth_ttl,
NULL, T_NAPTR, C_IN, "sszzzd", cut ? na->name : NULL,
na->order, na->pref, na->flags, na->services, na->regexp, na->replace))
anscount++;
/* restore config data */
if (cut)
*cut = '.';
}
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 (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++;
/* restore config data */
if (cut)
*cut = '.';
}
for (a = daemon->cnames; a; a = a->next)
if (in_zone(zone, a->alias, &cut))
{
strcpy(name, a->target);
if (!strchr(name, '.'))
{
strcat(name, ".");
strcat(name, zone->domain);
}
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL,
T_CNAME, C_IN, "d", cut ? a->alias : NULL, name))
anscount++;
}
cache_enumerate(1);
while ((crecp = cache_enumerate(0)))
{
if ((crecp->flags & (F_IPV4 | F_IPV6)) &&
!(crecp->flags & (F_NEG | F_NXDOMAIN)) &&
(crecp->flags & F_FORWARD))
{
if ((crecp->flags & F_DHCP) && !option_bool(OPT_DHCP_FQDN))
{
char *cache_name = cache_get_name(crecp);
if (!strchr(cache_name, '.') && filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))
{
qtype = T_A;
#ifdef HAVE_IPV6
if (crecp->flags & F_IPV6)
qtype = T_AAAA;
#endif
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
(crecp->flags & F_IPV4) ? "4" : "6", cache_name, &crecp->addr))
anscount++;
}
}
if ((crecp->flags & F_HOSTS) || (((crecp->flags & F_DHCP) && option_bool(OPT_DHCP_FQDN))))
{
strcpy(name, cache_get_name(crecp));
if (in_zone(zone, name, &cut) && filter_zone(zone, (crecp->flags & (F_IPV6 | F_IPV4)), &(crecp->addr.addr)))
{
qtype = T_A;
#ifdef HAVE_IPV6
if (crecp->flags & F_IPV6)
qtype = T_AAAA;
#endif
if (cut)
*cut = 0;
if (add_resource_record(header, limit, &trunc, -axfroffset, &ansp,
daemon->auth_ttl, NULL, qtype, C_IN,
(crecp->flags & F_IPV4) ? "4" : "6", cut ? name : NULL, &crecp->addr))
anscount++;
}
}
}
}
/* repeat SOA as last record */
if (add_resource_record(header, limit, &trunc, axfroffset, &ansp,
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
daemon->authserver, daemon->hostmaster,
daemon->soa_sn, daemon->soa_refresh,
daemon->soa_retry, daemon->soa_expiry,
daemon->auth_ttl))
anscount++;
}
}
/* done all questions, set up header and return length of result */
/* clear authoritative and truncated flags, set QR flag */
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC)) | HB3_QR;
/* clear RA flag */
header->hb4 &= ~HB4_RA;
/* authoritive */
if (auth)
header->hb3 |= HB3_AA;
/* truncation */
if (trunc)
header->hb3 |= HB3_TC;
if (anscount == 0 && auth && nxdomain)
SET_RCODE(header, NXDOMAIN);
else
SET_RCODE(header, NOERROR); /* no error */
header->ancount = htons(anscount);
header->nscount = htons(authcount);
header->arcount = htons(0);
return ansp - (unsigned char *)header;
}
#endif

View File

@@ -147,7 +147,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
addr->s6_addr[3] = 0;
}
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, parm)))
if (!((*callback)(addr, prefix, scope_id, iface_index, 0, 0, 0, parm)))
goto err;
}
#endif

View File

@@ -235,6 +235,29 @@ char *cache_get_name(struct crec *crecp)
return crecp->name.sname;
}
struct crec *cache_enumerate(int init)
{
static int bucket;
static struct crec *cache;
if (init)
{
bucket = 0;
cache = NULL;
}
else if (cache && cache->hash_next)
cache = cache->hash_next;
else
{
cache = NULL;
while (bucket < hash_size)
if ((cache = hash_table[bucket++]))
break;
}
return cache;
}
static int is_outdated_cname_pointer(struct crec *crecp)
{
if (!(crecp->flags & F_CNAME))
@@ -371,7 +394,7 @@ struct crec *cache_insert(char *name, struct all_addr *addr,
int freed_all = flags & F_REVERSE;
int free_avail = 0;
if(daemon->max_cache_ttl < ttl)
if (daemon->max_cache_ttl != 0 && daemon->max_cache_ttl < ttl)
ttl = daemon->max_cache_ttl;
/* Don't log keys */
@@ -1248,14 +1271,14 @@ char *record_source(int index)
return "<unknown>";
}
void querystr(char *str, unsigned short type)
void querystr(char *desc, char *str, unsigned short type)
{
unsigned int i;
sprintf(str, "query[type=%d]", type);
sprintf(str, "%s[type=%d]", desc, type);
for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
if (typestr[i].type == type)
sprintf(str,"query[%s]", typestr[i].name);
sprintf(str,"%s[%s]", desc, typestr[i].name);
}
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
@@ -1316,6 +1339,8 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
source = arg;
else if (flags & F_UPSTREAM)
source = "reply";
else if (flags & F_AUTH)
source = "auth";
else if (flags & F_SERVER)
{
source = "forwarded";

View File

@@ -42,7 +42,11 @@
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq"
#define AUTH_TTL 600 /* default TTL for auth DNS */
#define SOA_REFRESH 1200 /* SOA refresh default */
#define SOA_RETRY 180 /* SOA retry default */
#define SOA_EXPIRY 1209600 /* SOA expiry default */
/* compile-time options: uncomment below to enable or do eg.
make COPTS=-DHAVE_BROKEN_RTC
@@ -92,12 +96,18 @@ HAVE_CONNTRACK
a build-dependency on libnetfilter_conntrack, but the resulting binary will
still run happily on a kernel without conntrack support.
HAVE_AUTH
define this to include the facility to act as an authoritative DNS
server for one or more zones.
NO_IPV6
NO_TFTP
NO_DHCP
NO_DHCP6
NO_SCRIPT
NO_LARGEFILE
NO_AUTH
these are avilable to explictly disable compile time options which would
otherwise be enabled automatically (HAVE_IPV6, >2Gb file sizes) or
which are enabled by default in the distributed source tree. Building dnsmasq
@@ -119,6 +129,7 @@ RESOLVFILE
#define HAVE_DHCP6
#define HAVE_TFTP
#define HAVE_SCRIPT
#define HAVE_AUTH
/* #define HAVE_LUASCRIPT */
/* #define HAVE_BROKEN_RTC */
/* #define HAVE_DBUS */
@@ -307,6 +318,9 @@ HAVE_SOCKADDR_SA_LEN
#define HAVE_SCRIPT
#endif
#ifdef NO_AUTH
#undef HAVE_AUTH
#endif
/* Define a string indicating which options are in use.
DNSMASQP_COMPILE_OPTS is only defined in dnsmasq.c */
@@ -365,7 +379,11 @@ static char *compile_opts =
#ifndef HAVE_CONNTRACK
"no-"
#endif
"conntrack";
"conntrack "
#ifndef HAVE_AUTH
"no-"
#endif
"auth";
#endif

View File

@@ -333,83 +333,6 @@ void dhcp_update_configs(struct dhcp_config *configs)
}
#ifdef HAVE_DHCP6
static int join_multicast_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct ipv6_mreq mreq;
int fd, i, max = *((int *)vparam);
struct iname *tmp;
(void)prefix;
(void)scope;
(void)dad;
/* record which interfaces we join on, so that we do it at most one per
interface, even when they have multiple addresses. Use outpacket
as an array of int, since it's always allocated here and easy
to expand for theoretical vast numbers of interfaces. */
for (i = 0; i < max; i++)
if (if_index == ((int *)daemon->outpacket.iov_base)[i])
return 1;
if ((fd = socket(PF_INET6, SOCK_DGRAM, 0)) == -1)
return 0;
if (!indextoname(fd, if_index, ifrn_name))
{
close(fd);
return 0;
}
close(fd);
/* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name))
return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifrn_name) == 0))
return 1;
mreq.ipv6mr_interface = if_index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
if (daemon->ra_contexts &&
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
return 0;
expand_buf(&daemon->outpacket, (max+1) * sizeof(int));
((int *)daemon->outpacket.iov_base)[max++] = if_index;
*((int *)vparam) = max;
return 1;
}
void join_multicast(void)
{
int count = 0;
if (!iface_enumerate(AF_INET6, &count, join_multicast_worker))
die(_("failed to join DHCPv6 multicast group: %s"), NULL, EC_BADNET);
}
#endif
#ifdef HAVE_LINUX_NETWORK
void bindtodevice(int fd)
{
@@ -750,4 +673,86 @@ char *option_string(int prot, unsigned int opt, unsigned char *val, int opt_len,
}
void log_context(int family, struct dhcp_context *context)
{
/* Cannot use dhcp_buff* for RA contexts */
void *start = &context->start;
void *end = &context->end;
char *n = "", *m = "", *p = daemon->namebuff;
*p = 0;
#ifdef HAVE_DHCP6
if (family == AF_INET6)
{
struct in6_addr subnet = context->start6;
if (!(context->flags & CONTEXT_TEMPLATE))
setaddr6part(&subnet, 0);
inet_ntop(AF_INET6, &subnet, daemon->addrbuff, ADDRSTRLEN);
start = &context->start6;
end = &context->end6;
}
#endif
if ((context->flags & CONTEXT_DHCP) ||
!(context->flags & (CONTEXT_CONSTRUCTED | CONTEXT_TEMPLATE)))
{
if (family != AF_INET && (context->flags & CONTEXT_DEPRECATE))
strcpy(daemon->namebuff, _(", prefix deprecated"));
else
{
p += sprintf(p, _(", lease time "));
m = p;
prettyprint_time(p, context->lease_time);
p += strlen(p);
}
}
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_CONSTRUCTED)
{
n = p;
p += sprintf(p, ", constructed for %s", context->template_interface);
}
if (context->flags & CONTEXT_TEMPLATE)
{
n = p;
p += sprintf(p, ", template for %s", context->template_interface);
}
#endif
if ((context->flags & CONTEXT_DHCP) || family == AF_INET)
{
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
my_syslog(MS_DHCP | LOG_INFO,
(context->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s") :
(context->flags & CONTEXT_STATIC) ?
_("%s, static leases only on %.0s%s%s") :
(context->flags & CONTEXT_PROXY) ?
_("%s, proxy on subnet %.0s%s%.0s") :
_("%s, IP range %s -- %s%s"),
(family != AF_INET) ? "DHCPv6" : "DHCP",
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
}
#ifdef HAVE_DHCP6
if (context->flags & CONTEXT_RA_NAME)
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s%s"),
daemon->addrbuff, n);
if (context->flags & CONTEXT_RA)
my_syslog(MS_DHCP | LOG_INFO, _("router advertisement on %s%s%s"),
daemon->addrbuff,
(context->flags & (CONTEXT_CONSTRUCTED | CONTEXT_TEMPLATE)) ? "" : ", prefix valid ",
(context->flags & (CONTEXT_CONSTRUCTED | CONTEXT_TEMPLATE)) ? n : m);
#endif
}
#endif

View File

@@ -262,7 +262,7 @@ void dhcp_packet(time_t now, int pxe_fd)
parm.current = NULL;
parm.ind = iface_index;
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name))
if (!iface_check(AF_INET, (struct all_addr *)&iface_addr, ifr.ifr_name, NULL))
{
/* If we failed to match the primary address of the interface, see if we've got a --listen-address
for a secondary */

View File

@@ -25,7 +25,8 @@ struct iface_param {
};
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
int scope, int if_index, int flags,
int preferred, int valid, void *vparam);
static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, void *parm);
@@ -181,14 +182,17 @@ void dhcp6_packet(time_t now)
}
static int complete_context6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags, int preferred,
int valid, void *vparam)
{
struct dhcp_context *context;
struct iface_param *param = vparam;
struct iname *tmp;
(void)scope; /* warning */
(void)dad;
(void)flags;
(void)preferred;
(void)valid;
if (if_index == param->ind &&
!IN6_IS_ADDR_LOOPBACK(local) &&
@@ -210,7 +214,8 @@ static int complete_context6(struct in6_addr *local, int prefix,
for (context = daemon->dhcp6; context; context = context->next)
{
if (prefix == context->prefix &&
if (!(context->flags & CONTEXT_TEMPLATE) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
@@ -467,6 +472,131 @@ static int make_duid1(int index, unsigned int type, char *mac, size_t maclen, vo
return 0;
}
struct cparam {
time_t now;
int newone;
};
static int construct_worker(struct in6_addr *local, int prefix,
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
char ifrn_name[IFNAMSIZ];
struct in6_addr start6, end6;
struct dhcp_context *template, *context;
(void)scope;
(void)flags;
(void)valid;
(void)preferred;
struct cparam *param = vparam;
if (IN6_IS_ADDR_LOOPBACK(local) ||
IN6_IS_ADDR_LINKLOCAL(local) ||
IN6_IS_ADDR_MULTICAST(local))
return 1;
if (!indextoname(daemon->doing_dhcp6 ? daemon->dhcp6fd : daemon->icmp6fd, if_index, ifrn_name))
return 0;
for (template = daemon->dhcp6; template; template = template->next)
if (!(template->flags & CONTEXT_TEMPLATE))
{
/* non-template entries, just fill in interface and local addresses */
if (prefix == template->prefix &&
is_same_net6(local, &template->start6, prefix) &&
is_same_net6(local, &template->end6, prefix))
{
template->if_index = if_index;
template->local6 = *local;
}
}
else if (strcmp(ifrn_name, template->template_interface) == 0 &&
addr6part(local) == addr6part(&template->start6))
{
start6 = *local;
setaddr6part(&start6, addr6part(&template->start6));
end6 = *local;
setaddr6part(&end6, addr6part(&template->end6));
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_CONSTRUCTED) &&
IN6_ARE_ADDR_EQUAL(&start6, &context->start6) &&
IN6_ARE_ADDR_EQUAL(&end6, &context->end6))
{
context->flags &= ~CONTEXT_GC;
break;
}
if (!context && (context = whine_malloc(sizeof (struct dhcp_context))))
{
*context = *template;
context->start6 = start6;
context->end6 = end6;
context->flags &= ~CONTEXT_TEMPLATE;
context->flags |= CONTEXT_CONSTRUCTED;
context->if_index = if_index;
context->local6 = *local;
context->next = daemon->dhcp6;
daemon->dhcp6 = context;
ra_start_unsolicted(param->now, context);
/* we created a new one, need to call
lease_update_file to get periodic functions called */
param->newone = 1;
log_context(AF_INET6, context);
}
}
return 1;
}
void dhcp_construct_contexts(time_t now)
{
struct dhcp_context *tmp, *context, **up;
struct cparam param;
param.newone = 0;
param.now = now;
for (context = daemon->dhcp6; context; context = context->next)
if (context->flags & CONTEXT_CONSTRUCTED)
{
context->flags |= CONTEXT_GC;
context->if_index = 0;
}
iface_enumerate(AF_INET6, &param, construct_worker);
for (up = &daemon->dhcp6, context = daemon->dhcp6; context; context = tmp)
{
tmp = context->next;
if (context->flags & CONTEXT_GC)
{
if (daemon->dhcp6 == context)
daemon->dhcp6 = context->next;
*up = context->next;
free(context);
}
else
up = &context->next;
}
if (param.newone)
{
if (daemon->dhcp || daemon->doing_dhcp6)
lease_update_file(now);
else
/* Not doing DHCP, so no lease system, manage alarms for ra only */
send_alarm(periodic_ra(now), now);
}
}
#endif

View File

@@ -52,6 +52,7 @@
#define T_OPT 41
#define T_TKEY 249
#define T_TSIG 250
#define T_AXFR 252
#define T_MAILB 253
#define T_ANY 255

View File

@@ -51,6 +51,7 @@ int main (int argc, char **argv)
cap_user_header_t hdr = NULL;
cap_user_data_t data = NULL;
#endif
struct dhcp_context *context;
#ifdef LOCALEDIR
setlocale(LC_ALL, "");
@@ -84,6 +85,7 @@ int main (int argc, char **argv)
daemon->addrbuff = safe_malloc(ADDRSTRLEN);
#ifdef HAVE_DHCP
if (!daemon->lease_file)
{
@@ -147,69 +149,77 @@ int main (int argc, char **argv)
die(_("asychronous logging is not available under Android"), NULL, EC_BADCONF);
#endif
#ifndef HAVE_AUTH
if (daemon->authserver)
die(_("authoritative DNS not available: set HAVE_AUTH in src/config.h"), NULL, EC_BADCONF);
#endif
rand_init();
now = dnsmasq_time();
/* Create a serial at startup is not configured. */
if (daemon->authinterface && daemon->soa_sn == 0)
#ifdef HAVE_BROKEN_RTC
die(_("zone serial must be configured in --auth-soa"));
#else
daemon->soa_sn = now;
#endif
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
{
{
# ifdef HAVE_DHCP6
if (daemon->dhcp6)
{
daemon->doing_ra = option_bool(OPT_RA);
for (context = daemon->dhcp6; context; context = context->next)
{
if (context->flags & CONTEXT_DHCP)
daemon->doing_dhcp6 = 1;
if (context->flags & CONTEXT_RA)
daemon->doing_ra = 1;
#ifndef HAVE_LINUX_NETWORK
if (context->flags & CONTEXT_TEMPLATE)
die (_("dhcp-range constructor not available on this platform"), NULL, EC_BADCONF);
#endif
}
}
# endif
/* Note that order matters here, we must call lease_init before
creating any file descriptors which shouldn't be leaked
to the lease-script init process. We need to call common_init
before lease_init to allocate buffers it uses.*/
dhcp_common_init();
lease_init(now);
if (daemon->dhcp || daemon->doing_dhcp6)
{
dhcp_common_init();
lease_init(now);
}
if (daemon->dhcp)
dhcp_init();
}
# ifdef HAVE_DHCP6
/* Start RA subsystem if --enable-ra OR dhcp-range=<subnet>, ra-only */
if (daemon->ra_contexts || option_bool(OPT_RA))
{
/* link the DHCP6 contexts to the ra-only ones so we can traverse them all
from ->ra_contexts, but only the non-ra-onlies from ->dhcp6 */
struct dhcp_context *context;
if (daemon->doing_ra)
ra_init(now);
if (!daemon->ra_contexts)
daemon->ra_contexts = daemon->dhcp6;
else
{
for (context = daemon->ra_contexts; context->next; context = context->next);
context->next = daemon->dhcp6;
}
ra_init(now);
}
if (daemon->dhcp6)
dhcp6_init();
if (daemon->doing_dhcp6)
dhcp6_init();
# endif
}
#endif
#ifdef HAVE_LINUX_NETWORK
/* After lease_init */
netlink_init();
if (option_bool(OPT_NOWILD) && option_bool(OPT_CLEVERBIND))
die(_("cannot set --bind-interfaces and --bind-dynamic"), NULL, EC_BADCONF);
#endif
#ifdef HAVE_DHCP6
/* after netlink_init */
if (daemon->ra_contexts || daemon->dhcp6)
join_multicast();
#endif
#ifdef HAVE_DHCP
/* after netlink_init */
if (daemon->dhcp || daemon->dhcp6)
lease_find_interfaces(now);
#endif
if (!enumerate_interfaces())
die(_("failed to find list of interfaces: %s"), NULL, EC_MISC);
@@ -239,6 +249,12 @@ int main (int argc, char **argv)
}
else
create_wildcard_listeners();
#ifdef HAVE_DHCP6
/* after enumerate_interfaces() */
if (daemon->doing_dhcp6 || daemon->doing_ra)
join_multicast(1);
#endif
if (daemon->port != 0)
cache_init();
@@ -614,90 +630,27 @@ int main (int argc, char **argv)
if (daemon->max_logs != 0)
my_syslog(LOG_INFO, _("asynchronous logging enabled, queue limit is %d messages"), daemon->max_logs);
if (daemon->ra_contexts)
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6 || daemon->ra_contexts)
{
struct dhcp_context *dhcp_tmp;
int family = AF_INET;
dhcp_tmp = daemon->dhcp;
#ifdef HAVE_DHCP6
again:
#endif
for (; dhcp_tmp; dhcp_tmp = dhcp_tmp->next)
{
void *start = &dhcp_tmp->start;
void *end = &dhcp_tmp->end;
#ifdef HAVE_DHCP6
if (family == AF_INET6)
{
start = &dhcp_tmp->start6;
end = &dhcp_tmp->end6;
struct in6_addr subnet = dhcp_tmp->start6;
setaddr6part(&subnet, 0);
inet_ntop(AF_INET6, &subnet, daemon->dhcp_buff2, 256);
}
#endif
if (family != AF_INET && (dhcp_tmp->flags & CONTEXT_DEPRECATE))
strcpy(daemon->namebuff, _("prefix deprecated"));
else
{
char *p = daemon->namebuff;
p += sprintf(p, _("lease time "));
prettyprint_time(p, dhcp_tmp->lease_time);
}
inet_ntop(family, start, daemon->dhcp_buff, 256);
inet_ntop(family, end, daemon->dhcp_buff3, 256);
if ((dhcp_tmp->flags & CONTEXT_DHCP) || family == AF_INET)
my_syslog(MS_DHCP | LOG_INFO,
(dhcp_tmp->flags & CONTEXT_RA_STATELESS) ?
_("%s stateless on %s%.0s%.0s") :
(dhcp_tmp->flags & CONTEXT_STATIC) ?
_("%s, static leases only on %.0s%s, %s") :
(dhcp_tmp->flags & CONTEXT_PROXY) ?
_("%s, proxy on subnet %.0s%s%.0s") :
_("%s, IP range %s -- %s, %s"),
(family != AF_INET) ? "DHCPv6" : "DHCP",
daemon->dhcp_buff, daemon->dhcp_buff3, daemon->namebuff);
for (context = daemon->dhcp; context; context = context->next)
log_context(AF_INET, context);
if (dhcp_tmp->flags & CONTEXT_RA_NAME)
my_syslog(MS_DHCP | LOG_INFO, _("DHCPv4-derived IPv6 names on %s"),
daemon->dhcp_buff2);
if (dhcp_tmp->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS))
{
if (!(dhcp_tmp->flags & CONTEXT_DEPRECATE))
{
char *p = daemon->namebuff;
p += sprintf(p, _("prefix valid "));
prettyprint_time(p, dhcp_tmp->lease_time > 7200 ? dhcp_tmp->lease_time : 7200);
}
my_syslog(MS_DHCP | LOG_INFO, _("SLAAC on %s %s"),
daemon->dhcp_buff2, daemon->namebuff);
}
}
#ifdef HAVE_DHCP6
if (family == AF_INET)
{
family = AF_INET6;
if (daemon->ra_contexts)
dhcp_tmp = daemon->ra_contexts;
else
dhcp_tmp = daemon->dhcp6;
goto again;
}
#endif
# ifdef HAVE_DHCP6
for (context = daemon->dhcp6; context; context = context->next)
log_context(AF_INET6, context);
}
#endif
if (daemon->doing_dhcp6 || daemon->doing_ra)
dhcp_construct_contexts(now);
if (option_bool(OPT_RA))
my_syslog(MS_DHCP | LOG_INFO, _("IPv6 router advertisement enabled"));
# endif
/* after dhcp_contruct_contexts */
if (daemon->dhcp || daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
#ifdef HAVE_TFTP
if (option_bool(OPT_TFTP))
@@ -804,13 +757,13 @@ int main (int argc, char **argv)
#endif
#ifdef HAVE_DHCP6
if (daemon->dhcp6)
if (daemon->doing_dhcp6)
{
FD_SET(daemon->dhcp6fd, &rset);
bump_maxfd(daemon->dhcp6fd, &maxfd);
}
if (daemon->ra_contexts)
if (daemon->doing_ra)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
@@ -874,7 +827,7 @@ int main (int argc, char **argv)
#ifdef HAVE_LINUX_NETWORK
if (FD_ISSET(daemon->netlinkfd, &rset))
netlink_multicast();
netlink_multicast(now);
#endif
/* Check for changes to resolv files once per second max. */
@@ -922,11 +875,11 @@ int main (int argc, char **argv)
}
#ifdef HAVE_DHCP6
if (daemon->dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
if (daemon->doing_dhcp6 && FD_ISSET(daemon->dhcp6fd, &rset))
dhcp6_packet(now);
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet();
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet(now);
#endif
# ifdef HAVE_SCRIPT
@@ -1106,13 +1059,13 @@ static void async_event(int pipe, time_t now)
case EVENT_ALARM:
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
if (daemon->dhcp || daemon->doing_dhcp6)
{
lease_prune(NULL, now);
lease_update_file(now);
}
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
else if (daemon->doing_ra)
/* Not doing DHCP, so no lease system, manage alarms for ra only */
send_alarm(periodic_ra(now), now);
#endif
@@ -1269,7 +1222,7 @@ void clear_cache_and_reload(time_t now)
cache_reload();
#ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6)
if (daemon->dhcp || daemon->doing_dhcp6)
{
if (option_bool(OPT_ETHERS))
dhcp_read_ethers();
@@ -1280,7 +1233,7 @@ void clear_cache_and_reload(time_t now)
lease_update_dns(1);
}
#ifdef HAVE_DHCP6
else if (daemon->ra_contexts)
else if (daemon->doing_ra)
/* Not doing DHCP, so no lease system, manage
alarms for ra only */
send_alarm(periodic_ra(now), now);
@@ -1440,11 +1393,18 @@ static void check_dns_listeners(fd_set *set, time_t now)
struct server *s;
int flags;
struct in_addr netmask;
int auth_dns;
if (iface)
netmask = iface->netmask;
{
netmask = iface->netmask;
auth_dns = iface->dns_auth;
}
else
netmask.s_addr = 0;
{
netmask.s_addr = 0;
auth_dns = 0;
}
#ifndef NO_FORK
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to
@@ -1463,7 +1423,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, &tcp_addr, netmask);
buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
shutdown(confd, SHUT_RDWR);
close(confd);
@@ -1576,7 +1536,7 @@ int icmp_ping(struct in_addr addr)
set_log_writer(&wset, &maxfd);
#ifdef HAVE_DHCP6
if (daemon->ra_contexts)
if (daemon->doing_ra)
{
FD_SET(daemon->icmp6fd, &rset);
bump_maxfd(daemon->icmp6fd, &maxfd);
@@ -1595,8 +1555,8 @@ int icmp_ping(struct in_addr addr)
check_dns_listeners(&rset, now);
#ifdef HAVE_DHCP6
if (daemon->ra_contexts && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet();
if (daemon->doing_ra && FD_ISSET(daemon->icmp6fd, &rset))
icmp6_packet(now);
#endif
#ifdef HAVE_TFTP

View File

@@ -278,6 +278,20 @@ struct cname {
struct cname *next;
};
struct auth_zone {
char *domain;
struct subnet {
int is6, prefixlen;
struct in_addr addr4;
#ifdef HAVE_IPV6
struct in6_addr addr6;
#endif
struct subnet *next;
} *subnet;
struct auth_zone *next;
};
struct host_record {
struct name_list {
char *name;
@@ -357,6 +371,8 @@ struct crec {
#define F_SERVER (1u<<18)
#define F_QUERY (1u<<19)
#define F_NOERR (1u<<20)
#define F_AUTH (1u<<21)
/* composites */
#define F_TYPE (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS) /* Only one may be set */
@@ -373,6 +389,11 @@ union mysockaddr {
#endif
};
/* bits in flag param to IPv6 callbacks from iface_enumerate() */
#define IFACE_TENTATIVE 1
#define IFACE_DEPRECATED 2
#define SERV_FROM_RESOLV 1 /* 1 for servers from resolv, 0 for command line. */
#define SERV_NO_ADDR 2 /* no server, this domain is local only */
#define SERV_LITERAL_ADDRESS 4 /* addr is the answer, not the server */
@@ -412,8 +433,8 @@ struct server {
struct irec {
union mysockaddr addr;
struct in_addr netmask; /* only valid for IPv4 */
int tftp_ok, dhcp_ok, mtu, done, dad;
char *name;
int tftp_ok, dhcp_ok, mtu, done, dad, dns_auth, index, multicast_done;
char *name;
struct irec *next;
};
@@ -651,7 +672,7 @@ struct cond_domain {
#endif
int is6;
struct cond_domain *next;
};
};
struct dhcp_context {
unsigned int lease_time, addr_epoch;
@@ -662,7 +683,8 @@ struct dhcp_context {
struct in6_addr start6, end6; /* range of available addresses */
struct in6_addr local6;
int prefix, if_index;
time_t ra_time;
time_t ra_time, ra_short_period_start;
char *template_interface;
#endif
int flags;
struct dhcp_netid netid, *filter;
@@ -679,6 +701,11 @@ struct dhcp_context {
#define CONTEXT_RA_STATELESS 128
#define CONTEXT_DHCP 256
#define CONTEXT_DEPRECATE 512
#define CONTEXT_TEMPLATE 1024 /* create contexts using addresses */
#define CONTEXT_CONSTRUCTED 2048
#define CONTEXT_GC 4096
#define CONTEXT_RA 8192
struct ping_result {
struct in_addr addr;
@@ -733,17 +760,21 @@ extern struct daemon {
struct ptr_record *ptr;
struct host_record *host_records, *host_records_tail;
struct cname *cnames;
struct auth_zone *auth_zones;
struct interface_name *int_names;
char *mxtarget;
char *lease_file;
char *username, *groupname, *scriptuser;
char *luascript;
char *authserver, *hostmaster;
struct iname *authinterface;
struct name_list *secondary_forward_server;
int group_set, osport;
char *domain_suffix;
struct cond_domain *cond_domain;
char *runfile;
char *lease_change_command;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except;
struct iname *if_names, *if_addrs, *if_except, *dhcp_except, *auth_peers;
struct bogus_addr *bogus_addr;
struct server *servers;
int log_fac; /* log facility */
@@ -751,9 +782,9 @@ extern struct daemon {
int max_logs; /* queue limit */
int cachesize, ftabsize;
int port, query_port, min_port;
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl;
unsigned long local_ttl, neg_ttl, max_ttl, max_cache_ttl, auth_ttl;
struct hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6, *ra_contexts;
struct dhcp_context *dhcp, *dhcp6;
struct dhcp_config *dhcp_conf;
struct dhcp_opt *dhcp_opts, *dhcp_match, *dhcp_opts6, *dhcp_match6;
struct dhcp_vendor *dhcp_vendors;
@@ -764,6 +795,7 @@ extern struct daemon {
struct addr_list *override_relays;
int override;
int enable_pxe;
int doing_ra, doing_dhcp6;
struct dhcp_netid_list *dhcp_ignore, *dhcp_ignore_names, *dhcp_gen_names;
struct dhcp_netid_list *force_broadcast, *bootp_dynamic;
struct hostsfile *dhcp_hosts_file, *dhcp_opts_file;
@@ -778,6 +810,7 @@ extern struct daemon {
unsigned int duid_enterprise, duid_config_len;
unsigned char *duid_config;
char *dbus_name;
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
/* globally used stuff for DNS */
char *packet; /* packet buffer */
@@ -835,7 +868,7 @@ extern struct daemon {
void cache_init(void);
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
char *record_source(int index);
void querystr(char *str, unsigned short type);
void querystr(char *desc, char *str, unsigned short type);
struct crec *cache_find_by_addr(struct crec *crecp,
struct all_addr *addr, time_t now,
unsigned short prot);
@@ -851,6 +884,7 @@ struct in_addr a_record_from_hosts(char *name, time_t now);
void cache_unhash_dhcp(void);
void dump_cache(time_t now);
char *cache_get_name(struct crec *crecp);
struct crec *cache_enumerate(int init);
char *get_domain(struct in_addr addr);
#ifdef HAVE_IPV6
char *get_domain6(struct in6_addr *addr);
@@ -879,6 +913,18 @@ unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen);
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
int nameoffset, unsigned char **pp, unsigned long ttl,
int *offset, unsigned short type, unsigned short class, char *format, ...);
unsigned char *skip_questions(struct dns_header *header, size_t plen);
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes);
int in_arpa_name_2_addr(char *namein, struct all_addr *addrp);
/* auth.c */
#ifdef HAVE_AUTH
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr);
#endif
/* util.c */
void rand_init(void);
@@ -935,7 +981,7 @@ char *parse_server(char *arg, union mysockaddr *addr,
void reply_query(int fd, int family, time_t now);
void receive_query(struct listener *listen, time_t now);
unsigned char *tcp_request(int confd, time_t now,
union mysockaddr *local_addr, struct in_addr netmask);
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
void server_gone(struct server *server);
struct frec *get_new_frec(time_t now, int *wait);
int send_from(int fd, int nowild, char *packet, size_t len,
@@ -953,12 +999,15 @@ int enumerate_interfaces();
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 iface_check(int family, struct all_addr *addr, char *name, int *auth_dns);
int fix_fd(int fd);
struct in_addr get_ifaddr(char *intr);
#ifdef HAVE_IPV6
int set_ipv6pktinfo(int fd);
#endif
#ifdef HAVE_DHCP6
void join_multicast(int dienow);
#endif
/* dhcp.c */
#ifdef HAVE_DHCP
@@ -1040,7 +1089,7 @@ void poll_resolv(int force, int do_reload, time_t now);
/* netlink.c */
#ifdef HAVE_LINUX_NETWORK
void netlink_init(void);
void netlink_multicast(void);
void netlink_multicast(time_t now);
#endif
/* bpf.c */
@@ -1108,6 +1157,7 @@ struct dhcp_config *find_config6(struct dhcp_config *configs,
struct dhcp_config *config_find_by_address6(struct dhcp_config *configs, struct in6_addr *net,
int prefix, u64 addr);
void make_duid(time_t now);
void dhcp_construct_contexts(time_t now);
#endif
/* rfc3315.c */
@@ -1138,8 +1188,8 @@ void bindtodevice(int fd);
#endif
# ifdef HAVE_DHCP6
void display_opts6(void);
void join_multicast(void);
# endif
void log_context(int family, struct dhcp_context *context);
#endif
/* outpacket.c */
@@ -1158,16 +1208,14 @@ void put_opt6_string(char *s);
/* radv.c */
#ifdef HAVE_DHCP6
void ra_init(time_t now);
void icmp6_packet(void);
void icmp6_packet(time_t now);
time_t periodic_ra(time_t now);
void ra_start_unsolicted(time_t now, struct dhcp_context *context);
#endif
/* slaac.c */
#ifdef HAVE_DHCP6
void build_subnet_map(void);
void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force);
time_t periodic_slaac(time_t now, struct dhcp_lease *leases);
void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *interface, struct dhcp_lease *leases);
void schedule_subnet_map(void);
#endif

View File

@@ -635,6 +635,7 @@ void receive_query(struct listener *listen, time_t now)
size_t m;
ssize_t n;
int if_index = 0;
int auth_dns = 0;
struct iovec iov[1];
struct msghdr msg;
struct cmsghdr *cmptr;
@@ -657,17 +658,20 @@ void receive_query(struct listener *listen, time_t now)
/* packet buffer overwritten */
daemon->srv_save = NULL;
if (listen->iface && listen->family == AF_INET && option_bool(OPT_NOWILD))
dst_addr_4.s_addr = 0;
netmask.s_addr = 0;
if (listen->iface && option_bool(OPT_NOWILD))
{
dst_addr_4 = listen->iface->addr.in.sin_addr;
netmask = listen->iface->netmask;
auth_dns = listen->iface->dns_auth;
if (listen->family == AF_INET)
{
dst_addr_4 = listen->iface->addr.in.sin_addr;
netmask = listen->iface->netmask;
}
}
else
{
dst_addr_4.s_addr = 0;
netmask.s_addr = 0;
}
iov[0].iov_base = daemon->packet;
iov[0].iov_len = daemon->edns_pktsz;
@@ -760,7 +764,7 @@ void receive_query(struct listener *listen, time_t now)
/* enforce available interface configuration */
if (!indextoname(listen->fd, if_index, ifr.ifr_name) ||
!iface_check(listen->family, &dst_addr, ifr.ifr_name))
!iface_check(listen->family, &dst_addr, ifr.ifr_name, &auth_dns))
return;
if (listen->family == AF_INET && option_bool(OPT_LOCALISE))
@@ -796,7 +800,7 @@ void receive_query(struct listener *listen, time_t now)
{
char types[20];
querystr(types, type);
querystr(auth_dns ? "auth" : "query", types, type);
if (listen->family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
@@ -808,19 +812,32 @@ void receive_query(struct listener *listen, time_t now)
#endif
}
m = answer_request (header, ((char *) header) + PACKETSZ, (size_t)n,
dst_addr_4, netmask, now);
if (m >= 1)
#ifdef HAVE_AUTH
if (auth_dns)
{
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
(char *)header, m, &source_addr, &dst_addr, if_index);
daemon->local_answer++;
m = answer_auth(header, ((char *) header) + PACKETSZ, (size_t)n, now, &source_addr);
if (m >= 1)
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
(char *)header, m, &source_addr, &dst_addr, if_index);
}
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
header, (size_t)n, now, NULL))
daemon->queries_forwarded++;
else
daemon->local_answer++;
#endif
{
m = answer_request(header, ((char *) header) + PACKETSZ, (size_t)n,
dst_addr_4, netmask, now);
if (m >= 1)
{
send_from(listen->fd, option_bool(OPT_NOWILD) || option_bool(OPT_CLEVERBIND),
(char *)header, m, &source_addr, &dst_addr, if_index);
daemon->local_answer++;
}
else if (forward_query(listen->fd, &source_addr, &dst_addr, if_index,
header, (size_t)n, now, NULL))
daemon->queries_forwarded++;
else
daemon->local_answer++;
}
}
/* The daemon forks before calling this: it should deal with one connection,
@@ -828,13 +845,14 @@ void receive_query(struct listener *listen, time_t now)
about resources for debug mode, when the fork is suppressed: that's
done by the caller. */
unsigned char *tcp_request(int confd, time_t now,
union mysockaddr *local_addr, struct in_addr netmask)
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns)
{
size_t size = 0;
int norebind = 0;
int checking_disabled;
size_t m;
unsigned short qtype, gotname;
unsigned short qtype;
unsigned int gotname;
unsigned char c1, c2;
/* Max TCP packet + slop */
unsigned char *packet = whine_malloc(65536 + MAXDNAME + RRFIXEDSZ);
@@ -870,7 +888,7 @@ unsigned char *tcp_request(int confd, time_t now,
{
char types[20];
querystr(types, qtype);
querystr(auth_dns ? "auth" : "query", types, qtype);
if (peer_addr.sa.sa_family == AF_INET)
log_query(F_QUERY | F_IPV4 | F_FORWARD, daemon->namebuff,
@@ -887,142 +905,150 @@ unsigned char *tcp_request(int confd, time_t now,
else
dst_addr_4.s_addr = 0;
/* m > 0 if answered from cache */
m = answer_request(header, ((char *) header) + 65536, (unsigned int)size,
dst_addr_4, netmask, now);
/* Do this by steam now we're not in the select() loop */
check_log_writer(NULL);
if (m == 0)
#ifdef HAVE_AUTH
if (auth_dns)
m = answer_auth(header, ((char *) header) + 65536, (size_t)size, now, &peer_addr);
else
#endif
{
unsigned int flags = 0;
struct all_addr *addrp = NULL;
int type = 0;
char *domain = NULL;
if (option_bool(OPT_ADD_MAC))
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
/* m > 0 if answered from cache */
m = answer_request(header, ((char *) header) + 65536, (size_t)size,
dst_addr_4, netmask, now);
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
last_server = daemon->servers;
else
last_server = daemon->last_server;
if (!flags && last_server)
/* Do this by steam now we're not in the select() loop */
check_log_writer(NULL);
if (m == 0)
{
struct server *firstsendto = NULL;
unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
/* Loop round available servers until we succeed in connecting to one.
Note that this code subtley ensures that consecutive queries on this connection
which can go to the same server, do so. */
while (1)
{
if (!firstsendto)
firstsendto = last_server;
else
{
if (!(last_server = last_server->next))
last_server = daemon->servers;
if (last_server == firstsendto)
break;
}
unsigned int flags = 0;
struct all_addr *addrp = NULL;
int type = 0;
char *domain = NULL;
/* server for wrong domain */
if (type != (last_server->flags & SERV_TYPE) ||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
continue;
if (last_server->tcpfd == -1)
if (option_bool(OPT_ADD_MAC))
size = add_mac(header, size, ((char *) header) + 65536, &peer_addr);
if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
last_server = daemon->servers;
else
last_server = daemon->last_server;
if (!flags && last_server)
{
struct server *firstsendto = NULL;
unsigned int crc = questions_crc(header, (unsigned int)size, daemon->namebuff);
/* Loop round available servers until we succeed in connecting to one.
Note that this code subtley ensures that consecutive queries on this connection
which can go to the same server, do so. */
while (1)
{
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
if (!firstsendto)
firstsendto = last_server;
else
{
if (!(last_server = last_server->next))
last_server = daemon->servers;
if (last_server == firstsendto)
break;
}
/* server for wrong domain */
if (type != (last_server->flags & SERV_TYPE) ||
(type == SERV_HAS_DOMAIN && !hostname_isequal(domain, last_server->domain)))
continue;
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
if (last_server->tcpfd == -1)
{
if ((last_server->tcpfd = socket(last_server->addr.sa.sa_family, SOCK_STREAM, 0)) == -1)
continue;
if ((!local_bind(last_server->tcpfd, &last_server->source_addr, last_server->interface, 1) ||
connect(last_server->tcpfd, &last_server->addr.sa, sa_len(&last_server->addr)) == -1))
{
close(last_server->tcpfd);
last_server->tcpfd = -1;
continue;
}
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (option_bool(OPT_CONNTRACK))
{
unsigned int mark;
struct all_addr local;
#ifdef HAVE_IPV6
if (local_addr->sa.sa_family == AF_INET6)
local.addr.addr6 = local_addr->in6.sin6_addr;
else
#endif
local.addr.addr4 = local_addr->in.sin_addr;
if (get_incoming_mark(&peer_addr, &local, 1, &mark))
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
}
#endif
}
c1 = size >> 8;
c2 = size;
if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
!read_write(last_server->tcpfd, &c2, 1, 0) ||
!read_write(last_server->tcpfd, packet, size, 0) ||
!read_write(last_server->tcpfd, &c1, 1, 1) ||
!read_write(last_server->tcpfd, &c2, 1, 1))
{
close(last_server->tcpfd);
last_server->tcpfd = -1;
continue;
}
#ifdef HAVE_CONNTRACK
/* Copy connection mark of incoming query to outgoing connection. */
if (option_bool(OPT_CONNTRACK))
{
unsigned int mark;
struct all_addr local;
#ifdef HAVE_IPV6
if (local_addr->sa.sa_family == AF_INET6)
local.addr.addr6 = local_addr->in6.sin6_addr;
else
#endif
local.addr.addr4 = local_addr->in.sin_addr;
if (get_incoming_mark(&peer_addr, &local, 1, &mark))
setsockopt(last_server->tcpfd, SOL_SOCKET, SO_MARK, &mark, sizeof(unsigned int));
}
#endif
}
c1 = size >> 8;
c2 = size;
if (!read_write(last_server->tcpfd, &c1, 1, 0) ||
!read_write(last_server->tcpfd, &c2, 1, 0) ||
!read_write(last_server->tcpfd, packet, size, 0) ||
!read_write(last_server->tcpfd, &c1, 1, 1) ||
!read_write(last_server->tcpfd, &c2, 1, 1))
{
close(last_server->tcpfd);
last_server->tcpfd = -1;
continue;
}
m = (c1 << 8) | c2;
if (!read_write(last_server->tcpfd, packet, m, 1))
return packet;
if (!gotname)
strcpy(daemon->namebuff, "query");
if (last_server->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&last_server->addr.in.sin_addr, NULL);
}
m = (c1 << 8) | c2;
if (!read_write(last_server->tcpfd, packet, m, 1))
return packet;
if (!gotname)
strcpy(daemon->namebuff, "query");
if (last_server->addr.sa.sa_family == AF_INET)
log_query(F_SERVER | F_IPV4 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&last_server->addr.in.sin_addr, NULL);
#ifdef HAVE_IPV6
else
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
else
log_query(F_SERVER | F_IPV6 | F_FORWARD, daemon->namebuff,
(struct all_addr *)&last_server->addr.in6.sin6_addr, NULL);
#endif
/* There's no point in updating the cache, since this process will exit and
lose the information after a few queries. We make this call for the alias and
bogus-nxdomain side-effects. */
/* If the crc of the question section doesn't match the crc we sent, then
someone might be attempting to insert bogus values into the cache by
sending replies containing questions and bogus answers. */
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
m = process_reply(header, now, last_server, (unsigned int)m,
option_bool(OPT_NO_REBIND) && !norebind, checking_disabled);
break;
/* There's no point in updating the cache, since this process will exit and
lose the information after a few queries. We make this call for the alias and
bogus-nxdomain side-effects. */
/* If the crc of the question section doesn't match the crc we sent, then
someone might be attempting to insert bogus values into the cache by
sending replies containing questions and bogus answers. */
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
m = process_reply(header, now, last_server, (unsigned int)m,
option_bool(OPT_NO_REBIND) && !norebind, checking_disabled);
break;
}
}
/* In case of local answer or no connections made. */
if (m == 0)
m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
}
/* In case of local answer or no connections made. */
if (m == 0)
m = setup_reply(header, (unsigned int)size, addrp, flags, daemon->local_ttl);
}
check_log_writer(NULL);
c1 = m>>8;
c2 = m;
if (!read_write(confd, &c1, 1, 0) ||
if (m == 0 ||
!read_write(confd, &c1, 1, 0) ||
!read_write(confd, &c2, 1, 0) ||
!read_write(confd, packet, m, 0))
return packet;

View File

@@ -308,7 +308,7 @@ void lease_update_file(time_t now)
#ifdef HAVE_DHCP6
/* do timed RAs and determine when the next is, also pings to potential SLAAC addresses */
if (daemon->ra_contexts)
if (daemon->doing_ra)
{
time_t event;
@@ -363,12 +363,15 @@ static int find_interface_v4(struct in_addr local, int if_index,
#ifdef HAVE_DHCP6
static int find_interface_v6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
struct dhcp_lease *lease;
(void)scope;
(void)dad;
(void)flags;
(void)preferred;
(void)valid;
for (lease = leases; lease; lease = lease->next)
if ((lease->flags & (LEASE_TA | LEASE_NA)))
@@ -395,10 +398,6 @@ void lease_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
start-time. */
void lease_find_interfaces(time_t now)
{
#ifdef HAVE_DHCP6
build_subnet_map();
#endif
iface_enumerate(AF_INET, &now, find_interface_v4);
#ifdef HAVE_DHCP6
iface_enumerate(AF_INET6, &now, find_interface_v6);
@@ -420,6 +419,11 @@ void lease_update_dns(int force)
if (daemon->port != 0 && (dns_dirty || force))
{
#ifndef HAVE_BROKEN_RTC
/* force transfer to authoritative secondaries */
daemon->soa_sn++;
#endif
cache_unhash_dhcp();
for (lease = leases; lease; lease = lease->next)

View File

@@ -39,6 +39,7 @@ static struct iovec iov;
static u32 netlink_pid;
static int nl_async(struct nlmsghdr *h);
static void nl_newinterface(time_t now);
void netlink_init(void)
{
@@ -50,10 +51,14 @@ void netlink_init(void)
addr.nl_pid = 0; /* autobind */
addr.nl_groups = RTMGRP_IPV4_ROUTE;
if (option_bool(OPT_CLEVERBIND))
addr.nl_groups |= RTMGRP_IPV4_IFADDR;
addr.nl_groups |= RTMGRP_IPV4_IFADDR;
#ifdef HAVE_IPV6
addr.nl_groups |= RTMGRP_IPV6_ROUTE;
if (daemon->ra_contexts || option_bool(OPT_CLEVERBIND))
if (option_bool(OPT_CLEVERBIND))
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
#endif
#ifdef HAVE_DHCP6
if (daemon->doing_ra || daemon->doing_dhcp6)
addr.nl_groups |= RTMGRP_IPV6_IFADDR;
#endif
@@ -187,7 +192,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
if (h->nlmsg_seq != seq || h->nlmsg_pid != netlink_pid || h->nlmsg_type == NLMSG_ERROR)
{
/* May be multicast arriving async */
if (nl_async(h) && option_bool(OPT_CLEVERBIND))
if (nl_async(h))
newaddr = 1;
}
else if (h->nlmsg_type == NLMSG_DONE)
@@ -195,11 +200,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
/* handle async new interface address arrivals, these have to be done
after we complete as we're not re-entrant */
if (newaddr)
{
enumerate_interfaces();
create_bound_listeners(0);
}
nl_newinterface(dnsmasq_time());
return callback_ok;
}
else if (h->nlmsg_type == RTM_NEWADDR && family != AF_UNSPEC && family != AF_LOCAL)
@@ -236,17 +238,32 @@ int iface_enumerate(int family, void *parm, int (*callback)())
else if (ifa->ifa_family == AF_INET6)
{
struct in6_addr *addrp = NULL;
u32 valid = 0, preferred = 0;
int flags = 0;
while (RTA_OK(rta, len1))
{
if (rta->rta_type == IFA_ADDRESS)
addrp = ((struct in6_addr *)(rta+1));
else if (rta->rta_type == IFA_CACHEINFO)
{
struct ifa_cacheinfo *ifc = (struct ifa_cacheinfo *)(rta+1);
preferred = ifc->ifa_prefered;
valid = ifc->ifa_valid;
}
rta = RTA_NEXT(rta, len1);
}
if (ifa->ifa_flags & IFA_F_TENTATIVE)
flags |= IFACE_TENTATIVE;
if (ifa->ifa_flags & IFA_F_DEPRECATED)
flags |= IFACE_DEPRECATED;
if (addrp && callback_ok)
if (!((*callback)(addrp, (int)(ifa->ifa_prefixlen), (int)(ifa->ifa_scope),
(int)(ifa->ifa_index), (int)(ifa->ifa_flags & IFA_F_TENTATIVE), parm)))
(int)(ifa->ifa_index), flags,
(int) preferred, (int)valid, parm)))
callback_ok = 0;
}
#endif
@@ -305,7 +322,7 @@ int iface_enumerate(int family, void *parm, int (*callback)())
}
}
void netlink_multicast(void)
void netlink_multicast(time_t now)
{
ssize_t len;
struct nlmsghdr *h;
@@ -318,17 +335,14 @@ void netlink_multicast(void)
if ((len = netlink_recv()) != -1)
for (h = (struct nlmsghdr *)iov.iov_base; NLMSG_OK(h, (size_t)len); h = NLMSG_NEXT(h, len))
if (nl_async(h) && option_bool(OPT_CLEVERBIND))
if (nl_async(h))
newaddr = 1;
/* restore non-blocking status */
fcntl(daemon->netlinkfd, F_SETFL, flags);
if (newaddr)
{
enumerate_interfaces();
create_bound_listeners(0);
}
nl_newinterface(now);
}
static int nl_async(struct nlmsghdr *h)
@@ -371,25 +385,33 @@ static int nl_async(struct nlmsghdr *h)
}
return 0;
}
else if (h->nlmsg_type == RTM_NEWADDR)
{
#ifdef HAVE_DHCP6
/* force RAs to sync new network and pick up new interfaces. */
if (daemon->ra_contexts)
{
schedule_subnet_map();
ra_start_unsolicted(dnsmasq_time(), NULL);
/* cause lease_update_file to run after we return, in case we were called from
iface_enumerate and can't re-enter it now */
send_alarm(0, 0);
}
#endif
return 1; /* clever bind mode - rescan */
}
else if (h->nlmsg_type == RTM_NEWADDR || h->nlmsg_type == RTM_DELADDR)
return 1; /* clever bind mode - rescan */
return 0;
}
static void nl_newinterface(time_t now)
{
if (option_bool(OPT_CLEVERBIND))
{
enumerate_interfaces();
create_bound_listeners(0);
}
#ifdef HAVE_DHCP6
if (daemon->doing_dhcp6 || daemon->doing_ra)
{
dhcp_construct_contexts(now);
join_multicast(0);
}
if (daemon->doing_dhcp6)
lease_find_interfaces(now);
#endif
}
#endif

View File

@@ -107,7 +107,7 @@ int indextoname(int fd, int index, char *name)
#endif
int iface_check(int family, struct all_addr *addr, char *name)
int iface_check(int family, struct all_addr *addr, char *name, int *auth)
{
struct iname *tmp;
int ret = 1;
@@ -115,6 +115,9 @@ int iface_check(int family, struct all_addr *addr, char *name)
/* Note: have to check all and not bail out early, so that we set the
"used" flags. */
if (auth)
*auth = 0;
if (daemon->if_names || daemon->if_addrs)
{
ret = 0;
@@ -123,25 +126,48 @@ int iface_check(int family, struct all_addr *addr, char *name)
if (tmp->name && (strcmp(tmp->name, name) == 0))
ret = tmp->used = 1;
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == family)
{
if (family == AF_INET &&
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
ret = tmp->used = 1;
if (addr)
for (tmp = daemon->if_addrs; tmp; tmp = tmp->next)
if (tmp->addr.sa.sa_family == family)
{
if (family == AF_INET &&
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
ret = tmp->used = 1;
#ifdef HAVE_IPV6
else if (family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
&addr->addr.addr6))
ret = tmp->used = 1;
else if (family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr,
&addr->addr.addr6))
ret = tmp->used = 1;
#endif
}
}
}
for (tmp = daemon->if_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, name) == 0))
ret = 0;
for (tmp = daemon->authinterface; tmp; tmp = tmp->next)
if (tmp->name)
{
if (strcmp(tmp->name, name) == 0)
break;
}
else if (addr && tmp->addr.sa.sa_family == AF_INET && family == AF_INET &&
tmp->addr.in.sin_addr.s_addr == addr->addr.addr4.s_addr)
break;
#ifdef HAVE_IPV6
else if (addr && tmp->addr.sa.sa_family == AF_INET6 && family == AF_INET6 &&
IN6_ARE_ADDR_EQUAL(&tmp->addr.in6.sin6_addr, &addr->addr.addr6))
break;
#endif
if (tmp && auth)
{
*auth = 1;
ret = 1;
}
return ret;
}
@@ -153,6 +179,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
struct ifreq ifr;
int tftp_ok = !!option_bool(OPT_TFTP);
int dhcp_ok = 1;
int auth_dns = 0;
#ifdef HAVE_DHCP
struct iname *tmp;
#endif
@@ -210,25 +237,31 @@ 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))
!iface_check(AF_INET, (struct all_addr *)&addr->in.sin_addr, ifr.ifr_name, &auth_dns))
return 1;
#ifdef HAVE_DHCP
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
{
tftp_ok = 0;
dhcp_ok = 0;
}
#endif
#ifdef HAVE_IPV6
if (addr->sa.sa_family == AF_INET6 &&
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name))
!iface_check(AF_INET6, (struct all_addr *)&addr->in6.sin6_addr, ifr.ifr_name, &auth_dns))
return 1;
#endif
#ifdef HAVE_DHCP
/* No DHCP where we're doing auth DNS. */
if (auth_dns)
{
tftp_ok = 0;
dhcp_ok = 0;
}
else
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, ifr.ifr_name) == 0))
{
tftp_ok = 0;
dhcp_ok = 0;
}
#endif
/* add to list */
if ((iface = whine_malloc(sizeof(struct irec))))
{
@@ -236,9 +269,11 @@ static int iface_allowed(struct irec **irecp, int if_index,
iface->netmask = netmask;
iface->tftp_ok = tftp_ok;
iface->dhcp_ok = dhcp_ok;
iface->dns_auth = auth_dns;
iface->mtu = mtu;
iface->dad = dad;
iface->done = 0;
iface->done = iface->multicast_done = 0;
iface->index = if_index;
if ((iface->name = whine_malloc(strlen(ifr.ifr_name)+1)))
{
strcpy(iface->name, ifr.ifr_name);
@@ -247,6 +282,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
return 1;
}
free(iface);
}
errno = ENOMEM;
@@ -255,7 +291,8 @@ static int iface_allowed(struct irec **irecp, int if_index,
#ifdef HAVE_IPV6
static int iface_allowed_v6(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
union mysockaddr addr;
struct in_addr netmask; /* dummy */
@@ -263,6 +300,8 @@ static int iface_allowed_v6(struct in6_addr *local, int prefix,
(void)prefix; /* warning */
(void)scope; /* warning */
(void)preferred;
(void)valid;
memset(&addr, 0, sizeof(addr));
#ifdef HAVE_SOCKADDR_SA_LEN
@@ -273,7 +312,7 @@ 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, dad);
return iface_allowed((struct irec **)vparam, if_index, &addr, netmask, !!(flags & IFACE_TENTATIVE));
}
#endif
@@ -550,6 +589,61 @@ int is_dad_listeners(void)
return 0;
}
#ifdef HAVE_DHCP6
void join_multicast(int dienow)
{
struct irec *iface, *tmp;
for (iface = daemon->interfaces; iface; iface = iface->next)
if (iface->dhcp_ok && !iface->multicast_done)
{
/* There's an irec per address but we only want to join for multicast
once per interface. Weed out duplicates. */
for (tmp = daemon->interfaces; tmp; tmp = tmp->next)
if (tmp->multicast_done && tmp->index == iface->index)
break;
iface->multicast_done = 1;
if (!tmp)
{
struct ipv6_mreq mreq;
int err = 0;
mreq.ipv6mr_interface = iface->index;
inet_pton(AF_INET6, ALL_RELAY_AGENTS_AND_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
inet_pton(AF_INET6, ALL_SERVERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_dhcp6 &&
setsockopt(daemon->dhcp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
inet_pton(AF_INET6, ALL_ROUTERS, &mreq.ipv6mr_multiaddr);
if (daemon->doing_ra &&
setsockopt(daemon->icmp6fd, IPPROTO_IPV6, IPV6_JOIN_GROUP, &mreq, sizeof(mreq)) == -1)
err = 1;
if (err)
{
char *s = _("interface %s failed to join DHCPv6 multicast group: %s");
if (dienow)
die(s, iface->name, EC_BADNET);
else
my_syslog(LOG_ERR, s, iface->name, strerror(errno));
}
}
}
}
#endif
/* return a UDP socket bound to a random port, have to cope with straying into
occupied port nos and reserved ones. */
int random_sock(int family)

View File

@@ -121,6 +121,12 @@ struct myoption {
#define LOPT_RR 310
#define LOPT_CLVERBIND 311
#define LOPT_MAXCTTL 312
#define LOPT_AUTHZONE 313
#define LOPT_AUTHSERV 314
#define LOPT_AUTHTTL 315
#define LOPT_AUTHSOA 316
#define LOPT_AUTHSFS 317
#define LOPT_AUTHPEER 318
#ifdef HAVE_GETOPT_LONG
static const struct option opts[] =
@@ -247,6 +253,12 @@ static const struct myoption opts[] =
{ "dhcp-duid", 1, 0, LOPT_DUID },
{ "host-record", 1, 0, LOPT_HOST_REC },
{ "bind-dynamic", 0, 0, LOPT_CLVERBIND },
{ "auth-zone", 1, 0, LOPT_AUTHZONE },
{ "auth-server", 1, 0, LOPT_AUTHSERV },
{ "auth-ttl", 1, 0, LOPT_AUTHTTL },
{ "auth-soa", 1, 0, LOPT_AUTHSOA },
{ "auth-sec-servers", 1, 0, LOPT_AUTHSFS },
{ "auth-peer", 1, 0, LOPT_AUTHPEER },
{ NULL, 0, 0, 0 }
};
@@ -378,7 +390,13 @@ static struct {
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL },
{ LOPT_HOST_REC, ARG_DUP, "<name>,<address>", gettext_noop("Specify host (A/AAAA and PTR) records"), NULL },
{ LOPT_RR, ARG_DUP, "<name>,<RR-number>,[<data>]", gettext_noop("Specify arbitrary DNS resource record"), NULL },
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL},
{ LOPT_CLVERBIND, OPT_CLEVERBIND, NULL, gettext_noop("Bind to interfaces in use - check for new interfaces"), NULL },
{ LOPT_AUTHSERV, ARG_ONE, "<NS>,<interface>", gettext_noop("Export local names to global DNS"), NULL },
{ LOPT_AUTHZONE, ARG_DUP, "<domain>,<subnet>[,<subnet>]", gettext_noop("Domain to export to global DNS"), NULL },
{ LOPT_AUTHTTL, ARG_ONE, "<integer>", gettext_noop("Set TTL for authoritative replies"), NULL },
{ LOPT_AUTHSOA, ARG_ONE, "<serial>[,...]", gettext_noop("Set authoritive zone information"), NULL },
{ 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 },
{ 0, 0, NULL, NULL, NULL }
};
@@ -605,24 +623,6 @@ static void do_usage(void)
#define ret_err(x) do { strcpy(errstr, (x)); return 0; } while (0)
#ifdef HAVE_DHCP
static int is_tag_prefix(char *arg)
{
if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
return 1;
return 0;
}
static char *set_prefix(char *arg)
{
if (strstr(arg, "set:") == arg)
return arg+4;
return arg;
}
char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_addr, char *interface, int *flags)
{
int source_port = 0, serv_port = NAMESERVER_PORT;
@@ -710,6 +710,24 @@ char *parse_server(char *arg, union mysockaddr *addr, union mysockaddr *source_a
return NULL;
}
#ifdef HAVE_DHCP
static int is_tag_prefix(char *arg)
{
if (arg && (strstr(arg, "net:") == arg || strstr(arg, "tag:") == arg))
return 1;
return 0;
}
static char *set_prefix(char *arg)
{
if (strstr(arg, "set:") == arg)
return arg+4;
return arg;
}
/* This is too insanely large to keep in-line in the switch */
static int parse_dhcp_opt(char *errstr, char *arg, int flags)
{
@@ -1513,7 +1531,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->next = daemon->dhcp_hosts_file;
daemon->dhcp_hosts_file = new;
}
else if (option == LOPT_DHCP_OPTS)
else if (option == LOPT_DHCP_OPTS)
{
new->next = daemon->dhcp_opts_file;
daemon->dhcp_opts_file = new;
@@ -1521,6 +1539,133 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break;
}
case LOPT_AUTHSERV: /* --auth-server */
if (!(comma = split(arg)))
ret_err(gen_err);
daemon->authserver = opt_string_alloc(arg);
arg = comma;
do {
struct iname *new = opt_malloc(sizeof(struct iname));
comma = split(arg);
new->name = NULL;
unhide_metas(arg);
if ((new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
new->addr.sa.sa_family = AF_INET;
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &new->addr.in6.sin6_addr) > 0)
new->addr.sa.sa_family = AF_INET6;
#endif
else
new->name = opt_string_alloc(arg);
new->next = daemon->authinterface;
daemon->authinterface = new;
arg = comma;
} while (arg);
break;
case LOPT_AUTHSFS: /* --auth-sec-servers */
{
struct name_list *new;
do {
comma = split(arg);
new = opt_malloc(sizeof(struct name_list));
new->name = opt_string_alloc(arg);
new->next = daemon->secondary_forward_server;
daemon->secondary_forward_server = new;
arg = comma;
} while (arg);
break;
}
case LOPT_AUTHZONE: /* --auth-zone */
{
struct auth_zone *new;
comma = split(arg);
if (!comma)
ret_err(gen_err);
new = opt_malloc(sizeof(struct auth_zone));
new->domain = opt_string_alloc(arg);
new->subnet = NULL;
new->next = daemon->auth_zones;
daemon->auth_zones = new;
while ((arg = comma))
{
int prefixlen = 0;
char *prefix;
struct subnet *subnet = opt_malloc(sizeof(struct subnet));
subnet->next = new->subnet;
new->subnet = subnet;
comma = split(arg);
prefix = split_chr(arg, '/');
if (prefix && !atoi_check(prefix, &prefixlen))
ret_err(gen_err);
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;
}
#ifdef HAVE_IPV6
else if (inet_pton(AF_INET6, arg, &subnet->addr6))
{
subnet->prefixlen = (prefixlen == 0) ? 64 : prefixlen;
subnet->is6 = 1;
}
#endif
else
ret_err(gen_err);
}
break;
}
case LOPT_AUTHSOA: /* --auth-soa */
comma = split(arg);
atoi_check(arg, (int *)&daemon->soa_sn);
if (comma)
{
char *cp;
arg = comma;
comma = split(arg);
daemon->hostmaster = opt_string_alloc(arg);
for (cp = daemon->hostmaster; *cp; cp++)
if (*cp == '@')
*cp = '.';
if (comma)
{
arg = comma;
comma = split(arg);
atoi_check(arg, (int *)&daemon->soa_refresh);
if (comma)
{
arg = comma;
comma = split(arg);
atoi_check(arg, (int *)&daemon->soa_retry);
if (comma)
{
arg = comma;
comma = split(arg);
atoi_check(arg, (int *)&daemon->soa_expiry);
}
}
}
}
break;
case 's': /* --domain */
if (strcmp (arg, "#") == 0)
set_option_bool(OPT_RESOLV_DOMAIN);
@@ -1534,7 +1679,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
if (comma)
{
struct cond_domain *new = safe_malloc(sizeof(struct cond_domain));
struct cond_domain *new = opt_malloc(sizeof(struct cond_domain));
char *netpart;
unhide_metas(comma);
@@ -1748,14 +1893,15 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
case 'a': /* --listen-address */
case LOPT_AUTHPEER: /* --auth-peer */
do {
struct iname *new = opt_malloc(sizeof(struct iname));
comma = split(arg);
unhide_metas(arg);
new->next = daemon->if_addrs;
if (arg && (new->addr.in.sin_addr.s_addr = inet_addr(arg)) != (in_addr_t)-1)
{
new->addr.sa.sa_family = AF_INET;
new->addr.in.sin_port = 0;
#ifdef HAVE_SOCKADDR_SA_LEN
new->addr.in.sin_len = sizeof(new->addr.in);
#endif
@@ -1766,6 +1912,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
new->addr.sa.sa_family = AF_INET6;
new->addr.in6.sin6_flowinfo = 0;
new->addr.in6.sin6_scope_id = 0;
new->addr.in6.sin6_port = 0;
#ifdef HAVE_SOCKADDR_SA_LEN
new->addr.in6.sin6_len = sizeof(new->addr.in6);
#endif
@@ -1775,7 +1922,16 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
ret_err(gen_err);
new->used = 0;
daemon->if_addrs = new;
if (option == 'a')
{
new->next = daemon->if_addrs;
daemon->if_addrs = new;
}
else
{
new->next = daemon->auth_peers;
daemon->auth_peers = new;
}
arg = comma;
} while (arg);
break;
@@ -1933,6 +2089,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_NEGTTL: /* --neg-ttl */
case LOPT_MAXTTL: /* --max-ttl */
case LOPT_MAXCTTL: /* --max-cache-ttl */
case LOPT_AUTHTTL: /* --auth-ttl */
{
int ttl;
if (!atoi_check(arg, &ttl))
@@ -1943,6 +2100,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
daemon->max_ttl = (unsigned long)ttl;
else if (option == LOPT_MAXCTTL)
daemon->max_cache_ttl = (unsigned long)ttl;
else if (option == LOPT_AUTHTTL)
daemon->auth_ttl = (unsigned long)ttl;
else
daemon->local_ttl = (unsigned long)ttl;
break;
@@ -2021,7 +2180,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case 'F': /* --dhcp-range */
{
int k, leasepos = 2;
char *cp, *a[7] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL };
char *cp, *a[8] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
struct dhcp_context *new = opt_malloc(sizeof(struct dhcp_context));
memset (new, 0, sizeof(*new));
@@ -2068,7 +2227,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
}
}
for (k = 1; k < 7; k++)
for (k = 1; k < 8; k++)
if (!(a[k] = split(a[k-1])))
break;
@@ -2125,28 +2284,25 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
if (strcmp(a[leasepos], "static") == 0)
new->flags |= CONTEXT_STATIC | CONTEXT_DHCP;
else if (strcmp(a[leasepos], "ra-only") == 0 || strcmp(a[leasepos], "slaac") == 0 )
new->flags |= CONTEXT_RA_ONLY;
new->flags |= CONTEXT_RA_ONLY | CONTEXT_RA;
else if (strcmp(a[leasepos], "ra-names") == 0)
new->flags |= CONTEXT_RA_NAME;
new->flags |= CONTEXT_RA_NAME | CONTEXT_RA;
else if (strcmp(a[leasepos], "ra-stateless") == 0)
new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP;
new->flags |= CONTEXT_RA_STATELESS | CONTEXT_DHCP | CONTEXT_RA;
else if (leasepos == 1 && inet_pton(AF_INET6, a[leasepos], &new->end6))
new->flags |= CONTEXT_DHCP;
else if (strstr(a[leasepos], "constructor:") == a[leasepos])
{
new->template_interface = opt_string_alloc(a[leasepos] + 12);
new->flags |= CONTEXT_TEMPLATE;
}
else
break;
}
if (new->flags & CONTEXT_DHCP)
{
new->next = daemon->dhcp6;
daemon->dhcp6 = new;
}
else
{
new->next = daemon->ra_contexts;
daemon->ra_contexts = new;
}
new->next = daemon->dhcp6;
daemon->dhcp6 = new;
/* bare integer < 128 is prefix value */
if (leasepos < k)
{
@@ -2158,10 +2314,14 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
{
new->prefix = pref;
leasepos++;
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)) &&
new->prefix != 64)
ret_err(_("prefix must be exactly 64 for RA subnets"));
else if (new->prefix < 64)
if (new->prefix != 64)
{
if ((new->flags & (CONTEXT_RA_ONLY | CONTEXT_RA_NAME | CONTEXT_RA_STATELESS)))
ret_err(_("prefix must be exactly 64 for RA subnets"));
else if (new->template_interface)
ret_err(_("prefix must be exactly 64 for subnet constructors"));
}
if (new->prefix < 64)
ret_err(_("prefix must be at least 64"));
}
}
@@ -3613,6 +3773,10 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->tftp_max = TFTP_MAX_CONNECTIONS;
daemon->edns_pktsz = EDNS_PKTSZ;
daemon->log_fac = -1;
daemon->auth_ttl = AUTH_TTL;
daemon->soa_refresh = SOA_REFRESH;
daemon->soa_retry = SOA_RETRY;
daemon->soa_expiry = SOA_EXPIRY;
add_txt("version.bind", "dnsmasq-" VERSION );
add_txt("authors.bind", "Simon Kelley");
add_txt("copyright.bind", COPYRIGHT);
@@ -3720,7 +3884,15 @@ void read_opts(int argc, char **argv, char *compile_opts)
tmp->addr.in6.sin6_port = htons(daemon->port);
#endif /* IPv6 */
}
/* create default, if not specified */
if (daemon->authserver && !daemon->hostmaster)
{
strcpy(buff, "hostmaster.");
strcat(buff, daemon->authserver);
daemon->hostmaster = opt_string_alloc(buff);
}
/* only one of these need be specified: the other defaults to the host-name */
if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
{

View File

@@ -27,25 +27,28 @@
#include <netinet/icmp6.h>
struct ra_param {
time_t now;
int ind, managed, other, found_context, first;
char *if_name;
struct dhcp_netid *tags;
struct in6_addr link_local;
struct in6_addr link_local, link_global;
unsigned int pref_time;
};
struct search_param {
time_t now; int iface;
};
static void send_ra(int iface, char *iface_name, struct in6_addr *dest);
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest);
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam);
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam);
int scope, int if_index, int flags,
int prefered, int valid, void *vparam);
static int add_lla(int index, unsigned int type, char *mac, size_t maclen, void *parm);
static int hop_limit;
static time_t ra_short_period_start;
void ra_init(time_t now)
{
@@ -62,7 +65,7 @@ void ra_init(time_t now)
expand_buf(&daemon->outpacket, sizeof(struct dhcp_packet));
/* See if we're guessing SLAAC addresses, if so we need to recieve ping replies */
for (context = daemon->ra_contexts; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
break;
@@ -94,18 +97,20 @@ void ra_start_unsolicted(time_t now, struct dhcp_context *context)
if it's not appropriate to advertise those contexts.
This gets re-called on a netlink route-change to re-do the advertisement
and pick up new interfaces */
if (context)
context->ra_time = now;
context->ra_short_period_start = context->ra_time = now;
else
for (context = daemon->ra_contexts; context; context = context->next)
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
/* re-do frequently for a minute or so, in case the first gets lost. */
ra_short_period_start = now;
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE))
{
context->ra_time = now + (rand16()/13000); /* range 0 - 5 */
/* re-do frequently for a minute or so, in case the first gets lost. */
context->ra_short_period_start = now;
}
}
void icmp6_packet(void)
void icmp6_packet(time_t now)
{
char interface[IF_NAMESIZE+1];
ssize_t sz;
@@ -149,7 +154,7 @@ void icmp6_packet(void)
if (!indextoname(daemon->icmp6fd, if_index, interface))
return;
if (!iface_check(AF_LOCAL, NULL, interface))
if (!iface_check(AF_LOCAL, NULL, interface, NULL))
return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
@@ -174,11 +179,11 @@ void icmp6_packet(void)
my_syslog(MS_DHCP | LOG_INFO, "RTR-SOLICIT(%s) %s", interface, mac);
/* source address may not be valid in solicit request. */
send_ra(if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
send_ra(now, if_index, interface, !IN6_IS_ADDR_UNSPECIFIED(&from.sin6_addr) ? &from.sin6_addr : NULL);
}
}
static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
static void send_ra(time_t now, int iface, char *iface_name, struct in6_addr *dest)
{
struct ra_packet *ra;
struct ra_param parm;
@@ -206,13 +211,15 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
parm.found_context = 0;
parm.if_name = iface_name;
parm.first = 1;
parm.now = now;
parm.pref_time = 0;
/* set tag with name == interface */
iface_id.net = iface_name;
iface_id.next = NULL;
parm.tags = &iface_id;
for (context = daemon->ra_contexts; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
{
context->flags &= ~CONTEXT_RA_DONE;
context->netid.next = &context->netid;
@@ -260,7 +267,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
/* zero means "self" */
for (i = 0; i < opt_cfg->len; i += IN6ADDRSZ, a++)
if (IN6_IS_ADDR_UNSPECIFIED(a))
put_opt6(&parm.link_local, IN6ADDRSZ);
put_opt6(&parm.link_global, IN6ADDRSZ);
else
put_opt6(a, IN6ADDRSZ);
}
@@ -288,7 +295,7 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
put_opt6_char(3);
put_opt6_short(0);
put_opt6_long(1800); /* lifetime - twice RA retransmit */
put_opt6(&parm.link_local, IN6ADDRSZ);
put_opt6(&parm.link_global, IN6ADDRSZ);
}
/* set managed bits unless we're providing only RA on this link */
@@ -320,19 +327,18 @@ static void send_ra(int iface, char *iface_name, struct in6_addr *dest)
}
static int add_prefixes(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
unsigned int preferred, unsigned int valid, void *vparam)
{
struct ra_param *param = vparam;
(void)scope; /* warning */
(void)dad;
if (if_index == param->ind)
{
if (IN6_IS_ADDR_LINKLOCAL(local))
param->link_local = *local;
else if (!IN6_IS_ADDR_LOOPBACK(local) &&
!IN6_IS_ADDR_LINKLOCAL(local) &&
!IN6_IS_ADDR_MULTICAST(local))
{
int do_prefix = 0;
@@ -341,8 +347,9 @@ static int add_prefixes(struct in6_addr *local, int prefix,
unsigned int time = 0xffffffff;
struct dhcp_context *context;
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
@@ -365,7 +372,7 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->managed = 1;
param->other = 1;
}
/* find floor time */
if (time > context->lease_time)
time = context->lease_time;
@@ -395,6 +402,25 @@ static int add_prefixes(struct in6_addr *local, int prefix,
param->first = 0;
param->found_context = 1;
}
/* configured time is ceiling */
if (valid > time)
valid = time;
if ((flags & IFACE_DEPRECATED) || deprecate)
preferred = 0;
else
{
/* configured time is ceiling */
if (preferred > time)
preferred = time;
}
if (preferred > param->pref_time)
{
param->pref_time = preferred;
param->link_global = *local;
}
if (do_prefix)
{
@@ -405,17 +431,13 @@ static int add_prefixes(struct in6_addr *local, int prefix,
/* zero net part of address */
setaddr6part(local, addr6part(local) & ~((prefix == 64) ? (u64)-1LL : (1LLU << (128 - prefix)) - 1LLU));
/* lifetimes must be min 2 hrs, by RFC 2462 */
if (time < 7200)
time = 7200;
opt->type = ICMP6_OPT_PREFIX;
opt->len = 4;
opt->prefix_len = prefix;
/* autonomous only if we're not doing dhcp, always set "on-link" */
opt->flags = do_slaac ? 0xC0 : 0x80;
opt->valid_lifetime = htonl(time);
opt->preferred_lifetime = htonl(deprecate ? 0 : time);
opt->valid_lifetime = htonl(valid);
opt->preferred_lifetime = htonl(preferred);
opt->reserved = 0;
opt->prefix = *local;
@@ -462,7 +484,7 @@ time_t periodic_ra(time_t now)
while (1)
{
/* find overdue events, and time of first future event */
for (next_event = 0, context = daemon->ra_contexts; context; context = context->next)
for (next_event = 0, context = daemon->dhcp6; context; context = context->next)
if (context->ra_time != 0)
{
if (difftime(context->ra_time, now) <= 0.0)
@@ -485,58 +507,62 @@ time_t periodic_ra(time_t now)
context->ra_time = 0;
else if (param.iface != 0 &&
indextoname(daemon->icmp6fd, param.iface, interface) &&
iface_check(AF_LOCAL, NULL, interface))
iface_check(AF_LOCAL, NULL, interface, NULL))
{
struct iname *tmp;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)
if (tmp->name && (strcmp(tmp->name, interface) == 0))
break;
if (!tmp)
send_ra(param.iface, interface, NULL);
send_ra(now, param.iface, interface, NULL);
}
}
return next_event;
}
static int iface_search(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
int scope, int if_index, int flags,
int preferred, int valid, void *vparam)
{
struct search_param *param = vparam;
struct dhcp_context *context;
(void)scope;
(void)dad;
(void)preferred;
(void)valid;
for (context = daemon->ra_contexts; context; context = context->next)
if (prefix == context->prefix &&
for (context = daemon->dhcp6; context; context = context->next)
if (!(context->flags & CONTEXT_TEMPLATE) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
if (context->ra_time != 0 && difftime(context->ra_time, param->now) <= 0.0)
{
/* found an interface that's overdue for RA determine new
timeout value and arrange for RA to be sent unless interface is
still doing DAD.*/
if (!dad)
param->iface = if_index;
if (difftime(param->now, ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = param->now + 5 + (rand16()/4400);
else
/* range 450 - 600 */
context->ra_time = param->now + 450 + (rand16()/440);
/* zero timers for other contexts on the same subnet, so they don't timeout
independently */
for (context = context->next; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
context->ra_time = 0;
return 0; /* found, abort */
}
is_same_net6(local, &context->end6, prefix) &&
context->ra_time != 0 &&
difftime(context->ra_time, param->now) <= 0.0)
{
/* found an interface that's overdue for RA determine new
timeout value and arrange for RA to be sent unless interface is
still doing DAD.*/
if (!(flags & IFACE_TENTATIVE))
param->iface = if_index;
if (difftime(param->now, context->ra_short_period_start) < 60.0)
/* range 5 - 20 */
context->ra_time = param->now + 5 + (rand16()/4400);
else
/* range 450 - 600 */
context->ra_time = param->now + 450 + (rand16()/440);
/* zero timers for other contexts on the same subnet, so they don't timeout
independently */
for (context = context->next; context; context = context->next)
if (prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
context->ra_time = 0;
return 0; /* found, abort */
}
return 1; /* keep searching */
}

View File

@@ -16,10 +16,6 @@
#include "dnsmasq.h"
static int add_resource_record(struct dns_header *header, char *limit, int *truncp,
unsigned int nameoffset, unsigned char **pp,
unsigned long ttl, unsigned int *offset, unsigned short type,
unsigned short class, char *format, ...);
#define CHECK_LEN(header, pp, plen, len) \
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen))
@@ -27,8 +23,8 @@ static int add_resource_record(struct dns_header *header, char *limit, int *trun
#define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
static int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes)
int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes)
{
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
unsigned int j, l, hops = 0;
@@ -173,7 +169,7 @@ static int extract_name(struct dns_header *header, size_t plen, unsigned char **
/* Max size of input string (for IPv6) is 75 chars.) */
#define MAXARPANAME 75
static int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
int in_arpa_name_2_addr(char *namein, struct all_addr *addrp)
{
int j;
char name[MAXARPANAME+1], *cp1;
@@ -333,7 +329,7 @@ static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header,
return ansp;
}
static unsigned char *skip_questions(struct dns_header *header, size_t plen)
unsigned char *skip_questions(struct dns_header *header, size_t plen)
{
int q;
unsigned char *ansp = (unsigned char *)(header+1);
@@ -1189,8 +1185,8 @@ int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
return 0;
}
static int add_resource_record(struct dns_header *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp,
unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
int add_resource_record(struct dns_header *header, char *limit, int *truncp, int nameoffset, unsigned char **pp,
unsigned long ttl, int *offset, unsigned short type, unsigned short class, char *format, ...)
{
va_list ap;
unsigned char *sav, *p = *pp;
@@ -1201,8 +1197,26 @@ static int add_resource_record(struct dns_header *header, char *limit, int *trun
if (truncp && *truncp)
return 0;
va_start(ap, format); /* make ap point to 1st unamed argument */
if (nameoffset > 0)
{
PUTSHORT(nameoffset | 0xc000, p);
}
else
{
char *name = va_arg(ap, char *);
if (name)
p = do_rfc1035_name(p, name);
if (nameoffset < 0)
{
PUTSHORT(-nameoffset | 0xc000, p);
}
else
*p++ = 0;
}
PUTSHORT(nameoffset | 0xc000, p);
PUTSHORT(type, p);
PUTSHORT(class, p);
PUTLONG(ttl, p); /* TTL */
@@ -1210,8 +1224,6 @@ static int add_resource_record(struct dns_header *header, char *limit, int *trun
sav = p; /* Save pointer to RDLength field */
PUTSHORT(0, p); /* Placeholder RDLength */
va_start(ap, format); /* make ap point to 1st unamed argument */
for (; *format; format++)
switch (*format)
{
@@ -1307,7 +1319,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
unsigned char *p, *ansp, *pheader;
int qtype, qclass;
struct all_addr addr;
unsigned int nameoffset;
int nameoffset;
unsigned short flag;
int q, ans, anscount = 0, addncount = 0;
int dryrun = 0, sec_reqd = 0;
@@ -1689,7 +1701,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
ans = found = 1;
if (!dryrun)
{
unsigned int offset;
int offset;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<MX>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_MX, C_IN, "sd", rec->weight, rec->target))
@@ -1727,7 +1739,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
found = ans = 1;
if (!dryrun)
{
unsigned int offset;
int offset;
log_query(F_CONFIG | F_RRNAME, name, NULL, "<SRV>");
if (add_resource_record(header, limit, &trunc, nameoffset, &ansp, daemon->local_ttl,
&offset, T_SRV, C_IN, "sssd",
@@ -1857,7 +1869,3 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
return ansp - (unsigned char *)header;
}

View File

@@ -20,7 +20,6 @@
#include <netinet/icmp6.h>
static int map_rebuild = 0;
static int ping_id = 0;
void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
@@ -38,7 +37,7 @@ void slaac_add_addrs(struct dhcp_lease *lease, time_t now, int force)
old = lease->slaac_address;
lease->slaac_address = NULL;
for (context = daemon->ra_contexts; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) && lease->last_interface == context->if_index)
{
struct in6_addr addr = context->start6;
@@ -123,7 +122,7 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
struct slaac_address *slaac;
time_t next_event = 0;
for (context = daemon->ra_contexts; context; context = context->next)
for (context = daemon->dhcp6; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME))
break;
@@ -134,12 +133,6 @@ time_t periodic_slaac(time_t now, struct dhcp_lease *leases)
while (ping_id == 0)
ping_id = rand16();
if (map_rebuild)
{
map_rebuild = 0;
build_subnet_map();
}
for (lease = leases; lease; lease = lease->next)
for (slaac = lease->slaac_address; slaac; slaac = slaac->next)
{
@@ -211,51 +204,4 @@ void slaac_ping_reply(struct in6_addr *sender, unsigned char *packet, char *inte
lease_update_dns(gotone);
}
/* Build a map from ra-names subnets to corresponding interfaces. This
is used to go from DHCPv4 leases to SLAAC addresses,
interface->IPv6-subnet, IPv6-subnet + MAC address -> SLAAC.
*/
static int add_subnet(struct in6_addr *local, int prefix,
int scope, int if_index, int dad, void *vparam)
{
struct dhcp_context *context;
(void)scope;
(void)dad;
(void)vparam;
for (context = daemon->ra_contexts; context; context = context->next)
if ((context->flags & CONTEXT_RA_NAME) &&
prefix == context->prefix &&
is_same_net6(local, &context->start6, prefix) &&
is_same_net6(local, &context->end6, prefix))
{
context->if_index = if_index;
context->local6 = *local;
}
return 1;
}
void build_subnet_map(void)
{
struct dhcp_context *context;
int ok = 0;
for (context = daemon->ra_contexts; context; context = context->next)
{
context->if_index = 0;
if ((context->flags & CONTEXT_RA_NAME))
ok = 1;
}
/* ra-names configured */
if (ok)
iface_enumerate(AF_INET6, NULL, add_subnet);
}
void schedule_subnet_map(void)
{
map_rebuild = 1;
}
#endif

View File

@@ -193,12 +193,12 @@ void tftp_request(struct listener *listen, time_t now)
#ifdef HAVE_IPV6
if (listen->family == AF_INET6)
{
if (!iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name))
if (!iface_check(AF_INET6, (struct all_addr *)&addr.in6.sin6_addr, name, NULL))
return;
}
else
#endif
if (!iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name))
if (!iface_check(AF_INET, (struct all_addr *)&addr.in.sin_addr, name, NULL))
return;
#ifdef HAVE_DHCP