Commit 367341f7 authored by Simon Kelley's avatar Simon Kelley

Disable DNSSEC for server=/domain/.. servers unless trust-anchor provided.

parent eddf3652
...@@ -477,6 +477,7 @@ union mysockaddr { ...@@ -477,6 +477,7 @@ union mysockaddr {
#define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */ #define SERV_NO_REBIND 2048 /* inhibit dns-rebind protection */
#define SERV_FROM_FILE 4096 /* read from --servers-file */ #define SERV_FROM_FILE 4096 /* read from --servers-file */
#define SERV_LOOP 8192 /* server causes forwarding loop */ #define SERV_LOOP 8192 /* server causes forwarding loop */
#define SERV_DO_DNSSEC 16384 /* Validate DNSSEC when using this server */
struct serverfd { struct serverfd {
int fd; int fd;
......
...@@ -1892,7 +1892,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now) ...@@ -1892,7 +1892,7 @@ static int zone_status(char *name, int class, char *keyname, time_t now)
break; break;
} }
} }
/* Now work away from the trust anchor */ /* Now work away from the trust anchor */
while (1) while (1)
{ {
......
...@@ -106,8 +106,8 @@ int send_from(int fd, int nowild, char *packet, size_t len, ...@@ -106,8 +106,8 @@ int send_from(int fd, int nowild, char *packet, size_t len,
return 1; return 1;
} }
static unsigned int search_servers(time_t now, struct all_addr **addrpp, static unsigned int search_servers(time_t now, struct all_addr **addrpp, unsigned int qtype,
unsigned int qtype, char *qdomain, int *type, char **domain, int *norebind) char *qdomain, int *type, char **domain, int *norebind)
{ {
/* If the query ends in the domain in one of our servers, set /* If the query ends in the domain in one of our servers, set
...@@ -175,7 +175,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp, ...@@ -175,7 +175,7 @@ static unsigned int search_servers(time_t now, struct all_addr **addrpp,
if (domainlen >= matchlen) if (domainlen >= matchlen)
{ {
*type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND); *type = serv->flags & (SERV_HAS_DOMAIN | SERV_USE_RESOLV | SERV_NO_REBIND | SERV_DO_DNSSEC);
*domain = serv->domain; *domain = serv->domain;
matchlen = domainlen; matchlen = domainlen;
if (serv->flags & SERV_NO_ADDR) if (serv->flags & SERV_NO_ADDR)
...@@ -233,12 +233,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -233,12 +233,13 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
struct frec *forward, int ad_reqd, int do_bit) struct frec *forward, int ad_reqd, int do_bit)
{ {
char *domain = NULL; char *domain = NULL;
int type = 0, norebind = 0; int type = SERV_DO_DNSSEC, norebind = 0;
struct all_addr *addrp = NULL; struct all_addr *addrp = NULL;
unsigned int flags = 0; unsigned int flags = 0;
struct server *start = NULL; struct server *start = NULL;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
void *hash = hash_questions(header, plen, daemon->namebuff); void *hash = hash_questions(header, plen, daemon->namebuff);
int do_dnssec = 0;
#else #else
unsigned int crc = questions_crc(header, plen, daemon->namebuff); unsigned int crc = questions_crc(header, plen, daemon->namebuff);
void *hash = &crc; void *hash = &crc;
...@@ -315,6 +316,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -315,6 +316,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
daemon->last_server = NULL; daemon->last_server = NULL;
} }
type = forward->sentto->flags & SERV_TYPE; type = forward->sentto->flags & SERV_TYPE;
#ifdef HAVE_DNSSEC
do_dnssec = forward->sentto->flags & SERV_DO_DNSSEC;
#endif
if (!(start = forward->sentto->next)) if (!(start = forward->sentto->next))
start = daemon->servers; /* at end of list, recycle */ start = daemon->servers; /* at end of list, recycle */
header->id = htons(forward->new_id); header->id = htons(forward->new_id);
...@@ -324,6 +329,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -324,6 +329,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
if (gotname) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
#ifdef HAVE_DNSSEC
do_dnssec = type & SERV_DO_DNSSEC;
type &= ~SERV_DO_DNSSEC;
#endif
if (!flags && !(forward = get_new_frec(now, NULL, 0))) if (!flags && !(forward = get_new_frec(now, NULL, 0)))
/* table full - server failure. */ /* table full - server failure. */
flags = F_NEG; flags = F_NEG;
...@@ -406,7 +416,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr, ...@@ -406,7 +416,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
} }
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !(type & SERV_HAS_DOMAIN)) if (option_bool(OPT_DNSSEC_VALID) && do_dnssec)
{ {
size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ); size_t new = add_do_bit(header, plen, ((unsigned char *) header) + PACKETSZ);
...@@ -858,7 +868,7 @@ void reply_query(int fd, int family, time_t now) ...@@ -858,7 +868,7 @@ void reply_query(int fd, int family, time_t now)
no_cache_dnssec = 1; no_cache_dnssec = 1;
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (server && !(server->flags & SERV_HAS_DOMAIN) && if (server && (server->flags & SERV_DO_DNSSEC) &&
option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED)) option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
{ {
int status = 0; int status = 0;
...@@ -1640,6 +1650,10 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -1640,6 +1650,10 @@ unsigned char *tcp_request(int confd, time_t now,
if (gotname) if (gotname)
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind); flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
#ifdef HAVE_DNSSEC
type &= ~SERV_DO_DNSSEC;
#endif
if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server) if (type != 0 || option_bool(OPT_ORDER) || !daemon->last_server)
last_server = daemon->servers; last_server = daemon->servers;
else else
...@@ -1711,7 +1725,7 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -1711,7 +1725,7 @@ unsigned char *tcp_request(int confd, time_t now,
} }
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID)) if (option_bool(OPT_DNSSEC_VALID) && (last_server->flags & SERV_DO_DNSSEC))
{ {
new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536); new_size = add_do_bit(header, size, ((unsigned char *) header) + 65536);
...@@ -1757,7 +1771,7 @@ unsigned char *tcp_request(int confd, time_t now, ...@@ -1757,7 +1771,7 @@ unsigned char *tcp_request(int confd, time_t now,
#endif #endif
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled) if (option_bool(OPT_DNSSEC_VALID) && !checking_disabled && (last_server->flags & SERV_DO_DNSSEC))
{ {
int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */ int keycount = DNSSEC_WORK; /* Limit to number of DNSSEC questions, to catch loops and avoid filling cache. */
int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount); int status = tcp_key_recurse(now, STAT_OK, header, m, 0, daemon->namebuff, daemon->keyname, last_server, &keycount);
......
...@@ -1430,12 +1430,38 @@ void check_servers(void) ...@@ -1430,12 +1430,38 @@ void check_servers(void)
if (!option_bool(OPT_NOWILD)) if (!option_bool(OPT_NOWILD))
enumerate_interfaces(0); enumerate_interfaces(0);
#ifdef HAVE_DNSSEC
/* Disable DNSSEC validation when using server=/domain/.... servers
unless there's a configured trust anchor. */
for (serv = daemon->servers; serv; serv = serv->next)
serv->flags |= SERV_DO_DNSSEC;
#endif
for (serv = daemon->servers; serv; serv = serv->next) for (serv = daemon->servers; serv; serv = serv->next)
{ {
if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND))) if (!(serv->flags & (SERV_LITERAL_ADDRESS | SERV_NO_ADDR | SERV_USE_RESOLV | SERV_NO_REBIND)))
{ {
port = prettyprint_addr(&serv->addr, daemon->namebuff); #ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && (serv->flags & SERV_HAS_DOMAIN))
{
struct ds_config *ds;
char *domain = serv->domain;
/* .example.com is valid */
while (*domain == '.')
domain++;
for (ds = daemon->ds; ds; ds = ds->next)
if (ds->name[0] != 0 && hostname_isequal(domain, ds->name))
break;
if (!ds)
serv->flags &= ~SERV_DO_DNSSEC;
}
#endif
port = prettyprint_addr(&serv->addr, daemon->namebuff);
/* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */ /* 0.0.0.0 is nothing, the stack treats it like 127.0.0.1 */
if (serv->addr.sa.sa_family == AF_INET && if (serv->addr.sa.sa_family == AF_INET &&
serv->addr.in.sin_addr.s_addr == 0) serv->addr.in.sin_addr.s_addr == 0)
...@@ -1471,7 +1497,11 @@ void check_servers(void) ...@@ -1471,7 +1497,11 @@ void check_servers(void)
{ {
if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV)) if (serv->flags & (SERV_HAS_DOMAIN | SERV_FOR_NODOTS | SERV_USE_RESOLV))
{ {
char *s1, *s2; char *s1, *s2, *s3 = "";
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !(serv->flags & SERV_DO_DNSSEC))
s3 = _("(no DNSSEC)");
#endif
if (!(serv->flags & SERV_HAS_DOMAIN)) if (!(serv->flags & SERV_HAS_DOMAIN))
s1 = _("unqualified"), s2 = _("names"); s1 = _("unqualified"), s2 = _("names");
else if (strlen(serv->domain) == 0) else if (strlen(serv->domain) == 0)
...@@ -1484,7 +1514,7 @@ void check_servers(void) ...@@ -1484,7 +1514,7 @@ void check_servers(void)
else if (serv->flags & SERV_USE_RESOLV) else if (serv->flags & SERV_USE_RESOLV)
my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2); my_syslog(LOG_INFO, _("using standard nameservers for %s %s"), s1, s2);
else else
my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s"), daemon->namebuff, port, s1, s2); my_syslog(LOG_INFO, _("using nameserver %s#%d for %s %s %s"), daemon->namebuff, port, s1, s2, s3);
} }
#ifdef HAVE_LOOP #ifdef HAVE_LOOP
else if (serv->flags & SERV_LOOP) else if (serv->flags & SERV_LOOP)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment