Merge branch 'auth'

This commit is contained in:
Simon Kelley
2012-12-04 20:50:38 +00:00
15 changed files with 901 additions and 191 deletions

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 \ 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 \ 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 \ 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 \ hdrs = dnsmasq.h config.h dhcp-protocol.h dhcp6-protocol.h \
dns-protocol.h radv-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 \ netlink.c network.c option.c rfc1035.c \
rfc2131.c tftp.c util.c conntrack.c \ rfc2131.c tftp.c util.c conntrack.c \
dhcp6.c rfc3315.c dhcp-common.c outpacket.c \ dhcp6.c rfc3315.c dhcp-common.c outpacket.c \
radv.c slaac.c radv.c slaac.c auth.c
LOCAL_MODULE := dnsmasq LOCAL_MODULE := dnsmasq

499
src/auth.c Normal file
View File

@@ -0,0 +1,499 @@
/* 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"
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;
}
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now)
{
char *name = daemon->namebuff;
unsigned char *p, *ansp;
int qtype, qclass;
unsigned int nameoffset;
int q, anscount = 0, authcount = 0;
struct crec *crecp;
int auth = 1, trunc = 0, nxdomain = 1, soa = 0, ns = 0;
struct auth_zone *zone = NULL;
struct subnet *subnet = NULL;
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--)
{
size_t domainlen, namelen;
unsigned short flag = 0;
int found = 0;
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;
/* 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)
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;
}
domainlen = strlen(zone->domain);
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)
{
namelen = strlen(intr->name);
if (namelen >= domainlen && hostname_isequal(zone->domain, &intr->name[namelen - domainlen]) &&
(namelen == domainlen || intr->name[namelen - domainlen - 1] == '.'))
{
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))
{
namelen = strlen(name);
if (namelen > domainlen + 1 &&
name[namelen - domainlen - 1] != '.')
continue;
if (namelen < domainlen ||
!hostname_isequal(zone->domain, &name[namelen - domainlen]))
continue; /* wrong domain */
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:
namelen = strlen(name);
for (zone = daemon->auth_zones; zone; zone = zone->next)
{
domainlen = strlen(zone->domain);
if (namelen >= domainlen &&
hostname_isequal(zone->domain, &name[namelen - domainlen]) &&
(namelen == domainlen || name[namelen - domainlen - 1] == '.'))
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 (qtype == T_SOA && namelen == domainlen)
{
soa = 1; /* inhibits auth section */
found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<SOA>");
}
if (qtype == T_NS && namelen == domainlen)
{
ns = 1; /* inhibits auth section */
found = 1;
log_query(F_RRNAME | F_AUTH, zone->domain, NULL, "<NS>");
}
if (!option_bool(OPT_DHCP_FQDN) && namelen > domainlen + 1)
{
name[namelen - domainlen - 1] = 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)))
{
name[namelen - domainlen - 1] = '.'; /* restore domain part */
log_query(crecp->flags, name, &crecp->addr.addr, record_source(crecp->uid));
name[namelen - domainlen - 1] = 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)));
}
name[namelen - domainlen - 1] = '.'; /* 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)
{
if (!subnet)
name = zone->domain;
else
{
/* handle NS and SOA for PTR records */
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 */
if ((anscount != 0 || ns) &&
add_resource_record(header, limit, &trunc, 0, &ansp,
daemon->auth_ttl, NULL, T_NS, C_IN, "d", name, daemon->authserver))
{
if (ns)
anscount++;
else
authcount++;
}
if ((anscount == 0 || soa) &&
add_resource_record(header, limit, &trunc, 0, &ansp,
daemon->auth_ttl, NULL, T_SOA, C_IN, "ddlllll",
name, daemon->authserver, daemon->hostmaster,
daemon->soa_sn, daemon->soa_refresh,
daemon->soa_retry, daemon->soa_expiry,
daemon->auth_ttl))
{
if (soa)
anscount++;
else
authcount++;
}
}
/* 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);
return ansp - (unsigned char *)header;
}

View File

@@ -1248,14 +1248,14 @@ char *record_source(int index)
return "<unknown>"; return "<unknown>";
} }
void querystr(char *str, unsigned short type) void querystr(char *desc, char *str, unsigned short type)
{ {
unsigned int i; 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++) for (i = 0; i < (sizeof(typestr)/sizeof(typestr[0])); i++)
if (typestr[i].type == type) 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) void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
@@ -1316,6 +1316,8 @@ void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg)
source = arg; source = arg;
else if (flags & F_UPSTREAM) else if (flags & F_UPSTREAM)
source = "reply"; source = "reply";
else if (flags & F_AUTH)
source = "auth";
else if (flags & F_SERVER) else if (flags & F_SERVER)
{ {
source = "forwarded"; source = "forwarded";

View File

@@ -42,6 +42,10 @@
#define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */ #define EDNS0_OPTION_MAC 5 /* dyndns.org temporary assignment */
#define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */ #define DNSMASQ_SERVICE "uk.org.thekelleys.dnsmasq" /* Default - may be overridden by config */
#define DNSMASQ_PATH "/uk/org/thekelleys/dnsmasq" #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. /* compile-time options: uncomment below to enable or do eg.
make COPTS=-DHAVE_BROKEN_RTC make COPTS=-DHAVE_BROKEN_RTC

