mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28: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 : "";
|
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)
|
void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
||||||
{
|
{
|
||||||
char *source, *dest = daemon->addrbuff;
|
char *source, *dest = daemon->addrbuff;
|
||||||
char *verb = "is";
|
char *verb = "is";
|
||||||
|
char *extra = "";
|
||||||
|
|
||||||
if (!option_bool(OPT_LOG))
|
if (!option_bool(OPT_LOG))
|
||||||
return;
|
return;
|
||||||
@@ -1887,6 +1921,12 @@ void log_query(unsigned int flags, char *name, union all_addr *addr, char *arg)
|
|||||||
dest = "not implemented";
|
dest = "not implemented";
|
||||||
else
|
else
|
||||||
sprintf(daemon->addrbuff, "%u", rcode);
|
sprintf(daemon->addrbuff, "%u", rcode);
|
||||||
|
|
||||||
|
if (addr->log.ede != -1)
|
||||||
|
{
|
||||||
|
extra = daemon->addrbuff;
|
||||||
|
sprintf(extra, " (EDE:%s)", edestr(addr->log.ede));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
inet_ntop(flags & F_IPV4 ? AF_INET : AF_INET6,
|
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)
|
else if (flags & F_UPSTREAM)
|
||||||
source = "reply";
|
source = "reply";
|
||||||
else if (flags & F_SECSTAT)
|
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)
|
else if (flags & F_AUTH)
|
||||||
source = "auth";
|
source = "auth";
|
||||||
else if (flags & F_SERVER)
|
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 (option_bool(OPT_EXTRALOG))
|
||||||
{
|
{
|
||||||
if (flags & F_NOEXTRA)
|
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
|
else
|
||||||
{
|
{
|
||||||
int port = prettyprint_addr(daemon->log_source_addr, daemon->addrbuff2);
|
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
|
else
|
||||||
|
|||||||
@@ -80,10 +80,41 @@
|
|||||||
|
|
||||||
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
|
#define EDNS0_OPTION_MAC 65001 /* dyndns.org temporary assignment */
|
||||||
#define EDNS0_OPTION_CLIENT_SUBNET 8 /* IANA */
|
#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_NOMDEVICEID 65073 /* Nominum temporary assignment */
|
||||||
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
#define EDNS0_OPTION_NOMCPEID 65074 /* Nominum temporary assignment */
|
||||||
#define EDNS0_OPTION_UMBRELLA 20292 /* Cisco Umbrella 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 {
|
struct dns_header {
|
||||||
u16 id;
|
u16 id;
|
||||||
u8 hb3,hb4;
|
u8 hb3,hb4;
|
||||||
|
|||||||
@@ -323,6 +323,7 @@ union all_addr {
|
|||||||
/* for log_query */
|
/* for log_query */
|
||||||
struct {
|
struct {
|
||||||
unsigned short keytag, algo, digest, rcode;
|
unsigned short keytag, algo, digest, rcode;
|
||||||
|
int ede;
|
||||||
} log;
|
} log;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -686,17 +687,28 @@ struct hostsfile {
|
|||||||
#define DUMP_BOGUS 0x0040
|
#define DUMP_BOGUS 0x0040
|
||||||
#define DUMP_SEC_BOGUS 0x0080
|
#define DUMP_SEC_BOGUS 0x0080
|
||||||
|
|
||||||
|
|
||||||
/* DNSSEC status values. */
|
/* DNSSEC status values. */
|
||||||
#define STAT_SECURE 1
|
#define STAT_SECURE 0x10000
|
||||||
#define STAT_INSECURE 2
|
#define STAT_INSECURE 0x20000
|
||||||
#define STAT_BOGUS 3
|
#define STAT_BOGUS 0x30000
|
||||||
#define STAT_NEED_DS 4
|
#define STAT_NEED_DS 0x40000
|
||||||
#define STAT_NEED_KEY 5
|
#define STAT_NEED_KEY 0x50000
|
||||||
#define STAT_TRUNCATED 6
|
#define STAT_TRUNCATED 0x60000
|
||||||
#define STAT_SECURE_WILDCARD 7
|
#define STAT_SECURE_WILDCARD 0x70000
|
||||||
#define STAT_OK 8
|
#define STAT_OK 0x80000
|
||||||
#define STAT_ABANDONED 9
|
#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_NOREBIND 1
|
||||||
#define FREC_CHECKING_DISABLED 2
|
#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 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,
|
unsigned int extract_request(struct dns_header *header, size_t qlen,
|
||||||
char *name, unsigned short *typep);
|
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,
|
int extract_addresses(struct dns_header *header, size_t qlen, char *name,
|
||||||
time_t now, char **ipsets, int is_sign, int check_rebind,
|
time_t now, char **ipsets, int is_sign, int check_rebind,
|
||||||
int no_cache_dnssec, int secure, int *doctored);
|
int no_cache_dnssec, int secure, int *doctored);
|
||||||
@@ -1311,6 +1323,7 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* dnssec.c */
|
/* 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);
|
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_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);
|
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);
|
int dnskey_keytag(int alg, int flags, unsigned char *key, int keylen);
|
||||||
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
size_t filter_rrsigs(struct dns_header *header, size_t plen);
|
||||||
int setup_timestamp(void);
|
int setup_timestamp(void);
|
||||||
|
int errflags_to_ede(int status);
|
||||||
|
#endif
|
||||||
|
|
||||||
/* hash_questions.c */
|
/* hash_questions.c */
|
||||||
void hash_questions_init(void);
|
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 filter_servers(int seed, int flags, int *lowout, int *highout);
|
||||||
int is_local_answer(time_t now, int first, char *name);
|
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,
|
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);
|
int server_samegroup(struct server *a, struct server *b);
|
||||||
#ifdef HAVE_DNSSEC
|
#ifdef HAVE_DNSSEC
|
||||||
int dnssec_server(struct server *server, char *keyname, int *firstp, int *lastp);
|
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;
|
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.
|
/* Return bytes of canonicalised rrdata one by one.
|
||||||
Init state->ip with the RR, and state->end with the end of same.
|
Init state->ip with the RR, and state->end with the end of same.
|
||||||
Init state->op to NULL.
|
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;
|
struct crec *crecp = NULL;
|
||||||
u16 *rr_desc = rrfilter_desc(type);
|
u16 *rr_desc = rrfilter_desc(type);
|
||||||
u32 sig_expiration, sig_inception;
|
u32 sig_expiration, sig_inception;
|
||||||
|
int failflags = DNSSEC_FAIL_NOSIG | DNSSEC_FAIL_NYV | DNSSEC_FAIL_EXP | DNSSEC_FAIL_NOKEYSUP;
|
||||||
|
|
||||||
unsigned long curtime = time(0);
|
unsigned long curtime = time(0);
|
||||||
int time_check = is_check_date(curtime);
|
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;
|
char *name_start;
|
||||||
u32 nsigttl, ttl, orig_ttl;
|
u32 nsigttl, ttl, orig_ttl;
|
||||||
|
|
||||||
|
failflags &= ~DNSSEC_FAIL_NOSIG;
|
||||||
|
|
||||||
p = sigs[j];
|
p = sigs[j];
|
||||||
GETLONG(ttl, p);
|
GETLONG(ttl, p);
|
||||||
GETSHORT(rdlen, p); /* rdlen >= 18 checked previously */
|
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))
|
if (!extract_name(header, plen, &p, keyname, 1, 0))
|
||||||
return STAT_BOGUS;
|
return STAT_BOGUS;
|
||||||
|
|
||||||
if ((time_check && !check_date_range(curtime, sig_inception, sig_expiration)) ||
|
if (!time_check)
|
||||||
labels > name_labels ||
|
failflags &= ~(DNSSEC_FAIL_NYV | DNSSEC_FAIL_EXP);
|
||||||
!(hash = hash_find(algo_digest_name(algo))) ||
|
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))
|
!hash_init(hash, &ctx, &digest))
|
||||||
continue;
|
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;
|
unsigned long ttl, sig_ttl;
|
||||||
struct blockdata *key;
|
struct blockdata *key;
|
||||||
union all_addr a;
|
union all_addr a;
|
||||||
|
int failflags = DNSSEC_FAIL_NOSIG | DNSSEC_FAIL_NODSSUP | DNSSEC_FAIL_NOZONE | DNSSEC_FAIL_NOKEY;
|
||||||
|
|
||||||
if (ntohs(header->qdcount) != 1 ||
|
if (ntohs(header->qdcount) != 1 ||
|
||||||
RCODE(header) == SERVFAIL || RCODE(header) == REFUSED ||
|
RCODE(header) == SERVFAIL || RCODE(header) == REFUSED ||
|
||||||
!extract_name(header, plen, &p, name, 1, 4))
|
!extract_name(header, plen, &p, name, 1, 4))
|
||||||
return STAT_BOGUS;
|
return STAT_BOGUS | DNSSEC_FAIL_NOKEY;
|
||||||
|
|
||||||
GETSHORT(qtype, p);
|
GETSHORT(qtype, p);
|
||||||
GETSHORT(qclass, p);
|
GETSHORT(qclass, p);
|
||||||
|
|
||||||
if (qtype != T_DNSKEY || qclass != class || ntohs(header->ancount) == 0)
|
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 */
|
/* See if we have cached a DS record which validates this key */
|
||||||
if (!(crecp = cache_find_by_name(NULL, name, now, F_DS)))
|
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);
|
GETSHORT(flags, p);
|
||||||
if (*p++ != 3)
|
if (*p++ != 3)
|
||||||
return STAT_BOGUS;
|
return STAT_BOGUS | DNSSEC_FAIL_NOKEY;
|
||||||
algo = *p++;
|
algo = *p++;
|
||||||
keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
|
keytag = dnskey_keytag(algo, flags, p, rdlen - 4);
|
||||||
key = NULL;
|
key = NULL;
|
||||||
|
|
||||||
/* key must have zone key flag set */
|
/* key must have zone key flag set */
|
||||||
if (flags & 0x100)
|
if (flags & 0x100)
|
||||||
key = blockdata_alloc((char*)p, rdlen - 4);
|
{
|
||||||
|
key = blockdata_alloc((char*)p, rdlen - 4);
|
||||||
|
failflags &= ~DNSSEC_FAIL_NOZONE;
|
||||||
|
}
|
||||||
|
|
||||||
p = psave;
|
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;
|
unsigned char *digest, *ds_digest;
|
||||||
const struct nettle_hash *hash;
|
const struct nettle_hash *hash;
|
||||||
int sigcnt, rrcnt;
|
int sigcnt, rrcnt;
|
||||||
|
int wire_len;
|
||||||
|
|
||||||
if (recp1->addr.ds.algo == algo &&
|
if (recp1->addr.ds.algo == algo &&
|
||||||
recp1->addr.ds.keytag == keytag &&
|
recp1->addr.ds.keytag == keytag &&
|
||||||
recp1->uid == (unsigned int)class &&
|
recp1->uid == (unsigned int)class)
|
||||||
(hash = hash_find(ds_digest_name(recp1->addr.ds.digest))) &&
|
|
||||||
hash_init(hash, &ctx, &digest))
|
|
||||||
|
|
||||||
{
|
{
|
||||||
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
|
/* Note that digest may be different between DSs, so
|
||||||
we can't move this outside the loop. */
|
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)) &&
|
(ds_digest = blockdata_retrieve(recp1->addr.ds.keydata, recp1->addr.ds.keylen, NULL)) &&
|
||||||
memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
|
memcmp(ds_digest, digest, recp1->addr.ds.keylen) == 0 &&
|
||||||
explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
|
explore_rrset(header, plen, class, T_DNSKEY, name, keyname, &sigcnt, &rrcnt) &&
|
||||||
sigcnt != 0 && rrcnt != 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)
|
|
||||||
{
|
{
|
||||||
valid = 1;
|
if (sigcnt == 0)
|
||||||
break;
|
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");
|
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
|
/* 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
|
else
|
||||||
rc = dnssec_validate_reply(now, header, plen, name, keyname, NULL, 0, &neganswer, &nons, &neg_ttl);
|
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);
|
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);
|
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
|
/* 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
|
loop getting nowhere. Stop that now. This can happen of the DS answer comes
|
||||||
from the DS's zone, and not the parent zone. */
|
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");
|
log_query(F_NOEXTRA | F_UPSTREAM, name, NULL, "BOGUS DS");
|
||||||
return STAT_BOGUS;
|
return STAT_BOGUS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc != STAT_SECURE)
|
if (!STAT_ISEQUAL(rc, STAT_SECURE))
|
||||||
return rc;
|
return rc;
|
||||||
|
|
||||||
if (!neganswer)
|
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)))
|
if (!(p = skip_name(nsecs[i], header, plen, 15)))
|
||||||
return 0; /* bad packet */
|
return 0; /* bad packet */
|
||||||
|
|
||||||
p += 10; /* type, class, TTL, rdlen */
|
p += 10; /* type, class, TTL, rdlen */
|
||||||
algo = *p++;
|
algo = *p++;
|
||||||
|
|
||||||
if ((hash = hash_find(nsec3_digest_name(algo))))
|
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))
|
if (check_unsigned && i < ntohs(header->ancount))
|
||||||
{
|
{
|
||||||
rc = zone_status(name, class1, keyname, now);
|
rc = zone_status(name, class1, keyname, now);
|
||||||
if (rc == STAT_SECURE)
|
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||||
rc = STAT_BOGUS;
|
rc = STAT_BOGUS | DNSSEC_FAIL_NOSIG;
|
||||||
if (class)
|
if (class)
|
||||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
rc = STAT_INSECURE;
|
rc = STAT_INSECURE;
|
||||||
|
|
||||||
if (rc != STAT_INSECURE)
|
if (!STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||||
return rc;
|
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);
|
strcpy(daemon->workspacename, keyname);
|
||||||
rc = zone_status(daemon->workspacename, class1, keyname, now);
|
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)
|
if (class)
|
||||||
*class = class1; /* Class for NEED_DS or NEED_KEY */
|
*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 */
|
/* Zone is insecure, don't need to validate RRset */
|
||||||
if (rc == STAT_SECURE)
|
if (STAT_ISEQUAL(rc, STAT_SECURE))
|
||||||
{
|
{
|
||||||
unsigned long sig_ttl;
|
unsigned long sig_ttl;
|
||||||
rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
|
rc = validate_rrset(now, header, plen, class1, type1, sigcnt,
|
||||||
rrcnt, name, keyname, &wildname, NULL, 0, 0, 0, &sig_ttl);
|
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)
|
if (class)
|
||||||
*class = class1; /* Class for DS or DNSKEY */
|
*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.
|
Note that we may not yet have validated the NSEC/NSEC3 RRsets.
|
||||||
That's not a problem since if the RRsets later fail
|
That's not a problem since if the RRsets later fail
|
||||||
we'll return BOGUS then. */
|
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))
|
!prove_non_existence(header, plen, keyname, name, type1, class1, wildname, NULL, NULL))
|
||||||
return STAT_BOGUS;
|
return STAT_BOGUS | DNSSEC_FAIL_NONSEC;
|
||||||
|
|
||||||
rc = STAT_SECURE;
|
rc = STAT_SECURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == STAT_INSECURE)
|
if (STAT_ISEQUAL(rc, STAT_INSECURE))
|
||||||
secure = STAT_INSECURE;
|
secure = STAT_INSECURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* OK, all the RRsets validate, now see if we have a missing answer or CNAME target. */
|
/* 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++)
|
for (j = 0; j <targetidx; j++)
|
||||||
if ((p2 = targets[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 */
|
/* Empty DS without NSECS */
|
||||||
if (qtype == T_DS)
|
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)
|
if (class)
|
||||||
*class = qclass; /* Class for NEED_DS or NEED_KEY */
|
*class = qclass; /* Class for NEED_DS or NEED_KEY */
|
||||||
return rc;
|
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;
|
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 */
|
#endif /* HAVE_DNSSEC */
|
||||||
|
|||||||
@@ -340,7 +340,7 @@ int is_local_answer(time_t now, int first, char *name)
|
|||||||
return rc;
|
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;
|
int trunc = 0;
|
||||||
unsigned char *p;
|
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))
|
if (flags & (F_NXDOMAIN | F_NOERR))
|
||||||
log_query(flags | gotname | F_NEG | F_CONFIG | F_FORWARD, name, NULL, NULL);
|
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)))
|
if (!(p = skip_questions(header, size)))
|
||||||
return 0;
|
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;
|
int subnet, cacheable, forwarded = 0;
|
||||||
size_t edns0_len;
|
size_t edns0_len;
|
||||||
unsigned char *pheader;
|
unsigned char *pheader;
|
||||||
|
int ede = -1;
|
||||||
(void)do_bit;
|
(void)do_bit;
|
||||||
|
|
||||||
if (header->hb4 & HB4_CD)
|
if (header->hb4 & HB4_CD)
|
||||||
@@ -270,7 +271,10 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
|||||||
|
|
||||||
/* no available server. */
|
/* no available server. */
|
||||||
if (!lookup_domain(daemon->namebuff, gotname, &first, &last))
|
if (!lookup_domain(daemon->namebuff, gotname, &first, &last))
|
||||||
goto reply;
|
{
|
||||||
|
ede = EDE_NOT_READY;
|
||||||
|
goto reply;
|
||||||
|
}
|
||||||
|
|
||||||
/* Configured answer. */
|
/* Configured answer. */
|
||||||
if ((flags = is_local_answer(now, first, daemon->namebuff)))
|
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 */
|
/* could not send on, prepare to return */
|
||||||
header->id = htons(forward->frec_src.orig_id);
|
header->id = htons(forward->frec_src.orig_id);
|
||||||
free_frec(forward); /* cancel */
|
free_frec(forward); /* cancel */
|
||||||
|
ede = EDE_NETERR;
|
||||||
|
|
||||||
reply:
|
reply:
|
||||||
if (udpfd != -1)
|
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;
|
return 0;
|
||||||
|
|
||||||
if (oph)
|
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 defined(HAVE_CONNTRACK) && defined(HAVE_UBUS)
|
||||||
if (option_bool(OPT_CMARK_ALST_EN))
|
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,
|
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 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;
|
unsigned char *pheader, *sizep;
|
||||||
char **sets = 0;
|
char **sets = 0;
|
||||||
@@ -604,11 +616,10 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unsigned short udpsz;
|
|
||||||
|
|
||||||
/* If upstream is advertising a larger UDP packet size
|
/* If upstream is advertising a larger UDP packet size
|
||||||
than we allow, trim it so that we don't get overlarge
|
than we allow, trim it so that we don't get overlarge
|
||||||
requests for the client. We can't do this for signed packets. */
|
requests for the client. We can't do this for signed packets. */
|
||||||
|
unsigned short udpsz;
|
||||||
GETSHORT(udpsz, sizep);
|
GETSHORT(udpsz, sizep);
|
||||||
if (udpsz > daemon->edns_pktsz)
|
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;
|
union all_addr a;
|
||||||
a.log.rcode = rcode;
|
a.log.rcode = rcode;
|
||||||
|
a.log.ede = ede;
|
||||||
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
|
log_query(F_UPSTREAM | F_RCODE, "error", &a, NULL);
|
||||||
|
|
||||||
return resize_packet(header, n, pheader, plen);
|
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);
|
SET_RCODE(header, NXDOMAIN);
|
||||||
header->hb3 &= ~HB3_AA;
|
header->hb3 &= ~HB3_AA;
|
||||||
cache_secure = 0;
|
cache_secure = 0;
|
||||||
|
ede = EDE_BLOCKED;
|
||||||
}
|
}
|
||||||
else
|
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);
|
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||||
munged = 1;
|
munged = 1;
|
||||||
cache_secure = 0;
|
cache_secure = 0;
|
||||||
|
ede = EDE_BLOCKED;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (doctored)
|
if (doctored)
|
||||||
@@ -720,9 +734,14 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
|||||||
}
|
}
|
||||||
#endif
|
#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
|
/* do this after extract_addresses. Ensure NODATA reply and remove
|
||||||
nameserver info. */
|
nameserver info. */
|
||||||
|
|
||||||
if (munged)
|
if (munged)
|
||||||
{
|
{
|
||||||
header->ancount = htons(0);
|
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
|
/* 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
|
would invite infinite loops, since the answers to DNSKEY and DS queries
|
||||||
will not be cached, so they'll be repeated. */
|
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)
|
if (forward->flags & FREC_DNSKEY_QUERY)
|
||||||
status = dnssec_validate_by_ds(now, header, plen, daemon->namebuff, daemon->keyname, forward->class);
|
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),
|
!option_bool(OPT_DNSSEC_IGN_NS) && (forward->sentto->flags & SERV_DO_DNSSEC),
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
#ifdef HAVE_DUMPFILE
|
#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,
|
dump_packet((forward->flags & (FREC_DNSKEY_QUERY | FREC_DS_QUERY)) ? DUMP_SEC_BOGUS : DUMP_BOGUS,
|
||||||
header, (size_t)plen, &forward->sentto->addr, NULL);
|
header, (size_t)plen, &forward->sentto->addr, NULL);
|
||||||
#endif
|
#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
|
/* Can't validate, as we're missing key data. Put this
|
||||||
answer aside, whilst we get that. */
|
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;
|
struct frec *new = NULL;
|
||||||
int serverind;
|
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 */
|
/* validate routines leave name of required record in daemon->keyname */
|
||||||
nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
|
nn = dnssec_generate_query(header, ((unsigned char *) header) + server->edns_pktsz,
|
||||||
daemon->keyname, forward->class,
|
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);
|
hash = hash_questions(header, nn, daemon->namebuff);
|
||||||
|
|
||||||
if ((new = lookup_frec_by_query(hash, flags, FREC_DNSKEY_QUERY | FREC_DS_QUERY)))
|
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
|
#endif
|
||||||
server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
|
server_send_log(server, fd, header, nn, DUMP_SEC_QUERY,
|
||||||
F_NOEXTRA | F_DNSSEC, daemon->keyname,
|
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++;
|
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;
|
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0, bogusanswer = 0;
|
||||||
size_t nn;
|
size_t nn;
|
||||||
|
int ede = -1;
|
||||||
|
|
||||||
(void)status;
|
(void)status;
|
||||||
|
|
||||||
@@ -1085,36 +1105,40 @@ static void return_reply(time_t now, struct frec *forward, struct dns_header *he
|
|||||||
no_cache_dnssec = 1;
|
no_cache_dnssec = 1;
|
||||||
|
|
||||||
#ifdef HAVE_DNSSEC
|
#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;
|
no_cache_dnssec = 0;
|
||||||
|
|
||||||
if (status == STAT_TRUNCATED)
|
if (STAT_ISEQUAL(status, STAT_TRUNCATED))
|
||||||
header->hb3 |= HB3_TC;
|
header->hb3 |= HB3_TC;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char *result, *domain = "result";
|
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";
|
result = "ABANDONED";
|
||||||
status = STAT_BOGUS;
|
status = STAT_BOGUS;
|
||||||
}
|
}
|
||||||
else
|
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))
|
if (STAT_ISEQUAL(status, STAT_SECURE))
|
||||||
domain = daemon->namebuff;
|
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)
|
log_query(F_SECSTAT, domain, &a, result);
|
||||||
cache_secure = 1;
|
|
||||||
else if (status == STAT_BOGUS)
|
|
||||||
{
|
|
||||||
no_cache_dnssec = 1;
|
|
||||||
bogusanswer = 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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,
|
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_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;
|
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);
|
ubus_event_bcast_connmark_allowlist_refused(mark, name);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
setup_reply(header, /* flags: */ 0);
|
setup_reply(header, /* flags: */ 0, EDE_BLOCKED);
|
||||||
|
|
||||||
if (!(p = skip_questions(header, qlen)))
|
if (!(p = skip_questions(header, qlen)))
|
||||||
return 0;
|
return 0;
|
||||||
@@ -1545,10 +1570,13 @@ void receive_query(struct listener *listen, time_t now)
|
|||||||
#ifdef HAVE_CONNTRACK
|
#ifdef HAVE_CONNTRACK
|
||||||
else if (!allowed)
|
else if (!allowed)
|
||||||
{
|
{
|
||||||
|
u16 swap = htons(EDE_BLOCKED);
|
||||||
|
|
||||||
m = answer_disallowed(header, (size_t)n, (u32)mark, is_single_query ? daemon->namebuff : NULL);
|
m = answer_disallowed(header, (size_t)n, (u32)mark, is_single_query ? daemon->namebuff : NULL);
|
||||||
|
|
||||||
if (have_pseudoheader && m != 0)
|
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)
|
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 */
|
/* limit the amount of work we do, to avoid cycling forever on loops in the DNS */
|
||||||
if (--(*keycount) == 0)
|
if (--(*keycount) == 0)
|
||||||
new_status = STAT_ABANDONED;
|
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);
|
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);
|
new_status = dnssec_validate_ds(now, header, n, name, keyname, class);
|
||||||
else
|
else
|
||||||
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
|
new_status = dnssec_validate_reply(now, header, n, name, keyname, &class,
|
||||||
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
|
!option_bool(OPT_DNSSEC_IGN_NS) && (server->flags & SERV_DO_DNSSEC),
|
||||||
NULL, NULL, NULL);
|
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;
|
break;
|
||||||
|
|
||||||
/* Can't validate because we need a key/DS whose name now in keyname.
|
/* 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,
|
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 ||
|
if ((start = dnssec_server(server, daemon->keyname, &first, &last)) == -1 ||
|
||||||
(m = tcp_talk(first, last, start, packet, m, have_mark, mark, &server)) == 0)
|
(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;
|
daemon->log_display_id = ++daemon->log_id;
|
||||||
|
|
||||||
log_query_mysockaddr(F_NOEXTRA | F_DNSSEC, keyname, &server->addr,
|
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);
|
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;
|
daemon->log_display_id = log_save;
|
||||||
|
|
||||||
if (new_status != STAT_OK)
|
if (!STAT_ISEQUAL(new_status, STAT_OK))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1877,6 +1905,8 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
|
|
||||||
while (1)
|
while (1)
|
||||||
{
|
{
|
||||||
|
int ede = -1;
|
||||||
|
|
||||||
if (query_count == TCP_MAX_QUERIES ||
|
if (query_count == TCP_MAX_QUERIES ||
|
||||||
!packet ||
|
!packet ||
|
||||||
!read_write(confd, &c1, 1, 1) || !read_write(confd, &c2, 1, 1) ||
|
!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
|
#ifdef HAVE_CONNTRACK
|
||||||
else if (!allowed)
|
else if (!allowed)
|
||||||
{
|
{
|
||||||
|
u16 swap = htons(EDE_BLOCKED);
|
||||||
|
|
||||||
m = answer_disallowed(header, size, (u32)mark, is_single_query ? daemon->namebuff : NULL);
|
m = answer_disallowed(header, size, (u32)mark, is_single_query ? daemon->namebuff : NULL);
|
||||||
|
|
||||||
if (have_pseudoheader && m != 0)
|
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
|
#endif
|
||||||
#ifdef HAVE_AUTH
|
#ifdef HAVE_AUTH
|
||||||
@@ -1998,7 +2031,9 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
!strchr(daemon->namebuff, '.') &&
|
!strchr(daemon->namebuff, '.') &&
|
||||||
strlen(daemon->namebuff) != 0)
|
strlen(daemon->namebuff) != 0)
|
||||||
flags = F_NOERR;
|
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];
|
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. */
|
/* 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)
|
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 */
|
/* get query name again for logging - may have been overwritten */
|
||||||
if (!(gotname = extract_request(header, (unsigned int)size, daemon->namebuff, &qtype)))
|
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);
|
serv, have_mark, mark, &keycount);
|
||||||
char *result, *domain = "result";
|
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";
|
result = "ABANDONED";
|
||||||
status = STAT_BOGUS;
|
status = STAT_BOGUS;
|
||||||
}
|
}
|
||||||
else
|
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))
|
if (STAT_ISEQUAL(status, STAT_SECURE))
|
||||||
domain = daemon->namebuff;
|
cache_secure = 1;
|
||||||
|
else if (STAT_ISEQUAL(status, STAT_BOGUS))
|
||||||
log_query(F_SECSTAT, domain, NULL, result);
|
|
||||||
|
|
||||||
if (status == STAT_BOGUS)
|
|
||||||
{
|
{
|
||||||
no_cache_dnssec = 1;
|
no_cache_dnssec = 1;
|
||||||
bogusanswer = 1;
|
bogusanswer = 1;
|
||||||
|
|
||||||
|
if (extract_request(header, m, daemon->namebuff, NULL))
|
||||||
|
domain = daemon->namebuff;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (status == STAT_SECURE)
|
log_query(F_SECSTAT, domain, &a, result);
|
||||||
cache_secure = 1;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -2080,7 +2120,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
|||||||
|
|
||||||
m = process_reply(header, now, serv, (unsigned int)m,
|
m = process_reply(header, now, serv, (unsigned int)m,
|
||||||
option_bool(OPT_NO_REBIND) && !norebind, no_cache_dnssec, cache_secure, bogusanswer,
|
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 == 0)
|
||||||
{
|
{
|
||||||
if (!(m = make_local_answer(flags, gotname, size, header, daemon->namebuff,
|
if (!(m = make_local_answer(flags, gotname, size, header, daemon->namebuff,
|
||||||
((char *) header) + 65536, first, last)))
|
((char *) header) + 65536, first, last, ede)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (have_pseudoheader)
|
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);
|
check_log_writer(1);
|
||||||
|
|||||||
@@ -1017,7 +1017,7 @@ unsigned int extract_request(struct dns_header *header, size_t qlen, char *name,
|
|||||||
return F_QUERY;
|
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 */
|
/* clear authoritative and truncated flags, set QR flag */
|
||||||
header->hb3 = (header->hb3 & ~(HB3_AA | HB3_TC )) | HB3_QR;
|
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;
|
union all_addr a;
|
||||||
a.log.rcode = REFUSED;
|
a.log.rcode = REFUSED;
|
||||||
|
a.log.ede = ede;
|
||||||
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
log_query(F_CONFIG | F_RCODE, "error", &a, NULL);
|
||||||
SET_RCODE(header, REFUSED);
|
SET_RCODE(header, REFUSED);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user