unbound: Update to 1.26.2

Release notes at
    https://community.nlnetlabs.nl/t/unbound-1-26-2-released

Merge commit 'ce3304d97ba4861eabac759e538426a568aef0a5'

Security:	CVE-2026-35501
Security:	CVE-2026-50106
Security:	CVE-2026-96405
Security:	CVE-2026-97206
Security:	CVE-2026-109125
This commit is contained in:
Dag-Erling Smørgrav committed 2026-10-21 13:24:44 +00:00
commit c6d7a2478c
30 files changed
+317 -116

No files matched your search

+13 -12
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for unbound 1.26.1.
# Generated by GNU Autoconf 2.71 for unbound 1.26.2.
#
# Report bugs to <[email protected] or https://github.com/NLnetLabs/unbound/issues>.
#
@@ -622,8 +622,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
PACKAGE_VERSION='1.26.1'
PACKAGE_STRING='unbound 1.26.1'
PACKAGE_VERSION='1.26.2'
PACKAGE_STRING='unbound 1.26.2'
PACKAGE_BUGREPORT='[email protected] or https://github.com/NLnetLabs/unbound/issues'
PACKAGE_URL=''
@@ -1516,7 +1516,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures unbound 1.26.1 to adapt to many kinds of systems.
\`configure' configures unbound 1.26.2 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1582,7 +1582,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of unbound 1.26.1:";;
short | recursive ) echo "Configuration of unbound 1.26.2:";;
esac
cat <<\_ACEOF
@@ -1835,7 +1835,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
unbound configure 1.26.1
unbound configure 1.26.2
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2492,7 +2492,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by unbound $as_me 1.26.1, which was
It was created by unbound $as_me 1.26.2, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -3256,11 +3256,11 @@ UNBOUND_VERSION_MAJOR=1
UNBOUND_VERSION_MINOR=26
UNBOUND_VERSION_MICRO=1
UNBOUND_VERSION_MICRO=2
LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=40
LIBUNBOUND_REVISION=41
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -3368,6 +3368,7 @@ LIBUNBOUND_AGE=1
# 1.25.2 had 9:38:1
# 1.26.0 had 9:39:1
# 1.26.1 had 9:40:1
# 1.26.2 had 9:41:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -26467,7 +26468,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h
version=1.26.1
version=1.26.2
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5
printf %s "checking for build time... " >&6; }
@@ -26997,7 +26998,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by unbound $as_me 1.26.1, which was
This file was extended by unbound $as_me 1.26.2, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -27065,7 +27066,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
unbound config.status 1.26.1
unbound config.status 1.26.2
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
+3 -2
View File
@@ -12,14 +12,14 @@ sinclude(dnscrypt/dnscrypt.m4)
# must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1])
m4_define([VERSION_MINOR],[26])
m4_define([VERSION_MICRO],[1])
m4_define([VERSION_MICRO],[2])
AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[[email protected] or https://github.com/NLnetLabs/unbound/issues],[unbound])
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=40
LIBUNBOUND_REVISION=41
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -127,6 +127,7 @@ LIBUNBOUND_AGE=1
# 1.25.2 had 9:38:1
# 1.26.0 had 9:39:1
# 1.26.1 had 9:40:1
# 1.26.2 had 9:41:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
+1 -1
View File
@@ -1,4 +1,4 @@
README for Unbound 1.26.1
README for Unbound 1.26.2
Copyright 2007 NLnet Labs
http://unbound.net
+1 -1
View File
@@ -1,7 +1,7 @@
#
# Example configuration file.
#
# See unbound.conf(5) man page, version 1.26.1.
# See unbound.conf(5) man page, version 1.26.2.
#
# this is a comment.
+1 -1
View File
@@ -1,7 +1,7 @@
#
# Example configuration file.
#
# See unbound.conf(5) man page, version 1.26.1.
# See unbound.conf(5) man page, version 1.26.2.
#
# this is a comment.
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "LIBUNBOUND" "3" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "LIBUNBOUND" "3" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
libunbound \- Unbound DNS validating resolver 1.26.1 functions.
libunbound \- Unbound DNS validating resolver 1.26.2 functions.
.SH SYNOPSIS
.sp
\fB#include <unbound.h>\fP
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "LIBUNBOUND" "3" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "LIBUNBOUND" "3" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
libunbound \- Unbound DNS validating resolver 1.26.1 functions.
libunbound \- Unbound DNS validating resolver 1.26.2 functions.
.SH SYNOPSIS
.sp
\fB#include <unbound.h>\fP
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-ANCHOR" "8" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND-ANCHOR" "8" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound-anchor \- Unbound 1.26.1 anchor utility.
unbound-anchor \- Unbound 1.26.2 anchor utility.
.SH SYNOPSIS
.sp
\fBunbound\-anchor\fP [\fBopts\fP]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-ANCHOR" "8" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND-ANCHOR" "8" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound-anchor \- Unbound 1.26.1 anchor utility.
unbound-anchor \- Unbound 1.26.2 anchor utility.
.SH SYNOPSIS
.sp
\fBunbound\-anchor\fP [\fBopts\fP]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-CHECKCONF" "8" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND-CHECKCONF" "8" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound-checkconf \- Check Unbound 1.26.1 configuration file for errors.
unbound-checkconf \- Check Unbound 1.26.2 configuration file for errors.
.SH SYNOPSIS
.sp
\fBunbound\-checkconf\fP [\fB\-hf\fP] [\fB\-o option\fP] [cfgfile]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-CHECKCONF" "8" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND-CHECKCONF" "8" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound-checkconf \- Check Unbound 1.26.1 configuration file for errors.
unbound-checkconf \- Check Unbound 1.26.2 configuration file for errors.
.SH SYNOPSIS
.sp
\fBunbound\-checkconf\fP [\fB\-hf\fP] [\fB\-o option\fP] [cfgfile]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-CONTROL" "8" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND-CONTROL" "8" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound-control \- Unbound 1.26.1 remote server control utility.
unbound-control \- Unbound 1.26.2 remote server control utility.
.SH SYNOPSIS
.sp
\fBunbound\-control\fP [\fB\-hq\fP] [\fB\-c cfgfile\fP] [\fB\-s server\fP] command
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-CONTROL" "8" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND-CONTROL" "8" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound-control \- Unbound 1.26.1 remote server control utility.
unbound-control \- Unbound 1.26.2 remote server control utility.
.SH SYNOPSIS
.sp
\fBunbound\-control\fP [\fB\-hq\fP] [\fB\-c cfgfile\fP] [\fB\-s server\fP] command
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-HOST" "1" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND-HOST" "1" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound-host \- Unbound 1.26.1 DNS lookup utility.
unbound-host \- Unbound 1.26.2 DNS lookup utility.
.SH SYNOPSIS
.sp
\fBunbound\-host\fP [\fB\-C configfile\fP] [\fB\-vdhr46D\fP] [\fB\-c class\fP]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND-HOST" "1" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND-HOST" "1" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound-host \- Unbound 1.26.1 DNS lookup utility.
unbound-host \- Unbound 1.26.2 DNS lookup utility.
.SH SYNOPSIS
.sp
\fBunbound\-host\fP [\fB\-C configfile\fP] [\fB\-vdhr46D\fP] [\fB\-c class\fP]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND" "8" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND" "8" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound \- Unbound DNS validating resolver 1.26.1.
unbound \- Unbound DNS validating resolver 1.26.2.
.SH SYNOPSIS
.sp
\fBunbound\fP [\fB\-hdpVv\fP] [\fB\-c <cfgfile>\fP]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND" "8" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND" "8" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound \- Unbound DNS validating resolver 1.26.1.
unbound \- Unbound DNS validating resolver 1.26.2.
.SH SYNOPSIS
.sp
\fBunbound\fP [\fB\-hdpVv\fP] [\fB\-c <cfgfile>\fP]
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND.CONF" "5" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND.CONF" "5" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound.conf \- Unbound 1.26.1 configuration file.
unbound.conf \- Unbound 1.26.2 configuration file.
.SH SYNOPSIS
.sp
\fBunbound.conf\fP
+2 -2
View File
@@ -27,9 +27,9 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
.\" new: \\n[rst2man-indent\\n[rst2man-indent-level]]
.in \\n[rst2man-indent\\n[rst2man-indent-level]]u
..
.TH "UNBOUND.CONF" "5" "Sep 16, 2026" "1.26.1" "Unbound"
.TH "UNBOUND.CONF" "5" "Oct 21, 2026" "1.26.2" "Unbound"
.SH NAME
unbound.conf \- Unbound 1.26.1 configuration file.
unbound.conf \- Unbound 1.26.2 configuration file.
.SH SYNOPSIS
.sp
\fBunbound.conf\fP
+35 -21
View File
@@ -98,6 +98,11 @@
#define NUM_TIMEOUTS_FALLBACK_IXFR 3
/** number of IXFRs before an AXFR is performed, to consolidate RPZ memory. */
#define NUM_IXFR_BEFORE_AXFR 5
/** The max number of decompression pointers that are allowed in a received
* xfr packet. The parse fails if the limit is exceeded.
* For a lot of PTR records, with compression for a deep zone, that is about
* 20x pointers per RR, of about 16 bytes, more than 4000*20 = 80000. */
#define AUTH_XFR_DECOMPRESS_PACKET_LIMIT 128000
/** pick up nextprobe task to start waiting to perform transfer actions */
static void xfr_set_timeout(struct auth_xfer* xfr, struct module_env* env,
@@ -1363,7 +1368,8 @@ az_remove_rr(struct auth_zone* z, uint8_t* rr, size_t rr_len,
static int
decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
size_t pktlen, uint8_t* dname, uint16_t rr_type, uint16_t rr_class,
uint32_t rr_ttl, uint8_t* rr_data, uint16_t rr_rdlen)
uint32_t rr_ttl, uint8_t* rr_data, uint16_t rr_rdlen, int* budget,
int limit)
{
sldns_buffer pktbuf;
size_t dname_len = 0;
@@ -1377,7 +1383,7 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
/* decompress dname */
sldns_buffer_set_position(&pktbuf,
(size_t)(dname - sldns_buffer_current(&pktbuf)));
dname_len = pkt_dname_len(&pktbuf);
dname_len = pkt_dname_len_budget(&pktbuf, budget, limit);
if(dname_len == 0) return 0; /* parse fail on dname */
if(!sldns_buffer_available(buf, dname_len)) return 0;
dname_pkt_copy(&pktbuf, sldns_buffer_current(buf), dname);
@@ -1412,7 +1418,8 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
/* moves pktbuf to right after the
* compressed dname, and returns uncompressed
* dname length */
uncompressed_len = pkt_dname_len(&pktbuf);
uncompressed_len = pkt_dname_len_budget(
&pktbuf, budget, limit);
if(!uncompressed_len)
return 0; /* parse error in dname */
compressed_len = sldns_buffer_position(
@@ -1471,13 +1478,13 @@ static int
az_insert_rr_decompress(struct auth_zone* z, uint8_t* pkt, size_t pktlen,
struct sldns_buffer* scratch_buffer, uint8_t* dname, uint16_t rr_type,
uint16_t rr_class, uint32_t rr_ttl, uint8_t* rr_data,
uint16_t rr_rdlen, int* duplicate)
uint16_t rr_rdlen, int* duplicate, int* budget, int limit)
{
uint8_t* rr;
size_t rr_len;
size_t dname_len;
if(!decompress_rr_into_buffer(scratch_buffer, pkt, pktlen, dname,
rr_type, rr_class, rr_ttl, rr_data, rr_rdlen)) {
rr_type, rr_class, rr_ttl, rr_data, rr_rdlen, budget, limit)) {
log_err("could not decompress RR");
return 0;
}
@@ -1493,13 +1500,13 @@ static int
az_remove_rr_decompress(struct auth_zone* z, uint8_t* pkt, size_t pktlen,
struct sldns_buffer* scratch_buffer, uint8_t* dname, uint16_t rr_type,
uint16_t rr_class, uint32_t rr_ttl, uint8_t* rr_data,
uint16_t rr_rdlen, int* nonexist)
uint16_t rr_rdlen, int* nonexist, int* budget, int limit)
{
uint8_t* rr;
size_t rr_len;
size_t dname_len;
if(!decompress_rr_into_buffer(scratch_buffer, pkt, pktlen, dname,
rr_type, rr_class, rr_ttl, rr_data, rr_rdlen)) {
rr_type, rr_class, rr_ttl, rr_data, rr_rdlen, budget, limit)) {
log_err("could not decompress RR");
return 0;
}
@@ -4873,7 +4880,7 @@ chunk_rrlist_end(struct auth_chunk* rr_chunk, int rr_num)
/** RR list iterator, move to next RR */
static void
chunk_rrlist_gonext(struct auth_chunk** rr_chunk, int* rr_num,
size_t* rr_pos, size_t rr_nextpos)
size_t* rr_pos, size_t rr_nextpos, int* budget)
{
/* already at end of chunks? */
if(!*rr_chunk)
@@ -4887,6 +4894,7 @@ chunk_rrlist_gonext(struct auth_chunk** rr_chunk, int* rr_num,
}
/* no more RRs in this chunk */
/* continue with next chunk, see if it has RRs */
*budget = 0; /* new budget for next packet */
if(*rr_chunk)
*rr_chunk = (*rr_chunk)->next;
while(*rr_chunk) {
@@ -4970,11 +4978,12 @@ static int
ixfr_start_serial(struct auth_chunk* rr_chunk, int rr_num, size_t rr_pos,
uint8_t* rr_dname, uint16_t rr_type, uint16_t rr_class,
uint32_t rr_ttl, uint16_t rr_rdlen, uint8_t* rr_rdata,
size_t rr_nextpos, uint32_t transfer_serial, uint32_t xfr_serial)
size_t rr_nextpos, uint32_t transfer_serial, uint32_t xfr_serial,
int* budget)
{
uint32_t startserial;
/* move forward on RR */
chunk_rrlist_gonext(&rr_chunk, &rr_num, &rr_pos, rr_nextpos);
chunk_rrlist_gonext(&rr_chunk, &rr_num, &rr_pos, rr_nextpos, budget);
if(chunk_rrlist_end(rr_chunk, rr_num)) {
/* no second SOA */
verbose(VERB_OPS, "IXFR has no second SOA record");
@@ -5031,6 +5040,7 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
size_t rr_counter = 0;
int delmode = 0;
int softfail = 0;
int budget = 0, limit = AUTH_XFR_DECOMPRESS_PACKET_LIMIT;
xfr->num_ixfrs++;
@@ -5066,7 +5076,8 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
if(!ixfr_start_serial(rr_chunk, rr_num, rr_pos,
rr_dname, rr_type, rr_class, rr_ttl,
rr_rdlen, rr_rdata, rr_nextpos,
transfer_serial, xfr->serial)) {
transfer_serial, xfr->serial,
&budget)) {
return 0;
}
} else if(transfer_serial == serial) {
@@ -5110,7 +5121,7 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
if(!az_remove_rr_decompress(z, rr_chunk->data,
rr_chunk->len, scratch_buffer, rr_dname,
rr_type, rr_class, rr_ttl, rr_rdata, rr_rdlen,
&nonexist)) {
&nonexist, &budget, limit)) {
/* failed, malloc error or so */
return 0;
}
@@ -5130,7 +5141,7 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
if(!az_insert_rr_decompress(z, rr_chunk->data,
rr_chunk->len, scratch_buffer, rr_dname,
rr_type, rr_class, rr_ttl, rr_rdata, rr_rdlen,
&duplicate)) {
&duplicate, &budget, limit)) {
/* failed, malloc error or so */
return 0;
}
@@ -5144,7 +5155,8 @@ apply_ixfr(struct auth_xfer* xfr, struct auth_zone* z,
}
rr_counter++;
chunk_rrlist_gonext(&rr_chunk, &rr_num, &rr_pos, rr_nextpos);
chunk_rrlist_gonext(&rr_chunk, &rr_num, &rr_pos, rr_nextpos,
&budget);
}
if(softfail) {
verbose(VERB_ALGO, "IXFR did not apply cleanly, fetching full zone");
@@ -5168,6 +5180,7 @@ apply_axfr(struct auth_xfer* xfr, struct auth_zone* z,
size_t rr_nextpos;
size_t rr_counter = 0;
int have_end_soa = 0;
int budget = 0, limit = AUTH_XFR_DECOMPRESS_PACKET_LIMIT;
auth_zone_clear_data(z);
xfr->have_zone = 0;
@@ -5201,13 +5214,14 @@ apply_axfr(struct auth_xfer* xfr, struct auth_zone* z,
/* add this RR */
if(!az_insert_rr_decompress(z, rr_chunk->data, rr_chunk->len,
scratch_buffer, rr_dname, rr_type, rr_class, rr_ttl,
rr_rdata, rr_rdlen, NULL)) {
rr_rdata, rr_rdlen, NULL, &budget, limit)) {
/* failed, malloc error or so */
return 0;
}
rr_counter++;
chunk_rrlist_gonext(&rr_chunk, &rr_num, &rr_pos, rr_nextpos);
chunk_rrlist_gonext(&rr_chunk, &rr_num, &rr_pos, rr_nextpos,
&budget);
}
if(!have_end_soa) {
log_err("no end SOA record for AXFR");
@@ -6049,7 +6063,7 @@ check_xfer_packet(sldns_buffer* pkt, struct auth_xfer* xfr,
int* gonextonfail, int* transferdone)
{
uint8_t* wire = sldns_buffer_begin(pkt);
int i;
int i, budget = 0, limit = AUTH_XFR_DECOMPRESS_PACKET_LIMIT;
if(sldns_buffer_limit(pkt) < LDNS_HEADER_SIZE) {
verbose(VERB_ALGO, "xfr to %s failed, packet too small",
xfr->task_transfer->master->host);
@@ -6111,7 +6125,7 @@ check_xfer_packet(sldns_buffer* pkt, struct auth_xfer* xfr,
for(i=0; i<(int)LDNS_QDCOUNT(wire); i++) {
size_t pos = sldns_buffer_position(pkt);
uint16_t qtype, qclass;
if(pkt_dname_len(pkt) == 0) {
if(pkt_dname_len_budget(pkt, &budget, limit) == 0) {
verbose(VERB_ALGO, "xfr to %s failed, packet with "
"malformed dname",
xfr->task_transfer->master->host);
@@ -6161,7 +6175,7 @@ check_xfer_packet(sldns_buffer* pkt, struct auth_xfer* xfr,
for(i=0; i<(int)LDNS_ANCOUNT(wire); i++) {
size_t pos = sldns_buffer_position(pkt);
uint16_t tp, rdlen;
if(pkt_dname_len(pkt) == 0) {
if(pkt_dname_len_budget(pkt, &budget, limit) == 0) {
verbose(VERB_ALGO, "xfr to %s failed, packet with "
"malformed dname in answer section",
xfr->task_transfer->master->host);
@@ -6277,7 +6291,7 @@ check_xfer_packet(sldns_buffer* pkt, struct auth_xfer* xfr,
/* we skip over the RRs checking packet format */
for(i=0; i<(int)LDNS_NSCOUNT(wire); i++) {
uint16_t rdlen;
if(pkt_dname_len(pkt) == 0) {
if(pkt_dname_len_budget(pkt, &budget, limit) == 0) {
verbose(VERB_ALGO, "xfr to %s failed, packet with "
"malformed dname in authority section",
xfr->task_transfer->master->host);
@@ -6306,7 +6320,7 @@ check_xfer_packet(sldns_buffer* pkt, struct auth_xfer* xfr,
/* check additional section */
for(i=0; i<(int)LDNS_ARCOUNT(wire); i++) {
uint16_t rdlen;
if(pkt_dname_len(pkt) == 0) {
if(pkt_dname_len_budget(pkt, &budget, limit) == 0) {
verbose(VERB_ALGO, "xfr to %s failed, packet with "
"malformed dname in additional section",
xfr->task_transfer->master->host);
+30 -10
View File
@@ -506,8 +506,10 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
"incoming query.");
if(rep->c->use_h2)
http2_stream_remove_mesh_state(rep->c->h2_stream);
#ifdef HAVE_NGTCP2
else if(rep->c->type == comm_doq && rep->doq_stream)
doq_stream_remove_mesh_state(rep->doq_stream);
doq_find_stream_remove_mesh_state(rep);
#endif
comm_point_drop_reply(rep);
mesh->stats_dropped++;
return;
@@ -521,8 +523,10 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
"dropping incoming query.");
if(rep->c->use_h2)
http2_stream_remove_mesh_state(rep->c->h2_stream);
#ifdef HAVE_NGTCP2
else if(rep->c->type == comm_doq && rep->doq_stream)
doq_stream_remove_mesh_state(rep->doq_stream);
doq_find_stream_remove_mesh_state(rep);
#endif
comm_point_drop_reply(rep);
mesh->num_queries_replyaddr_limit++;
return;
@@ -598,6 +602,9 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
if(rep->c->use_h2) {
http2_stream_add_meshstate(rep->c->h2_stream, mesh, s);
} else if(rep->c->type == comm_doq && rep->doq_stream) {
/* The mesh_new_client call is in the worker callback, that
* is called from the doq handler that has the conn locked
* for this stream. It can add directly, without more locks. */
doq_stream_add_meshstate(rep->doq_stream, mesh, s);
}
/* add serve expired timer if required and not already there */
@@ -655,6 +662,9 @@ servfail_mem:
if(rep->c->use_h2)
http2_stream_remove_mesh_state(rep->c->h2_stream);
else if(rep->c->type == comm_doq && rep->doq_stream)
/* The mesh_new_client call is in the worker callback, that
* is called from the doq handler that has the conn locked
* for this stream. It can remove without more locks. */
doq_stream_remove_mesh_state(rep->doq_stream);
comm_point_send_reply(rep);
if(added_reply_without_accounting) {
@@ -1145,9 +1155,10 @@ mesh_state_cleanup(struct mesh_state* mstate)
mstate);
else if(rep->query_reply.c->use_h2)
http2_stream_remove_mesh_state(rep->h2_stream);
#ifdef HAVE_NGTCP2
else if(rep->query_reply.doq_stream)
doq_stream_remove_mesh_state(
rep->query_reply.doq_stream);
doq_find_stream_remove_mesh_state(&rep->query_reply);
#endif
comm_point_drop_reply(&rep->query_reply);
log_assert(mesh->num_reply_addrs > 0);
mesh->num_reply_addrs--;
@@ -1538,7 +1549,7 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
r->h2_stream->mesh_state = NULL;
#ifdef HAVE_NGTCP2
} else if(r->query_reply.doq_stream) {
r->query_reply.doq_stream->mesh_state = NULL;
doq_find_stream_remove_mesh_state(&r->query_reply);
#endif
}
/* send the reply */
@@ -1837,8 +1848,10 @@ void mesh_query_done(struct mesh_state* mstate)
mstate);
else if(r->query_reply.c->use_h2)
http2_stream_remove_mesh_state(r->h2_stream);
#ifdef HAVE_NGTCP2
else if(r->query_reply.doq_stream)
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
doq_find_stream_remove_mesh_state(&r->query_reply);
#endif
comm_point_drop_reply(&r->query_reply);
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
mstate->s.env->mesh->num_reply_addrs--;
@@ -1871,8 +1884,10 @@ void mesh_query_done(struct mesh_state* mstate)
r->query_reply.c->tcp_req_info, mstate);
} else if(r->query_reply.c->use_h2) {
http2_stream_remove_mesh_state(r->h2_stream);
#ifdef HAVE_NGTCP2
} else if(r->query_reply.doq_stream) {
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
doq_find_stream_remove_mesh_state(&r->query_reply);
#endif
}
comm_point_drop_reply(&r->query_reply);
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
@@ -2481,8 +2496,11 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
* don't point back. */
if(n->h2_stream) n->h2_stream->mesh_state = NULL;
#ifdef HAVE_NGTCP2
if(n->query_reply.doq_stream)
n->query_reply.doq_stream->mesh_state = NULL;
/* When doq calls with doq_stream nonNULL, it removes
* the mesh_reply itself, and also already has the conn
* locked, so no need to remove it here */
if(!doq_stream && n->query_reply.doq_stream)
doq_find_stream_remove_mesh_state(&n->query_reply);
#endif
/* prev = prev; */
@@ -2663,8 +2681,10 @@ mesh_serve_expired_callback(void* arg)
r->query_reply.c->tcp_req_info, mstate);
else if(r->query_reply.c->use_h2)
http2_stream_remove_mesh_state(r->h2_stream);
#ifdef HAVE_NGTCP2
else if(r->query_reply.doq_stream)
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
doq_find_stream_remove_mesh_state(&r->query_reply);
#endif
comm_point_drop_reply(&r->query_reply);
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
mstate->s.env->mesh->num_reply_addrs--;
@@ -1524,6 +1524,49 @@ outnet_send_wait_udp(struct outside_network* outnet)
}
}
/** Clear out all pending requests that are on the port. */
static void
clear_pending_from_port(struct outside_network* outnet, struct comm_point* c)
{
/* Otherwise, the clear the cache action of unwanted_threshold, can
* have revealed this communication port. */
struct pending* p, *np, *list = NULL, *last = NULL;
/* First, remove the entries from the tree. */
/* The rbtree rbnode.right is used to build the temporary list here.
* Otherwise the list could be malloced. */
p = (struct pending*)rbtree_first(outnet->pending);
while((rbnode_type*)p != RBTREE_NULL) {
np = (struct pending*)rbtree_next((rbnode_type*)p);
if(p->pc->cp == c) {
comm_timer_disable(p->timer);
(void)rbtree_delete(outnet->pending, p->node.key);
if(last)
last->node.right = (rbnode_type*)p;
else list = p;
last = p;
p->node.right = NULL;
}
p = np;
}
/* The entries are removed from the tree, call their callbacks. */
p = list;
while(p) {
np = (struct pending*)p->node.right;
p->node.right = RBTREE_NULL;
/* callback error on pending */
if(p->cb) {
fptr_ok(fptr_whitelist_pending_udp(p->cb));
(void)(*p->cb)(p->pc->cp, p->cb_arg,
NETEVENT_CLOSED, NULL);
}
portcomm_loweruse(outnet, p->pc);
pending_delete(NULL, p);
outnet_send_wait_udp(outnet);
p = np;
}
}
int
outnet_udp_cb(struct comm_point* c, void* arg, int error,
struct comm_reply *reply_info)
@@ -1568,6 +1611,7 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
outnet->unwanted_action));
(*outnet->unwanted_action)(outnet->unwanted_param);
outnet->unwanted_total = 0;
clear_pending_from_port(outnet, c);
}
return 0;
}
@@ -1588,6 +1632,7 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
outnet->unwanted_action));
(*outnet->unwanted_action)(outnet->unwanted_param);
outnet->unwanted_total = 0;
clear_pending_from_port(outnet, c);
}
return 0;
}
+55
View File
@@ -236,6 +236,61 @@ fail:
return 0;
}
size_t
pkt_dname_len_budget(struct sldns_buffer* pkt, int* budget, int limit)
{
size_t len = 0;
int ptrcount = 0;
uint8_t labellen;
size_t endpos = 0;
/* read dname and determine length */
/* check compression pointers, loops, out of bounds */
while(1) {
/* read next label */
if(sldns_buffer_remaining(pkt) < 1)
return 0;
labellen = sldns_buffer_read_u8(pkt);
if(LABEL_IS_PTR(labellen)) {
/* compression ptr */
uint16_t ptr;
if(sldns_buffer_remaining(pkt) < 1)
return 0;
ptr = PTR_OFFSET(labellen, sldns_buffer_read_u8(pkt));
if(++(*budget) > limit) {
verbose(VERB_ALGO, "The decompression pointer "
"limit of %d has been exceeded", limit);
return 0; /* too many decompression pointers */
}
if(ptrcount++ > MAX_COMPRESS_PTRS)
return 0; /* loop! */
if(sldns_buffer_limit(pkt) <= ptr)
return 0; /* out of bounds! */
if(!endpos)
endpos = sldns_buffer_position(pkt);
sldns_buffer_set_position(pkt, ptr);
} else {
/* label contents */
if(labellen > 0x3f)
return 0; /* label too long */
len += 1 + labellen;
if(len > LDNS_MAX_DOMAINLEN)
return 0;
if(labellen == 0) {
/* end of dname */
break;
}
if(sldns_buffer_remaining(pkt) < labellen)
return 0;
sldns_buffer_skip(pkt, (ssize_t)labellen);
}
}
if(endpos)
sldns_buffer_set_position(pkt, endpos);
return len;
}
int
dname_pkt_compare(sldns_buffer* pkt, uint8_t* d1, uint8_t* d2)
{
+16
View File
@@ -109,6 +109,22 @@ int query_dname_compare(uint8_t* d1, uint8_t* d2);
*/
size_t pkt_dname_len(struct sldns_buffer* pkt);
/**
* Determine correct, compressed, dname present in packet.
* Checks for parse errors. Has a budget and limit for decompression,
* if the limit is exceeded, this is an error.
* @param pkt: packet to read from (from current start position).
* @param budget: the budget of decompression pointer follows.
* It is updated with the additional count (if any) of pointer follows,
* so that a running total can be kept over a number of dnames.
* @param limit: the limit of decompression pointer follows.
* @return: 0 on parse error.
* At exit the position is right after the (compressed) dname.
* Compression pointers are followed and checked for loops.
* The uncompressed wireformat length is returned.
*/
size_t pkt_dname_len_budget(struct sldns_buffer* pkt, int* budget, int limit);
/**
* Compare dnames in packet (compressed). Dnames must be valid.
* routine performs lowercasing, so the packet casing is preserved.
+40 -21
View File
@@ -54,6 +54,9 @@
#include "sldns/wire2str.h"
#define MAX_PARSED_EDNS_OPTIONS 100
/** The max number of decompression pointers that are allowed in a received
* packet. The parse fails if the limit is exceeded. */
#define PARSE_DECOMPRESS_LIMIT 2048
/** smart comparison of (compressed, valid) dnames from packet */
static int
@@ -114,7 +117,7 @@ new_rrset(struct msg_parse* msg, uint8_t* dname, size_t dnamelen,
/** See if next rrset is nsec at zone apex */
static int
nsec_at_apex(sldns_buffer* pkt)
nsec_at_apex(sldns_buffer* pkt, int* budget, int limit)
{
/* we are at ttl position in packet. */
size_t pos = sldns_buffer_position(pkt);
@@ -128,7 +131,7 @@ nsec_at_apex(sldns_buffer* pkt)
return 0; /* parse error happens later */
}
/* must validate the nsec next domain name format */
if(pkt_dname_len(pkt) == 0) {
if(pkt_dname_len_budget(pkt, budget, limit) == 0) {
sldns_buffer_set_position(pkt, pos);
return 0; /* parse error */
}
@@ -159,10 +162,11 @@ nsec_at_apex(sldns_buffer* pkt)
/** Calculate rrset flags */
static uint32_t
pkt_rrset_flags(sldns_buffer* pkt, uint16_t type, sldns_pkt_section sec)
pkt_rrset_flags(sldns_buffer* pkt, uint16_t type, sldns_pkt_section sec,
int* budget, int limit)
{
uint32_t f = 0;
if(type == LDNS_RR_TYPE_NSEC && nsec_at_apex(pkt)) {
if(type == LDNS_RR_TYPE_NSEC && nsec_at_apex(pkt, budget, limit)) {
f |= PACKED_RRSET_NSEC_AT_APEX;
} else if(type == LDNS_RR_TYPE_SOA && sec == LDNS_SECTION_AUTHORITY) {
f |= PACKED_RRSET_SOA_NEG;
@@ -462,6 +466,8 @@ change_rrsig_rrset(struct rrset_parse* sigset, struct msg_parse* msg,
* @param rrset_prev: last seen RRset.
* @param section: the current section in the packet.
* @param region: used to allocate temporary parsing data.
* @param budget: decompression budget.
* @param limit: decompression limit.
* @return 0 on out of memory.
*/
static int
@@ -471,7 +477,8 @@ find_rrset(struct msg_parse* msg, sldns_buffer* pkt, uint8_t* dname,
uint8_t** prev_dname_first, uint8_t** prev_dname_last,
size_t* prev_dnamelen, uint16_t* prev_type,
uint16_t* prev_dclass, struct rrset_parse** rrset_prev,
sldns_pkt_section section, struct regional* region)
sldns_pkt_section section, struct regional* region, int* budget,
int limit)
{
hashvalue_type dname_h = pkt_hash_rrset_first(pkt, dname);
uint16_t covtype;
@@ -498,7 +505,7 @@ find_rrset(struct msg_parse* msg, sldns_buffer* pkt, uint8_t* dname,
}
}
/* find by hashing and lookup in hashtable */
*rrset_flags = pkt_rrset_flags(pkt, type, section);
*rrset_flags = pkt_rrset_flags(pkt, type, section, budget, limit);
/* if rrsig - try to lookup matching data set first */
if(type == LDNS_RR_TYPE_RRSIG && pkt_rrsig_covered(pkt,
@@ -580,10 +587,13 @@ find_rrset(struct msg_parse* msg, sldns_buffer* pkt, uint8_t* dname,
* @param pkt: packet, position at call must be at start of query section.
* at end position is after query section.
* @param msg: store results here.
* @param budget: decompression budget.
* @param limit: decompression limit.
* @return: 0 if OK, or rcode on error.
*/
static int
parse_query_section(sldns_buffer* pkt, struct msg_parse* msg)
parse_query_section(sldns_buffer* pkt, struct msg_parse* msg, int* budget,
int limit)
{
if(msg->qdcount == 0)
return 0;
@@ -593,7 +603,7 @@ parse_query_section(sldns_buffer* pkt, struct msg_parse* msg)
if(sldns_buffer_remaining(pkt) <= 0)
return LDNS_RCODE_FORMERR;
msg->qname = sldns_buffer_current(pkt);
if((msg->qname_len = pkt_dname_len(pkt)) == 0)
if((msg->qname_len = pkt_dname_len_budget(pkt, budget, limit)) == 0)
return LDNS_RCODE_FORMERR;
if(sldns_buffer_remaining(pkt) < sizeof(uint16_t)*2)
return LDNS_RCODE_FORMERR;
@@ -638,7 +648,8 @@ get_rdf_size(sldns_rdf_type rdf)
/** calculate the size of one rr */
static int
calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr)
calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr, int* budget,
int limit)
{
const sldns_rr_descriptor* desc;
uint16_t pkt_len; /* length of rr inside the packet */
@@ -659,7 +670,8 @@ calc_size(sldns_buffer* pkt, uint16_t type, struct rr_parse* rr)
case LDNS_RDF_TYPE_DNAME:
/* decompress every domain name */
oldpos = sldns_buffer_position(pkt);
if((len = pkt_dname_len(pkt)) == 0)
if((len = pkt_dname_len_budget(pkt, budget,
limit)) == 0)
return 0; /* malformed dname */
if(sldns_buffer_position(pkt)-oldpos > pkt_len)
return 0; /* dname exceeds rdata */
@@ -758,7 +770,7 @@ sig_is_double(sldns_buffer* pkt, struct rrset_parse* rrset, uint8_t* ttldata)
static int
add_rr_to_rrset(struct rrset_parse* rrset, sldns_buffer* pkt,
struct msg_parse* msg, struct regional* region,
sldns_pkt_section section, uint16_t type)
sldns_pkt_section section, uint16_t type, int* budget, int limit)
{
struct rr_parse* rr;
/* check section of rrset. */
@@ -809,8 +821,10 @@ add_rr_to_rrset(struct rrset_parse* rrset, sldns_buffer* pkt,
}
/* calc decompressed size */
if(!calc_size(pkt, type, rr))
if(!calc_size(pkt, type, rr, budget, limit)) {
if(*budget > limit) return LDNS_RCODE_SERVFAIL;
return LDNS_RCODE_FORMERR;
}
rrset->size += rr->size;
return 0;
@@ -825,12 +839,14 @@ add_rr_to_rrset(struct rrset_parse* rrset, sldns_buffer* pkt,
* @param section: section enum.
* @param num_rrs: how many rrs are in the section.
* @param num_rrsets: returns number of rrsets in the section.
* @param budget: decompression budget.
* @param limit: decompression limit.
* @return: 0 if OK, or rcode on error.
*/
static int
parse_section(sldns_buffer* pkt, struct msg_parse* msg,
struct regional* region, sldns_pkt_section section,
uint16_t num_rrs, size_t* num_rrsets)
uint16_t num_rrs, size_t* num_rrsets, int* budget, int limit)
{
uint16_t i;
uint8_t* dname, *prev_dname_f = NULL, *prev_dname_l = NULL;
@@ -849,8 +865,10 @@ parse_section(sldns_buffer* pkt, struct msg_parse* msg,
for(i=0; i<num_rrs; i++) {
/* parse this RR. */
dname = sldns_buffer_current(pkt);
if((dnamelen = pkt_dname_len(pkt)) == 0)
if((dnamelen = pkt_dname_len_budget(pkt, budget, limit)) == 0) {
if(*budget > limit) return LDNS_RCODE_SERVFAIL;
return LDNS_RCODE_FORMERR;
}
if(sldns_buffer_remaining(pkt) < 10) /* type, class, ttl, len */
return LDNS_RCODE_FORMERR;
type = sldns_buffer_read_u16(pkt);
@@ -886,7 +904,7 @@ parse_section(sldns_buffer* pkt, struct msg_parse* msg,
if(!find_rrset(msg, pkt, dname, dnamelen, type, dclass, &hash,
&rrset_flags, &prev_dname_f, &prev_dname_l,
&prev_dnamelen, &prev_type, &prev_dclass, &rrset,
section, region))
section, region, budget, limit))
return LDNS_RCODE_SERVFAIL;
if(!rrset) {
/* it is a new RR set. hash&flags already calculated.*/
@@ -906,7 +924,7 @@ parse_section(sldns_buffer* pkt, struct msg_parse* msg,
}
/* add to rrset. */
if((r=add_rr_to_rrset(rrset, pkt, msg, region, section,
type)) != 0)
type, budget, limit)) != 0)
return r;
}
return 0;
@@ -915,7 +933,7 @@ parse_section(sldns_buffer* pkt, struct msg_parse* msg,
int
parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
{
int ret;
int ret, budget = 0, limit = PARSE_DECOMPRESS_LIMIT;
if(sldns_buffer_remaining(pkt) < LDNS_HEADER_SIZE)
return LDNS_RCODE_FORMERR;
/* read the header */
@@ -927,19 +945,20 @@ parse_packet(sldns_buffer* pkt, struct msg_parse* msg, struct regional* region)
msg->arcount = sldns_buffer_read_u16(pkt);
if(msg->qdcount > 1)
return LDNS_RCODE_FORMERR;
if((ret = parse_query_section(pkt, msg)) != 0)
if((ret = parse_query_section(pkt, msg, &budget, limit)) != 0)
return ret;
if((ret = parse_section(pkt, msg, region, LDNS_SECTION_ANSWER,
msg->ancount, &msg->an_rrsets)) != 0)
msg->ancount, &msg->an_rrsets, &budget, limit)) != 0)
return ret;
if((ret = parse_section(pkt, msg, region, LDNS_SECTION_AUTHORITY,
msg->nscount, &msg->ns_rrsets)) != 0)
msg->nscount, &msg->ns_rrsets, &budget, limit)) != 0)
return ret;
if(sldns_buffer_remaining(pkt) == 0 && msg->arcount == 1) {
/* BIND accepts leniently that an EDNS record is missing.
* so, we do too. */
} else if((ret = parse_section(pkt, msg, region,
LDNS_SECTION_ADDITIONAL, msg->arcount, &msg->ar_rrsets)) != 0)
LDNS_SECTION_ADDITIONAL, msg->arcount, &msg->ar_rrsets,
&budget, limit)) != 0)
return ret;
/* if(sldns_buffer_remaining(pkt) > 0) { */
/* there is spurious data at end of packet. ignore */
+22 -4
View File
@@ -2828,7 +2828,7 @@ doq_lookup_repinfo(struct doq_table* table, struct comm_reply* repinfo)
/** doq find connection and stream. From inside callbacks from worker. */
static int
doq_lookup_conn_stream(struct comm_reply* repinfo, struct comm_point* c,
struct doq_conn** conn, struct doq_stream** stream)
struct doq_conn** conn, struct doq_stream** stream, int checkclose)
{
log_assert(c->doq_socket);
if(c->doq_socket->current_conn) {
@@ -2856,7 +2856,7 @@ doq_lookup_conn_stream(struct comm_reply* repinfo, struct comm_point* c,
}
return 0;
}
if((*stream)->is_closed) {
if(checkclose && (*stream)->is_closed) {
/* stream is closed, ignore reply or drop */
if(!c->doq_socket->current_conn) {
/* Not inside callbacks, we have our own lock on conn.
@@ -2868,6 +2868,24 @@ doq_lookup_conn_stream(struct comm_reply* repinfo, struct comm_point* c,
return 1;
}
/** doq remove mesh state from stream */
void doq_find_stream_remove_mesh_state(struct comm_reply* repinfo)
{
struct doq_conn* conn;
struct doq_stream* stream;
log_assert(repinfo->c->type == comm_doq);
if(!doq_lookup_conn_stream(repinfo, repinfo->c, &conn, &stream, 0)) {
/* No stream, it may have been removed. */
return;
}
doq_stream_remove_mesh_state(stream);
if(!repinfo->c->doq_socket->current_conn) {
/* Not inside callbacks, we have our own lock on conn.
* Release it. */
lock_basic_unlock(&conn->lock);
}
}
/** doq send a reply from a comm reply */
static void
doq_socket_send_reply(struct comm_reply* repinfo)
@@ -2875,7 +2893,7 @@ doq_socket_send_reply(struct comm_reply* repinfo)
struct doq_conn* conn;
struct doq_stream* stream;
log_assert(repinfo->c->type == comm_doq);
if(!doq_lookup_conn_stream(repinfo, repinfo->c, &conn, &stream)) {
if(!doq_lookup_conn_stream(repinfo, repinfo->c, &conn, &stream, 1)) {
verbose(VERB_ALGO, "doq: send_reply but %s is gone",
(conn?"stream":"connection"));
/* No stream, it may have been closed. */
@@ -2906,7 +2924,7 @@ doq_socket_drop_reply(struct comm_reply* repinfo)
struct doq_conn* conn;
struct doq_stream* stream;
log_assert(repinfo->c->type == comm_doq);
if(!doq_lookup_conn_stream(repinfo, repinfo->c, &conn, &stream)) {
if(!doq_lookup_conn_stream(repinfo, repinfo->c, &conn, &stream, 1)) {
verbose(VERB_ALGO, "doq: drop_reply but %s is gone",
(conn?"stream":"connection"));
/* The connection or stream is already gone. */
+4
View File
@@ -1136,6 +1136,10 @@ void doq_send_pkt(struct comm_point* c, struct doq_pkt_addr* paddr,
/** doq timer callback function. */
void doq_timer_cb(void* arg);
/** Find and lock doq connection and remove mesh state from the stream
* (found by id).*/
void doq_find_stream_remove_mesh_state(struct comm_reply* repinfo);
/** tcp read again callback function. For tcp req info listen. */
void tcp_read_again_cb(void* arg);
+16 -12
View File
@@ -1963,14 +1963,7 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
lookup_name = vq->qchase.qname;
lookup_len = vq->qchase.qname_len;
/* for type DS look at the parent side for keys/trustanchor */
/* also for NSEC not at apex */
if(vq->qchase.qtype == LDNS_RR_TYPE_DS ||
(vq->qchase.qtype == LDNS_RR_TYPE_NSEC &&
vq->orig_msg->rep->rrset_count > vq->rrset_skip &&
ntohs(vq->orig_msg->rep->rrsets[vq->rrset_skip]->rk.type) ==
LDNS_RR_TYPE_NSEC &&
!(vq->orig_msg->rep->rrsets[vq->rrset_skip]->
rk.flags&PACKED_RRSET_NSEC_AT_APEX))) {
if(vq->qchase.qtype == LDNS_RR_TYPE_DS) {
dname_remove_label(&lookup_name, &lookup_len);
}
@@ -2007,13 +2000,15 @@ processInit(struct module_qstate* qstate, struct val_qstate* vq,
anchor = anchors_lookup(qstate->env->anchors,
lookup_name, lookup_len, vq->qchase.qclass);
if(!anchor) { /* unsigned parent denies anchor*/
verbose(VERB_QUERY, "unsigned parent zone denies"
" trust anchor, indeterminate");
vq->chase_reply->security = sec_status_indeterminate;
update_reason_bogus(vq->chase_reply, LDNS_EDE_DNSSEC_INDETERMINATE);
verbose(VERB_ALGO, "unsigned parent zone denies"
" trust anchor, thus bogus");
errinf_ede(qstate, "unsigned parent zone denies trust anchor, thus bogus", LDNS_EDE_DNSSEC_BOGUS);
vq->chase_reply->security = sec_status_bogus;
update_reason_bogus(vq->chase_reply, LDNS_EDE_DNSSEC_BOGUS);
vq->state = VAL_FINISHED_STATE;
return 1;
}
vq->parent_denial_must_be_secure = 1;
verbose(VERB_ALGO, "trust anchor NXDOMAIN by signed parent");
} else if(subtype == VAL_CLASS_POSITIVE &&
qstate->qinfo.qtype == LDNS_RR_TYPE_DNSKEY &&
@@ -2538,6 +2533,15 @@ processFinished(struct module_qstate* qstate, struct val_qstate* vq,
enum val_classification subtype = val_classify_response(
qstate->query_flags, &qstate->qinfo, &vq->qchase,
vq->orig_msg->rep, vq->rrset_skip);
if(vq->parent_denial_must_be_secure) {
if(vq->chase_reply->security != sec_status_secure &&
vq->chase_reply->security != sec_status_bogus) {
verbose(VERB_ALGO, "parent denial of trust island subdomain is not secure, thus bogus");
vq->chase_reply->security = sec_status_bogus;
update_reason_bogus(vq->chase_reply, LDNS_EDE_DNSSEC_BOGUS);
errinf_ede(qstate, "parent denial of trust island subdomain is not secure, thus bogus", LDNS_EDE_DNSSEC_BOGUS);
}
}
/* store overall validation result in orig_msg */
if(vq->rrset_skip == 0) {
+4
View File
@@ -244,6 +244,10 @@ struct val_qstate {
int num_nsec_attempts;
/** The nsec attempts have been exceeded. */
int num_nsec_attempts_exceeded;
/** if validation must be secure, (else bogus) for NXDOMAIN
* from signed parent to (removed) trust anchor subdomain. */
int parent_denial_must_be_secure;
};
/**
+3 -3
View File
@@ -947,7 +947,7 @@
#define PACKAGE_NAME "unbound"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "unbound 1.26.1"
#define PACKAGE_STRING "unbound 1.26.2"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "unbound"
@@ -956,7 +956,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "1.26.1"
#define PACKAGE_VERSION "1.26.2"
/* default pidfile location */
#define PIDFILE "/var/unbound/unbound.pid"
@@ -979,7 +979,7 @@
#define ROOT_CERT_FILE "/var/unbound/icannbundle.pem"
/* version number for resource files */
#define RSRC_PACKAGE_VERSION 1,26,1,0
#define RSRC_PACKAGE_VERSION 1,26,2,0
/* Directory to chdir to */
#define RUN_DIR "/var/unbound"