mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Handle extending EDNS0 OPT RR.
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
109
src/edns0.c
109
src/edns0.c
@@ -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;
|
||||
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;
|
||||
|
||||
if (!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)))
|
||||
{
|
||||
if (is_sign)
|
||||
return plen;
|
||||
p = find_pseudoheader(header, plen, NULL, &udp_len, &is_sign, &is_last);
|
||||
|
||||
/* 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
|
||||
if (is_sign)
|
||||
return plen;
|
||||
|
||||
if (p)
|
||||
{
|
||||
/* Existing header */
|
||||
int i;
|
||||
unsigned short code, len, flags;
|
||||
unsigned short code, len;
|
||||
|
||||
/* 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 */
|
||||
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;
|
||||
@@ -166,21 +152,60 @@ size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *l
|
||||
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)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user