Handle extending EDNS0 OPT RR.

This commit is contained in:
Simon Kelley
2015-12-21 16:23:47 +00:00
parent 1d03016bbc
commit 5bb88f0963
4 changed files with 81 additions and 56 deletions

View File

@@ -1117,8 +1117,6 @@ size_t answer_request(struct dns_header *header, char *limit, size_t qlen,
int check_for_bogus_wildcard(struct dns_header *header, size_t qlen, char *name,
struct bogus_addr *addr, time_t now);
int check_for_ignored_address(struct dns_header *header, size_t qlen, struct bogus_addr *baddr);
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
size_t *len, unsigned char **p, int *is_sign);
int check_for_local_domain(char *name, time_t now);
unsigned int questions_crc(struct dns_header *header, size_t plen, char *buff);
size_t resize_packet(struct dns_header *header, size_t plen,
@@ -1514,6 +1512,8 @@ u16 *rrfilter_desc(int type);
int expand_workspace(unsigned char ***wkspc, int *szp, int new);
/* edns0.c */
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen,
size_t *len, unsigned char **p, int *is_sign, int *is_last);
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);

View File

@@ -2206,7 +2206,7 @@ size_t dnssec_generate_query(struct dns_header *header, char *end, char *name, i
ret = add_do_bit(header, p - (unsigned char *)header, end);
if (find_pseudoheader(header, ret, NULL, &p, NULL))
if (find_pseudoheader(header, ret, NULL, &p, NULL, NULL))
PUTSHORT(edns_pktsz, p);
return ret;

View File

@@ -16,12 +16,12 @@
#include "dnsmasq.h"
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign)
unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t *len, unsigned char **p, int *is_sign, int *is_last)
{
/* See if packet has an RFC2671 pseudoheader, and if so return a pointer to it.
also return length of pseudoheader in *len and pointer to the UDP size in *p
Finally, check to see if a packet is signed. If it is we cannot change a single bit before
forwarding. We look for SIG and TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
forwarding. We look for TSIG in the addition section, and TKEY queries (for GSS-TSIG) */
int i, arcount = ntohs(header->arcount);
unsigned char *ansp = (unsigned char *)(header+1);
@@ -76,8 +76,13 @@ unsigned char *find_pseudoheader(struct dns_header *header, size_t plen, size_t
{
if (len)
*len = ansp - start;
if (p)
*p = save;
if (is_last)
*is_last = (i == arcount-1);
ret = start;
}
else if (is_sign &&
@@ -100,50 +105,31 @@ struct macparm {
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)
{
unsigned char *lenp, *datap, *p;
int rdlen, is_sign;
if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
{
if (is_sign)
return plen;
unsigned char *lenp, *datap, *p, *udp_len, *buff = NULL;
int rdlen = 0, is_sign, is_last;
unsigned short flags = set_do ? 0x8000 : 0, rcode = 0;
/* We are adding the pseudoheader */
if (!(p = skip_questions(header, plen)) ||
!(p = skip_section(p,
ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
header, plen)))
return plen;
*p++ = 0; /* empty name */
PUTSHORT(T_OPT, p);
PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
PUTSHORT(0, p); /* extended RCODE and version */
PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
lenp = p;
PUTSHORT(0, p); /* RDLEN */
rdlen = 0;
if (((ssize_t)optlen) > (limit - (p + 4)))
return plen; /* Too big */
header->arcount = htons(ntohs(header->arcount) + 1);
datap = p;
}
else
p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
if (is_sign)
return plen;
if (p)
{
/* Existing header */
int i;
unsigned short code, len, flags;
/* Must be at the end, if exists */
if (ntohs(header->arcount) != 1 ||
is_sign ||
(!(p = skip_name(p, header, plen, 10))))
return plen;
p += 6; /* skip UDP length and RCODE */
unsigned short code, len;
p = udp_len;
GETSHORT(udp_sz, p);
GETSHORT(rcode, p);
GETSHORT(flags, p);
if (set_do)
{
p -=2;
PUTSHORT(flags | 0x8000, p);
flags |= 0x8000;
PUTSHORT(flags, p);
}
lenp = p;
@@ -165,22 +151,61 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
return plen;
p += len;
}
if (((ssize_t)optlen) > (limit - (p + 4)))
return plen; /* Too big */
/* If we're going to extend the RR, it has to be the last RR in the packet */
if (!is_last)
{
/* First, take a copy of the options. */
if (rdlen != 0 && (buff = whine_malloc(rdlen)))
memcpy(buff, datap, rdlen);
/* now, delete OPT RR */
plen = rrfilter(header, plen, 0);
/* Now, force addition of a new one */
p = NULL;
}
}
if (!p)
{
/* We are (re)adding the pseudoheader */
if (!(p = skip_questions(header, plen)) ||
!(p = skip_section(p,
ntohs(header->ancount) + ntohs(header->nscount) + ntohs(header->arcount),
header, plen)))
return plen;
*p++ = 0; /* empty name */
PUTSHORT(T_OPT, p);
PUTSHORT(udp_sz, p); /* max packet length, 512 if not given in EDNS0 header */
PUTSHORT(rcode, p); /* extended RCODE and version */
PUTSHORT(flags, p); /* DO flag */
lenp = p;
PUTSHORT(rdlen, p); /* RDLEN */
datap = p;
/* Copy back any options */
if (buff)
{
memcpy(p, buff, rdlen);
free(buff);
p += rdlen;
}
header->arcount = htons(ntohs(header->arcount) + 1);
}
if (((ssize_t)optlen) > (limit - (p + 4)))
return plen; /* Too big */
/* Add new option */
if (optno != 0)
{
PUTSHORT(optno, p);
PUTSHORT(optlen, p);
memcpy(p, opt, optlen);
p += optlen;
PUTSHORT(p - datap, lenp);
}
PUTSHORT(p - datap, lenp);
return p - (unsigned char *)header;
}
static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *parmv)

View File

@@ -276,7 +276,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
blockdata_retrieve(forward->stash, forward->stash_len, (void *)header);
plen = forward->stash_len;
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign) && !is_sign)
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
PUTSHORT(SAFE_PKTSZ, pheader);
if (forward->sentto->addr.sa.sa_family == AF_INET)
@@ -479,7 +479,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
}
#ifdef HAVE_DNSSEC
if (option_bool(OPT_DNSSEC_VALID) && !do_bit)
if (option_bool(OPT_DNSSEC_VALID) && (forward->flags & FREC_ADDED_PHEADER))
{
/* Difficult one here. If our client didn't send EDNS0, we will have set the UDP
packet size to 512. But that won't provide space for the RRSIGS in many cases.
@@ -489,7 +489,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
the truncated bit? */
unsigned char *pheader;
int is_sign;
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign))
if (find_pseudoheader(header, plen, NULL, &pheader, &is_sign, NULL) && !is_sign)
PUTSHORT(start->edns_pktsz, pheader);
}
#endif
@@ -584,7 +584,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
}
#endif
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign)))
if ((pheader = find_pseudoheader(header, n, &plen, &sizep, &is_sign, NULL)))
{
if (check_subnet && !check_source(header, plen, pheader, query_source))
{
@@ -779,7 +779,7 @@ void reply_query(int fd, int family, time_t now)
int is_sign;
/* recreate query from reply */
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign);
pheader = find_pseudoheader(header, (size_t)n, &plen, NULL, &is_sign, NULL);
if (!is_sign)
{
header->ancount = htons(0);
@@ -1313,7 +1313,7 @@ void receive_query(struct listener *listen, time_t now)
#endif
}
if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL))
if (find_pseudoheader(header, (size_t)n, NULL, &pheader, NULL, NULL))
{
unsigned short flags;
@@ -1569,7 +1569,7 @@ unsigned char *tcp_request(int confd, time_t now,
do_bit = 0;
if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL))
if (find_pseudoheader(header, (size_t)size, NULL, &pheader, NULL, NULL))
{
unsigned short flags;
@@ -1578,7 +1578,7 @@ unsigned char *tcp_request(int confd, time_t now,
GETSHORT(flags, pheader);
if (flags & 0x8000)
do_bit = 1;/* do bit */
do_bit = 1; /* do bit */
}
#ifdef HAVE_AUTH