mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-10-28 11:25:21 +01:00
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:
commit
c6d7a2478c
30 files changed
+317
-116
No files matched your search
Vendored
+13
-12
@@ -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\\"
|
||||
|
||||
|
||||
@@ -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,4 +1,4 @@
|
||||
README for Unbound 1.26.1
|
||||
README for Unbound 1.26.2
|
||||
Copyright 2007 NLnet Labs
|
||||
http://unbound.net
|
||||
|
||||
|
||||
@@ -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,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.
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in new issue
Block a user