mirror of
https://github.com/pi-hole/dnsmasq.git
synced 2025-12-19 18:28:25 +00:00
Commit to allow master merge.
This commit is contained in:
@@ -81,10 +81,10 @@ int main (int argc, char **argv)
|
||||
umask(022); /* known umask, create leases and pid files as 0644 */
|
||||
|
||||
read_opts(argc, argv, compile_opts);
|
||||
if (option_bool(OPT_DNSSEC_VALIDATE))
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
if (daemon->doctors) exit(1); /* TODO */
|
||||
if (daemon->edns_pktsz < PACKETSZ)
|
||||
daemon->edns_pktsz = option_bool(OPT_DNSSEC_VALIDATE) ? EDNS_PKTSZ : PACKETSZ;
|
||||
daemon->edns_pktsz = option_bool(OPT_DNSSEC_VALID) ? EDNS_PKTSZ : PACKETSZ;
|
||||
daemon->packet_buff_sz = daemon->edns_pktsz > DNSMASQ_PACKETSZ ?
|
||||
daemon->edns_pktsz : DNSMASQ_PACKETSZ;
|
||||
daemon->packet = safe_malloc(daemon->packet_buff_sz);
|
||||
@@ -1302,7 +1302,7 @@ static int set_dns_listeners(time_t now, fd_set *set, int *maxfdp)
|
||||
|
||||
/* will we be able to get memory? */
|
||||
if (daemon->port != 0)
|
||||
get_new_frec(now, &wait);
|
||||
get_new_frec(now, &wait, 0);
|
||||
|
||||
for (serverfdp = daemon->sfds; serverfdp; serverfdp = serverfdp->next)
|
||||
{
|
||||
|
||||
@@ -228,7 +228,7 @@ struct event_desc {
|
||||
#define OPT_QUIET_DHCP 42
|
||||
#define OPT_QUIET_DHCP6 43
|
||||
#define OPT_QUIET_RA 44
|
||||
#define OPT_DNSSEC_VALIDATE 45
|
||||
#define OPT_DNSSEC_VALID 45
|
||||
#define OPT_LAST 46
|
||||
|
||||
/* extra flags for my_syslog, we use a couple of facilities since they are known
|
||||
@@ -352,7 +352,7 @@ struct crec {
|
||||
int uid; /* -1 if union is interface-name */
|
||||
} cname;
|
||||
struct {
|
||||
struct keydata *keydata;
|
||||
struct blockdata *keydata;
|
||||
unsigned char algo;
|
||||
unsigned char digest; /* DS only */
|
||||
unsigned short keytag;
|
||||
@@ -499,9 +499,20 @@ struct hostsfile {
|
||||
int index; /* matches to cache entries for logging */
|
||||
};
|
||||
|
||||
|
||||
/* 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 FREC_NOREBIND 1
|
||||
#define FREC_CHECKING_DISABLED 2
|
||||
#define FREC_HAS_SUBNET 4
|
||||
#define FREC_DNSSEC_QUERY 8
|
||||
#define FREC_DNSKEY_QUERY 16
|
||||
#define FREC_DS_QUERY 32
|
||||
|
||||
struct frec {
|
||||
union mysockaddr source;
|
||||
@@ -516,6 +527,12 @@ struct frec {
|
||||
int fd, forwardall, flags;
|
||||
unsigned int crc;
|
||||
time_t time;
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct blockdata *stash; /* Saved reply, whilst we validate */
|
||||
size_t stash_len;
|
||||
struct frec *dependent; /* Query awaiting internally-generated DNSKEY or DS query */
|
||||
struct frec *blocking_query; /* Query which is blocking us. */
|
||||
#endif
|
||||
struct frec *next;
|
||||
};
|
||||
|
||||
@@ -954,9 +971,9 @@ char *cache_get_name(struct crec *crecp);
|
||||
char *cache_get_cname_target(struct crec *crecp);
|
||||
struct crec *cache_enumerate(int init);
|
||||
#ifdef HAVE_DNSSEC
|
||||
struct keydata *keydata_alloc(char *data, size_t len);
|
||||
size_t keydata_walk(struct keydata **key, unsigned char **p, size_t cnt);
|
||||
void keydata_free(struct keydata *blocks);
|
||||
struct blockdata *blockdata_alloc(char *data, size_t len);
|
||||
size_t blockdata_walk(struct blockdata **key, unsigned char **p, size_t cnt);
|
||||
void blockdata_free(struct blockdata *blocks);
|
||||
#endif
|
||||
|
||||
/* domain.c */
|
||||
@@ -992,6 +1009,9 @@ size_t resize_packet(struct dns_header *header, size_t plen,
|
||||
unsigned char *pheader, size_t hlen);
|
||||
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);
|
||||
#ifdef HAVE_DNSSEC
|
||||
size_t add_do_bit(struct dns_header *header, size_t plen, char *limit);
|
||||
#endif
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer);
|
||||
int add_resource_record(struct dns_header *header, char *limit, int *truncp,
|
||||
int nameoffset, unsigned char **pp, unsigned long ttl,
|
||||
@@ -1010,7 +1030,7 @@ int in_zone(struct auth_zone *zone, char *name, char **cut);
|
||||
#endif
|
||||
|
||||
/* dnssec.c */
|
||||
int dnssec_validate(struct dns_header *header, size_t plen);
|
||||
int dnssec_validate(int flags, struct dns_header *header, size_t plen);
|
||||
|
||||
/* util.c */
|
||||
void rand_init(void);
|
||||
@@ -1072,7 +1092,7 @@ void receive_query(struct listener *listen, time_t now);
|
||||
unsigned char *tcp_request(int confd, time_t now,
|
||||
union mysockaddr *local_addr, struct in_addr netmask, int auth_dns);
|
||||
void server_gone(struct server *server);
|
||||
struct frec *get_new_frec(time_t now, int *wait);
|
||||
struct frec *get_new_frec(time_t now, int *wait, int force);
|
||||
int send_from(int fd, int nowild, char *packet, size_t len,
|
||||
union mysockaddr *to, struct all_addr *source,
|
||||
unsigned int iface);
|
||||
|
||||
14
src/dnssec.c
14
src/dnssec.c
@@ -713,7 +713,7 @@ int dnssec_parsekey(struct dns_header *header, size_t pktlen, char *owner, unsig
|
||||
int rdlen, unsigned char *rdata)
|
||||
{
|
||||
int flags, proto, alg;
|
||||
struct keydata *key; struct crec *crecp;
|
||||
struct blockdata *key; struct crec *crecp;
|
||||
unsigned char *ordata = rdata; int ordlen = rdlen;
|
||||
|
||||
CHECKED_GETSHORT(flags, rdata, rdlen);
|
||||
@@ -726,7 +726,7 @@ int dnssec_parsekey(struct dns_header *header, size_t pktlen, char *owner, unsig
|
||||
if (!(flags & 0x100))
|
||||
return 0;
|
||||
|
||||
key = keydata_alloc((char*)rdata, rdlen);
|
||||
key = blockdata_alloc((char*)rdata, rdlen);
|
||||
|
||||
/* TODO: time(0) is correct here? */
|
||||
crecp = cache_insert(owner, NULL, time(0), ttl, F_FORWARD | F_DNSKEY);
|
||||
@@ -741,7 +741,7 @@ int dnssec_parsekey(struct dns_header *header, size_t pktlen, char *owner, unsig
|
||||
}
|
||||
else
|
||||
{
|
||||
keydata_free(key);
|
||||
blockdata_free(key);
|
||||
/* TODO: if insertion really might fail, verify we don't depend on cache
|
||||
insertion success for validation workflow correctness */
|
||||
printf("DNSKEY: cache insertion failure\n");
|
||||
@@ -754,7 +754,7 @@ int dnssec_parseds(struct dns_header *header, size_t pktlen, char *owner, unsign
|
||||
int rdlen, unsigned char *rdata)
|
||||
{
|
||||
int keytag, algo, dig;
|
||||
struct keydata *key; struct crec *crec_ds, *crec_key;
|
||||
struct blockdata *key; struct crec *crec_ds, *crec_key;
|
||||
|
||||
CHECKED_GETSHORT(keytag, rdata, rdlen);
|
||||
CHECKED_GETCHAR(algo, rdata, rdlen);
|
||||
@@ -763,13 +763,13 @@ int dnssec_parseds(struct dns_header *header, size_t pktlen, char *owner, unsign
|
||||
if (!digestalg_supported(dig))
|
||||
return 0;
|
||||
|
||||
key = keydata_alloc((char*)rdata, rdlen);
|
||||
key = blockdata_alloc((char*)rdata, rdlen);
|
||||
|
||||
/* TODO: time(0) is correct here? */
|
||||
crec_ds = cache_insert(owner, NULL, time(0), ttl, F_FORWARD | F_DS);
|
||||
if (!crec_ds)
|
||||
{
|
||||
keydata_free(key);
|
||||
blockdata_free(key);
|
||||
/* TODO: if insertion really might fail, verify we don't depend on cache
|
||||
insertion success for validation workflow correctness */
|
||||
printf("DS: cache insertion failure\n");
|
||||
@@ -800,7 +800,7 @@ int dnssec_parseds(struct dns_header *header, size_t pktlen, char *owner, unsign
|
||||
return 0;
|
||||
}
|
||||
|
||||
int dnssec_validate(struct dns_header *header, size_t pktlen)
|
||||
int dnssec1_validate(struct dns_header *header, size_t pktlen)
|
||||
{
|
||||
unsigned char *p, *reply;
|
||||
char *owner = daemon->namebuff;
|
||||
|
||||
161
src/forward.c
161
src/forward.c
@@ -270,7 +270,7 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
if (gotname)
|
||||
flags = search_servers(now, &addrp, gotname, daemon->namebuff, &type, &domain, &norebind);
|
||||
|
||||
if (!flags && !(forward = get_new_frec(now, NULL)))
|
||||
if (!flags && !(forward = get_new_frec(now, NULL, 0)))
|
||||
/* table full - server failure. */
|
||||
flags = F_NEG;
|
||||
|
||||
@@ -342,6 +342,11 @@ static int forward_query(int udpfd, union mysockaddr *udpaddr,
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
plen = add_do_bit(header, plen, ((char *) header) + PACKETSZ);
|
||||
#endif
|
||||
|
||||
while (1)
|
||||
{
|
||||
/* only send to servers dealing with our domain.
|
||||
@@ -447,12 +452,13 @@ 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 checking_disabled, int check_subnet, union mysockaddr *query_source)
|
||||
int no_cache, int cache_secure, int check_subnet, union mysockaddr *query_source)
|
||||
{
|
||||
unsigned char *pheader, *sizep;
|
||||
char **sets = 0;
|
||||
int munged = 0, is_sign;
|
||||
size_t plen;
|
||||
int squash_ad = 0;
|
||||
|
||||
#ifdef HAVE_IPSET
|
||||
/* Similar algorithm to search_servers. */
|
||||
@@ -495,10 +501,20 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* RFC 4035 sect 4.6 para 3 */
|
||||
if (!is_sign && !option_bool(OPT_DNSSEC_PROXY))
|
||||
header->hb4 &= ~HB4_AD;
|
||||
squash_ad = 1;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID))
|
||||
squash_ad = no_cache;
|
||||
|
||||
if (cache_secure)
|
||||
header->hb4 |= HB4_AD;
|
||||
#endif
|
||||
|
||||
if (squash_ad)
|
||||
header->hb4 &= ~HB4_AD;
|
||||
|
||||
if (OPCODE(header) != QUERY || (RCODE(header) != NOERROR && RCODE(header) != NXDOMAIN))
|
||||
return n;
|
||||
@@ -513,11 +529,6 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
server->flags |= SERV_WARNED_RECURSIVE;
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
printf("validate\n");
|
||||
dnssec_validate(header, n);
|
||||
#endif
|
||||
|
||||
if (daemon->bogus_addr && RCODE(header) != NXDOMAIN &&
|
||||
check_for_bogus_wildcard(header, n, daemon->namebuff, daemon->bogus_addr, now))
|
||||
{
|
||||
@@ -539,7 +550,7 @@ static size_t process_reply(struct dns_header *header, time_t now, struct server
|
||||
SET_RCODE(header, NOERROR);
|
||||
}
|
||||
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, checking_disabled))
|
||||
if (extract_addresses(header, n, daemon->namebuff, now, sets, is_sign, check_rebind, no_cache))
|
||||
{
|
||||
my_syslog(LOG_WARNING, _("possible DNS-rebind attack detected: %s"), daemon->namebuff);
|
||||
munged = 1;
|
||||
@@ -598,8 +609,6 @@ void reply_query(int fd, int family, time_t now)
|
||||
!(forward = lookup_frec(ntohs(header->id), questions_crc(header, n, daemon->namebuff))))
|
||||
return;
|
||||
|
||||
server = forward->sentto;
|
||||
|
||||
if ((RCODE(header) == SERVFAIL || RCODE(header) == REFUSED) &&
|
||||
!option_bool(OPT_ORDER) &&
|
||||
forward->forwardall == 0)
|
||||
@@ -625,6 +634,8 @@ void reply_query(int fd, int family, time_t now)
|
||||
}
|
||||
}
|
||||
|
||||
server = forward->sentto;
|
||||
|
||||
if ((forward->sentto->flags & SERV_TYPE) == 0)
|
||||
{
|
||||
if (RCODE(header) == SERVFAIL || RCODE(header) == REFUSED)
|
||||
@@ -653,12 +664,106 @@ void reply_query(int fd, int family, time_t now)
|
||||
if (forward->forwardall == 0 || --forward->forwardall == 1 ||
|
||||
(RCODE(header) != REFUSED && RCODE(header) != SERVFAIL))
|
||||
{
|
||||
int check_rebind = !(forward->flags & FREC_NOREBIND);
|
||||
int check_rebind = 0, no_cache_dnssec = 0, cache_secure = 0;
|
||||
|
||||
if (!option_bool(OPT_NO_REBIND))
|
||||
check_rebind = 0;
|
||||
if (option_bool(OPT_NO_REBIND))
|
||||
check_rebind = !(forward->flags & FREC_NOREBIND);
|
||||
|
||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, forward->flags & FREC_CHECKING_DISABLED,
|
||||
/* Don't cache replies where DNSSEC validation was turned off, either
|
||||
the upstream server told us so, or the original query specified it. */
|
||||
if ((header->hb4 & HB4_CD) || (forward->flags & FREC_CHECKING_DISABLED))
|
||||
no_cache_dnssec = 1;
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (option_bool(OPT_DNSSEC_VALID) && !(forward->flags & FREC_CHECKING_DISABLED))
|
||||
{
|
||||
int status = dnssec_validate(forward->flags, header, n);
|
||||
|
||||
/* 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)
|
||||
{
|
||||
struct frec *new;
|
||||
if ((forward->stash = blockdata_alloc((char *)header, n)))
|
||||
{
|
||||
forward->stash_len = n;
|
||||
|
||||
/* Now formulate a query for the missing data. */
|
||||
nn = dnssec_generate_query(header, status);
|
||||
new = get_new_frec(now, NULL, 1);
|
||||
|
||||
if (new)
|
||||
{
|
||||
int fd;
|
||||
|
||||
new = forward; /* copy everything, then overwrite */
|
||||
new->dependent = forward; /* to find query awaiting new one. */
|
||||
forward->blocking_query = new; /* for garbage cleaning */
|
||||
new->flags |= FREC_DNSSEC_QUERY;
|
||||
if (status == STAT_NEED_KEY)
|
||||
new->flags |= FREC_DNSKEY_QUERY; /* So we verify differently */
|
||||
else if (status == STAT_NEED_DS)
|
||||
new->flags |= FREC_DS_QUERY;
|
||||
new->crc = questions_crc(header, nn, daemon->namebuff);
|
||||
new->new_id = get_id(new->crc);
|
||||
|
||||
/* Don't resend this. */
|
||||
daemon->srv_save = NULL;
|
||||
|
||||
if (server->sfd)
|
||||
fd = server->sfd->fd;
|
||||
else
|
||||
#ifdef HAVE_IPV6
|
||||
/* Note that we use the same random port for the DNSSEC stuff */
|
||||
if (server->addr.sa.sa_family == AF_INET6)
|
||||
{
|
||||
fd = new->rfd6->fd;
|
||||
new->rfd6->refcount++;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
fd = new->rfd4->fd;
|
||||
new->rfd4->refcount++;
|
||||
}
|
||||
|
||||
/* Send DNSSEC query to same server as original query */
|
||||
while (sendto(fd, (char *)header, nn, 0, &server->addr.sa, sa_len(&server->addr)) == -1 && retry_send());
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Ok, we reached far enough up the chain-of-trust that we can validate something.
|
||||
Now wind back down, pulling back answers which wouldn't previously validate
|
||||
and validate them with the new data. Failure to find needed data here is an internal error.
|
||||
Once we get to the original answer (FREC_DNSSEC_QUERY not set) and it validates,
|
||||
return it to the original requestor. */
|
||||
while (forward->flags & FREC_DNSSEC_QUERY)
|
||||
{
|
||||
if (status == STAT_SECURE)
|
||||
extract_dnssec_replies();
|
||||
free_frec(forward);
|
||||
forward = forward->dependent;
|
||||
blockdata_retrieve_and_free(forward->stash, forward->stash_len, (void *)header);
|
||||
n = forward->stash_len;
|
||||
if (status == STAT_SECURE)
|
||||
{
|
||||
status = dnssec_validate(forward->flags, header, n);
|
||||
if (status == STAT_NEED_DS || status == STAT_NEED_KEY)
|
||||
my_syslog(LOG_ERR, _("Unexpected missing data for DNSSEC validation"));
|
||||
}
|
||||
}
|
||||
|
||||
if (status == STAT_SECURE)
|
||||
cache_secure = 1;
|
||||
/* TODO return SERVFAIL here */
|
||||
else if (status == STAT_BOGUS)
|
||||
no_cache_dnssec = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((nn = process_reply(header, now, server, (size_t)n, check_rebind, no_cache_dnssec, cache_secure,
|
||||
forward->flags & FREC_HAS_SUBNET, &forward->source)))
|
||||
{
|
||||
header->id = htons(forward->orig_id);
|
||||
@@ -1129,7 +1234,7 @@ unsigned char *tcp_request(int confd, time_t now,
|
||||
if (crc == questions_crc(header, (unsigned int)m, daemon->namebuff))
|
||||
m = process_reply(header, now, last_server, (unsigned int)m,
|
||||
option_bool(OPT_NO_REBIND) && !norebind, checking_disabled,
|
||||
check_subnet, &peer_addr);
|
||||
0, check_subnet, &peer_addr); /* TODO - cache secure */
|
||||
|
||||
break;
|
||||
}
|
||||
@@ -1163,6 +1268,9 @@ static struct frec *allocate_frec(time_t now)
|
||||
f->flags = 0;
|
||||
#ifdef HAVE_IPV6
|
||||
f->rfd6 = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_DNSSEC
|
||||
f->blocking_query = NULL;
|
||||
#endif
|
||||
daemon->frec_list = f;
|
||||
}
|
||||
@@ -1221,13 +1329,26 @@ static void free_frec(struct frec *f)
|
||||
|
||||
f->rfd6 = NULL;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
if (f->stash)
|
||||
blockdata_free(f->stash);
|
||||
|
||||
/* Anything we're waiting on is pointless now, too */
|
||||
if (f->blocking_query)
|
||||
free_frec(f->blocking_query);
|
||||
f->blocking_query = NULL;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
/* if wait==NULL return a free or older than TIMEOUT record.
|
||||
else return *wait zero if one available, or *wait is delay to
|
||||
when the oldest in-use record will expire. Impose an absolute
|
||||
limit of 4*TIMEOUT before we wipe things (for random sockets) */
|
||||
struct frec *get_new_frec(time_t now, int *wait)
|
||||
limit of 4*TIMEOUT before we wipe things (for random sockets).
|
||||
If force is set, always return a result, even if we have
|
||||
to allocate above the limit. */
|
||||
struct frec *get_new_frec(time_t now, int *wait, int force)
|
||||
{
|
||||
struct frec *f, *oldest, *target;
|
||||
int count;
|
||||
@@ -1276,7 +1397,7 @@ struct frec *get_new_frec(time_t now, int *wait)
|
||||
}
|
||||
|
||||
/* none available, calculate time 'till oldest record expires */
|
||||
if (count > daemon->ftabsize)
|
||||
if (!force && count > daemon->ftabsize)
|
||||
{
|
||||
static time_t last_log = 0;
|
||||
|
||||
|
||||
@@ -427,7 +427,7 @@ static struct {
|
||||
{ LOPT_IPSET, ARG_DUP, "/<domain>/<ipset>[,<ipset>...]", gettext_noop("Specify ipsets to which matching domains should be added"), NULL },
|
||||
{ LOPT_SYNTH, ARG_DUP, "<domain>,<range>,[<prefix>]", gettext_noop("Specify a domain and address range for synthesised names"), NULL },
|
||||
#ifdef HAVE_DNSSEC
|
||||
{ LOPT_SEC_VALID, OPT_DNSSEC_VALIDATE, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
|
||||
{ LOPT_SEC_VALID, OPT_DNSSEC_VALID, NULL, gettext_noop("Activate DNSSEC validation"), NULL },
|
||||
#endif
|
||||
#ifdef OPTION6_PREFIX_CLASS
|
||||
{ LOPT_PREF_CLSS, ARG_DUP, "set:tag,<class>", gettext_noop("Specify DHCPv6 prefix class"), NULL },
|
||||
|
||||
@@ -515,7 +515,7 @@ struct macparm {
|
||||
};
|
||||
|
||||
static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned char *limit,
|
||||
int optno, unsigned char *opt, size_t optlen)
|
||||
int optno, unsigned char *opt, size_t optlen, int set_do)
|
||||
{
|
||||
unsigned char *lenp, *datap, *p;
|
||||
int rdlen;
|
||||
@@ -531,7 +531,8 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
|
||||
*p++ = 0; /* empty name */
|
||||
PUTSHORT(T_OPT, p);
|
||||
PUTSHORT(daemon->edns_pktsz, p); /* max packet length */
|
||||
PUTLONG(0, p); /* extended RCODE */
|
||||
PUTSHORT(0, p); /* extended RCODE and version */
|
||||
PUTSHORT(set_do ? 0x8000 : 0, p); /* DO flag */
|
||||
lenp = p;
|
||||
PUTSHORT(0, p); /* RDLEN */
|
||||
rdlen = 0;
|
||||
@@ -543,7 +544,7 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
|
||||
else
|
||||
{
|
||||
int i, is_sign;
|
||||
unsigned short code, len;
|
||||
unsigned short code, len, flags;
|
||||
|
||||
if (ntohs(header->arcount) != 1 ||
|
||||
!(p = find_pseudoheader(header, plen, NULL, NULL, &is_sign)) ||
|
||||
@@ -551,7 +552,13 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
|
||||
(!(p = skip_name(p, header, plen, 10))))
|
||||
return plen;
|
||||
|
||||
p += 8; /* skip UDP length and RCODE */
|
||||
p += 6; /* skip UDP length and RCODE */
|
||||
GETSHORT(flags, p);
|
||||
if (set_do)
|
||||
{
|
||||
p -=2;
|
||||
PUTSHORT(flags | 0x8000, p);
|
||||
}
|
||||
|
||||
lenp = p;
|
||||
GETSHORT(rdlen, p);
|
||||
@@ -559,6 +566,10 @@ static size_t add_pseudoheader(struct dns_header *header, size_t plen, unsigned
|
||||
return plen; /* bad packet */
|
||||
datap = p;
|
||||
|
||||
/* no option to add */
|
||||
if (optno == 0)
|
||||
return plen;
|
||||
|
||||
/* check if option already there */
|
||||
for (i = 0; i + 4 < rdlen; i += len + 4)
|
||||
{
|
||||
@@ -602,7 +613,7 @@ static int filter_mac(int family, char *addrp, char *mac, size_t maclen, void *p
|
||||
if (!match)
|
||||
return 1; /* continue */
|
||||
|
||||
parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen);
|
||||
parm->plen = add_pseudoheader(parm->header, parm->plen, parm->limit, EDNS0_OPTION_MAC, (unsigned char *)mac, maclen, 0);
|
||||
|
||||
return 0; /* done */
|
||||
}
|
||||
@@ -681,9 +692,16 @@ size_t add_source_addr(struct dns_header *header, size_t plen, char *limit, unio
|
||||
struct subnet_opt opt;
|
||||
|
||||
len = calc_subnet_opt(&opt, source);
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len);
|
||||
return add_pseudoheader(header, plen, (unsigned char *)limit, EDNS0_OPTION_CLIENT_SUBNET, (unsigned char *)&opt, len, 0);
|
||||
}
|
||||
|
||||
#ifdef HAVE_DNSSEC
|
||||
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);
|
||||
}
|
||||
#endif
|
||||
|
||||
int check_source(struct dns_header *header, size_t plen, unsigned char *pseudoheader, union mysockaddr *peer)
|
||||
{
|
||||
/* Section 9.2, Check that subnet option in reply matches. */
|
||||
@@ -878,7 +896,7 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name)
|
||||
expired and cleaned out that way.
|
||||
Return 1 if we reject an address because it look like part of dns-rebinding attack. */
|
||||
int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t now,
|
||||
char **ipsets, int is_sign, int check_rebind, int checking_disabled)
|
||||
char **ipsets, int is_sign, int check_rebind, int no_cache_dnssec)
|
||||
{
|
||||
unsigned char *p, *p1, *endrr, *namep;
|
||||
int i, j, qtype, qclass, aqtype, aqclass, ardlen, res, searched_soa = 0;
|
||||
@@ -1118,15 +1136,13 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
|
||||
}
|
||||
|
||||
/* Don't put stuff from a truncated packet into the cache.
|
||||
Don't cache replies where DNSSEC validation was turned off, either
|
||||
the upstream server told us so, or the original query specified it.
|
||||
Don't cache replies from non-recursive nameservers, since we may get a
|
||||
reply containing a CNAME but not its target, even though the target
|
||||
does exist. */
|
||||
if (!(header->hb3 & HB3_TC) &&
|
||||
!(header->hb4 & HB4_CD) &&
|
||||
(header->hb4 & HB4_RA) &&
|
||||
!checking_disabled)
|
||||
!no_cache_dnssec)
|
||||
cache_end_insert();
|
||||
|
||||
return 0;
|
||||
|
||||
Reference in New Issue
Block a user