View File

@@ -366,7 +366,7 @@ static int join_multicast_worker(struct in6_addr *local, int prefix,
close(fd); close(fd);
/* Are we doing DHCP on this interface? */ /* Are we doing DHCP on this interface? */
if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name)) if (!iface_check(AF_INET6, (struct all_addr *)local, ifrn_name, NULL))
return 1; return 1;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)

View File

@@ -262,7 +262,7 @@ void dhcp_packet(time_t now, int pxe_fd)
parm.current = NULL; parm.current = NULL;
parm.ind = iface_index; 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 /* If we failed to match the primary address of the interface, see if we've got a --listen-address
for a secondary */ for a secondary */

View File

@@ -84,6 +84,7 @@ int main (int argc, char **argv)
daemon->addrbuff = safe_malloc(ADDRSTRLEN); daemon->addrbuff = safe_malloc(ADDRSTRLEN);
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
if (!daemon->lease_file) if (!daemon->lease_file)
{ {
@@ -151,6 +152,14 @@ int main (int argc, char **argv)
now = dnsmasq_time(); 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 #ifdef HAVE_DHCP
if (daemon->dhcp || daemon->dhcp6) if (daemon->dhcp || daemon->dhcp6)
{ {
@@ -1440,11 +1449,18 @@ static void check_dns_listeners(fd_set *set, time_t now)
struct server *s; struct server *s;
int flags; int flags;
struct in_addr netmask; struct in_addr netmask;
int auth_dns;
if (iface) if (iface)
netmask = iface->netmask; {
netmask = iface->netmask;
auth_dns = iface->dns_auth;
}
else else
netmask.s_addr = 0; {
netmask.s_addr = 0;
auth_dns = 0;
}
#ifndef NO_FORK #ifndef NO_FORK
/* Arrange for SIGALARM after CHILD_LIFETIME seconds to /* Arrange for SIGALARM after CHILD_LIFETIME seconds to
@@ -1463,7 +1479,7 @@ static void check_dns_listeners(fd_set *set, time_t now)
if ((flags = fcntl(confd, F_GETFL, 0)) != -1) if ((flags = fcntl(confd, F_GETFL, 0)) != -1)
fcntl(confd, F_SETFL, flags & ~O_NONBLOCK); fcntl(confd, F_SETFL, flags & ~O_NONBLOCK);
buff = tcp_request(confd, now, &tcp_addr, netmask); buff = tcp_request(confd, now, &tcp_addr, netmask, auth_dns);
shutdown(confd, SHUT_RDWR); shutdown(confd, SHUT_RDWR);
close(confd); close(confd);

View File

@@ -278,6 +278,20 @@ struct cname {
struct cname *next; 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 host_record {
struct name_list { struct name_list {
char *name; char *name;
@@ -357,6 +371,8 @@ struct crec {
#define F_SERVER (1u<<18) #define F_SERVER (1u<<18)
#define F_QUERY (1u<<19) #define F_QUERY (1u<<19)
#define F_NOERR (1u<<20) #define F_NOERR (1u<<20)
#define F_AUTH (1u<<21)
/* composites */ /* composites */
#define F_TYPE (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS) /* Only one may be set */ #define F_TYPE (F_IPV4 | F_IPV6 | F_DNSKEY | F_DS) /* Only one may be set */
@@ -412,7 +428,7 @@ struct server {
struct irec { struct irec {
union mysockaddr addr; union mysockaddr addr;
struct in_addr netmask; /* only valid for IPv4 */ struct in_addr netmask; /* only valid for IPv4 */
int tftp_ok, dhcp_ok, mtu, done, dad; int tftp_ok, dhcp_ok, mtu, done, dad, dns_auth;
char *name; char *name;
struct irec *next; struct irec *next;
}; };
@@ -733,11 +749,13 @@ extern struct daemon {
struct ptr_record *ptr; struct ptr_record *ptr;
struct host_record *host_records, *host_records_tail; struct host_record *host_records, *host_records_tail;
struct cname *cnames; struct cname *cnames;
struct auth_zone *auth_zones;
struct interface_name *int_names; struct interface_name *int_names;
char *mxtarget; char *mxtarget;
char *lease_file; char *lease_file;
char *username, *groupname, *scriptuser; char *username, *groupname, *scriptuser;
char *luascript; char *luascript;
char *authserver, *authinterface, *hostmaster;
int group_set, osport; int group_set, osport;
char *domain_suffix; char *domain_suffix;
struct cond_domain *cond_domain; struct cond_domain *cond_domain;
@@ -751,7 +769,7 @@ extern struct daemon {
int max_logs; /* queue limit */ int max_logs; /* queue limit */
int cachesize, ftabsize; int cachesize, ftabsize;
int port, query_port, min_port; 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 hostsfile *addn_hosts;
struct dhcp_context *dhcp, *dhcp6, *ra_contexts; struct dhcp_context *dhcp, *dhcp6, *ra_contexts;
struct dhcp_config *dhcp_conf; struct dhcp_config *dhcp_conf;
@@ -778,6 +796,7 @@ extern struct daemon {
unsigned int duid_enterprise, duid_config_len; unsigned int duid_enterprise, duid_config_len;
unsigned char *duid_config; unsigned char *duid_config;
char *dbus_name; char *dbus_name;
unsigned long soa_sn, soa_refresh, soa_retry, soa_expiry;
/* globally used stuff for DNS */ /* globally used stuff for DNS */
char *packet; /* packet buffer */ char *packet; /* packet buffer */
@@ -835,7 +854,7 @@ extern struct daemon {
void cache_init(void); void cache_init(void);
void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg); void log_query(unsigned int flags, char *name, struct all_addr *addr, char *arg);
char *record_source(int index); 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 crec *cache_find_by_addr(struct crec *crecp,
struct all_addr *addr, time_t now, struct all_addr *addr, time_t now,
unsigned short prot); unsigned short prot);
@@ -879,6 +898,16 @@ unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
size_t resize_packet(struct dns_header *header, size_t plen, size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen); unsigned char *pheader, size_t hlen);
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3); 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,
unsigned int nameoffset, unsigned char **pp, unsigned long ttl,
unsigned 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 */
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now);
/* util.c */ /* util.c */
void rand_init(void); void rand_init(void);
@@ -935,7 +964,7 @@ char *parse_server(char *arg, union mysockaddr *addr,
void reply_query(int fd, int family, time_t now); void reply_query(int fd, int family, time_t now);
void receive_query(struct listener *listen, time_t now); void receive_query(struct listener *listen, time_t now);
unsigned char *tcp_request(int confd, 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); void server_gone(struct server *server);
struct frec *get_new_frec(time_t now, int *wait); struct frec *get_new_frec(time_t now, int *wait);
int send_from(int fd, int nowild, char *packet, size_t len, int send_from(int fd, int nowild, char *packet, size_t len,
@@ -953,7 +982,7 @@ int enumerate_interfaces();
void create_wildcard_listeners(void); void create_wildcard_listeners(void);
void create_bound_listeners(int die); void create_bound_listeners(int die);
int is_dad_listeners(void); 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); int fix_fd(int fd);
struct in_addr get_ifaddr(char *intr); struct in_addr get_ifaddr(char *intr);
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6

View File

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

View File

@@ -107,7 +107,7 @@ int indextoname(int fd, int index, char *name)
#endif #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; struct iname *tmp;
int ret = 1; int ret = 1;
@@ -115,6 +115,17 @@ 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 /* Note: have to check all and not bail out early, so that we set the
"used" flags. */ "used" flags. */
if (auth)
{
if (daemon->authinterface && strcmp(daemon->authinterface, name) == 0)
{
*auth = 1;
return 1;
}
else
*auth = 0;
}
if (daemon->if_names || daemon->if_addrs) if (daemon->if_names || daemon->if_addrs)
{ {
ret = 0; ret = 0;
@@ -153,6 +164,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
struct ifreq ifr; struct ifreq ifr;
int tftp_ok = !!option_bool(OPT_TFTP); int tftp_ok = !!option_bool(OPT_TFTP);
int dhcp_ok = 1; int dhcp_ok = 1;
int auth_dns = 0;
#ifdef HAVE_DHCP #ifdef HAVE_DHCP
struct iname *tmp; struct iname *tmp;
#endif #endif
@@ -210,24 +222,30 @@ static int iface_allowed(struct irec **irecp, int if_index,
} }
if (addr->sa.sa_family == AF_INET && 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; 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 #ifdef HAVE_IPV6
if (addr->sa.sa_family == AF_INET6 && 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; return 1;
#endif #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 */ /* add to list */
if ((iface = whine_malloc(sizeof(struct irec)))) if ((iface = whine_malloc(sizeof(struct irec))))
@@ -236,6 +254,7 @@ static int iface_allowed(struct irec **irecp, int if_index,
iface->netmask = netmask; iface->netmask = netmask;
iface->tftp_ok = tftp_ok; iface->tftp_ok = tftp_ok;
iface->dhcp_ok = dhcp_ok; iface->dhcp_ok = dhcp_ok;
iface->dns_auth = auth_dns;
iface->mtu = mtu; iface->mtu = mtu;
iface->dad = dad; iface->dad = dad;
iface->done = 0; iface->done = 0;

View File

@@ -121,6 +121,10 @@ struct myoption {
#define LOPT_RR 310 #define LOPT_RR 310
#define LOPT_CLVERBIND 311 #define LOPT_CLVERBIND 311
#define LOPT_MAXCTTL 312 #define LOPT_MAXCTTL 312
#define LOPT_AUTHZONE 313
#define LOPT_AUTHSERV 314
#define LOPT_AUTHTTL 315
#define LOPT_AUTHSOA 316
#ifdef HAVE_GETOPT_LONG #ifdef HAVE_GETOPT_LONG
static const struct option opts[] = static const struct option opts[] =
@@ -247,6 +251,10 @@ static const struct myoption opts[] =
{ "dhcp-duid", 1, 0, LOPT_DUID }, { "dhcp-duid", 1, 0, LOPT_DUID },
{ "host-record", 1, 0, LOPT_HOST_REC }, { "host-record", 1, 0, LOPT_HOST_REC },
{ "bind-dynamic", 0, 0, LOPT_CLVERBIND }, { "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 },
{ NULL, 0, 0, 0 } { NULL, 0, 0, 0 }
}; };
@@ -378,7 +386,11 @@ static struct {
{ LOPT_DUID, ARG_ONE, "<enterprise>,<duid>", gettext_noop("Specify DUID_EN-type DHCPv6 server DUID"), NULL }, { 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_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_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 },
{ 0, 0, NULL, NULL, NULL } { 0, 0, NULL, NULL, NULL }
}; };
@@ -1521,6 +1533,99 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
break; break;
} }
case LOPT_AUTHSERV: /* --auth-server */
if (!(comma = split(arg)))
ret_err(gen_err);
daemon->authserver = opt_string_alloc(arg);
daemon->authinterface = opt_string_alloc(comma);
break;
case LOPT_AUTHZONE: /* --auth-zone */
{
struct auth_zone *new;
comma = split(arg);
if (!comma)
ret_err(gen_err);
new = safe_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 = safe_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 */ case 's': /* --domain */
if (strcmp (arg, "#") == 0) if (strcmp (arg, "#") == 0)
set_option_bool(OPT_RESOLV_DOMAIN); set_option_bool(OPT_RESOLV_DOMAIN);
@@ -1933,6 +2038,7 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
case LOPT_NEGTTL: /* --neg-ttl */ case LOPT_NEGTTL: /* --neg-ttl */
case LOPT_MAXTTL: /* --max-ttl */ case LOPT_MAXTTL: /* --max-ttl */
case LOPT_MAXCTTL: /* --max-cache-ttl */ case LOPT_MAXCTTL: /* --max-cache-ttl */
case LOPT_AUTHTTL: /* --auth-ttl */
{ {
int ttl; int ttl;
if (!atoi_check(arg, &ttl)) if (!atoi_check(arg, &ttl))
@@ -1943,6 +2049,8 @@ static int one_opt(int option, char *arg, char *errstr, char *gen_err, int comma
daemon->max_ttl = (unsigned long)ttl; daemon->max_ttl = (unsigned long)ttl;
else if (option == LOPT_MAXCTTL) else if (option == LOPT_MAXCTTL)
daemon->max_cache_ttl = (unsigned long)ttl; daemon->max_cache_ttl = (unsigned long)ttl;
else if (option == LOPT_AUTHTTL)
daemon->auth_ttl = (unsigned long)ttl;
else else
daemon->local_ttl = (unsigned long)ttl; daemon->local_ttl = (unsigned long)ttl;
break; break;
@@ -3613,6 +3721,10 @@ void read_opts(int argc, char **argv, char *compile_opts)
daemon->tftp_max = TFTP_MAX_CONNECTIONS; daemon->tftp_max = TFTP_MAX_CONNECTIONS;
daemon->edns_pktsz = EDNS_PKTSZ; daemon->edns_pktsz = EDNS_PKTSZ;
daemon->log_fac = -1; 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("version.bind", "dnsmasq-" VERSION );
add_txt("authors.bind", "Simon Kelley"); add_txt("authors.bind", "Simon Kelley");
add_txt("copyright.bind", COPYRIGHT); add_txt("copyright.bind", COPYRIGHT);
@@ -3721,6 +3833,14 @@ void read_opts(int argc, char **argv, char *compile_opts)
#endif /* IPv6 */ #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 */ /* only one of these need be specified: the other defaults to the host-name */
if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget) if (option_bool(OPT_LOCALMX) || daemon->mxnames || daemon->mxtarget)
{ {

View File

@@ -149,7 +149,7 @@ void icmp6_packet(void)
if (!indextoname(daemon->icmp6fd, if_index, interface)) if (!indextoname(daemon->icmp6fd, if_index, interface))
return; return;
if (!iface_check(AF_LOCAL, NULL, interface)) if (!iface_check(AF_LOCAL, NULL, interface, NULL))
return; return;
for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next) for (tmp = daemon->dhcp_except; tmp; tmp = tmp->next)

View File

@@ -16,10 +16,6 @@
#include "dnsmasq.h" #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) \ #define CHECK_LEN(header, pp, plen, len) \
((size_t)((pp) - (unsigned char *)(header) + (len)) <= (plen)) ((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) \ #define ADD_RDLEN(header, pp, plen, len) \
(!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1)) (!CHECK_LEN(header, pp, plen, len) ? 0 : (((pp) += (len)), 1))
static int extract_name(struct dns_header *header, size_t plen, unsigned char **pp, int extract_name(struct dns_header *header, size_t plen, unsigned char **pp,
char *name, int isExtract, int extrabytes) char *name, int isExtract, int extrabytes)
{ {
unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL; unsigned char *cp = (unsigned char *)name, *p = *pp, *p1 = NULL;
unsigned int j, l, hops = 0; 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.) */ /* Max size of input string (for IPv6) is 75 chars.) */
#define MAXARPANAME 75 #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; int j;
char name[MAXARPANAME+1], *cp1; char name[MAXARPANAME+1], *cp1;
@@ -333,7 +329,7 @@ static unsigned char *skip_name(unsigned char *ansp, struct dns_header *header,
return ansp; 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; int q;
unsigned char *ansp = (unsigned char *)(header+1); 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; return 0;
} }
static int add_resource_record(struct dns_header *header, char *limit, int *truncp, unsigned int nameoffset, unsigned char **pp, 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, ...) unsigned long ttl, unsigned int *offset, unsigned short type, unsigned short class, char *format, ...)
{ {
va_list ap; va_list ap;
unsigned char *sav, *p = *pp; unsigned char *sav, *p = *pp;
@@ -1202,7 +1198,18 @@ static int add_resource_record(struct dns_header *header, char *limit, int *trun
if (truncp && *truncp) if (truncp && *truncp)
return 0; return 0;
PUTSHORT(nameoffset | 0xc000, p); va_start(ap, format); /* make ap point to 1st unamed argument */
if (nameoffset != 0)
{
PUTSHORT(nameoffset | 0xc000, p);
}
else
{
p = do_rfc1035_name(p, va_arg(ap, char *));
*p++ = 0;
}
PUTSHORT(type, p); PUTSHORT(type, p);
PUTSHORT(class, p); PUTSHORT(class, p);
PUTLONG(ttl, p); /* TTL */ PUTLONG(ttl, p); /* TTL */
@@ -1210,8 +1217,6 @@ static int add_resource_record(struct dns_header *header, char *limit, int *trun
sav = p; /* Save pointer to RDLength field */ sav = p; /* Save pointer to RDLength field */
PUTSHORT(0, p); /* Placeholder RDLength */ PUTSHORT(0, p); /* Placeholder RDLength */
va_start(ap, format); /* make ap point to 1st unamed argument */
for (; *format; format++) for (; *format; format++)
switch (*format) switch (*format)
{ {
@@ -1857,7 +1862,3 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
return ansp - (unsigned char *)header; return ansp - (unsigned char *)header;
} }

View File

@@ -193,12 +193,12 @@ void tftp_request(struct listener *listen, time_t now)
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
if (listen->family == AF_INET6) 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; return;
} }
else else
#endif #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; return;
#ifdef HAVE_DHCP #ifdef HAVE_DHCP