Commit fa14bec8 authored by Simon Kelley's avatar Simon Kelley

Major tidy up of EDNS0 handling and computation/use of udp packet size.

parent 14a4ae88
...@@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, char **cut) ...@@ -81,7 +81,8 @@ int in_zone(struct auth_zone *zone, char *name, char **cut)
} }
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr, int local_query) size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t now, union mysockaddr *peer_addr,
int local_query, int do_bit, int have_pseudoheader)
{ {
char *name = daemon->namebuff; char *name = daemon->namebuff;
unsigned char *p, *ansp; unsigned char *p, *ansp;
...@@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n ...@@ -820,6 +821,11 @@ size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, time_t n
header->ancount = htons(anscount); header->ancount = htons(anscount);
header->nscount = htons(authcount); header->nscount = htons(authcount);
header->arcount = htons(0); header->arcount = htons(0);
/* Advertise our packet size limit in our reply */
if (have_pseudoheader)
return add_pseudoheader(header, ansp - (unsigned char *)header, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
return ansp - (unsigned char *)header; return ansp - (unsigned char *)header;
} }
......
...@@ -1113,7 +1113,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff, ...@@ -1113,7 +1113,7 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *namebuff,
int no_cache, int secure, int *doctored); int no_cache, int secure, int *doctored);
size_t answer_request(struct dns_header *header, char *limit, size_t qlen, size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int *ad_reqd, int *do_bit); time_t now, int ad_reqd, int do_bit, int have_pseudoheader);
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name, int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
struct bogus_addr *addr, time_t now); struct bogus_addr *addr, time_t now);
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr); int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
...@@ -1123,6 +1123,8 @@ int check_for_local_domain(char *name, time_t now); ...@@ -1123,6 +1123,8 @@ int check_for_local_domain(char *name, time_t now);
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff); unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
size_t resize_packet(struct dns_header *header, size_t plen, size_t resize_packet(struct dns_header *header, size_t plen,
unsigned char *pheader, size_t hlen); unsigned char *pheader, size_t hlen);
size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do);
size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3); size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysockaddr *l3);
size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source); size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, union mysockaddr *source);
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
...@@ -1141,7 +1143,8 @@ int private_net(struct in_addr addr, int ban_localhost); ...@@ -1141,7 +1143,8 @@ int private_net(struct in_addr addr, int ban_localhost);
/* auth.c */ /* auth.c */
#ifdef HAVE_AUTH #ifdef HAVE_AUTH
size_t answer_auth(struct dns_header *header, char *limit, size_t qlen, size_t answer_auth(struct dns_header *header, char *limit, size_t qlen,
time_t now, union mysockaddr *peer_addr, int local_query); time_t now, union mysockaddr *peer_addr, int local_query,
int do_bit, int have_pseudoheader);
int in_zone(struct auth_zone *zone, char *name, char **cut); int in_zone(struct auth_zone *zone, char *name, char **cut);
#endif #endif
......
...@@ -67,7 +67,6 @@ static char *algo_digest_name(int algo) ...@@ -67,7 +67,6 @@ static char *algo_digest_name(int algo)
case 12: return "gosthash94"; case 12: return "gosthash94";
case 13: return "sha256"; case 13: return "sha256";
case 14: return "sha384"; case 14: return "sha384";
default: return NULL; default: return NULL;
} }
} }
......
This diff is collapsed.
...@@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int (*callback)()) ...@@ -288,7 +288,8 @@ int iface_enumerate(int family, void *parm, int (*callback)())
rta = RTA_NEXT(rta, len1); rta = RTA_NEXT(rta, len1);
} }
if (inaddr && mac && callback_ok) if (!(neigh->ndm_state & (NUD_NOARP | NUD_INCOMPLETE | NUD_FAILED)) &&
inaddr && mac && callback_ok)
if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm))) if (!((*callback)(neigh->ndm_family, inaddr, mac, maclen, parm)))
callback_ok = 0; callback_ok = 0;
} }
......
...@@ -489,8 +489,8 @@ struct macparm { ...@@ -489,8 +489,8 @@ struct macparm {
union mysockaddr *l3; union mysockaddr *l3;
}; };
static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit, size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
int optno, unsigned char *opt, size_t optlen, int set_do) unsigned short udp_sz, int optno, unsigned char *opt, size_t optlen, int set_do)
{ {
unsigned char *lenp, *datap, *p; unsigned char *lenp, *datap, *p;
int rdlen, is_sign; int rdlen, is_sign;
...@@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned ...@@ -508,7 +508,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
return plen; return plen;
*p++ = 0; /* empty name */ *p++ = 0; /* empty name */
PUTSHORT(T_OPT, p); PUTSHORT(T_OPT, p);
PUTSHORT(SAFE_PKTSZ, p); /* max packet length, this will be overwritten */ PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
PUTSHORT(0, p); /* extended RCODE and version */ PUTSHORT(0, p); /* extended RCODE and version */
PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */ PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
lenp = p; lenp = p;
...@@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p ...@@ -594,7 +594,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
if (!match) if (!match)
return 1; /* continue */ return 1; /* continue */
parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0); parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, PACKETSZ, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
return 0; /* done */ return 0; /* done */
} }
...@@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock ...@@ -603,12 +603,6 @@ size_t add_mac(struct dns_header *header, size_t plen, char *limit, union mysock
{ {
struct macparm parm; struct macparm parm;
/* Must have an existing pseudoheader as the only ar-record,
or have no ar-records. Must also not be signed */
if (ntohs(header->arcount) > 1)
return plen;
parm.header = header; parm.header = header;
parm.limit = (unsigned char *)limit; parm.limit = (unsigned char *)limit;
parm.plen = plen; parm.plen = plen;
...@@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio ...@@ -699,13 +693,13 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio
struct subnet_opt opt; struct subnet_opt opt;
len = calc_subnet_opt(&opt, source); len = calc_subnet_opt(&opt, source);
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0); return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
} }
#ifdef HAVE_DNSSEC #ifdef HAVE_DNSSEC
size_t add_do_bit(struct dns_header *header, size_t plen, char *limit) size_t add_do_bit(struct dns_header *header, size_t plen, char *limit)
{ {
return add_pseudoheader(header, plen, (unsigned char *)limit, 0, NULL, 0, 1); return add_pseudoheader(header, plen, (unsigned char *)limit, PACKETSZ, 0, NULL, 0, 1);
} }
#endif #endif
...@@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now) ...@@ -1525,16 +1519,16 @@ static unsigned long crec_ttl(struct crec *crecp, time_t now)
/* return zero if we can't answer from cache, or packet size if we can */ /* return zero if we can't answer from cache, or packet size if we can */
size_t answer_request(struct dns_header *header, char *limit, size_t qlen, size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
struct in_addr local_addr, struct in_addr local_netmask, struct in_addr local_addr, struct in_addr local_netmask,
time_t now, int *ad_reqd, int *do_bit) time_t now, int ad_reqd, int do_bit, int have_pseudoheader)
{ {
char *name = daemon->namebuff; char *name = daemon->namebuff;
unsigned char *p, *ansp, *pheader; unsigned char *p, *ansp;
unsigned int qtype, qclass; unsigned int qtype, qclass;
struct all_addr addr; struct all_addr addr;
int nameoffset; int nameoffset;
unsigned short flag; unsigned short flag;
int q, ans, anscount = 0, addncount = 0; int q, ans, anscount = 0, addncount = 0;
int dryrun = 0, sec_reqd = 0, have_pseudoheader = 0; int dryrun = 0;
struct crec *crecp; struct crec *crecp;
int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1; int nxdomain = 0, auth = 1, trunc = 0, sec_data = 1;
struct mx_srv_record *rec; struct mx_srv_record *rec;
...@@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1550,35 +1544,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (header->hb4 & HB4_CD) if (header->hb4 & HB4_CD)
sec_data = 0; sec_data = 0;
/* RFC 6840 5.7 */
*ad_reqd = header->hb4 & HB4_AD;
*do_bit = 0;
/* If there is an additional data section then it will be overwritten by /* If there is an additional data section then it will be overwritten by
partial replies, so we have to do a dry run to see if we can answer partial replies, so we have to do a dry run to see if we can answer
the query. */ the query. */
if (ntohs(header->arcount) != 0) if (ntohs(header->arcount) != 0)
{ dryrun = 1;
dryrun = 1;
/* If there's an additional section, there might be an EDNS(0) pseudoheader */
if (find_pseudoheader(header, qlen, NULL, &pheader, NULL))
{
unsigned short flags;
have_pseudoheader = 1;
pheader += 4; /* udp size, ext_rcode */
GETSHORT(flags, pheader);
if ((sec_reqd = flags & 0x8000))
{
*do_bit = 1;/* do bit */
*ad_reqd = 1;
}
}
}
for (rec = daemon->mxnames; rec; rec = rec->next) for (rec = daemon->mxnames; rec; rec = rec->next)
rec->offset = 0; rec->offset = 0;
...@@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1603,11 +1573,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
GETSHORT(qtype, p); GETSHORT(qtype, p);
GETSHORT(qclass, p); GETSHORT(qclass, p);
/* Don't filter RRSIGS from answers to ANY queries, even if do-bit
not set. */
if (qtype == T_ANY)
*do_bit = 1;
ans = 0; /* have we answered this question */ ans = 0; /* have we answered this question */
if (qtype == T_TXT || qtype == T_ANY) if (qtype == T_TXT || qtype == T_ANY)
...@@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1739,7 +1704,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
the zone is unsigned, which implies that we're doing the zone is unsigned, which implies that we're doing
validation. */ validation. */
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) ||
!sec_reqd || !do_bit ||
(option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK))) (option_bool(OPT_DNSSEC_VALID) && !(crecp->flags & F_DNSSECOK)))
{ {
do do
...@@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1927,7 +1892,7 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
} }
/* If the client asked for DNSSEC don't use cached data. */ /* If the client asked for DNSSEC don't use cached data. */
if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !sec_reqd || !(crecp->flags & F_DNSSECOK)) if ((crecp->flags & (F_HOSTS | F_DHCP | F_CONFIG)) || !do_bit || !(crecp->flags & F_DNSSECOK))
do do
{ {
/* don't answer wildcard queries with data not from /etc/hosts /* don't answer wildcard queries with data not from /etc/hosts
...@@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -1961,17 +1926,12 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
if (crecp->flags & F_NEG) if (crecp->flags & F_NEG)
{ {
/* We don't cache NSEC records, so if a DNSSEC-validated negative answer ans = 1;
is cached and the client wants DNSSEC, forward rather than answering from the cache */ auth = 0;
if (!sec_reqd || !(crecp->flags & F_DNSSECOK)) if (crecp->flags & F_NXDOMAIN)
{ nxdomain = 1;
ans = 1; if (!dryrun)
auth = 0; log_query(crecp->flags, name, NULL, NULL);
if (crecp->flags & F_NXDOMAIN)
nxdomain = 1;
if (!dryrun)
log_query(crecp->flags, name, NULL, NULL);
}
} }
else else
{ {
...@@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen, ...@@ -2209,10 +2169,11 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
len = ansp - (unsigned char *)header; len = ansp - (unsigned char *)header;
/* Advertise our packet size limit in our reply */
if (have_pseudoheader) if (have_pseudoheader)
len = add_pseudoheader(header, len, (unsigned char *)limit, 0, NULL, 0, sec_reqd); len = add_pseudoheader(header, len, (unsigned char *)limit, daemon->edns_pktsz, 0, NULL, 0, do_bit);
if (*ad_reqd && sec_data) if (ad_reqd && sec_data)
header->hb4 |= HB4_AD; header->hb4 |= HB4_AD;
else else
header->hb4 &= ~HB4_AD; header->hb4 &= ~HB4_AD;
......
...@@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode) ...@@ -243,7 +243,7 @@ size_t rrfilter(struct dns_header *header, size_t plen, int mode)
for (p = rrs[0], i = 1; i < rr_found; i += 2) for (p = rrs[0], i = 1; i < rr_found; i += 2)
{ {
unsigned char *start = rrs[i]; unsigned char *start = rrs[i];
unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)(header+1)) + plen; unsigned char *end = (i != rr_found - 1) ? rrs[i+1] : ((unsigned char *)header) + plen;
memmove(p, start, end-start); memmove(p, start, end-start);
p += end-start; p += end-start;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment