Compare commits

...
13 Commits
Author SHA1 Message Date
W.C.A. Wijngaards 8ee0bca833 - Fix stat_values.tdir test to have less test failures. 2026-08-11 10:07:38 +02:00
W.C.A. Wijngaards c58e6add2b - Fix #1492 from zacek: Data race in log_init() on
key_created/log_lock when calling ub_ctx_create()
  concurrently from multiple threads.
2026-08-11 09:42:30 +02:00
W.C.A. Wijngaards 93a56205cf - Fix #1489 from jplesnik: Replace removed Python 2 C API
macros for SWIG 4.5.0 compatibility.
2026-08-07 08:57:32 +02:00
W.C.A. Wijngaards 709f622658 Note issue number in Changlog entry. 2026-08-06 17:15:55 +02:00
akhanin-dnsfandGitHub 307fc6f062 - Fix bounds check in packed_rr_to_string, it checked the (#1488)
assembled rr length against the output string length
  dest_len, instead of against the size of the rr buffer it
  writes into. Callers in cachedump.c and remote.c pass a
  dest_len larger than that buffer.
- Unit test for packed_rr_to_string.
2026-08-06 17:04:05 +02:00
W.C.A. Wijngaards 8b33c5d7ff - Fix #1487: regression in 1.26.0, ipsecmod is now always
partly enabled.
2026-08-06 09:46:18 +02:00
W.C.A. Wijngaards 36bd52afb9 Fix typo in Changelog. 2026-08-06 09:08:33 +02:00
W.C.A. Wijngaards b7d13ff12b - Fix ##1485: the list_forwards command omits port numbers.
The list_forwards and list_stubs commands for
  unbound-control print port and tls auth name.
2026-08-06 09:08:17 +02:00
W.C.A. Wijngaards bdfcfb861f - Fix to set makedist.sh to not wget config.sub and
config.guess from git repo. The fetch times out, and the
  version from libtoolize is much more recent now than
  that it was when the wget was added.
2026-08-04 10:04:34 +02:00
W.C.A. Wijngaards b444deffd2 Note 1.26.0 release. 2026-08-04 10:01:59 +02:00
W.C.A. Wijngaards ff28b7e5cf - For #1483: The failure reason when an NSEC NXDOMAIN is
encountered when looking for an insecure delegation, is
  fixed to mention the NSEC records, instead of nonexistent
  NSEC3 records, that it attempted.
2026-07-31 09:53:47 +02:00
W.C.A. Wijngaards 79b84bbc91 - Fix #1482: DNS-over-QUIC doesn't work with simple config.
That fixes interface-automatic for use with doq service.
2026-07-30 08:24:42 +02:00
W.C.A. Wijngaards cbfc3b0342 - Tag for 1.26.0rc1. The repo continues with version 1.26.1. 2026-07-28 09:45:59 +02:00
17 changed files with 371 additions and 44 deletions
Vendored
+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.0.
# Generated by GNU Autoconf 2.71 for unbound 1.26.1.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl 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.0'
PACKAGE_STRING='unbound 1.26.0'
PACKAGE_VERSION='1.26.1'
PACKAGE_STRING='unbound 1.26.1'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
PACKAGE_URL=''
@@ -1513,7 +1513,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.0 to adapt to many kinds of systems.
\`configure' configures unbound 1.26.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1579,7 +1579,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of unbound 1.26.0:";;
short | recursive ) echo "Configuration of unbound 1.26.1:";;
esac
cat <<\_ACEOF
@@ -1832,7 +1832,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
unbound configure 1.26.0
unbound configure 1.26.1
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2489,7 +2489,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.0, which was
It was created by unbound $as_me 1.26.1, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -3253,11 +3253,11 @@ UNBOUND_VERSION_MAJOR=1
UNBOUND_VERSION_MINOR=26
UNBOUND_VERSION_MICRO=0
UNBOUND_VERSION_MICRO=1
LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=39
LIBUNBOUND_REVISION=40
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -3364,6 +3364,7 @@ LIBUNBOUND_AGE=1
# 1.25.1 had 9:37:1
# 1.25.2 had 9:38:1
# 1.26.0 had 9:39:1
# 1.26.1 had 9:40:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -25711,7 +25712,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h
version=1.26.0
version=1.26.1
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5
printf %s "checking for build time... " >&6; }
@@ -26241,7 +26242,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.0, which was
This file was extended by unbound $as_me 1.26.1, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -26309,7 +26310,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.0
unbound config.status 1.26.1
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],[0])
m4_define([VERSION_MICRO],[1])
AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl 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=39
LIBUNBOUND_REVISION=40
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -126,6 +126,7 @@ LIBUNBOUND_AGE=1
# 1.25.1 had 9:37:1
# 1.25.2 had 9:38:1
# 1.26.0 had 9:39:1
# 1.26.1 had 9:40:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
+22 -3
View File
@@ -2681,7 +2681,7 @@ static int
ssl_print_name_dp(RES* ssl, const char* str, uint8_t* nm, uint16_t dclass,
struct delegpt* dp)
{
char buf[LDNS_MAX_DOMAINLEN];
char buf[LDNS_MAX_DOMAINLEN], portstr[128], tls_auth_name[256];
struct delegpt_ns* ns;
struct delegpt_addr* a;
int f = 0;
@@ -2696,13 +2696,32 @@ ssl_print_name_dp(RES* ssl, const char* str, uint8_t* nm, uint16_t dclass,
}
for(ns = dp->nslist; ns; ns = ns->next) {
dname_str(ns->name, buf);
if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf))
if(ns->port != UNBOUND_DNS_PORT)
snprintf(portstr, sizeof(portstr), "@%d", ns->port);
else portstr[0]=0;
if(ns->tls_auth_name)
snprintf(tls_auth_name, sizeof(tls_auth_name), "#%s",
ns->tls_auth_name);
else tls_auth_name[0]=0;
if(!ssl_printf(ssl, "%s%s%s%s", (f?" ":""), buf, portstr,
tls_auth_name))
return 0;
f = 1;
}
for(a = dp->target_list; a; a = a->next_target) {
int port = (unsigned)((a->addr.ss_family == AF_INET) ?
ntohs(((struct sockaddr_in*)&a->addr)->sin_port) :
ntohs(((struct sockaddr_in6*)&a->addr)->sin6_port));
addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf));
if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf))
if(port != UNBOUND_DNS_PORT)
snprintf(portstr, sizeof(portstr), "@%d", port);
else portstr[0]=0;
if(a->tls_auth_name)
snprintf(tls_auth_name, sizeof(tls_auth_name), "#%s",
a->tls_auth_name);
else tls_auth_name[0]=0;
if(!ssl_printf(ssl, "%s%s%s%s", (f?" ":""), buf, portstr,
tls_auth_name))
return 0;
f = 1;
}
+45
View File
@@ -1,3 +1,48 @@
11 August 2026: Wouter
- Fix #1492 from zacek: Data race in log_init() on
key_created/log_lock when calling ub_ctx_create()
concurrently from multiple threads.
- Fix stat_values.tdir test to have less test failures.
7 August 2026: Wouter
- Fix #1489 from jplesnik: Replace removed Python 2 C API
macros for SWIG 4.5.0 compatibility.
6 August 2026: Alex Khanin
- Fix #1488: bounds check in packed_rr_to_string, it checked
the assembled rr length against the output string length
dest_len, instead of against the size of the rr buffer it
writes into. Callers in cachedump.c and remote.c pass a
dest_len larger than that buffer.
- Unit test for packed_rr_to_string.
6 August 2026: Wouter
- Fix #1485: the list_forwards command omits port numbers.
The list_forwards and list_stubs commands for
unbound-control print port and tls auth name.
- Fix #1487: regression in 1.26.0, ipsecmod is now always
partly enabled.
4 August 2026: Wouter
- Fix to set makedist.sh to not wget config.sub and
config.guess from git repo. The fetch times out, and the
version from libtoolize is much more recent now than
that it was when the wget was added.
31 July 2026: Wouter
- For #1483: The failure reason when an NSEC NXDOMAIN is
encountered when looking for an insecure delegation, is
fixed to mention the NSEC records, instead of nonexistent
NSEC3 records, that it attempted.
30 July 2026: Wouter
- Fix #1482: DNS-over-QUIC doesn't work with simple config.
That fixes interface-automatic for use with doq service.
28 July 2026: Wouter
- Tag for 1.26.0rc1. The repo continues with version 1.26.1.
This became 1.26.0 on 4 aug 2026.
24 July 2026: Wouter
- Merge #1433 from jisakiel: Add new static zone type
block_aaaa to suppress AAAA queries.
+7 -3
View File
@@ -59,6 +59,11 @@
static int
ipsecmod_apply_cfg(struct ipsecmod_env* ipsecmod_env, struct config_file* cfg)
{
if(cfg->ipsecmod_whitelist &&
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
return 0;
if(!cfg->ipsecmod_enabled)
return 1;
if(!cfg->ipsecmod_hook || (cfg->ipsecmod_hook && !cfg->ipsecmod_hook[0])) {
log_err("ipsecmod: missing ipsecmod-hook.");
return 0;
@@ -68,9 +73,6 @@ ipsecmod_apply_cfg(struct ipsecmod_env* ipsecmod_env, struct config_file* cfg)
cfg->ipsecmod_hook, strerror(errno));
return 0;
}
if(cfg->ipsecmod_whitelist &&
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
return 0;
return 1;
}
@@ -626,6 +628,8 @@ ipsecmod_inform_super(struct module_qstate* qstate, int id,
verbose(VERB_ALGO, "super has no ipsecmod state");
return;
}
if(!siq->enabled)
return;
if(qstate->return_msg) {
struct ub_packed_rrset_key* rrset_key = reply_find_answer_rrset(
+3
View File
@@ -608,6 +608,8 @@ rm -rf .git .travis.yml .gitattributes .github .gitignore || error_cleanup "Fail
info "Adding libtool utils (libtoolize)."
libtoolize -c --install || libtoolize -c || error_cleanup "Libtoolize failed."
# Turn this off, if the git repo times out for lookups.
if test "updateconfigsub" = "false"; then
# https://www.gnu.org/software/gettext/manual/html_node/config_002eguess.html
info "Updating config.guess and config.sub"
wget -O config.guess 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD'
@@ -621,6 +623,7 @@ if [ `uname -s | grep -i -c darwin` -ne 0 ]; then
xattr -d com.apple.quarantine config.sub
fi
fi
fi
info "Building configure script (autoreconf)."
autoreconf -f || error_cleanup "Autoconf failed."
+14 -14
View File
@@ -79,7 +79,7 @@
i+(int)((unsigned int)name[i]) < len) {
memmove(buf, name + i + 1, (unsigned int)name[i]);
buf[(unsigned int)name[i]] = 0;
PyList_SetItem(list, cnt, PyString_FromString(buf));
PyList_SetItem(list, cnt, PyUnicode_FromString(buf));
}
i += ((unsigned int)name[i]) + 1;
cnt++;
@@ -96,7 +96,7 @@
list = PyList_New(len);
for (i=0; i < len; i++) {
PyList_SET_ITEM(list, i, PyString_FromString(array[i]));
PyList_SET_ITEM(list, i, PyUnicode_FromString(array[i]));
}
return list;
}
@@ -207,7 +207,7 @@ struct query_info {
char buf[LDNS_MAX_DOMAINLEN];
buf[0] = '\0';
dname_str((uint8_t*)PyBytes_AsString(dname), buf);
return PyString_FromString(buf);
return PyUnicode_FromString(buf);
}
%}
@@ -345,7 +345,7 @@ struct packed_rrset_data {
PyObject* _get_data_rr_len(struct packed_rrset_data* d, int idx) {
if ((d != NULL) && (idx >= 0) &&
((size_t)idx < (d->count+d->rrsig_count)))
return PyInt_FromLong(d->rr_len[idx]);
return PyLong_FromLong(d->rr_len[idx]);
return Py_None;
}
void _set_data_rr_ttl(struct packed_rrset_data* d, int idx, uint32_t ttl)
@@ -357,7 +357,7 @@ struct packed_rrset_data {
PyObject* _get_data_rr_ttl(struct packed_rrset_data* d, int idx) {
if ((d != NULL) && (idx >= 0) &&
((size_t)idx < (d->count+d->rrsig_count)))
return PyInt_FromLong(d->rr_ttl[idx]);
return PyLong_FromLong(d->rr_ttl[idx]);
return Py_None;
}
PyObject* _get_data_rr_data(struct packed_rrset_data* d, int idx) {
@@ -555,12 +555,12 @@ struct sockaddr_storage {};
if (ss->ss_family == AF_INET) {
const struct sockaddr_in *sa4 = (struct sockaddr_in *)ss;
return PyInt_FromLong(ntohs(sa4->sin_port));
return PyLong_FromLong(ntohs(sa4->sin_port));
}
if (ss->ss_family == AF_INET6) {
const struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ss;
return PyInt_FromLong(ntohs(sa6->sin6_port));
return PyLong_FromLong(ntohs(sa6->sin6_port));
}
return Py_None;
@@ -574,7 +574,7 @@ struct sockaddr_storage {};
}
sa6 = (struct sockaddr_in6 *)ss;
return PyInt_FromLong(ntohl(sa6->sin6_flowinfo));
return PyLong_FromLong(ntohl(sa6->sin6_flowinfo));
}
PyObject *_sockaddr_storage_scope_id(const struct sockaddr_storage *ss) {
@@ -585,7 +585,7 @@ struct sockaddr_storage {};
}
sa6 = (struct sockaddr_in6 *)ss;
return PyInt_FromLong(ntohl(sa6->sin6_scope_id));
return PyLong_FromLong(ntohl(sa6->sin6_scope_id));
}
%}
@@ -661,7 +661,7 @@ struct edns_option {
%inline %{
PyObject* _edns_option_opt_code_get(struct edns_option* option) {
uint16_t opt_code = option->opt_code;
return PyInt_FromLong(opt_code);
return PyLong_FromLong(opt_code);
}
PyObject* _edns_option_opt_data_get(struct edns_option* option) {
@@ -1627,7 +1627,7 @@ int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_edns);
@@ -1711,7 +1711,7 @@ out:
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_qinfo);
@@ -1765,7 +1765,7 @@ out:
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_qstate);
@@ -1814,7 +1814,7 @@ out:
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_qstate);
+4 -4
View File
@@ -246,14 +246,14 @@ log_py_err(void)
}
/* And it should be a string all ready to go - duplicate it. */
if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) {
if (!PyBytes_Check(obResult) && !PyUnicode_Check(obResult)) {
log_err("pythonmod: cannot print exception, "
"StringIO.getvalue() result did not String_Check"
" or Unicode_Check");
goto cleanup;
}
if(PyString_Check(obResult)) {
result = PyString_AsString(obResult);
if(PyBytes_Check(obResult)) {
result = PyBytes_AsString(obResult);
} else {
ascstr = PyUnicode_AsASCIIString(obResult);
result = PyBytes_AsString(ascstr);
@@ -450,7 +450,7 @@ int pythonmod_init(struct module_env* env, int id)
pe->data = PyDict_New();
/* add the script filename to the global "mod_env" for trivial access */
fname = PyString_FromString(pe->fname);
fname = PyUnicode_FromString(pe->fname);
if(PyDict_SetItemString(pe->data, "script", fname) < 0) {
log_err("pythonmod: could not add item to dictionary");
Py_XDECREF(fname);
+22 -4
View File
@@ -1341,13 +1341,33 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if((is_doq) && !(is_https || is_ssl)) do_tcp = 0;
if(do_auto) {
enum listen_type auto_port_type;
ub_sock = calloc(1, sizeof(struct unbound_socket));
if(!ub_sock)
return 0;
if(is_dnscrypt) {
auto_port_type = listen_type_udpancil_dnscrypt;
add = "udpancil_dnscrypt";
} else if(is_doq) {
auto_port_type = listen_type_doq;
add = "doq";
if(if_listens_on(ifname, port, 53, NULL)) {
log_err("DNS over QUIC is strictly not "
"allowed on port 53 as per RFC 9250. "
"Port 53 is for DNS datagrams. Error "
"for interface '%s'.", ifname);
free(ub_sock->addr);
free(ub_sock);
return 0;
}
} else {
auto_port_type = listen_type_udpancil;
add = "udpancil";
}
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
&noip6, rcv, snd, reuseport, transparent,
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock,
(is_dnscrypt?"udpancil_dnscrypt":"udpancil"))) == -1) {
add)) == -1) {
free(ub_sock->addr);
free(ub_sock);
if(noip6) {
@@ -1366,9 +1386,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if (sock_queue_timeout && !set_recvtimestamp(s)) {
log_warn("socket timestamping is not available");
}
if(!port_insert(list, s, is_dnscrypt
?listen_type_udpancil_dnscrypt:listen_type_udpancil,
is_pp2, ub_sock)) {
if(!port_insert(list, s, auto_port_type, is_pp2, ub_sock)) {
sock_close(s);
free(ub_sock->addr);
free(ub_sock);
+84
View File
@@ -1337,6 +1337,89 @@ static void mesh_test(void)
free(c1);
}
#include "util/data/packed_rrset.h"
#include "sldns/sbuffer.h"
/** packed_rrset unit tests */
static void packed_rrset_test(void)
{
/* packed_rr_to_string assembles the dname, type, class, ttl and
* rdata of one rr into a buffer of 65535 bytes. Check that it
* refuses an rr that does not fit in there, also when the caller
* passes a dest_len that is larger than that, like the callers in
* daemon/cachedump.c and daemon/remote.c do. Without the check it
* writes past the end of the assembly buffer. */
uint8_t smalldname[] = "\003www\007example\003com";
uint8_t smallrdata[] = {0, 4, 1, 2, 3, 4};
uint8_t maxdname[LDNS_MAX_DOMAINLEN];
struct ub_packed_rrset_key rrk;
struct packed_rrset_data d;
uint8_t* rr_data[1];
size_t rr_len[1];
time_t rr_ttl[1];
size_t dest_len = 65535*4+2048; /* the size daemon/cachedump.c uses */
char* dest = (char*)malloc(dest_len);
int i;
unit_show_func("util/data/packed_rrset.c", "packed_rr_to_string");
if(!dest) fatal_exit("out of memory");
memset(&rrk, 0, sizeof(rrk));
memset(&d, 0, sizeof(d));
rrk.entry.data = &d;
rrk.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
d.count = 1;
d.rr_len = rr_len;
d.rr_ttl = rr_ttl;
d.rr_data = rr_data;
rr_ttl[0] = 3600;
/* an ordinary rr is printed, also with the large dest_len */
rrk.rk.dname = smalldname;
rrk.rk.dname_len = sizeof(smalldname);
rrk.rk.type = htons(LDNS_RR_TYPE_A);
rr_data[0] = smallrdata;
rr_len[0] = sizeof(smallrdata);
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 1);
unit_assert(strstr(dest, "1.2.3.4") != NULL);
/* a dname of the maximum length, 127 labels of one character */
for(i=0; i<127; i++) {
maxdname[i*2] = 1;
maxdname[i*2+1] = (uint8_t)'a';
}
maxdname[254] = 0;
rrk.rk.dname = maxdname;
rrk.rk.dname_len = sizeof(maxdname);
rrk.rk.type = htons(LDNS_RR_TYPE_TXT);
/* 255+2+2+4+65272 is exactly 65535, that still fits */
rr_len[0] = 65535 - 255 - 8;
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
if(!rr_data[0]) fatal_exit("out of memory");
sldns_write_uint16(rr_data[0], (uint16_t)(rr_len[0]-2));
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 1);
free(rr_data[0]);
/* one more byte of rdata does not fit and must be refused */
rr_len[0] = 65535 - 255 - 8 + 1;
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
if(!rr_data[0]) fatal_exit("out of memory");
sldns_write_uint16(rr_data[0], (uint16_t)(rr_len[0]-2));
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 0);
unit_assert(dest[0] == 0);
free(rr_data[0]);
/* the largest rdata an rr can hold, well over the buffer */
rr_len[0] = 2 + 65535;
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
if(!rr_data[0]) fatal_exit("out of memory");
sldns_write_uint16(rr_data[0], 65535);
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 0);
unit_assert(dest[0] == 0);
free(rr_data[0]);
free(dest);
}
void unit_show_func(const char* file, const char* func)
{
printf("test %s:%s\n", file, func);
@@ -1409,6 +1492,7 @@ main(int argc, char* argv[])
zonemd_test();
tcpreuse_test();
msgparse_test();
packed_rrset_test();
edns_ede_answer_encode_test();
localzone_test();
mesh_test();
+6 -1
View File
@@ -107,7 +107,12 @@ check_expected_stats () {
# Check that the rest (unspecified) stats are all 0 (no surprises).
check_rest_stats () {
echo "> Checking rest stats"
grep -F -x -v -f $EXPECTED_STATS_FILE $FILTERED_STATS_FILE > $REST_STATS_FILE
grep -F -x -v -f $EXPECTED_STATS_FILE $FILTERED_STATS_FILE | \
grep -F -v -e "msg.cache.max_collisions" \
-e "rrset.cache.max_collisions" | \
> $REST_STATS_FILE
# It filtered out the 'max_collisions', since at random, a msg
# or rrset cache entry could have a cache hash collision. */
if test $DEBUG -ne 0; then
echo "Rest:"
cat $REST_STATS_FILE
+82
View File
@@ -0,0 +1,82 @@
; config options
server:
; This is the test key 29332 in the testdata.
trust-anchor: ". 3600 IN DS 29332 8 2 b75e26316631b6e37cbc977323a08769f86e36a10fee888676d35f61e2ff4181"
val-override-date: "20201020135527"
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
fake-sha1: yes
trust-anchor-signaling: no
minimal-responses: no
log-servfail: yes
forward-zone:
name: "."
forward-addr: 10.5.5.5
CONFIG_END
SCENARIO_BEGIN Test nxdomain that gets unsigned response
; and the DS lookup that it makes gets an NSEC NXDOMAIN response.
; 10.5.5.5 forwarder
RANGE_BEGIN 0 100
ADDRESS 10.5.5.5
; unsigned NXDOMAIN response, from the first forwarder, here it is served
; from the upstream.
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NXDOMAIN
SECTION QUESTION
example.veryinvalid. IN TXT
SECTION AUTHORITY
. 3600 IN SOA ns.root. host.root. 1 3600 3600 3600 3600
ENTRY_END
; DNSKEY answer, using CSK for test simplicity.
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN DNSKEY
SECTION ANSWER
. IN DNSKEY 257 3 8 AwEAAb4WMOTBLTFvmBra5m6SK4VfViOzmvyUAU0qv861ZQXeEFvwlndqNU9rwRsMxrSWAYs5nHErKDn49usC/HyxxW1477iGFHhfgL4mjNreJm9zft2QFB1VLbRbEPYdDMLCn4co0qnG7/KG8W2i8Pym1L7f+aREwbLo+/716AS2PbaKMhfWLKLiq5wnBcUClQMNzCiwhqxDJp1oePqfkVdeUgXOtgi0dYRIKyQFhJ5VWJ22npoi/Gif0XLCADAlAwRLKc8o/yJkCxskzgpHpw5Cki1lclg0aq4ssOuPRQ+ne6IHYCz9D2mwzulblhLFamKdq7aHzNt4NlyxhpANVFiKLD8= ;{id = 29332 (ksk), size = 2048b}
. 3600 IN RRSIG DNSKEY 8 0 3600 20201116135527 20201019135527 29332 . ToK8hJrGa+kNu6y8FpRwZq2FjDPBAk5Ctchia3Vu9yTth2dR7BhK2ALTWVBwAQGwiwxXKoVK9QCxdQM0ti7CVb9x75bejkd2E6UGWVmqyTRPpn3D43qYARm87y3ZVKG7LlWHp8UOf21XLp1H7R+wuipIvBJ1XA+QGXThPdbV9EEz1kKGdprBfdpFkQdcAiuYYrOTa5cJ11z32mGiQ12fWjpb4UUbfcoDD9YOoa/S5a6h7jYBOfm75ZB8UCW3Z/SlsN8KIfYZsg5CZphpf38XH5uNLMmzpaWYhfamJZJve9Isx4eILNmdMLK4E8ESwDFCVNzMIqdf20VRg6Lh7nwQeA==
ENTRY_END
; answer for DS, from another forwarder, here returned from the test upstream.
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NXDOMAIN
SECTION QUESTION
veryinvalid. IN DS
SECTION AUTHORITY
versicherung. 3600 IN NSEC vet. NS DS RRSIG NSEC
versicherung. 3600 IN RRSIG NSEC 8 1 3600 20201116135527 20201019135527 29332 . AVAON9Y7AVwX9YWQK8JPcB6Wk/tEfQT7JrLiCRlBBQA0+mpVYYYtMyrm4aMjkhusqYcnpIZoLGOI/dxJjIwDgnMkd4EqY2oICea3I260f8z2v9e7zNobyUTjkoWsmLPc7VRLtEGKu1XyVpt7DX6ElGoSUhU4JsTx7wkkXU0SGAakL0bhK8K68B92NEVwgKX4D7+kVfpjc0aHaB3rAkhQCM/G0jEFp0RuhTX1aru6IuYrZmjW0dvQ2niec6NaYzvuGnbhMLlFLuXqSmI2B7uIFx894usd1cVWnSRg49bAkuiEv5q04ltRel1huJBGGiZlLEwanS5g53C5DHfq10OUrw==
. 3600 IN NSEC aaa. NS SOA RRSIG NSEC DNSKEY ZONEMD
. 3600 IN RRSIG NSEC 8 0 3600 20201116135527 20201019135527 29332 . E8r6rpFgFBUda2GnFSMzHZLtjy1dT+ZS0wPRE12RNwVK547bo2vByv9EFhOHS6sEIFqX+AmIJotuiEPKnCFUTr6FKscaxtw38dJRZ3wldqV6dmqUiRmz91crDCV5nSL45FIbkWKk1Q+tnXie3sZ4zwBc12kGg2BttMAQ0i4sbMbf6EUNYZGwYzSB0/VhXVJcl8gl+5lfpiVqfWNZI7vTEaHqrC2gBC3UK1cQE9lQOqhJ6H5ThA1FR9j/mZFM9sG5vQ2Mqlzl2iiN2Y6mCptDY1vwfff6AnT0YeDwJ/XwGisMZrSvTCYaiRndb8CUUmCr23AFy5OER1rmeFGkHX5+WQ==
. 3600 IN SOA ns.root. host.root. 1 3600 3600 3600 3600
. 3600 IN RRSIG SOA 8 0 3600 20201116135527 20201019135527 29332 . tVeReLMXPnl6rk4QX94xy9lCodQ+xc39lokbNkvbXnTURNCOAwtNiMMPlAAJ3/HTpIxo175gPfupACIveBtgajdp85jUIvLMOM5B6lX80+dUPBGZ4gHVjf+8EGnr7q2wnW2+KcJu0OhN2g+YqCV6aPi8pzuAp+AMsBYcMfXqEQq9Lxqv6TL50MUCJN3GPCyBIdjbs/A+ZB7D1EOO1YgdbsMHK/pWKYt4UfBFfekoA6joIGf4vBKKRTWnoo0BcrFob3AW1SyJkoxoqEsN3YAVL9jNkJCkU0/adLypHgDNayLgsWI5/o4Ng8LxN6tNxAilkMhcGY80T5g0uo+ukY7McA==
ENTRY_END
RANGE_END
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD DO
SECTION QUESTION
example.veryinvalid. IN TXT
ENTRY_END
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA DO SERVFAIL
SECTION QUESTION
example.veryinvalid. IN TXT
SECTION ANSWER
ENTRY_END
SCENARIO_END
+3 -1
View File
@@ -280,7 +280,9 @@ int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i,
size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i];
time_t adjust = 0;
log_assert(dest_len > 0 && dest);
if(rlen > dest_len) {
/* rlen is the length written into rr, dest_len bounds the output
* string; check both, callers can pass a dest_len over sizeof(rr). */
if(rlen > dest_len || rlen > sizeof(rr)) {
dest[0] = 0;
return 0;
}
+21
View File
@@ -72,6 +72,14 @@ static ub_thread_key_type logkey;
#ifndef THREADS_DISABLED
/** pthread mutex to protect FILE* */
static lock_basic_type log_lock;
#ifdef HAVE_PTHREAD
/* Guards the one-time initialization below. Without this, two threads
* calling log_init() for the first time concurrently (e.g. via
* ub_ctx_create() from a multi-threaded application) can both observe
* key_created==0 and both call lock_basic_init(&log_lock), a data race
* that reinitializes/corrupts an in-use mutex. */
static pthread_once_t log_lock_once = PTHREAD_ONCE_INIT;
#endif
#endif
/** the identity of this executable/process */
static const char* ident="unbound";
@@ -85,15 +93,28 @@ static int log_time_asc = 0;
/** print time in iso format */
static int log_time_iso = 0;
#if !defined(THREADS_DISABLED) && defined(HAVE_PTHREAD)
static void log_lock_init_once(void)
{
ub_thread_key_create(&logkey, NULL);
lock_basic_init(&log_lock);
key_created = 1;
}
#endif
void
log_init(const char* filename, int use_syslog, const char* chrootdir)
{
FILE *f;
#if !defined(THREADS_DISABLED) && defined(HAVE_PTHREAD)
(void)pthread_once(&log_lock_once, log_lock_init_once);
#else
if(!key_created) {
key_created = 1;
ub_thread_key_create(&logkey, NULL);
lock_basic_init(&log_lock);
}
#endif
lock_basic_lock(&log_lock);
if(logfile
#if defined(HAVE_SYSLOG_H) || defined(UB_ON_WINDOWS)
+14
View File
@@ -1323,6 +1323,20 @@ int val_has_signed_nsecs(struct reply_info* rep, char** reason)
return 0;
}
void val_has_auth_nsecs(struct reply_info* rep, int* has_nsec, int* has_nsec3)
{
size_t i, num_nsec = 0, num_nsec3 = 0;
for(i=rep->an_numrrsets; i<rep->an_numrrsets+rep->ns_numrrsets; i++) {
if(rep->rrsets[i]->rk.type == htons(LDNS_RR_TYPE_NSEC))
num_nsec++;
else if(rep->rrsets[i]->rk.type == htons(LDNS_RR_TYPE_NSEC3))
num_nsec3++;
else continue;
}
*has_nsec = (num_nsec != 0);
*has_nsec3 = (num_nsec3 != 0);
}
struct dns_msg*
val_find_DS(struct module_env* env, uint8_t* nm, size_t nmlen, uint16_t c,
struct regional* region, uint8_t* topname)
+8
View File
@@ -410,6 +410,14 @@ void val_blacklist(struct sock_list** blacklist, struct regional* region,
*/
int val_has_signed_nsecs(struct reply_info* rep, char** reason);
/**
* See if there are NSECs, or NSEC3s in the authority section.
* @param rep: reply to check
* @param has_nsec: returned true if it has nsecs.
* @param has_nsec3: returned true if it has nsec3s.
*/
void val_has_auth_nsecs(struct reply_info* rep, int* has_nsec, int* has_nsec3);
/**
* Return algo number for favorite (best) algorithm that we support in DS.
* @param ds_rrset: the DSes in this rrset are inspected and best algo chosen.
+20
View File
@@ -3116,6 +3116,7 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
case sec_status_unchecked:
default:
/* NSEC proof did not work, try next */
verbose(VERB_ALGO, "NSEC proof did not prove insecure delegation, try NSEC3");
break;
}
@@ -3151,6 +3152,25 @@ ds_response_to_ke(struct module_qstate* qstate, struct val_qstate* vq,
*ke = NULL;
return 0;
case sec_status_bogus:
/* It could be that the NSEC proof failed,
* and, then tried NSEC3. */
{
int has_nsec=0, has_nsec3=0;
val_has_auth_nsecs(msg->rep, &has_nsec,
&has_nsec3);
if(!has_nsec3 && has_nsec) {
/* The NSECs are the cause, mention that in the error message. */
verbose(VERB_DETAIL, "NSECs for the "
"referral did not prove no DS.");
errinf_ede(qstate, "NSECs for the referral did not prove no DS", LDNS_EDE_DNSSEC_BOGUS);
goto return_bogus;
}
if(!has_nsec3 && !has_nsec) {
verbose(VERB_DETAIL, "absence of NSECs and NSEC3s when attempting to prove no DS.");
errinf_ede(qstate, "no NSECs or NSEC3s when attempting to prove no DS", LDNS_EDE_DNSSEC_BOGUS);
goto return_bogus;
}
}
verbose(VERB_DETAIL, "NSEC3s for the "
"referral did not prove no DS.");
errinf_ede(qstate, reason, reason_bogus);