mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 10:18:25 +00:00
Merge branch 'extended-error'
This commit is contained in:
54
src/cache.c
54
src/cache.c
@@ -1861,10 +1861,44 @@ char *querystr(char *desc, unsigned short type)
|
||||
return buff ? buff : "";
|
||||
}
|
||||
|
||||
static char *edestr(int ede)
|
||||
{
|
||||
switch (ede)
|
||||
{
|
||||
case EDE_OTHER: return "other";
|
||||
case EDE_USUPDNSKEY: return "unsupported DNSKEY algorithm";
|
||||
case EDE_USUPDS: return "unsupported DS digest";
|
||||
case EDE_STALE: return "stale answer";
|
||||
case EDE_FORGED: return "forged";
|
||||
case EDE_DNSSEC_IND: return "DNSSEC indeterminate";
|
||||
case EDE_DNSSEC_BOGUS: return "DNSSEC bogus";
|
||||
case EDE_SIG_EXP: return "DNSSEC signature expired";
|
||||
case EDE_SIG_NYV: return "DNSSEC sig not yet valid";
|
||||
case EDE_NO_DNSKEY: return "DNSKEY missing";
|
||||
case EDE_NO_RRSIG: return "RRSIG missing";
|
||||
case EDE_NO_ZONEKEY: return "no zone key bit set";
|
||||
case EDE_NO_NSEC: return "NSEC(3) missing";
|
||||
case EDE_CACHED_ERR: return "cached error";
|
||||
case EDE_NOT_READY: return "not ready";
|
||||
case EDE_BLOCKED: return "blocked";
|
||||
case EDE_CENSORED: return "censored";
|
||||
case EDE_FILTERED: return "filtered";
|
||||
case EDE_PROHIBITED: return "prohibited";
|
||||
case EDE_STALE_NXD: return "stale NXDOMAIN";
|
||||
case EDE_NOT_AUTH: return "not authoritative";
|
||||
case EDE_NOT_SUP: return "not supported";
|
||||
case EDE_NO_AUTH: return "no reachable authority";
|
||||
case EDE_NETERR: return "network error";
|
||||
case EDE_INVALID_DATA: return "invalid data";
|
||||
default: return "unknown";
|
||||
}
|
||||
}
|
||||
|
||||
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
{
|
||||
char *source, *dest = daemon->addrbuff;
|
||||
char *verb = "is";
|
||||
char *extra = "";
|
||||
|
||||
if (!option_bool(OPT_LOG))
|
||||
return;
|
||||
@@ -1887,6 +1921,12 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
dest = "not implemented";
|
||||
else
|
||||
sprintf(daemon->addrbuff, "%u", rcode);
|
||||
|
||||
if (addr->log.ede != -1)
|
||||
{
|
||||
extra = daemon->addrbuff;
|
||||
sprintf(extra, " (EDE:%s)", edestr(addr->log.ede));
|
||||
}
|
||||
}
|
||||
else
|
||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
||||
@@ -1932,7 +1972,15 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
else if (flags & F_UPSTREAM)
|
||||
source = "reply";
|
||||
else if (flags & F_SECSTAT)
|
||||
source = "validation";
|
||||
{
|
||||
if (addr && addr->log.ede != -1)
|
||||
{
|
||||
extra = daemon->addrbuff;
|
||||
sprintf(extra, " (EDE:%s)", edestr(addr->log.ede));
|
||||
}
|
||||
source = "validation";
|
||||
dest = arg;
|
||||
}
|
||||
else if (flags & F_AUTH)
|
||||
source = "auth";
|
||||
else if (flags & F_SERVER)
|
||||
@@ -1966,11 +2014,11 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||
if (option_bool(OPT_EXTRALOG))
|
||||
{
|
||||
if (flags & F_NOEXTRA)
|
||||
my_syslog(LOG_INFO, "%u %s %s %s %s", daemon->log_display_id, source, name, verb, dest);
|
||||
my_syslog(LOG_INFO, "%u %s %s %s %s%s", daemon->log_display_id, source, name, verb, dest, extra);
|
||||
else
|
||||
{
|
||||
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
|
||||
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest);
|
||||
my_syslog(LOG_INFO, "%u %s/%u %s %s %s %s%s", daemon->log_display_id, daemon->addrbuff2, port, source, name, verb, dest, extra);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
@@ -80,10 +80,41 @@
|
||||
|
||||
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
|
||||
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
|
||||
#define EDNS0_OPTION_EDE 15 /* IANA - RFC 8914 */
|
||||
#define EDNS0_OPTION_NOMDEVICEID 65073 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
||||
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella temporary assignment */
|
||||
|
||||
/* RFC-8914 extended errors */
|
||||
#define EDE_OTHER 0 /* Other */
|
||||
#define EDE_USUPDNSKEY 1 /* Unsupported DNSKEY algo */
|
||||
#define EDE_USUPDS 2 /* Unsupported DS Digest */
|
||||
#define EDE_STALE 3 /* Stale answer */
|
||||
#define EDE_FORGED 4 /* Forged answer */
|
||||
#define EDE_DNSSEC_IND 5 /* DNSSEC Indeterminate */
|
||||
#define EDE_DNSSEC_BOGUS 6 /* DNSSEC Bogus */
|
||||
#define EDE_SIG_EXP 7 /* Signature Expired */
|
||||
#define EDE_SIG_NYV 8 /* Signature Not Yet Valid */
|
||||
#define EDE_NO_DNSKEY 9 /* DNSKEY missing */
|
||||
#define EDE_NO_RRSIG 10 /* RRSIGs missing */
|
||||
#define EDE_NO_ZONEKEY 11 /* No Zone Key Bit Set */
|
||||
#define EDE_NO_NSEC 12 /* NSEC Missing */
|
||||
#define EDE_CACHED_ERR 13 /* Cached Error */
|
||||
#define EDE_NOT_READY 14 /* Not Ready */
|
||||
#define EDE_BLOCKED 15 /* Blocked */
|
||||
#define EDE_CENSORED 16 /* Censored */
|
||||
#define EDE_FILTERED 17 /* Filtered */
|
||||
#define EDE_PROHIBITED 18 /* Prohibited */
|
||||
#define EDE_STALE_NXD 19 /* Stale NXDOMAIN */
|
||||
#define EDE_NOT_AUTH 20 /* Not Authoritative */
|
||||
#define EDE_NOT_SUP 21 /* Not Supported */
|
||||
#define EDE_NO_AUTH 22 /* No Reachable Authority */
|
||||
#define EDE_NETERR 23 /* Network error */
|
||||
#define EDE_INVALID_DATA 24 /* Invalid Data */
|
||||
|
||||
|
||||
|
||||
|
||||
struct dns_header {
|
||||
u16 id;
|
||||
u8 hb3,hb4;
|
||||
|
||||
@@ -323,6 +323,7 @@ union all_addr {
|
||||
/* for log_query */
|
||||
struct {
|
||||
unsigned short keytag, algo, digest, rcode;
|
||||
int ede;
|
||||
} log;
|
||||
};
|
||||
|
||||
@@ -686,17 +687,28 @@ struct hostsfile {
|
||||
#define DUMP_BOGUS 0x0040
|
||||
#define DUMP_SEC_BOGUS 0x0080
|
||||
|
||||
|
||||
/* DNSSEC status values. */
|
||||
#define STAT_SECURE 1
|
||||
#define STAT_INSECURE 2
|
||||
#define STAT_BOGUS 3
|
||||
#define STAT_NEED_DS 4
|
||||
#define STAT_NEED_KEY 5
|
||||
#define STAT_TRUNCATED 6
|
||||
#define STAT_SECURE_WILDCARD 7
|
||||
#define STAT_OK 8
|
||||
#define STAT_ABANDONED 9
|
||||
#define STAT_SECURE 0x10000
|
||||
#define STAT_INSECURE 0x20000
|
||||
#define STAT_BOGUS 0x30000
|
||||
#define STAT_NEED_DS 0x40000
|
||||
#define STAT_NEED_KEY 0x50000
|
||||
#define STAT_TRUNCATED 0x60000
|
||||
#define STAT_SECURE_WILDCARD 0x70000
|
||||
#define STAT_OK 0x80000
|
||||
#define STAT_ABANDONED 0x90000
|
||||
|
||||
#define DNSSEC_FAIL_NYV 0x0001 /* key not yet valid */
|
||||
#define DNSSEC_FAIL_EXP 0x0002 /* key expired */
|
||||
#define DNSSEC_FAIL_INDET 0x0004 /* indetermined */
|
||||
#define DNSSEC_FAIL_NOKEYSUP 0x0008 /* no supported key algo. */
|
||||
#define DNSSEC_FAIL_NOSIG 0x0010 /* No RRsigs */
|
||||
#define DNSSEC_FAIL_NOZONE 0x0020 /* No Zone bit set */
|
||||
#define DNSSEC_FAIL_NONSEC 0x0040 /* No NSEC */
|
||||
#define DNSSEC_FAIL_NODSSUP 0x0080 /* no supported DS algo. */
|
||||
#define DNSSEC_FAIL_NOKEY 0x0100 /* no DNSKEY */
|
||||
|
||||
#define STAT_ISEQUAL(a, b) (((a) & 0xffff0000) == (b))
|
||||
|
||||
#define FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
@@ -1280,7 +1292,7 @@ unsigned char *skip_questions(struct dns_header *header, size_t plen);
|
||||
unsigned char *skip_section(unsigned char *ansp, int count, struct dns_header *header, size_t plen);
|
||||
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||
char *name, unsigned short *typep);
|
||||
void setup_reply(struct dns_header *header, unsigned int flags);
|
||||
void setup_reply(struct dns_header *header, unsigned int flags, int ede);
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
||||
time_t now, char **ipsets, int is_sign, int check_rebind,
|
||||
int no_cache_dnssec, int secure, int *doctored);
|
||||
@@ -1311,6 +1323,7 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
|
||||
#endif
|
||||
|
||||
/* dnssec.c */
|
||||
#ifdef HAVE_DNSSEC
|
||||
size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char *name, int class, int type, int edns_pktsz);
|
||||
int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char *name, char *keyname, int class);
|
||||
@@ -1319,6 +1332,8 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
|
||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||
int setup_timestamp(void);
|
||||
int errflags_to_ede(int status);
|
||||
#endif
|
||||
|
||||
/* hash_questions.c */
|
||||
void hash_questions_init(void);
|
||||
@@ -1742,7 +1757,7 @@ int lookup_domain(char *qdomain, int flags, int *lowout, int *highout);
|
||||
int filter_servers(int seed, int flags, int *lowout, int *highout);
|
||||
int is_local_answer(time_t now, int first, char *name);
|
||||
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header,
|
||||
char *name, char *limit, int first, int last);
|
||||
char *name, char *limit, int first, int last, int ede);
|
||||
int server_samegroup(struct server *a, struct server *b);
|
||||
#ifdef HAVE_DNSSEC
|
||||
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp);
|
||||
|
||||
155
src/dnssec.c
155
src/dnssec.c
@@ -215,14 +215,6 @@ static int is_check_date(unsigned long curtime)
|
||||
return !daemon->dnssec_no_time_check;
|
||||
}
|
||||
|
||||
/* Check whether today/now is between date_start and date_end */
|
||||
static int check_date_range(unsigned long curtime, u32 date_start, u32 date_end)
|
||||
{
|
||||
/* We must explicitly check against wanted values, because of SERIAL_UNDEF */
|
||||
return serial_compare_32(curtime, date_start) == SERIAL_GT
|
||||
&& serial_compare_32(curtime, date_end) == SERIAL_LT;
|
||||
}
|
||||
|
||||
/* Return bytes of canonicalised rrdata one by one.
|
||||
Init state->ip with the RR, and state->end with the end of same.
|
||||
Init state->op to NULL.
|
||||
@@ -534,6 +526,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
struct crec *crecp = NULL;
|
||||
u16 *rr_desc = rrfilter_desc(type);
|
||||
u32 sig_expiration, sig_inception;
|
||||
int failflags = DNSSEC_FAIL_NOSIG | DNSSEC_FAIL_NYV | DNSSEC_FAIL_EXP | DNSSEC_FAIL_NOKEYSUP;
|
||||
|
||||
unsigned long curtime = time(0);
|
||||
int time_check = is_check_date(curtime);
|
||||
@@ -558,6 +551,8 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
char *name_start;
|
||||
u32 nsigttl, ttl, orig_ttl;
|
||||
|
||||
failflags &= ~DNSSEC_FAIL_NOSIG;
|
||||
|
||||
p = sigs[j];
|
||||
GETLONG(ttl, p);
|
||||
GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
|
||||
@@ -574,9 +569,28 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
if (!extract_name(header, plen, &p, keyname, 1, 0))
|
||||
return STAT_BOGUS;
|
||||
|
||||
if ((time_check && !check_date_range(curtime, sig_inception, sig_expiration)) ||
|
||||
labels > name_labels ||
|
||||
!(hash = hash_find(algo_digest_name(algo))) ||
|
||||
if (!time_check)
|
||||
failflags &= ~(DNSSEC_FAIL_NYV | DNSSEC_FAIL_EXP);
|
||||
else
|
||||
{
|
||||
/* We must explicitly check against wanted values, because of SERIAL_UNDEF */
|
||||
if (serial_compare_32(curtime, sig_inception) == SERIAL_LT)
|
||||
continue;
|
||||
else
|
||||
failflags &= ~DNSSEC_FAIL_NYV;
|
||||
|
||||
if (serial_compare_32(curtime, sig_expiration) == SERIAL_GT)
|
||||
continue;
|
||||
else
|
||||
failflags &= ~DNSSEC_FAIL_EXP;
|
||||
}
|
||||
|
||||
if (!(hash = hash_find(algo_digest_name(algo))))
|
||||
continue;
|
||||
else
|
||||
failflags &= ~DNSSEC_FAIL_NOKEYSUP;
|
||||
|
||||
if (labels > name_labels ||
|
||||
!hash_init(hash, &ctx, &digest))
|
||||
continue;
|
||||
|
||||
@@ -730,7 +744,7 @@ static int validate_rrset(time_t now, struct dns_header *header, size_t plen, in
|
||||
}
|
||||
}
|
||||
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | failflags;
|
||||
}
|
||||
|
||||
|
||||
@@ -751,17 +765,18 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
unsigned long ttl, sig_ttl;
|
||||
struct blockdata *key;
|
||||
union all_addr a;
|
||||
int failflags = DNSSEC_FAIL_NOSIG | DNSSEC_FAIL_NODSSUP | DNSSEC_FAIL_NOZONE | DNSSEC_FAIL_NOKEY;
|
||||
|
||||
if (ntohs(header->qdcount) != 1 ||
|
||||
RCODE(header) == SERVFAIL || RCODE(header) == REFUSED ||
|
||||
!extract_name(header, plen, &p, name, 1, 4))
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NOKEY;
|
||||
|
||||
GETSHORT(qtype, p);
|
||||
GETSHORT(qclass, p);
|
||||
|
||||
if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NOKEY;
|
||||
|
||||
/* See if we have cached a DS record which validates this key */
|
||||
if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
|
||||
@@ -795,14 +810,17 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
|
||||
GETSHORT(flags, p);
|
||||
if (*p++ != 3)
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NOKEY;
|
||||
algo = *p++;
|
||||
keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
|
||||
key = NULL;
|
||||
|
||||
/* key must have zone key flag set */
|
||||
if (flags & 0x100)
|
||||
key = blockdata_alloc((char*)p, rdlen - 4);
|
||||
{
|
||||
key = blockdata_alloc((char*)p, rdlen - 4);
|
||||
failflags &= ~DNSSEC_FAIL_NOZONE;
|
||||
}
|
||||
|
||||
p = psave;
|
||||
|
||||
@@ -823,15 +841,23 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
unsigned char *digest, *ds_digest;
|
||||
const struct nettle_hash *hash;
|
||||
int sigcnt, rrcnt;
|
||||
int wire_len;
|
||||
|
||||
if (recp1->addr.ds.algo == algo &&
|
||||
recp1->addr.ds.keytag == keytag &&
|
||||
recp1->uid == (unsigned int)class &&
|
||||
(hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
|
||||
hash_init(hash, &ctx, &digest))
|
||||
|
||||
recp1->uid == (unsigned int)class)
|
||||
{
|
||||
int wire_len = to_wire(name);
|
||||
failflags &= ~DNSSEC_FAIL_NOKEY;
|
||||
|
||||
if (!(hash = hash_find(ds_digest_name(recp1->addr.ds.digest))))
|
||||
continue;
|
||||
else
|
||||
failflags &= ~DNSSEC_FAIL_NODSSUP;
|
||||
|
||||
if (!hash_init(hash, &ctx, &digest))
|
||||
continue;
|
||||
|
||||
wire_len = to_wire(name);
|
||||
|
||||
/* Note that digest may be different between DSs, so
|
||||
we can't move this outside the loop. */
|
||||
@@ -846,12 +872,23 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
(ds_digest = blockdata_retrieve(recp1->addr.ds.keydata, recp1->addr.ds.keylen, NULL)) &&
|
||||
memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
|
||||
explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
|
||||
sigcnt != 0 && rrcnt != 0 &&
|
||||
validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname,
|
||||
NULL, key, rdlen - 4, algo, keytag, &sig_ttl) == STAT_SECURE)
|
||||
rrcnt != 0)
|
||||
{
|
||||
valid = 1;
|
||||
break;
|
||||
if (sigcnt == 0)
|
||||
continue;
|
||||
else
|
||||
failflags &= ~DNSSEC_FAIL_NOSIG;
|
||||
|
||||
rc = validate_rrset(now, header, plen, class, T_DNSKEY, sigcnt, rrcnt, name, keyname,
|
||||
NULL, key, rdlen - 4, algo, keytag, &sig_ttl);
|
||||
|
||||
failflags &= rc;
|
||||
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
{
|
||||
valid = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -936,7 +973,7 @@ int dnssec_validate_by_ds(time_t now, struct dns_header *header, size_t plen, ch
|
||||
}
|
||||
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DNSKEY");
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | failflags;
|
||||
}
|
||||
|
||||
/* The DNS packet is expected to contain the answer to a DS query
|
||||
@@ -971,10 +1008,11 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
else
|
||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons, &neg_ttl);
|
||||
|
||||
if (rc == STAT_INSECURE)
|
||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("Insecure DS reply received for %s, check domain configuration and upstream DNS server DNSSEC support"), name);
|
||||
rc = STAT_BOGUS;
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS - not secure");
|
||||
return STAT_BOGUS | DNSSEC_FAIL_INDET;
|
||||
}
|
||||
|
||||
p = (unsigned char *)(header+1);
|
||||
@@ -984,13 +1022,13 @@ int dnssec_validate_ds(time_t now, struct dns_header *header, size_t plen, char
|
||||
/* If the key needed to validate the DS is on the same domain as the DS, we'll
|
||||
loop getting nowhere. Stop that now. This can happen of the DS answer comes
|
||||
from the DS's zone, and not the parent zone. */
|
||||
if (rc == STAT_BOGUS || (rc == STAT_NEED_KEY && hostname_isequal(name, keyname)))
|
||||
if (STAT_ISEQUAL(rc, STAT_NEED_KEY) && hostname_isequal(name, keyname))
|
||||
{
|
||||
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
|
||||
return STAT_BOGUS;
|
||||
}
|
||||
|
||||
if (rc != STAT_SECURE)
|
||||
if (!STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
return rc;
|
||||
|
||||
if (!neganswer)
|
||||
@@ -1456,7 +1494,7 @@ static int prove_non_existence_nsec3(struct dns_header *header, size_t plen, uns
|
||||
if (!(p = skip_name(nsecs[i], header, plen, 15)))
|
||||
return 0; /* bad packet */
|
||||
|
||||
p += 10; /* type, class, TTL, rdlen */
|
||||
p += 10; /* type, class, TTL, rdlen */
|
||||
algo = *p++;
|
||||
|
||||
if ((hash = hash_find(nsec3_digest_name(algo))))
|
||||
@@ -1959,15 +1997,15 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
if (check_unsigned && i < ntohs(header->ancount))
|
||||
{
|
||||
rc = zone_status(name, class1, keyname, now);
|
||||
if (rc == STAT_SECURE)
|
||||
rc = STAT_BOGUS;
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
rc = STAT_BOGUS | DNSSEC_FAIL_NOSIG;
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
}
|
||||
else
|
||||
rc = STAT_INSECURE;
|
||||
|
||||
if (rc != STAT_INSECURE)
|
||||
if (!STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
return rc;
|
||||
}
|
||||
}
|
||||
@@ -1978,7 +2016,7 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
strcpy(daemon->workspacename, keyname);
|
||||
rc = zone_status(daemon->workspacename, class1, keyname, now);
|
||||
|
||||
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
|
||||
if (STAT_ISEQUAL(rc, STAT_BOGUS) || STAT_ISEQUAL(rc, STAT_NEED_KEY) || STAT_ISEQUAL(rc, STAT_NEED_DS))
|
||||
{
|
||||
if (class)
|
||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||
@@ -1986,13 +2024,13 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
}
|
||||
|
||||
/* Zone is insecure, don't need to validate RRset */
|
||||
if (rc == STAT_SECURE)
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||
{
|
||||
unsigned long sig_ttl;
|
||||
rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
|
||||
rrcnt, name, keyname, &wildname, NULL, 0, 0, 0, &sig_ttl);
|
||||
|
||||
if (rc == STAT_BOGUS || rc == STAT_NEED_KEY || rc == STAT_NEED_DS)
|
||||
if (STAT_ISEQUAL(rc, STAT_BOGUS) || STAT_ISEQUAL(rc, STAT_NEED_KEY) || STAT_ISEQUAL(rc, STAT_NEED_DS))
|
||||
{
|
||||
if (class)
|
||||
*class = class1; /* Class for DS or DNSKEY */
|
||||
@@ -2025,21 +2063,21 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
|
||||
That's not a problem since if the RRsets later fail
|
||||
we'll return BOGUS then. */
|
||||
if (rc == STAT_SECURE_WILDCARD &&
|
||||
if (STAT_ISEQUAL(rc, STAT_SECURE_WILDCARD) &&
|
||||
!prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL, NULL))
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NONSEC;
|
||||
|
||||
rc = STAT_SECURE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (rc == STAT_INSECURE)
|
||||
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||
secure = STAT_INSECURE;
|
||||
}
|
||||
|
||||
/* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
|
||||
if (secure == STAT_SECURE)
|
||||
if (STAT_ISEQUAL(secure, STAT_SECURE))
|
||||
for (j = 0; j <targetidx; j++)
|
||||
if ((p2 = targets[j]))
|
||||
{
|
||||
@@ -2057,16 +2095,16 @@ int dnssec_validate_reply(time_t now, struct dns_header *header, size_t plen, ch
|
||||
{
|
||||
/* Empty DS without NSECS */
|
||||
if (qtype == T_DS)
|
||||
return STAT_BOGUS;
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NONSEC;
|
||||
|
||||
if ((rc = zone_status(name, qclass, keyname, now)) != STAT_SECURE)
|
||||
if (STAT_ISEQUAL((rc = zone_status(name, qclass, keyname, now)), STAT_SECURE))
|
||||
{
|
||||
if (class)
|
||||
*class = qclass; /* Class for NEED_DS or NEED_KEY */
|
||||
return rc;
|
||||
}
|
||||
|
||||
return STAT_BOGUS; /* signed zone, no NSECs */
|
||||
return STAT_BOGUS | DNSSEC_FAIL_NONSEC; /* signed zone, no NSECs */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2130,4 +2168,31 @@ size_t dnssec_generate_query(struct dns_header *header, unsigned char *end, char
|
||||
return ret;
|
||||
}
|
||||
|
||||
int errflags_to_ede(int status)
|
||||
{
|
||||
/* We can end up with more than one flag set for some errors,
|
||||
so this encodes a rough priority so the (eg) No sig is reported
|
||||
before no-unexpired-sig. */
|
||||
|
||||
if (status & DNSSEC_FAIL_NYV)
|
||||
return EDE_SIG_NYV;
|
||||
else if (status & DNSSEC_FAIL_EXP)
|
||||
return EDE_SIG_EXP;
|
||||
else if (status & DNSSEC_FAIL_NOKEYSUP)
|
||||
return EDE_USUPDNSKEY;
|
||||
else if (status & DNSSEC_FAIL_NOZONE)
|
||||
return EDE_NO_ZONEKEY;
|
||||
else if (status & DNSSEC_FAIL_NOKEY)
|
||||
return EDE_NO_DNSKEY;
|
||||
else if (status & DNSSEC_FAIL_NODSSUP)
|
||||
return EDE_USUPDS;
|
||||
else if (status & DNSSEC_FAIL_NONSEC)
|
||||
return EDE_NO_NSEC;
|
||||
else if (status & DNSSEC_FAIL_INDET)
|
||||
return EDE_DNSSEC_IND;
|
||||
else if (status & DNSSEC_FAIL_NOSIG)
|
||||
return EDE_NO_RRSIG;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
#endif /* HAVE_DNSSEC */
|
||||
|
||||
@@ -340,7 +340,7 @@ int is_local_answer(time_t now, int first, char *name)
|
||||
return rc;
|
||||
}
|
||||
|
||||
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, char *limit, int first, int last)
|
||||
size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header *header, char *name, char *limit, int first, int last, int ede)
|
||||
{
|
||||
int trunc = 0;
|
||||
unsigned char *p;
|
||||
@@ -350,7 +350,7 @@ size_t make_local_answer(int flags, int gotname, size_t size, struct dns_header
|
||||
if (flags & (F_NXDOMAIN | F_NOERR))
|
||||
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL);
|
||||
|
||||
setup_reply(header, flags);
|
||||
setup_reply(header, flags, ede);
|
||||
|
||||
if (!(p = skip_questions(header, size)))
|
||||
return 0;
|
||||
|
||||
151
src/forward.c
151
src/forward.c
@@ -177,6 +177,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
int subnet, cacheable, forwarded = 0;
|
||||
size_t edns0_len;
|
||||
unsigned char *pheader;
|
||||
int ede = -1;
|
||||
(void)do_bit;
|
||||
|
||||
if (header->hb4 & HB4_CD)
|
||||
@@ -270,7 +271,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
/* no available server. */
|
||||
if (!lookup_domain(daemon->namebuff, gotname, &first, &last))
|
||||
goto reply;
|
||||
{
|
||||
ede = EDE_NOT_READY;
|
||||
goto reply;
|
||||
}
|
||||
|
||||
/* Configured answer. */
|
||||
if ((flags = is_local_answer(now, first, daemon->namebuff)))
|
||||
@@ -521,15 +525,23 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
/* could not send on, prepare to return */
|
||||
header->id = htons(forward->frec_src.orig_id);
|
||||
free_frec(forward); /* cancel */
|
||||
ede = EDE_NETERR;
|
||||
|
||||
reply:
|
||||
if (udpfd != -1)
|
||||
{
|
||||
if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, limit, first, last)))
|
||||
if (!(plen = make_local_answer(flags, gotname, plen, header, daemon->namebuff, limit, first, last, ede)))
|
||||
return 0;
|
||||
|
||||
if (oph)
|
||||
plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
{
|
||||
u16 swap = htons((u16)ede);
|
||||
|
||||
if (ede != -1)
|
||||
plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
else
|
||||
plen = add_pseudoheader(header, plen, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
}
|
||||
|
||||
#if defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||
if (option_bool(OPT_CMARK_ALST_EN))
|
||||
@@ -549,7 +561,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
|
||||
static size_t process_reply(struct dns_header *header, time_t now, struct server *server, size_t n, int check_rebind,
|
||||
int no_cache, int cache_secure, int bogusanswer, int ad_reqd, int do_bit, int added_pheader,
|
||||
int check_subnet, union mysockaddr *query_source)
|
||||
int check_subnet, union mysockaddr *query_source, unsigned char *limit, int ede)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
char **sets = 0;
|
||||
@@ -604,11 +616,10 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
}
|
||||
else
|
||||
{
|
||||
unsigned short udpsz;
|
||||
|
||||
/* If upstream is advertising a larger UDP packet size
|
||||
than we allow, trim it so that we don't get overlarge
|
||||
requests for the client. We can't do this for signed packets. */
|
||||
unsigned short udpsz;
|
||||
GETSHORT(udpsz, sizep);
|
||||
if (udpsz > daemon->edns_pktsz)
|
||||
{
|
||||
@@ -645,6 +656,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
{
|
||||
union all_addr a;
|
||||
a.log.rcode = rcode;
|
||||
a.log.ede = ede;
|
||||
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
|
||||
|
||||
return resize_packet(header, n, pheader, plen);
|
||||
@@ -667,6 +679,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
SET_RCODE(header, NXDOMAIN);
|
||||
header->hb3 &= ~HB3_AA;
|
||||
cache_secure = 0;
|
||||
ede = EDE_BLOCKED;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -693,6 +706,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||
munged = 1;
|
||||
cache_secure = 0;
|
||||
ede = EDE_BLOCKED;
|
||||
}
|
||||
|
||||
if (doctored)
|
||||
@@ -720,9 +734,14 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
}
|
||||
#endif
|
||||
|
||||
if (pheader && ede != -1)
|
||||
{
|
||||
u16 swap = htons((u16)ede);
|
||||
n = add_pseudoheader(header, n, limit, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 1);
|
||||
}
|
||||
|
||||
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||
nameserver info. */
|
||||
|
||||
if (munged)
|
||||
{
|
||||
header->ancount = htons(0);
|
||||
@@ -762,7 +781,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
/* As soon as anything returns BOGUS, we stop and unwind, to do otherwise
|
||||
would invite infinite loops, since the answers to DNSKEY and DS queries
|
||||
will not be cached, so they'll be repeated. */
|
||||
if (status != STAT_BOGUS && status != STAT_TRUNCATED && status != STAT_ABANDONED)
|
||||
if (!STAT_ISEQUAL(status, STAT_BOGUS) && !STAT_ISEQUAL(status, STAT_TRUNCATED) && !STAT_ISEQUAL(status, STAT_ABANDONED))
|
||||
{
|
||||
if (forward->flags & FREC_DNSKEY_QUERY)
|
||||
status = dnssec_validate_by_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class);
|
||||
@@ -773,7 +792,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
!option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL, NULL);
|
||||
#ifdef HAVE_DUMPFILE
|
||||
if (status == STAT_BOGUS)
|
||||
if (STAT_ISEQUAL(status, STAT_BOGUS))
|
||||
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
|
||||
header, (size_t)plen, &forward->sentto->addr, NULL);
|
||||
#endif
|
||||
@@ -781,7 +800,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
|
||||
/* Can't validate, as we're missing key data. Put this
|
||||
answer aside, whilst we get that. */
|
||||
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
||||
if (STAT_ISEQUAL(status, STAT_NEED_DS) || STAT_ISEQUAL(status, STAT_NEED_KEY))
|
||||
{
|
||||
struct frec *new = NULL;
|
||||
int serverind;
|
||||
@@ -800,9 +819,9 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
/* validate routines leave name of required record in daemon->keyname */
|
||||
nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
|
||||
daemon->keyname, forward->class,
|
||||
status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
|
||||
STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS, server->edns_pktsz);
|
||||
|
||||
flags = (status == STAT_NEED_KEY) ? FREC_DNSKEY_QUERY : FREC_DS_QUERY;
|
||||
flags = STAT_ISEQUAL(status, STAT_NEED_KEY) ? FREC_DNSKEY_QUERY : FREC_DS_QUERY;
|
||||
hash = hash_questions(header, nn, daemon->namebuff);
|
||||
|
||||
if ((new = lookup_frec_by_query(hash, flags, FREC_DNSKEY_QUERY | FREC_DS_QUERY)))
|
||||
@@ -872,7 +891,7 @@ static void dnssec_validate(struct frec *forward, struct dns_header *header,
|
||||
#endif
|
||||
server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
|
||||
F_NOEXTRA | F_DNSSEC, daemon->keyname,
|
||||
querystr("dnssec-query", status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
|
||||
querystr("dnssec-query", STAT_ISEQUAL(status, STAT_NEED_KEY) ? T_DNSKEY : T_DS));
|
||||
server->queries++;
|
||||
}
|
||||
|
||||
@@ -1073,6 +1092,7 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
{
|
||||
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||
size_t nn;
|
||||
int ede = -1;
|
||||
|
||||
(void)status;
|
||||
|
||||
@@ -1085,36 +1105,40 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
no_cache_dnssec = 1;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (status != STAT_OK)
|
||||
if (!STAT_ISEQUAL(status, STAT_OK))
|
||||
{
|
||||
/* status is STAT_OK when validation not turned on. */
|
||||
no_cache_dnssec = 0;
|
||||
|
||||
if (status == STAT_TRUNCATED)
|
||||
if (STAT_ISEQUAL(status, STAT_TRUNCATED))
|
||||
header->hb3 |= HB3_TC;
|
||||
else
|
||||
{
|
||||
char *result, *domain = "result";
|
||||
union all_addr a;
|
||||
|
||||
if (status == STAT_ABANDONED)
|
||||
a.log.ede = ede = errflags_to_ede(status);
|
||||
|
||||
if (STAT_ISEQUAL(status, STAT_ABANDONED))
|
||||
{
|
||||
result = "ABANDONED";
|
||||
status = STAT_BOGUS;
|
||||
}
|
||||
else
|
||||
result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
||||
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
|
||||
|
||||
if (status == STAT_BOGUS && extract_request(header, n, daemon->namebuff, NULL))
|
||||
domain = daemon->namebuff;
|
||||
if (STAT_ISEQUAL(status, STAT_SECURE))
|
||||
cache_secure = 1;
|
||||
else if (STAT_ISEQUAL(status, STAT_BOGUS))
|
||||
{
|
||||
no_cache_dnssec = 1;
|
||||
bogusanswer = 1;
|
||||
|
||||
log_query(F_SECSTAT, domain, NULL, result);
|
||||
}
|
||||
if (extract_request(header, n, daemon->namebuff, NULL))
|
||||
domain = daemon->namebuff;
|
||||
}
|
||||
|
||||
if (status == STAT_SECURE)
|
||||
cache_secure = 1;
|
||||
else if (status == STAT_BOGUS)
|
||||
{
|
||||
no_cache_dnssec = 1;
|
||||
bogusanswer = 1;
|
||||
log_query(F_SECSTAT, domain, &a, result);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -1135,7 +1159,8 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
||||
|
||||
if ((nn = process_reply(header, now, forward->sentto, (size_t)n, check_rebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
forward->flags & FREC_AD_QUESTION, forward->flags & FREC_DO_QUESTION,
|
||||
forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source)))
|
||||
forward->flags & FREC_ADDED_PHEADER, forward->flags & FREC_HAS_SUBNET, &forward->frec_src.source,
|
||||
((unsigned char *)header) + daemon->edns_pktsz, ede)))
|
||||
{
|
||||
struct frec_src *src;
|
||||
|
||||
@@ -1221,7 +1246,7 @@ static size_t answer_disallowed(struct dns_header *header, size_t qlen, u32 mark
|
||||
ubus_event_bcast_connmark_allowlist_refused(mark, name);
|
||||
#endif
|
||||
|
||||
setup_reply(header, /* flags: */ 0);
|
||||
setup_reply(header, /* flags: */ 0, EDE_BLOCKED);
|
||||
|
||||
if (!(p = skip_questions(header, qlen)))
|
||||
return 0;
|
||||
@@ -1545,10 +1570,13 @@ void receive_query(struct listener *listen, time_t now)
|
||||
#ifdef HAVE_CONNTRACK
|
||||
else if (!allowed)
|
||||
{
|
||||
u16 swap = htons(EDE_BLOCKED);
|
||||
|
||||
m = answer_disallowed(header, (size_t)n, (u32)mark, is_single_query ? daemon->namebuff : NULL);
|
||||
|
||||
if (have_pseudoheader && m != 0)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + udp_size, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + udp_size, daemon->edns_pktsz,
|
||||
EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
|
||||
if (m >= 1)
|
||||
{
|
||||
@@ -1731,16 +1759,16 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
/* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
|
||||
if (--(*keycount) == 0)
|
||||
new_status = STAT_ABANDONED;
|
||||
else if (status == STAT_NEED_KEY)
|
||||
else if (STAT_ISEQUAL(status, STAT_NEED_KEY))
|
||||
new_status = dnssec_validate_by_ds(now, header, n, name, keyname, class);
|
||||
else if (status == STAT_NEED_DS)
|
||||
else if (STAT_ISEQUAL(status, STAT_NEED_DS))
|
||||
new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
|
||||
else
|
||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
|
||||
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
|
||||
NULL, NULL, NULL);
|
||||
|
||||
if (new_status != STAT_NEED_DS && new_status != STAT_NEED_KEY)
|
||||
if (!STAT_ISEQUAL(new_status, STAT_NEED_DS) && !STAT_ISEQUAL(new_status, STAT_NEED_KEY))
|
||||
break;
|
||||
|
||||
/* Can't validate because we need a key/DS whose name now in keyname.
|
||||
@@ -1758,7 +1786,7 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
}
|
||||
|
||||
m = dnssec_generate_query(new_header, ((unsigned char *) new_header) + 65536, keyname, class,
|
||||
new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS, server->edns_pktsz);
|
||||
STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS, server->edns_pktsz);
|
||||
|
||||
if ((start = dnssec_server(server, daemon->keyname, &first, &last)) == -1 ||
|
||||
(m = tcp_talk(first, last, start, packet, m, have_mark, mark, &server)) == 0)
|
||||
@@ -1771,13 +1799,13 @@ static int tcp_key_recurse(time_t now, int status, struct dns_header *header, si
|
||||
daemon->log_display_id = ++daemon->log_id;
|
||||
|
||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
|
||||
querystr("dnssec-query", new_status == STAT_NEED_KEY ? T_DNSKEY : T_DS));
|
||||
querystr("dnssec-query", STAT_ISEQUAL(new_status, STAT_NEED_KEY) ? T_DNSKEY : T_DS));
|
||||
|
||||
new_status = tcp_key_recurse(now, new_status, new_header, m, class, name, keyname, server, have_mark, mark, keycount);
|
||||
|
||||
daemon->log_display_id = log_save;
|
||||
|
||||
if (new_status != STAT_OK)
|
||||
if (!STAT_ISEQUAL(new_status, STAT_OK))
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1877,6 +1905,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
while (1)
|
||||
{
|
||||
int ede = -1;
|
||||
|
||||
if (query_count == TCP_MAX_QUERIES ||
|
||||
!packet ||
|
||||
!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
|
||||
@@ -1962,10 +1992,13 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
#ifdef HAVE_CONNTRACK
|
||||
else if (!allowed)
|
||||
{
|
||||
u16 swap = htons(EDE_BLOCKED);
|
||||
|
||||
m = answer_disallowed(header, size, (u32)mark, is_single_query ? daemon->namebuff : NULL);
|
||||
|
||||
if (have_pseudoheader && m != 0)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz,
|
||||
EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_AUTH
|
||||
@@ -1998,7 +2031,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
!strchr(daemon->namebuff, '.') &&
|
||||
strlen(daemon->namebuff) != 0)
|
||||
flags = F_NOERR;
|
||||
else if (lookup_domain(daemon->namebuff, gotname, &first, &last) && !(flags = is_local_answer(now, first, daemon->namebuff)))
|
||||
else if (!lookup_domain(daemon->namebuff, gotname, &first, &last))
|
||||
ede = EDE_NOT_READY; /* No configured servers */
|
||||
else if (!(flags = is_local_answer(now, first, daemon->namebuff)))
|
||||
{
|
||||
master = daemon->serverarray[first];
|
||||
|
||||
@@ -2028,7 +2063,10 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
/* Loop round available servers until we succeed in connecting to one. */
|
||||
if ((m = tcp_talk(first, last, start, packet, size, have_mark, mark, &serv)) == 0)
|
||||
break;
|
||||
{
|
||||
ede = EDE_NETERR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* get query name again for logging - may have been overwritten */
|
||||
if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
||||
@@ -2043,27 +2081,29 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
serv, have_mark, mark, &keycount);
|
||||
char *result, *domain = "result";
|
||||
|
||||
if (status == STAT_ABANDONED)
|
||||
union all_addr a;
|
||||
a.log.ede = ede = errflags_to_ede(status);
|
||||
|
||||
if (STAT_ISEQUAL(status, STAT_ABANDONED))
|
||||
{
|
||||
result = "ABANDONED";
|
||||
status = STAT_BOGUS;
|
||||
}
|
||||
else
|
||||
result = (status == STAT_SECURE ? "SECURE" : (status == STAT_INSECURE ? "INSECURE" : "BOGUS"));
|
||||
result = (STAT_ISEQUAL(status, STAT_SECURE) ? "SECURE" : (STAT_ISEQUAL(status, STAT_INSECURE) ? "INSECURE" : "BOGUS"));
|
||||
|
||||
if (status == STAT_BOGUS && extract_request(header, m, daemon->namebuff, NULL))
|
||||
domain = daemon->namebuff;
|
||||
|
||||
log_query(F_SECSTAT, domain, NULL, result);
|
||||
|
||||
if (status == STAT_BOGUS)
|
||||
if (STAT_ISEQUAL(status, STAT_SECURE))
|
||||
cache_secure = 1;
|
||||
else if (STAT_ISEQUAL(status, STAT_BOGUS))
|
||||
{
|
||||
no_cache_dnssec = 1;
|
||||
bogusanswer = 1;
|
||||
|
||||
if (extract_request(header, m, daemon->namebuff, NULL))
|
||||
domain = daemon->namebuff;
|
||||
}
|
||||
|
||||
if (status == STAT_SECURE)
|
||||
cache_secure = 1;
|
||||
log_query(F_SECSTAT, domain, &a, result);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -2080,7 +2120,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
|
||||
m = process_reply(header, now, serv, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
||||
ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr);
|
||||
ad_reqd, do_bit, added_pheader, check_subnet, &peer_addr, ((unsigned char *)header) + 65536, ede);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2089,11 +2129,18 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (m == 0)
|
||||
{
|
||||
if (!(m = make_local_answer(flags, gotname, size, header, daemon->namebuff,
|
||||
((char *) header) + 65536, first, last)))
|
||||
((char *) header) + 65536, first, last, ede)))
|
||||
break;
|
||||
|
||||
if (have_pseudoheader)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
{
|
||||
u16 swap = htons((u16)ede);
|
||||
|
||||
if (ede != -1)
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, EDNS0_OPTION_EDE, (unsigned char *)&swap, 2, do_bit, 0);
|
||||
else
|
||||
m = add_pseudoheader(header, m, ((unsigned char *) header) + 65536, daemon->edns_pktsz, 0, NULL, 0, do_bit, 0);
|
||||
}
|
||||
}
|
||||
|
||||
check_log_writer(1);
|
||||
|
||||
@@ -1017,7 +1017,7 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
||||
return F_QUERY;
|
||||
}
|
||||
|
||||
void setup_reply(struct dns_header *header, unsigned int flags)
|
||||
void setup_reply(struct dns_header *header, unsigned int flags, int ede)
|
||||
{
|
||||
/* clear authoritative and truncated flags, set QR flag */
|
||||
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC )) | HB3_QR;
|
||||
@@ -1040,6 +1040,7 @@ void setup_reply(struct dns_header *header, unsigned int flags)
|
||||
{
|
||||
union all_addr a;
|
||||
a.log.rcode = REFUSED;
|
||||
a.log.ede = ede;
|
||||
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
||||
SET_RCODE(header, REFUSED);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user