mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-17 21:25:50 +02:00
Compare commits
206
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c33ad1b1a2 | ||
|
|
84d9682dd0 | ||
|
|
4b1635e194 | ||
|
|
aac261cbb3 | ||
|
|
ae1b3810cc | ||
|
|
96f8755520 | ||
|
|
2ce2ca3691 | ||
|
|
c29ff70f6a | ||
|
|
8a15ffee62 | ||
|
|
8c702de175 | ||
|
|
804cff4c15 | ||
|
|
e180b06298 | ||
|
|
3530c81e29 | ||
|
|
02b16de1ae | ||
|
|
1ad8d4c395 | ||
|
|
364ac737f7 | ||
|
|
f7637a4f18 | ||
|
|
1e1940383a | ||
|
|
f52a9e864b | ||
|
|
13ec8d0f26 | ||
|
|
27f22b8808 | ||
|
|
f54e0791ba | ||
|
|
01dfd2f466 | ||
|
|
f157c691bb | ||
|
|
fea0ff550b | ||
|
|
87d59bfced | ||
|
|
75b6dba593 | ||
|
|
138fb48eac | ||
|
|
dae7a37974 | ||
|
|
8ae4b4545d | ||
|
|
c343fff3a4 | ||
|
|
a794c87578 | ||
|
|
ef5ca84360 | ||
|
|
8d8fa42266 | ||
|
|
a587535c5d | ||
|
|
94d5babaee | ||
|
|
fe946ba4e9 | ||
|
|
6a31e470f8 | ||
|
|
e577695aeb | ||
|
|
25fe602024 | ||
|
|
df0e86de49 | ||
|
|
e49b550cf3 | ||
|
|
07c96792f2 | ||
|
|
84ab430e11 | ||
|
|
53499e4a88 | ||
|
|
8a25a97687 | ||
|
|
c112bcf2fd | ||
|
|
9de549c498 | ||
|
|
84c645e7b3 | ||
|
|
197a425c7d | ||
|
|
311054728d | ||
|
|
6d74856212 | ||
|
|
d489e6027e | ||
|
|
e1d146d6b0 | ||
|
|
eb2fe8df8d | ||
|
|
86a8be75f0 | ||
|
|
52fc5ee374 | ||
|
|
82359c8fb1 | ||
|
|
c996671a1f | ||
|
|
e233a1ef65 | ||
|
|
06ff9f20d0 | ||
|
|
af209a12ea | ||
|
|
84ac7e1b58 | ||
|
|
24d502763c | ||
|
|
99c61c19ac | ||
|
|
cb05e9d525 | ||
|
|
abddd4e270 | ||
|
|
656b412492 | ||
|
|
f15a46fcd4 | ||
|
|
8d434bf744 | ||
|
|
13b269d398 | ||
|
|
7aff88881a | ||
|
|
b97bd3a1fc | ||
|
|
6aa5ad85f4 | ||
|
|
42b19c20c1 | ||
|
|
db1fe8b475 | ||
|
|
f4f964f4fb | ||
|
|
a2272860de | ||
|
|
95083d4377 | ||
|
|
5ce0bf5281 | ||
|
|
6a0d5e2cb1 | ||
|
|
330d5211c9 | ||
|
|
2dc28a249a | ||
|
|
c5f14dc880 | ||
|
|
a2ace114de | ||
|
|
2e9b880718 | ||
|
|
a0ec6cd946 | ||
|
|
ea36979c40 | ||
|
|
315077b9e6 | ||
|
|
535d899bef | ||
|
|
8656cfd4c8 | ||
|
|
8f44ddb7de | ||
|
|
4484dc3954 | ||
|
|
eb3bba0724 | ||
|
|
2eff1d8ab5 | ||
|
|
4672fa5b53 | ||
|
|
18029fc44f | ||
|
|
5c6f56f8f1 | ||
|
|
9af29c3ed1 | ||
|
|
76ef8c5803 | ||
|
|
94ef1a8fee | ||
|
|
683241a2f5 | ||
|
|
92ab54641e | ||
|
|
da3812953a | ||
|
|
1bd7c8dfee | ||
|
|
8f96ae7acf | ||
|
|
c4f8e60c85 | ||
|
|
a296b248b0 | ||
|
|
1ef131299a | ||
|
|
5b58a872ef | ||
|
|
94b04d6d46 | ||
|
|
f1a65eb4e8 | ||
|
|
38e1e3eec3 | ||
|
|
bff3d762ff | ||
|
|
fb322f3e87 | ||
|
|
2feee13735 | ||
|
|
1d36696462 | ||
|
|
aa4e2a9e69 | ||
|
|
8e04d04949 | ||
|
|
c5627dbd52 | ||
|
|
014ed9c5ff | ||
|
|
16e1e6d375 | ||
|
|
1a9a4e4ca1 | ||
|
|
f7f638e18f | ||
|
|
c956aea93d | ||
|
|
4556a4f490 | ||
|
|
1cdddf0fe9 | ||
|
|
18fec256b7 | ||
|
|
567c70dada | ||
|
|
8b4b2a88f7 | ||
|
|
faf40c97fc | ||
|
|
daa016e3e4 | ||
|
|
039f69e735 | ||
|
|
b39009e487 | ||
|
|
933769ee73 | ||
|
|
57bff79627 | ||
|
|
1b5559d534 | ||
|
|
9d271c5343 | ||
|
|
74cc49e6c4 | ||
|
|
d414ebf0c7 | ||
|
|
9b123d1b78 | ||
|
|
37b71261a2 | ||
|
|
4426db4d3d | ||
|
|
fe10bc7682 | ||
|
|
67d2eae28c | ||
|
|
9010a7075e | ||
|
|
cc6dbc9f38 | ||
|
|
4198343dbe | ||
|
|
08600d68e8 | ||
|
|
18e098285e | ||
|
|
f1b35bab4b | ||
|
|
84ed77238d | ||
|
|
adb0374a4d | ||
|
|
b0b634558b | ||
|
|
8546247292 | ||
|
|
44659cb3bf | ||
|
|
a1ac2d0252 | ||
|
|
5c7a26b615 | ||
|
|
09d352b917 | ||
|
|
c0522043f0 | ||
|
|
b858801feb | ||
|
|
588db09928 | ||
|
|
5c66c48a1b | ||
|
|
83336477c6 | ||
|
|
e3e5eb66cf | ||
|
|
00d3b97dbb | ||
|
|
f6269baa60 | ||
|
|
19154c6e58 | ||
|
|
0f43b0ea6c | ||
|
|
e6d92f458f | ||
|
|
a31b9d50e2 | ||
|
|
fceb4e8585 | ||
|
|
98f4257890 | ||
|
|
0a15118aff | ||
|
|
e887a79a92 | ||
|
|
f9b9050ab8 | ||
|
|
94735384fd | ||
|
|
5dab0609e5 | ||
|
|
024c921dbf | ||
|
|
1a808e2978 | ||
|
|
56ded934de | ||
|
|
98952f11d1 | ||
|
|
cb4b3de62f | ||
|
|
c8dcfc0853 | ||
|
|
2bb28fdf12 | ||
|
|
6ad26909dd | ||
|
|
9602973c86 | ||
|
|
713b1783d4 | ||
|
|
e06b7eb3f1 | ||
|
|
a33f0638e1 | ||
|
|
bbeee42e25 | ||
|
|
1cb9595a42 | ||
|
|
aa21e38b3a | ||
|
|
964848b94a | ||
|
|
a4dd321fd8 | ||
|
|
d23a28a693 | ||
|
|
5423c0a8e9 | ||
|
|
6a5385f291 | ||
|
|
16f3478048 | ||
|
|
c8860a5fb6 | ||
|
|
735c96aac7 | ||
|
|
a75ea01a15 | ||
|
|
21f02a0865 | ||
|
|
e017d66fc1 | ||
|
|
adaf5dab49 | ||
|
|
1d3d78dff5 |
@@ -12,6 +12,7 @@ jobs:
|
||||
build:
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- name: GCC on Linux
|
||||
@@ -48,15 +49,6 @@ jobs:
|
||||
os: ubuntu-latest
|
||||
config: 'CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=address" --disable-flto --disable-static'
|
||||
make_test: "yes"
|
||||
- name: Apple iPhone on iOS, armv7
|
||||
os: macos-latest
|
||||
AUTOTOOLS_HOST: armv7-apple-ios
|
||||
OPENSSL_HOST: ios-cross
|
||||
IOS_SDK: iPhoneOS
|
||||
IOS_CPU: armv7s
|
||||
test_ios: "yes"
|
||||
config: "no"
|
||||
make: "no"
|
||||
- name: Apple iPhone on iOS, arm64
|
||||
os: macos-latest
|
||||
AUTOTOOLS_HOST: aarch64-apple-ios
|
||||
@@ -84,15 +76,6 @@ jobs:
|
||||
test_ios: "yes"
|
||||
config: "no"
|
||||
make: "no"
|
||||
- name: iPhoneSimulator on OS X, i386
|
||||
os: macos-latest
|
||||
AUTOTOOLS_HOST: i386-apple-ios
|
||||
OPENSSL_HOST: iphoneos-cross
|
||||
IOS_SDK: iPhoneSimulator
|
||||
IOS_CPU: i386
|
||||
test_ios: "yes"
|
||||
config: "no"
|
||||
make: "no"
|
||||
- name: iPhoneSimulator on OS X, x86_64
|
||||
os: macos-latest
|
||||
AUTOTOOLS_HOST: x86_64-apple-ios
|
||||
@@ -190,7 +173,7 @@ jobs:
|
||||
cross_platform_config: "--enable-debug --disable-flto --with-libevent --disable-static"
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
submodules: false
|
||||
persist-credentials: false
|
||||
@@ -206,6 +189,8 @@ jobs:
|
||||
cd ..
|
||||
export prepath=`pwd`
|
||||
echo prepath=${prepath}
|
||||
# parralel build option
|
||||
export MINJ="-j4"
|
||||
echo "choco install winflexbison3"
|
||||
choco install winflexbison3
|
||||
echo 'LEX="win_flex"'
|
||||
@@ -228,8 +213,8 @@ jobs:
|
||||
C:/msys64/usr/bin/perl ./Configure no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix="$prepath/openssl" PERL="C:/msys64/usr/bin/perl"
|
||||
# make the libs only, build faster
|
||||
echo "make build_libs"
|
||||
#make
|
||||
make build_libs
|
||||
#make $MINJ
|
||||
make $MINJ build_libs
|
||||
mv Makefile Makefile.orig
|
||||
# fixup \\ in the installtop to /.
|
||||
echo "fixup INSTALLTOP"
|
||||
@@ -261,7 +246,7 @@ jobs:
|
||||
mv xmlwf/Makefile xmlwf/Makefile.orig
|
||||
sed -e 's/SHELL/SHELLZZ/g' < xmlwf/Makefile.orig > xmlwf/Makefile
|
||||
echo "make"
|
||||
make
|
||||
make $MINJ
|
||||
echo "make install"
|
||||
make install
|
||||
cd ..
|
||||
@@ -269,7 +254,7 @@ jobs:
|
||||
cd unbound
|
||||
echo "./configure --enable-debug --enable-static-exe --disable-flto \"--with-ssl=$prepath/openssl\" --with-libexpat=\"$prepath/expat\" --disable-shared"
|
||||
./configure --enable-debug --enable-static-exe --disable-flto "--with-ssl=$prepath/openssl" --with-libexpat="$prepath/expat" --disable-shared
|
||||
make
|
||||
make $MINJ
|
||||
# specific test output
|
||||
#make testbound.exe; ./testbound.exe -s
|
||||
#make testbound; ./testbound.exe -p testdata/acl.rpl -o -vvvv
|
||||
@@ -364,7 +349,7 @@ jobs:
|
||||
echo "::endgroup::"
|
||||
- name: cross-platform-action on ${{ matrix.cross_platform_os }} ${{ matrix.cross_platform_version }}
|
||||
if: ${{ matrix.with_cross_platform_action == 'yes' }}
|
||||
uses: cross-platform-actions/action@v0.25.0
|
||||
uses: cross-platform-actions/action@v1.0.0
|
||||
env:
|
||||
CROSS_PLATFORM_OS: ${{ matrix.cross_platform_os }}
|
||||
with:
|
||||
|
||||
@@ -12,7 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
- uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
- name: configure
|
||||
|
||||
@@ -25,18 +25,21 @@ Unbound can be compiled and installed using:
|
||||
./configure && make && make install
|
||||
```
|
||||
|
||||
You can use libevent if you want. libevent is useful when using many (10000)
|
||||
outgoing ports. By default max 256 ports are opened at the same time and the
|
||||
builtin alternative is equally capable and a little faster.
|
||||
|
||||
You can use libevent if you want. libevent is useful when using many (e.g.,
|
||||
10000) outgoing ports.
|
||||
Use the `--with-libevent` configure option to compile Unbound with libevent
|
||||
support.
|
||||
|
||||
If not, the default builtin alternative opens max 256 ports at the same time
|
||||
and is equally capable and a little faster.
|
||||
|
||||
|
||||
## Unbound configuration
|
||||
|
||||
All of Unbound's configuration options are described in the man pages, which
|
||||
will be installed and are available on the Unbound
|
||||
[documentation page](https://unbound.docs.nlnetlabs.nl/).
|
||||
All of Unbound's configuration options are described in the `unbound.conf(5)`
|
||||
man page, which will be installed and is also available on the Unbound
|
||||
[documentation page](https://unbound.docs.nlnetlabs.nl/en/latest/manpages/unbound.conf.html)
|
||||
for the latest version.
|
||||
|
||||
An example configuration file is located in
|
||||
An example configuration file, with minimal documentation, is located in
|
||||
[doc/example.conf](https://github.com/NLnetLabs/unbound/blob/master/doc/example.conf.in).
|
||||
|
||||
+7
-1
@@ -2,7 +2,9 @@
|
||||
# Copyright 2009, Wouter Wijngaards, NLnet Labs.
|
||||
# BSD licensed.
|
||||
#
|
||||
# Version 50
|
||||
# Version 51
|
||||
# 2025-11-06 Fix ACX_CHECK_NONSTRING_ATTRIBUTE to reject clang, that prints
|
||||
# a warning for 'unknown attribute' when nonstring is used.
|
||||
# 2025-09-29 add ac_cv_func_malloc_0_nonnull as a cache value for the malloc(0)
|
||||
# check by ACX_FUNC_MALLOC.
|
||||
# 2025-09-29 add ACX_CHECK_NONSTRING_ATTRIBUTE, AHX_CONFIG_NONSTRING_ATTRIBUTE.
|
||||
@@ -535,6 +537,9 @@ dnl result in HAVE_ATTR_NONSTRING.
|
||||
dnl Make sure you include AHX_CONFIG_NONSTRING_ATTRIBUTE also.
|
||||
AC_DEFUN([ACX_CHECK_NONSTRING_ATTRIBUTE],
|
||||
[AC_REQUIRE([AC_PROG_CC])
|
||||
AC_REQUIRE([ACX_CHECK_ERROR_FLAGS])
|
||||
BAKCFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $ERRFLAG"
|
||||
AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "nonstring" attribute)
|
||||
AC_CACHE_VAL(ac_cv_c_nonstring_attribute,
|
||||
[ac_cv_c_nonstring_attribute=no
|
||||
@@ -546,6 +551,7 @@ struct test {
|
||||
struct test t = { "1" };
|
||||
(void) t;
|
||||
]])],[ac_cv_c_nonstring_attribute="yes"],[ac_cv_c_nonstring_attribute="no"])
|
||||
CFLAGS="$BAKCFLAGS"
|
||||
])
|
||||
|
||||
dnl Setup ATTR_NONSTRING config.h parts.
|
||||
|
||||
+11
-4
@@ -754,8 +754,10 @@ cachedb_intcache_store(struct module_qstate* qstate, int msg_expired,
|
||||
"(original ttl: %d)", (int)original_ttl);
|
||||
/* The expired entry does not get checked by the validator
|
||||
* and we need a validation value for it. */
|
||||
/* By setting this to unchecked, bogus data is not returned
|
||||
* as non-bogus. */
|
||||
if(qstate->env->cfg->cachedb_check_when_serve_expired)
|
||||
qstate->return_msg->rep->security = sec_status_insecure;
|
||||
qstate->return_msg->rep->security = sec_status_unchecked;
|
||||
}
|
||||
(void)dns_cache_store(qstate->env, &qstate->qinfo,
|
||||
qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0,
|
||||
@@ -803,8 +805,11 @@ cachedb_handle_query(struct module_qstate* qstate,
|
||||
return;
|
||||
}
|
||||
|
||||
if(qstate->blacklist || qstate->no_cache_lookup) {
|
||||
/* cache is blacklisted or we are instructed from edns to not look */
|
||||
if(qstate->blacklist || qstate->no_cache_lookup
|
||||
|| iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL,
|
||||
NULL, 0)) {
|
||||
/* cache is blacklisted or we are instructed from edns to not
|
||||
* look or a forwarder/stub forbids it */
|
||||
/* pass request to next module */
|
||||
qstate->ext_state[id] = module_wait_module;
|
||||
return;
|
||||
@@ -892,7 +897,9 @@ cachedb_handle_response(struct module_qstate* qstate,
|
||||
{
|
||||
qstate->is_cachedb_answer = 0;
|
||||
/* check if we are not enabled or instructed to not cache, and skip */
|
||||
if(!ie->enabled || qstate->no_cache_store) {
|
||||
if(!ie->enabled || qstate->no_cache_store
|
||||
|| iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL,
|
||||
NULL, 0)) {
|
||||
/* we are done with the query */
|
||||
qstate->ext_state[id] = module_finished;
|
||||
return;
|
||||
|
||||
@@ -143,6 +143,12 @@ redis_connect(const char* host, int port, const char* path,
|
||||
{
|
||||
struct timeval now_val;
|
||||
redisContext* ctx;
|
||||
#ifdef THREADS_DISABLED
|
||||
/* Fix attribute unused warning.
|
||||
* wait_lock is only used with lock_basic_* functions that are nop'ed
|
||||
* when compiled without thread support. */
|
||||
(void)wait_lock;
|
||||
#endif /* THREADS_DISABLED */
|
||||
|
||||
/* See if the redis server is down, and reconnect has to wait. */
|
||||
if(*reconnect_attempts > REDIS_RECONNECT_ATTEMPT_LIMIT) {
|
||||
|
||||
@@ -38,6 +38,9 @@
|
||||
#ifndef UB_ON_WINDOWS
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
#ifdef __QNX__
|
||||
#include "util/log.h"
|
||||
#endif /* __QNX__ */
|
||||
|
||||
#define KEYSTREAM_ONLY
|
||||
#include "chacha_private.h"
|
||||
@@ -187,7 +190,11 @@ _rs_stir(void)
|
||||
if(errno != ENOSYS ||
|
||||
fallback_getentropy_urandom(rnd, sizeof rnd) == -1) {
|
||||
#ifdef SIGKILL
|
||||
#ifndef __QNX__
|
||||
raise(SIGKILL);
|
||||
#else /* !__QNX__ */
|
||||
fatal_exit("failed to getentropy");
|
||||
#endif /* __QNX__ */
|
||||
#else
|
||||
exit(9); /* windows */
|
||||
#endif
|
||||
|
||||
@@ -48,8 +48,8 @@ typedef struct
|
||||
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
|
||||
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
|
||||
|
||||
static const char sigma[16] = "expand 32-byte k";
|
||||
static const char tau[16] = "expand 16-byte k";
|
||||
static const char ATTR_NONSTRING(sigma[16]) = "expand 32-byte k";
|
||||
static const char ATTR_NONSTRING(tau[16]) = "expand 16-byte k";
|
||||
|
||||
static void
|
||||
chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ATTR_UNUSED(ivbits))
|
||||
|
||||
@@ -29,7 +29,9 @@
|
||||
#include <sys/param.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/resource.h>
|
||||
#ifndef __QNX__
|
||||
#include <sys/syscall.h>
|
||||
#endif /* !__QNX__ */
|
||||
#ifdef SYS__sysctl
|
||||
#include <linux/sysctl.h>
|
||||
#endif
|
||||
@@ -42,7 +44,9 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#ifndef __QNX__
|
||||
#include <link.h>
|
||||
#endif /* __QNX__ */
|
||||
#include <termios.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
@@ -60,12 +64,14 @@
|
||||
#define SHA512_Final(r, c) sha512_digest(c, SHA512_DIGEST_SIZE, r)
|
||||
#endif
|
||||
|
||||
#ifndef __QNX__
|
||||
#include <linux/types.h>
|
||||
#include <linux/random.h>
|
||||
#ifdef HAVE_GETAUXVAL
|
||||
#include <sys/auxv.h>
|
||||
#endif
|
||||
#include <sys/vfs.h>
|
||||
#endif /* !__QNX__ */
|
||||
#ifndef MAP_ANON
|
||||
#define MAP_ANON MAP_ANONYMOUS
|
||||
#endif
|
||||
@@ -94,8 +100,10 @@ static int getentropy_urandom(void *buf, size_t len);
|
||||
#ifdef SYS__sysctl
|
||||
static int getentropy_sysctl(void *buf, size_t len);
|
||||
#endif
|
||||
#ifndef __QNX__
|
||||
static int getentropy_fallback(void *buf, size_t len);
|
||||
static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data);
|
||||
#endif /* !__QNX__ */
|
||||
|
||||
int
|
||||
getentropy(void *buf, size_t len)
|
||||
@@ -178,6 +186,7 @@ getentropy(void *buf, size_t len)
|
||||
* sysctl ABI, or consider providing a new failsafe API which
|
||||
* works in a chroot or when file descriptors are exhausted.
|
||||
*/
|
||||
#ifndef __QNX__
|
||||
#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
|
||||
#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
|
||||
raise(SIGKILL);
|
||||
@@ -185,6 +194,9 @@ getentropy(void *buf, size_t len)
|
||||
ret = getentropy_fallback(buf, len);
|
||||
if (ret != -1)
|
||||
return (ret);
|
||||
#else /* !__QNX__ */
|
||||
fatal_exit("failed to read from /dev/urandom");
|
||||
#endif /* __QNX__ */
|
||||
|
||||
errno = EIO;
|
||||
return (ret);
|
||||
@@ -214,7 +226,11 @@ getentropy_urandom(void *buf, size_t len)
|
||||
{
|
||||
struct stat st;
|
||||
size_t i;
|
||||
#ifndef __QNX__
|
||||
int fd, cnt, flags;
|
||||
#else /* !__QNX__ */
|
||||
int fd, flags;
|
||||
#endif /* __QNX__ */
|
||||
int save_errno = errno;
|
||||
|
||||
start:
|
||||
@@ -241,10 +257,12 @@ start:
|
||||
close(fd);
|
||||
goto nodevrandom;
|
||||
}
|
||||
#ifndef __QNX__
|
||||
if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) {
|
||||
close(fd);
|
||||
goto nodevrandom;
|
||||
}
|
||||
#endif /* !__QNX__ */
|
||||
for (i = 0; i < len; ) {
|
||||
size_t wanted = len - i;
|
||||
ssize_t ret = read(fd, (char *)buf + i, wanted);
|
||||
@@ -265,6 +283,7 @@ nodevrandom:
|
||||
return (-1);
|
||||
}
|
||||
|
||||
#ifndef __QNX__
|
||||
#ifdef SYS__sysctl
|
||||
static int
|
||||
getentropy_sysctl(void *buf, size_t len)
|
||||
@@ -537,3 +556,4 @@ getentropy_fallback(void *buf, size_t len)
|
||||
errno = save_errno;
|
||||
return (0); /* satisfied */
|
||||
}
|
||||
#endif /* !__QNX__ */
|
||||
|
||||
+1
-4
@@ -42,10 +42,7 @@ static const int year_lengths[2] = {
|
||||
};
|
||||
|
||||
static void
|
||||
timesub(timep, offset, tmp)
|
||||
const time_t * const timep;
|
||||
const long offset;
|
||||
struct tm * const tmp;
|
||||
timesub(const time_t * const timep, const long offset, struct tm * const tmp)
|
||||
{
|
||||
long days;
|
||||
long rem;
|
||||
|
||||
+21
@@ -564,12 +564,27 @@
|
||||
/* Define if you have POSIX threads libraries and header files. */
|
||||
#undef HAVE_PTHREAD
|
||||
|
||||
/* Define to 1 if you have the <pthread_np.h> header file. */
|
||||
#undef HAVE_PTHREAD_NP_H
|
||||
|
||||
/* Have PTHREAD_PRIO_INHERIT. */
|
||||
#undef HAVE_PTHREAD_PRIO_INHERIT
|
||||
|
||||
/* Define to 1 if the system has the type `pthread_rwlock_t'. */
|
||||
#undef HAVE_PTHREAD_RWLOCK_T
|
||||
|
||||
/* Define if pthread_setname_np has the common 2 arguments. */
|
||||
#undef HAVE_PTHREAD_SETNAME_NP
|
||||
|
||||
/* Define if pthread_setname_np has only 1 argument. */
|
||||
#undef HAVE_PTHREAD_SETNAME_NP1
|
||||
|
||||
/* Define if pthread_setname_np has 3 arguments. */
|
||||
#undef HAVE_PTHREAD_SETNAME_NP3
|
||||
|
||||
/* Define if pthread_setname_np exists as pthread_set_name_np instead. */
|
||||
#undef HAVE_PTHREAD_SET_NAME_NP
|
||||
|
||||
/* Define to 1 if the system has the type `pthread_spinlock_t'. */
|
||||
#undef HAVE_PTHREAD_SPINLOCK_T
|
||||
|
||||
@@ -735,6 +750,12 @@
|
||||
/* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */
|
||||
#undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
|
||||
|
||||
/* Define to 1 if `st_mtimensec' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_MTIMENSEC
|
||||
|
||||
/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */
|
||||
#undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
|
||||
|
||||
/* Define if you have Swig libraries and header files. */
|
||||
#undef HAVE_SWIG
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
#! /bin/sh
|
||||
# Guess values for system-dependent variables and create Makefiles.
|
||||
# Generated by GNU Autoconf 2.71 for unbound 1.24.1.
|
||||
# Generated by GNU Autoconf 2.71 for unbound 1.25.2.
|
||||
#
|
||||
# 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.24.1'
|
||||
PACKAGE_STRING='unbound 1.24.1'
|
||||
PACKAGE_VERSION='1.25.2'
|
||||
PACKAGE_STRING='unbound 1.25.2'
|
||||
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.24.1 to adapt to many kinds of systems.
|
||||
\`configure' configures unbound 1.25.2 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.24.1:";;
|
||||
short | recursive ) echo "Configuration of unbound 1.25.2:";;
|
||||
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.24.1
|
||||
unbound configure 1.25.2
|
||||
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.24.1, which was
|
||||
It was created by unbound $as_me 1.25.2, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
$ $0$ac_configure_args_raw
|
||||
@@ -3251,13 +3251,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
UNBOUND_VERSION_MAJOR=1
|
||||
|
||||
UNBOUND_VERSION_MINOR=24
|
||||
UNBOUND_VERSION_MINOR=25
|
||||
|
||||
UNBOUND_VERSION_MICRO=1
|
||||
UNBOUND_VERSION_MICRO=2
|
||||
|
||||
|
||||
LIBUNBOUND_CURRENT=9
|
||||
LIBUNBOUND_REVISION=34
|
||||
LIBUNBOUND_REVISION=38
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -3359,6 +3359,10 @@ LIBUNBOUND_AGE=1
|
||||
# 1.23.1 had 9:32:1
|
||||
# 1.24.0 had 9:33:1
|
||||
# 1.24.1 had 9:34:1
|
||||
# 1.24.2 had 9:35:1
|
||||
# 1.25.0 had 9:36:1
|
||||
# 1.25.1 had 9:37:1
|
||||
# 1.25.2 had 9:38:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
@@ -6948,6 +6952,9 @@ printf "%s\n" "#define HAVE_ATTR_UNUSED 1" >>confdefs.h
|
||||
fi
|
||||
|
||||
|
||||
|
||||
BAKCFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS $ERRFLAG"
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"nonstring\" attribute" >&5
|
||||
printf %s "checking whether the C compiler (${CC-cc}) accepts the \"nonstring\" attribute... " >&6; }
|
||||
if test ${ac_cv_c_nonstring_attribute+y}
|
||||
@@ -6980,6 +6987,7 @@ else $as_nop
|
||||
ac_cv_c_nonstring_attribute="no"
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
CFLAGS="$BAKCFLAGS"
|
||||
|
||||
fi
|
||||
|
||||
@@ -7058,7 +7066,14 @@ else $as_nop
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
#include <stdio.h>
|
||||
__attribute__((noreturn)) void f(int x) { printf("%d", x); }
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
__attribute__((noreturn)) void f(int x) { printf("%d", x); exit(1); }
|
||||
|
||||
int
|
||||
main (void)
|
||||
@@ -19067,6 +19082,171 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
|
||||
|
||||
fi
|
||||
|
||||
if test x_$ub_have_pthreads != x_no; then
|
||||
# Long checks to support pthread_setname_np().
|
||||
# Some OSes have the extra non-portable functions in a specific
|
||||
# header file.
|
||||
ac_fn_c_check_header_compile "$LINENO" "pthread_np.h" "ac_cv_header_pthread_np_h" "$ac_includes_default
|
||||
"
|
||||
if test "x$ac_cv_header_pthread_np_h" = xyes
|
||||
then :
|
||||
printf "%s\n" "#define HAVE_PTHREAD_NP_H 1" >>confdefs.h
|
||||
|
||||
fi
|
||||
|
||||
BAKCFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Werror"
|
||||
# MacOS only has 1 argument, the name.
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np has only 1 argument" >&5
|
||||
printf %s "checking whether pthread_setname_np has only 1 argument... " >&6; }
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
$ac_includes_default
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
(void)pthread_setname_np("");
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"
|
||||
then :
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
|
||||
printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP1 1" >>confdefs.h
|
||||
|
||||
|
||||
else $as_nop
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; }
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
# NetBSD has 3 arguments to allow for formatting of the name.
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np has 3 arguments" >&5
|
||||
printf %s "checking whether pthread_setname_np has 3 arguments... " >&6; }
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
$ac_includes_default
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
(void)pthread_setname_np(0, "", NULL);
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"
|
||||
then :
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
|
||||
printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP3 1" >>confdefs.h
|
||||
|
||||
|
||||
else $as_nop
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; }
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
# Most OSes have the common 2 arguments, thread and name.
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np has the common 2 arguments" >&5
|
||||
printf %s "checking whether pthread_setname_np has the common 2 arguments... " >&6; }
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
$ac_includes_default
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
(void)pthread_setname_np(0, "");
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"
|
||||
then :
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
|
||||
printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP 1" >>confdefs.h
|
||||
|
||||
|
||||
else $as_nop
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; }
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
# FreeBSD/OpenBSD use a slightly different function name.
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np exists as pthread_set_name_np instead" >&5
|
||||
printf %s "checking whether pthread_setname_np exists as pthread_set_name_np instead... " >&6; }
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
$ac_includes_default
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
|
||||
(void)pthread_set_name_np(0, "");
|
||||
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_compile "$LINENO"
|
||||
then :
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
|
||||
printf "%s\n" "yes" >&6; }
|
||||
|
||||
printf "%s\n" "#define HAVE_PTHREAD_SET_NAME_NP 1" >>confdefs.h
|
||||
|
||||
|
||||
else $as_nop
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; }
|
||||
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
CFLAGS="$BAKCFLAGS"
|
||||
fi
|
||||
|
||||
# check solaris thread library
|
||||
|
||||
# Check whether --with-solaris-threads was given.
|
||||
@@ -21519,7 +21699,7 @@ fi
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if openssl supports SHA2 and ECDSA with EVP" >&5
|
||||
printf %s "checking if openssl supports SHA2 and ECDSA with EVP... " >&6; }
|
||||
if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
|
||||
if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then
|
||||
if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL 0\." >/dev/null; then
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
|
||||
printf "%s\n" "no" >&6; }
|
||||
|
||||
@@ -22743,6 +22923,29 @@ printf "%s\n" "no" >&6; }
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
|
||||
|
||||
ac_fn_check_decl "$LINENO" "CLOCK_MONOTONIC
|
||||
" "ac_cv_have_decl_CLOCK_MONOTONIC_________" "$ac_includes_default
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
" "$ac_c_undeclared_builtin_options" "CFLAGS"
|
||||
if test "x$ac_cv_have_decl_CLOCK_MONOTONIC_________" = xyes
|
||||
then :
|
||||
|
||||
|
||||
else $as_nop
|
||||
as_fn_error $? "ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system" "$LINENO" 5
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
# set static linking for uninstalled libraries if requested
|
||||
@@ -22804,10 +23007,12 @@ then :
|
||||
LIBS="$LIBS -lz"
|
||||
fi
|
||||
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
if echo "$host" | $GREP -i -e linux >/dev/null; then
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -22868,10 +23073,12 @@ then :
|
||||
LIBS="$LIBS -lz"
|
||||
fi
|
||||
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
if echo "$host" | $GREP -i -e linux >/dev/null; then
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -23247,6 +23454,23 @@ printf "%s\n" "no" >&6; }
|
||||
|
||||
fi
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimensec" "ac_cv_member_struct_stat_st_mtimensec" "$ac_includes_default"
|
||||
if test "x$ac_cv_member_struct_stat_st_mtimensec" = xyes
|
||||
then :
|
||||
|
||||
printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1" >>confdefs.h
|
||||
|
||||
|
||||
fi
|
||||
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim.tv_nsec" "ac_cv_member_struct_stat_st_mtim_tv_nsec" "$ac_includes_default"
|
||||
if test "x$ac_cv_member_struct_stat_st_mtim_tv_nsec" = xyes
|
||||
then :
|
||||
|
||||
printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1" >>confdefs.h
|
||||
|
||||
|
||||
fi
|
||||
|
||||
ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_len" "ac_cv_member_struct_sockaddr_un_sun_len" "
|
||||
@@ -25352,7 +25576,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h
|
||||
|
||||
|
||||
|
||||
version=1.24.1
|
||||
version=1.25.2
|
||||
|
||||
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5
|
||||
printf %s "checking for build time... " >&6; }
|
||||
@@ -25882,7 +26106,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.24.1, which was
|
||||
This file was extended by unbound $as_me 1.25.2, which was
|
||||
generated by GNU Autoconf 2.71. Invocation command line was
|
||||
|
||||
CONFIG_FILES = $CONFIG_FILES
|
||||
@@ -25950,7 +26174,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.24.1
|
||||
unbound config.status 1.25.2
|
||||
configured by $0, generated by GNU Autoconf 2.71,
|
||||
with options \\"\$ac_cs_config\\"
|
||||
|
||||
|
||||
+115
-13
@@ -11,15 +11,15 @@ sinclude(dnscrypt/dnscrypt.m4)
|
||||
|
||||
# must be numbers. ac_defun because of later processing
|
||||
m4_define([VERSION_MAJOR],[1])
|
||||
m4_define([VERSION_MINOR],[24])
|
||||
m4_define([VERSION_MICRO],[1])
|
||||
m4_define([VERSION_MINOR],[25])
|
||||
m4_define([VERSION_MICRO],[2])
|
||||
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=34
|
||||
LIBUNBOUND_REVISION=38
|
||||
LIBUNBOUND_AGE=1
|
||||
# 1.0.0 had 0:12:0
|
||||
# 1.0.1 had 0:13:0
|
||||
@@ -121,6 +121,10 @@ LIBUNBOUND_AGE=1
|
||||
# 1.23.1 had 9:32:1
|
||||
# 1.24.0 had 9:33:1
|
||||
# 1.24.1 had 9:34:1
|
||||
# 1.24.2 had 9:35:1
|
||||
# 1.25.0 had 9:36:1
|
||||
# 1.25.1 had 9:37:1
|
||||
# 1.25.2 had 9:38:1
|
||||
|
||||
# Current -- the number of the binary API that we're implementing
|
||||
# Revision -- which iteration of the implementation of the binary
|
||||
@@ -360,7 +364,14 @@ AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "noreturn" attribu
|
||||
AC_CACHE_VAL(ac_cv_c_noreturn_attribute,
|
||||
[ac_cv_c_noreturn_attribute=no
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h>
|
||||
__attribute__((noreturn)) void f(int x) { printf("%d", x); }
|
||||
#ifdef STDC_HEADERS
|
||||
# include <stdlib.h>
|
||||
#else
|
||||
# ifdef HAVE_STDLIB_H
|
||||
# include <stdlib.h>
|
||||
# endif
|
||||
#endif
|
||||
__attribute__((noreturn)) void f(int x) { printf("%d", x); exit(1); }
|
||||
]], [[
|
||||
f(1);
|
||||
]])],[ac_cv_c_noreturn_attribute="yes"],[ac_cv_c_noreturn_attribute="no"])
|
||||
@@ -722,6 +733,76 @@ int main(void) {return 0;}
|
||||
])
|
||||
fi
|
||||
|
||||
if test x_$ub_have_pthreads != x_no; then
|
||||
# Long checks to support pthread_setname_np().
|
||||
# Some OSes have the extra non-portable functions in a specific
|
||||
# header file.
|
||||
AC_CHECK_HEADERS([pthread_np.h],,, [AC_INCLUDES_DEFAULT])
|
||||
BAKCFLAGS="$CFLAGS"
|
||||
CFLAGS="$CFLAGS -Werror"
|
||||
# MacOS only has 1 argument, the name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np has only 1 argument])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_setname_np("");
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP1, 1, [Define if pthread_setname_np has only 1 argument.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
# NetBSD has 3 arguments to allow for formatting of the name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np has 3 arguments])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_setname_np(0, "", NULL);
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP3, 1, [Define if pthread_setname_np has 3 arguments.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
# Most OSes have the common 2 arguments, thread and name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np has the common 2 arguments])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_setname_np(0, "");
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP, 1, [Define if pthread_setname_np has the common 2 arguments.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
# FreeBSD/OpenBSD use a slightly different function name.
|
||||
AC_MSG_CHECKING([whether pthread_setname_np exists as pthread_set_name_np instead])
|
||||
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
|
||||
#include <pthread.h>
|
||||
#ifdef HAVE_PTHREAD_NP_H
|
||||
#include <pthread_np.h>
|
||||
#endif
|
||||
],[
|
||||
(void)pthread_set_name_np(0, "");
|
||||
])],[
|
||||
AC_MSG_RESULT(yes)
|
||||
AC_DEFINE(HAVE_PTHREAD_SET_NAME_NP, 1, [Define if pthread_setname_np exists as pthread_set_name_np instead.])
|
||||
],[
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
CFLAGS="$BAKCFLAGS"
|
||||
fi
|
||||
|
||||
# check solaris thread library
|
||||
AC_ARG_WITH(solaris-threads, AS_HELP_STRING([--with-solaris-threads],[use solaris native thread library.]), [ ],[ withval="no" ])
|
||||
ub_have_sol_threads=no
|
||||
@@ -1253,7 +1334,7 @@ case "$enable_ecdsa" in
|
||||
# see if OPENSSL 1.0.0 or later (has EVP MD and Verify independency)
|
||||
AC_MSG_CHECKING([if openssl supports SHA2 and ECDSA with EVP])
|
||||
if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
|
||||
if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then
|
||||
if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL 0\." >/dev/null; then
|
||||
AC_MSG_RESULT([no])
|
||||
AC_DEFINE_UNQUOTED([USE_ECDSA_EVP_WORKAROUND], [1], [Define this to enable an EVP workaround for older openssl])
|
||||
else
|
||||
@@ -1655,6 +1736,22 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
|
||||
AC_MSG_RESULT(no)
|
||||
])
|
||||
|
||||
AC_CHECK_DECL([CLOCK_MONOTONIC]
|
||||
, []
|
||||
, [AC_MSG_ERROR([ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system])]
|
||||
, [AC_INCLUDES_DEFAULT
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
# include <sys/time.h>
|
||||
# include <time.h>
|
||||
#else
|
||||
# ifdef HAVE_SYS_TIME_H
|
||||
# include <sys/time.h>
|
||||
# else
|
||||
# include <time.h>
|
||||
# endif
|
||||
#endif
|
||||
])
|
||||
|
||||
fi
|
||||
|
||||
# set static linking for uninstalled libraries if requested
|
||||
@@ -1673,10 +1770,12 @@ if test x_$enable_static_exe = x_yes; then
|
||||
LIBS="$LIBS -lgdi32"
|
||||
fi
|
||||
AC_CHECK_LIB([z], [compress], [ LIBS="$LIBS -lz" ])
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
if echo "$host" | $GREP -i -e linux >/dev/null; then
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -1694,10 +1793,12 @@ if test x_$enable_fully_static = x_yes; then
|
||||
LIBS="$LIBS -lgdi32"
|
||||
fi
|
||||
AC_CHECK_LIB([z], [compress], [ LIBS="$LIBS -lz" ])
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
if echo "$host" | $GREP -i -e linux >/dev/null; then
|
||||
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
|
||||
:
|
||||
else
|
||||
LIBS="$LIBS -l:libssp.a"
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
@@ -1756,6 +1857,7 @@ if test $ac_cv_func_daemon = yes; then
|
||||
])
|
||||
fi
|
||||
|
||||
AC_CHECK_MEMBERS([struct stat.st_mtimensec, struct stat.st_mtim.tv_nsec])
|
||||
AC_CHECK_MEMBERS([struct sockaddr_un.sun_len],,,[
|
||||
AC_INCLUDES_DEFAULT
|
||||
#ifdef HAVE_SYS_UN_H
|
||||
|
||||
@@ -58,3 +58,5 @@ distribution but may be helpful.
|
||||
* unbound.init_yocto: An init script to start and stop the server. Put it
|
||||
in /etc/init.d/unbound to use it. It is for the Yocto Project, in
|
||||
embedded systems, contributed by beni-sandu.
|
||||
* gost12.patch: adds ECC-GOST12 support for the informational RFC9558.
|
||||
Contributed by Igor V. Ruzanov.
|
||||
|
||||
@@ -0,0 +1,325 @@
|
||||
diff --git a/sldns/keyraw.c b/sldns/keyraw.c
|
||||
index 42a9262a3..cc6406a56 100644
|
||||
--- a/sldns/keyraw.c
|
||||
+++ b/sldns/keyraw.c
|
||||
@@ -85,7 +85,7 @@ sldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
|
||||
}
|
||||
break;
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
return 512;
|
||||
#endif
|
||||
#ifdef USE_ECDSA
|
||||
@@ -146,7 +146,7 @@ sldns_key_EVP_load_gost_id(void)
|
||||
if(gost_id) return gost_id;
|
||||
|
||||
/* see if configuration loaded gost implementation from other engine*/
|
||||
- meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
|
||||
+ meth = EVP_PKEY_asn1_find_str(NULL, "gost2012_256", -1);
|
||||
if(meth) {
|
||||
EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
|
||||
return gost_id;
|
||||
@@ -170,7 +170,7 @@ sldns_key_EVP_load_gost_id(void)
|
||||
return 0;
|
||||
}
|
||||
|
||||
- meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
|
||||
+ meth = EVP_PKEY_asn1_find_str(&e, "gost2012_256", -1);
|
||||
if(!meth) {
|
||||
/* algo not found */
|
||||
ENGINE_finish(e);
|
||||
@@ -536,12 +536,17 @@ EVP_PKEY* sldns_key_rsa2pkey_raw(unsigned char* key, size_t len)
|
||||
EVP_PKEY*
|
||||
sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
|
||||
{
|
||||
- /* prefix header for X509 encoding */
|
||||
- uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
|
||||
- 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
|
||||
- 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03,
|
||||
- 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
|
||||
- unsigned char encoded[37+64];
|
||||
+ /* prefix header for X509 encoding
|
||||
+ *
|
||||
+ * note: based on draft-makarenko-gost2012-dnssec-01 (pre-RFC9558 and it DOES work!)
|
||||
+ * ASN1 header described in RFC9558 is not suitable due to d2i_PUBKEY() works with
|
||||
+ * non-compressed public keys (two additional bytes 0x04, 0x40 at the end of header)
|
||||
+ */
|
||||
+ uint8_t asn[32] = { 0x30, 0x5e, 0x30, 0x17, 0x06, 0x08, 0x2a, 0x85,
|
||||
+ 0x03, 0x07, 0x01, 0x01, 0x01, 0x01, 0x30, 0x0b,
|
||||
+ 0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02,
|
||||
+ 0x01, 0x01, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40 };
|
||||
+ unsigned char encoded[32+64];
|
||||
const unsigned char* pp;
|
||||
if(keylen != 64) {
|
||||
/* key wrong size */
|
||||
@@ -549,8 +554,8 @@ sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
|
||||
}
|
||||
|
||||
/* create evp_key */
|
||||
- memmove(encoded, asn, 37);
|
||||
- memmove(encoded+37, key, 64);
|
||||
+ memmove(encoded, asn, 32);
|
||||
+ memmove(encoded+32, key, 64);
|
||||
pp = (unsigned char*)&encoded[0];
|
||||
|
||||
return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
|
||||
diff --git a/sldns/rrdef.h b/sldns/rrdef.h
|
||||
index bbc3d5b86..7d5f3c057 100644
|
||||
--- a/sldns/rrdef.h
|
||||
+++ b/sldns/rrdef.h
|
||||
@@ -384,11 +384,12 @@ enum sldns_enum_algorithm
|
||||
LDNS_RSASHA1_NSEC3 = 7,
|
||||
LDNS_RSASHA256 = 8, /* RFC 5702 */
|
||||
LDNS_RSASHA512 = 10, /* RFC 5702 */
|
||||
- LDNS_ECC_GOST = 12, /* RFC 5933 */
|
||||
+ LDNS_ECC_GOST = 12, /* RFC 5933, deprecated */
|
||||
LDNS_ECDSAP256SHA256 = 13, /* RFC 6605 */
|
||||
LDNS_ECDSAP384SHA384 = 14, /* RFC 6605 */
|
||||
LDNS_ED25519 = 15, /* RFC 8080 */
|
||||
LDNS_ED448 = 16, /* RFC 8080 */
|
||||
+ LDNS_ECC_GOST12 = 23, /* RFC 9558 */
|
||||
LDNS_INDIRECT = 252,
|
||||
LDNS_PRIVATEDNS = 253,
|
||||
LDNS_PRIVATEOID = 254
|
||||
@@ -402,8 +403,9 @@ enum sldns_enum_hash
|
||||
{
|
||||
LDNS_SHA1 = 1, /* RFC 4034 */
|
||||
LDNS_SHA256 = 2, /* RFC 4509 */
|
||||
- LDNS_HASH_GOST = 3, /* RFC 5933 */
|
||||
- LDNS_SHA384 = 4 /* RFC 6605 */
|
||||
+ LDNS_HASH_GOST = 3, /* RFC 5933, deprecated */
|
||||
+ LDNS_SHA384 = 4, /* RFC 6605 */
|
||||
+ LDNS_HASH_GOST12 = 5 /* RFC 9558 */
|
||||
};
|
||||
typedef enum sldns_enum_hash sldns_hash;
|
||||
|
||||
diff --git a/sldns/wire2str.c b/sldns/wire2str.c
|
||||
index 75b8f37b0..b4c4755e6 100644
|
||||
--- a/sldns/wire2str.c
|
||||
+++ b/sldns/wire2str.c
|
||||
@@ -45,11 +45,12 @@ static sldns_lookup_table sldns_algorithms_data[] = {
|
||||
{ LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" },
|
||||
{ LDNS_RSASHA256, "RSASHA256"},
|
||||
{ LDNS_RSASHA512, "RSASHA512"},
|
||||
- { LDNS_ECC_GOST, "ECC-GOST"},
|
||||
+ { LDNS_ECC_GOST, "ECC-GOST"}, /* deprecated */
|
||||
{ LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"},
|
||||
{ LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"},
|
||||
{ LDNS_ED25519, "ED25519"},
|
||||
{ LDNS_ED448, "ED448"},
|
||||
+ { LDNS_ECC_GOST12, "ECC-GOST12"},
|
||||
{ LDNS_INDIRECT, "INDIRECT" },
|
||||
{ LDNS_PRIVATEDNS, "PRIVATEDNS" },
|
||||
{ LDNS_PRIVATEOID, "PRIVATEOID" },
|
||||
@@ -61,8 +62,9 @@ sldns_lookup_table* sldns_algorithms = sldns_algorithms_data;
|
||||
static sldns_lookup_table sldns_hashes_data[] = {
|
||||
{ LDNS_SHA1, "SHA1" },
|
||||
{ LDNS_SHA256, "SHA256" },
|
||||
- { LDNS_HASH_GOST, "HASH-GOST" },
|
||||
+ { LDNS_HASH_GOST, "HASH-GOST" }, /* deprecated */
|
||||
{ LDNS_SHA384, "SHA384" },
|
||||
+ { LDNS_HASH_GOST12, "HASH-GOST12" },
|
||||
{ 0, NULL }
|
||||
};
|
||||
sldns_lookup_table* sldns_hashes = sldns_hashes_data;
|
||||
diff --git a/testcode/unitverify.c b/testcode/unitverify.c
|
||||
index fcf2e2ffe..4a33e9f6a 100644
|
||||
--- a/testcode/unitverify.c
|
||||
+++ b/testcode/unitverify.c
|
||||
@@ -696,7 +696,7 @@ verify_test(void)
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
if(sldns_key_EVP_load_gost_id())
|
||||
- verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost", "20090807060504");
|
||||
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost12", "20251226060504");
|
||||
else printf("Warning: skipped GOST, openssl does not provide gost.\n");
|
||||
#endif
|
||||
#ifdef USE_ECDSA
|
||||
diff --git a/testdata/test_sigs.gost12 b/testdata/test_sigs.gost12
|
||||
new file mode 100644
|
||||
index 000000000..72a250cff
|
||||
--- /dev/null
|
||||
+++ b/testdata/test_sigs.gost12
|
||||
@@ -0,0 +1,39 @@
|
||||
+; Signature test file
|
||||
+
|
||||
+; first entry is a DNSKEY answer, with the DNSKEY rrset used for verification.
|
||||
+; later entries are verified with it.
|
||||
+
|
||||
+; Test GOST signatures using algo number 23.
|
||||
+
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+nlnetlabs.nl. IN DNSKEY
|
||||
+SECTION ANSWER
|
||||
+nlnetlabs.nl. 3600 IN DNSKEY 256 3 23 cdOtkEcb6NhcdOpIbPYtWyWxdlUiKgtKQbYg3lIjtG7i3fYjUID9zyOgoQEiV9wuGCfrw5cNsnvNw+8HiVFK4g== ;{id = 12301 (zsk), size = 512b}
|
||||
+ENTRY_END
|
||||
+
|
||||
+; entry to test
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+open.nlnetlabs.nl. IN A
|
||||
+SECTION ANSWER
|
||||
+open.nlnetlabs.nl. 600 IN A 213.154.224.1
|
||||
+open.nlnetlabs.nl. 600 IN RRSIG A 23 3 600 20260122084903 20251225084903 12301 nlnetlabs.nl. I12wYNs96DxMy26CWx296/sWMJAFg4nNXBo0sw7PnuMbJW5NFAmZYtFWhUdOWn4umaiodYOAmKG8Zg/OKvEtAQ==
|
||||
+ENTRY_END
|
||||
+
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+open.nlnetlabs.nl. IN AAAA
|
||||
+SECTION ANSWER
|
||||
+open.nlnetlabs.nl. 600 IN AAAA 2001:7b8:206:1::1
|
||||
+open.nlnetlabs.nl. 600 IN AAAA 2001:7b8:206:1::53
|
||||
+open.nlnetlabs.nl. 600 IN RRSIG AAAA 23 3 600 20260122084903 20251225084903 12301 nlnetlabs.nl. J0jHa+CP8HM6UDa2+uYgaze2mfpJTh2hkZ2KwMTYb5sfL6iBmxxql0c/403Itk4fMfYBMGn7zfzDQ+CxnCgSWw==
|
||||
+ENTRY_END
|
||||
+
|
||||
+ENTRY_BEGIN
|
||||
+SECTION QUESTION
|
||||
+open.nlnetlabs.nl. IN NSEC
|
||||
+SECTION ANSWER
|
||||
+open.nlnetlabs.nl. 86400 IN NSEC nlnetlabs.nl. A AAAA RRSIG NSEC
|
||||
+open.nlnetlabs.nl. 86400 IN RRSIG NSEC 23 3 86400 20260122084903 20251225084903 12301 nlnetlabs.nl. INCLYe9vAaNYaYx5Ay3Q6QdX+wPW9sMRvVlGt/jUEGgCi+88QlV80CT1oHrhRI66I14Wk6NRAGZRNx1tUPSHSg==
|
||||
+ENTRY_END
|
||||
diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c
|
||||
index be8347b1b..4f621a309 100644
|
||||
--- a/validator/val_secalgo.c
|
||||
+++ b/validator/val_secalgo.c
|
||||
@@ -246,10 +246,10 @@ ds_digest_size_supported(int algo)
|
||||
return SHA256_DIGEST_LENGTH;
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_HASH_GOST12:
|
||||
/* we support GOST if it can be loaded */
|
||||
(void)sldns_key_EVP_load_gost_id();
|
||||
- if(EVP_get_digestbyname("md_gost94"))
|
||||
+ if(EVP_get_digestbyname("md_gost12_256"))
|
||||
return 32;
|
||||
else return 0;
|
||||
#endif
|
||||
@@ -265,9 +265,9 @@ ds_digest_size_supported(int algo)
|
||||
#ifdef USE_GOST
|
||||
/** Perform GOST hash */
|
||||
static int
|
||||
-do_gost94(unsigned char* data, size_t len, unsigned char* dest)
|
||||
+do_gost12(unsigned char* data, size_t len, unsigned char* dest)
|
||||
{
|
||||
- const EVP_MD* md = EVP_get_digestbyname("md_gost94");
|
||||
+ const EVP_MD* md = EVP_get_digestbyname("md_gost12_256");
|
||||
if(!md)
|
||||
return 0;
|
||||
return sldns_digest_evp(data, (unsigned int)len, dest, md);
|
||||
@@ -302,8 +302,8 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
|
||||
return 1;
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_HASH_GOST:
|
||||
- if(do_gost94(buf, len, res))
|
||||
+ case LDNS_HASH_GOST12:
|
||||
+ if(do_gost12(buf, len, res))
|
||||
return 1;
|
||||
break;
|
||||
#endif
|
||||
@@ -384,7 +384,7 @@ dnskey_algo_id_is_supported(int id)
|
||||
#endif
|
||||
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
/* we support GOST if it can be loaded */
|
||||
return sldns_key_EVP_load_gost_id();
|
||||
#endif
|
||||
@@ -612,17 +612,17 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
|
||||
|
||||
break;
|
||||
#ifdef USE_GOST
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
*evp_key = sldns_gost2pkey_raw(key, keylen);
|
||||
if(!*evp_key) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
"sldns_gost2pkey_raw failed");
|
||||
return 0;
|
||||
}
|
||||
- *digest_type = EVP_get_digestbyname("md_gost94");
|
||||
+ *digest_type = EVP_get_digestbyname("md_gost12_256");
|
||||
if(!*digest_type) {
|
||||
verbose(VERB_QUERY, "verify: "
|
||||
- "EVP_getdigest md_gost94 failed");
|
||||
+ "EVP_getdigest md_gost12_256 failed");
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
@@ -964,7 +964,7 @@ ds_digest_size_supported(int algo)
|
||||
return SHA384_LENGTH;
|
||||
#endif
|
||||
/* GOST not supported in NSS */
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_HASH_GOST12:
|
||||
default: break;
|
||||
}
|
||||
return 0;
|
||||
@@ -991,7 +991,7 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
|
||||
return HASH_HashBuf(HASH_AlgSHA384, res, buf, len)
|
||||
== SECSuccess;
|
||||
#endif
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_HASH_GOST12:
|
||||
default:
|
||||
verbose(VERB_QUERY, "unknown DS digest algorithm %d",
|
||||
algo);
|
||||
@@ -1031,7 +1031,7 @@ dnskey_algo_id_is_supported(int id)
|
||||
case LDNS_ECDSAP384SHA384:
|
||||
return PK11_TokenExists(CKM_ECDSA);
|
||||
#endif
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -1352,7 +1352,7 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
|
||||
/* no prefix for DSA verification */
|
||||
break;
|
||||
#endif /* USE_ECDSA */
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
verbose(VERB_QUERY, "verify: unknown algorithm %d",
|
||||
algo);
|
||||
@@ -1675,7 +1675,7 @@ ds_digest_size_supported(int algo)
|
||||
return SHA384_DIGEST_SIZE;
|
||||
#endif
|
||||
/* GOST not supported */
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1700,7 +1700,7 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
|
||||
return _digest_nettle(SHA384_DIGEST_SIZE, buf, len, res);
|
||||
|
||||
#endif
|
||||
- case LDNS_HASH_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
verbose(VERB_QUERY, "unknown DS digest algorithm %d",
|
||||
algo);
|
||||
@@ -1744,7 +1744,7 @@ dnskey_algo_id_is_supported(int id)
|
||||
return 1;
|
||||
#endif
|
||||
case LDNS_RSAMD5: /* RFC 6725 deprecates RSAMD5 */
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
@@ -2103,7 +2103,7 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock,
|
||||
return sec_status_secure;
|
||||
#endif
|
||||
case LDNS_RSAMD5:
|
||||
- case LDNS_ECC_GOST:
|
||||
+ case LDNS_ECC_GOST12:
|
||||
default:
|
||||
*reason = "unable to verify signature, unknown algorithm";
|
||||
return sec_status_bogus;
|
||||
@@ -1,21 +1,22 @@
|
||||
#!/usr/bin/env bash
|
||||
OPENSSL_VERSION=1.1.1d
|
||||
|
||||
echo "Downloading OpenSSL"
|
||||
if ! curl -L -k -s -o openssl-1.1.1d.tar.gz https://www.openssl.org/source/openssl-1.1.1d.tar.gz;
|
||||
if ! curl -L -k -s -o openssl-$OPENSSL_VERSION.tar.gz https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz;
|
||||
then
|
||||
echo "Failed to download OpenSSL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Unpacking OpenSSL"
|
||||
rm -rf ./openssl-1.1.1d
|
||||
if ! tar -xf openssl-1.1.1d.tar.gz;
|
||||
rm -rf ./openssl-$OPENSSL_VERSION
|
||||
if ! tar -xf openssl-$OPENSSL_VERSION.tar.gz;
|
||||
then
|
||||
echo "Failed to unpack OpenSSL"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd openssl-1.1.1d || exit 1
|
||||
cd openssl-$OPENSSL_VERSION || exit 1
|
||||
|
||||
if ! cp ../contrib/ios/15-ios.conf Configurations/; then
|
||||
echo "Failed to copy OpenSSL ios config"
|
||||
@@ -27,7 +28,8 @@ fi
|
||||
# Also see https://github.com/openssl/openssl/issues/7607.
|
||||
if ! patch -u -p0 < ../contrib/ios/openssl.patch; then
|
||||
echo "Failed to patch OpenSSL"
|
||||
exit 1
|
||||
# the partial patch may be useful.
|
||||
#exit 1
|
||||
fi
|
||||
|
||||
echo "Configuring OpenSSL"
|
||||
|
||||
@@ -175,6 +175,7 @@ fi
|
||||
# For example, remove 4.3, 6.2, and 6.1 if they are not installed. We go back to
|
||||
# the 1.0 SDKs because Apple WatchOS uses low numbers, like 2.0 and 2.1.
|
||||
XCODE_SDK=
|
||||
if test -z "$SDK_VERSION"; then
|
||||
for i in $(seq -f "%.1f" 30.0 -0.1 1.0)
|
||||
do
|
||||
if [ -d "$XCODE_DEVELOPER_SDK/Developer/SDKs/$IOS_SDK$i.sdk" ]; then
|
||||
@@ -182,6 +183,10 @@ do
|
||||
break
|
||||
fi
|
||||
done
|
||||
else
|
||||
i="$SDK_VERSION"
|
||||
XCODE_SDK="$IOS_SDK$i.sdk"
|
||||
fi
|
||||
|
||||
# Error checking
|
||||
if [ -z "$XCODE_SDK" ]; then
|
||||
|
||||
+316
-22
@@ -79,6 +79,7 @@
|
||||
#include "util/tcp_conn_limit.h"
|
||||
#include "util/edns.h"
|
||||
#include "services/listen_dnsport.h"
|
||||
#include "services/outside_network.h"
|
||||
#include "services/cache/rrset.h"
|
||||
#include "services/cache/infra.h"
|
||||
#include "services/localzone.h"
|
||||
@@ -199,6 +200,255 @@ signal_handling_playback(struct worker* wrk)
|
||||
sig_record_reload = 0;
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/* setup a listening ssl context, fatal_exit() on any failure */
|
||||
static void
|
||||
setup_listen_sslctx(void** ctx, int is_dot, int is_doh,
|
||||
struct config_file* cfg, char* chroot)
|
||||
{
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
if(!(*ctx = listen_sslctx_create(key, pem, NULL,
|
||||
cfg->tls_ciphers, cfg->tls_ciphersuites,
|
||||
(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0),
|
||||
is_dot, is_doh, cfg->tls_protocols))) {
|
||||
fatal_exit("could not set up listen SSL_CTX");
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
void* daemon_setup_listen_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
(void)setup_listen_sslctx(&ctx, 1, 0, cfg, daemon->chroot);
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
void* daemon_setup_listen_doh_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
(void)setup_listen_sslctx(&ctx, 0, 1, cfg, daemon->chroot);
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_NGHTTP2_NGHTTP2_H */
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
#ifdef HAVE_NGTCP2
|
||||
void* daemon_setup_listen_quic_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
char* chroot = daemon->chroot;
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
|
||||
if(!(ctx = quic_sslctx_create(key, pem, NULL))) {
|
||||
fatal_exit("could not set up quic SSL_CTX");
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
void* daemon_setup_connect_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg)
|
||||
{
|
||||
void* ctx;
|
||||
char* bundle, *chroot = daemon->chroot;
|
||||
bundle = cfg->tls_cert_bundle;
|
||||
if(chroot && bundle && strncmp(bundle, chroot, strlen(chroot)) == 0)
|
||||
bundle += strlen(chroot);
|
||||
|
||||
if(!(ctx = connect_sslctx_create(NULL, NULL, bundle,
|
||||
cfg->tls_win_cert)))
|
||||
fatal_exit("could not set up connect SSL_CTX");
|
||||
return ctx;
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
/* setups the needed ssl contexts, fatal_exit() on any failure */
|
||||
void
|
||||
daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
char* chroot = daemon->chroot;
|
||||
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
|
||||
/* setup the session keys; the callback to use them will be
|
||||
* attached to each sslctx separately */
|
||||
if(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0) {
|
||||
if(!listen_sslctx_setup_ticket_keys(
|
||||
cfg->tls_session_ticket_keys.first, chroot)) {
|
||||
fatal_exit("could not set session ticket SSL_CTX");
|
||||
}
|
||||
}
|
||||
daemon->listen_dot_sslctx = daemon_setup_listen_dot_sslctx(
|
||||
daemon, cfg);
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
if(cfg_has_https(cfg)) {
|
||||
daemon->listen_doh_sslctx =
|
||||
daemon_setup_listen_doh_sslctx(daemon, cfg);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(cfg_has_quic(cfg)) {
|
||||
daemon->listen_quic_sslctx =
|
||||
daemon_setup_listen_quic_sslctx(daemon, cfg);
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
|
||||
/* Store the file name and mtime to detect changes later. */
|
||||
daemon->ssl_service_key = strdup(cfg->ssl_service_key);
|
||||
if(!daemon->ssl_service_key)
|
||||
fatal_exit("could not setup ssl ctx: out of memory");
|
||||
if(cfg->ssl_service_pem) {
|
||||
daemon->ssl_service_pem = strdup(cfg->ssl_service_pem);
|
||||
if(!daemon->ssl_service_pem)
|
||||
fatal_exit("could not setup ssl ctx: out of memory");
|
||||
} else {
|
||||
daemon->ssl_service_pem = NULL;
|
||||
}
|
||||
if(!file_get_mtime(key,
|
||||
&daemon->mtime_ssl_service_key,
|
||||
&daemon->mtime_ns_ssl_service_key, NULL))
|
||||
log_err("Could not stat(%s): %s",
|
||||
key, strerror(errno));
|
||||
if(pem) {
|
||||
if(!file_get_mtime(pem,
|
||||
&daemon->mtime_ssl_service_pem,
|
||||
&daemon->mtime_ns_ssl_service_pem, NULL))
|
||||
log_err("Could not stat(%s): %s",
|
||||
pem, strerror(errno));
|
||||
} else {
|
||||
daemon->mtime_ssl_service_pem = 0;
|
||||
daemon->mtime_ns_ssl_service_pem = 0;
|
||||
}
|
||||
}
|
||||
daemon->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(
|
||||
daemon, cfg);
|
||||
#else /* HAVE_SSL */
|
||||
(void)daemon;(void)cfg;
|
||||
#endif /* HAVE_SSL */
|
||||
}
|
||||
|
||||
/** Delete the ssl ctxs */
|
||||
static void
|
||||
daemon_delete_sslctxs(struct daemon* daemon)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
listen_sslctx_delete_ticket_keys();
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx);
|
||||
daemon->listen_dot_sslctx = NULL;
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx);
|
||||
daemon->listen_doh_sslctx = NULL;
|
||||
SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx);
|
||||
daemon->connect_dot_sslctx = NULL;
|
||||
free(daemon->ssl_service_key);
|
||||
daemon->ssl_service_key = NULL;
|
||||
free(daemon->ssl_service_pem);
|
||||
daemon->ssl_service_pem = NULL;
|
||||
#else
|
||||
(void)daemon;
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx);
|
||||
daemon->listen_quic_sslctx = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
ssl_cert_changed(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
time_t mtime = 0;
|
||||
long ns = 0;
|
||||
char* chroot = daemon->chroot;
|
||||
char* key = cfg->ssl_service_key;
|
||||
char* pem = cfg->ssl_service_pem;
|
||||
log_assert(daemon->ssl_service_key && cfg->ssl_service_key);
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
|
||||
if(strcmp(daemon->ssl_service_key, cfg->ssl_service_key) != 0)
|
||||
return 1;
|
||||
if(daemon->ssl_service_pem && cfg->ssl_service_pem &&
|
||||
strcmp(daemon->ssl_service_pem, cfg->ssl_service_pem) != 0)
|
||||
return 1;
|
||||
if(!file_get_mtime(key, &mtime, &ns, NULL)) {
|
||||
log_err("Could not stat(%s): %s",
|
||||
key, strerror(errno));
|
||||
/* It has probably changed, but file read is likely going to
|
||||
* fail. */
|
||||
return 0;
|
||||
}
|
||||
if(mtime != daemon->mtime_ssl_service_key ||
|
||||
ns != daemon->mtime_ns_ssl_service_key)
|
||||
return 1;
|
||||
if(pem) {
|
||||
if(!file_get_mtime(pem, &mtime, &ns, NULL)) {
|
||||
log_err("Could not stat(%s): %s",
|
||||
pem, strerror(errno));
|
||||
/* It has probably changed, but file read is likely going to
|
||||
* fail. */
|
||||
return 0;
|
||||
}
|
||||
if(mtime != daemon->mtime_ssl_service_pem ||
|
||||
ns != daemon->mtime_ns_ssl_service_pem)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Reload the sslctxs if they have changed */
|
||||
static void
|
||||
daemon_reload_sslctxs(struct daemon* daemon)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
if(daemon->cfg->ssl_service_key && daemon->cfg->ssl_service_key[0]) {
|
||||
/* See if changed */
|
||||
if(!daemon->ssl_service_key ||
|
||||
ssl_cert_changed(daemon,daemon->cfg)) {
|
||||
verbose(VERB_ALGO, "Reloading certificates");
|
||||
daemon_delete_sslctxs(daemon);
|
||||
daemon_setup_sslctxs(daemon, daemon->cfg);
|
||||
}
|
||||
} else {
|
||||
/* See if sslctxs are removed from config. */
|
||||
if(daemon->ssl_service_key) {
|
||||
verbose(VERB_ALGO, "Removing certificates");
|
||||
daemon_delete_sslctxs(daemon);
|
||||
}
|
||||
}
|
||||
#else
|
||||
(void)daemon;
|
||||
#endif
|
||||
}
|
||||
|
||||
struct daemon*
|
||||
daemon_init(void)
|
||||
{
|
||||
@@ -235,7 +485,11 @@ daemon_init(void)
|
||||
# else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
# endif
|
||||
# if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS
|
||||
/* grab the COMP method ptr because openssl leaks it */
|
||||
@@ -244,7 +498,11 @@ daemon_init(void)
|
||||
# if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
# else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
# endif
|
||||
# if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
|
||||
if(!ub_openssl_lock_init())
|
||||
@@ -556,11 +814,17 @@ daemon_create_workers(struct daemon* daemon)
|
||||
fatal_exit("out of memory during daemon init");
|
||||
numport = daemon_get_shufport(daemon, shufport);
|
||||
verbose(VERB_ALGO, "total of %d outgoing ports available", numport);
|
||||
if(!(daemon->shared_ports = shared_ports_create(daemon->cfg->out_ifs,
|
||||
daemon->cfg->num_out_ifs, daemon->cfg->do_ip4,
|
||||
daemon->cfg->do_ip6, shufport, numport)))
|
||||
fatal_exit("could not setup shared ports: out of memory");
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
daemon->doq_table = doq_table_create(daemon->cfg, daemon->rand);
|
||||
if(!daemon->doq_table)
|
||||
fatal_exit("could not create doq_table: out of memory");
|
||||
if (cfg_has_quic(daemon->cfg)) {
|
||||
daemon->doq_table = doq_table_create(daemon->cfg, daemon->rand);
|
||||
if(!daemon->doq_table)
|
||||
fatal_exit("could not create doq_table: out of memory");
|
||||
}
|
||||
#endif
|
||||
|
||||
daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1);
|
||||
@@ -584,10 +848,7 @@ daemon_create_workers(struct daemon* daemon)
|
||||
#endif
|
||||
}
|
||||
for(i=0; i<daemon->num; i++) {
|
||||
if(!(daemon->workers[i] = worker_create(daemon, i,
|
||||
shufport+numport*i/daemon->num,
|
||||
numport*(i+1)/daemon->num - numport*i/daemon->num)))
|
||||
/* the above is not ports/numthr, due to rounding */
|
||||
if(!(daemon->workers[i] = worker_create(daemon, i)))
|
||||
fatal_exit("could not create worker");
|
||||
}
|
||||
/* create per-worker alloc caches if not reusing existing ones. */
|
||||
@@ -631,6 +892,25 @@ static void close_other_pipes(struct daemon* daemon, int thr)
|
||||
}
|
||||
#endif /* THREADS_DISABLED */
|
||||
|
||||
/**
|
||||
* Function to set the thread local log ID.
|
||||
* Either the internal thread number, or the LWP ID on Linux based on
|
||||
* configuration.
|
||||
*/
|
||||
static void
|
||||
set_log_thread_id(struct worker* worker, struct config_file* cfg)
|
||||
{
|
||||
(void)cfg;
|
||||
log_assert(worker);
|
||||
#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED)
|
||||
worker->thread_tid = gettid();
|
||||
if(cfg->log_thread_id)
|
||||
log_thread_set(&worker->thread_tid);
|
||||
else
|
||||
#endif
|
||||
log_thread_set(&worker->thread_num);
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to start one thread.
|
||||
* @param arg: user argument.
|
||||
@@ -641,7 +921,14 @@ thread_start(void* arg)
|
||||
{
|
||||
struct worker* worker = (struct worker*)arg;
|
||||
int port_num = 0;
|
||||
log_thread_set(&worker->thread_num);
|
||||
log_assert(worker->thr_id);
|
||||
set_log_thread_id(worker, worker->daemon->cfg);
|
||||
{
|
||||
char name[16]; /* seems to be the safest size between
|
||||
different OSes */
|
||||
snprintf(name, sizeof(name), "unbound/%u", worker->thread_num);
|
||||
ub_thread_setname(worker->thr_id, name);
|
||||
}
|
||||
ub_thread_blocksigs();
|
||||
#ifdef THREADS_DISABLED
|
||||
/* close pipe ends used by main */
|
||||
@@ -716,6 +1003,7 @@ daemon_fork(struct daemon* daemon)
|
||||
#endif
|
||||
|
||||
log_assert(daemon);
|
||||
daemon_reload_sslctxs(daemon);
|
||||
if(!(daemon->env->views = views_create()))
|
||||
fatal_exit("Could not create views: out of memory");
|
||||
/* create individual views and their localzone/data trees */
|
||||
@@ -801,9 +1089,19 @@ daemon_fork(struct daemon* daemon)
|
||||
fatal_exit("RPZ requires the respip module");
|
||||
|
||||
/* first create all the worker structures, so we can pass
|
||||
* them to the newly created threads.
|
||||
* them to the newly created threads.
|
||||
*/
|
||||
daemon_create_workers(daemon);
|
||||
/* Set it for the first (main) worker since it does not take part in
|
||||
* the thread_start() procedure.
|
||||
*/
|
||||
set_log_thread_id(daemon->workers[0], daemon->cfg);
|
||||
/* If shm stats need an offset, calculate it */
|
||||
if(daemon->cfg->shm_enable && daemon->cfg->stat_interval > 0) {
|
||||
daemon->stat_time_specific = 1;
|
||||
daemon->stat_time_offset =
|
||||
((int)time(NULL))%daemon->cfg->stat_interval;
|
||||
}
|
||||
|
||||
#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
|
||||
/* in libev the first inited base gets signals */
|
||||
@@ -908,6 +1206,8 @@ daemon_cleanup(struct daemon* daemon)
|
||||
if(!daemon->reuse_cache || daemon->need_to_exit)
|
||||
daemon_clear_allocs(daemon);
|
||||
daemon->num = 0;
|
||||
shared_ports_delete(daemon->shared_ports);
|
||||
daemon->shared_ports = NULL;
|
||||
#ifdef USE_DNSTAP
|
||||
dt_delete(daemon->dtenv);
|
||||
daemon->dtenv = NULL;
|
||||
@@ -917,8 +1217,10 @@ daemon_cleanup(struct daemon* daemon)
|
||||
daemon->dnscenv = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
doq_table_delete(daemon->doq_table);
|
||||
daemon->doq_table = NULL;
|
||||
if (daemon->doq_table) {
|
||||
doq_table_delete(daemon->doq_table);
|
||||
daemon->doq_table = NULL;
|
||||
}
|
||||
#endif
|
||||
daemon->cfg = NULL;
|
||||
}
|
||||
@@ -956,15 +1258,7 @@ daemon_delete(struct daemon* daemon)
|
||||
free(daemon->pidfile);
|
||||
free(daemon->cfgfile);
|
||||
free(daemon->env);
|
||||
#ifdef HAVE_SSL
|
||||
listen_sslctx_delete_ticket_keys();
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx);
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx);
|
||||
SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx);
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx);
|
||||
#endif
|
||||
daemon_delete_sslctxs(daemon);
|
||||
free(daemon);
|
||||
/* lex cleanup */
|
||||
ub_c_lex_destroy();
|
||||
|
||||
@@ -62,6 +62,7 @@ struct doq_table;
|
||||
struct cookie_secrets;
|
||||
struct fast_reload_thread;
|
||||
struct fast_reload_printq;
|
||||
struct shared_ports;
|
||||
|
||||
#include "dnstap/dnstap_config.h"
|
||||
#ifdef USE_DNSTAP
|
||||
@@ -97,6 +98,8 @@ struct daemon {
|
||||
int rc_port;
|
||||
/** listening ports for remote control */
|
||||
struct listen_port* rc_ports;
|
||||
/** the shared ports structure, with random ports numbers. */
|
||||
struct shared_ports* shared_ports;
|
||||
/** remote control connections management (for first worker) */
|
||||
struct daemon_remote* rc;
|
||||
/** ssl context for listening to dnstcp over ssl */
|
||||
@@ -107,6 +110,18 @@ struct daemon {
|
||||
void* listen_doh_sslctx;
|
||||
/** ssl context for listening to quic */
|
||||
void* listen_quic_sslctx;
|
||||
/** the file name that the ssl context is made with, private key. */
|
||||
char* ssl_service_key;
|
||||
/** the file name that the ssl context is made with, certificate. */
|
||||
char* ssl_service_pem;
|
||||
/** modification time for ssl_service_key, in sec and ns. Like
|
||||
* in a struct timespec, but without that for portability. */
|
||||
time_t mtime_ssl_service_key;
|
||||
long mtime_ns_ssl_service_key;
|
||||
/** modification time for ssl_service_pem, in sec and ns. Like
|
||||
* in a struct timespec, but without that for portability. */
|
||||
time_t mtime_ssl_service_pem;
|
||||
long mtime_ns_ssl_service_pem;
|
||||
/** num threads allocated */
|
||||
int num;
|
||||
/** num threads allocated in the previous config or 0 at first */
|
||||
@@ -143,7 +158,14 @@ struct daemon {
|
||||
/** the dnstap environment master value, copied and changed by threads*/
|
||||
struct dt_env* dtenv;
|
||||
#endif
|
||||
/** The SHM info for shared memory stats. */
|
||||
struct shm_main_info* shm_info;
|
||||
/** if the timeout for statistics is attempted at specific offset.
|
||||
* If it is true, the stat timeout is the interval+offset, and that
|
||||
* picks (roughly) the same time offset every time period. */
|
||||
int stat_time_specific;
|
||||
/** if the timeout is specific, what offset in the period. */
|
||||
int stat_time_offset;
|
||||
/** some response-ip tags or actions are configured if true */
|
||||
int use_response_ip;
|
||||
/** some RPZ policies are configured */
|
||||
@@ -229,4 +251,26 @@ void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg);
|
||||
*/
|
||||
int setup_acl_for_ports(struct acl_list* list, struct listen_port* port_list);
|
||||
|
||||
/* setups the needed ssl contexts, fatal_exit() on any failure */
|
||||
void daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg);
|
||||
|
||||
/** See if the SSL cert files have changed */
|
||||
int ssl_cert_changed(struct daemon* daemon, struct config_file* cfg);
|
||||
|
||||
/** Setup the listening DoT SSL_CTX, returns the ssl ctx. */
|
||||
void* daemon_setup_listen_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Setup the listening DoH SSL_CTX, returns the ssl ctx. */
|
||||
void* daemon_setup_listen_doh_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Setup the listening Quic SSL_CTX, returns the ssl ctx */
|
||||
void* daemon_setup_listen_quic_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
/** Setup the connect DoT SSL_CTX, returns the ssl ctx */
|
||||
void* daemon_setup_connect_dot_sslctx(struct daemon* daemon,
|
||||
struct config_file* cfg);
|
||||
|
||||
#endif /* DAEMON_H */
|
||||
|
||||
+327
-6
@@ -153,7 +153,7 @@ remote_setup_ctx(struct daemon_remote* rc, struct config_file* cfg)
|
||||
log_crypto_err("could not SSL_CTX_new");
|
||||
return 0;
|
||||
}
|
||||
if(!listen_sslctx_setup(rc->ctx, cfg->tls_use_system_policy_versions)) {
|
||||
if(!listen_sslctx_setup(rc->ctx, cfg->tls_protocols)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -307,6 +307,26 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err,
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
char* s = strchr(ip, '@');
|
||||
char newif[128];
|
||||
if(s) {
|
||||
/* override port with ifspec@port */
|
||||
int portnr;
|
||||
if((size_t)(s-ip) >= sizeof(newif)) {
|
||||
log_err("ifname too long: %s", ip);
|
||||
return -1;
|
||||
}
|
||||
portnr = atoi(s+1);
|
||||
if(portnr < 0 || 0 == portnr || portnr > 65535) {
|
||||
log_err("invalid portnumber in control-interface: %s", ip);
|
||||
return -1;
|
||||
}
|
||||
(void)strlcpy(newif, ip, sizeof(newif));
|
||||
newif[s-ip] = 0;
|
||||
ip = newif;
|
||||
snprintf(port, sizeof(port), "%d", portnr);
|
||||
port[sizeof(port)-1]=0;
|
||||
}
|
||||
hints.ai_socktype = SOCK_STREAM;
|
||||
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
|
||||
if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) {
|
||||
@@ -801,6 +821,8 @@ print_stats(RES* ssl, const char* nm, struct ub_stats_info* s)
|
||||
(unsigned long)s->svr.num_queries_cookie_invalid)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.queries_discard_timeout"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.num_queries_discard_timeout)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.queries_replyaddr_limit"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.num_queries_replyaddr_limit)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.queries_wait_limit"SQ"%lu\n", nm,
|
||||
(unsigned long)s->svr.num_queries_wait_limit)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%lu\n", nm,
|
||||
@@ -845,6 +867,8 @@ print_stats(RES* ssl, const char* nm, struct ub_stats_info* s)
|
||||
(unsigned long)s->mesh_num_states)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.requestlist.current.user"SQ"%lu\n", nm,
|
||||
(unsigned long)s->mesh_num_reply_states)) return 0;
|
||||
if(!ssl_printf(ssl, "%s.requestlist.current.replies"SQ"%lu\n", nm,
|
||||
(unsigned long)s->mesh_num_reply_addrs)) return 0;
|
||||
#ifndef S_SPLINT_S
|
||||
sumwait.tv_sec = s->mesh_replies_sum_wait_sec;
|
||||
sumwait.tv_usec = s->mesh_replies_sum_wait_usec;
|
||||
@@ -1634,6 +1658,14 @@ do_view_data_add(RES* ssl, struct worker* worker, char* arg)
|
||||
ssl_printf(ssl,"error out of memory\n");
|
||||
return;
|
||||
}
|
||||
if(!v->isfirst) {
|
||||
/* Global local-zone is not used for this view,
|
||||
* therefore add defaults to this view-specific
|
||||
* local-zone. */
|
||||
struct config_file lz_cfg;
|
||||
memset(&lz_cfg, 0, sizeof(lz_cfg));
|
||||
local_zone_enter_defaults(v->local_zones, &lz_cfg);
|
||||
}
|
||||
}
|
||||
do_data_add(ssl, v->local_zones, arg2);
|
||||
lock_rw_unlock(&v->lock);
|
||||
@@ -1659,6 +1691,14 @@ do_view_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker,
|
||||
ssl_printf(ssl,"error out of memory\n");
|
||||
return;
|
||||
}
|
||||
if(!v->isfirst) {
|
||||
/* Global local-zone is not used for this view,
|
||||
* therefore add defaults to this view-specific
|
||||
* local-zone. */
|
||||
struct config_file lz_cfg;
|
||||
memset(&lz_cfg, 0, sizeof(lz_cfg));
|
||||
local_zone_enter_defaults(v->local_zones, &lz_cfg);
|
||||
}
|
||||
}
|
||||
/* put the view name in the command buf */
|
||||
(void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg);
|
||||
@@ -4629,6 +4669,26 @@ fr_init_time(struct timeval* time_start, struct timeval* time_read,
|
||||
* are kept in here. They can then be deleted.
|
||||
*/
|
||||
struct fast_reload_construct {
|
||||
/** ssl context for listening to dnstcp over ssl */
|
||||
void* listen_dot_sslctx;
|
||||
/** ssl context for connecting to dnstcp over ssl */
|
||||
void* connect_dot_sslctx;
|
||||
/** ssl context for listening to DoH */
|
||||
void* listen_doh_sslctx;
|
||||
/** ssl context for listening to quic */
|
||||
void* listen_quic_sslctx;
|
||||
/** the file name that the ssl context is made with, private key. */
|
||||
char* ssl_service_key;
|
||||
/** the file name that the ssl context is made with, certificate. */
|
||||
char* ssl_service_pem;
|
||||
/** modification time for ssl_service_key, in sec and ns. Like
|
||||
* in a struct timespec, but without that for portability. */
|
||||
time_t mtime_ssl_service_key;
|
||||
long mtime_ns_ssl_service_key;
|
||||
/** modification time for ssl_service_pem, in sec and ns. Like
|
||||
* in a struct timespec, but without that for portability. */
|
||||
time_t mtime_ssl_service_pem;
|
||||
long mtime_ns_ssl_service_pem;
|
||||
/** construct for views */
|
||||
struct views* views;
|
||||
/** construct for auth zones */
|
||||
@@ -4932,9 +4992,7 @@ fr_check_compat_cfg(struct fast_reload_thread* fr, struct config_file* newcfg)
|
||||
FR_CHECK_CHANGED_CFG("http_notls_downstream", http_notls_downstream, changed_str);
|
||||
FR_CHECK_CHANGED_CFG("https-port", https_port, changed_str);
|
||||
FR_CHECK_CHANGED_CFG("tls-port", ssl_port, changed_str);
|
||||
FR_CHECK_CHANGED_CFG_STR("tls-service-key", ssl_service_key, changed_str);
|
||||
FR_CHECK_CHANGED_CFG_STR("tls-service-pem", ssl_service_pem, changed_str);
|
||||
FR_CHECK_CHANGED_CFG_STR("tls-cert-bundle", tls_cert_bundle, changed_str);
|
||||
FR_CHECK_CHANGED_CFG_STR("tls-protocols", tls_protocols, changed_str);
|
||||
FR_CHECK_CHANGED_CFG_STRLIST("proxy-protocol-port", proxy_protocol_port, changed_str);
|
||||
FR_CHECK_CHANGED_CFG_STRLIST("tls-additional-port", tls_additional_port, changed_str);
|
||||
FR_CHECK_CHANGED_CFG_STR("interface-automatic-ports", if_automatic_ports, changed_str);
|
||||
@@ -5043,6 +5101,19 @@ fr_construct_clear(struct fast_reload_construct* ct)
|
||||
wait_limits_free(&ct->wait_limits_netblock);
|
||||
wait_limits_free(&ct->wait_limits_cookie_netblock);
|
||||
domain_limits_free(&ct->domain_limits);
|
||||
#ifdef HAVE_SSL
|
||||
/* The SSL contexts can be SSL_CTX_free here. It is reference
|
||||
* counted. So ongoing transfers with can continue.
|
||||
* Once they are done, the context is freed. */
|
||||
SSL_CTX_free((SSL_CTX*)ct->listen_dot_sslctx);
|
||||
SSL_CTX_free((SSL_CTX*)ct->connect_dot_sslctx);
|
||||
SSL_CTX_free((SSL_CTX*)ct->listen_doh_sslctx);
|
||||
#endif /* HAVE_SSL */
|
||||
#ifdef HAVE_NGTCP2
|
||||
SSL_CTX_free((SSL_CTX*)ct->listen_quic_sslctx);
|
||||
#endif
|
||||
free(ct->ssl_service_key);
|
||||
free(ct->ssl_service_pem);
|
||||
/* Delete the log identity here so that the global value is not
|
||||
* reset by config_delete. */
|
||||
if(ct->oldcfg && ct->oldcfg->log_identity) {
|
||||
@@ -5175,6 +5246,7 @@ config_file_getmem(struct config_file* cfg)
|
||||
m += getmem_config_strlist(cfg->tls_session_ticket_keys.first);
|
||||
m += getmem_str(cfg->tls_ciphers);
|
||||
m += getmem_str(cfg->tls_ciphersuites);
|
||||
m += getmem_str(cfg->tls_protocols);
|
||||
m += getmem_str(cfg->http_endpoint);
|
||||
m += (cfg->outgoing_avail_ports?65536*sizeof(int):0);
|
||||
m += getmem_str(cfg->target_fetch_policy);
|
||||
@@ -5291,6 +5363,8 @@ fr_printmem(struct fast_reload_thread* fr,
|
||||
size_t mem = 0;
|
||||
if(fr_poll_for_quit(fr))
|
||||
return 1;
|
||||
mem += getmem_str(ct->ssl_service_key);
|
||||
mem += getmem_str(ct->ssl_service_pem);
|
||||
mem += views_get_mem(ct->views);
|
||||
mem += respip_set_get_mem(ct->respip_set);
|
||||
mem += auth_zones_get_mem(ct->auth_zones);
|
||||
@@ -5524,6 +5598,96 @@ auth_zones_check_changes(struct fast_reload_thread* fr,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Check if the sslctxs have changed. */
|
||||
static int
|
||||
fr_check_sslctx_change(struct fast_reload_thread* fr,
|
||||
struct config_file* newcfg)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
struct daemon* daemon = fr->worker->daemon;
|
||||
if(newcfg->ssl_service_key && newcfg->ssl_service_key[0]) {
|
||||
if(!daemon->ssl_service_key ||
|
||||
ssl_cert_changed(daemon, newcfg))
|
||||
return 1;
|
||||
} else {
|
||||
if(daemon->ssl_service_key)
|
||||
return 1; /* it is removed */
|
||||
}
|
||||
if((daemon->cfg->tls_cert_bundle && !newcfg->tls_cert_bundle) ||
|
||||
(!daemon->cfg->tls_cert_bundle && newcfg->tls_cert_bundle) ||
|
||||
(daemon->cfg->tls_cert_bundle && newcfg->tls_cert_bundle &&
|
||||
strcmp(daemon->cfg->tls_cert_bundle, newcfg->tls_cert_bundle)!=0))
|
||||
return 1; /* The tls-cert-bundle has changed and return
|
||||
true here makes it reload the connect_dot_sslctx. */
|
||||
#else
|
||||
(void)fr; (void)newcfg;
|
||||
#endif /* HAVE_SSL */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Create the SSL CTXs when they have changed. */
|
||||
static int
|
||||
ct_create_sslctxs(struct fast_reload_construct* ct,
|
||||
struct config_file* newcfg, struct daemon* daemon)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
char* chroot = daemon->chroot;
|
||||
char* key = newcfg->ssl_service_key;
|
||||
char* pem = newcfg->ssl_service_pem;
|
||||
|
||||
if(!(newcfg->ssl_service_key && newcfg->ssl_service_key[0])) {
|
||||
/* Leave listen ctxs and file str at NULL */
|
||||
ct->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(
|
||||
daemon, newcfg);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
|
||||
key += strlen(chroot);
|
||||
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
|
||||
pem += strlen(chroot);
|
||||
|
||||
ct->listen_dot_sslctx = daemon_setup_listen_dot_sslctx(daemon, newcfg);
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
if(cfg_has_https(newcfg)) {
|
||||
ct->listen_doh_sslctx = daemon_setup_listen_doh_sslctx(
|
||||
daemon, newcfg);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(cfg_has_quic(newcfg)) {
|
||||
ct->listen_quic_sslctx = daemon_setup_listen_quic_sslctx(
|
||||
daemon, newcfg);
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
ct->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(daemon,
|
||||
newcfg);
|
||||
|
||||
/* Store mtime and names */
|
||||
ct->ssl_service_key = strdup(newcfg->ssl_service_key);
|
||||
if(!ct->ssl_service_key) {
|
||||
log_err("ct_create_sslctxs: out of memory");
|
||||
return 0;
|
||||
}
|
||||
ct->ssl_service_pem = strdup(newcfg->ssl_service_pem);
|
||||
if(!ct->ssl_service_pem) {
|
||||
log_err("ct_create_sslctxs: out of memory");
|
||||
return 0;
|
||||
}
|
||||
if(!file_get_mtime(key, &ct->mtime_ssl_service_key,
|
||||
&ct->mtime_ns_ssl_service_key, NULL))
|
||||
log_err("Could not stat(%s): %s",
|
||||
key, strerror(errno));
|
||||
if(!file_get_mtime(pem, &ct->mtime_ssl_service_pem,
|
||||
&ct->mtime_ns_ssl_service_pem, NULL))
|
||||
log_err("Could not stat(%s): %s",
|
||||
pem, strerror(errno));
|
||||
#else
|
||||
(void)ct; (void)newcfg; (void)daemon;
|
||||
#endif /* HAVE_SSL */
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** fast reload thread, construct from config the new items */
|
||||
static int
|
||||
fr_construct_from_config(struct fast_reload_thread* fr,
|
||||
@@ -5531,6 +5695,13 @@ fr_construct_from_config(struct fast_reload_thread* fr,
|
||||
{
|
||||
int have_view_respip_cfg = 0;
|
||||
|
||||
fr->sslctxs_changed = fr_check_sslctx_change(fr, newcfg);
|
||||
if(fr->sslctxs_changed) {
|
||||
if(!ct_create_sslctxs(ct, newcfg, fr->worker->daemon)) {
|
||||
fr_construct_clear(ct);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(!(ct->views = views_create())) {
|
||||
fr_construct_clear(ct);
|
||||
return 0;
|
||||
@@ -5808,6 +5979,44 @@ auth_zones_swap(struct auth_zones* az, struct auth_zones* data)
|
||||
* the xfer elements can continue to be their callbacks. */
|
||||
}
|
||||
|
||||
/** Swap two void* */
|
||||
static void
|
||||
void_ptr_swap(void** a, void **b)
|
||||
{
|
||||
void* tmp = *a;
|
||||
*a = *b;
|
||||
*b = tmp;
|
||||
}
|
||||
|
||||
/** Swap two char* */
|
||||
static void
|
||||
char_ptr_swap(char** a, char **b)
|
||||
{
|
||||
char* tmp = *a;
|
||||
*a = *b;
|
||||
*b = tmp;
|
||||
}
|
||||
|
||||
/** Swap and set ssl ctx information */
|
||||
static void
|
||||
sslctxs_swap(struct daemon* daemon, struct fast_reload_construct* ct)
|
||||
{
|
||||
void_ptr_swap(&daemon->listen_dot_sslctx, &ct->listen_dot_sslctx);
|
||||
void_ptr_swap(&daemon->connect_dot_sslctx, &ct->connect_dot_sslctx);
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
void_ptr_swap(&daemon->listen_doh_sslctx, &ct->listen_doh_sslctx);
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
void_ptr_swap(&daemon->listen_quic_sslctx, &ct->listen_quic_sslctx);
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
char_ptr_swap(&daemon->ssl_service_key, &ct->ssl_service_key);
|
||||
char_ptr_swap(&daemon->ssl_service_pem, &ct->ssl_service_pem);
|
||||
daemon->mtime_ssl_service_key = ct->mtime_ssl_service_key;
|
||||
daemon->mtime_ns_ssl_service_key = ct->mtime_ns_ssl_service_key;
|
||||
daemon->mtime_ssl_service_pem = ct->mtime_ssl_service_pem;
|
||||
daemon->mtime_ns_ssl_service_pem = ct->mtime_ns_ssl_service_pem;
|
||||
}
|
||||
|
||||
#if defined(ATOMIC_POINTER_LOCK_FREE) && defined(HAVE_LINK_ATOMIC_STORE)
|
||||
/** Fast reload thread, if atomics are available, copy the config items
|
||||
* one by one with atomic store operations. */
|
||||
@@ -5869,8 +6078,8 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
|
||||
COPY_VAR_ptr(tls_session_ticket_keys.last);
|
||||
COPY_VAR_ptr(tls_ciphers);
|
||||
COPY_VAR_ptr(tls_ciphersuites);
|
||||
COPY_VAR_ptr(tls_protocols);
|
||||
COPY_VAR_int(tls_use_sni);
|
||||
COPY_VAR_int(tls_use_system_policy_versions);
|
||||
COPY_VAR_int(https_port);
|
||||
COPY_VAR_ptr(http_endpoint);
|
||||
COPY_VAR_uint32_t(http_max_streams);
|
||||
@@ -5968,6 +6177,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
|
||||
COPY_VAR_int(log_servfail);
|
||||
COPY_VAR_ptr(log_identity);
|
||||
COPY_VAR_int(log_destaddr);
|
||||
COPY_VAR_int(log_thread_id);
|
||||
COPY_VAR_int(hide_identity);
|
||||
COPY_VAR_int(hide_version);
|
||||
COPY_VAR_int(hide_trustanchor);
|
||||
@@ -6177,6 +6387,20 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
|
||||
COPY_VAR_ptr(ipset_name_v6);
|
||||
#endif
|
||||
COPY_VAR_int(ede);
|
||||
COPY_VAR_int(iter_scrub_ns);
|
||||
COPY_VAR_int(iter_scrub_cname);
|
||||
COPY_VAR_int(iter_scrub_rrsig);
|
||||
COPY_VAR_int(max_global_quota);
|
||||
COPY_VAR_int(iter_scrub_promiscuous);
|
||||
|
||||
#undef COPY_VAR_int
|
||||
#undef COPY_VAR_ptr
|
||||
#undef COPY_VAR_unsigned_int
|
||||
#undef COPY_VAR_size_t
|
||||
#undef COPY_VAR_uint8_t
|
||||
#undef COPY_VAR_uint16_t
|
||||
#undef COPY_VAR_uint32_t
|
||||
#undef COPY_VAR_int32_t
|
||||
}
|
||||
#endif /* ATOMIC_POINTER_LOCK_FREE && HAVE_LINK_ATOMIC_STORE */
|
||||
|
||||
@@ -6402,6 +6626,9 @@ fr_reload_config(struct fast_reload_thread* fr, struct config_file* newcfg,
|
||||
daemon->env->cachedb_enabled = cachedb_is_enabled(&daemon->mods,
|
||||
daemon->env);
|
||||
#endif
|
||||
if(fr->sslctxs_changed) {
|
||||
sslctxs_swap(daemon, ct);
|
||||
}
|
||||
#ifdef USE_DNSTAP
|
||||
if(env->cfg->dnstap) {
|
||||
if(!fr->fr_nopause)
|
||||
@@ -6626,7 +6853,19 @@ static void* fast_reload_thread_main(void* arg)
|
||||
struct fast_reload_thread* fast_reload_thread = (struct fast_reload_thread*)arg;
|
||||
struct timeval time_start, time_read, time_construct, time_reload,
|
||||
time_end;
|
||||
log_thread_set(&fast_reload_thread->threadnum);
|
||||
const char name[16] = "unbound/freload"; /* seems to be the safest size
|
||||
between different OSes */
|
||||
|
||||
#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED)
|
||||
fast_reload_thread->thread_tid = gettid();
|
||||
if(fast_reload_thread->thread_tid_log)
|
||||
log_thread_set(&fast_reload_thread->thread_tid);
|
||||
else
|
||||
#endif
|
||||
log_thread_set(&fast_reload_thread->threadnum);
|
||||
|
||||
ub_thread_setname(fast_reload_thread->tid, name);
|
||||
(void)name; /* When setname is not defined, ignore the name variable. */
|
||||
|
||||
verbose(VERB_ALGO, "start fast reload thread");
|
||||
if(fast_reload_thread->fr_verb >= 1) {
|
||||
@@ -7014,6 +7253,9 @@ fast_reload_thread_setup(struct worker* worker, int fr_verb, int fr_nopause,
|
||||
lock_basic_init(&fr->fr_output_lock);
|
||||
lock_protect(&fr->fr_output_lock, fr->fr_output,
|
||||
sizeof(*fr->fr_output));
|
||||
#ifdef HAVE_GETTID
|
||||
fr->thread_tid_log = worker->env.cfg->log_thread_id;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -7588,6 +7830,44 @@ fr_worker_pickup_auth_changes(struct worker* worker,
|
||||
}
|
||||
}
|
||||
|
||||
/** Fast reload, the worker picks up changes in listen_dnsport. */
|
||||
static void
|
||||
fr_worker_pickup_listen_dnsport(struct worker* worker)
|
||||
{
|
||||
struct listen_dnsport* front = worker->front;
|
||||
struct daemon* daemon = worker->daemon;
|
||||
if(worker->daemon->fast_reload_thread->sslctxs_changed) {
|
||||
struct listen_list* ll;
|
||||
void* dot_sslctx = daemon->listen_dot_sslctx;
|
||||
void* doh_sslctx = daemon->listen_doh_sslctx;
|
||||
#ifdef HAVE_NGTCP2
|
||||
void* quic_sslctx = daemon->listen_quic_sslctx;
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
for(ll = front->cps; ll; ll = ll->next) {
|
||||
struct comm_point* cp = ll->com;
|
||||
if(cp->type == comm_tcp_accept &&
|
||||
cp->tcp_handlers &&
|
||||
cp->max_tcp_count > 0 &&
|
||||
cp->tcp_handlers[0]->type == comm_http) {
|
||||
if(cp->ssl)
|
||||
cp->ssl = doh_sslctx;
|
||||
} else if(cp->type == comm_tcp_accept) {
|
||||
if(cp->ssl)
|
||||
cp->ssl = dot_sslctx;
|
||||
#ifdef HAVE_NGTCP2
|
||||
} else if(cp->type == comm_doq) {
|
||||
if(cp->ssl) {
|
||||
cp->ssl = quic_sslctx;
|
||||
if(cp->doq_socket)
|
||||
cp->doq_socket->ctx =
|
||||
(SSL_CTX*)quic_sslctx;
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Fast reload, the worker picks up changes in outside_network. */
|
||||
static void
|
||||
fr_worker_pickup_outside_network(struct worker* worker)
|
||||
@@ -7603,6 +7883,8 @@ fr_worker_pickup_outside_network(struct worker* worker)
|
||||
outnet->tcp_reuse_timeout = cfg->tcp_reuse_timeout;
|
||||
outnet->tcp_auth_query_timeout = cfg->tcp_auth_query_timeout;
|
||||
outnet->delayclose = cfg->delay_close;
|
||||
if(worker->daemon->fast_reload_thread->sslctxs_changed)
|
||||
outnet->sslctx = worker->daemon->connect_dot_sslctx;
|
||||
if(outnet->delayclose) {
|
||||
#ifndef S_SPLINT_S
|
||||
outnet->delay_tv.tv_sec = cfg->delay_close/1000;
|
||||
@@ -7611,6 +7893,41 @@ fr_worker_pickup_outside_network(struct worker* worker)
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef USE_DNSTAP
|
||||
/** Fast reload, the worker picks up changes to DNSTAP configuration. */
|
||||
static void
|
||||
fr_worker_pickup_dnstap_changes(struct worker* worker)
|
||||
{
|
||||
struct dt_env* w_dtenv = &worker->dtenv;
|
||||
struct dt_env* d_dtenv = worker->daemon->dtenv;
|
||||
log_assert(d_dtenv != NULL || !worker->daemon->cfg->dnstap);
|
||||
if(d_dtenv == NULL) {
|
||||
/* There is no environment when DNSTAP was not enabled
|
||||
* in the configuration. */
|
||||
return;
|
||||
}
|
||||
w_dtenv->identity = d_dtenv->identity;
|
||||
w_dtenv->len_identity = d_dtenv->len_identity;
|
||||
w_dtenv->version = d_dtenv->version;
|
||||
w_dtenv->len_version = d_dtenv->len_version;
|
||||
w_dtenv->log_resolver_query_messages =
|
||||
d_dtenv->log_resolver_query_messages;
|
||||
w_dtenv->log_resolver_response_messages =
|
||||
d_dtenv->log_resolver_response_messages;
|
||||
w_dtenv->log_client_query_messages =
|
||||
d_dtenv->log_client_query_messages;
|
||||
w_dtenv->log_client_response_messages =
|
||||
d_dtenv->log_client_response_messages;
|
||||
w_dtenv->log_forwarder_query_messages =
|
||||
d_dtenv->log_forwarder_query_messages;
|
||||
w_dtenv->log_forwarder_response_messages =
|
||||
d_dtenv->log_forwarder_response_messages;
|
||||
lock_basic_lock(&d_dtenv->sample_lock);
|
||||
w_dtenv->sample_rate = d_dtenv->sample_rate;
|
||||
lock_basic_unlock(&d_dtenv->sample_lock);
|
||||
}
|
||||
#endif /* USE_DNSTAP */
|
||||
|
||||
void
|
||||
fast_reload_worker_pickup_changes(struct worker* worker)
|
||||
{
|
||||
@@ -7638,7 +7955,11 @@ fast_reload_worker_pickup_changes(struct worker* worker)
|
||||
#ifdef USE_CACHEDB
|
||||
worker->env.cachedb_enabled = worker->daemon->env->cachedb_enabled;
|
||||
#endif
|
||||
fr_worker_pickup_listen_dnsport(worker);
|
||||
fr_worker_pickup_outside_network(worker);
|
||||
#ifdef USE_DNSTAP
|
||||
fr_worker_pickup_dnstap_changes(worker);
|
||||
#endif
|
||||
}
|
||||
|
||||
/** fast reload thread, handle reload_stop notification, send reload stop
|
||||
|
||||
@@ -206,6 +206,12 @@ struct fast_reload_thread {
|
||||
int commpair[2];
|
||||
/** thread id, of the io thread */
|
||||
ub_thread_type tid;
|
||||
#ifdef HAVE_GETTID
|
||||
/** thread tid, the LWP id */
|
||||
pid_t thread_tid;
|
||||
/** if logging should include the LWP id */
|
||||
int thread_tid_log;
|
||||
#endif
|
||||
/** if the io processing has started */
|
||||
int started;
|
||||
/** if the thread has to quit */
|
||||
@@ -249,6 +255,8 @@ struct fast_reload_thread {
|
||||
struct fast_reload_auth_change* auth_zone_change_list;
|
||||
/** the old tree of auth zones, to lookup. */
|
||||
struct auth_zones* old_auth_zones;
|
||||
/** If the ssl ctxs have changed. */
|
||||
int sslctxs_changed;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -262,6 +262,7 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
|
||||
s->svr = worker->stats;
|
||||
s->mesh_num_states = (long long)worker->env.mesh->all.count;
|
||||
s->mesh_num_reply_states = (long long)worker->env.mesh->num_reply_states;
|
||||
s->mesh_num_reply_addrs = (long long)worker->env.mesh->num_reply_addrs;
|
||||
s->mesh_jostled = (long long)worker->env.mesh->stats_jostled;
|
||||
s->mesh_dropped = (long long)worker->env.mesh->stats_dropped;
|
||||
s->mesh_replies_sent = (long long)worker->env.mesh->replies_sent;
|
||||
@@ -284,6 +285,8 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
|
||||
NUM_BUCKETS_HIST);
|
||||
s->svr.num_queries_discard_timeout +=
|
||||
(long long)worker->env.mesh->num_queries_discard_timeout;
|
||||
s->svr.num_queries_replyaddr_limit +=
|
||||
(long long)worker->env.mesh->num_queries_replyaddr_limit;
|
||||
s->svr.num_queries_wait_limit +=
|
||||
(long long)worker->env.mesh->num_queries_wait_limit;
|
||||
s->svr.num_dns_error_reports +=
|
||||
@@ -448,6 +451,8 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
|
||||
total->svr.num_queries_cookie_invalid += a->svr.num_queries_cookie_invalid;
|
||||
total->svr.num_queries_discard_timeout +=
|
||||
a->svr.num_queries_discard_timeout;
|
||||
total->svr.num_queries_replyaddr_limit +=
|
||||
a->svr.num_queries_replyaddr_limit;
|
||||
total->svr.num_queries_wait_limit += a->svr.num_queries_wait_limit;
|
||||
total->svr.num_dns_error_reports += a->svr.num_dns_error_reports;
|
||||
total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
|
||||
@@ -519,6 +524,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
|
||||
|
||||
total->mesh_num_states += a->mesh_num_states;
|
||||
total->mesh_num_reply_states += a->mesh_num_reply_states;
|
||||
total->mesh_num_reply_addrs += a->mesh_num_reply_addrs;
|
||||
total->mesh_jostled += a->mesh_jostled;
|
||||
total->mesh_dropped += a->mesh_dropped;
|
||||
total->mesh_replies_sent += a->mesh_replies_sent;
|
||||
|
||||
+4
-47
@@ -463,57 +463,13 @@ detach(void)
|
||||
#endif /* HAVE_DAEMON */
|
||||
}
|
||||
|
||||
#ifdef HAVE_SSL
|
||||
/* setup a listening ssl context, fatal_exit() on any failure */
|
||||
/** setup the remote and ticket keys */
|
||||
static void
|
||||
setup_listen_sslctx(void** ctx, int is_dot, int is_doh, struct config_file* cfg)
|
||||
{
|
||||
if(!(*ctx = listen_sslctx_create(
|
||||
cfg->ssl_service_key, cfg->ssl_service_pem, NULL,
|
||||
cfg->tls_ciphers, cfg->tls_ciphersuites,
|
||||
(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0),
|
||||
is_dot, is_doh, cfg->tls_use_system_policy_versions))) {
|
||||
fatal_exit("could not set up listen SSL_CTX");
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
/* setups the needed ssl contexts, fatal_exit() on any failure */
|
||||
static void
|
||||
setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
|
||||
setup_sslctx_remote(struct daemon* daemon, struct config_file* cfg)
|
||||
{
|
||||
#ifdef HAVE_SSL
|
||||
if(!(daemon->rc = daemon_remote_create(cfg)))
|
||||
fatal_exit("could not set up remote-control");
|
||||
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
|
||||
/* setup the session keys; the callback to use them will be
|
||||
* attached to each sslctx separately */
|
||||
if(cfg->tls_session_ticket_keys.first &&
|
||||
cfg->tls_session_ticket_keys.first->str[0] != 0) {
|
||||
if(!listen_sslctx_setup_ticket_keys(
|
||||
cfg->tls_session_ticket_keys.first)) {
|
||||
fatal_exit("could not set session ticket SSL_CTX");
|
||||
}
|
||||
}
|
||||
(void)setup_listen_sslctx(&daemon->listen_dot_sslctx, 1, 0, cfg);
|
||||
#ifdef HAVE_NGHTTP2_NGHTTP2_H
|
||||
if(cfg_has_https(cfg)) {
|
||||
(void)setup_listen_sslctx(&daemon->listen_doh_sslctx, 0, 1, cfg);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(cfg_has_quic(cfg)) {
|
||||
if(!(daemon->listen_quic_sslctx = quic_sslctx_create(
|
||||
cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) {
|
||||
fatal_exit("could not set up quic SSL_CTX");
|
||||
}
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
}
|
||||
if(!(daemon->connect_dot_sslctx = connect_sslctx_create(NULL, NULL,
|
||||
cfg->tls_cert_bundle, cfg->tls_win_cert)))
|
||||
fatal_exit("could not set up connect SSL_CTX");
|
||||
#else /* HAVE_SSL */
|
||||
(void)daemon;(void)cfg;
|
||||
#endif /* HAVE_SSL */
|
||||
@@ -545,7 +501,8 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
|
||||
#endif
|
||||
|
||||
/* read ssl keys while superuser and outside chroot */
|
||||
(void)setup_sslctxs(daemon, cfg);
|
||||
setup_sslctx_remote(daemon, cfg);
|
||||
daemon_setup_sslctxs(daemon, cfg);
|
||||
|
||||
/* init syslog (as root) if needed, before daemonize, otherwise
|
||||
* a fork error could not be printed since daemonize closed stderr.*/
|
||||
|
||||
+180
-98
@@ -255,7 +255,8 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
|
||||
return 0;
|
||||
}
|
||||
/* sanity check. */
|
||||
if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
|
||||
if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE
|
||||
|| !LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
|
||||
|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
|
||||
LDNS_PACKET_QUERY
|
||||
|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
|
||||
@@ -292,6 +293,44 @@ worker_err_ratelimit(struct worker* worker, int err)
|
||||
return err;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reply with an error.
|
||||
* This reply includes the qname if it has been parsed.
|
||||
* For error ratelimiting, the err ratelimit routine should be checked
|
||||
* beforehand. The reply is without EDNS, and copies RD and sets QR flag.
|
||||
* @param pkt: the packet buffer from the comm point.
|
||||
* @param err: the error code that would be wanted.
|
||||
* @param qname_len: 0 if not parsed, and the qname length in packet.
|
||||
*/
|
||||
static void
|
||||
query_error(sldns_buffer* pkt, int err, size_t qname_len)
|
||||
{
|
||||
/* Preserve the RD flag.
|
||||
* The CD flag must be cleared in authoritative answers,
|
||||
* also the AD flag need not be copied into answers.
|
||||
* The other flags need not be copied into the answer. */
|
||||
sldns_buffer_write_u16_at(pkt, 2,
|
||||
sldns_buffer_read_u16_at(pkt, 2)&0x0100U);
|
||||
LDNS_QR_SET(sldns_buffer_begin(pkt)); /* Set QR flag. */
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(pkt), err); /* Set rcode */
|
||||
|
||||
if(qname_len && LDNS_QDCOUNT(sldns_buffer_begin(pkt))>=1 &&
|
||||
qname_len <= LDNS_MAX_DOMAINLEN) {
|
||||
/* Copy query into the answer. */
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(pkt), 1);
|
||||
sldns_buffer_set_position(pkt, LDNS_HEADER_SIZE +
|
||||
qname_len + 2 /* type */ + 2 /* class */ );
|
||||
} else {
|
||||
/* No query section in answer. */
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
sldns_buffer_set_position(pkt, LDNS_HEADER_SIZE);
|
||||
}
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(pkt), 0);
|
||||
sldns_buffer_flip(pkt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Structure holding the result of the worker_check_request function.
|
||||
* Based on configuration it could be called up to four times; ideally should
|
||||
@@ -329,7 +368,6 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker,
|
||||
return;
|
||||
}
|
||||
if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
|
||||
LDNS_TC_CLR(sldns_buffer_begin(pkt));
|
||||
verbose(VERB_QUERY, "request bad, has TC bit on");
|
||||
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
|
||||
return;
|
||||
@@ -971,6 +1009,7 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
|
||||
size_t udpsize = edns->udp_size;
|
||||
edns->edns_version = EDNS_ADVERTISED_VERSION;
|
||||
edns->udp_size = EDNS_ADVERTISED_SIZE;
|
||||
edns->ext_rcode = 0;
|
||||
edns->bits &= EDNS_DO;
|
||||
if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
|
||||
LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad,
|
||||
@@ -1229,9 +1268,7 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
worker_check_request(c->buffer, worker, check_result);
|
||||
if(check_result->value != 0) {
|
||||
if(check_result->value != -1) {
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
check_result->value);
|
||||
query_error(c->buffer, check_result->value, 0);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
@@ -1248,41 +1285,17 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
/* check additional section is present and that we respond with EDEs */
|
||||
if(LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) != 1
|
||||
|| !ede) {
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_REFUSED);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (!query_dname_len(c->buffer)) {
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
return 1;
|
||||
}
|
||||
/* space available for query type and class? */
|
||||
if (sldns_buffer_remaining(c->buffer) < 2 * sizeof(uint16_t)) {
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
return 1;
|
||||
}
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
@@ -1304,35 +1317,27 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
|
||||
if(!skip_pkt_rrs(c->buffer,
|
||||
((int)LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)))+
|
||||
((int)LDNS_NSCOUNT(sldns_buffer_begin(c->buffer))))) {
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR,
|
||||
opt_rr_mark - LDNS_HEADER_SIZE
|
||||
- 2 /* qtype */ - 2 /* qclass */);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Do we have a valid OPT RR here? If not return REFUSED (could be a valid TSIG or something so no FORMERR) */
|
||||
/* domain name must be the root of length 1. */
|
||||
if(sldns_buffer_remaining(c->buffer) < 1 || *sldns_buffer_current(c->buffer) != 0) {
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED,
|
||||
opt_rr_mark - LDNS_HEADER_SIZE
|
||||
- 2 /* qtype */ - 2 /* qclass */);
|
||||
return 1;
|
||||
} else {
|
||||
sldns_buffer_skip(c->buffer, 1); /* skip root label */
|
||||
}
|
||||
if(sldns_buffer_remaining(c->buffer) < 2 ||
|
||||
sldns_buffer_read_u16(c->buffer) != LDNS_RR_TYPE_OPT) {
|
||||
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
|
||||
sldns_buffer_set_position(c->buffer, opt_rr_mark);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED,
|
||||
opt_rr_mark - LDNS_HEADER_SIZE
|
||||
- 2 /* qtype */ - 2 /* qclass */);
|
||||
return 1;
|
||||
}
|
||||
/* Write OPT RR directly after the query,
|
||||
@@ -1444,6 +1449,24 @@ check_ip_ratelimit(struct worker* worker, struct sockaddr_storage* addr,
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is the callback function when a request arrives. It is passed
|
||||
* the packet and user argument. Return true to send a reply.
|
||||
* This is of type comm_point_callback_type. The struct comm_point contains
|
||||
* more comments on the comm_point.callback member about the function.
|
||||
* @param c: the comm_point where the request arrives on.
|
||||
* @param arg: the user argument for the callback, the worker.
|
||||
* @param error: This can be NETEVENT_NOERROR, NETEVENT_TIMEOUT,
|
||||
* NETEVENT_CLOSED or other comm point callback error values.
|
||||
* @param repinfo: The reply info, use it to send a reply. If the reply
|
||||
* is immediate, return 1. If the reply is later on return 0 and save
|
||||
* the repinfo, to call comm_point_send_reply on.
|
||||
* @return 1 to sent a reply straight away, for like cache response so that
|
||||
* no allocation needs to be done. And only internal preallocated buffers
|
||||
* are used. Return 0 and save the repinfo to reply later, for responses
|
||||
* that need to be looked up. Return 0 and call comm_point_drop_reply on
|
||||
* the repinfo to drop the response.
|
||||
*/
|
||||
int
|
||||
worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply* repinfo)
|
||||
@@ -1510,6 +1533,10 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
"dnscrypt: worker check request: bad query.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(check_result.value != -1) {
|
||||
query_error(c->buffer, check_result.value, 0);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
@@ -1518,8 +1545,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
"dnscrypt: worker parse request: formerror.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
dname_str(qinfo.qname, buf);
|
||||
if(!(qinfo.qtype == LDNS_RR_TYPE_TXT &&
|
||||
@@ -1530,9 +1562,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
worker->daemon->dnscenv->provider_name,
|
||||
sldns_rr_descript(qinfo.qtype)->_name,
|
||||
buf);
|
||||
comm_point_drop_reply(repinfo);
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_SERVFAIL) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo.qname_len);
|
||||
worker->stats.num_query_dnscrypt_cleartext++;
|
||||
return 0;
|
||||
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
|
||||
return 1;
|
||||
}
|
||||
worker->stats.num_query_dnscrypt_cert++;
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
@@ -1572,9 +1610,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "worker check request: bad query.");
|
||||
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
|
||||
if(check_result.value != -1) {
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
check_result.value);
|
||||
query_error(c->buffer, check_result.value, 0);
|
||||
return 1;
|
||||
}
|
||||
comm_point_drop_reply(repinfo);
|
||||
@@ -1608,10 +1644,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
|
||||
goto send_reply;
|
||||
}
|
||||
if(worker->env.cfg->log_queries) {
|
||||
@@ -1624,10 +1657,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "worker request: refused zone transfer.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_REFUSED);
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
query_error(c->buffer, LDNS_RCODE_REFUSED, qinfo.qname_len);
|
||||
if(worker->stats.extended) {
|
||||
worker->stats.qtype[qinfo.qtype]++;
|
||||
}
|
||||
@@ -1646,10 +1680,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
comm_point_drop_reply(repinfo);
|
||||
return 0;
|
||||
}
|
||||
sldns_buffer_rewind(c->buffer);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_FORMERR);
|
||||
query_error(c->buffer, LDNS_RCODE_FORMERR, qinfo.qname_len);
|
||||
if(worker->stats.extended) {
|
||||
worker->stats.qtype[qinfo.qtype]++;
|
||||
}
|
||||
@@ -1657,13 +1688,17 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
}
|
||||
if((ret=parse_edns_from_query_pkt(
|
||||
c->buffer, &edns, worker->env.cfg, c, repinfo,
|
||||
(worker->env.now ? *worker->env.now : time(NULL)),
|
||||
worker->scratchpad,
|
||||
*worker->env.now, worker->scratchpad,
|
||||
worker->daemon->cookie_secrets)) != 0) {
|
||||
struct edns_data reply_edns;
|
||||
verbose(VERB_ALGO, "worker parse edns: formerror.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(worker_err_ratelimit(worker, ret) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
memset(&reply_edns, 0, sizeof(reply_edns));
|
||||
reply_edns.edns_present = 1;
|
||||
error_encode(c->buffer, ret, &qinfo,
|
||||
@@ -1680,6 +1715,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "query with bad edns version.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
if(worker_err_ratelimit(worker, EDNS_RCODE_BADVERS) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns);
|
||||
@@ -1725,6 +1765,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
|
||||
else if(edns.cookie_present) {
|
||||
/* Cookie present, but not valid: Cookie was bad! */
|
||||
if(worker_err_ratelimit(worker, LDNS_EXT_RCODE_BADCOOKIE) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
extended_error_encode(c->buffer,
|
||||
LDNS_EXT_RCODE_BADCOOKIE, &qinfo,
|
||||
*(uint16_t*)(void *)
|
||||
@@ -1739,6 +1784,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
"need cookie or stateful transport");
|
||||
log_addr(VERB_ALGO, "from",&repinfo->remote_addr
|
||||
, repinfo->remote_addrlen);
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
|
||||
worker->scratchpad, LDNS_EDE_OTHER,
|
||||
"DNS Cookie needed for UDP replies");
|
||||
@@ -1765,14 +1815,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
verbose(VERB_ALGO, "worker request: edns is too small.");
|
||||
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
|
||||
repinfo->client_addrlen);
|
||||
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_SERVFAIL) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
/* A small error without qname, and TC flag on. */
|
||||
query_error(c->buffer, LDNS_RCODE_SERVFAIL, 0);
|
||||
LDNS_TC_SET(sldns_buffer_begin(c->buffer));
|
||||
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
|
||||
sldns_buffer_write_at(c->buffer, 4,
|
||||
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
|
||||
sldns_buffer_flip(c->buffer);
|
||||
regional_free_all(worker->scratchpad);
|
||||
goto send_reply;
|
||||
}
|
||||
@@ -1780,7 +1830,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
server_stats_insquery(&worker->stats, c, qinfo.qtype,
|
||||
qinfo.qclass, &edns, repinfo);
|
||||
if(c->type != comm_udp)
|
||||
#ifdef USE_DNSCRYPT
|
||||
edns.udp_size = (c->dnscrypt && repinfo->is_dnscrypted)
|
||||
? sldns_buffer_capacity(c->buffer) - DNSCRYPT_REPLY_HEADER_SIZE
|
||||
: 65535;
|
||||
#else
|
||||
edns.udp_size = 65535; /* max size for TCP replies */
|
||||
#endif
|
||||
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
|
||||
&edns, repinfo, c->buffer)) {
|
||||
regional_free_all(worker->scratchpad);
|
||||
@@ -1857,6 +1913,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
* ACLs allow the snooping. */
|
||||
if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) &&
|
||||
acl != acl_allow_snoop ) {
|
||||
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
/* This ratelimited error query is accounted in the stats,
|
||||
* as an incoming query. */
|
||||
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
|
||||
comm_point_drop_reply(repinfo);
|
||||
regional_free_all(worker->scratchpad);
|
||||
return 0;
|
||||
}
|
||||
if(worker->env.cfg->ede) {
|
||||
EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
|
||||
worker->scratchpad, LDNS_EDE_NOT_AUTHORITATIVE, "");
|
||||
@@ -1865,9 +1930,6 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
|
||||
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
|
||||
sldns_buffer_read_u16_at(c->buffer, 2), &edns);
|
||||
regional_free_all(worker->scratchpad);
|
||||
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
|
||||
&repinfo->client_addr, repinfo->client_addrlen);
|
||||
|
||||
goto send_reply;
|
||||
}
|
||||
|
||||
@@ -2058,7 +2120,7 @@ send_reply_rc:
|
||||
}
|
||||
}
|
||||
#ifdef USE_DNSCRYPT
|
||||
if(!dnsc_handle_uncurved_request(repinfo)) {
|
||||
if(!dnsc_handle_uncurved_request(repinfo, c->buffer)) {
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
@@ -2106,10 +2168,37 @@ worker_restart_timer(struct worker* worker)
|
||||
{
|
||||
if(worker->env.cfg->stat_interval > 0) {
|
||||
struct timeval tv;
|
||||
if(worker->daemon->stat_time_specific) {
|
||||
struct timeval dest, now;
|
||||
int interval = worker->env.cfg->stat_interval;
|
||||
int offset = worker->daemon->stat_time_offset;
|
||||
int nows, spec;
|
||||
if(gettimeofday(&now, NULL) < 0)
|
||||
log_err("gettimeofday: %s", strerror(errno));
|
||||
#ifndef S_SPLINT_S
|
||||
tv.tv_sec = worker->env.cfg->stat_interval;
|
||||
tv.tv_usec = 0;
|
||||
nows = (int)now.tv_sec;
|
||||
/* The next time is on the timer interval, at the
|
||||
* specific offset, time value % interval = offset. */
|
||||
/* It relies on the integer division below to drop the
|
||||
* remainder in order to calculate the expected
|
||||
* result. */
|
||||
spec = ((nows-offset)/interval+1)*interval+offset;
|
||||
/* This is instead of an assertion, and should not
|
||||
* be needed. So assert(spec > nows), tv is going to
|
||||
* be positive. */
|
||||
if(spec<=nows) spec += interval;
|
||||
dest.tv_sec = spec;
|
||||
dest.tv_usec = 0;
|
||||
#endif
|
||||
/* Subtract in timeval, so the fractions of a second
|
||||
* are rounded to the whole specific time. */
|
||||
timeval_subtract(&tv, &dest, &now);
|
||||
} else {
|
||||
#ifndef S_SPLINT_S
|
||||
tv.tv_sec = worker->env.cfg->stat_interval;
|
||||
tv.tv_usec = 0;
|
||||
#endif
|
||||
}
|
||||
comm_timer_set(worker->stat_timer, &tv);
|
||||
}
|
||||
}
|
||||
@@ -2144,23 +2233,16 @@ void worker_probe_timer_cb(void* arg)
|
||||
}
|
||||
|
||||
struct worker*
|
||||
worker_create(struct daemon* daemon, int id, int* ports, int n)
|
||||
worker_create(struct daemon* daemon, int id)
|
||||
{
|
||||
unsigned int seed;
|
||||
struct worker* worker = (struct worker*)calloc(1,
|
||||
sizeof(struct worker));
|
||||
if(!worker)
|
||||
return NULL;
|
||||
worker->numports = n;
|
||||
worker->ports = (int*)memdup(ports, sizeof(int)*n);
|
||||
if(!worker->ports) {
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
worker->daemon = daemon;
|
||||
worker->thread_num = id;
|
||||
if(!(worker->cmd = tube_create())) {
|
||||
free(worker->ports);
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2168,7 +2250,6 @@ worker_create(struct daemon* daemon, int id, int* ports, int n)
|
||||
if(!(worker->rndstate = ub_initstate(daemon->rand))) {
|
||||
log_err("could not init random numbers.");
|
||||
tube_delete(worker->cmd);
|
||||
free(worker->ports);
|
||||
free(worker);
|
||||
return NULL;
|
||||
}
|
||||
@@ -2184,9 +2265,6 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
struct dt_env* dtenv = &worker->dtenv;
|
||||
#else
|
||||
void* dtenv = NULL;
|
||||
#endif
|
||||
#ifdef HAVE_GETTID
|
||||
worker->thread_tid = gettid();
|
||||
#endif
|
||||
worker->need_to_exit = 0;
|
||||
worker->base = comm_base_create(do_sigs);
|
||||
@@ -2270,14 +2348,14 @@ worker_init(struct worker* worker, struct config_file *cfg,
|
||||
cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
|
||||
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
|
||||
worker->daemon->env->infra_cache, worker->rndstate,
|
||||
cfg->use_caps_bits_for_id, worker->ports, worker->numports,
|
||||
cfg->use_caps_bits_for_id,
|
||||
cfg->unwanted_threshold, cfg->outgoing_tcp_mss,
|
||||
&worker_alloc_cleanup, worker,
|
||||
cfg->do_udp || cfg->udp_upstream_without_downstream,
|
||||
worker->daemon->connect_dot_sslctx, cfg->delay_close,
|
||||
cfg->tls_use_sni, dtenv, cfg->udp_connect,
|
||||
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
|
||||
cfg->tcp_auth_query_timeout);
|
||||
cfg->tcp_auth_query_timeout, worker->daemon->shared_ports);
|
||||
if(!worker->back) {
|
||||
log_err("could not create outgoing sockets");
|
||||
worker_delete(worker);
|
||||
@@ -2428,7 +2506,6 @@ worker_delete(struct worker* worker)
|
||||
tube_delete(worker->cmd);
|
||||
comm_timer_delete(worker->stat_timer);
|
||||
comm_timer_delete(worker->env.probe_timer);
|
||||
free(worker->ports);
|
||||
if(worker->thread_num == 0) {
|
||||
#ifdef UB_ON_WINDOWS
|
||||
wsvc_desetup_worker(worker);
|
||||
@@ -2560,6 +2637,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
+1
-7
@@ -104,10 +104,6 @@ struct worker {
|
||||
struct listen_dnsport* front;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** ports to be used by this worker. */
|
||||
int* ports;
|
||||
/** number of ports for this worker */
|
||||
int numports;
|
||||
/** the signal handler */
|
||||
struct comm_signal* comsig;
|
||||
/** commpoint to listen to commands. */
|
||||
@@ -146,11 +142,9 @@ struct worker {
|
||||
* with backpointers only. Use worker_init on it later.
|
||||
* @param daemon: the daemon that this worker thread is part of.
|
||||
* @param id: the thread number from 0.. numthreads-1.
|
||||
* @param ports: the ports it is allowed to use, array.
|
||||
* @param n: the number of ports.
|
||||
* @return: the new worker or NULL on alloc failure.
|
||||
*/
|
||||
struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n);
|
||||
struct worker* worker_create(struct daemon* daemon, int id);
|
||||
|
||||
/**
|
||||
* Initialize worker.
|
||||
|
||||
+8
-7
@@ -366,22 +366,23 @@ static int
|
||||
dns64_apply_cfg(struct dns64_env* dns64_env, struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* s;
|
||||
verbose(VERB_ALGO, "dns64-prefix: %s", cfg->dns64_prefix);
|
||||
if (!netblockstrtoaddr(cfg->dns64_prefix ? cfg->dns64_prefix :
|
||||
DEFAULT_DNS64_PREFIX, 0, &dns64_env->prefix_addr,
|
||||
const char* dns64_prefix = cfg->dns64_prefix ?
|
||||
cfg->dns64_prefix : DEFAULT_DNS64_PREFIX;
|
||||
verbose(VERB_ALGO, "dns64-prefix: %s", dns64_prefix);
|
||||
if (!netblockstrtoaddr(dns64_prefix, 0, &dns64_env->prefix_addr,
|
||||
&dns64_env->prefix_addrlen, &dns64_env->prefix_net)) {
|
||||
log_err("cannot parse dns64-prefix netblock: %s", cfg->dns64_prefix);
|
||||
log_err("cannot parse dns64-prefix netblock: %s", dns64_prefix);
|
||||
return 0;
|
||||
}
|
||||
if (!addr_is_ip6(&dns64_env->prefix_addr, dns64_env->prefix_addrlen)) {
|
||||
log_err("dns64_prefix is not IPv6: %s", cfg->dns64_prefix);
|
||||
log_err("dns64_prefix is not IPv6: %s", dns64_prefix);
|
||||
return 0;
|
||||
}
|
||||
if (dns64_env->prefix_net != 32 && dns64_env->prefix_net != 40 &&
|
||||
dns64_env->prefix_net != 48 && dns64_env->prefix_net != 56 &&
|
||||
dns64_env->prefix_net != 64 && dns64_env->prefix_net != 96 ) {
|
||||
log_err("dns64-prefix length it not 32, 40, 48, 56, 64 or 96: %s",
|
||||
cfg->dns64_prefix);
|
||||
log_err("dns64-prefix length is not 32, 40, 48, 56, 64 or 96: %s",
|
||||
dns64_prefix);
|
||||
return 0;
|
||||
}
|
||||
for(s = cfg->dns64_ignore_aaaa; s; s = s->next) {
|
||||
|
||||
+24
-4
@@ -361,7 +361,7 @@ dnscrypt_server_uncurve(struct dnsc_env* env,
|
||||
|
||||
len -= DNSCRYPT_QUERY_HEADER_SIZE;
|
||||
|
||||
while (*sldns_buffer_at(buffer, --len) == 0)
|
||||
while (len>0 && *sldns_buffer_at(buffer, --len) == 0)
|
||||
;
|
||||
|
||||
if (*sldns_buffer_at(buffer, len) != 0x80) {
|
||||
@@ -474,10 +474,18 @@ dnscrypt_server_curve(const dnsccert *cert,
|
||||
uint8_t *const buf = sldns_buffer_begin(buffer);
|
||||
size_t len = sldns_buffer_limit(buffer);
|
||||
|
||||
if(len + DNSCRYPT_REPLY_HEADER_SIZE > sldns_buffer_capacity(buffer))
|
||||
return -1;
|
||||
sldns_buffer_clear(buffer);
|
||||
|
||||
if(udp){
|
||||
if (max_len > max_reply_size)
|
||||
max_len = max_reply_size;
|
||||
}
|
||||
if(max_len > sldns_buffer_capacity(buffer))
|
||||
max_len = sldns_buffer_capacity(buffer);
|
||||
if(max_len > 65535)
|
||||
max_len = 65535;
|
||||
|
||||
|
||||
memcpy(nonce, client_nonce, crypto_box_HALF_NONCEBYTES);
|
||||
@@ -520,6 +528,7 @@ dnscrypt_server_curve(const dnsccert *cert,
|
||||
DNSCRYPT_MAGIC_HEADER_LEN,
|
||||
nonce,
|
||||
crypto_box_NONCEBYTES);
|
||||
sldns_buffer_flip(buffer);
|
||||
sldns_buffer_set_limit(buffer, len + DNSCRYPT_REPLY_HEADER_SIZE);
|
||||
return 0;
|
||||
}
|
||||
@@ -663,6 +672,8 @@ dnsc_find_cert(struct dnsc_env* dnscenv, struct sldns_buffer* buffer)
|
||||
}
|
||||
dnscrypt_header = (struct dnscrypt_query_header *)sldns_buffer_begin(buffer);
|
||||
for (i = 0U; i < dnscenv->signed_certs_count; i++) {
|
||||
if(!certs[i].keypair)
|
||||
continue;
|
||||
if (memcmp(certs[i].magic_query, dnscrypt_header->magic_query,
|
||||
DNSCRYPT_MAGIC_HEADER_LEN) == 0) {
|
||||
return &certs[i];
|
||||
@@ -804,6 +815,7 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg)
|
||||
sizeof *env->keypairs);
|
||||
env->certs = sodium_allocarray(env->signed_certs_count,
|
||||
sizeof *env->certs);
|
||||
memset(env->certs, 0, env->signed_certs_count * sizeof(*env->certs));
|
||||
|
||||
cert_id = 0U;
|
||||
keypair_id = 0U;
|
||||
@@ -912,12 +924,13 @@ dnsc_handle_curved_request(struct dnsc_env* dnscenv,
|
||||
}
|
||||
|
||||
int
|
||||
dnsc_handle_uncurved_request(struct comm_reply *repinfo)
|
||||
dnsc_handle_uncurved_request(struct comm_reply *repinfo,
|
||||
struct sldns_buffer* buffer)
|
||||
{
|
||||
if(!repinfo->c->dnscrypt) {
|
||||
return 1;
|
||||
}
|
||||
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, repinfo->c->buffer);
|
||||
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, buffer);
|
||||
if(!repinfo->is_dnscrypted) {
|
||||
return 1;
|
||||
}
|
||||
@@ -963,12 +976,19 @@ dnsc_create(void)
|
||||
int
|
||||
dnsc_apply_cfg(struct dnsc_env *env, struct config_file *cfg)
|
||||
{
|
||||
int nkeys;
|
||||
if(dnsc_parse_certs(env, cfg) <= 0) {
|
||||
fatal_exit("dnsc_apply_cfg: no cert file loaded");
|
||||
}
|
||||
if(dnsc_parse_keys(env, cfg) <= 0) {
|
||||
nkeys = dnsc_parse_keys(env, cfg);
|
||||
if(nkeys <= 0) {
|
||||
fatal_exit("dnsc_apply_cfg: no key file loaded");
|
||||
}
|
||||
if((size_t)nkeys < env->signed_certs_count) {
|
||||
fatal_exit("dnsc_apply_cfg: %u dnscrypt-provider-cert file(s) have no "
|
||||
"matching dnscrypt-secret-key",
|
||||
(unsigned)(env->signed_certs_count - (size_t)nkeys));
|
||||
}
|
||||
randombytes_buf(env->hash_key, sizeof env->hash_key);
|
||||
env->provider_name = cfg->dnscrypt_provider;
|
||||
|
||||
|
||||
+2
-1
@@ -128,7 +128,8 @@ int dnsc_handle_curved_request(struct dnsc_env* dnscenv,
|
||||
* \return 0 in case of failure.
|
||||
*/
|
||||
|
||||
int dnsc_handle_uncurved_request(struct comm_reply *repinfo);
|
||||
int dnsc_handle_uncurved_request(struct comm_reply *repinfo,
|
||||
struct sldns_buffer* buffer);
|
||||
|
||||
/**
|
||||
* Computes the size of the shared secret cache entry.
|
||||
|
||||
+15
-1
@@ -448,6 +448,9 @@ int dt_io_thread_apply_cfg(struct dt_io_thread* dtio, struct config_file *cfg)
|
||||
dtio->tls_use_sni = cfg->tls_use_sni;
|
||||
#endif /* HAVE_SSL */
|
||||
}
|
||||
#ifdef HAVE_GETTID
|
||||
dtio->thread_tid_log = cfg->log_thread_id;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2130,7 +2133,18 @@ static void* dnstap_io(void* arg)
|
||||
struct dt_io_thread* dtio = (struct dt_io_thread*)arg;
|
||||
time_t secs = 0;
|
||||
struct timeval now;
|
||||
log_thread_set(&dtio->threadnum);
|
||||
const char name[16] = "unbound/dnstap"; /* seems to be the safest size
|
||||
between different OSes */
|
||||
|
||||
#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED)
|
||||
dtio->thread_tid = gettid();
|
||||
if(dtio->thread_tid_log)
|
||||
log_thread_set(&dtio->thread_tid);
|
||||
else
|
||||
#endif
|
||||
log_thread_set(&dtio->threadnum);
|
||||
|
||||
ub_thread_setname(dtio->tid, name);
|
||||
|
||||
/* setup */
|
||||
verbose(VERB_ALGO, "start dnstap io thread");
|
||||
|
||||
@@ -131,6 +131,12 @@ struct dt_io_thread {
|
||||
struct dt_io_list_item* io_list_iter;
|
||||
/** thread id, of the io thread */
|
||||
ub_thread_type tid;
|
||||
#ifdef HAVE_GETTID
|
||||
/** thread tid, the LWP id */
|
||||
pid_t thread_tid;
|
||||
/** if logging should include the LWP id */
|
||||
int thread_tid_log;
|
||||
#endif
|
||||
/** if the io processing has started */
|
||||
int started;
|
||||
/** ssl context for the io thread, for tls connections. type SSL_CTX* */
|
||||
|
||||
@@ -330,7 +330,7 @@ static struct tap_socket* tap_socket_new_tcpaccept(char* ip,
|
||||
/** create new socket (unconnected, not base-added), or NULL malloc fail */
|
||||
static struct tap_socket* tap_socket_new_tlsaccept(char* ip,
|
||||
void (*ev_cb)(int, short, void*), void* data, char* server_key,
|
||||
char* server_cert, char* verifypem)
|
||||
char* server_cert, char* verifypem, char* tls_protocols)
|
||||
{
|
||||
struct tap_socket* s = calloc(1, sizeof(*s));
|
||||
if(!s) {
|
||||
@@ -347,7 +347,7 @@ static struct tap_socket* tap_socket_new_tlsaccept(char* ip,
|
||||
s->ev_cb = ev_cb;
|
||||
s->data = data;
|
||||
s->sslctx = listen_sslctx_create(server_key, server_cert, verifypem,
|
||||
NULL, NULL, 0, 0, 0, 0);
|
||||
NULL, NULL, 0, 0, 0, tls_protocols);
|
||||
if(!s->sslctx) {
|
||||
log_err("could not create ssl context");
|
||||
free(s->ip);
|
||||
@@ -1261,13 +1261,13 @@ static void setup_tcp_list(struct main_tap_data* maindata,
|
||||
/** setup tls accept sockets */
|
||||
static void setup_tls_list(struct main_tap_data* maindata,
|
||||
struct config_strlist_head* tls_list, char* server_key,
|
||||
char* server_cert, char* verifypem)
|
||||
char* server_cert, char* verifypem, char* tls_protocols)
|
||||
{
|
||||
struct config_strlist* item;
|
||||
for(item = tls_list->first; item; item = item->next) {
|
||||
struct tap_socket* s;
|
||||
s = tap_socket_new_tlsaccept(item->str, &dtio_mainfdcallback,
|
||||
maindata, server_key, server_cert, verifypem);
|
||||
maindata, server_key, server_cert, verifypem, tls_protocols);
|
||||
if(!s) fatal_exit("out of memory");
|
||||
if(!tap_socket_list_insert(&maindata->acceptlist, s))
|
||||
fatal_exit("out of memory");
|
||||
@@ -1300,7 +1300,7 @@ static void
|
||||
setup_and_run(struct config_strlist_head* local_list,
|
||||
struct config_strlist_head* tcp_list,
|
||||
struct config_strlist_head* tls_list, char* server_key,
|
||||
char* server_cert, char* verifypem)
|
||||
char* server_cert, char* verifypem, char* tls_protocols)
|
||||
{
|
||||
time_t secs = 0;
|
||||
struct timeval now;
|
||||
@@ -1326,7 +1326,7 @@ setup_and_run(struct config_strlist_head* local_list,
|
||||
setup_local_list(maindata, local_list);
|
||||
setup_tcp_list(maindata, tcp_list);
|
||||
setup_tls_list(maindata, tls_list, server_key, server_cert,
|
||||
verifypem);
|
||||
verifypem, tls_protocols);
|
||||
if(!tap_socket_list_addevs(maindata->acceptlist, base))
|
||||
fatal_exit("could not setup accept events");
|
||||
if(verbosity) log_info("start of service");
|
||||
@@ -1462,6 +1462,8 @@ int main(int argc, char** argv)
|
||||
struct config_strlist_head tcp_list;
|
||||
struct config_strlist_head tls_list;
|
||||
char* server_key = NULL, *server_cert = NULL, *verifypem = NULL;
|
||||
|
||||
char* tls_protocols = "TLSv1.2 TLSv1.3";
|
||||
#ifdef USE_WINSOCK
|
||||
WSADATA wsa_data;
|
||||
if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
|
||||
@@ -1561,17 +1563,25 @@ int main(int argc, char** argv)
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#endif /* HAVE_SSL */
|
||||
}
|
||||
setup_and_run(&local_list, &tcp_list, &tls_list, server_key,
|
||||
server_cert, verifypem);
|
||||
server_cert, verifypem, tls_protocols);
|
||||
config_delstrlist(local_list.first);
|
||||
config_delstrlist(tcp_list.first);
|
||||
config_delstrlist(tls_list.first);
|
||||
@@ -1725,6 +1735,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
+453
@@ -1,3 +1,456 @@
|
||||
20 May 2026: Wouter
|
||||
- Fix CVE-2026-33278, Possible remote code execution during DNSSEC
|
||||
validation. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-42944, Heap overflow and crash with multiple nsid,
|
||||
cookie, padding EDNS options. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix CVE-2026-42959, Crash during DNSSEC validation of malicious
|
||||
content. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-32792, Packet of death with DNSCrypt. Thanks to Andrew
|
||||
Griffiths from 'calif.io' for the report.
|
||||
- Fix CVE-2026-40622, "Ghost domain name" variant. Thanks to Qifan
|
||||
Zhang, Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-41292, Parsing a long list of incoming EDNS options
|
||||
degrades performance. Thanks to GitHub user 'N0zoM1z0', also Qifan
|
||||
Zhang from Palo Alto Networks, for the report.
|
||||
- Fix CVE-2026-42534, Jostle logic bypass degrades resolution
|
||||
performance. Thanks to Qifan Zhang, Palo Alto Networks, for the
|
||||
report.
|
||||
- Fix CVE-2026-42923, Degradation of service with unbounded NSEC3
|
||||
hash calculations. Thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
the report.
|
||||
- Fix CVE-2026-42960, Possible cache poisoning attack while following
|
||||
delegation. Thanks to TaoFei Guo from Peking University, Yang Luo
|
||||
and JianJun Chen, Tsinghua University, for the report.
|
||||
- Fix CVE-2026-44390, Unbounded name compression in certain cases
|
||||
causes degradation of service. Thanks to Qifan Zhang, Palo Alto
|
||||
Networks, for the report.
|
||||
- Fix CVE-2026-44608, Use after free and crash in RPZ code. Thanks
|
||||
to Qifan Zhang, Palo Alto Networks, for the report.
|
||||
|
||||
23 April 2026: Wouter
|
||||
- Merge #1441: Fix buffer overrun in
|
||||
doq_repinfo_retrieve_localaddr().
|
||||
- For #1441: Fix type of ipv6 addr struct.
|
||||
|
||||
21 April 2026: Wouter
|
||||
- Add test case for malformed SVCB records. Thanks to
|
||||
Qifan Zhang, Palo Alto Networks for the additional test.
|
||||
- Fix for the Jiggle Attack. The server is fixed to answer
|
||||
with errors for error cases, and does not stay silent.
|
||||
In addition, the error replies do not contain parts of the
|
||||
incoming query. This is more conformant, stops reflection
|
||||
and stops it as a covert channel. Thanks to Yuqi Qiu and
|
||||
Xiang Li, Nankai University (AOSP Lab) for the report.
|
||||
In addition, thanks to Qifan Zhang, Palo Alto Networks, for
|
||||
noting the fingerprinting possibility, that is also fixed
|
||||
with this.
|
||||
- Fix EDNS extended RCODE reflection. This fixes that
|
||||
the server does not echo extended rcode values after class
|
||||
chaos queries. Thanks to Qifan Zhang, Palo Alto Networks
|
||||
for the report.
|
||||
- Fix for iterator RCODE handling of YXDOMAIN. This fixes
|
||||
that the server only accepts YXDOMAIN answers that contain
|
||||
a DNAME record. This stops bad answers, and checks that
|
||||
the authoritative server gives correct replies.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks for the report.
|
||||
- Fix for missing bounds check for decompressing dnames
|
||||
for downloaded authority zones. This fixes that the server
|
||||
could end up with malformed zone content after receiving
|
||||
truncated packet contents from an AXFR. In addition, the
|
||||
domain names in the SOA rdata are checked before the
|
||||
authority code picks up the zone serial.
|
||||
Thanks to Halil Oktay for the report.
|
||||
- Fix that upstream TLS connections are not reused as TLS
|
||||
connections for a different name, at the same IP. This
|
||||
checks that the tls name is correct when reusing the
|
||||
upstream connections. Thanks to TaoFei Guo from Peking
|
||||
University and JianJun Chen from Tsinghua University for
|
||||
the report.
|
||||
- Fix that signatures are not allowed with revoked dnskeys.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks for the report.
|
||||
- Fix that a DNAME with an unsigned CNAME is checked for
|
||||
the correct match. This stops that for certain zone
|
||||
configurations an unchecked unsigned CNAME could get
|
||||
secure status. Thanks to Qifan Zhang, Palo Alto Networks
|
||||
for the report.
|
||||
- Fix handling of wildcard CNAMEs in the chain of trust.
|
||||
An improper wildcard in the chain of trust would send
|
||||
the retries to the wrong upstream. Also it could label
|
||||
the step in the chain of trust as secure, when it was not.
|
||||
Thanks to Qifan Zhang, Palo Alto Networks for the report.
|
||||
- Set version number to 1.25.0 of code repository.
|
||||
- Fix doxygen comment syntax.
|
||||
|
||||
20 April 2026: Wouter
|
||||
- Fix compile warnings for thread setname routine, and test compile.
|
||||
- Fix unused variable warning when compiled without ssl.
|
||||
- Fix test with https zone for libressl.
|
||||
|
||||
17 April 2026: Wouter
|
||||
- Fix setup of ssl context copy of the tls service pem option,
|
||||
from a clang analyzer warning.
|
||||
- Fix setup of ssl context copy, to check for the tls service
|
||||
pem option for stat calls.
|
||||
- Fix to compile the shm code when there is no shmget.
|
||||
- Update github ci to use actions/checkout@v6.
|
||||
- Update github ci cross platform to use
|
||||
cross-platform-actions/action@v1.0.0.
|
||||
- Fix github ci to speed up with parralel build, for windows ci.
|
||||
- Fix compat/chacha_private sigma and tau definitions to use
|
||||
nonstring attribute.
|
||||
- Fix compat/gmtime_r old style definition syntax.
|
||||
- Fix to increase size of the buffer for the win_svc reportev log
|
||||
function.
|
||||
- Fix ttl comparisons in rdata_copy for 32bit signed or unsigned.
|
||||
- Fix subnet store of servfail to not leak memory.
|
||||
- Update generated man pages.
|
||||
- Update generated configure, with autoconf.
|
||||
- Fix pthread_setname detection to fail on warnings.
|
||||
|
||||
17 April 2026: Yorgos
|
||||
- Merge #1400: Support pthread_setname_np. Adds support for
|
||||
pthread_setname_np and variants to set the name on spawned threads
|
||||
for easier debugging/monitoring.
|
||||
|
||||
16 April 2026: Yorgos
|
||||
- Merge #1406: Introduce new 'tls-protocols' configuration option.
|
||||
- Introduce new 'tls-protocols' configuration option that specifies
|
||||
which of the supported TLS protocols will be used.
|
||||
This change invalidates some previous changes:
|
||||
- TLSv1.2 is again enabled by default, but can be selectively turned
|
||||
off if desired (related to #1303).
|
||||
- The biefly introduced (not yet released) 'tls-use-system-versions'
|
||||
configuration option, that addressed #1346, is reverted in favor of
|
||||
'tls-protocols'.
|
||||
- The briefly introduced (not yet released) '--enable-system-tls'
|
||||
configure option, related to #1401, is no longer needed with the new
|
||||
option and the current default.
|
||||
- Fix cleaning up DoH session. The same query can be on multiple
|
||||
streams in a session.
|
||||
|
||||
16 April 2026: Wouter
|
||||
- Fix configure, autoconf for #1406.
|
||||
|
||||
15 April 2026: Wouter
|
||||
- Fix RFC7766 compliance when client sends EOF over TCP. It stops
|
||||
pending replies and closes. Thanks to Yuxiao Wu, Tsinghua
|
||||
University for the report.
|
||||
- Fix to shorten RRSIG count in scrubber, this protects against
|
||||
an overly large number of RRSIGs. It can be configured with
|
||||
`iter-scrub-rrsig: 8`, it has default 8. Thanks to Yuxiao Wu,
|
||||
Tsinghua University for the report.
|
||||
|
||||
14 April 2026: Wouter
|
||||
- Fix #1017: memory corruption related core dumps.
|
||||
When alloc_reg_obtain has an empty list, return a new allocation.
|
||||
- Fix clang analyzer warning for subnetmod, when return_msg is
|
||||
NULL for update cache, like when it stores servfail status.
|
||||
- iana portlist updated.
|
||||
|
||||
13 April 2026: Yorgos
|
||||
- Update the documentation of 'max-query-restarts' in the man page.
|
||||
|
||||
10 April 2026: Wouter
|
||||
- Fix for EDNS client subnet so that it does not store SERVFAIL in
|
||||
the global cache after a failed lookup, such as timeouts. A failure
|
||||
entry is stored in the subnet cache, for the query name, for a
|
||||
couple of seconds. Queries can continue to use the subnet cache
|
||||
during that time.
|
||||
|
||||
7 April 2026: Yorgos
|
||||
- Fix unused variable warning.
|
||||
|
||||
30 March 2026: Wouter
|
||||
- Merge #1408: Fix shared memory stats with threads.
|
||||
|
||||
27 March 2026: Wouter
|
||||
- Fix to allow the control-interface config to use ip@port notation.
|
||||
- Fix test code to allow empty hex answer packets from testbound.
|
||||
- Fix defense in depth for service callback with empty packet.
|
||||
|
||||
24 March 2026: Wouter
|
||||
- Fix to check for invalid http content length and chunk size,
|
||||
and to check the RR rdata field lengths when decompressing and
|
||||
inserting RRs from an authority zone transfer. This stops
|
||||
large memory use and heap buffer-overflow read errors. Thanks
|
||||
to Haruto Kimura (Stella) for the report.
|
||||
|
||||
20 March 2026: Wouter
|
||||
- Fix for testcode pktview to check buffer size and log errors.
|
||||
|
||||
13 March 2026: Yorgos
|
||||
- Fix to ignore out-of-zone DNAME records for CNAME synthesis. Thanks
|
||||
to Yuxiao Wu, Yiyi Wang, Zhang Chao, Baojun Liu, and Haixin Duan from
|
||||
Tsinghua University.
|
||||
|
||||
13 March 2026: Wouter
|
||||
- Fix #278: DoT: complete unbound restart required on certificate
|
||||
renew. Fix so that a reload checks if the files have changed, and
|
||||
if so, reload the contexts. Also for DoH, DoQ and outgoing DoT.
|
||||
- iana portlist updated.
|
||||
- For #278: fast_reload can reload tls-service-key, tls-service-pem
|
||||
and tls-cert-bundle changes. It checks the modification time of
|
||||
the tls-service-key and tls-service-pem files for update.
|
||||
- Fix detection of http listening port in fast_reload.
|
||||
- Fix to add tls-service-key to memory printout for fast_reload.
|
||||
|
||||
9 March 2026: Wouter
|
||||
- Fix compile failure in unbound-checkconf for older gcc compiler.
|
||||
- Merge #1418: Apply cache TTL policy to DNAME and synthesized
|
||||
CNAME on wire path.
|
||||
|
||||
6 March 2026: Wouter
|
||||
- Merge #1415: Add lock unlock for view in memory error handling.
|
||||
|
||||
6 March 2026: Yorgos
|
||||
- Document the suggestion for a higher value for 'outgoing-range';
|
||||
helps when the request list is full.
|
||||
- Warn for unused 'nodefault' local-zone configuration in
|
||||
unbound-checkconf (related to #1416).
|
||||
|
||||
5 March 2026: Wouter
|
||||
- Fix for DNS Rebinding Bypass via SVCB/HTTPS Records in Unbound.
|
||||
Thanks to Kunta Chu, School of Software, Tsinghua University,
|
||||
Taofei Guo, Peking University, and Jianjun Chen, Institute for
|
||||
Network Sciences and Cyberspace, Tsinghua University for the
|
||||
report. The private-address option is fixed to also elide
|
||||
SVCB and HTTPS records that match the filter.
|
||||
- Update generated man pages.
|
||||
|
||||
4 March 2026: Yorgos
|
||||
- For #1411: Introduce a failing case in the rpl test so that it only
|
||||
passes with the fix in place.
|
||||
|
||||
3 March 2026: Wouter
|
||||
- Merge #1411: Allow synthesized DNAME TTL=0 to be served from cache
|
||||
within grace period. The responses are served from cache within
|
||||
a 1-second grace period. Reduces recursion when authoritative
|
||||
servers return DNAME with TTL=0 (RFC 2308). Response
|
||||
still returns TTL=0 to clients. Adds a test for it.
|
||||
- For #1411: Fix that the lookup for DNAME uses flag. Fix assertion
|
||||
in expired calc debug routine.
|
||||
|
||||
27 February 2026: Wouter
|
||||
- Merge #1409: Documentation CNAME in redirect-type local-zone.
|
||||
- Update generated man pages.
|
||||
|
||||
25 February 2026: Wouter
|
||||
- Fix validator to set unchecked when validation recursion
|
||||
requests are passed. The edns subnet module checks if validation
|
||||
is needed for a cache response, and set the validator to protect
|
||||
the cache with validation for non-subnet lookups.
|
||||
|
||||
23 February 2026: Wouter
|
||||
- Fix to have cachedb not return expired bogus data as non-bogus.
|
||||
- Fix to make the cachedb_val_expired.crpl succeed.
|
||||
|
||||
23 February 2026: Yorgos
|
||||
- Fix to disallow cache lookup/store in external cachedb when a
|
||||
forwarder/stub forbids it with the no-cache option.
|
||||
- Fixed some typos reported in #1395 by rezky_nightky.
|
||||
|
||||
17 February 2026: Wouter
|
||||
- Fix to remove unused conditional from cookie timestamp at
|
||||
worker env.
|
||||
- For #1405: local-zone always_refuse also blocks queries of type DS.
|
||||
|
||||
16 February 2026: Yorgos
|
||||
- Fix #1404: Priming the root key fails after loading ipfire.org RPZ
|
||||
zones. Fixed by including the ZONEMD RRtype in the list of types to
|
||||
ignore for RPZ zones. Analysis and patch provided by ummeegge.
|
||||
|
||||
16 February 2026: Wouter
|
||||
- Fix that cachedb aggressive negative responses have the RA flag set.
|
||||
|
||||
11 February 2026: Wouter
|
||||
- Fix #1403: Inconsistency between do-nat64 and do-not-query-address
|
||||
during retries.
|
||||
|
||||
9 February 2026: Wouter
|
||||
- Merge #1401: Add a new build-time option for system TLS.
|
||||
The --enable-system-tls flag enables the
|
||||
tls-use-system-policy-versions setting by default.
|
||||
- Update generated man pages.
|
||||
|
||||
6 February 2026: Yorgos
|
||||
- Fix #1389: [FR] replacement with ECC-GOST12 according to RFC9558.
|
||||
Patch contributed by Igor V. Ruzanov, available in
|
||||
contrib/gost12.patch.
|
||||
|
||||
4 February 2026: Wouter
|
||||
- Fix local privilege escalation on Windows. Thanks to Hao Huang and
|
||||
CrisprXiang with Fudan University for the report. The OpenSSL
|
||||
init calls are set to not load the openssl.cnf file when compiled
|
||||
for Windows.
|
||||
|
||||
3 February 2026: Yorgos
|
||||
- Eagerly remove .skip mark files in between mini_tdir.sh runs in case
|
||||
there has been a change on the environment.
|
||||
|
||||
27 January 2026: Wouter
|
||||
- Add test for allow-notify with a host name.
|
||||
|
||||
26 January 2026: Wouter
|
||||
- Fix that allow-notify entries with hostnames are copied after IPv4
|
||||
and IPv6 lookup.
|
||||
- Fix to not skip allow-notify hostname lookups when there are only
|
||||
urls.
|
||||
|
||||
23 January 2026: Yorgos
|
||||
- Merge #1396: Log Linux thread ID.
|
||||
- On Linux systems log the system-wide unique thread ID instead of
|
||||
Unbound's internal thread counter.
|
||||
- Introduce the 'log-thread-id' configuration option to manage logging
|
||||
the system-wide Linux thread ID for easier debugging with system
|
||||
tools.
|
||||
- Update generated man pages.
|
||||
|
||||
22 January 2026: Wouter
|
||||
- Fix that fast reload copies the iter_scrub_ns, iter_scrub_cname
|
||||
and max_global_quota options.
|
||||
- Fix http test tool petal to not print errors when there is no
|
||||
error.
|
||||
|
||||
21 January 2026: Wouter
|
||||
- Merge #1388: QNX Porting support for unbound.
|
||||
|
||||
19 January 2026: Wouter
|
||||
- Merge #1392: Include "V" (version) option in synopsis.
|
||||
|
||||
15 January 2026: Wouter
|
||||
- Fix documentation for requestlist.overwritten and
|
||||
requestlist.exceeded, it explains which query was dropped.
|
||||
|
||||
8 January 2026: Wouter
|
||||
- Merge #1381: Do not initialize quic_table unless it is enabled.
|
||||
|
||||
6 January 2026: Wouter
|
||||
- Fix edns subnet, that scope zero queries, when there is a
|
||||
subquery without subnet, and the forward-no-cache or
|
||||
stub-no-cache option is set, it is not stored in cache due to
|
||||
the forward or stub option.
|
||||
|
||||
6 January 2026: Yorgos
|
||||
- Merge #1391 from Götz Görisch: Fix documentation to adhere to
|
||||
RFC5952.
|
||||
|
||||
31 December 2025: Yorgos
|
||||
- Update the unbound-anchor man page to note write permissions of the
|
||||
generated file if it is to be used with Unbound's
|
||||
auto-trust-anchor-file option.
|
||||
- Use the same EDE removal logic when encoding errors as when encoding
|
||||
replies.
|
||||
|
||||
30 December 2025: Yorgos
|
||||
- Mark "THROWAWAY" and "(DNSSEC) LAME" responses clearly as Unbound's
|
||||
categorization in the log output.
|
||||
|
||||
24 December 2025: Yorgos
|
||||
- More specific wording in the unbound.conf man page for stub-first
|
||||
and forward-first options.
|
||||
|
||||
3 December 2025: Wouter
|
||||
- Fix http2 drop handling to clear the postpone_drop state so that
|
||||
other streams on the http2 session are not affected by a drop,
|
||||
and can clean up properly if also dropped. Fix http2 send reply
|
||||
so that when there is a send failure is does not recurse into
|
||||
the mesh functions and also does not drop the connection due to
|
||||
the condition of one stream.
|
||||
|
||||
2 December 2025: Wouter
|
||||
- Fix to remove http2 stream mesh state when mesh new request is
|
||||
dropping the new request.
|
||||
|
||||
1 December 2025: Wouter
|
||||
- Fix to add EDNS CO flag to testbound and debug message log.
|
||||
- Fix header comment about EDE reference in validator/val_sigcrypt.h.
|
||||
|
||||
28 November 2025: Yorgos
|
||||
- For #1375, there is no DNSTAP environment if it wasn't configured.
|
||||
|
||||
26 November 2025: Yorgos
|
||||
- Tag for 1.24.2 release.
|
||||
The repository continues with version 1.24.3.
|
||||
|
||||
13 November 2025: Wouter
|
||||
- Merge #1374: Mesh reply counters.
|
||||
This adds the statistics num.queries.replyaddr_limit and
|
||||
requestlist.current.replies.
|
||||
- Merge #1375: Copy DNSTAP changes from daemon to workers after
|
||||
fast_reload.
|
||||
|
||||
12 November 2025: Wouter
|
||||
- Fix that when discard timeout drops packet, they are accounted as
|
||||
less reply addresses in use in the mesh area.
|
||||
- iana portlist updated.
|
||||
|
||||
6 November 2025: Wouter
|
||||
- Fix add comment to worker_handle_request function that explain it.
|
||||
- Fix configure test for noreturn attribute so it compiles without
|
||||
warning.
|
||||
- Fix configure test for nonstring attribute so that it does not
|
||||
accept when the compiler prints a warning about an unknown
|
||||
attribute.
|
||||
|
||||
4 November 2025: Wouter
|
||||
- Fix dns64 log output to log the default instead of a null string.
|
||||
|
||||
1 November 2025: Yorgos
|
||||
- Fix #1366: Infra cache does not work correctly for NAT64, by
|
||||
moving the NAT64 synthesis from the iterator when selecting a target
|
||||
address, to the delegation point itself when adding target
|
||||
addresses.
|
||||
|
||||
27 October 2025: Yorgos
|
||||
- Merge #1331 from Jitka Plesníková: Replace deprecated $function by
|
||||
new $action, for SWIG.
|
||||
- Fix #1165, document the possible circular dependency when using
|
||||
host names instead of IP addresses for name servers in stub/forward
|
||||
zones and log a warning when spotted in the configuration.
|
||||
|
||||
24 October 2025: Yorgos
|
||||
- unbound.conf man page updates to include a preview of the section
|
||||
clauses and some reformatting around the use of "clause", "option"
|
||||
and "attributes". Based on Havard Eidnes' suggestions on the
|
||||
mailing list.
|
||||
- Fix unused attribute warning in redis.c when threads are not
|
||||
supported.
|
||||
- For #1364, use OPENSSL_VERSION_TEXT instead of OPENSSL_VERSION_NUMBER
|
||||
for part of the configure script. OPENSSL_VERSION_TEXT is more
|
||||
consistent across versions.
|
||||
|
||||
22 October 2025: Yorgos
|
||||
- Tag for 1.24.1 release.
|
||||
The repository continues with version 1.24.2.
|
||||
|
||||
15 October 2025: Wouter
|
||||
- Fix to drop UDP for discard-timeout, but not stream connections.
|
||||
- Fix to reply with SERVFAIL when the wait-limit is exceeded.
|
||||
- Add extended dns error code for invalid query type to definition
|
||||
list.
|
||||
- Fix unbound.conf man page entry for root-hints to say it can
|
||||
be used without strongly recommending it.
|
||||
- Remove iPhone armv7s, and iPhoneSimulator i386 from ios ci.
|
||||
The lib system does not provide symbols for it on the new macos
|
||||
runner.
|
||||
- Fix to exclude libssp for windows compiles.
|
||||
|
||||
10 October 2025: Wouter
|
||||
- Fix #1358 Enabling FIPS in OpenSSL causes unit test to fail.
|
||||
|
||||
3 October 2025: Yorgos
|
||||
- Note 'respip' and 'dns64' module order in the unbound.conf
|
||||
man page.
|
||||
- Note clearly that 'wait-limit: 0' disables all wait limits.
|
||||
- 'wait-limit-cookie: 0' can now disable cookie validated wait
|
||||
limits.
|
||||
|
||||
2 October 2025: Wouter
|
||||
- Fix that https is set up as enabled when the port is listed in
|
||||
interface-automatic-ports. Also for the set up of quic it is
|
||||
enabled when listed there.
|
||||
|
||||
30 September 2025: Wouter
|
||||
- Fix for #1344: Fix that respip and dns64 can be enabled at the
|
||||
same time, the client info is copied for attach_sub and add_sub
|
||||
|
||||
+3
-3
@@ -13,7 +13,7 @@ If you're not using DNSSEC then you may remove "validator".
|
||||
|
||||
2. The "dns64-prefix" directive indicates your DNS64 prefix. For example:
|
||||
|
||||
dns64-prefix: 64:FF9B::/96
|
||||
dns64-prefix: 64:ff9b::/96
|
||||
|
||||
The prefix must be a /96 or shorter.
|
||||
|
||||
@@ -42,9 +42,9 @@ To enable NAT64 in Unbound, add to unbound.conf's "server" section:
|
||||
do-nat64: yes
|
||||
|
||||
The NAT64 prefix defaults to the DNS64 prefix, which in turn defaults to the
|
||||
standard 64:FF9B::/96 prefix. You can reconfigure it with:
|
||||
standard 64:ff9b::/96 prefix. You can reconfigure it with:
|
||||
|
||||
nat64-prefix: 64:FF9B::/96
|
||||
nat64-prefix: 64:ff9b::/96
|
||||
|
||||
To test NAT64 operation, pick a domain that only has IPv4 reachability for its
|
||||
nameservers and try resolving any names in that domain.
|
||||
|
||||
+45
-19
@@ -54,7 +54,7 @@ server:
|
||||
# interface: 192.0.2.153
|
||||
# interface: 192.0.2.154
|
||||
# interface: 192.0.2.154@5003
|
||||
# interface: 2001:DB8::5
|
||||
# interface: 2001:db8::5
|
||||
# interface: eth0@5003
|
||||
|
||||
# enable this feature to copy the source address of queries to reply.
|
||||
@@ -72,12 +72,12 @@ server:
|
||||
# server from by ip-address. If none, the default (all) interface
|
||||
# is used. Specify every interface on a 'outgoing-interface:' line.
|
||||
# outgoing-interface: 192.0.2.153
|
||||
# outgoing-interface: 2001:DB8::5
|
||||
# outgoing-interface: 2001:DB8::6
|
||||
# outgoing-interface: 2001:db8::5
|
||||
# outgoing-interface: 2001:db8::6
|
||||
|
||||
# Specify a netblock to use remainder 64 bits as random bits for
|
||||
# upstream queries. Uses freebind option (Linux).
|
||||
# outgoing-interface: 2001:DB8::/64
|
||||
# outgoing-interface: 2001:db8::/64
|
||||
# Also (Linux:) ip -6 addr add 2001:db8::/64 dev lo
|
||||
# And: ip -6 route add local 2001:db8::/64 dev lo
|
||||
# And set prefer-ip6: yes to use the ip6 randomness from a netblock.
|
||||
@@ -193,9 +193,16 @@ server:
|
||||
# Limit on number of CNAME, DNAME records for incoming packets.
|
||||
# iter-scrub-cname: 11
|
||||
|
||||
# Limit on number of RRSIGs for an RRset for incoming packets.
|
||||
# iter-scrub-rrsig: 8
|
||||
|
||||
# Limit on upstream queries for an incoming query and its recursion.
|
||||
# max-global-quota: 200
|
||||
|
||||
# Should the scrubber remove promiscuous NS from positive answers,
|
||||
# protects against poison attempts.
|
||||
# iter-scrub-promiscuous: yes
|
||||
|
||||
# msec for waiting for an unknown server to reply. Increase if you
|
||||
# are behind a slow satellite link, to eg. 1128.
|
||||
# unknown-server-time-limit: 376
|
||||
@@ -375,7 +382,7 @@ server:
|
||||
# interface-action: 192.0.2.153 allow
|
||||
# interface-action: 192.0.2.154 allow
|
||||
# interface-action: 192.0.2.154@5003 allow
|
||||
# interface-action: 2001:DB8::5 allow
|
||||
# interface-action: 2001:db8::5 allow
|
||||
# interface-action: eth0@5003 allow
|
||||
|
||||
# Similar to 'access-control-tag:' but for interfaces.
|
||||
@@ -492,6 +499,10 @@ server:
|
||||
# print log lines that say why queries return SERVFAIL to clients.
|
||||
# log-servfail: no
|
||||
|
||||
# log system-wide Linux thread ID, insted of Unbound's internal thread
|
||||
# counter. Only on Linux and only when threads are available.
|
||||
# log-thread-id: no
|
||||
|
||||
# the pid file. Can be an absolute path outside of chroot/work dir.
|
||||
# pidfile: "@UNBOUND_PIDFILE@"
|
||||
|
||||
@@ -654,7 +665,7 @@ server:
|
||||
# or, just before the iterator).
|
||||
# module-config: "validator iterator"
|
||||
|
||||
# File with trusted keys, kept uptodate using RFC5011 probes,
|
||||
# File with trusted keys, kept up-to-date using RFC5011 probes,
|
||||
# initial file like trust-anchor-file, then it stores metadata.
|
||||
# Use several entries, one per domain name, to track multiple zones.
|
||||
#
|
||||
@@ -714,7 +725,7 @@ server:
|
||||
# val-max-restart: 5
|
||||
|
||||
# Should additional section of secure message also be kept clean of
|
||||
# unsecure data. Useful to shield the users of this validator from
|
||||
# non-secure data. Useful to shield the users of this validator from
|
||||
# potential bogus data in the additional section. All unsigned data
|
||||
# in the additional section is removed from secure messages.
|
||||
# val-clean-additional: yes
|
||||
@@ -922,6 +933,22 @@ server:
|
||||
# add a netblock specific override to a localzone, with zone type
|
||||
# local-zone-override: "example.com" 192.0.2.0/24 refuse
|
||||
|
||||
# Action to apply when the IP address in an AAAA or A RR in the answer
|
||||
# section of a response matches the specified IP netblock.
|
||||
# Requires use of the respip module.
|
||||
# response-ip: 192.0.2.0/24 redirect
|
||||
|
||||
# Redirect as specified by the "resource record string" when the IP
|
||||
# address in an AAAA or A RR in the answer section of a response
|
||||
# matches the specified IP netblock.
|
||||
# Requires use of the respip module.
|
||||
# response-ip-data: 192.0.2.0/24 "example. A 192.0.2.1"
|
||||
|
||||
# Apply tag(s) when the IP address in an AAAA or A RR in the answer
|
||||
# section of a response matches the specified IP netblock.
|
||||
# Requires use of the respip module.
|
||||
# response-ip-tag: 192.0.2.0/24 "tag1 tag2"
|
||||
|
||||
# service clients over TLS (on the TCP sockets) with plain DNS inside
|
||||
# the TLS stream, and over HTTPS using HTTP/2 as specified in RFC8484.
|
||||
# Give the certificate to use and private key.
|
||||
@@ -941,16 +968,12 @@ server:
|
||||
# tls-ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"
|
||||
|
||||
# Use the SNI extension for TLS connections. Default is yes.
|
||||
# Changing the value requires a reload.
|
||||
# Changing the value requires a restart.
|
||||
# tls-use-sni: yes
|
||||
|
||||
# Allow general-purpose version-flexible TLS server configuration that
|
||||
# may be further restricted by the system's policy.
|
||||
# Use only if you want to support legacy TLS client connections.
|
||||
# Default is no and Unbound will only use the latest available TLS
|
||||
# version.
|
||||
# Changing the value requires a reload.
|
||||
# tls-use-system-policy-versions: no
|
||||
# TLS protocols.
|
||||
# Changing the value requires a restart.
|
||||
# tls-protocols: "TLSv1.2 TLSv1.3"
|
||||
|
||||
# Add the secret file for TLS Session Ticket.
|
||||
# Secret file must be 80 bytes of random data.
|
||||
@@ -1266,10 +1289,11 @@ remote-control:
|
||||
# zonefile: "example.org.zone"
|
||||
|
||||
# Views
|
||||
# Create named views. Name must be unique. Map views to requests using
|
||||
# the access-control-view option. Views can contain zero or more local-zone
|
||||
# and local-data options. Options from matching views will override global
|
||||
# options. Global options will be used if no matching view is found.
|
||||
# Create named views. Name must be unique.
|
||||
# Map views to requests using the access-control-view/interface-view options.
|
||||
# Views can contain zero or more local-zone and local-data options.
|
||||
# Options from matching views will override global options.
|
||||
# Global options will be used if no matching view is found.
|
||||
# With view-first yes, it will try to answer using the global local-zone and
|
||||
# local-data elements if there is no view specific match.
|
||||
# view:
|
||||
@@ -1277,6 +1301,8 @@ remote-control:
|
||||
# local-zone: "example.com" redirect
|
||||
# local-data: "example.com A 192.0.2.3"
|
||||
# local-data-ptr: "192.0.2.3 www.example.com"
|
||||
# response-ip: 192.0.2.0/24 redirect
|
||||
# response-ip-data: 192.0.2.0/24 "example. A 192.0.2.1"
|
||||
# view-first: no
|
||||
# view:
|
||||
# name: "anotherview"
|
||||
|
||||
+1
-1
@@ -416,6 +416,6 @@ on a function return with file read failure.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2025, NLnet Labs
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
+13
-4
@@ -39,9 +39,17 @@ unbound-anchor \- Unbound @version@ anchor utility.
|
||||
validation.
|
||||
The program fetches the trust anchor with the method from \fI\%RFC 7958\fP when
|
||||
regular \fI\%RFC 5011\fP update fails to bring it up to date.
|
||||
It can be run (as root) from the commandline, or run as part of startup
|
||||
scripts.
|
||||
Before you start the \fI\%unbound(8)\fP DNS server.
|
||||
It can be run from the commandline, or run as part of startup scripts before
|
||||
you start the \fI\%unbound(8)\fP DNS server.
|
||||
.sp
|
||||
Note that if you want to use \fI\%RFC 5011\fP with Unbound (i.e., the
|
||||
\fI\%auto\-trust\-anchor\-file\fP option) so
|
||||
that trust anchor information is automatically tracked by Unbound during
|
||||
operation, the user that Unbound runs under (by default \(aqunbound\(aq) must have
|
||||
write permissions to the file and the directory the file lives in (for creating
|
||||
temporary files).
|
||||
In this case you would probably want to run this program as the designated
|
||||
Unbound user.
|
||||
.sp
|
||||
Suggested usage:
|
||||
.INDENT 0.0
|
||||
@@ -52,6 +60,7 @@ Suggested usage:
|
||||
# in the init scripts.
|
||||
# provide or update the root anchor (if necessary)
|
||||
unbound\-anchor \-a \(dq@UNBOUND_ROOTKEY_FILE@\(dq
|
||||
|
||||
# Please note usage of this root anchor is at your own risk
|
||||
# and under the terms of our LICENSE (see source).
|
||||
#
|
||||
@@ -295,6 +304,6 @@ Signature on the root key information.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2025, NLnet Labs
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
+12
-3
@@ -51,9 +51,17 @@ Description
|
||||
validation.
|
||||
The program fetches the trust anchor with the method from :rfc:`7958` when
|
||||
regular :rfc:`5011` update fails to bring it up to date.
|
||||
It can be run (as root) from the commandline, or run as part of startup
|
||||
scripts.
|
||||
Before you start the :doc:`unbound(8)</manpages/unbound>` DNS server.
|
||||
It can be run from the commandline, or run as part of startup scripts before
|
||||
you start the :doc:`unbound(8)</manpages/unbound>` DNS server.
|
||||
|
||||
Note that if you want to use :rfc:`5011` with Unbound (i.e., the
|
||||
:ref:`auto-trust-anchor-file<unbound.conf.auto-trust-anchor-file>` option) so
|
||||
that trust anchor information is automatically tracked by Unbound during
|
||||
operation, the user that Unbound runs under (by default 'unbound') must have
|
||||
write permissions to the file and the directory the file lives in (for creating
|
||||
temporary files).
|
||||
In this case you would probably want to run this program as the designated
|
||||
Unbound user.
|
||||
|
||||
Suggested usage:
|
||||
|
||||
@@ -62,6 +70,7 @@ Suggested usage:
|
||||
# in the init scripts.
|
||||
# provide or update the root anchor (if necessary)
|
||||
unbound-anchor -a "@UNBOUND_ROOTKEY_FILE@"
|
||||
|
||||
# Please note usage of this root anchor is at your own risk
|
||||
# and under the terms of our LICENSE (see source).
|
||||
#
|
||||
|
||||
@@ -88,6 +88,6 @@ Unbound configuration file.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2025, NLnet Labs
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
@@ -167,6 +167,9 @@ ipset,
|
||||
\fI\%tcp\-reuse\-timeout\fP,
|
||||
\fI\%tcp\-auth\-query\-timeout\fP,
|
||||
\fI\%delay\-close\fP\&.
|
||||
\fI\%iter\-scrub\-promiscuous\fP\&.
|
||||
\fI\%tls\-service\-key\fP\&.
|
||||
\fI\%tls\-service\-pem\fP\&.
|
||||
.sp
|
||||
It does not work with
|
||||
\fI\%interface\fP and
|
||||
@@ -879,6 +882,11 @@ number of queries removed due to discard\-timeout by thread
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B threadX.num.queries_replyaddr_limit
|
||||
number of queries removed due to replyaddr limits by thread
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B threadX.num.queries_wait_limit
|
||||
number of queries removed due to wait\-limit by thread
|
||||
.UNINDENT
|
||||
@@ -972,6 +980,10 @@ Number of requests in the request list that were overwritten by newer
|
||||
entries.
|
||||
This happens if there is a flood of queries that recursive processing and
|
||||
the server has a hard time.
|
||||
The counter is increased when during the flood the
|
||||
\fI\%jostle\-timeout\fP
|
||||
allows a query to be removed in favor of a new incoming query.
|
||||
The older query is then dropped to make space.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -979,6 +991,12 @@ the server has a hard time.
|
||||
Queries that were dropped because the request list was full.
|
||||
This happens if a flood of queries need recursive processing, and the
|
||||
server can not keep up.
|
||||
The counter is increased when during the flood there is no space
|
||||
to be made with the jostle out of an older query, and the new query
|
||||
is dropped.
|
||||
Since no older queries are removed, see
|
||||
\fI\%jostle\-timeout\fP setting, there
|
||||
is no space for the new query.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -993,6 +1011,13 @@ Current size of the request list, only the requests from client queries.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B threadX.requestlist.current.replies
|
||||
Current count of the number of reply entries waiting on request list
|
||||
entries. Because a request list entry can send results to multiple reply
|
||||
addresses, this number may be larger than the size of the request list.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B threadX.recursion.time.avg
|
||||
Average time it took to answer queries that needed recursive processing.
|
||||
Note that queries that were answered from the cache are not in this average.
|
||||
@@ -1047,6 +1072,11 @@ summed over threads.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B total.num.queries_replyaddr_limit
|
||||
summed over threads.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B total.num.queries_wait_limit
|
||||
summed over threads.
|
||||
.UNINDENT
|
||||
@@ -1137,6 +1167,16 @@ summed over threads.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B total.requestlist.current.user
|
||||
summed over threads.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B total.requestlist.current.replies
|
||||
summed over threads.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B total.recursion.time.median
|
||||
averaged over threads.
|
||||
.UNINDENT
|
||||
@@ -1542,6 +1582,6 @@ directory with private keys (\fBunbound_server.key\fP and
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2025, NLnet Labs
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
@@ -169,6 +169,9 @@ There are several commands that the server understands.
|
||||
:ref:`tcp-reuse-timeout<unbound.conf.tcp-reuse-timeout>`,
|
||||
:ref:`tcp-auth-query-timeout<unbound.conf.tcp-auth-query-timeout>`,
|
||||
:ref:`delay-close<unbound.conf.delay-close>`.
|
||||
:ref:`iter-scrub-promiscuous<unbound.conf.iter-scrub-promiscuous>`.
|
||||
:ref:`tls-service-key<unbound.conf.tls-service-key>`.
|
||||
:ref:`tls-service-pem<unbound.conf.tls-service-pem>`.
|
||||
|
||||
It does not work with
|
||||
:ref:`interface<unbound.conf.interface>` and
|
||||
@@ -814,6 +817,10 @@ number of statistic counters:
|
||||
number of queries removed due to discard-timeout by thread
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@threadX.num.queries_replyaddr_limit@@
|
||||
number of queries removed due to replyaddr limits by thread
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@threadX.num.queries_wait_limit@@
|
||||
number of queries removed due to wait-limit by thread
|
||||
|
||||
@@ -892,12 +899,22 @@ number of statistic counters:
|
||||
entries.
|
||||
This happens if there is a flood of queries that recursive processing and
|
||||
the server has a hard time.
|
||||
The counter is increased when during the flood the
|
||||
:ref:`jostle-timeout<unbound.conf.jostle-timeout>`
|
||||
allows a query to be removed in favor of a new incoming query.
|
||||
The older query is then dropped to make space.
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@threadX.requestlist.exceeded@@
|
||||
Queries that were dropped because the request list was full.
|
||||
This happens if a flood of queries need recursive processing, and the
|
||||
server can not keep up.
|
||||
The counter is increased when during the flood there is no space
|
||||
to be made with the jostle out of an older query, and the new query
|
||||
is dropped.
|
||||
Since no older queries are removed, see
|
||||
:ref:`jostle-timeout<unbound.conf.jostle-timeout>` setting, there
|
||||
is no space for the new query.
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@threadX.requestlist.current.all@@
|
||||
@@ -909,6 +926,12 @@ number of statistic counters:
|
||||
Current size of the request list, only the requests from client queries.
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@threadX.requestlist.current.replies@@
|
||||
Current count of the number of reply entries waiting on request list
|
||||
entries. Because a request list entry can send results to multiple reply
|
||||
addresses, this number may be larger than the size of the request list.
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@threadX.recursion.time.avg@@
|
||||
Average time it took to answer queries that needed recursive processing.
|
||||
Note that queries that were answered from the cache are not in this average.
|
||||
@@ -954,6 +977,10 @@ number of statistic counters:
|
||||
summed over threads.
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@total.num.queries_replyaddr_limit@@
|
||||
summed over threads.
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@total.num.queries_wait_limit@@
|
||||
summed over threads.
|
||||
|
||||
@@ -1026,6 +1053,14 @@ number of statistic counters:
|
||||
summed over threads.
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@total.requestlist.current.user@@
|
||||
summed over threads.
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@total.requestlist.current.replies@@
|
||||
summed over threads.
|
||||
|
||||
|
||||
@@UAHL@unbound-control.stats@total.recursion.time.median@@
|
||||
averaged over threads.
|
||||
|
||||
|
||||
@@ -185,6 +185,6 @@ encountered a fatal error.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2025, NLnet Labs
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
+2
-2
@@ -32,7 +32,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
|
||||
unbound \- Unbound DNS validating resolver @version@.
|
||||
.SH SYNOPSIS
|
||||
.sp
|
||||
\fBunbound\fP [\fB\-hdpv\fP] [\fB\-c <cfgfile>\fP]
|
||||
\fBunbound\fP [\fB\-hdpVv\fP] [\fB\-c <cfgfile>\fP]
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
\fBunbound\fP is a caching DNS resolver.
|
||||
@@ -118,6 +118,6 @@ Show the version number and build options, and exit.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2025, NLnet Labs
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
+388
-148
@@ -36,44 +36,49 @@ unbound.conf \- Unbound @version@ configuration file.
|
||||
.SH DESCRIPTION
|
||||
.sp
|
||||
\fBunbound.conf\fP is used to configure \fI\%unbound(8)\fP\&.
|
||||
The file format has attributes and values.
|
||||
Some attributes have attributes inside them.
|
||||
The notation is: \fBattribute: value\fP\&.
|
||||
.sp
|
||||
Comments start with \fB#\fP and last to the end of line.
|
||||
Empty lines are ignored as is whitespace at the beginning of a line.
|
||||
.sp
|
||||
The utility \fI\%unbound\-checkconf(8)\fP can be
|
||||
used to check \fBunbound.conf\fP prior to usage.
|
||||
.SH FILE FORMAT
|
||||
.sp
|
||||
Whitespace is used to separate keywords.
|
||||
Whitespace indentation is insignificant, but is still recommended for visual
|
||||
clarity.
|
||||
Comments start with \fB#\fP and last to the end of line.
|
||||
Empty lines are ignored, as is whitespace at the beginning of a line.
|
||||
.sp
|
||||
Attribute keywords end with a colon (\fB:\fP) and they are either options or
|
||||
section clauses (group options together).
|
||||
.sp
|
||||
The configuration file is logically divided into \fBsections\fP where each section
|
||||
is introduced by a \fI\%section clause\fP\&.
|
||||
.SH EXAMPLE
|
||||
.sp
|
||||
An example config file is shown below.
|
||||
Copy this to \fB/etc/unbound/unbound.conf\fP and start the server with:
|
||||
An example minimal config file is shown below; most settings are the defaults.
|
||||
Copy this to \fB@ub_conf_file@\fP and start the server with:
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
.ft C
|
||||
$ unbound \-c /etc/unbound/unbound.conf
|
||||
$ unbound \-c @ub_conf_file@
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
Most settings are the defaults.
|
||||
Stop the server with:
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
.ft C
|
||||
$ kill \(gacat /etc/unbound/unbound.pid\(ga
|
||||
$ kill \(gacat @UNBOUND_PIDFILE@\(ga
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
Below is a minimal config file.
|
||||
The source distribution contains an extensive \fBexample.conf\fP file with
|
||||
all the options.
|
||||
.INDENT 0.0
|
||||
@@ -83,33 +88,87 @@ all the options.
|
||||
.ft C
|
||||
# unbound.conf(5) config file for unbound(8).
|
||||
server:
|
||||
directory: \(dq/etc/unbound\(dq
|
||||
directory: \(dq@UNBOUND_RUN_DIR@\(dq
|
||||
username: unbound
|
||||
# make sure unbound can access entropy from inside the chroot.
|
||||
# e.g. on linux the use these commands (on BSD, devfs(8) is used):
|
||||
# mount \-\-bind \-n /dev/urandom /etc/unbound/dev/urandom
|
||||
# and mount \-\-bind \-n /dev/log /etc/unbound/dev/log
|
||||
chroot: \(dq/etc/unbound\(dq
|
||||
# logfile: \(dq/etc/unbound/unbound.log\(dq #uncomment to use logfile.
|
||||
pidfile: \(dq/etc/unbound/unbound.pid\(dq
|
||||
# mount \-\-bind \-n /dev/urandom @UNBOUND_RUN_DIR@/dev/urandom
|
||||
# and mount \-\-bind \-n /dev/log @UNBOUND_RUN_DIR@/dev/log
|
||||
chroot: \(dq@UNBOUND_CHROOT_DIR@\(dq
|
||||
# logfile: \(dq@UNBOUND_RUN_DIR@/unbound.log\(dq #uncomment to use logfile.
|
||||
pidfile: \(dq@UNBOUND_PIDFILE@\(dq
|
||||
# verbosity: 1 # uncomment and increase to get more logging.
|
||||
# listen on all interfaces, answer queries from the local subnet.
|
||||
interface: 0.0.0.0
|
||||
interface: ::0
|
||||
access\-control: 10.0.0.0/8 allow
|
||||
access\-control: 2001:DB8::/64 allow
|
||||
access\-control: 2001:db8::/64 allow
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.SH FILE FORMAT
|
||||
.SH SECTION CLAUSES
|
||||
.sp
|
||||
There must be whitespace between keywords.
|
||||
Attribute keywords end with a colon \fB\(aq:\(aq\fP\&.
|
||||
An attribute is followed by a value, or its containing attributes in which case
|
||||
it is referred to as a clause.
|
||||
Clauses can be repeated throughout the file (or included files) to group
|
||||
attributes under the same clause.
|
||||
The recognized section clauses are:
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B \fI\%server:\fP
|
||||
Most of the configuration is found in this section.
|
||||
.TP
|
||||
.B \fI\%remote\-control:\fP
|
||||
Configuration for the facility used by
|
||||
\fI\%unbound\-control(8)\fP\&.
|
||||
.TP
|
||||
.B \fI\%stub\-zone:\fP
|
||||
Configuration for a zone that redirects to specific authoritative name
|
||||
servers, e.g. for zones not generally available on the greater
|
||||
Internet.
|
||||
.TP
|
||||
.B \fI\%forward\-zone:\fP
|
||||
Configuration for a zone that forwards to specific DNS resolvers.
|
||||
.TP
|
||||
.B \fI\%auth\-zone:\fP
|
||||
Configuration for local authoritative zones.
|
||||
.TP
|
||||
.B \fI\%view:\fP
|
||||
Overriding a small subset of configuration for incoming requests.
|
||||
Requests are mapped to views with
|
||||
\fI\%access\-control\-view\fP and
|
||||
\fI\%interface\-view\fP\&.
|
||||
.TP
|
||||
.B \fI\%python:\fP
|
||||
Configuration for the optional \fBpython\fP script module.
|
||||
.TP
|
||||
.B \fI\%dynlib:\fP
|
||||
Configuration for the optional \fBdynlib\fP module that loads dynamic
|
||||
libraries into Unbound.
|
||||
.TP
|
||||
.B \fI\%dnscrypt:\fP
|
||||
Configuration for the optional DNSCrypt feature.
|
||||
.TP
|
||||
.B \fI\%cachedb:\fP
|
||||
Configuration for the optional \fBcachedb\fP module that can interface
|
||||
with second level caches, currently Redis or Redis\-complatible
|
||||
databases.
|
||||
.TP
|
||||
.B \fI\%dnstap:\fP
|
||||
Configuration of the optional dnstap logging feature; a flexible,
|
||||
structured binary log format for DNS software.
|
||||
.TP
|
||||
.B \fI\%rpz:\fP
|
||||
Configuration for Response Policy Zones that allows for DNS filtering.
|
||||
Requires the \fBrespip\fP module.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
Section clauses can be repeated throughout the file (or included files) to
|
||||
logically group options in one visually cohesive group.
|
||||
This may be particularly useful for the \fBserver:\fP clause with its myriad of
|
||||
options.
|
||||
.SH INCLUDING FILES
|
||||
.sp
|
||||
Files can be included using the \fBinclude:\fP directive.
|
||||
It can appear anywhere, it accepts a single file name as argument.
|
||||
@@ -124,11 +183,11 @@ Wildcards can be used to include multiple files, see \fIglob(7)\fP\&.
|
||||
.sp
|
||||
For a more structural include option, the \fBinclude\-toplevel:\fP directive can
|
||||
be used.
|
||||
This closes whatever clause is currently active (if any) and forces the use of
|
||||
clauses in the included files and right after this directive.
|
||||
.SS Server Options
|
||||
This closes whatever section clause is currently active (if any) and forces the
|
||||
use of section clauses in the included files and right after this directive.
|
||||
.SH SERVER OPTIONS
|
||||
.sp
|
||||
These options are part of the \fBserver:\fP clause.
|
||||
These options are part of the \fBserver:\fP section.
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B verbosity: \fI<number>\fP
|
||||
@@ -323,6 +382,10 @@ Default depends on compile options.
|
||||
Larger numbers need extra resources from the operating system.
|
||||
For performance a very large value is best, use libevent to make this
|
||||
possible.
|
||||
Should be higher (preferably double) than the value of
|
||||
\fI\%num\-queries\-per\-thread\fP to
|
||||
account for cases where the request list is full and avoid file descriptor
|
||||
starvation.
|
||||
.sp
|
||||
Default: 4096 (libevent) / 960 (minievent) / 48 (windows)
|
||||
.UNINDENT
|
||||
@@ -539,6 +602,9 @@ Default: 376
|
||||
The wait time in msec where recursion requests are dropped.
|
||||
This is to stop a large number of replies from accumulating.
|
||||
They receive no reply, the work item continues to recurse.
|
||||
For UDP the replies are dropped, for stream connections the reply
|
||||
is not dropped if the stream connection is still open ready to receive
|
||||
answers.
|
||||
It is nice to be a bit larger than
|
||||
\fI\%serve\-expired\-client\-timeout\fP
|
||||
if that is enabled.
|
||||
@@ -554,7 +620,7 @@ The number of replies that can wait for recursion, for an IP address.
|
||||
This makes a ratelimit per IP address of waiting replies for recursion.
|
||||
It stops very large amounts of queries waiting to be returned to one
|
||||
destination.
|
||||
The value \fB0\fP disables wait limits.
|
||||
The value \fB0\fP disables all wait limits.
|
||||
.sp
|
||||
Default: 1000
|
||||
.UNINDENT
|
||||
@@ -563,7 +629,11 @@ Default: 1000
|
||||
.B wait\-limit\-cookie: \fI<number>\fP
|
||||
The number of replies that can wait for recursion, for an IP address
|
||||
that sent the query with a valid DNS Cookie.
|
||||
Since the cookie validates the client address, this limit can be higher.
|
||||
Since the cookie already validates the client address, this option allows
|
||||
to override a configured
|
||||
\fI\%wait\-limit\fP value usually with a higher one
|
||||
for cookie validated queries.
|
||||
The value \fB0\fP disables wait limits for cookie validated queries.
|
||||
.sp
|
||||
Default: 10000
|
||||
.UNINDENT
|
||||
@@ -1069,9 +1139,13 @@ The file must contain the private key for the TLS session, the public
|
||||
certificate is in the \fI\%tls\-service\-pem\fP
|
||||
file and it must also be specified if
|
||||
\fI\%tls\-service\-key\fP is specified.
|
||||
Enabling or disabling this service requires a restart (a reload is not
|
||||
enough), because the key is read while root permissions are held and before
|
||||
chroot (if any).
|
||||
If the key is stored with root permissions or outside of chroot, then
|
||||
a change or enabling or disabling requires a restart (a reload is not
|
||||
enough).
|
||||
But if the key file (and tls\-service\-pem file) are accessible, then they
|
||||
are read in on reload, and fast_reload.
|
||||
The server checks the modification time of the file (and the filename)
|
||||
to see if the file has changed for reload.
|
||||
The ports enabled implicitly or explicitly via
|
||||
\fI\%tls\-port\fP and
|
||||
\fI\%https\-port\fP do not provide normal DNS TCP
|
||||
@@ -1153,8 +1227,8 @@ Default: no
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B tls\-system\-cert: \fI<yes or no>\fP
|
||||
This the same attribute as the
|
||||
\fI\%tls\-win\-cert\fP attribute, under a
|
||||
This the same as the
|
||||
\fI\%tls\-win\-cert\fP option, under a
|
||||
different name.
|
||||
Because it is not windows specific.
|
||||
.UNINDENT
|
||||
@@ -1224,7 +1298,7 @@ Enable or disable sending the SNI extension on TLS connections.
|
||||
\fBNOTE:\fP
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
Changing the value requires a reload.
|
||||
Changing the value requires a restart.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
@@ -1232,30 +1306,19 @@ Default: yes
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B tls\-use\-system\-policy\-versions: \fI<yes or no>\fP
|
||||
Enable or disable general\-puspose version\-flexible TLS server configuration
|
||||
when serving TLS.
|
||||
This will allow the whole list of available TLS versions provided by the
|
||||
crypto library, which may have been further restricted by the system\(aqs
|
||||
crypto policy.
|
||||
.sp
|
||||
By default Unbound only uses the latest available TLS version.
|
||||
.sp
|
||||
\fBCAUTION:\fP
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
Use only if you want to support legacy TLS client connections.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.B tls\-protocols: \fI\(dq<list of protocols>\(dq\fP
|
||||
Specify the allowed TLS protocol versions to use, in no particular order.
|
||||
Possible values are \fBTLSv1.2\fP and \fBTLSv1.3\fP\&.
|
||||
Enclose list of protocols in quotes (\fB\(dq\(dq\fP) and put spaces between them.
|
||||
.sp
|
||||
\fBNOTE:\fP
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
Changing the value requires a reload.
|
||||
Changing the value requires a restart.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
Default: no
|
||||
Default: \(dqTLSv1.2 TLSv1.3\(dq
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -1384,6 +1447,9 @@ The port number on which to provide DNS\-over\-QUIC service.
|
||||
Only interfaces configured with that port number as @number get the QUIC
|
||||
service.
|
||||
The interface uses QUIC for the UDP traffic on that port number.
|
||||
If it is set to 0, the server does not init QUIC code, and QUIC is
|
||||
disabled.
|
||||
This is similar to if QUIC is not in use, but then explicitly.
|
||||
.sp
|
||||
Default: 853
|
||||
.UNINDENT
|
||||
@@ -1607,8 +1673,8 @@ implicit default \(dqaccess\-control: 127.0.0.0/8 allow\(dq option.
|
||||
.INDENT 3.5
|
||||
The interface needs to be already specified with
|
||||
\fI\%interface\fP and that any
|
||||
\fBaccess\-control*:\fP attribute overrides all \fBinterface\-*:\fP
|
||||
attributes for targeted clients.
|
||||
\fBaccess\-control*:\fP option overrides all \fBinterface\-*:\fP
|
||||
options for targeted clients.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
@@ -1623,8 +1689,8 @@ for interfaces.
|
||||
.INDENT 3.5
|
||||
The interface needs to be already specified with
|
||||
\fI\%interface\fP and that any
|
||||
\fBaccess\-control*:\fP attribute overrides all \fBinterface\-*:\fP
|
||||
attributes for targeted clients.
|
||||
\fBaccess\-control*:\fP option overrides all \fBinterface\-*:\fP
|
||||
options for targeted clients.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
@@ -1640,8 +1706,8 @@ but for interfaces.
|
||||
.INDENT 3.5
|
||||
The interface needs to be already specified with
|
||||
\fI\%interface\fP and that any
|
||||
\fBaccess\-control*:\fP attribute overrides all \fBinterface\-*:\fP
|
||||
attributes for targeted clients.
|
||||
\fBaccess\-control*:\fP option overrides all \fBinterface\-*:\fP
|
||||
options for targeted clients.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
@@ -1657,8 +1723,8 @@ for interfaces.
|
||||
.INDENT 3.5
|
||||
The interface needs to be already specified with
|
||||
\fI\%interface\fP and that any
|
||||
\fBaccess\-control*:\fP attribute overrides all \fBinterface\-*:\fP
|
||||
attributes for targeted clients.
|
||||
\fBaccess\-control*:\fP option overrides all \fBinterface\-*:\fP
|
||||
options for targeted clients.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
@@ -1673,8 +1739,8 @@ but for interfaces.
|
||||
.INDENT 3.5
|
||||
The interface needs to be already specified with
|
||||
\fI\%interface\fP and that any
|
||||
\fBaccess\-control*:\fP attribute overrides all \fBinterface\-*:\fP
|
||||
attributes for targeted clients.
|
||||
\fBaccess\-control*:\fP option overrides all \fBinterface\-*:\fP
|
||||
options for targeted clients.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
@@ -1751,7 +1817,7 @@ The logfile is appended to, in the following format:
|
||||
.UNINDENT
|
||||
.sp
|
||||
If this option is given, the \fI\%use\-syslog\fP
|
||||
attribute is internally set to \fBno\fP\&.
|
||||
option is internally set to \fBno\fP\&.
|
||||
.sp
|
||||
The logfile is reopened (for append) when the config file is reread, on
|
||||
SIGHUP.
|
||||
@@ -1861,6 +1927,16 @@ Default: no
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B log\-thread\-id: \fI<yes or no>\fP
|
||||
(Only on Linux and only when threads are available)
|
||||
Logs the system\-wide Linux thread ID instead of Unbound\(aqs internal thread
|
||||
counter.
|
||||
Can be useful when debugging with system tools.
|
||||
.sp
|
||||
Default: no
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B pidfile: \fI<filename>\fP
|
||||
The process id is written to the file.
|
||||
Default is \fB\(dq@UNBOUND_PIDFILE@\(dq\fP\&.
|
||||
@@ -1899,8 +1975,8 @@ Read the root hints from this file.
|
||||
Default is nothing, using builtin hints for the IN class.
|
||||
The file has the format of zone files, with root nameserver names and
|
||||
addresses only.
|
||||
The default may become outdated, when servers change, therefore it is good
|
||||
practice to use a root hints file.
|
||||
The default may become outdated, when servers change, and then it is
|
||||
possible to use a root hints file with specific servers.
|
||||
.sp
|
||||
Default: \(dq\(dq
|
||||
.UNINDENT
|
||||
@@ -2193,6 +2269,11 @@ This protects against so\-called DNS Rebinding, where a user browser is
|
||||
turned into a network proxy, allowing remote access through the browser to
|
||||
other parts of your private network.
|
||||
.sp
|
||||
The option removes resource records of types A, AAAA, SVCB and HTTPS
|
||||
that match the filter.
|
||||
Inside the SVCB and HTTPS records, the svcparams of type ipv4hint
|
||||
and ipv6hint are checked for matches.
|
||||
.sp
|
||||
Some names can be allowed to contain your private addresses, by default all
|
||||
the \fI\%local\-data\fP that you configured is
|
||||
allowed to, and you can specify additional names using
|
||||
@@ -2931,6 +3012,39 @@ local\-data: \(dqexample.com. A 127.0.0.1\(dq
|
||||
queries for \fBwww.example.com\fP and \fBwww.foo.example.com\fP are
|
||||
redirected, so that users with web browsers cannot access sites with
|
||||
suffix example.com.
|
||||
.sp
|
||||
A \fBCNAME\fP record can also be provided via local\-data:
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
.sp
|
||||
.nf
|
||||
.ft C
|
||||
local\-zone: \(dqexample.com.\(dq redirect
|
||||
local\-data: \(dqexample.com. CNAME www.example.org.\(dq
|
||||
.ft P
|
||||
.fi
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
In that case, the \fBCNAME\fP is resolved and the answer
|
||||
includes resolved target records as well.
|
||||
The \fBCNAME\fP record has to be with the zone name of the local\-zone,
|
||||
and there can be one CNAME, not more.
|
||||
The \fBCNAME\fP record has to be at the zone apex of the
|
||||
\fBredirect\fP zone, then it is used for redirection.
|
||||
The resolution proceeds with upstream DNS resolution, and
|
||||
that does not include the lookup in local zones.
|
||||
So the record is not able to point in local zones, but it
|
||||
can point to upstream DNS answers.
|
||||
.sp
|
||||
\fBCNAME\fP resolution is supported only in type \fBredirect\fP
|
||||
local\-zone, and in type \fBinform_redirect\fP local\-zone.
|
||||
.sp
|
||||
As different from \fBCNAME\fP records that are used elsewhere, in
|
||||
the \fBredirect\fP type local\-zone, it is supported that in the target
|
||||
of the record a wildcard label gets expanded to the query name, with
|
||||
for example: \fBexample.com. CNAME *.foo.net.\fP gets expanded
|
||||
to \fBwww.example.com. CNAME www.example.com.foo.net.\fP\&.
|
||||
.UNINDENT
|
||||
.INDENT 7.0
|
||||
.TP
|
||||
@@ -2989,6 +3103,9 @@ use IPv6 protocol and avoid any queries to IPv4.
|
||||
.B always_refuse
|
||||
Like \fI\%refuse\fP, but ignores
|
||||
local data and refuses the query.
|
||||
This type also blocks queries of type DS for the zone name.
|
||||
That can break the DNSSEC chain of trust, but it is refused anyway.
|
||||
The block for type DS assists in more completely blocking the zone.
|
||||
.UNINDENT
|
||||
.INDENT 7.0
|
||||
.TP
|
||||
@@ -3311,7 +3428,7 @@ zone section below.
|
||||
Configure local data shorthand for a PTR record with the reversed IPv4 or
|
||||
IPv6 address and the host name.
|
||||
For example \fB\(dq192.0.2.4 www.example.com\(dq\fP\&.
|
||||
TTL can be inserted like this: \fB\(dq2001:DB8::4 7200 www.example.com\(dq\fP
|
||||
TTL can be inserted like this: \fB\(dq2001:db8::4 7200 www.example.com\(dq\fP
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -3368,7 +3485,7 @@ This specifies the action data for
|
||||
\fI\%response\-ip\fP with action being to redirect
|
||||
as specified by \fI<\(dqresource record string\(dq>\fP\&.
|
||||
\fI<\(dqResource record string\(dq>\fP is similar to that of
|
||||
\fI\%access\-control\-tag\-action\fP,
|
||||
\fI\%access\-control\-tag\-data\fP,
|
||||
but it must be of either AAAA, A or CNAME types.
|
||||
If the \fI<IP\-netblock>\fP is an IPv6/IPv4 prefix, the record must be AAAA/A
|
||||
respectively, unless it is a CNAME (which can be used for both versions of
|
||||
@@ -3652,6 +3769,10 @@ Default: 32
|
||||
Hard limit on the number of times Unbound is allowed to restart a query
|
||||
upon encountering a CNAME record.
|
||||
Results in SERVFAIL when reached.
|
||||
This applies to chained CNAME records but not sporadic CNAME records that
|
||||
could be encountered in the lifetime of the query\(aqs resolution effort.
|
||||
When a CNAME chain concludes, the counter keeping track of this limit is
|
||||
reset.
|
||||
Changing this value needs caution as it can allow long CNAME chains to be
|
||||
accepted, where Unbound needs to verify (resolve) each link individually.
|
||||
.sp
|
||||
@@ -3679,6 +3800,16 @@ Default: 11
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B iter\-scrub\-rrsig: \fI<number>\fP
|
||||
Limit on the number of RRSIGs allowed for an RRset, from the iterator
|
||||
scrubber.
|
||||
This protects against an overly large number of RRSIGs.
|
||||
Clips off the remainder of the RRSIG list at that point.
|
||||
.sp
|
||||
Default: 8
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B max\-global\-quota: \fI<number>\fP
|
||||
Limit on the number of upstream queries sent out for an incoming query and
|
||||
its subqueries from recursion.
|
||||
@@ -3689,6 +3820,15 @@ Default: 200
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B iter\-scrub\-promiscuous: \fI<yes or no>\fP
|
||||
Should the iterator scrubber remove promiscuous NS from positive answers.
|
||||
This protects against poisonous contents, that could affect names in the
|
||||
same zone as a spoofed packet.
|
||||
.sp
|
||||
Default: yes
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B fast\-server\-permil: \fI<number>\fP
|
||||
Specify how many times out of 1000 to pick from the set of fastest servers.
|
||||
0 turns the feature off.
|
||||
@@ -3829,17 +3969,18 @@ enabled to increase privacy on the outgoing reports.
|
||||
.sp
|
||||
Default: no
|
||||
.UNINDENT
|
||||
.SS Remote Control Options
|
||||
.SH REMOTE CONTROL OPTIONS
|
||||
.sp
|
||||
These options are part of the \fBremote\-control:\fP section and are the
|
||||
declarations for the remote control facility.
|
||||
.sp
|
||||
In the \fBremote\-control:\fP clause are the declarations for the remote control
|
||||
facility.
|
||||
If this is enabled, the \fI\%unbound\-control(8)\fP
|
||||
utility can be used to send commands to the running Unbound server.
|
||||
The server uses these clauses to setup TLSv1 security for the connection.
|
||||
The \fI\%unbound\-control(8)\fP utility also reads the
|
||||
\fBremote\-control:\fP section for options.
|
||||
The server uses these options to setup TLS security for the connection.
|
||||
The \fI\%unbound\-control(8)\fP utility also reads
|
||||
this \fBremote\-control:\fP section for options.
|
||||
To setup the correct self\-signed certificates use the
|
||||
\fIunbound\-control\-setup(8)\fP utility.
|
||||
\fBunbound\-control\-setup(8)\fP utility.
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B control\-enable: \fI<yes or no>\fP
|
||||
@@ -3850,7 +3991,7 @@ Default: no
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B control\-interface: \fI<IP address or interface name or path>\fP
|
||||
.B control\-interface: \fI<IP address or interface name[@port] or path>\fP
|
||||
Give IPv4 or IPv6 addresses or local socket path to listen on for control
|
||||
commands.
|
||||
If an interface name is used instead of an IP address, the list of IP
|
||||
@@ -3939,9 +4080,11 @@ This file is used by \fI\%unbound\-control(8)\fP\&.
|
||||
.sp
|
||||
Default: unbound_control.pem
|
||||
.UNINDENT
|
||||
.SS Stub Zone Options
|
||||
.SH STUB ZONE OPTIONS
|
||||
.sp
|
||||
There may be multiple \fBstub\-zone:\fP clauses.
|
||||
These options are part of the \fBstub\-zone:\fP section.
|
||||
.sp
|
||||
There may be multiple \fBstub\-zone:\fP sections.
|
||||
Each with a \fI\%name\fP and zero or more hostnames or
|
||||
IP addresses.
|
||||
For the stub zone this list of nameservers is used.
|
||||
@@ -3980,9 +4123,10 @@ Consider adding \fI\%server\fP statements for
|
||||
\fI\%domain\-insecure\fP and for
|
||||
\fI\%local\-zone: <name> nodefault\fP
|
||||
for the zone if it is a locally served zone.
|
||||
The insecure clause stops DNSSEC from invalidating the zone.
|
||||
The \fI\%domain\-insecure\fP option stops DNSSEC
|
||||
from invalidating the zone.
|
||||
The \fI\%local\-zone: nodefault\fP (or
|
||||
\fI\%transparent\fP) clause makes the
|
||||
\fI\%transparent\fP) option makes the
|
||||
(reverse\-) zone bypass Unbound\(aqs filtering of \fI\%RFC 1918\fP zones.
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -3996,6 +4140,23 @@ This is the full domain name of the zone.
|
||||
Name of stub zone nameserver.
|
||||
Is itself resolved before it is used.
|
||||
.sp
|
||||
\fBCAUTION:\fP
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
If the domain (or a subdomain) from this zone is used as the host, it
|
||||
will unavoidably introduce a circular dependency on retrieving the IP
|
||||
addresses of the name server.
|
||||
In that case, it is suggested to use
|
||||
\fI\%stub\-addr\fP instead.
|
||||
Alternatively,
|
||||
\fI\%stub\-first: yes\fP can also work
|
||||
around the circular dependency by trying resolution outside of this
|
||||
zone.
|
||||
However this has the caveat that it would allow escaping this zone when
|
||||
any resolution attempt fails within this zone.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
To use a non\-default port for DNS communication append \fB\(aq@\(aq\fP with the
|
||||
port number.
|
||||
.sp
|
||||
@@ -4036,9 +4197,12 @@ Default: no
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B stub\-first: \fI<yes or no>\fP
|
||||
If enabled, a query is attempted without the stub clause if it fails.
|
||||
If enabled, a query is attempted without this stub section if it fails.
|
||||
The data could not be retrieved and would have caused SERVFAIL because the
|
||||
servers are unreachable, instead it is tried without this clause.
|
||||
servers are unreachable, instead it is tried without this stub section.
|
||||
This can lead to using less specific configured forward/stub/auth zones if
|
||||
any, or end up to otherwise normal recursive resolution for that particular
|
||||
query.
|
||||
.sp
|
||||
Default: no
|
||||
.UNINDENT
|
||||
@@ -4071,9 +4235,11 @@ This is useful when you want immediate changes to be visible.
|
||||
.sp
|
||||
Default: no
|
||||
.UNINDENT
|
||||
.SS Forward Zone Options
|
||||
.SH FORWARD ZONE OPTIONS
|
||||
.sp
|
||||
There may be multiple \fBforward\-zone:\fP clauses.
|
||||
These options are part of the \fBforward\-zone:\fP section.
|
||||
.sp
|
||||
There may be multiple \fBforward\-zone:\fP sections.
|
||||
Each with a \fI\%name\fP and zero or more hostnames
|
||||
or IP addresses.
|
||||
For the forward zone this list of nameservers is used to forward the queries
|
||||
@@ -4104,6 +4270,23 @@ This is the full domain name of the zone.
|
||||
Name of server to forward to.
|
||||
Is itself resolved before it is used.
|
||||
.sp
|
||||
\fBCAUTION:\fP
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
If the domain (or a subdomain) from this zone is used as the host, it
|
||||
will unavoidably introduce a circular dependency on retrieving the IP
|
||||
addresses of the name server.
|
||||
In that case, it is suggested to use
|
||||
\fI\%forward\-addr\fP instead.
|
||||
Alternatively,
|
||||
\fI\%forward\-first: yes\fP can also
|
||||
work around the circular dependency by trying resolution outside of
|
||||
this zone.
|
||||
However this has the caveat that it would allow escaping this zone when
|
||||
any resolution attempt fails within this zone.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
To use a non\-default port for DNS communication append \fB\(aq@\(aq\fP with the
|
||||
port number.
|
||||
.sp
|
||||
@@ -4140,9 +4323,11 @@ The cert must also match a CA from the
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B forward\-first: \fI<yes or no>\fP
|
||||
If a forwarded query is met with a SERVFAIL error, and this option is
|
||||
enabled, Unbound will fall back to normal recursive resolution for this
|
||||
query as if no query forwarding had been specified.
|
||||
If a forwarded query is met with a SERVFAIL error and this option is
|
||||
enabled Unbound will fall back to less specific resolution.
|
||||
This can lead to using less specific configured forward/stub/auth zones if
|
||||
any, or end up to otherwise normal recursive resolution for that particular
|
||||
query.
|
||||
.sp
|
||||
Default: no
|
||||
.UNINDENT
|
||||
@@ -4180,12 +4365,14 @@ This is useful when you want immediate changes to be visible.
|
||||
.sp
|
||||
Default: no
|
||||
.UNINDENT
|
||||
.SS Authority Zone Options
|
||||
.SH AUTHORITY ZONE OPTIONS
|
||||
.sp
|
||||
These options are part of the \fBauth\-zone:\fP section.
|
||||
.sp
|
||||
Authority zones are configured with \fBauth\-zone:\fP, and each one must have a
|
||||
\fI\%name\fP\&.
|
||||
There can be multiple ones, by listing multiple auth\-zone clauses, each with a
|
||||
different name, pertaining to that part of the namespace.
|
||||
There can be multiple ones, by listing multiple \fBauth\-zone\fP section clauses,
|
||||
each with a different name, pertaining to that part of the namespace.
|
||||
The authority zone with the name closest to the name looked up is used.
|
||||
Authority zones can be processed on two distinct, non\-exclusive, configurable
|
||||
stages.
|
||||
@@ -4216,7 +4403,7 @@ consult the local zone data while resolving.
|
||||
In this case, the aforementioned CNAME example will result in a thoroughly
|
||||
resolved answer.
|
||||
.sp
|
||||
Authority zones can be read from zonefile.
|
||||
Authority zones can be read from a zonefile.
|
||||
And can be kept updated via AXFR and IXFR.
|
||||
After update the zonefile is rewritten.
|
||||
The update mechanism uses the SOA timer values and performs SOA UDP queries to
|
||||
@@ -4253,9 +4440,15 @@ does not support AXFR/IXFR for the zone, but if you used
|
||||
\fI\%url\fP to download the zonefile as a text file
|
||||
from a webserver that would work.
|
||||
.sp
|
||||
If you specify the hostname, you cannot use the domain from the zonefile,
|
||||
because it may not have that when retrieving that data, instead use a plain
|
||||
IP address to avoid a circular dependency on retrieving that IP address.
|
||||
\fBCAUTION:\fP
|
||||
.INDENT 7.0
|
||||
.INDENT 3.5
|
||||
If you specify the hostname, you cannot use the domain from the
|
||||
zonefile, because it may not have that when retrieving that data,
|
||||
instead use a plain IP address to avoid a circular dependency on
|
||||
retrieving that IP address.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -4401,18 +4594,20 @@ If not given then no zonefile is used.
|
||||
If the file does not exist or is empty, Unbound will attempt to fetch zone
|
||||
data (eg. from the primary servers).
|
||||
.UNINDENT
|
||||
.SS View Options
|
||||
.SH VIEW OPTIONS
|
||||
.sp
|
||||
There may be multiple \fBview:\fP clauses.
|
||||
These options are part of the \fBview:\fP section.
|
||||
.sp
|
||||
There may be multiple \fBview:\fP sections.
|
||||
Each with a \fI\%name\fP and zero or more
|
||||
\fI\%local\-zone\fP and
|
||||
\fI\%local\-data\fP attributes.
|
||||
\fI\%local\-data\fP options.
|
||||
Views can also contain \fI\%view\-first\fP,
|
||||
\fI\%response\-ip\fP,
|
||||
\fI\%response\-ip\-data\fP and
|
||||
\fI\%local\-data\-ptr\fP attributes.
|
||||
\fI\%local\-data\-ptr\fP options.
|
||||
View can be mapped to requests by specifying the view name in an
|
||||
\fI\%access\-control\-view\fP attribute.
|
||||
\fI\%access\-control\-view\fP option.
|
||||
Options from matching views will override global options.
|
||||
Global options will be used if no matching view is found, or when the matching
|
||||
view does not have the option specified.
|
||||
@@ -4422,7 +4617,7 @@ view does not have the option specified.
|
||||
Name of the view.
|
||||
Must be unique.
|
||||
This name is used in the
|
||||
\fI\%access\-control\-view\fP attribute.
|
||||
\fI\%access\-control\-view\fP option.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
@@ -4455,6 +4650,22 @@ Has the same behaviour as the global
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B response\-ip: \fI<IP\-netblock> <action>\fP
|
||||
This requires use of the \fBrespip\fP module.
|
||||
.sp
|
||||
Similar to \fI\%response\-ip\fP but
|
||||
only applies to this view.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B response\-ip\-data: \fI<IP\-netblock> <\(dqresource record string\(dq>\fP
|
||||
This requires use of the \fBrespip\fP module.
|
||||
.sp
|
||||
Similar to \fI\%response\-ip\-data\fP but
|
||||
only applies to this view.
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B view\-first: \fI<yes or no>\fP
|
||||
If enabled, it attempts to use the global
|
||||
\fI\%local\-zone\fP and
|
||||
@@ -4463,9 +4674,11 @@ view specific options.
|
||||
.sp
|
||||
Default: no
|
||||
.UNINDENT
|
||||
.SS Python Module Options
|
||||
.SH PYTHON MODULE OPTIONS
|
||||
.sp
|
||||
The \fBpython:\fP clause gives the settings for the \fIpython(1)\fP script module.
|
||||
These options are part of the \fBpython:\fP section.
|
||||
.sp
|
||||
The \fBpython:\fP section gives the settings for the \fIpython(1)\fP script module.
|
||||
This module acts like the iterator and validator modules do, on queries and
|
||||
answers.
|
||||
To enable the script module it has to be compiled into the daemon, and the word
|
||||
@@ -4488,14 +4701,16 @@ The script file to load.
|
||||
Repeat this option for every python module instance added to the
|
||||
\fI\%module\-config\fP option.
|
||||
.UNINDENT
|
||||
.SS Dynamic Library Module Options
|
||||
.SH DYNAMIC LIBRARY MODULE OPTIONS
|
||||
.sp
|
||||
The \fBdynlib:\fP clause gives the settings for the \fBdynlib\fP module.
|
||||
These options are part of the \fBdynlib:\fP section.
|
||||
.sp
|
||||
The \fBdynlib:\fP section gives the settings for the \fBdynlib\fP module.
|
||||
This module is only a very small wrapper that allows dynamic modules to be
|
||||
loaded on runtime instead of being compiled into the application.
|
||||
To enable the dynlib module it has to be compiled into the daemon, and the word
|
||||
\fBdynlib\fP has to be put in the
|
||||
\fI\%module\-config\fP attribute.
|
||||
\fI\%module\-config\fP option.
|
||||
Multiple instances of dynamic libraries are supported by adding the word
|
||||
\fBdynlib\fP more than once.
|
||||
.sp
|
||||
@@ -4510,7 +4725,9 @@ The dynamic library file to load.
|
||||
Repeat this option for every dynlib module instance added to the
|
||||
\fI\%module\-config\fP option.
|
||||
.UNINDENT
|
||||
.SS DNS64 Module Options
|
||||
.SH DNS64 MODULE OPTIONS
|
||||
.sp
|
||||
These options are part of the \fBserver:\fP section.
|
||||
.sp
|
||||
The \fBdns64\fP module must be configured in the
|
||||
\fI\%module\-config\fP directive, e.g.:
|
||||
@@ -4530,7 +4747,11 @@ and be compiled into the daemon to be enabled.
|
||||
\fBNOTE:\fP
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
These settings go in the \fI\%server:\fP section.
|
||||
If combining the \fBrespip\fP and \fBdns64\fP modules, the \fBrespip\fP module
|
||||
needs to appear before the \fBdns64\fP module in the
|
||||
\fI\%module\-config\fP
|
||||
configuration option so that response IP and/or RPZ feeds can properly
|
||||
filter responses regardless of DNS64 synthesis.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.INDENT 0.0
|
||||
@@ -4566,12 +4787,12 @@ Can be entered multiple times, list a new domain for which it applies, one
|
||||
per line.
|
||||
Applies also to names underneath the name given.
|
||||
.UNINDENT
|
||||
.SS NAT64 Operation
|
||||
.SH NAT64 OPTIONS
|
||||
.sp
|
||||
These options are part of the \fBserver:\fP section.
|
||||
.sp
|
||||
NAT64 operation allows using a NAT64 prefix for outbound requests to IPv4\-only
|
||||
servers.
|
||||
It is controlled by two options in the
|
||||
\fI\%server:\fP section:
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B do\-nat64: \fI<yes or no>\fP
|
||||
@@ -4587,11 +4808,24 @@ Default: no
|
||||
Use a specific NAT64 prefix to reach IPv4\-only servers.
|
||||
The prefix length must be one of /32, /40, /48, /56, /64 or /96.
|
||||
.sp
|
||||
The NAT64 prefix is allowed by the
|
||||
\fI\%do\-not\-query\-address\fP option,
|
||||
so that there is a clear outcome of addresses in both; the NAT64 prefix
|
||||
is allowed.
|
||||
The IPv4 address could be filtered by the
|
||||
\fI\%do\-not\-query\-address\fP option,
|
||||
if needed.
|
||||
Allowing the NAT64 prefix is useful when using do\-not\-query\-address
|
||||
for a cluster of machines that is IPv6\-only and uses NAT64, but does
|
||||
not have internet access.
|
||||
.sp
|
||||
Default: 64:ff9b::/96 (same as \fI\%dns64\-prefix\fP)
|
||||
.UNINDENT
|
||||
.SS DNSCrypt Options
|
||||
.SH DNSCRYPT OPTIONS
|
||||
.sp
|
||||
The \fBdnscrypt:\fP clause gives the settings of the dnscrypt channel.
|
||||
These options are part of the \fBdnscrypt:\fP section.
|
||||
.sp
|
||||
The \fBdnscrypt:\fP section gives the settings of the dnscrypt channel.
|
||||
While those options are available, they are only meaningful if Unbound was
|
||||
compiled with \fB\-\-enable\-dnscrypt\fP\&.
|
||||
Currently certificate and secret/public keys cannot be generated by Unbound.
|
||||
@@ -4721,7 +4955,9 @@ If left unconfigured, it will be configured automatically to be a power of
|
||||
.sp
|
||||
Default: (unconfigured)
|
||||
.UNINDENT
|
||||
.SS EDNS Client Subnet Module Options
|
||||
.SH EDNS CLIENT SUBNET MODULE OPTIONS
|
||||
.sp
|
||||
These options are part of the \fBserver:\fP section.
|
||||
.sp
|
||||
The ECS module must be configured in the
|
||||
\fI\%module\-config\fP directive, e.g.:
|
||||
@@ -4738,13 +4974,6 @@ module\-config: \(dqsubnetcache validator iterator\(dq
|
||||
.sp
|
||||
and be compiled into the daemon to be enabled.
|
||||
.sp
|
||||
\fBNOTE:\fP
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
These settings go in the \fI\%server:\fP section.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
If the destination address is allowed in the configuration Unbound will add the
|
||||
EDNS0 option to the query containing the relevant part of the client\(aqs address.
|
||||
When an answer contains the ECS option the response and the option are placed
|
||||
@@ -4866,7 +5095,9 @@ This number applies for each qname/qclass/qtype tuple.
|
||||
.sp
|
||||
Default: 100
|
||||
.UNINDENT
|
||||
.SS Opportunistic IPsec Support Module Options
|
||||
.SH OPPORTUNISTIC IPSEC SUPPORT MODULE OPTIONS
|
||||
.sp
|
||||
These options are part of the \fBserver:\fP section.
|
||||
.sp
|
||||
The IPsec module must be configured in the
|
||||
\fI\%module\-config\fP directive, e.g.:
|
||||
@@ -4883,13 +5114,6 @@ module\-config: \(dqipsecmod validator iterator\(dq
|
||||
.sp
|
||||
and be compiled into Unbound by using \fB\-\-enable\-ipsecmod\fP to be enabled.
|
||||
.sp
|
||||
\fBNOTE:\fP
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
These settings go in the \fI\%server:\fP section.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
When Unbound receives an A/AAAA query that is not in the cache and finds a
|
||||
valid answer, it will withhold returning the answer and instead will generate
|
||||
an IPSECKEY subquery for the same domain name.
|
||||
@@ -4987,7 +5211,9 @@ If the option is not specified, all domains are treated as being allowed
|
||||
.B ipsecmod\-whitelist: \fI<domain>\fP
|
||||
Alternate syntax for \fI\%ipsecmod\-allow\fP\&.
|
||||
.UNINDENT
|
||||
.SS Cache DB Module Options
|
||||
.SH CACHE DB MODULE OPTIONS
|
||||
.sp
|
||||
These options are part of the \fBcachedb:\fP section.
|
||||
.sp
|
||||
The Cache DB module must be configured in the
|
||||
\fI\%module\-config\fP directive, e.g.:
|
||||
@@ -5049,7 +5275,7 @@ If connection close or timeout happens too often, Unbound will be effectively
|
||||
unusable with this backend.
|
||||
It\(aqs the administrator\(aqs responsibility to make the assumption hold.
|
||||
.sp
|
||||
The \fBcachedb:\fP clause gives custom settings of the cache DB module.
|
||||
The \fBcachedb:\fP section gives custom settings of the cache DB module.
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B backend: \fI<backend name>\fP
|
||||
@@ -5277,10 +5503,13 @@ for the Redis replica server.
|
||||
.sp
|
||||
Default: 0
|
||||
.UNINDENT
|
||||
.SS DNSTAP Logging Options
|
||||
.SH DNSTAP OPTIONS
|
||||
.sp
|
||||
DNSTAP support, when compiled in by using \fB\-\-enable\-dnstap\fP, is enabled in
|
||||
the \fBdnstap:\fP section.
|
||||
These options are part of the \fBdnstap:\fP section.
|
||||
.sp
|
||||
DNSTAP is a flexible, structured binary log format for DNS software.
|
||||
When compiled in by using \fB\-\-enable\-dnstap\fP, it can be enabled in the
|
||||
\fBdnstap:\fP section.
|
||||
This starts an extra thread (when compiled with threading) that writes the log
|
||||
information to the destination.
|
||||
If Unbound is compiled without threading it does not spawn a thread, but
|
||||
@@ -5446,15 +5675,18 @@ Enable to log forwarder response messages.
|
||||
.sp
|
||||
Default: no
|
||||
.UNINDENT
|
||||
.SS Response Policy Zone Options
|
||||
.SH RESPONSE POLICY ZONE OPTIONS
|
||||
.sp
|
||||
Response Policy Zones are configured with \fBrpz:\fP, and each one must have a
|
||||
\fI\%name\fP attribute.
|
||||
There can be multiple ones, by listing multiple RPZ clauses, each with a
|
||||
different name.
|
||||
RPZ clauses are applied in order of configuration and any match from an earlier
|
||||
RPZ zone will terminate the RPZ lookup.
|
||||
These options are part of the \fBrpz:\fP section.
|
||||
.sp
|
||||
Response Policy Zones are configured with \fBrpz:\fP section clauses, and each
|
||||
one must have a \fI\%name\fP option.
|
||||
There can be multiple ones, by listing multiple \fBrpz:\fP section clauses, each
|
||||
with a different name.
|
||||
RPZ sections are applied in order of configuration and any match from an
|
||||
earlier RPZ zone will terminate the RPZ lookup.
|
||||
Note that a PASSTHRU action is still considered a match.
|
||||
.sp
|
||||
The respip module needs to be added to the
|
||||
\fI\%module\-config\fP, e.g.:
|
||||
.INDENT 0.0
|
||||
@@ -5468,6 +5700,17 @@ module\-config: \(dqrespip validator iterator\(dq
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
\fBNOTE:\fP
|
||||
.INDENT 0.0
|
||||
.INDENT 3.5
|
||||
If combining the \fBrespip\fP and \fBdns64\fP modules, the \fBrespip\fP module
|
||||
needs to appear before the \fBdns64\fP module in the
|
||||
\fI\%module\-config\fP
|
||||
configuration option so that response IP and/or RPZ feeds can properly
|
||||
filter responses regardless of DNS64 synthesis.
|
||||
.UNINDENT
|
||||
.UNINDENT
|
||||
.sp
|
||||
QNAME, Response IP Address, nsdname, nsip and clientip triggers are supported.
|
||||
Supported actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp\-only
|
||||
and drop.
|
||||
@@ -5536,9 +5779,6 @@ A 192.0.2.1 answer with this IP address
|
||||
.sp
|
||||
Other records like AAAA, TXT and other CNAMEs (not rpz\-..) can also be used to
|
||||
answer queries with that content.
|
||||
.sp
|
||||
The RPZ zones can be configured in the config file with these settings in the
|
||||
\fBrpz:\fP block.
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B name: \fI<zone name>\fP
|
||||
@@ -5677,7 +5917,7 @@ Default: no
|
||||
.INDENT 0.0
|
||||
.TP
|
||||
.B tags: \fI\(dq<list of tags>\(dq\fP
|
||||
Limit the policies from this RPZ clause to clients with a matching tag.
|
||||
Limit the policies from this RPZ section to clients with a matching tag.
|
||||
.sp
|
||||
Tags need to be defined in \fI\%define\-tag\fP and
|
||||
can be assigned to client addresses using
|
||||
@@ -5685,7 +5925,7 @@ can be assigned to client addresses using
|
||||
\fI\%interface\-tag\fP\&.
|
||||
Enclose list of tags in quotes (\fB\(dq\(dq\fP) and put spaces between tags.
|
||||
.sp
|
||||
If no tags are specified the policies from this clause will be applied for
|
||||
If no tags are specified the policies from this section will be applied for
|
||||
all clients.
|
||||
.UNINDENT
|
||||
.SH MEMORY CONTROL EXAMPLE
|
||||
@@ -5754,6 +5994,6 @@ Default is to log to \fIsyslog(3)\fP\&.
|
||||
.SH AUTHOR
|
||||
Unbound developers are mentioned in the CREDITS file in the distribution.
|
||||
.SH COPYRIGHT
|
||||
1999-2025, NLnet Labs
|
||||
1999-2026, NLnet Labs
|
||||
.\" Generated by docutils manpage writer.
|
||||
.
|
||||
|
||||
+385
-144
@@ -46,34 +46,41 @@ Description
|
||||
-----------
|
||||
|
||||
**unbound.conf** is used to configure :doc:`unbound(8)</manpages/unbound>`.
|
||||
The file format has attributes and values.
|
||||
Some attributes have attributes inside them.
|
||||
The notation is: ``attribute: value``.
|
||||
|
||||
Comments start with ``#`` and last to the end of line.
|
||||
Empty lines are ignored as is whitespace at the beginning of a line.
|
||||
|
||||
The utility :doc:`unbound-checkconf(8)</manpages/unbound-checkconf>` can be
|
||||
used to check ``unbound.conf`` prior to usage.
|
||||
|
||||
File Format
|
||||
-----------
|
||||
|
||||
Whitespace is used to separate keywords.
|
||||
Whitespace indentation is insignificant, but is still recommended for visual
|
||||
clarity.
|
||||
Comments start with ``#`` and last to the end of line.
|
||||
Empty lines are ignored, as is whitespace at the beginning of a line.
|
||||
|
||||
Attribute keywords end with a colon (``:``) and they are either options or
|
||||
section clauses (group options together).
|
||||
|
||||
The configuration file is logically divided into **sections** where each section
|
||||
is introduced by a :ref:`section clause<unbound.conf.clauses>`.
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
An example config file is shown below.
|
||||
Copy this to :file:`/etc/unbound/unbound.conf` and start the server with:
|
||||
An example minimal config file is shown below; most settings are the defaults.
|
||||
Copy this to ``@ub_conf_file@`` and start the server with:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ unbound -c /etc/unbound/unbound.conf
|
||||
$ unbound -c @ub_conf_file@
|
||||
|
||||
Most settings are the defaults.
|
||||
Stop the server with:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ kill `cat /etc/unbound/unbound.pid`
|
||||
$ kill `cat @UNBOUND_PIDFILE@`
|
||||
|
||||
Below is a minimal config file.
|
||||
The source distribution contains an extensive :file:`example.conf` file with
|
||||
all the options.
|
||||
|
||||
@@ -81,35 +88,87 @@ all the options.
|
||||
|
||||
# unbound.conf(5) config file for unbound(8).
|
||||
server:
|
||||
directory: "/etc/unbound"
|
||||
directory: "@UNBOUND_RUN_DIR@"
|
||||
username: unbound
|
||||
# make sure unbound can access entropy from inside the chroot.
|
||||
# e.g. on linux the use these commands (on BSD, devfs(8) is used):
|
||||
# mount --bind -n /dev/urandom /etc/unbound/dev/urandom
|
||||
# and mount --bind -n /dev/log /etc/unbound/dev/log
|
||||
chroot: "/etc/unbound"
|
||||
# logfile: "/etc/unbound/unbound.log" #uncomment to use logfile.
|
||||
pidfile: "/etc/unbound/unbound.pid"
|
||||
# mount --bind -n /dev/urandom @UNBOUND_RUN_DIR@/dev/urandom
|
||||
# and mount --bind -n /dev/log @UNBOUND_RUN_DIR@/dev/log
|
||||
chroot: "@UNBOUND_CHROOT_DIR@"
|
||||
# logfile: "@UNBOUND_RUN_DIR@/unbound.log" #uncomment to use logfile.
|
||||
pidfile: "@UNBOUND_PIDFILE@"
|
||||
# verbosity: 1 # uncomment and increase to get more logging.
|
||||
# listen on all interfaces, answer queries from the local subnet.
|
||||
interface: 0.0.0.0
|
||||
interface: ::0
|
||||
access-control: 10.0.0.0/8 allow
|
||||
access-control: 2001:DB8::/64 allow
|
||||
access-control: 2001:db8::/64 allow
|
||||
|
||||
File Format
|
||||
-----------
|
||||
.. _unbound.conf.clauses:
|
||||
|
||||
There must be whitespace between keywords.
|
||||
Attribute keywords end with a colon ``':'``.
|
||||
An attribute is followed by a value, or its containing attributes in which case
|
||||
it is referred to as a clause.
|
||||
Clauses can be repeated throughout the file (or included files) to group
|
||||
attributes under the same clause.
|
||||
Section Clauses
|
||||
---------------
|
||||
|
||||
The recognized section clauses are:
|
||||
|
||||
:ref:`server:<unbound.conf.server>`
|
||||
Most of the configuration is found in this section.
|
||||
|
||||
:ref:`remote-control:<unbound.conf.remote>`
|
||||
Configuration for the facility used by
|
||||
:doc:`unbound-control(8)</manpages/unbound-control>`.
|
||||
|
||||
:ref:`stub-zone:<unbound.conf.stub>`
|
||||
Configuration for a zone that redirects to specific authoritative name
|
||||
servers, e.g. for zones not generally available on the greater
|
||||
Internet.
|
||||
|
||||
:ref:`forward-zone:<unbound.conf.forward>`
|
||||
Configuration for a zone that forwards to specific DNS resolvers.
|
||||
|
||||
:ref:`auth-zone:<unbound.conf.auth>`
|
||||
Configuration for local authoritative zones.
|
||||
|
||||
:ref:`view:<unbound.conf.view>`
|
||||
Overriding a small subset of configuration for incoming requests.
|
||||
Requests are mapped to views with
|
||||
:ref:`access-control-view<unbound.conf.access-control-view>` and
|
||||
:ref:`interface-view<unbound.conf.interface-view>`.
|
||||
|
||||
:ref:`python:<unbound.conf.python>`
|
||||
Configuration for the optional ``python`` script module.
|
||||
|
||||
:ref:`dynlib:<unbound.conf.dynlib>`
|
||||
Configuration for the optional ``dynlib`` module that loads dynamic
|
||||
libraries into Unbound.
|
||||
|
||||
:ref:`dnscrypt:<unbound.conf.dnscrypt>`
|
||||
Configuration for the optional DNSCrypt feature.
|
||||
|
||||
:ref:`cachedb:<unbound.conf.cachedb>`
|
||||
Configuration for the optional ``cachedb`` module that can interface
|
||||
with second level caches, currently Redis or Redis-complatible
|
||||
databases.
|
||||
|
||||
:ref:`dnstap:<unbound.conf.dnstap>`
|
||||
Configuration of the optional dnstap logging feature; a flexible,
|
||||
structured binary log format for DNS software.
|
||||
|
||||
:ref:`rpz:<unbound.conf.rpz>`
|
||||
Configuration for Response Policy Zones that allows for DNS filtering.
|
||||
Requires the ``respip`` module.
|
||||
|
||||
Section clauses can be repeated throughout the file (or included files) to
|
||||
logically group options in one visually cohesive group.
|
||||
This may be particularly useful for the ``server:`` clause with its myriad of
|
||||
options.
|
||||
|
||||
.. _unbound.conf.include:
|
||||
|
||||
Files can be included using the **include:** directive.
|
||||
Including Files
|
||||
---------------
|
||||
|
||||
Files can be included using the ``include:`` directive.
|
||||
It can appear anywhere, it accepts a single file name as argument.
|
||||
Processing continues as if the text from the included file was copied into the
|
||||
config file at that point.
|
||||
@@ -122,17 +181,17 @@ Wildcards can be used to include multiple files, see *glob(7)*.
|
||||
|
||||
.. _unbound.conf.include-toplevel:
|
||||
|
||||
For a more structural include option, the **include-toplevel:** directive can
|
||||
For a more structural include option, the ``include-toplevel:`` directive can
|
||||
be used.
|
||||
This closes whatever clause is currently active (if any) and forces the use of
|
||||
clauses in the included files and right after this directive.
|
||||
This closes whatever section clause is currently active (if any) and forces the
|
||||
use of section clauses in the included files and right after this directive.
|
||||
|
||||
.. _unbound.conf.server:
|
||||
|
||||
Server Options
|
||||
^^^^^^^^^^^^^^
|
||||
--------------
|
||||
|
||||
These options are part of the **server:** clause.
|
||||
These options are part of the ``server:`` section.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@verbosity@@: *<number>*
|
||||
@@ -307,6 +366,10 @@ These options are part of the **server:** clause.
|
||||
Larger numbers need extra resources from the operating system.
|
||||
For performance a very large value is best, use libevent to make this
|
||||
possible.
|
||||
Should be higher (preferably double) than the value of
|
||||
:ref:`num-queries-per-thread<unbound.conf.num-queries-per-thread>` to
|
||||
account for cases where the request list is full and avoid file descriptor
|
||||
starvation.
|
||||
|
||||
Default: 4096 (libevent) / 960 (minievent) / 48 (windows)
|
||||
|
||||
@@ -496,6 +559,9 @@ These options are part of the **server:** clause.
|
||||
The wait time in msec where recursion requests are dropped.
|
||||
This is to stop a large number of replies from accumulating.
|
||||
They receive no reply, the work item continues to recurse.
|
||||
For UDP the replies are dropped, for stream connections the reply
|
||||
is not dropped if the stream connection is still open ready to receive
|
||||
answers.
|
||||
It is nice to be a bit larger than
|
||||
:ref:`serve-expired-client-timeout<unbound.conf.serve-expired-client-timeout>`
|
||||
if that is enabled.
|
||||
@@ -510,7 +576,7 @@ These options are part of the **server:** clause.
|
||||
This makes a ratelimit per IP address of waiting replies for recursion.
|
||||
It stops very large amounts of queries waiting to be returned to one
|
||||
destination.
|
||||
The value ``0`` disables wait limits.
|
||||
The value ``0`` disables all wait limits.
|
||||
|
||||
Default: 1000
|
||||
|
||||
@@ -518,7 +584,11 @@ These options are part of the **server:** clause.
|
||||
@@UAHL@unbound.conf@wait-limit-cookie@@: *<number>*
|
||||
The number of replies that can wait for recursion, for an IP address
|
||||
that sent the query with a valid DNS Cookie.
|
||||
Since the cookie validates the client address, this limit can be higher.
|
||||
Since the cookie already validates the client address, this option allows
|
||||
to override a configured
|
||||
:ref:`wait-limit<unbound.conf.wait-limit>` value usually with a higher one
|
||||
for cookie validated queries.
|
||||
The value ``0`` disables wait limits for cookie validated queries.
|
||||
|
||||
Default: 10000
|
||||
|
||||
@@ -978,9 +1048,13 @@ These options are part of the **server:** clause.
|
||||
certificate is in the :ref:`tls-service-pem<unbound.conf.tls-service-pem>`
|
||||
file and it must also be specified if
|
||||
:ref:`tls-service-key<unbound.conf.tls-service-key>` is specified.
|
||||
Enabling or disabling this service requires a restart (a reload is not
|
||||
enough), because the key is read while root permissions are held and before
|
||||
chroot (if any).
|
||||
If the key is stored with root permissions or outside of chroot, then
|
||||
a change or enabling or disabling requires a restart (a reload is not
|
||||
enough).
|
||||
But if the key file (and tls-service-pem file) are accessible, then they
|
||||
are read in on reload, and fast_reload.
|
||||
The server checks the modification time of the file (and the filename)
|
||||
to see if the file has changed for reload.
|
||||
The ports enabled implicitly or explicitly via
|
||||
:ref:`tls-port<unbound.conf.tls-port>` and
|
||||
:ref:`https-port<unbound.conf.https-port>` do not provide normal DNS TCP
|
||||
@@ -1049,8 +1123,8 @@ These options are part of the **server:** clause.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@tls-system-cert@@: *<yes or no>*
|
||||
This the same attribute as the
|
||||
:ref:`tls-win-cert<unbound.conf.tls-win-cert>` attribute, under a
|
||||
This the same as the
|
||||
:ref:`tls-win-cert<unbound.conf.tls-win-cert>` option, under a
|
||||
different name.
|
||||
Because it is not windows specific.
|
||||
|
||||
@@ -1106,25 +1180,19 @@ These options are part of the **server:** clause.
|
||||
@@UAHL@unbound.conf@tls-use-sni@@: *<yes or no>*
|
||||
Enable or disable sending the SNI extension on TLS connections.
|
||||
|
||||
.. note:: Changing the value requires a reload.
|
||||
.. note:: Changing the value requires a restart.
|
||||
|
||||
Default: yes
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@tls-use-system-policy-versions@@: *<yes or no>*
|
||||
Enable or disable general-puspose version-flexible TLS server configuration
|
||||
when serving TLS.
|
||||
This will allow the whole list of available TLS versions provided by the
|
||||
crypto library, which may have been further restricted by the system's
|
||||
crypto policy.
|
||||
@@UAHL@unbound.conf@tls-protocols@@: *"<list of protocols>"*
|
||||
Specify the allowed TLS protocol versions to use, in no particular order.
|
||||
Possible values are ``TLSv1.2`` and ``TLSv1.3``.
|
||||
Enclose list of protocols in quotes (``""``) and put spaces between them.
|
||||
|
||||
By default Unbound only uses the latest available TLS version.
|
||||
.. note:: Changing the value requires a restart.
|
||||
|
||||
.. caution:: Use only if you want to support legacy TLS client connections.
|
||||
|
||||
.. note:: Changing the value requires a reload.
|
||||
|
||||
Default: no
|
||||
Default: "TLSv1.2 TLSv1.3"
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@pad-responses@@: *<yes or no>*
|
||||
@@ -1240,6 +1308,9 @@ These options are part of the **server:** clause.
|
||||
Only interfaces configured with that port number as @number get the QUIC
|
||||
service.
|
||||
The interface uses QUIC for the UDP traffic on that port number.
|
||||
If it is set to 0, the server does not init QUIC code, and QUIC is
|
||||
disabled.
|
||||
This is similar to if QUIC is not in use, but then explicitly.
|
||||
|
||||
Default: 853
|
||||
|
||||
@@ -1437,8 +1508,8 @@ These options are part of the **server:** clause.
|
||||
.. note::
|
||||
The interface needs to be already specified with
|
||||
:ref:`interface<unbound.conf.interface>` and that any
|
||||
**access-control\*:** attribute overrides all **interface-\*:**
|
||||
attributes for targeted clients.
|
||||
**access-control\*:** option overrides all **interface-\*:**
|
||||
options for targeted clients.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@interface-tag@@: *<ip address or interface name [@port]> <"list of tags">*
|
||||
@@ -1448,8 +1519,8 @@ These options are part of the **server:** clause.
|
||||
.. note::
|
||||
The interface needs to be already specified with
|
||||
:ref:`interface<unbound.conf.interface>` and that any
|
||||
**access-control\*:** attribute overrides all **interface-\*:**
|
||||
attributes for targeted clients.
|
||||
**access-control\*:** option overrides all **interface-\*:**
|
||||
options for targeted clients.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@interface-tag-action@@: *<ip address or interface name [@port]> <tag> <action>*
|
||||
@@ -1460,8 +1531,8 @@ These options are part of the **server:** clause.
|
||||
.. note::
|
||||
The interface needs to be already specified with
|
||||
:ref:`interface<unbound.conf.interface>` and that any
|
||||
**access-control\*:** attribute overrides all **interface-\*:**
|
||||
attributes for targeted clients.
|
||||
**access-control\*:** option overrides all **interface-\*:**
|
||||
options for targeted clients.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@interface-tag-data@@: *<ip address or interface name [@port]> <tag> <"resource record string">*
|
||||
@@ -1472,8 +1543,8 @@ These options are part of the **server:** clause.
|
||||
.. note::
|
||||
The interface needs to be already specified with
|
||||
:ref:`interface<unbound.conf.interface>` and that any
|
||||
**access-control\*:** attribute overrides all **interface-\*:**
|
||||
attributes for targeted clients.
|
||||
**access-control\*:** option overrides all **interface-\*:**
|
||||
options for targeted clients.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@interface-view@@: *<ip address or interface name [@port]> <view name>*
|
||||
@@ -1483,8 +1554,8 @@ These options are part of the **server:** clause.
|
||||
.. note::
|
||||
The interface needs to be already specified with
|
||||
:ref:`interface<unbound.conf.interface>` and that any
|
||||
**access-control\*:** attribute overrides all **interface-\*:**
|
||||
attributes for targeted clients.
|
||||
**access-control\*:** option overrides all **interface-\*:**
|
||||
options for targeted clients.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@chroot@@: *<directory>*
|
||||
@@ -1549,7 +1620,7 @@ These options are part of the **server:** clause.
|
||||
[seconds since 1970] unbound[pid:tid]: type: message.
|
||||
|
||||
If this option is given, the :ref:`use-syslog<unbound.conf.use-syslog>`
|
||||
attribute is internally set to ``no``.
|
||||
option is internally set to ``no``.
|
||||
|
||||
The logfile is reopened (for append) when the config file is reread, on
|
||||
SIGHUP.
|
||||
@@ -1648,6 +1719,15 @@ These options are part of the **server:** clause.
|
||||
Default: no
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@log-thread-id@@: *<yes or no>*
|
||||
(Only on Linux and only when threads are available)
|
||||
Logs the system-wide Linux thread ID instead of Unbound's internal thread
|
||||
counter.
|
||||
Can be useful when debugging with system tools.
|
||||
|
||||
Default: no
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@pidfile@@: *<filename>*
|
||||
The process id is written to the file.
|
||||
Default is :file:`"@UNBOUND_PIDFILE@"`.
|
||||
@@ -1673,8 +1753,8 @@ These options are part of the **server:** clause.
|
||||
Default is nothing, using builtin hints for the IN class.
|
||||
The file has the format of zone files, with root nameserver names and
|
||||
addresses only.
|
||||
The default may become outdated, when servers change, therefore it is good
|
||||
practice to use a root hints file.
|
||||
The default may become outdated, when servers change, and then it is
|
||||
possible to use a root hints file with specific servers.
|
||||
|
||||
Default: ""
|
||||
|
||||
@@ -1934,6 +2014,11 @@ These options are part of the **server:** clause.
|
||||
turned into a network proxy, allowing remote access through the browser to
|
||||
other parts of your private network.
|
||||
|
||||
The option removes resource records of types A, AAAA, SVCB and HTTPS
|
||||
that match the filter.
|
||||
Inside the SVCB and HTTPS records, the svcparams of type ipv4hint
|
||||
and ipv6hint are checked for matches.
|
||||
|
||||
Some names can be allowed to contain your private addresses, by default all
|
||||
the :ref:`local-data<unbound.conf.local-data>` that you configured is
|
||||
allowed to, and you can specify additional names using
|
||||
@@ -1970,6 +2055,13 @@ These options are part of the **server:** clause.
|
||||
flushing away any poison.
|
||||
A value of 10 million is suggested.
|
||||
|
||||
It is useful to add 0.0.0.0/8 and '::' to the
|
||||
:ref:`do-not-query-address<unbound.conf.do-not-query-address>` list.
|
||||
Otherwise they may be answered, from localhost, and the different source
|
||||
makes an unwanted reply that unnecessarily ticks up.
|
||||
The :ref:`do-not-query-localhost<unbound.conf.do-not-query-localhost>`
|
||||
option includes them, the zero subnets, when it is enabled.
|
||||
|
||||
Default: 0 (disabled)
|
||||
|
||||
|
||||
@@ -2584,6 +2676,33 @@ These options are part of the **server:** clause.
|
||||
redirected, so that users with web browsers cannot access sites with
|
||||
suffix example.com.
|
||||
|
||||
A ``CNAME`` record can also be provided via local-data:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
local-zone: "example.com." redirect
|
||||
local-data: "example.com. CNAME www.example.org."
|
||||
|
||||
In that case, the ``CNAME`` is resolved and the answer
|
||||
includes resolved target records as well.
|
||||
The ``CNAME`` record has to be with the zone name of the local-zone,
|
||||
and there can be one CNAME, not more.
|
||||
The ``CNAME`` record has to be at the zone apex of the
|
||||
``redirect`` zone, then it is used for redirection.
|
||||
The resolution proceeds with upstream DNS resolution, and
|
||||
that does not include the lookup in local zones.
|
||||
So the record is not able to point in local zones, but it
|
||||
can point to upstream DNS answers.
|
||||
|
||||
``CNAME`` resolution is supported only in type ``redirect``
|
||||
local-zone, and in type ``inform_redirect`` local-zone.
|
||||
|
||||
As different from ``CNAME`` records that are used elsewhere, in
|
||||
the ``redirect`` type local-zone, it is supported that in the target
|
||||
of the record a wildcard label gets expanded to the query name, with
|
||||
for example: ``example.com. CNAME *.foo.net.`` gets expanded
|
||||
to ``www.example.com. CNAME www.example.com.foo.net.``.
|
||||
|
||||
@@UAHL@unbound.conf.local-zone.type@inform@@
|
||||
The query is answered normally, same as
|
||||
:ref:`transparent<unbound.conf.local-zone.type.transparent>`.
|
||||
@@ -2623,6 +2742,9 @@ These options are part of the **server:** clause.
|
||||
@@UAHL@unbound.conf.local-zone.type@always_refuse@@
|
||||
Like :ref:`refuse<unbound.conf.local-zone.type.refuse>`, but ignores
|
||||
local data and refuses the query.
|
||||
This type also blocks queries of type DS for the zone name.
|
||||
That can break the DNSSEC chain of trust, but it is refused anyway.
|
||||
The block for type DS assists in more completely blocking the zone.
|
||||
|
||||
@@UAHL@unbound.conf.local-zone.type@always_nxdomain@@
|
||||
Like :ref:`static<unbound.conf.local-zone.type.static>`, but ignores
|
||||
@@ -2830,7 +2952,7 @@ These options are part of the **server:** clause.
|
||||
Configure local data shorthand for a PTR record with the reversed IPv4 or
|
||||
IPv6 address and the host name.
|
||||
For example ``"192.0.2.4 www.example.com"``.
|
||||
TTL can be inserted like this: ``"2001:DB8::4 7200 www.example.com"``
|
||||
TTL can be inserted like this: ``"2001:db8::4 7200 www.example.com"``
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@local-zone-tag@@: *<zone> <"list of tags">*
|
||||
@@ -2883,7 +3005,7 @@ These options are part of the **server:** clause.
|
||||
:ref:`response-ip<unbound.conf.response-ip>` with action being to redirect
|
||||
as specified by *<"resource record string">*.
|
||||
*<"Resource record string">* is similar to that of
|
||||
:ref:`access-control-tag-action<unbound.conf.access-control-tag-action>`,
|
||||
:ref:`access-control-tag-data<unbound.conf.access-control-tag-data>`,
|
||||
but it must be of either AAAA, A or CNAME types.
|
||||
If the *<IP-netblock>* is an IPv6/IPv4 prefix, the record must be AAAA/A
|
||||
respectively, unless it is a CNAME (which can be used for both versions of
|
||||
@@ -3145,6 +3267,10 @@ These options are part of the **server:** clause.
|
||||
Hard limit on the number of times Unbound is allowed to restart a query
|
||||
upon encountering a CNAME record.
|
||||
Results in SERVFAIL when reached.
|
||||
This applies to chained CNAME records but not sporadic CNAME records that
|
||||
could be encountered in the lifetime of the query's resolution effort.
|
||||
When a CNAME chain concludes, the counter keeping track of this limit is
|
||||
reset.
|
||||
Changing this value needs caution as it can allow long CNAME chains to be
|
||||
accepted, where Unbound needs to verify (resolve) each link individually.
|
||||
|
||||
@@ -3169,6 +3295,15 @@ These options are part of the **server:** clause.
|
||||
Default: 11
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@iter-scrub-rrsig@@: *<number>*
|
||||
Limit on the number of RRSIGs allowed for an RRset, from the iterator
|
||||
scrubber.
|
||||
This protects against an overly large number of RRSIGs.
|
||||
Clips off the remainder of the RRSIG list at that point.
|
||||
|
||||
Default: 8
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@max-global-quota@@: *<number>*
|
||||
Limit on the number of upstream queries sent out for an incoming query and
|
||||
its subqueries from recursion.
|
||||
@@ -3178,6 +3313,14 @@ These options are part of the **server:** clause.
|
||||
Default: 200
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@iter-scrub-promiscuous@@: *<yes or no>*
|
||||
Should the iterator scrubber remove promiscuous NS from positive answers.
|
||||
This protects against poisonous contents, that could affect names in the
|
||||
same zone as a spoofed packet.
|
||||
|
||||
Default: yes
|
||||
|
||||
|
||||
@@UAHL@unbound.conf@fast-server-permil@@: *<number>*
|
||||
Specify how many times out of 1000 to pick from the set of fastest servers.
|
||||
0 turns the feature off.
|
||||
@@ -3304,17 +3447,18 @@ These options are part of the **server:** clause.
|
||||
.. _unbound.conf.remote:
|
||||
|
||||
Remote Control Options
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
----------------------
|
||||
|
||||
These options are part of the ``remote-control:`` section and are the
|
||||
declarations for the remote control facility.
|
||||
|
||||
In the **remote-control:** clause are the declarations for the remote control
|
||||
facility.
|
||||
If this is enabled, the :doc:`unbound-control(8)</manpages/unbound-control>`
|
||||
utility can be used to send commands to the running Unbound server.
|
||||
The server uses these clauses to setup TLSv1 security for the connection.
|
||||
The :doc:`unbound-control(8)</manpages/unbound-control>` utility also reads the
|
||||
**remote-control:** section for options.
|
||||
The server uses these options to setup TLS security for the connection.
|
||||
The :doc:`unbound-control(8)</manpages/unbound-control>` utility also reads
|
||||
this ``remote-control:`` section for options.
|
||||
To setup the correct self-signed certificates use the
|
||||
*unbound-control-setup(8)* utility.
|
||||
``unbound-control-setup(8)`` utility.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.remote@control-enable@@: *<yes or no>*
|
||||
@@ -3324,7 +3468,7 @@ To setup the correct self-signed certificates use the
|
||||
Default: no
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.remote@control-interface@@: *<IP address or interface name or path>*
|
||||
@@UAHL@unbound.conf.remote@control-interface@@: *<IP address or interface name[@port] or path>*
|
||||
Give IPv4 or IPv6 addresses or local socket path to listen on for control
|
||||
commands.
|
||||
If an interface name is used instead of an IP address, the list of IP
|
||||
@@ -3406,9 +3550,11 @@ To setup the correct self-signed certificates use the
|
||||
.. _unbound.conf.stub:
|
||||
|
||||
Stub Zone Options
|
||||
^^^^^^^^^^^^^^^^^
|
||||
-----------------
|
||||
|
||||
There may be multiple **stub-zone:** clauses.
|
||||
These options are part of the ``stub-zone:`` section.
|
||||
|
||||
There may be multiple ``stub-zone:`` sections.
|
||||
Each with a :ref:`name<unbound.conf.stub.name>` and zero or more hostnames or
|
||||
IP addresses.
|
||||
For the stub zone this list of nameservers is used.
|
||||
@@ -3441,9 +3587,10 @@ Consider adding :ref:`server<unbound.conf.server>` statements for
|
||||
:ref:`domain-insecure<unbound.conf.domain-insecure>` and for
|
||||
:ref:`local-zone: \<name\> nodefault<unbound.conf.local-zone.type.nodefault>`
|
||||
for the zone if it is a locally served zone.
|
||||
The insecure clause stops DNSSEC from invalidating the zone.
|
||||
The :ref:`domain-insecure<unbound.conf.domain-insecure>` option stops DNSSEC
|
||||
from invalidating the zone.
|
||||
The :ref:`local-zone: nodefault<unbound.conf.local-zone.type.nodefault>` (or
|
||||
:ref:`transparent<unbound.conf.local-zone.type.transparent>`) clause makes the
|
||||
:ref:`transparent<unbound.conf.local-zone.type.transparent>`) option makes the
|
||||
(reverse-) zone bypass Unbound's filtering of :rfc:`1918` zones.
|
||||
|
||||
|
||||
@@ -3456,6 +3603,19 @@ The :ref:`local-zone: nodefault<unbound.conf.local-zone.type.nodefault>` (or
|
||||
Name of stub zone nameserver.
|
||||
Is itself resolved before it is used.
|
||||
|
||||
.. caution::
|
||||
If the domain (or a subdomain) from this zone is used as the host, it
|
||||
will unavoidably introduce a circular dependency on retrieving the IP
|
||||
addresses of the name server.
|
||||
In that case, it is suggested to use
|
||||
:ref:`stub-addr<unbound.conf.stub.stub-addr>` instead.
|
||||
Alternatively,
|
||||
:ref:`stub-first: yes<unbound.conf.stub.stub-first>` can also work
|
||||
around the circular dependency by trying resolution outside of this
|
||||
zone.
|
||||
However this has the caveat that it would allow escaping this zone when
|
||||
any resolution attempt fails within this zone.
|
||||
|
||||
To use a non-default port for DNS communication append ``'@'`` with the
|
||||
port number.
|
||||
|
||||
@@ -3493,9 +3653,12 @@ The :ref:`local-zone: nodefault<unbound.conf.local-zone.type.nodefault>` (or
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.stub@stub-first@@: *<yes or no>*
|
||||
If enabled, a query is attempted without the stub clause if it fails.
|
||||
If enabled, a query is attempted without this stub section if it fails.
|
||||
The data could not be retrieved and would have caused SERVFAIL because the
|
||||
servers are unreachable, instead it is tried without this clause.
|
||||
servers are unreachable, instead it is tried without this stub section.
|
||||
This can lead to using less specific configured forward/stub/auth zones if
|
||||
any, or end up to otherwise normal recursive resolution for that particular
|
||||
query.
|
||||
|
||||
Default: no
|
||||
|
||||
@@ -3527,9 +3690,11 @@ The :ref:`local-zone: nodefault<unbound.conf.local-zone.type.nodefault>` (or
|
||||
.. _unbound.conf.forward:
|
||||
|
||||
Forward Zone Options
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
--------------------
|
||||
|
||||
There may be multiple **forward-zone:** clauses.
|
||||
These options are part of the ``forward-zone:`` section.
|
||||
|
||||
There may be multiple ``forward-zone:`` sections.
|
||||
Each with a :ref:`name<unbound.conf.forward.name>` and zero or more hostnames
|
||||
or IP addresses.
|
||||
For the forward zone this list of nameservers is used to forward the queries
|
||||
@@ -3559,6 +3724,19 @@ cache).
|
||||
Name of server to forward to.
|
||||
Is itself resolved before it is used.
|
||||
|
||||
.. caution::
|
||||
If the domain (or a subdomain) from this zone is used as the host, it
|
||||
will unavoidably introduce a circular dependency on retrieving the IP
|
||||
addresses of the name server.
|
||||
In that case, it is suggested to use
|
||||
:ref:`forward-addr<unbound.conf.forward.forward-addr>` instead.
|
||||
Alternatively,
|
||||
:ref:`forward-first: yes<unbound.conf.forward.forward-first>` can also
|
||||
work around the circular dependency by trying resolution outside of
|
||||
this zone.
|
||||
However this has the caveat that it would allow escaping this zone when
|
||||
any resolution attempt fails within this zone.
|
||||
|
||||
To use a non-default port for DNS communication append ``'@'`` with the
|
||||
port number.
|
||||
|
||||
@@ -3593,9 +3771,11 @@ cache).
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.forward@forward-first@@: *<yes or no>*
|
||||
If a forwarded query is met with a SERVFAIL error, and this option is
|
||||
enabled, Unbound will fall back to normal recursive resolution for this
|
||||
query as if no query forwarding had been specified.
|
||||
If a forwarded query is met with a SERVFAIL error and this option is
|
||||
enabled Unbound will fall back to less specific resolution.
|
||||
This can lead to using less specific configured forward/stub/auth zones if
|
||||
any, or end up to otherwise normal recursive resolution for that particular
|
||||
query.
|
||||
|
||||
Default: no
|
||||
|
||||
@@ -3632,12 +3812,14 @@ cache).
|
||||
.. _unbound.conf.auth:
|
||||
|
||||
Authority Zone Options
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
----------------------
|
||||
|
||||
Authority zones are configured with **auth-zone:**, and each one must have a
|
||||
These options are part of the ``auth-zone:`` section.
|
||||
|
||||
Authority zones are configured with ``auth-zone:``, and each one must have a
|
||||
:ref:`name<unbound.conf.auth.name>`.
|
||||
There can be multiple ones, by listing multiple auth-zone clauses, each with a
|
||||
different name, pertaining to that part of the namespace.
|
||||
There can be multiple ones, by listing multiple ``auth-zone`` section clauses,
|
||||
each with a different name, pertaining to that part of the namespace.
|
||||
The authority zone with the name closest to the name looked up is used.
|
||||
Authority zones can be processed on two distinct, non-exclusive, configurable
|
||||
stages.
|
||||
@@ -3668,7 +3850,7 @@ consult the local zone data while resolving.
|
||||
In this case, the aforementioned CNAME example will result in a thoroughly
|
||||
resolved answer.
|
||||
|
||||
Authority zones can be read from zonefile.
|
||||
Authority zones can be read from a zonefile.
|
||||
And can be kept updated via AXFR and IXFR.
|
||||
After update the zonefile is rewritten.
|
||||
The update mechanism uses the SOA timer values and performs SOA UDP queries to
|
||||
@@ -3704,9 +3886,11 @@ fallback activates to fetch from the upstream instead of the SERVFAIL.
|
||||
:ref:`url<unbound.conf.auth.url>` to download the zonefile as a text file
|
||||
from a webserver that would work.
|
||||
|
||||
If you specify the hostname, you cannot use the domain from the zonefile,
|
||||
because it may not have that when retrieving that data, instead use a plain
|
||||
IP address to avoid a circular dependency on retrieving that IP address.
|
||||
.. caution::
|
||||
If you specify the hostname, you cannot use the domain from the
|
||||
zonefile, because it may not have that when retrieving that data,
|
||||
instead use a plain IP address to avoid a circular dependency on
|
||||
retrieving that IP address.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.auth@master@@: *<IP address or host name>*
|
||||
@@ -3837,18 +4021,20 @@ fallback activates to fetch from the upstream instead of the SERVFAIL.
|
||||
.. _unbound.conf.view:
|
||||
|
||||
View Options
|
||||
^^^^^^^^^^^^
|
||||
------------
|
||||
|
||||
There may be multiple **view:** clauses.
|
||||
These options are part of the ``view:`` section.
|
||||
|
||||
There may be multiple ``view:`` sections.
|
||||
Each with a :ref:`name<unbound.conf.view.name>` and zero or more
|
||||
:ref:`local-zone<unbound.conf.view.local-zone>` and
|
||||
:ref:`local-data<unbound.conf.view.local-data>` attributes.
|
||||
:ref:`local-data<unbound.conf.view.local-data>` options.
|
||||
Views can also contain :ref:`view-first<unbound.conf.view.view-first>`,
|
||||
:ref:`response-ip<unbound.conf.response-ip>`,
|
||||
:ref:`response-ip-data<unbound.conf.response-ip-data>` and
|
||||
:ref:`local-data-ptr<unbound.conf.view.local-data-ptr>` attributes.
|
||||
:ref:`local-data-ptr<unbound.conf.view.local-data-ptr>` options.
|
||||
View can be mapped to requests by specifying the view name in an
|
||||
:ref:`access-control-view<unbound.conf.access-control-view>` attribute.
|
||||
:ref:`access-control-view<unbound.conf.access-control-view>` option.
|
||||
Options from matching views will override global options.
|
||||
Global options will be used if no matching view is found, or when the matching
|
||||
view does not have the option specified.
|
||||
@@ -3858,7 +4044,7 @@ view does not have the option specified.
|
||||
Name of the view.
|
||||
Must be unique.
|
||||
This name is used in the
|
||||
:ref:`access-control-view<unbound.conf.access-control-view>` attribute.
|
||||
:ref:`access-control-view<unbound.conf.access-control-view>` option.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.view@local-zone@@: *<zone> <type>*
|
||||
@@ -3887,6 +4073,20 @@ view does not have the option specified.
|
||||
:ref:`local-data-ptr<unbound.conf.local-data-ptr>` elements.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.view@response-ip@@: *<IP-netblock> <action>*
|
||||
This requires use of the ``respip`` module.
|
||||
|
||||
Similar to :ref:`response-ip<unbound.conf.response-ip>` but
|
||||
only applies to this view.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.view@response-ip-data@@: *<IP-netblock> <"resource record string">*
|
||||
This requires use of the ``respip`` module.
|
||||
|
||||
Similar to :ref:`response-ip-data<unbound.conf.response-ip-data>` but
|
||||
only applies to this view.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.view@view-first@@: *<yes or no>*
|
||||
If enabled, it attempts to use the global
|
||||
:ref:`local-zone<unbound.conf.local-zone>` and
|
||||
@@ -3895,10 +4095,14 @@ view does not have the option specified.
|
||||
|
||||
Default: no
|
||||
|
||||
Python Module Options
|
||||
^^^^^^^^^^^^^^^^^^^^^
|
||||
.. _unbound.conf.python:
|
||||
|
||||
The **python:** clause gives the settings for the *python(1)* script module.
|
||||
Python Module Options
|
||||
---------------------
|
||||
|
||||
These options are part of the ``python:`` section.
|
||||
|
||||
The ``python:`` section gives the settings for the *python(1)* script module.
|
||||
This module acts like the iterator and validator modules do, on queries and
|
||||
answers.
|
||||
To enable the script module it has to be compiled into the daemon, and the word
|
||||
@@ -3921,15 +4125,19 @@ path to the working directory.
|
||||
Repeat this option for every python module instance added to the
|
||||
:ref:`module-config<unbound.conf.module-config>` option.
|
||||
|
||||
Dynamic Library Module Options
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
.. _unbound.conf.dynlib:
|
||||
|
||||
The **dynlib:** clause gives the settings for the ``dynlib`` module.
|
||||
Dynamic Library Module Options
|
||||
------------------------------
|
||||
|
||||
These options are part of the ``dynlib:`` section.
|
||||
|
||||
The ``dynlib:`` section gives the settings for the ``dynlib`` module.
|
||||
This module is only a very small wrapper that allows dynamic modules to be
|
||||
loaded on runtime instead of being compiled into the application.
|
||||
To enable the dynlib module it has to be compiled into the daemon, and the word
|
||||
``dynlib`` has to be put in the
|
||||
:ref:`module-config<unbound.conf.module-config>` attribute.
|
||||
:ref:`module-config<unbound.conf.module-config>` option.
|
||||
Multiple instances of dynamic libraries are supported by adding the word
|
||||
``dynlib`` more than once.
|
||||
|
||||
@@ -3945,7 +4153,9 @@ directory.
|
||||
:ref:`module-config<unbound.conf.module-config>` option.
|
||||
|
||||
DNS64 Module Options
|
||||
^^^^^^^^^^^^^^^^^^^^
|
||||
--------------------
|
||||
|
||||
These options are part of the ``server:`` section.
|
||||
|
||||
The ``dns64`` module must be configured in the
|
||||
:ref:`module-config<unbound.conf.module-config>` directive, e.g.:
|
||||
@@ -3957,7 +4167,11 @@ The ``dns64`` module must be configured in the
|
||||
and be compiled into the daemon to be enabled.
|
||||
|
||||
.. note::
|
||||
These settings go in the :ref:`server:<unbound.conf.server>` section.
|
||||
If combining the ``respip`` and ``dns64`` modules, the ``respip`` module
|
||||
needs to appear before the ``dns64`` module in the
|
||||
:ref:`module-config<unbound.conf.module-config>`
|
||||
configuration option so that response IP and/or RPZ feeds can properly
|
||||
filter responses regardless of DNS64 synthesis.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.dns64@dns64-prefix@@: *<IPv6 prefix>*
|
||||
@@ -3983,13 +4197,13 @@ and be compiled into the daemon to be enabled.
|
||||
per line.
|
||||
Applies also to names underneath the name given.
|
||||
|
||||
NAT64 Operation
|
||||
^^^^^^^^^^^^^^^
|
||||
NAT64 Options
|
||||
-------------
|
||||
|
||||
These options are part of the ``server:`` section.
|
||||
|
||||
NAT64 operation allows using a NAT64 prefix for outbound requests to IPv4-only
|
||||
servers.
|
||||
It is controlled by two options in the
|
||||
:ref:`server:<unbound.conf.server>` section:
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.nat64@do-nat64@@: *<yes or no>*
|
||||
@@ -4004,12 +4218,27 @@ It is controlled by two options in the
|
||||
Use a specific NAT64 prefix to reach IPv4-only servers.
|
||||
The prefix length must be one of /32, /40, /48, /56, /64 or /96.
|
||||
|
||||
The NAT64 prefix is allowed by the
|
||||
:ref:`do-not-query-address<unbound.conf.do-not-query-address>` option,
|
||||
so that there is a clear outcome of addresses in both; the NAT64 prefix
|
||||
is allowed.
|
||||
The IPv4 address could be filtered by the
|
||||
:ref:`do-not-query-address<unbound.conf.do-not-query-address>` option,
|
||||
if needed.
|
||||
Allowing the NAT64 prefix is useful when using do-not-query-address
|
||||
for a cluster of machines that is IPv6-only and uses NAT64, but does
|
||||
not have internet access.
|
||||
|
||||
Default: 64:ff9b::/96 (same as :ref:`dns64-prefix<unbound.conf.dns64.dns64-prefix>`)
|
||||
|
||||
DNSCrypt Options
|
||||
^^^^^^^^^^^^^^^^
|
||||
.. _unbound.conf.dnscrypt:
|
||||
|
||||
The **dnscrypt:** clause gives the settings of the dnscrypt channel.
|
||||
DNSCrypt Options
|
||||
----------------
|
||||
|
||||
These options are part of the ``dnscrypt:`` section.
|
||||
|
||||
The ``dnscrypt:`` section gives the settings of the dnscrypt channel.
|
||||
While those options are available, they are only meaningful if Unbound was
|
||||
compiled with ``--enable-dnscrypt``.
|
||||
Currently certificate and secret/public keys cannot be generated by Unbound.
|
||||
@@ -4116,7 +4345,9 @@ https://github.com/cofyc/dnscrypt-wrapper/blob/master/README.md#usage
|
||||
Default: (unconfigured)
|
||||
|
||||
EDNS Client Subnet Module Options
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
---------------------------------
|
||||
|
||||
These options are part of the ``server:`` section.
|
||||
|
||||
The ECS module must be configured in the
|
||||
:ref:`module-config<unbound.conf.module-config>` directive, e.g.:
|
||||
@@ -4127,9 +4358,6 @@ The ECS module must be configured in the
|
||||
|
||||
and be compiled into the daemon to be enabled.
|
||||
|
||||
.. note::
|
||||
These settings go in the :ref:`server:<unbound.conf.server>` section.
|
||||
|
||||
If the destination address is allowed in the configuration Unbound will add the
|
||||
EDNS0 option to the query containing the relevant part of the client's address.
|
||||
When an answer contains the ECS option the response and the option are placed
|
||||
@@ -4244,7 +4472,9 @@ This module does not interact with the
|
||||
Default: 100
|
||||
|
||||
Opportunistic IPsec Support Module Options
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
------------------------------------------
|
||||
|
||||
These options are part of the ``server:`` section.
|
||||
|
||||
The IPsec module must be configured in the
|
||||
:ref:`module-config<unbound.conf.module-config>` directive, e.g.:
|
||||
@@ -4255,9 +4485,6 @@ The IPsec module must be configured in the
|
||||
|
||||
and be compiled into Unbound by using ``--enable-ipsecmod`` to be enabled.
|
||||
|
||||
.. note::
|
||||
These settings go in the :ref:`server:<unbound.conf.server>` section.
|
||||
|
||||
When Unbound receives an A/AAAA query that is not in the cache and finds a
|
||||
valid answer, it will withhold returning the answer and instead will generate
|
||||
an IPSECKEY subquery for the same domain name.
|
||||
@@ -4347,8 +4574,12 @@ answer given from cache is still relevant for opportunistic IPsec.
|
||||
@@UAHL@unbound.conf@ipsecmod-whitelist@@: *<domain>*
|
||||
Alternate syntax for :ref:`ipsecmod-allow<unbound.conf.ipsecmod-allow>`.
|
||||
|
||||
.. _unbound.conf.cachedb:
|
||||
|
||||
Cache DB Module Options
|
||||
^^^^^^^^^^^^^^^^^^^^^^^
|
||||
-----------------------
|
||||
|
||||
These options are part of the ``cachedb:`` section.
|
||||
|
||||
The Cache DB module must be configured in the
|
||||
:ref:`module-config<unbound.conf.module-config>` directive, e.g.:
|
||||
@@ -4400,7 +4631,7 @@ If connection close or timeout happens too often, Unbound will be effectively
|
||||
unusable with this backend.
|
||||
It's the administrator's responsibility to make the assumption hold.
|
||||
|
||||
The **cachedb:** clause gives custom settings of the cache DB module.
|
||||
The ``cachedb:`` section gives custom settings of the cache DB module.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.cachedb@backend@@: *<backend name>*
|
||||
@@ -4448,7 +4679,7 @@ The **cachedb:** clause gives custom settings of the cache DB module.
|
||||
|
||||
Default: yes
|
||||
|
||||
The following **cachedb:** options are specific to the ``redis`` backend.
|
||||
The following ``cachedb:`` options are specific to the ``redis`` backend.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.cachedb@redis-server-host@@: *<server address or name>*
|
||||
@@ -4607,11 +4838,14 @@ The following **cachedb:** options are specific to the ``redis`` backend.
|
||||
|
||||
.. _unbound.conf.dnstap:
|
||||
|
||||
DNSTAP Logging Options
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
DNSTAP Options
|
||||
--------------
|
||||
|
||||
DNSTAP support, when compiled in by using ``--enable-dnstap``, is enabled in
|
||||
the **dnstap:** section.
|
||||
These options are part of the ``dnstap:`` section.
|
||||
|
||||
DNSTAP is a flexible, structured binary log format for DNS software.
|
||||
When compiled in by using ``--enable-dnstap``, it can be enabled in the
|
||||
``dnstap:`` section.
|
||||
This starts an extra thread (when compiled with threading) that writes the log
|
||||
information to the destination.
|
||||
If Unbound is compiled without threading it does not spawn a thread, but
|
||||
@@ -4761,15 +4995,18 @@ connects per-process to the destination.
|
||||
.. _unbound.conf.rpz:
|
||||
|
||||
Response Policy Zone Options
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
----------------------------
|
||||
|
||||
Response Policy Zones are configured with **rpz:**, and each one must have a
|
||||
:ref:`name<unbound.conf.rpz.name>` attribute.
|
||||
There can be multiple ones, by listing multiple RPZ clauses, each with a
|
||||
different name.
|
||||
RPZ clauses are applied in order of configuration and any match from an earlier
|
||||
RPZ zone will terminate the RPZ lookup.
|
||||
These options are part of the ``rpz:`` section.
|
||||
|
||||
Response Policy Zones are configured with ``rpz:`` section clauses, and each
|
||||
one must have a :ref:`name<unbound.conf.rpz.name>` option.
|
||||
There can be multiple ones, by listing multiple ``rpz:`` section clauses, each
|
||||
with a different name.
|
||||
RPZ sections are applied in order of configuration and any match from an
|
||||
earlier RPZ zone will terminate the RPZ lookup.
|
||||
Note that a PASSTHRU action is still considered a match.
|
||||
|
||||
The respip module needs to be added to the
|
||||
:ref:`module-config<unbound.conf.module-config>`, e.g.:
|
||||
|
||||
@@ -4777,6 +5014,13 @@ The respip module needs to be added to the
|
||||
|
||||
module-config: "respip validator iterator"
|
||||
|
||||
.. note::
|
||||
If combining the ``respip`` and ``dns64`` modules, the ``respip`` module
|
||||
needs to appear before the ``dns64`` module in the
|
||||
:ref:`module-config<unbound.conf.module-config>`
|
||||
configuration option so that response IP and/or RPZ feeds can properly
|
||||
filter responses regardless of DNS64 synthesis.
|
||||
|
||||
QNAME, Response IP Address, nsdname, nsip and clientip triggers are supported.
|
||||
Supported actions are: NXDOMAIN, NODATA, PASSTHRU, DROP, Local Data, tcp-only
|
||||
and drop.
|
||||
@@ -4828,9 +5072,6 @@ The actions are specified with the record on the right
|
||||
Other records like AAAA, TXT and other CNAMEs (not rpz-..) can also be used to
|
||||
answer queries with that content.
|
||||
|
||||
The RPZ zones can be configured in the config file with these settings in the
|
||||
**rpz:** block.
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.rpz@name@@: *<zone name>*
|
||||
Name of the authority zone.
|
||||
@@ -4946,7 +5187,7 @@ The RPZ zones can be configured in the config file with these settings in the
|
||||
|
||||
|
||||
@@UAHL@unbound.conf.rpz@tags@@: *"<list of tags>"*
|
||||
Limit the policies from this RPZ clause to clients with a matching tag.
|
||||
Limit the policies from this RPZ section to clients with a matching tag.
|
||||
|
||||
Tags need to be defined in :ref:`define-tag<unbound.conf.define-tag>` and
|
||||
can be assigned to client addresses using
|
||||
@@ -4954,7 +5195,7 @@ The RPZ zones can be configured in the config file with these settings in the
|
||||
:ref:`interface-tag<unbound.conf.interface-tag>`.
|
||||
Enclose list of tags in quotes (``""``) and put spaces between tags.
|
||||
|
||||
If no tags are specified the policies from this clause will be applied for
|
||||
If no tags are specified the policies from this section will be applied for
|
||||
all clients.
|
||||
|
||||
Memory Control Example
|
||||
|
||||
+1
-1
@@ -42,7 +42,7 @@ unbound(8)
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
**unbound** [``-hdpv``] [``-c <cfgfile>``]
|
||||
**unbound** [``-hdpVv``] [``-c <cfgfile>``]
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
+99
-5
@@ -70,6 +70,7 @@ subnet_data_delete(void *d, void *ATTR_UNUSED(arg))
|
||||
r = (struct subnet_msg_cache_data*)d;
|
||||
addrtree_delete(r->tree4);
|
||||
addrtree_delete(r->tree6);
|
||||
free(r->reason_fail);
|
||||
free(r);
|
||||
}
|
||||
|
||||
@@ -84,6 +85,8 @@ msg_cache_sizefunc(void *k, void *d)
|
||||
+ q->key.qname_len + lock_get_mem(&q->entry.lock);
|
||||
s += addrtree_size(r->tree4);
|
||||
s += addrtree_size(r->tree6);
|
||||
if(r->reason_fail)
|
||||
s += strlen(r->reason_fail)+1;
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -162,8 +165,15 @@ int ecs_whitelist_check(struct query_info* qinfo,
|
||||
if(!ecs_is_whitelisted(sn_env->whitelist,
|
||||
addr, addrlen, qinfo->qname, qinfo->qname_len,
|
||||
qinfo->qclass)) {
|
||||
verbose(VERB_ALGO, "subnet store subquery global, name and addr have no subnet treatment.");
|
||||
qstate->no_cache_store = 0;
|
||||
/* The stub or forward can have no_cache set.*/
|
||||
if(iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) {
|
||||
verbose(VERB_ALGO, "subnet subquery is not stored globally, stuborfwd is no_cache");
|
||||
} else {
|
||||
verbose(VERB_ALGO, "subnet store subquery global, name and addr have no subnet treatment.%s",
|
||||
(sq->started_no_cache_store?
|
||||
" But the subnet module was started with no_cache_store for the super query, and that is still applied to this query":""));
|
||||
qstate->no_cache_store = sq->started_no_cache_store;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
@@ -193,12 +203,18 @@ int ecs_whitelist_check(struct query_info* qinfo,
|
||||
if(sq->ecs_server_out.subnet_source_mask == 0) {
|
||||
sq->subnet_sent_no_subnet = 1;
|
||||
sq->subnet_sent = 0;
|
||||
/* The result should end up in subnet cache,
|
||||
* not in global cache. */
|
||||
qstate->no_cache_store = 1;
|
||||
return 1;
|
||||
}
|
||||
subnet_ecs_opt_list_append(&sq->ecs_server_out,
|
||||
&qstate->edns_opts_back_out, qstate, region);
|
||||
}
|
||||
sq->subnet_sent = 1;
|
||||
/* Do not store servfails in global cache, since the subnet
|
||||
* option is sent out. */
|
||||
qstate->no_cache_store = 1;
|
||||
}
|
||||
else {
|
||||
/* Outgoing ECS option is set, but we don't want to sent it to
|
||||
@@ -420,6 +436,35 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
}
|
||||
/* lru_entry->lock is locked regardless of how we got here,
|
||||
* either from the slabhash_lookup, or above in the new allocated */
|
||||
if(!qstate->return_msg && qstate->error_response_cache) {
|
||||
struct subnet_msg_cache_data *data =
|
||||
(struct subnet_msg_cache_data*)lru_entry->data;
|
||||
data->ttl_servfail = *qstate->env->now + NORR_TTL;
|
||||
data->ede_fail = errinf_to_reason_bogus(qstate);
|
||||
diff_size = (data->reason_fail?strlen(data->reason_fail)+1:0);
|
||||
if(qstate->errinf) {
|
||||
char* str = errinf_to_str_misc(qstate);
|
||||
free(data->reason_fail);
|
||||
data->reason_fail = NULL;
|
||||
if(str)
|
||||
data->reason_fail = strdup(str);
|
||||
}
|
||||
diff_size = (data->reason_fail?strlen(data->reason_fail)+1:0)
|
||||
- diff_size;
|
||||
lock_rw_unlock(&lru_entry->lock);
|
||||
if (need_to_insert) {
|
||||
slabhash_insert(subnet_msg_cache, h, lru_entry,
|
||||
lru_entry->data, NULL);
|
||||
} else {
|
||||
slabhash_update_space_used(subnet_msg_cache, h, NULL,
|
||||
diff_size);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if(!qstate->return_msg) {
|
||||
lock_rw_unlock(&lru_entry->lock);
|
||||
return;
|
||||
}
|
||||
/* Step 2, find the correct tree */
|
||||
if (!(tree = get_tree(lru_entry->data, edns, sne, qstate->env->cfg))) {
|
||||
lock_rw_unlock(&lru_entry->lock);
|
||||
@@ -463,6 +508,21 @@ update_cache(struct module_qstate *qstate, int id)
|
||||
}
|
||||
}
|
||||
|
||||
/** See if there is a stored servfail, returns true if so, and sets reply. */
|
||||
static int
|
||||
lookup_check_servfail(struct module_qstate *qstate,
|
||||
struct subnet_msg_cache_data *data)
|
||||
{
|
||||
struct module_env *env = qstate->env;
|
||||
if(!data)
|
||||
return 0;
|
||||
if(!data->ttl_servfail || TTL_IS_EXPIRED(data->ttl_servfail, *env->now))
|
||||
return 0;
|
||||
qstate->return_rcode = LDNS_RCODE_SERVFAIL;
|
||||
errinf_ede(qstate, data->reason_fail, data->ede_fail);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** Lookup in cache and reply true iff reply is sent. */
|
||||
static int
|
||||
lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq, int prefetch)
|
||||
@@ -476,6 +536,8 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
|
||||
struct addrtree *tree;
|
||||
struct addrnode *node;
|
||||
uint8_t scope;
|
||||
int must_validate = (!(qstate->query_flags&BIT_CD)
|
||||
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
|
||||
|
||||
memset(&sq->ecs_client_out, 0, sizeof(sq->ecs_client_out));
|
||||
|
||||
@@ -489,12 +551,20 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
|
||||
tree = (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4)?
|
||||
data->tree4 : data->tree6;
|
||||
if (!tree) { /* qinfo in cache but not for this family */
|
||||
if(lookup_check_servfail(qstate, data)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 1;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
node = addrtree_find(tree, (addrkey_t*)ecs->subnet_addr,
|
||||
ecs->subnet_source_mask, *env->now);
|
||||
if (!node) { /* plain old cache miss */
|
||||
if(lookup_check_servfail(qstate, data)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 1;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -503,12 +573,24 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
|
||||
(struct reply_info *)node->elem, qstate->region, *env->now, 0,
|
||||
env->scratch);
|
||||
scope = (uint8_t)node->scope;
|
||||
lock_rw_unlock(&e->lock);
|
||||
|
||||
if (!qstate->return_msg) { /* Failed allocation or expired TTL */
|
||||
if(lookup_check_servfail(qstate, data)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 1;
|
||||
}
|
||||
lock_rw_unlock(&e->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
lock_rw_unlock(&e->lock);
|
||||
if(qstate->return_msg->rep->security == sec_status_unchecked
|
||||
&& must_validate) {
|
||||
/* The message has to be validated first. */
|
||||
verbose(VERB_ALGO, "subnet: unchecked cache entry needs "
|
||||
"validation");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (sq->subnet_downstream) { /* relay to interested client */
|
||||
sq->ecs_client_out.subnet_scope_mask = scope;
|
||||
sq->ecs_client_out.subnet_addr_fam = ecs->subnet_addr_fam;
|
||||
@@ -563,7 +645,10 @@ generate_sub_request(struct module_qstate *qstate, int id, struct subnet_qstate*
|
||||
qflags |= BIT_RD;
|
||||
if((qstate->query_flags & BIT_CD)!=0) {
|
||||
qflags |= BIT_CD;
|
||||
valrec = 1;
|
||||
/* The valrec is left off. Leave out: valrec = 1;
|
||||
* So that the cache is protected with DNSSEC validation.
|
||||
* Just like the global cache. DNSSEC validation is performed
|
||||
* regardless of the setting of the querier's CD flag. */
|
||||
}
|
||||
|
||||
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
|
||||
@@ -580,6 +665,7 @@ generate_sub_request(struct module_qstate *qstate, int id, struct subnet_qstate*
|
||||
}
|
||||
subsq = (struct subnet_qstate*)subq->minfo[id];
|
||||
subsq->is_subquery_nonsubnet = 1;
|
||||
subsq->started_no_cache_store = sq->started_no_cache_store;
|
||||
|
||||
/* When the client asks 0.0.0.0/0 and the name is not treated
|
||||
* as subnet, it is to be stored in the global cache.
|
||||
@@ -632,6 +718,12 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
|
||||
/* already an answer and its not a message, but retain
|
||||
* the actual rcode, instead of module_error, so send
|
||||
* module_finished */
|
||||
if(qstate->error_response_cache) {
|
||||
verbose(VERB_ALGO, "subnet: store error response");
|
||||
lock_rw_wrlock(&sne->biglock);
|
||||
update_cache(qstate, id);
|
||||
lock_rw_unlock(&sne->biglock);
|
||||
}
|
||||
return module_finished;
|
||||
}
|
||||
|
||||
@@ -881,9 +973,11 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id,
|
||||
sq->max_scope = sq->ecs_server_in.subnet_scope_mask;
|
||||
} else if(sq->subnet_sent_no_subnet) {
|
||||
/* The answer can be stored as scope 0, not in global cache. */
|
||||
/* This was already set in ecs_whitelist_check */
|
||||
qstate->no_cache_store = 1;
|
||||
} else if(sq->subnet_sent) {
|
||||
/* Need another query to be able to store in global cache. */
|
||||
/* This was already set in ecs_whitelist_check */
|
||||
qstate->no_cache_store = 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -69,8 +69,18 @@ struct subnet_env {
|
||||
};
|
||||
|
||||
struct subnet_msg_cache_data {
|
||||
/** Tree for nodes with IPv4 subnets. */
|
||||
struct addrtree* tree4;
|
||||
/** Tree for nodes with IPv6 subnets. */
|
||||
struct addrtree* tree6;
|
||||
/** If servfail is stored, for how long. Abs time in seconds.
|
||||
* This protects against too much recusion on the item when
|
||||
* resolution fails, for a couple of seconds. */
|
||||
time_t ttl_servfail;
|
||||
/** servfail ede */
|
||||
sldns_ede_code ede_fail;
|
||||
/** servfail reason */
|
||||
char* reason_fail;
|
||||
};
|
||||
|
||||
struct subnet_qstate {
|
||||
|
||||
@@ -132,6 +132,18 @@ donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
|
||||
if(cfg->do_ip6) {
|
||||
if(!donotq_str_cfg(dq, "::1"))
|
||||
return 0;
|
||||
if(!donotq_str_cfg(dq, "::ffff:127.0.0.0/104"))
|
||||
return 0;
|
||||
}
|
||||
/* RFC 1122 3.2.1.3 / RFC 6890 / RFC 4291 2.5.2: not valid as
|
||||
* destination; on Linux these route to the local host. */
|
||||
if(!donotq_str_cfg(dq, "0.0.0.0/8"))
|
||||
return 0;
|
||||
if(cfg->do_ip6) {
|
||||
if(!donotq_str_cfg(dq, "::"))
|
||||
return 0;
|
||||
if(!donotq_str_cfg(dq, "::ffff:0:0/96"))
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
addr_tree_init_parents(&dq->tree);
|
||||
|
||||
@@ -228,6 +228,11 @@ read_fwds_host(struct config_stub* s, struct delegpt* dp)
|
||||
s->name, p->str);
|
||||
return 0;
|
||||
}
|
||||
if(dname_subdomain_c(dname, dp->name)) {
|
||||
log_warn("forward-host '%s' may have a circular "
|
||||
"dependency on forward-zone '%s'",
|
||||
p->str, s->name);
|
||||
}
|
||||
#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
|
||||
if(tls_auth_name)
|
||||
log_err("no name verification functionality in "
|
||||
|
||||
@@ -231,6 +231,11 @@ read_stubs_host(struct config_stub* s, struct delegpt* dp)
|
||||
s->name, p->str);
|
||||
return 0;
|
||||
}
|
||||
if(dname_subdomain_c(dname, dp->name)) {
|
||||
log_warn("stub-host '%s' may have a circular "
|
||||
"dependency on stub-zone '%s'",
|
||||
p->str, s->name);
|
||||
}
|
||||
#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
|
||||
if(tls_auth_name)
|
||||
log_err("no name verification functionality in "
|
||||
|
||||
+167
-1
@@ -207,6 +207,168 @@ size_t priv_get_mem(struct iter_priv* priv)
|
||||
return sizeof(*priv) + regional_get_mem(priv->region);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if svcparam ipv4hint contains a private address.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param d: the data bytes.
|
||||
* @param data_len: number of data bytes in the svcparam.
|
||||
* @param addr: address to return the private address to log in to.
|
||||
* It has space for IPv4 and IPv6 addresses.
|
||||
* @param addrlen: length of the addr. Returns the correct size for the addr.
|
||||
* @return true if the rdata contains a private address.
|
||||
*/
|
||||
static int svcb_ipv4hint_contains_priv_addr(struct iter_priv* priv,
|
||||
uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
struct sockaddr_in sa;
|
||||
*addrlen = (socklen_t)sizeof(struct sockaddr_in);
|
||||
memset(&sa, 0, sizeof(struct sockaddr_in));
|
||||
sa.sin_family = AF_INET;
|
||||
sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
|
||||
while(data_len >= LDNS_IP4ADDRLEN) {
|
||||
memmove(&sa.sin_addr, d, LDNS_IP4ADDRLEN);
|
||||
memmove(addr, &sa, *addrlen);
|
||||
if(priv_lookup_addr(priv, addr, *addrlen))
|
||||
return 1;
|
||||
|
||||
d += LDNS_IP4ADDRLEN;
|
||||
data_len -= LDNS_IP4ADDRLEN;
|
||||
}
|
||||
/* if data_len != 0 here, then the svcparam is malformed. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if svcparam ipv6hint contains a private address.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param d: the data bytes.
|
||||
* @param data_len: number of data bytes in the svcparam.
|
||||
* @param addr: address to return the private address to log in to.
|
||||
* It has space for IPv4 and IPv6 addresses.
|
||||
* @param addrlen: length of the addr. Returns the correct size for the addr.
|
||||
* @return true if the rdata contains a private address.
|
||||
*/
|
||||
static int svcb_ipv6hint_contains_priv_addr(struct iter_priv* priv,
|
||||
uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
struct sockaddr_in6 sa;
|
||||
*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
|
||||
memset(&sa, 0, sizeof(struct sockaddr_in6));
|
||||
sa.sin6_family = AF_INET6;
|
||||
sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
|
||||
|
||||
while(data_len >= LDNS_IP6ADDRLEN) {
|
||||
memmove(&sa.sin6_addr, d, LDNS_IP6ADDRLEN);
|
||||
memmove(addr, &sa, *addrlen);
|
||||
if(priv_lookup_addr(priv, addr, *addrlen))
|
||||
return 1;
|
||||
|
||||
d += LDNS_IP6ADDRLEN;
|
||||
data_len -= LDNS_IP6ADDRLEN;
|
||||
}
|
||||
/* if data_len != 0 here, then the svcparam is malformed. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if type SVCB and HTTPS rdata contains a private address.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param pkt: the packet.
|
||||
* @param rr: the rr with rdata to check.
|
||||
* @param addr: address to return the private address to log in to.
|
||||
* @param addrlen: length of the addr. Initially the total size, on
|
||||
* return the correct size for the addr.
|
||||
* @return true if the rdata contains a private address.
|
||||
*/
|
||||
static int svcb_rr_contains_priv_addr(struct iter_priv* priv,
|
||||
sldns_buffer* pkt, struct rr_parse* rr, struct sockaddr_storage* addr,
|
||||
socklen_t* addrlen)
|
||||
{
|
||||
uint8_t* d = rr->ttl_data;
|
||||
uint16_t svcparamkey, data_len, rdatalen;
|
||||
size_t oldpos, dname_len, dname_start, dname_compr_len;
|
||||
d += 4; /* skip TTL */
|
||||
rdatalen = sldns_read_uint16(d); /* read rdata length */
|
||||
d += 2;
|
||||
|
||||
if(rdatalen < 2 /* priority */ + 1 /* 1 length target */)
|
||||
return 0; /* malformed, too short */
|
||||
d += 2; /* skip priority */
|
||||
rdatalen -= 2;
|
||||
oldpos = sldns_buffer_position(pkt);
|
||||
sldns_buffer_set_position(pkt, (size_t)(d - sldns_buffer_begin(pkt)));
|
||||
dname_start = sldns_buffer_position(pkt);
|
||||
dname_len = pkt_dname_len(pkt);
|
||||
dname_compr_len = sldns_buffer_position(pkt) - dname_start;
|
||||
sldns_buffer_set_position(pkt, oldpos);
|
||||
if(dname_len == 0)
|
||||
return 0; /* dname malformed */
|
||||
if(dname_compr_len > rdatalen)
|
||||
return 0; /* malformed */
|
||||
d += dname_compr_len; /* skip target */
|
||||
rdatalen -= dname_compr_len;
|
||||
|
||||
while(rdatalen >= 4) {
|
||||
svcparamkey = sldns_read_uint16(d);
|
||||
data_len = sldns_read_uint16(d+2);
|
||||
d += 4;
|
||||
rdatalen -= 4;
|
||||
|
||||
/* verify that we have data_len data */
|
||||
if(data_len > rdatalen) {
|
||||
/* It is malformed, but if there are addresses
|
||||
* in there it can be rejected. */
|
||||
data_len = rdatalen;
|
||||
}
|
||||
|
||||
if(!data_len)
|
||||
continue; /* no data for the svcparamkey */
|
||||
|
||||
if(svcparamkey == SVCB_KEY_IPV4HINT) {
|
||||
if(svcb_ipv4hint_contains_priv_addr(priv, d, data_len,
|
||||
addr, addrlen))
|
||||
return 1;
|
||||
} else if(svcparamkey == SVCB_KEY_IPV6HINT) {
|
||||
if(svcb_ipv6hint_contains_priv_addr(priv, d, data_len,
|
||||
addr, addrlen))
|
||||
return 1;
|
||||
}
|
||||
d += data_len;
|
||||
rdatalen -= data_len;
|
||||
}
|
||||
/* If rdatalen != 0 here, then the svcb rdata is malformed. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the SVCB and HTTPS rrset is bad.
|
||||
* @param priv: private address lookup struct.
|
||||
* @param pkt: the packet.
|
||||
* @param rrset: the rrset to check.
|
||||
* @return 1 if the entire rrset has to be removed. 0 if not.
|
||||
* It removes RRs if they have private addresses, and log that.
|
||||
*/
|
||||
static int priv_svcb_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
struct rrset_parse* rrset)
|
||||
{
|
||||
struct rr_parse* rr, *prev = NULL;
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen = (socklen_t)sizeof(addr);
|
||||
for(rr = rrset->rr_first; rr; rr = rr->next) {
|
||||
if(svcb_rr_contains_priv_addr(priv, pkt, rr, &addr,
|
||||
&addrlen)) {
|
||||
if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, addrlen))
|
||||
return 1;
|
||||
continue;
|
||||
}
|
||||
prev = rr;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
struct rrset_parse* rrset)
|
||||
{
|
||||
@@ -268,7 +430,11 @@ int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
|
||||
}
|
||||
prev = rr;
|
||||
}
|
||||
}
|
||||
} else if(rrset->type == LDNS_RR_TYPE_SVCB ||
|
||||
rrset->type == LDNS_RR_TYPE_HTTPS) {
|
||||
if(priv_svcb_rrset_bad(priv, pkt, rrset))
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
+121
-12
@@ -285,6 +285,17 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
|
||||
return NULL;
|
||||
memmove(cn->rr_first->ttl_data, rrset->rr_first->ttl_data,
|
||||
sizeof(uint32_t)); /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
/* Apply cache TTL policy so DNAME and synthesized CNAME stay equal
|
||||
* and respect cache-min-ttl/cache-max-ttl (same as rdata_copy path). */
|
||||
if(!SERVE_ORIGINAL_TTL) {
|
||||
uint32_t ttl = sldns_read_uint32(cn->rr_first->ttl_data);
|
||||
time_t ttl_t = (time_t)ttl;
|
||||
if(ttl_t < MIN_TTL) ttl_t = MIN_TTL;
|
||||
if(ttl_t > MAX_TTL) ttl_t = MAX_TTL;
|
||||
ttl = (uint32_t)ttl_t;
|
||||
sldns_write_uint32(cn->rr_first->ttl_data, ttl);
|
||||
sldns_write_uint32(rrset->rr_first->ttl_data, ttl);
|
||||
}
|
||||
sldns_write_uint16(cn->rr_first->ttl_data+4, aliaslen);
|
||||
memmove(cn->rr_first->ttl_data+6, alias, aliaslen);
|
||||
cn->rr_first->size = sizeof(uint16_t)+aliaslen;
|
||||
@@ -408,6 +419,43 @@ shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
|
||||
else rrset->rr_first = NULL;
|
||||
}
|
||||
|
||||
/** Shorten RRSIGs list */
|
||||
static void
|
||||
shorten_rrsig(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
|
||||
{
|
||||
/* The too large list of RRSIGs on the RRset is shortened.
|
||||
* This is so that too large content does not overwhelm the cache.
|
||||
* The validator does not validate more than a max number of
|
||||
* RRSIGs as well. */
|
||||
int i;
|
||||
struct rr_parse* rr = rrset->rrsig_first, *prev = NULL;
|
||||
if(!rr)
|
||||
return;
|
||||
for(i=0; i<count; i++) {
|
||||
prev = rr;
|
||||
rr = rr->next;
|
||||
if(!rr)
|
||||
return; /* The RRSIG list is already short. */
|
||||
}
|
||||
if(verbosity >= VERB_QUERY
|
||||
&& rrset->dname_len <= LDNS_MAX_DOMAINLEN) {
|
||||
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
|
||||
dname_pkt_copy(pkt, buf, rrset->dname);
|
||||
log_nametypeclass(VERB_QUERY, "normalize: shorten RRSIGs:",
|
||||
buf, rrset->type, ntohs(rrset->rrset_class));
|
||||
}
|
||||
/* remove further rrsigs */
|
||||
rrset->rrsig_last = prev;
|
||||
rrset->rrsig_count = count;
|
||||
while(rr) {
|
||||
rrset->size -= rr->size;
|
||||
rr = rr->next;
|
||||
}
|
||||
if(rrset->rrsig_last)
|
||||
rrset->rrsig_last->next = NULL;
|
||||
else rrset->rrsig_first = NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* This routine normalizes a response. This includes removing "irrelevant"
|
||||
* records from the answer and additional sections and (re)synthesizing
|
||||
@@ -418,12 +466,13 @@ shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
|
||||
* @param qinfo: original query.
|
||||
* @param region: where to allocate synthesized CNAMEs.
|
||||
* @param env: module env with config options.
|
||||
* @param zonename: name of server zone.
|
||||
* @return 0 on error.
|
||||
*/
|
||||
static int
|
||||
scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
struct query_info* qinfo, struct regional* region,
|
||||
struct module_env* env)
|
||||
struct module_env* env, uint8_t* zonename)
|
||||
{
|
||||
uint8_t* sname = qinfo->qname;
|
||||
size_t snamelen = qinfo->qname_len;
|
||||
@@ -431,7 +480,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
int cname_length = 0; /* number of CNAMEs, or DNAMEs */
|
||||
|
||||
if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR &&
|
||||
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN)
|
||||
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN &&
|
||||
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_YXDOMAIN)
|
||||
return 1;
|
||||
|
||||
/* For the ANSWER section, remove all "irrelevant" records and add
|
||||
@@ -443,6 +493,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
prev = NULL;
|
||||
rrset = msg->rrset_first;
|
||||
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
|
||||
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
|
||||
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
|
||||
if(cname_length > env->cfg->iter_scrub_cname) {
|
||||
/* Too many CNAMEs, or DNAMEs, from the authority
|
||||
* server, scrub down the length to something
|
||||
@@ -453,8 +505,9 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(rrset->type == LDNS_RR_TYPE_DNAME &&
|
||||
pkt_strict_sub(pkt, sname, rrset->dname)) {
|
||||
if(rrset->type == LDNS_RR_TYPE_DNAME &&
|
||||
pkt_strict_sub(pkt, sname, rrset->dname) &&
|
||||
pkt_sub(pkt, rrset->dname, zonename)) {
|
||||
/* check if next rrset is correct CNAME. else,
|
||||
* synthesize a CNAME */
|
||||
struct rrset_parse* nx = rrset->rrset_all_next;
|
||||
@@ -470,6 +523,11 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
&aliaslen, pkt)) {
|
||||
verbose(VERB_ALGO, "synthesized CNAME "
|
||||
"too long");
|
||||
if(FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_YXDOMAIN) {
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
cname_length++;
|
||||
@@ -495,8 +553,6 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
log_err("out of memory synthesizing CNAME");
|
||||
return 0;
|
||||
}
|
||||
/* FIXME: resolve the conflict between synthesized
|
||||
* CNAME ttls and the cache. */
|
||||
rrset = nx;
|
||||
continue;
|
||||
|
||||
@@ -518,7 +574,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
if(nx && nx->section == LDNS_SECTION_ANSWER &&
|
||||
nx->type == LDNS_RR_TYPE_DNAME &&
|
||||
nx->rr_count == 1 &&
|
||||
pkt_strict_sub(pkt, sname, nx->dname)) {
|
||||
pkt_strict_sub(pkt, sname, nx->dname) &&
|
||||
pkt_sub(pkt, nx->dname, zonename)) {
|
||||
/* there is a DNAME after this CNAME, it
|
||||
* is in the ANSWER section, and the DNAME
|
||||
* applies to the name we cover */
|
||||
@@ -613,6 +670,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
|
||||
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
|
||||
/* only one NS set allowed in authority section */
|
||||
if(rrset->type==LDNS_RR_TYPE_NS) {
|
||||
/* NS set must be pertinent to the query */
|
||||
@@ -634,6 +693,45 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
/* If the NS set is a promiscuous NS set, scrub that
|
||||
* to remove potential for poisonous contents that
|
||||
* affects other names in the same zone. Remove
|
||||
* promiscuous NS sets in positive answers, that
|
||||
* thus have records in the answer section. Nodata
|
||||
* and nxdomain promiscuous NS sets have been removed
|
||||
* already. Since the NS rrset is scrubbed, its
|
||||
* address records are also not marked to be allowed
|
||||
* and are removed later. */
|
||||
if(FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR &&
|
||||
msg->an_rrsets != 0 &&
|
||||
env->cfg->iter_scrub_promiscuous) {
|
||||
remove_rrset("normalize: removing promiscuous "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
/* Also delete promiscuous NS for other RCODEs */
|
||||
if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR
|
||||
&& env->cfg->iter_scrub_promiscuous) {
|
||||
remove_rrset("normalize: removing promiscuous "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
/* Also delete promiscuous NS for NOERROR with nodata
|
||||
* for authoritative answers, not for delegations.
|
||||
* NOERROR with an_rrsets!=0 already handled.
|
||||
* Also NOERROR and soa_in_auth already handled.
|
||||
* NOERROR with an_rrsets==0, and not a referral.
|
||||
* referral is (NS not the zonename, noSOA).
|
||||
*/
|
||||
if(FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR
|
||||
&& msg->an_rrsets == 0
|
||||
&& !(dname_pkt_compare(pkt, rrset->dname,
|
||||
zonename) != 0 && !soa_in_auth(msg))
|
||||
&& env->cfg->iter_scrub_promiscuous) {
|
||||
remove_rrset("normalize: removing promiscuous "
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if(nsset == NULL) {
|
||||
nsset = rrset;
|
||||
} else {
|
||||
@@ -679,7 +777,13 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
rrset->rrset_all_next = NULL;
|
||||
return 1;
|
||||
}
|
||||
mark_additional_rrset(pkt, msg, rrset);
|
||||
/* Only mark glue as allowed for type NS in the authority
|
||||
* section. Other RR types do not get glue for them, it
|
||||
* is allowed from the answer section, but not authority
|
||||
* so that a message can not have address records cached
|
||||
* as a side effect to the query. */
|
||||
if(rrset->type==LDNS_RR_TYPE_NS)
|
||||
mark_additional_rrset(pkt, msg, rrset);
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
@@ -716,6 +820,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
"RRset:", pkt, msg, prev, &rrset);
|
||||
continue;
|
||||
}
|
||||
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
|
||||
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
|
||||
prev = rrset;
|
||||
rrset = rrset->rrset_all_next;
|
||||
}
|
||||
@@ -926,8 +1032,10 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
}
|
||||
|
||||
/* remove private addresses */
|
||||
if( (rrset->type == LDNS_RR_TYPE_A ||
|
||||
rrset->type == LDNS_RR_TYPE_AAAA)) {
|
||||
if(rrset->type == LDNS_RR_TYPE_A ||
|
||||
rrset->type == LDNS_RR_TYPE_AAAA ||
|
||||
rrset->type == LDNS_RR_TYPE_SVCB ||
|
||||
rrset->type == LDNS_RR_TYPE_HTTPS) {
|
||||
|
||||
/* do not set servfail since this leads to too
|
||||
* many drops of other people using rfc1918 space */
|
||||
@@ -1044,7 +1152,8 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
/* this is not required for basic operation but is a forgery
|
||||
* resistance (security) feature */
|
||||
if((FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NOERROR ||
|
||||
FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NXDOMAIN) &&
|
||||
FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_NXDOMAIN ||
|
||||
FLAGS_GET_RCODE(msg->flags) == LDNS_RCODE_YXDOMAIN) &&
|
||||
msg->qdcount == 0)
|
||||
return 0;
|
||||
|
||||
@@ -1058,7 +1167,7 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
|
||||
}
|
||||
|
||||
/* normalize the response, this cleans up the additional. */
|
||||
if(!scrub_normalize(pkt, msg, qinfo, region, env))
|
||||
if(!scrub_normalize(pkt, msg, qinfo, region, env, zonename))
|
||||
return 0;
|
||||
/* delete all out-of-zone information */
|
||||
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate))
|
||||
|
||||
+46
-4
@@ -253,7 +253,9 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** filter out unsuitable targets
|
||||
/** filter out unsuitable targets.
|
||||
* Applies NAT64 if needed as well by replacing the IPv4 with the synthesized
|
||||
* IPv6 address.
|
||||
* @param iter_env: iterator environment with ipv6-support flag.
|
||||
* @param env: module environment with infra cache.
|
||||
* @param name: zone name
|
||||
@@ -306,9 +308,30 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
|
||||
if(a->bogus)
|
||||
return -1; /* address of server is bogus */
|
||||
if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) {
|
||||
log_addr(VERB_ALGO, "skip addr on the donotquery list",
|
||||
&a->addr, a->addrlen);
|
||||
return -1; /* server is on the donotquery list */
|
||||
if(iter_env->nat64.use_nat64 &&
|
||||
addr_is_ip6(&a->addr, a->addrlen) &&
|
||||
a->addrlen == iter_env->nat64.nat64_prefix_addrlen &&
|
||||
addr_in_common(&a->addr, 128,
|
||||
&iter_env->nat64.nat64_prefix_addr,
|
||||
iter_env->nat64.nat64_prefix_net,
|
||||
iter_env->nat64.nat64_prefix_addrlen) ==
|
||||
iter_env->nat64.nat64_prefix_net) {
|
||||
/* The NAT64 is enabled, and address is IPv6, it is
|
||||
* in the NAT64 prefix. It is allowed.
|
||||
* So that in an IPv6-only cluster without internet
|
||||
* access, that makes the NAT64 translation continue
|
||||
* to work. The NAT64 prefix is allowed. */
|
||||
/* Otherwise, after a timeout, the already NAT64
|
||||
* translated address would be treated differently,
|
||||
* and that causes confusion. */
|
||||
log_addr(VERB_ALGO, "the addr is on the donotquery "
|
||||
"list, but allowed because it is NAT64",
|
||||
&a->addr, a->addrlen);
|
||||
} else {
|
||||
log_addr(VERB_ALGO, "skip addr on the donotquery list",
|
||||
&a->addr, a->addrlen);
|
||||
return -1; /* server is on the donotquery list */
|
||||
}
|
||||
}
|
||||
if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr, a->addrlen)) {
|
||||
return -1; /* there is no ip6 available */
|
||||
@@ -317,6 +340,20 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
|
||||
!addr_is_ip6(&a->addr, a->addrlen)) {
|
||||
return -1; /* there is no ip4 available */
|
||||
}
|
||||
if(iter_env->nat64.use_nat64 && !addr_is_ip6(&a->addr, a->addrlen)) {
|
||||
struct sockaddr_storage real_addr;
|
||||
socklen_t real_addrlen;
|
||||
addr_to_nat64(&a->addr, &iter_env->nat64.nat64_prefix_addr,
|
||||
iter_env->nat64.nat64_prefix_addrlen,
|
||||
iter_env->nat64.nat64_prefix_net,
|
||||
&real_addr, &real_addrlen);
|
||||
log_name_addr(VERB_QUERY, "NAT64 apply: from: ",
|
||||
name, &a->addr, a->addrlen);
|
||||
log_name_addr(VERB_QUERY, "NAT64 apply: to: ",
|
||||
name, &real_addr, real_addrlen);
|
||||
a->addr = real_addr;
|
||||
a->addrlen = real_addrlen;
|
||||
}
|
||||
/* check lameness - need zone , class info */
|
||||
if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen,
|
||||
name, namelen, qtype, &lame, &dnsseclame, &reclame,
|
||||
@@ -1511,6 +1548,11 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
|
||||
struct delegpt *dp;
|
||||
int nolock = 1;
|
||||
|
||||
log_assert((retdpname && retdpnamelen
|
||||
&& dpname_storage && dpname_storage_len > 0) ||
|
||||
(retdpname == NULL && retdpnamelen == NULL
|
||||
&& dpname_storage == NULL && dpname_storage_len == 0));
|
||||
|
||||
/* Check for stub. */
|
||||
/* Lock both forwards and hints for atomic read. */
|
||||
lock_rw_rdlock(&qstate->env->fwds->lock);
|
||||
|
||||
@@ -84,6 +84,7 @@ int iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg);
|
||||
/**
|
||||
* Select a valid, nice target to send query to.
|
||||
* Sorting and removing unsuitable targets is combined.
|
||||
* Adds records to the infra cache if not already there.
|
||||
*
|
||||
* @param iter_env: iterator module global state, with ip6 enabled and
|
||||
* do-not-query-addresses.
|
||||
|
||||
+65
-39
@@ -81,7 +81,8 @@ int BLACKLIST_PENALTY = (120000*4);
|
||||
/** Timeout when only a single probe query per IP is allowed. */
|
||||
int PROBE_MAXRTO = PROBE_MAXRTO_DEFAULT; /* in msec */
|
||||
|
||||
static void target_count_increase_nx(struct iter_qstate* iq, int num);
|
||||
static void target_count_increase_nx(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num);
|
||||
|
||||
int
|
||||
iter_init(struct module_env* env, int id)
|
||||
@@ -250,7 +251,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
|
||||
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) &&
|
||||
(dpns->got6 == 2 || !ie->supports_ipv6)) {
|
||||
dpns->resolved = 1; /* mark as failed */
|
||||
target_count_increase_nx(super_iq, 1);
|
||||
target_count_increase_nx(super, super_iq, 1);
|
||||
}
|
||||
}
|
||||
if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) {
|
||||
@@ -297,6 +298,7 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
|
||||
struct reply_info err;
|
||||
struct msgreply_entry* msg;
|
||||
if(qstate->no_cache_store) {
|
||||
qstate->error_response_cache = 1;
|
||||
return error_response(qstate, id, rcode);
|
||||
}
|
||||
if(qstate->prefetch_leeway > NORR_TTL) {
|
||||
@@ -733,7 +735,7 @@ is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq)
|
||||
* created for the parent query.
|
||||
*/
|
||||
static void
|
||||
target_count_create(struct iter_qstate* iq)
|
||||
target_count_create(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
{
|
||||
if(!iq->target_count) {
|
||||
iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int));
|
||||
@@ -741,33 +743,57 @@ target_count_create(struct iter_qstate* iq)
|
||||
if(iq->target_count) {
|
||||
iq->target_count[TARGET_COUNT_REF] = 1;
|
||||
iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*));
|
||||
/* continue global quota from where it was. */
|
||||
if(qstate->global_quota_reached >
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA])
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] =
|
||||
qstate->global_quota_reached;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase(struct iter_qstate* iq, int num)
|
||||
target_count_store(struct module_qstate* qstate, struct iter_qstate* iq)
|
||||
{
|
||||
target_count_create(iq);
|
||||
if(iq->target_count) {
|
||||
/* By storing the global quota counter, it stays
|
||||
* there to be picked up if the module is restarted,
|
||||
* eg. due to a validator retry, and then the
|
||||
* target_count_create routine picks it up. */
|
||||
if(iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] >
|
||||
qstate->global_quota_reached)
|
||||
qstate->global_quota_reached =
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA];
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(qstate, iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[TARGET_COUNT_QUERIES] += num;
|
||||
iq->dp_target_count++;
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase_nx(struct iter_qstate* iq, int num)
|
||||
target_count_increase_nx(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(iq);
|
||||
target_count_create(qstate, iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[TARGET_COUNT_NX] += num;
|
||||
}
|
||||
|
||||
static void
|
||||
target_count_increase_global_quota(struct iter_qstate* iq, int num)
|
||||
target_count_increase_global_quota(struct module_qstate* qstate,
|
||||
struct iter_qstate* iq, int num)
|
||||
{
|
||||
target_count_create(iq);
|
||||
target_count_create(qstate, iq);
|
||||
if(iq->target_count)
|
||||
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num;
|
||||
target_count_store(qstate, iq);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -860,7 +886,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
|
||||
subiq = (struct iter_qstate*)subq->minfo[id];
|
||||
memset(subiq, 0, sizeof(*subiq));
|
||||
subiq->num_target_queries = 0;
|
||||
target_count_create(iq);
|
||||
target_count_create(qstate, iq);
|
||||
subiq->target_count = iq->target_count;
|
||||
if(iq->target_count) {
|
||||
iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */
|
||||
@@ -2233,7 +2259,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += qs;
|
||||
target_count_increase(iq, qs);
|
||||
target_count_increase(qstate, iq, qs);
|
||||
if(qs != 0) {
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0; /* and wait for them */
|
||||
@@ -2289,7 +2315,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* lookups at a time. */
|
||||
verbose(VERB_ALGO, "try parent-side glue lookup");
|
||||
iq->num_target_queries += query_count;
|
||||
target_count_increase(iq, query_count);
|
||||
target_count_increase(qstate, iq, query_count);
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0;
|
||||
}
|
||||
@@ -2309,7 +2335,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
if(query_count != 0) { /* suspend to await results */
|
||||
verbose(VERB_ALGO, "try parent-side glue lookup");
|
||||
iq->num_target_queries += query_count;
|
||||
target_count_increase(iq, query_count);
|
||||
target_count_increase(qstate, iq, query_count);
|
||||
qstate->ext_state[id] = module_wait_subquery;
|
||||
return 0;
|
||||
}
|
||||
@@ -2436,8 +2462,6 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
int tf_policy;
|
||||
struct delegpt_addr* target;
|
||||
struct outbound_entry* outq;
|
||||
struct sockaddr_storage real_addr;
|
||||
socklen_t real_addrlen;
|
||||
int auth_fallback = 0;
|
||||
uint8_t* qout_orig = NULL;
|
||||
size_t qout_orig_len = 0;
|
||||
@@ -2789,7 +2813,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
if(iq->num_target_queries > 0) {
|
||||
/* wait to get all targets, we want to try em */
|
||||
verbose(VERB_ALGO, "wait for all targets for fallback");
|
||||
@@ -2840,7 +2864,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
/* errors ignored, these targets are not strictly necessary for
|
||||
* this result, we do not have to reply with SERVFAIL */
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
}
|
||||
|
||||
/* Add the current set of unused targets to our queue. */
|
||||
@@ -2963,7 +2987,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
iq->num_target_queries += qs;
|
||||
target_count_increase(iq, qs);
|
||||
target_count_increase(qstate, iq, qs);
|
||||
}
|
||||
/* Since a target query might have been made, we
|
||||
* need to check again. */
|
||||
@@ -3023,7 +3047,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* this result, we do not have to reply with SERVFAIL */
|
||||
if(extra > 0) {
|
||||
iq->num_target_queries += extra;
|
||||
target_count_increase(iq, extra);
|
||||
target_count_increase(qstate, iq, extra);
|
||||
check_waiting_queries(iq, qstate, id);
|
||||
/* undo qname minimise step because we'll get back here
|
||||
* to do it again */
|
||||
@@ -3036,7 +3060,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
}
|
||||
}
|
||||
|
||||
target_count_increase_global_quota(iq, 1);
|
||||
target_count_increase_global_quota(qstate, iq, 1);
|
||||
if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]
|
||||
> MAX_GLOBAL_QUOTA) {
|
||||
char s[LDNS_MAX_DOMAINLEN];
|
||||
@@ -3060,17 +3084,6 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iq->dnssec_lame_query?" but lame_query anyway": "");
|
||||
}
|
||||
|
||||
real_addr = target->addr;
|
||||
real_addrlen = target->addrlen;
|
||||
|
||||
if(ie->nat64.use_nat64 && target->addr.ss_family == AF_INET) {
|
||||
addr_to_nat64(&target->addr, &ie->nat64.nat64_prefix_addr,
|
||||
ie->nat64.nat64_prefix_addrlen, ie->nat64.nat64_prefix_net,
|
||||
&real_addr, &real_addrlen);
|
||||
log_name_addr(VERB_QUERY, "applied NAT64:",
|
||||
iq->dp->name, &real_addr, real_addrlen);
|
||||
}
|
||||
|
||||
fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query));
|
||||
outq = (*qstate->env->send_query)(&iq->qinfo_out,
|
||||
iq->chase_flags | (iq->chase_to_rd?BIT_RD:0),
|
||||
@@ -3082,7 +3095,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
!qstate->blacklist&&(!iter_qname_indicates_dnssec(qstate->env,
|
||||
&iq->qinfo_out)||target->attempts==1)?0:BIT_CD),
|
||||
iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
|
||||
ie, iq), sq_check_ratelimit, &real_addr, real_addrlen,
|
||||
ie, iq), sq_check_ratelimit, &target->addr, target->addrlen,
|
||||
iq->dp->name, iq->dp->namelen,
|
||||
(iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream),
|
||||
(iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream),
|
||||
@@ -3099,7 +3112,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
|
||||
}
|
||||
log_addr(VERB_QUERY, "error sending query to auth server",
|
||||
&real_addr, real_addrlen);
|
||||
&target->addr, target->addrlen);
|
||||
if(qstate->env->cfg->qname_minimisation)
|
||||
iq->minimisation_state = SKIP_MINIMISE_STATE;
|
||||
return next_state(iq, QUERYTARGETS_STATE);
|
||||
@@ -3236,8 +3249,19 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
} else iter_scrub_ds(iq->response, NULL, NULL);
|
||||
if(type == RESPONSE_TYPE_THROWAWAY &&
|
||||
FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_YXDOMAIN) {
|
||||
/* YXDOMAIN is a permanent error, no need to retry */
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
/* YXDOMAIN is a permanent error for DNAME expansion overflow
|
||||
* (RFC 6672 Section 2.2). Only accept if the response
|
||||
* contains a DNAME record in the answer section; otherwise
|
||||
* treat as invalid, to make sure the authoritative answer
|
||||
* make sense. */
|
||||
size_t i;
|
||||
for(i=0; i<iq->response->rep->an_numrrsets; i++) {
|
||||
if(ntohs(iq->response->rep->rrsets[i]->rk.type)
|
||||
== LDNS_RR_TYPE_DNAME) {
|
||||
type = RESPONSE_TYPE_ANSWER;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(type == RESPONSE_TYPE_CNAME)
|
||||
origtypecname = 1;
|
||||
@@ -3616,7 +3640,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
return next_state(iq, INIT_REQUEST_STATE);
|
||||
} else if(type == RESPONSE_TYPE_LAME) {
|
||||
/* Cache the LAMEness. */
|
||||
verbose(VERB_DETAIL, "query response was %sLAME",
|
||||
verbose(VERB_DETAIL, "query response was categorized as %sLAME",
|
||||
dnsseclame?"DNSSEC ":"");
|
||||
if(!dname_subdomain_c(iq->qchase.qname, iq->dp->name)) {
|
||||
log_err("mark lame: mismatch in qname and dpname");
|
||||
@@ -3655,7 +3679,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
* In this case, the event is just sent directly back to
|
||||
* the QUERYTARGETS_STATE without resetting anything,
|
||||
* because, clearly, the next target must be tried. */
|
||||
verbose(VERB_DETAIL, "query response was THROWAWAY");
|
||||
verbose(VERB_DETAIL, "query response was categorized as THROWAWAY");
|
||||
} else {
|
||||
log_warn("A query response came back with an unknown type: %d",
|
||||
(int)type);
|
||||
@@ -3880,7 +3904,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
||||
/* no new addresses, increase the nxns counter, like
|
||||
* this could be a list of wildcards with no new
|
||||
* addresses */
|
||||
target_count_increase_nx(foriq, 1);
|
||||
target_count_increase_nx(qstate, foriq, 1);
|
||||
}
|
||||
verbose(VERB_ALGO, "added target response");
|
||||
delegpt_log(VERB_ALGO, foriq->dp);
|
||||
@@ -3892,7 +3916,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
|
||||
dpns->resolved = 1; /* fail the target */
|
||||
/* do not count cached answers */
|
||||
if(qstate->reply_origin && qstate->reply_origin->len != 0) {
|
||||
target_count_increase_nx(foriq, 1);
|
||||
target_count_increase_nx(qstate, foriq, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4117,6 +4141,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
|
||||
iter_store_parentside_neg(qstate->env, &qstate->qinfo,
|
||||
iq->deleg_msg?iq->deleg_msg->rep:
|
||||
(iq->response?iq->response->rep:NULL));
|
||||
target_count_store(qstate, iq);
|
||||
if(!iq->response) {
|
||||
verbose(VERB_ALGO, "No response is set, servfail");
|
||||
errinf(qstate, "(no response found at query finish)");
|
||||
@@ -4532,6 +4557,7 @@ iter_clear(struct module_qstate* qstate, int id)
|
||||
iq = (struct iter_qstate*)qstate->minfo[id];
|
||||
if(iq) {
|
||||
outbound_list_clear(&iq->outlist);
|
||||
target_count_store(qstate, iq);
|
||||
if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) {
|
||||
free(iq->target_count);
|
||||
if(*iq->nxns_dp) free(*iq->nxns_dp);
|
||||
|
||||
+11
-2
@@ -105,6 +105,7 @@ libworker_delete_env(struct libworker* w)
|
||||
SSL_CTX_free(w->sslctx);
|
||||
#endif
|
||||
outside_network_delete(w->back);
|
||||
shared_ports_delete(w->shared_ports);
|
||||
}
|
||||
|
||||
/** delete libworker struct */
|
||||
@@ -219,17 +220,25 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
if(!(w->shared_ports = shared_ports_create(cfg->out_ifs,
|
||||
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, ports, numports))) {
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
}
|
||||
libworker_delete(w);
|
||||
return NULL;
|
||||
}
|
||||
w->back = outside_network_create(w->base, cfg->msg_buffer_size,
|
||||
(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
|
||||
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
|
||||
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
|
||||
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
|
||||
ports, numports, cfg->unwanted_threshold,
|
||||
cfg->unwanted_threshold,
|
||||
cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w,
|
||||
cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
|
||||
cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect,
|
||||
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
|
||||
cfg->tcp_auth_query_timeout);
|
||||
cfg->tcp_auth_query_timeout, w->shared_ports);
|
||||
w->env->outnet = w->back;
|
||||
if(!w->is_bg || w->is_bg_thread) {
|
||||
lock_basic_unlock(&ctx->cfglock);
|
||||
|
||||
@@ -60,6 +60,7 @@ struct tube;
|
||||
struct sldns_buffer;
|
||||
struct ub_event_base;
|
||||
struct query_info;
|
||||
struct shared_ports;
|
||||
|
||||
/**
|
||||
* The library-worker status structure
|
||||
@@ -84,6 +85,8 @@ struct libworker {
|
||||
struct comm_base* base;
|
||||
/** the backside outside network interface to the auth servers */
|
||||
struct outside_network* back;
|
||||
/** shared ports structure */
|
||||
struct shared_ports* shared_ports;
|
||||
/** random() table for this worker. */
|
||||
struct ub_randstate* rndstate;
|
||||
/** sslcontext for SSL wrapped DNS over TCP queries */
|
||||
|
||||
@@ -853,7 +853,7 @@ Result: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104']
|
||||
%{
|
||||
//printf("resolve_start(%lX)\n",(long unsigned int)arg1);
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
$function
|
||||
$action
|
||||
Py_END_ALLOW_THREADS
|
||||
//printf("resolve_stop()\n");
|
||||
%}
|
||||
|
||||
@@ -853,6 +853,8 @@ struct ub_server_stats {
|
||||
long long qquic;
|
||||
/** number of queries removed due to discard-timeout */
|
||||
long long num_queries_discard_timeout;
|
||||
/** number of queries removed due to replyaddr limit */
|
||||
long long num_queries_replyaddr_limit;
|
||||
/** number of queries removed due to wait-limit */
|
||||
long long num_queries_wait_limit;
|
||||
/** number of dns error reports generated */
|
||||
@@ -872,6 +874,8 @@ struct ub_stats_info {
|
||||
long long mesh_num_states;
|
||||
/** mesh stats: current number of reply (user) states */
|
||||
long long mesh_num_reply_states;
|
||||
/** mesh stats: current number of reply entries */
|
||||
long long mesh_num_reply_addrs;
|
||||
/** mesh stats: number of reply states overwritten with a new one */
|
||||
long long mesh_jostled;
|
||||
/** mesh stats: number of incoming queries dropped */
|
||||
|
||||
@@ -700,7 +700,5 @@ cleanup
|
||||
storehash unbound-$version.tar.gz
|
||||
echo "create unbound-$version.tar.gz.asc with:"
|
||||
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound-$version.tar.gz"
|
||||
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound-$version.zip"
|
||||
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound_setup_$version.exe"
|
||||
|
||||
info "Unbound distribution created successfully."
|
||||
|
||||
+10
-1
@@ -973,6 +973,9 @@ respip_rewrite_reply(const struct query_info* qinfo,
|
||||
lock_rw_unlock(&raddr->lock);
|
||||
lock_rw_unlock(&a->lock);
|
||||
lock_rw_unlock(&az->rpz_lock);
|
||||
if(view) {
|
||||
lock_rw_unlock(&view->lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if(rpz_used) {
|
||||
@@ -1111,7 +1114,13 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
|
||||
if((qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA ||
|
||||
qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) &&
|
||||
qstate->return_msg && qstate->return_msg->rep) {
|
||||
qstate->return_msg && qstate->return_msg->rep &&
|
||||
!(qstate->env->need_to_validate &&
|
||||
(!(qstate->query_flags & BIT_CD)
|
||||
|| qstate->env->cfg->ignore_cd) &&
|
||||
(qstate->return_msg->rep->security <= sec_status_bogus
|
||||
|| qstate->return_msg->rep->security ==
|
||||
sec_status_secure_sentinel_fail))) {
|
||||
struct reply_info* new_rep = qstate->return_msg->rep;
|
||||
struct ub_packed_rrset_key* alias_rrset = NULL;
|
||||
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
|
||||
|
||||
+107
-28
@@ -1369,6 +1369,10 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
|
||||
uncompressed_len = pkt_dname_len(&pktbuf);
|
||||
if(!uncompressed_len)
|
||||
return 0; /* parse error in dname */
|
||||
compressed_len = sldns_buffer_position(
|
||||
&pktbuf) - oldpos;
|
||||
if(compressed_len > rdlen)
|
||||
return 0; /* dname exceeds rdata */
|
||||
if(!sldns_buffer_available(buf,
|
||||
uncompressed_len))
|
||||
/* dname too long for buffer */
|
||||
@@ -1376,14 +1380,15 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
|
||||
dname_pkt_copy(&pktbuf,
|
||||
sldns_buffer_current(buf), rd);
|
||||
sldns_buffer_skip(buf, (ssize_t)uncompressed_len);
|
||||
compressed_len = sldns_buffer_position(
|
||||
&pktbuf) - oldpos;
|
||||
rd += compressed_len;
|
||||
rdlen -= compressed_len;
|
||||
count--;
|
||||
len = 0;
|
||||
break;
|
||||
case LDNS_RDF_TYPE_STR:
|
||||
/* Check rdlen for resilience, because it is
|
||||
* checked above, that rdlen > 0 */
|
||||
if(rdlen < 1) return 0; /* malformed */
|
||||
len = rd[0] + 1;
|
||||
break;
|
||||
default:
|
||||
@@ -1391,6 +1396,8 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
|
||||
break;
|
||||
}
|
||||
if(len) {
|
||||
if(len > rdlen)
|
||||
return 0; /* malformed */
|
||||
if(!sldns_buffer_available(buf, len))
|
||||
return 0; /* too long for buffer */
|
||||
sldns_buffer_write(buf, rd, len);
|
||||
@@ -1998,12 +2005,21 @@ auth_zone_get_serial(struct auth_zone* z, uint32_t* serial)
|
||||
struct auth_data* apex;
|
||||
struct auth_rrset* soa;
|
||||
struct packed_rrset_data* d;
|
||||
size_t primlen, mboxlen;
|
||||
apex = az_find_name(z, z->name, z->namelen);
|
||||
if(!apex) return 0;
|
||||
soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
|
||||
if(!soa || soa->data->count==0)
|
||||
return 0; /* no RRset or no RRs in rrset */
|
||||
if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */
|
||||
if((primlen = dname_valid(soa->data->rr_data[0]+2,
|
||||
soa->data->rr_len[0]-2)) == 0)
|
||||
return 0; /* primary dname malformed */
|
||||
if((mboxlen = dname_valid(soa->data->rr_data[0]+2+primlen,
|
||||
soa->data->rr_len[0]-2-primlen)) == 0)
|
||||
return 0; /* mailbox dname malformed */
|
||||
if(2+primlen+mboxlen+4*5 != soa->data->rr_len[0])
|
||||
return 0; /* rdata malformed */
|
||||
d = soa->data;
|
||||
*serial = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-20));
|
||||
return 1;
|
||||
@@ -2016,12 +2032,21 @@ xfr_find_soa(struct auth_zone* z, struct auth_xfer* xfr)
|
||||
struct auth_data* apex;
|
||||
struct auth_rrset* soa;
|
||||
struct packed_rrset_data* d;
|
||||
size_t primlen, mboxlen;
|
||||
apex = az_find_name(z, z->name, z->namelen);
|
||||
if(!apex) return 0;
|
||||
soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
|
||||
if(!soa || soa->data->count==0)
|
||||
return 0; /* no RRset or no RRs in rrset */
|
||||
if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */
|
||||
if((primlen = dname_valid(soa->data->rr_data[0]+2,
|
||||
soa->data->rr_len[0]-2)) == 0)
|
||||
return 0; /* primary dname malformed */
|
||||
if((mboxlen = dname_valid(soa->data->rr_data[0]+2+primlen,
|
||||
soa->data->rr_len[0]-2-primlen)) == 0)
|
||||
return 0; /* mailbox dname malformed */
|
||||
if(2+primlen+mboxlen+4*5 != soa->data->rr_len[0])
|
||||
return 0; /* rdata malformed */
|
||||
/* SOA record ends with serial, refresh, retry, expiry, minimum,
|
||||
* as 4 byte fields */
|
||||
d = soa->data;
|
||||
@@ -3990,6 +4015,22 @@ auth_master_copy(struct auth_master* o)
|
||||
return m;
|
||||
}
|
||||
|
||||
/** append the master to the copied list. */
|
||||
static int
|
||||
auth_master_copy_and_append(struct auth_master* p, struct auth_master** list,
|
||||
struct auth_master** last)
|
||||
{
|
||||
struct auth_master* m = auth_master_copy(p);
|
||||
if(!m) {
|
||||
return 0;
|
||||
}
|
||||
m->next = NULL;
|
||||
if(*last) (*last)->next = m;
|
||||
if(!*list) *list = m;
|
||||
*last = m;
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** copy the master addresses from the task_probe lookups to the allow_notify
|
||||
* list of masters */
|
||||
static void
|
||||
@@ -3998,17 +4039,27 @@ probe_copy_masters_for_allow_notify(struct auth_xfer* xfr)
|
||||
struct auth_master* list = NULL, *last = NULL;
|
||||
struct auth_master* p;
|
||||
/* build up new list with copies */
|
||||
for(p = xfr->task_transfer->masters; p; p=p->next) {
|
||||
struct auth_master* m = auth_master_copy(p);
|
||||
if(!m) {
|
||||
/* The list in task probe has been looked up before the list in
|
||||
* task transfer. */
|
||||
for(p = xfr->task_probe->masters; p; p=p->next) {
|
||||
if(!auth_master_copy_and_append(p, &list, &last)) {
|
||||
auth_free_masters(list);
|
||||
/* failed because of malloc failure, use old list */
|
||||
return;
|
||||
}
|
||||
}
|
||||
/* The list in task transfer also contains the http entries. */
|
||||
for(p = xfr->task_transfer->masters; p; p=p->next) {
|
||||
/* Copy the http entries from this lookup. The allow_notify
|
||||
* entries are not looked up from this list. The other
|
||||
* ones are already in from the probe lookups. */
|
||||
if(!p->http)
|
||||
continue;
|
||||
if(!auth_master_copy_and_append(p, &list, &last)) {
|
||||
auth_free_masters(list);
|
||||
/* failed because of malloc failure, use old list */
|
||||
return;
|
||||
}
|
||||
m->next = NULL;
|
||||
if(last) last->next = m;
|
||||
if(!list) list = m;
|
||||
last = m;
|
||||
}
|
||||
/* success, replace list */
|
||||
auth_free_masters(xfr->allow_notify_list);
|
||||
@@ -5694,8 +5745,7 @@ xfr_master_add_addrs(struct auth_master* m, struct ub_packed_rrset_key* rrset,
|
||||
|
||||
/** callback for task_transfer lookup of host name, of A or AAAA */
|
||||
void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus),
|
||||
int ATTR_UNUSED(was_ratelimited))
|
||||
enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited))
|
||||
{
|
||||
struct auth_xfer* xfr = (struct auth_xfer*)arg;
|
||||
struct module_env* env;
|
||||
@@ -5708,7 +5758,16 @@ void auth_xfer_transfer_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
}
|
||||
|
||||
/* process result */
|
||||
if(rcode == LDNS_RCODE_NOERROR) {
|
||||
if(sec == sec_status_bogus || sec == sec_status_secure_sentinel_fail) {
|
||||
if(verbosity >= VERB_OPS) {
|
||||
char zname[LDNS_MAX_DOMAINLEN];
|
||||
dname_str(xfr->name, zname);
|
||||
verbose(VERB_OPS, "auth zone %s: primary %s address lookup is DNSSEC bogus: %s",
|
||||
zname, xfr->task_transfer->lookup_target->host,
|
||||
(why_bogus?why_bogus:""));
|
||||
}
|
||||
/* fall through to next-lookup / next-master */
|
||||
} else if(rcode == LDNS_RCODE_NOERROR) {
|
||||
uint16_t wanted_qtype = LDNS_RR_TYPE_A;
|
||||
struct regional* temp = env->scratch;
|
||||
struct query_info rq;
|
||||
@@ -6669,6 +6728,18 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** return true if there are probe (SOA UDP query) targets in the master list*/
|
||||
static int
|
||||
have_probe_targets(struct auth_master* list)
|
||||
{
|
||||
struct auth_master* p;
|
||||
for(p=list; p; p = p->next) {
|
||||
if(!p->allow_notify && p->host)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** move to sending the probe packets, next if fails. task_probe */
|
||||
static void
|
||||
xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
|
||||
@@ -6708,6 +6779,16 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
|
||||
verbose(VERB_ALGO, "auth zone %s probe: finished only_lookup", zname);
|
||||
}
|
||||
xfr_probe_disown(xfr);
|
||||
if(!have_probe_targets(xfr->task_probe->masters)) {
|
||||
/* If there are no masters to probe, go to transfer. */
|
||||
if(xfr->task_transfer->worker == NULL) {
|
||||
xfr_start_transfer(xfr, env, NULL);
|
||||
return;
|
||||
}
|
||||
/* The transfer is already in progress. */
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
return;
|
||||
}
|
||||
if(xfr->task_nextprobe->worker == NULL)
|
||||
xfr_set_timeout(xfr, env, 0, 0);
|
||||
lock_basic_unlock(&xfr->lock);
|
||||
@@ -6757,8 +6838,7 @@ xfr_probe_send_or_end(struct auth_xfer* xfr, struct module_env* env)
|
||||
|
||||
/** callback for task_probe lookup of host name, of A or AAAA */
|
||||
void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
enum sec_status ATTR_UNUSED(sec), char* ATTR_UNUSED(why_bogus),
|
||||
int ATTR_UNUSED(was_ratelimited))
|
||||
enum sec_status sec, char* why_bogus, int ATTR_UNUSED(was_ratelimited))
|
||||
{
|
||||
struct auth_xfer* xfr = (struct auth_xfer*)arg;
|
||||
struct module_env* env;
|
||||
@@ -6771,7 +6851,16 @@ void auth_xfer_probe_lookup_callback(void* arg, int rcode, sldns_buffer* buf,
|
||||
}
|
||||
|
||||
/* process result */
|
||||
if(rcode == LDNS_RCODE_NOERROR) {
|
||||
if(sec == sec_status_bogus || sec == sec_status_secure_sentinel_fail) {
|
||||
if(verbosity >= VERB_OPS) {
|
||||
char zname[LDNS_MAX_DOMAINLEN];
|
||||
dname_str(xfr->name, zname);
|
||||
verbose(VERB_OPS, "auth zone %s: primary %s address probe lookup is DNSSEC bogus: %s",
|
||||
zname, xfr->task_transfer->lookup_target->host,
|
||||
(why_bogus?why_bogus:""));
|
||||
}
|
||||
/* fall through to next-lookup / next-master */
|
||||
} else if(rcode == LDNS_RCODE_NOERROR) {
|
||||
uint16_t wanted_qtype = LDNS_RR_TYPE_A;
|
||||
struct regional* temp = env->scratch;
|
||||
struct query_info rq;
|
||||
@@ -6864,18 +6953,6 @@ auth_xfer_timer(void* arg)
|
||||
}
|
||||
}
|
||||
|
||||
/** return true if there are probe (SOA UDP query) targets in the master list*/
|
||||
static int
|
||||
have_probe_targets(struct auth_master* list)
|
||||
{
|
||||
struct auth_master* p;
|
||||
for(p=list; p; p = p->next) {
|
||||
if(!p->allow_notify && p->host)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** start task_probe if possible, if no masters for probe start task_transfer
|
||||
* returns true if task has been started, and false if the task is already
|
||||
* in progress. */
|
||||
@@ -6887,7 +6964,9 @@ xfr_start_probe(struct auth_xfer* xfr, struct module_env* env,
|
||||
* progress (due to notify)) */
|
||||
if(xfr->task_probe->worker == NULL) {
|
||||
if(!have_probe_targets(xfr->task_probe->masters) &&
|
||||
!(xfr->task_probe->only_lookup &&
|
||||
xfr->task_probe->masters != NULL)
|
||||
xfr->task_probe->only_lookup = 1;
|
||||
if(!(xfr->task_probe->only_lookup &&
|
||||
xfr->task_probe->masters != NULL)) {
|
||||
/* useless to pick up task_probe, no masters to
|
||||
* probe. Instead attempt to pick up task transfer */
|
||||
|
||||
Vendored
+30
-8
@@ -232,8 +232,15 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
|
||||
|
||||
/* snip off front part of qname until the type is found */
|
||||
while(qnamelen > 0) {
|
||||
if((rrset = rrset_cache_lookup(env->rrset_cache, qname,
|
||||
qnamelen, searchtype, qclass, 0, now, 0))) {
|
||||
rrset = rrset_cache_lookup(env->rrset_cache, qname,
|
||||
qnamelen, searchtype, qclass, 0, now, 0);
|
||||
if(!rrset && searchtype == LDNS_RR_TYPE_DNAME)
|
||||
/* If not found, for type DNAME, try 0TTL stored,
|
||||
* for its grace period. */
|
||||
rrset = rrset_cache_lookup(env->rrset_cache, qname,
|
||||
qnamelen, searchtype, qclass,
|
||||
PACKED_RRSET_UPSTREAM_0TTL, now, 0);
|
||||
if(rrset) {
|
||||
uint8_t* origqname = qname;
|
||||
size_t origqnamelen = qnamelen;
|
||||
if(!noexpiredabove)
|
||||
@@ -270,6 +277,8 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
|
||||
|
||||
/* snip off front label */
|
||||
lablen = *qname;
|
||||
if(lablen == 0)
|
||||
break;
|
||||
qname += lablen + 1;
|
||||
qnamelen -= lablen + 1;
|
||||
}
|
||||
@@ -705,10 +714,16 @@ struct dns_msg*
|
||||
dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region)
|
||||
{
|
||||
size_t i;
|
||||
struct ub_packed_rrset_key** saved_rrsets;
|
||||
struct dns_msg* res = NULL;
|
||||
size_t rep_alloc_size = sizeof(struct reply_info)
|
||||
- sizeof(struct rrset_ref); /* this is the size of res->rep
|
||||
allocated in gen_dns_msg() */
|
||||
res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count);
|
||||
if(!res) return NULL;
|
||||
*res->rep = *origin->rep;
|
||||
saved_rrsets = res->rep->rrsets; /* save rrsets alloc by gen_dns_msg */
|
||||
memcpy(res->rep, origin->rep, rep_alloc_size);
|
||||
res->rep->rrsets = saved_rrsets;
|
||||
if(origin->rep->reason_bogus_str) {
|
||||
res->rep->reason_bogus_str = regional_strdup(region,
|
||||
origin->rep->reason_bogus_str);
|
||||
@@ -766,8 +781,15 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
rrset->entry.data;
|
||||
uint8_t* newname, *dtarg = NULL;
|
||||
size_t newlen, dtarglen;
|
||||
if(TTL_IS_EXPIRED(d->ttl, now))
|
||||
return NULL;
|
||||
time_t rr_ttl;
|
||||
if(TTL_IS_EXPIRED(d->ttl, now)) {
|
||||
/* Allow TTL=0 DNAME from upstream within grace period */
|
||||
if(!(rrset->rk.flags & PACKED_RRSET_UPSTREAM_0TTL))
|
||||
return NULL;
|
||||
rr_ttl = 0;
|
||||
} else {
|
||||
rr_ttl = d->ttl - now;
|
||||
}
|
||||
/* only allow validated (with DNSSEC) DNAMEs used from cache
|
||||
* for insecure DNAMEs, query again. */
|
||||
*sec_status = d->security;
|
||||
@@ -779,7 +801,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
msg->rep->flags = BIT_QR; /* reply, no AA, no error */
|
||||
msg->rep->authoritative = 0; /* reply stored in cache can't be authoritative */
|
||||
msg->rep->qdcount = 1;
|
||||
msg->rep->ttl = d->ttl - now;
|
||||
msg->rep->ttl = rr_ttl;
|
||||
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
|
||||
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
|
||||
msg->rep->serve_expired_norec_ttl = 0;
|
||||
@@ -831,7 +853,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
|
||||
if(!newd)
|
||||
return NULL;
|
||||
ck->entry.data = newd;
|
||||
newd->ttl = d->ttl - now; /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
newd->ttl = rr_ttl; /* RFC6672: synth CNAME TTL == DNAME TTL */
|
||||
newd->count = 1;
|
||||
newd->rrsig_count = 0;
|
||||
newd->trust = rrset_trust_ans_noAA;
|
||||
@@ -1045,7 +1067,7 @@ dns_cache_lookup(struct module_env* env,
|
||||
if(env->cfg->harden_below_nxdomain) {
|
||||
while(!dname_is_root(k.qname)) {
|
||||
if(dpname && dpnamelen
|
||||
&& !dname_subdomain_c(k.qname, dpname))
|
||||
&& !dname_strict_subdomain_c(k.qname, dpname))
|
||||
break; /* no synth nxdomain above the stub */
|
||||
dname_remove_label(&k.qname, &k.qname_len);
|
||||
h = query_info_hash(&k, flags);
|
||||
|
||||
Vendored
+2
-1
@@ -1269,7 +1269,8 @@ int infra_wait_limit_allowed(struct infra_cache* infra, struct comm_reply* rep,
|
||||
int cookie_valid, struct config_file* cfg)
|
||||
{
|
||||
struct lruhash_entry* entry;
|
||||
if(cfg->wait_limit == 0)
|
||||
if(cfg->wait_limit == 0 ||
|
||||
(cookie_valid && cfg->wait_limit_cookie == 0))
|
||||
return 1;
|
||||
|
||||
entry = infra_find_ip_ratedata(infra, &rep->client_addr,
|
||||
|
||||
Vendored
+65
-5
@@ -50,6 +50,7 @@
|
||||
#include "util/regional.h"
|
||||
#include "util/alloc.h"
|
||||
#include "util/net_help.h"
|
||||
#include "validator/val_utils.h"
|
||||
|
||||
void
|
||||
rrset_markdel(void* key)
|
||||
@@ -126,7 +127,8 @@ rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key,
|
||||
|
||||
/** see if rrset needs to be updated in the cache */
|
||||
static int
|
||||
need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
|
||||
need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns,
|
||||
int a_aaaa)
|
||||
{
|
||||
struct packed_rrset_data* newd = (struct packed_rrset_data*)nd;
|
||||
struct packed_rrset_data* cached = (struct packed_rrset_data*)cd;
|
||||
@@ -149,6 +151,20 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
|
||||
if(equal && !TTL_IS_EXPIRED(cached->ttl, timenow) &&
|
||||
cached->security == sec_status_bogus)
|
||||
return 0;
|
||||
/* ghost-domain: never let an NS overwrite extend lifetime
|
||||
* past the entry it replaces, regardless of trust. */
|
||||
/* Also for A/AAAA and it is glue. */
|
||||
if((ns ||
|
||||
(a_aaaa && cached->trust==rrset_trust_add_noAA))
|
||||
&& !TTL_IS_EXPIRED(cached->ttl, timenow) &&
|
||||
newd->ttl > cached->ttl) {
|
||||
size_t i;
|
||||
if(a_aaaa) newd->trust=rrset_trust_add_noAA;
|
||||
newd->ttl = cached->ttl;
|
||||
for(i=0; i<(newd->count+newd->rrsig_count); i++)
|
||||
if(newd->rr_ttl[i] > newd->ttl)
|
||||
newd->rr_ttl[i] = newd->ttl;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
/* o item in cache has expired */
|
||||
@@ -213,7 +229,8 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
equal = rrsetdata_equal((struct packed_rrset_data*)k->entry.
|
||||
data, (struct packed_rrset_data*)e->data);
|
||||
if(!need_to_update_rrset(k->entry.data, e->data, timenow,
|
||||
equal, (rrset_type==LDNS_RR_TYPE_NS))) {
|
||||
equal, (rrset_type==LDNS_RR_TYPE_NS),
|
||||
(rrset_type==LDNS_RR_TYPE_A || rrset_type==LDNS_RR_TYPE_AAAA))) {
|
||||
/* cache is superior, return that value */
|
||||
lock_rw_unlock(&e->lock);
|
||||
ub_packed_rrset_parsedelete(k, alloc);
|
||||
@@ -245,12 +262,43 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** See if the name is a within signer authority */
|
||||
static int
|
||||
dname_subdomain_rrsig_signers(uint8_t* dname,
|
||||
struct ub_packed_rrset_key* rrset)
|
||||
{
|
||||
struct packed_rrset_data* d = (struct packed_rrset_data*)
|
||||
rrset->entry.data;
|
||||
size_t i;
|
||||
if(!d || !d->rrsig_count)
|
||||
return 0;
|
||||
for(i=0; i<d->rrsig_count; i++) {
|
||||
uint8_t* sname = NULL;
|
||||
size_t slen = 0;
|
||||
rrsig_get_signer(d->rr_data[d->count+i], d->rr_len[d->count+i],
|
||||
&sname, &slen);
|
||||
if(!sname || !slen)
|
||||
return 0; /* malformed */
|
||||
if(!dname_subdomain_c(dname, sname))
|
||||
return 0; /* not a subdomain */
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
|
||||
struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len,
|
||||
struct alloc_cache* alloc, time_t timenow)
|
||||
{
|
||||
struct rrset_ref ref;
|
||||
uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3];
|
||||
|
||||
/* See if the RRSIG signer name allows this wildcard,
|
||||
* the new rrset should fall within the zone of the RRSIG signer(s). */
|
||||
if(!dname_subdomain_rrsig_signers(ce, rrset)) {
|
||||
verbose(VERB_ALGO, "wildcard canonical parent outside signer authority");
|
||||
return;
|
||||
}
|
||||
|
||||
rrset = packed_rrset_copy_alloc(rrset, alloc, timenow);
|
||||
if(!rrset) {
|
||||
log_err("malloc failure in rrset_cache_update_wildcard");
|
||||
@@ -278,6 +326,10 @@ void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
|
||||
(void)rrset_cache_update(rrset_cache, &ref, alloc, timenow);
|
||||
}
|
||||
|
||||
/** Grace period in seconds for TTL=0 DNAME rrsets (RFC 2308: do not cache).
|
||||
* Allows synthesis from cache within this window to reduce recursion load. */
|
||||
#define DNAME_TTL0_GRACE_SECONDS 1
|
||||
|
||||
struct ub_packed_rrset_key*
|
||||
rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen,
|
||||
uint16_t qtype, uint16_t qclass, uint32_t flags, time_t timenow,
|
||||
@@ -300,12 +352,20 @@ rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen,
|
||||
/* check TTL */
|
||||
struct packed_rrset_data* data =
|
||||
(struct packed_rrset_data*)e->data;
|
||||
struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key;
|
||||
if(TTL_IS_EXPIRED(data->ttl, timenow)) {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return NULL;
|
||||
/* Allow TTL=0 DNAME within grace period for synthesis */
|
||||
if(qtype == LDNS_RR_TYPE_DNAME &&
|
||||
(k->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) &&
|
||||
(timenow - data->ttl_add) <= DNAME_TTL0_GRACE_SECONDS) {
|
||||
/* within grace: allow for synthesis */
|
||||
} else {
|
||||
lock_rw_unlock(&e->lock);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/* we're done */
|
||||
return (struct ub_packed_rrset_key*)e->key;
|
||||
return k;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
+176
-98
@@ -42,7 +42,6 @@
|
||||
#ifdef HAVE_SYS_TYPES_H
|
||||
# include <sys/types.h>
|
||||
#endif
|
||||
#include <sys/time.h>
|
||||
#include <limits.h>
|
||||
#ifdef USE_TCP_FASTOPEN
|
||||
#include <netinet/tcp.h>
|
||||
@@ -1564,7 +1563,7 @@ listen_create(struct comm_base* base, struct listen_port* ports,
|
||||
cp = comm_point_create_udp(base, ports->fd,
|
||||
front->udp_buff, ports->pp2_enabled, cb,
|
||||
cb_arg, ports->socket);
|
||||
} else if(ports->ftype == listen_type_doq) {
|
||||
} else if(ports->ftype == listen_type_doq && doq_table) {
|
||||
#ifndef HAVE_NGTCP2
|
||||
log_warn("Unbound is not compiled with "
|
||||
"ngtcp2. This is required to use DNS "
|
||||
@@ -2167,7 +2166,8 @@ void tcp_req_info_clear(struct tcp_req_info* req)
|
||||
open = req->open_req_list;
|
||||
while(open) {
|
||||
nopen = open->next;
|
||||
mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp);
|
||||
mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp,
|
||||
NULL);
|
||||
free(open);
|
||||
open = nopen;
|
||||
}
|
||||
@@ -2300,21 +2300,8 @@ int
|
||||
tcp_req_info_handle_read_close(struct tcp_req_info* req)
|
||||
{
|
||||
verbose(VERB_ALGO, "tcp channel read side closed %d", req->cp->fd);
|
||||
/* reset byte count for (potential) partial read */
|
||||
req->cp->tcp_byte_count = 0;
|
||||
/* if we still have results to write, pick up next and write it */
|
||||
if(req->num_done_req != 0) {
|
||||
tcp_req_pickup_next_result(req);
|
||||
tcp_req_info_setup_listen(req);
|
||||
return 1;
|
||||
}
|
||||
/* if nothing to do, this closes the connection */
|
||||
if(req->num_open_req == 0 && req->num_done_req == 0)
|
||||
return 0;
|
||||
/* otherwise, we must be waiting for dns resolve, wait with timeout */
|
||||
req->read_is_closed = 1;
|
||||
tcp_req_info_setup_listen(req);
|
||||
return 1;
|
||||
/* RFC 7766 6.2.4 says to drop pending replies when client closes. */
|
||||
return 0; /* drop connection */
|
||||
}
|
||||
|
||||
void
|
||||
@@ -2884,6 +2871,7 @@ submit_http_error:
|
||||
sldns_buffer_flip(h2_stream->qbuffer);
|
||||
h2_session->postpone_drop = 1;
|
||||
query_read_done = http2_query_read_done(h2_session, h2_stream);
|
||||
h2_session->postpone_drop = 0;
|
||||
if(query_read_done < 0)
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
else if(!query_read_done) {
|
||||
@@ -2893,11 +2881,9 @@ submit_http_error:
|
||||
* failure will result in reclaiming (and closing)
|
||||
* of comm point. */
|
||||
verbose(VERB_QUERY, "http2 query dropped in worker cb");
|
||||
h2_session->postpone_drop = 0;
|
||||
return NGHTTP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
/* nothing to submit right now, query added to mesh. */
|
||||
h2_session->postpone_drop = 0;
|
||||
return 0;
|
||||
}
|
||||
if(!http2_submit_dns_response(h2_session)) {
|
||||
@@ -3275,14 +3261,18 @@ nghttp2_session_callbacks* http2_req_callbacks_create(void)
|
||||
struct doq_table*
|
||||
doq_table_create(struct config_file* cfg, struct ub_randstate* rnd)
|
||||
{
|
||||
struct doq_table* table = calloc(1, sizeof(*table));
|
||||
struct doq_table* table;
|
||||
|
||||
if (!cfg->quic_port)
|
||||
return NULL;
|
||||
table = calloc(1, sizeof(*table));
|
||||
if(!table)
|
||||
return NULL;
|
||||
#ifdef USE_NGTCP2_CRYPTO_OSSL
|
||||
/* Initialize the ossl crypto, it is harmless to call twice,
|
||||
* and this is before use of doq connections. */
|
||||
if(ngtcp2_crypto_ossl_init() != 0) {
|
||||
log_err("ngtcp2_crypto_oss_init failed");
|
||||
log_err("ngtcp2_crypto_ossl_init failed");
|
||||
free(table);
|
||||
return NULL;
|
||||
}
|
||||
@@ -3354,7 +3344,7 @@ conn_tree_del(rbnode_type* node, void* arg)
|
||||
{
|
||||
struct doq_table* table = (struct doq_table*)arg;
|
||||
struct doq_conn* conn;
|
||||
if(!node)
|
||||
if(!node || !table)
|
||||
return;
|
||||
conn = (struct doq_conn*)node->key;
|
||||
if(conn->timer.timer_in_list) {
|
||||
@@ -3409,13 +3399,13 @@ doq_table_delete(struct doq_table* table)
|
||||
}
|
||||
|
||||
struct doq_timer*
|
||||
doq_timer_find_time(struct doq_table* table, struct timeval* tv)
|
||||
doq_timer_find_time(struct doq_table* table, ngtcp2_tstamp ts)
|
||||
{
|
||||
struct doq_timer key;
|
||||
struct rbnode_type* node;
|
||||
log_assert(table != NULL);
|
||||
memset(&key, 0, sizeof(key));
|
||||
key.time.tv_sec = tv->tv_sec;
|
||||
key.time.tv_usec = tv->tv_usec;
|
||||
key.time_mono = ts;
|
||||
node = rbtree_search(table->timer_tree, &key);
|
||||
if(node)
|
||||
return (struct doq_timer*)node->key;
|
||||
@@ -3463,7 +3453,7 @@ doq_timer_list_remove(struct doq_table* table, struct doq_timer* timer)
|
||||
if(!timer->timer_in_list)
|
||||
return;
|
||||
/* The item in the rbtree has the list start and end. */
|
||||
rb_timer = doq_timer_find_time(table, &timer->time);
|
||||
rb_timer = doq_timer_find_time(table, timer->time_mono);
|
||||
if(rb_timer) {
|
||||
if(timer->setlist_prev)
|
||||
timer->setlist_prev->setlist_next = timer->setlist_next;
|
||||
@@ -3509,7 +3499,8 @@ doq_timer_unset(struct doq_table* table, struct doq_timer* timer)
|
||||
}
|
||||
|
||||
void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
|
||||
struct doq_server_socket* worker_doq_socket, struct timeval* tv)
|
||||
struct doq_server_socket* worker_doq_socket, struct timeval* tv,
|
||||
ngtcp2_tstamp ts)
|
||||
{
|
||||
struct doq_timer* rb_timer;
|
||||
if(verbosity >= VERB_ALGO && timer->conn) {
|
||||
@@ -3523,14 +3514,14 @@ void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
|
||||
(int)rel.tv_sec, (int)rel.tv_usec);
|
||||
}
|
||||
if(timer->timer_in_tree || timer->timer_in_list) {
|
||||
if(timer->time.tv_sec == tv->tv_sec &&
|
||||
timer->time.tv_usec == tv->tv_usec)
|
||||
if(timer->time_mono == ts)
|
||||
return; /* already set on that time */
|
||||
doq_timer_unset(table, timer);
|
||||
}
|
||||
timer->time.tv_sec = tv->tv_sec;
|
||||
timer->time.tv_usec = tv->tv_usec;
|
||||
rb_timer = doq_timer_find_time(table, tv);
|
||||
timer->time_real.tv_sec = tv->tv_sec;
|
||||
timer->time_real.tv_usec = tv->tv_usec;
|
||||
timer->time_mono = ts;
|
||||
rb_timer = doq_timer_find_time(table, ts);
|
||||
if(rb_timer) {
|
||||
/* There is a timeout already with this value. Timer is
|
||||
* added to the setlist. */
|
||||
@@ -3606,15 +3597,29 @@ doq_conn_create(struct comm_point* c, struct doq_pkt_addr* paddr,
|
||||
return conn;
|
||||
}
|
||||
|
||||
/** The arguments for doq stream tree del. */
|
||||
struct doq_stream_tree_del_args {
|
||||
/** The doq table. */
|
||||
struct doq_table* table;
|
||||
/** The doq connection for the stream. */
|
||||
struct doq_conn* conn;
|
||||
};
|
||||
|
||||
/** delete stream tree node */
|
||||
static void
|
||||
stream_tree_del(rbnode_type* node, void* arg)
|
||||
{
|
||||
struct doq_table* table = (struct doq_table*)arg;
|
||||
struct doq_stream_tree_del_args* args = (struct doq_stream_tree_del_args*)arg;
|
||||
struct doq_table* table = args->table;
|
||||
struct doq_stream* stream;
|
||||
if(!node)
|
||||
return;
|
||||
stream = (struct doq_stream*)node;
|
||||
if(stream->mesh_state) {
|
||||
mesh_state_remove_reply(stream->mesh, stream->mesh_state,
|
||||
args->conn->doq_socket->cp, stream);
|
||||
stream->mesh_state = NULL;
|
||||
}
|
||||
if(stream->in)
|
||||
doq_table_quic_size_subtract(table, stream->inlen);
|
||||
if(stream->out)
|
||||
@@ -3636,7 +3641,11 @@ doq_conn_delete(struct doq_conn* conn, struct doq_table* table)
|
||||
* because the ngtcp2 conn is deleted. */
|
||||
SSL_set_app_data(conn->ssl, NULL);
|
||||
if(conn->stream_tree.count != 0) {
|
||||
traverse_postorder(&conn->stream_tree, stream_tree_del, table);
|
||||
struct doq_stream_tree_del_args args;
|
||||
memset(&args, 0, sizeof(args));
|
||||
args.table = table;
|
||||
args.conn = conn;
|
||||
traverse_postorder(&conn->stream_tree, stream_tree_del, &args);
|
||||
}
|
||||
free(conn->key.dcid);
|
||||
SSL_free(conn->ssl);
|
||||
@@ -3709,13 +3718,9 @@ int doq_timer_cmp(const void* key1, const void* key2)
|
||||
{
|
||||
struct doq_timer* e = (struct doq_timer*)key1;
|
||||
struct doq_timer* f = (struct doq_timer*)key2;
|
||||
if(e->time.tv_sec < f->time.tv_sec)
|
||||
if(e->time_mono < f->time_mono)
|
||||
return -1;
|
||||
if(e->time.tv_sec > f->time.tv_sec)
|
||||
return 1;
|
||||
if(e->time.tv_usec < f->time.tv_usec)
|
||||
return -1;
|
||||
if(e->time.tv_usec > f->time.tv_usec)
|
||||
if(e->time_mono > f->time_mono)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
@@ -3776,7 +3781,7 @@ doq_repinfo_retrieve_localaddr(struct comm_reply* repinfo,
|
||||
memset(sa6, 0, *localaddrlen);
|
||||
sa6->sin6_family = AF_INET6;
|
||||
memmove(&sa6->sin6_addr, &repinfo->pktinfo.v6info.ipi6_addr,
|
||||
*localaddrlen);
|
||||
sizeof(struct in6_addr));
|
||||
sa6->sin6_port = repinfo->doq_srcport;
|
||||
#endif
|
||||
} else {
|
||||
@@ -3786,7 +3791,7 @@ doq_repinfo_retrieve_localaddr(struct comm_reply* repinfo,
|
||||
memset(sa, 0, *localaddrlen);
|
||||
sa->sin_family = AF_INET;
|
||||
memmove(&sa->sin_addr, &repinfo->pktinfo.v4info.ipi_addr,
|
||||
*localaddrlen);
|
||||
sizeof(struct in_addr));
|
||||
sa->sin_port = repinfo->doq_srcport;
|
||||
#elif defined(IP_RECVDSTADDR)
|
||||
struct sockaddr_in* sa = (struct sockaddr_in*)localaddr;
|
||||
@@ -3949,6 +3954,11 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
|
||||
if(stream->is_closed)
|
||||
return 1;
|
||||
stream->is_closed = 1;
|
||||
if(stream->mesh_state) {
|
||||
mesh_state_remove_reply(stream->mesh, stream->mesh_state,
|
||||
conn->doq_socket->cp, stream);
|
||||
stream->mesh_state = NULL;
|
||||
}
|
||||
doq_stream_off_write_list(conn, stream);
|
||||
if(send_shutdown) {
|
||||
verbose(VERB_ALGO, "doq: shutdown stream_id %d with app_error_code %d",
|
||||
@@ -3978,7 +3988,8 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
|
||||
|
||||
/** doq stream pick up answer data from buffer */
|
||||
static int
|
||||
doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf)
|
||||
doq_stream_pickup_answer(struct doq_conn* conn, struct doq_stream* stream,
|
||||
struct sldns_buffer* buf)
|
||||
{
|
||||
stream->is_answer_available = 1;
|
||||
if(stream->out) {
|
||||
@@ -3988,6 +3999,11 @@ doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf)
|
||||
}
|
||||
stream->nwrite = 0;
|
||||
stream->outlen = sldns_buffer_limit(buf);
|
||||
if(!doq_table_quic_size_available(conn->doq_socket->table,
|
||||
conn->doq_socket->cfg, stream->outlen)) {
|
||||
verbose(VERB_ALGO, "doq stream: no space for reply length");
|
||||
return 0;
|
||||
}
|
||||
/* For quic the output bytes have to stay allocated and available,
|
||||
* for potential resends, until the remote end has acknowledged them.
|
||||
* This includes the tcplen start uint16_t, in outlen_wire. */
|
||||
@@ -4014,24 +4030,56 @@ doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
|
||||
if(stream->out)
|
||||
doq_table_quic_size_subtract(conn->doq_socket->table,
|
||||
stream->outlen);
|
||||
if(!doq_stream_pickup_answer(stream, buf))
|
||||
if(!doq_stream_pickup_answer(conn, stream, buf))
|
||||
return 0;
|
||||
doq_table_quic_size_add(conn->doq_socket->table, stream->outlen);
|
||||
doq_stream_on_write_list(conn, stream);
|
||||
doq_conn_write_enable(conn);
|
||||
return 1;
|
||||
}
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
|
||||
void
|
||||
doq_stream_add_meshstate(struct doq_stream* stream,
|
||||
struct mesh_area* mesh, struct mesh_state* m)
|
||||
{
|
||||
#ifdef HAVE_NGTCP2
|
||||
stream->mesh = mesh;
|
||||
stream->mesh_state = m;
|
||||
#else
|
||||
(void)stream; (void)mesh; (void)m;
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
doq_stream_remove_mesh_state(struct doq_stream* stream)
|
||||
{
|
||||
#ifdef HAVE_NGTCP2
|
||||
if(!stream)
|
||||
return;
|
||||
stream->mesh_state = NULL;
|
||||
#else
|
||||
(void)stream;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
/** doq stream data length has completed, allocations can be done. False on
|
||||
* allocation failure. */
|
||||
static int
|
||||
doq_stream_datalen_complete(struct doq_stream* stream, struct doq_table* table)
|
||||
doq_stream_datalen_complete(struct doq_conn* conn, struct doq_stream* stream,
|
||||
struct doq_table* table)
|
||||
{
|
||||
if(stream->inlen > 1024*1024) {
|
||||
log_err("doq stream in length too large %d",
|
||||
(int)stream->inlen);
|
||||
return 0;
|
||||
}
|
||||
if(!doq_table_quic_size_available(table, conn->doq_socket->cfg,
|
||||
stream->inlen)) {
|
||||
verbose(VERB_ALGO, "doq stream: no space for query length");
|
||||
return 0;
|
||||
}
|
||||
stream->in = calloc(1, stream->inlen);
|
||||
if(!stream->in) {
|
||||
log_err("doq could not read stream, calloc failed: "
|
||||
@@ -4076,6 +4124,7 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream)
|
||||
return 0;
|
||||
}
|
||||
c->repinfo.doq_streamid = stream->stream_id;
|
||||
c->repinfo.doq_stream = stream;
|
||||
conn->doq_socket->current_conn = conn;
|
||||
fptr_ok(fptr_whitelist_comm_point(c->callback));
|
||||
if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo)) {
|
||||
@@ -4092,8 +4141,9 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream)
|
||||
|
||||
/** doq receive data for a stream, more bytes of the incoming data */
|
||||
static int
|
||||
doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data,
|
||||
size_t datalen, int* recv_done, struct doq_table* table)
|
||||
doq_stream_recv_data(struct doq_conn* conn, struct doq_stream* stream,
|
||||
const uint8_t* data, size_t datalen, int* recv_done,
|
||||
struct doq_table* table)
|
||||
{
|
||||
int got_data = 0;
|
||||
/* read the tcplength uint16_t at the start */
|
||||
@@ -4114,7 +4164,7 @@ doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data,
|
||||
if(stream->nread == 2) {
|
||||
/* the initial length value is completed */
|
||||
stream->inlen = ntohs(tcplen);
|
||||
if(!doq_stream_datalen_complete(stream, table))
|
||||
if(!doq_stream_datalen_complete(conn, stream, table))
|
||||
return 0;
|
||||
} else {
|
||||
/* store for later */
|
||||
@@ -4263,12 +4313,11 @@ doq_submit_new_token(struct doq_conn* conn)
|
||||
ngtcp2_ssize tokenlen;
|
||||
int ret;
|
||||
const ngtcp2_path* path = ngtcp2_conn_get_path(conn->conn);
|
||||
ngtcp2_tstamp ts = doq_get_timestamp_nanosec();
|
||||
|
||||
tokenlen = ngtcp2_crypto_generate_regular_token(token,
|
||||
conn->doq_socket->static_secret,
|
||||
conn->doq_socket->static_secret_len, path->remote.addr,
|
||||
path->remote.addrlen, ts);
|
||||
path->remote.addrlen, doq_get_timestamp_nanosec());
|
||||
if(tokenlen < 0) {
|
||||
log_err("doq ngtcp2_crypto_generate_regular_token failed");
|
||||
return 1;
|
||||
@@ -4331,8 +4380,7 @@ doq_stream_open_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
|
||||
verbose(VERB_ALGO, "doq: stream with this id already exists");
|
||||
return 0;
|
||||
}
|
||||
if(stream_id != 0 && stream_id != 4 && /* allow one stream on a new connection */
|
||||
!doq_table_quic_size_available(doq_conn->doq_socket->table,
|
||||
if(!doq_table_quic_size_available(doq_conn->doq_socket->table,
|
||||
doq_conn->doq_socket->cfg, sizeof(*stream)
|
||||
+ 100 /* estimated query in */
|
||||
+ 512 /* estimated response out */
|
||||
@@ -4390,8 +4438,8 @@ doq_recv_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags,
|
||||
return 0;
|
||||
}
|
||||
if(datalen != 0) {
|
||||
if(!doq_stream_recv_data(stream, data, datalen, &recv_done,
|
||||
doq_conn->doq_socket->table))
|
||||
if(!doq_stream_recv_data(doq_conn, stream, data, datalen,
|
||||
&recv_done, doq_conn->doq_socket->table))
|
||||
return NGTCP2_ERR_CALLBACK_FAILURE;
|
||||
}
|
||||
if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) {
|
||||
@@ -4460,6 +4508,29 @@ doq_stream_reset_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** ngtcp2 extend_max_stream_data function */
|
||||
int doq_extend_max_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn),
|
||||
int64_t stream_id, uint64_t max_data, void* user_data,
|
||||
void* ATTR_UNUSED(stream_user_data))
|
||||
{
|
||||
struct doq_conn* doq_conn = (struct doq_conn*)user_data;
|
||||
struct doq_stream* stream;
|
||||
verbose(VERB_ALGO, "doq extend_max_stream_data stream id %d "
|
||||
"max_data %d ", (int)stream_id, (int)max_data);
|
||||
if(max_data == 0)
|
||||
return 0;
|
||||
stream = doq_stream_find(doq_conn, stream_id);
|
||||
if(!stream) {
|
||||
verbose(VERB_ALGO, "doq: unknown stream %d", (int)stream_id);
|
||||
return 0;
|
||||
}
|
||||
if(!stream->is_answer_available)
|
||||
return 0;
|
||||
doq_stream_on_write_list(doq_conn, stream);
|
||||
doq_conn_write_enable(doq_conn);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** ngtcp2 acked_stream_data_offset callback function */
|
||||
static int
|
||||
doq_acked_stream_data_offset_cb(ngtcp2_conn* ATTR_UNUSED(conn),
|
||||
@@ -4834,6 +4905,7 @@ doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen,
|
||||
callbacks.stream_open = doq_stream_open_cb;
|
||||
callbacks.stream_close = doq_stream_close_cb;
|
||||
callbacks.stream_reset = doq_stream_reset_cb;
|
||||
callbacks.extend_max_stream_data = doq_extend_max_stream_data_cb;
|
||||
callbacks.acked_stream_data_offset = doq_acked_stream_data_offset_cb;
|
||||
callbacks.recv_stream_data = doq_recv_stream_data_cb;
|
||||
|
||||
@@ -4922,6 +4994,7 @@ doq_conid_find(struct doq_table* table, const uint8_t* data, size_t datalen)
|
||||
key.node.key = &key;
|
||||
key.cid = (void*)data;
|
||||
key.cidlen = datalen;
|
||||
log_assert(table != NULL);
|
||||
node = rbtree_search(table->conid_tree, &key);
|
||||
if(node)
|
||||
return (struct doq_conid*)node->key;
|
||||
@@ -5109,23 +5182,30 @@ doq_conn_clear_conids(struct doq_conn* conn)
|
||||
|
||||
ngtcp2_tstamp doq_get_timestamp_nanosec(void)
|
||||
{
|
||||
#ifdef CLOCK_REALTIME
|
||||
struct timespec tp;
|
||||
memset(&tp, 0, sizeof(tp));
|
||||
/* Get a nanosecond time, that can be compared with the event base. */
|
||||
if(clock_gettime(CLOCK_REALTIME, &tp) == -1) {
|
||||
log_err("clock_gettime failed: %s", strerror(errno));
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
if(clock_gettime(CLOCK_BOOTTIME, &tp) == -1) {
|
||||
#endif
|
||||
if(clock_gettime(CLOCK_MONOTONIC, &tp) == -1) {
|
||||
log_err("clock_gettime failed: %s", strerror(errno));
|
||||
}
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
}
|
||||
#endif
|
||||
return ((uint64_t)tp.tv_sec)*((uint64_t)1000000000) +
|
||||
((uint64_t)tp.tv_nsec);
|
||||
#else
|
||||
}
|
||||
|
||||
static struct timeval doq_get_timevalue(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
if(gettimeofday(&tv, NULL) < 0) {
|
||||
log_err("gettimeofday failed: %s", strerror(errno));
|
||||
memset(&tv, 0, sizeof(tv));
|
||||
}
|
||||
return ((uint64_t)tv.tv_sec)*((uint64_t)1000000000) +
|
||||
((uint64_t)tv.tv_usec)*((uint64_t)1000);
|
||||
#endif /* CLOCK_REALTIME */
|
||||
return tv;
|
||||
}
|
||||
|
||||
/** doq start the closing period for the connection. */
|
||||
@@ -5248,18 +5328,17 @@ doq_conn_recv(struct comm_point* c, struct doq_pkt_addr* paddr,
|
||||
int* err_drop)
|
||||
{
|
||||
int ret;
|
||||
ngtcp2_tstamp ts;
|
||||
struct ngtcp2_path path;
|
||||
memset(&path, 0, sizeof(path));
|
||||
path.remote.addr = (struct sockaddr*)&paddr->addr;
|
||||
path.remote.addrlen = paddr->addrlen;
|
||||
path.local.addr = (struct sockaddr*)&paddr->localaddr;
|
||||
path.local.addrlen = paddr->localaddrlen;
|
||||
ts = doq_get_timestamp_nanosec();
|
||||
|
||||
ret = ngtcp2_conn_read_pkt(conn->conn, &path, pi,
|
||||
sldns_buffer_begin(c->doq_socket->pkt_buf),
|
||||
sldns_buffer_limit(c->doq_socket->pkt_buf), ts);
|
||||
sldns_buffer_limit(c->doq_socket->pkt_buf),
|
||||
doq_get_timestamp_nanosec());
|
||||
if(ret != 0) {
|
||||
if(err_retry)
|
||||
*err_retry = 0;
|
||||
@@ -5347,7 +5426,6 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
{
|
||||
struct doq_stream* stream = conn->stream_write_first;
|
||||
ngtcp2_path_storage ps;
|
||||
ngtcp2_tstamp ts = doq_get_timestamp_nanosec();
|
||||
size_t num_packets = 0, max_packets = 65535;
|
||||
ngtcp2_path_storage_zero(&ps);
|
||||
|
||||
@@ -5400,7 +5478,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
ret = ngtcp2_conn_writev_stream(conn->conn, &ps.path, &pi,
|
||||
sldns_buffer_begin(c->doq_socket->pkt_buf),
|
||||
sldns_buffer_remaining(c->doq_socket->pkt_buf),
|
||||
&ndatalen, flags, stream_id, datav, datav_count, ts);
|
||||
&ndatalen, flags, stream_id, datav, datav_count,
|
||||
doq_get_timestamp_nanosec());
|
||||
if(ret < 0) {
|
||||
if(ret == NGTCP2_ERR_WRITE_MORE) {
|
||||
verbose(VERB_ALGO, "doq: write more, ndatalen %d", (int)ndatalen);
|
||||
@@ -5415,26 +5494,20 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
continue;
|
||||
} else if(ret == NGTCP2_ERR_STREAM_DATA_BLOCKED) {
|
||||
verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_DATA_BLOCKED");
|
||||
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
|
||||
ngtcp2_ccerr_set_application_error(
|
||||
&conn->ccerr, -1, NULL, 0);
|
||||
#else
|
||||
ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0);
|
||||
#endif
|
||||
if(err_drop)
|
||||
*err_drop = 0;
|
||||
if(!doq_conn_close_error(c, conn)) {
|
||||
if(err_drop)
|
||||
*err_drop = 1;
|
||||
if(stream) {
|
||||
doq_stream_off_write_list(conn, stream);
|
||||
stream = stream->write_next;
|
||||
continue;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
} else if(ret == NGTCP2_ERR_STREAM_SHUT_WR) {
|
||||
verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_SHUT_WR");
|
||||
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
|
||||
ngtcp2_ccerr_set_application_error(
|
||||
&conn->ccerr, -1, NULL, 0);
|
||||
&conn->ccerr, DOQ_APP_ERROR_CODE, NULL, 0);
|
||||
#else
|
||||
ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0);
|
||||
ngtcp2_connection_close_error_set_application_error(&conn->last_error, DOQ_APP_ERROR_CODE, NULL, 0);
|
||||
#endif
|
||||
if(err_drop)
|
||||
*err_drop = 0;
|
||||
@@ -5472,7 +5545,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
if(ret == 0) {
|
||||
/* congestion limited */
|
||||
doq_conn_write_disable(conn);
|
||||
ngtcp2_conn_update_pkt_tx_time(conn->conn, ts);
|
||||
ngtcp2_conn_update_pkt_tx_time(conn->conn,
|
||||
doq_get_timestamp_nanosec());
|
||||
return 1;
|
||||
}
|
||||
sldns_buffer_set_position(c->doq_socket->pkt_buf, ret);
|
||||
@@ -5486,7 +5560,7 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
|
||||
if(stream)
|
||||
stream = stream->write_next;
|
||||
}
|
||||
ngtcp2_conn_update_pkt_tx_time(conn->conn, ts);
|
||||
ngtcp2_conn_update_pkt_tx_time(conn->conn, doq_get_timestamp_nanosec());
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -5563,32 +5637,35 @@ doq_table_pop_first(struct doq_table* table)
|
||||
}
|
||||
|
||||
int
|
||||
doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv)
|
||||
doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv, ngtcp2_tstamp* ts)
|
||||
{
|
||||
ngtcp2_tstamp expiry = ngtcp2_conn_get_expiry(conn->conn);
|
||||
ngtcp2_tstamp now = doq_get_timestamp_nanosec();
|
||||
ngtcp2_tstamp doq_expiry = ngtcp2_conn_get_expiry(conn->conn);
|
||||
ngtcp2_tstamp doq_now = doq_get_timestamp_nanosec();
|
||||
ngtcp2_tstamp t;
|
||||
struct timeval now = doq_get_timevalue();
|
||||
|
||||
if(expiry <= now) {
|
||||
if(doq_expiry <= doq_now || doq_expiry == UINT64_MAX) {
|
||||
/* UINT64_MAX means there is no next expiry. */
|
||||
/* The timer has already expired, add with zero timeout.
|
||||
* This should call the callback straight away. Calling it
|
||||
* from the event callbacks is cleaner than calling it here,
|
||||
* because then it is always called with the same locks and
|
||||
* so on. This routine only has the conn.lock. */
|
||||
t = now;
|
||||
t = doq_now;
|
||||
memcpy(tv, &now, sizeof(*tv));
|
||||
} else {
|
||||
t = expiry;
|
||||
t = doq_expiry;
|
||||
memset(tv, 0, sizeof(*tv));
|
||||
tv->tv_sec = (doq_expiry - doq_now) / NGTCP2_SECONDS;
|
||||
tv->tv_usec = ((doq_expiry - doq_now) / NGTCP2_MICROSECONDS)%1000000;
|
||||
timeval_add(tv, &now);
|
||||
}
|
||||
|
||||
/* convert to timeval */
|
||||
memset(tv, 0, sizeof(*tv));
|
||||
tv->tv_sec = t / NGTCP2_SECONDS;
|
||||
tv->tv_usec = (t / NGTCP2_MICROSECONDS)%1000000;
|
||||
*ts = t;
|
||||
|
||||
/* If we already have a timer, is it the right value? */
|
||||
if(conn->timer.timer_in_tree || conn->timer.timer_in_list) {
|
||||
if(conn->timer.time.tv_sec == tv->tv_sec &&
|
||||
conn->timer.time.tv_usec == tv->tv_usec)
|
||||
if(conn->timer.time_mono == *ts)
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
@@ -5609,13 +5686,12 @@ doq_conn_log_line(struct doq_conn* conn, char* s)
|
||||
int
|
||||
doq_conn_handle_timeout(struct doq_conn* conn)
|
||||
{
|
||||
ngtcp2_tstamp now = doq_get_timestamp_nanosec();
|
||||
int rv;
|
||||
|
||||
if(verbosity >= VERB_ALGO)
|
||||
doq_conn_log_line(conn, "timeout");
|
||||
|
||||
rv = ngtcp2_conn_handle_expiry(conn->conn, now);
|
||||
rv = ngtcp2_conn_handle_expiry(conn->conn, doq_get_timestamp_nanosec());
|
||||
if(rv != 0) {
|
||||
verbose(VERB_ALGO, "ngtcp2_conn_handle_expiry failed: %s",
|
||||
ngtcp2_strerror(rv));
|
||||
@@ -5662,6 +5738,8 @@ doq_table_quic_size_available(struct doq_table* table,
|
||||
struct config_file* cfg, size_t mem)
|
||||
{
|
||||
size_t cur;
|
||||
if (!table)
|
||||
return 0;
|
||||
lock_basic_lock(&table->size_lock);
|
||||
cur = table->current_size;
|
||||
lock_basic_unlock(&table->size_lock);
|
||||
|
||||
@@ -61,6 +61,8 @@ struct config_file;
|
||||
struct addrinfo;
|
||||
struct sldns_buffer;
|
||||
struct tcl_list;
|
||||
struct mesh_area;
|
||||
struct mesh_state;
|
||||
|
||||
/**
|
||||
* Listening for queries structure.
|
||||
@@ -538,8 +540,11 @@ void doq_table_delete(struct doq_table* table);
|
||||
struct doq_timer {
|
||||
/** The rbnode in the tree sorted by timeout value. Key this struct. */
|
||||
struct rbnode_type node;
|
||||
/** The timeout value. Monotonic value used with ngtcp2.
|
||||
* This time value is used for the tree operations. */
|
||||
ngtcp2_tstamp time_mono;
|
||||
/** The timeout value. Absolute time value. */
|
||||
struct timeval time;
|
||||
struct timeval time_real;
|
||||
/** If the timer is in the time tree, with the node. */
|
||||
int timer_in_tree;
|
||||
/** If there are more timers with the exact same timeout value,
|
||||
@@ -689,6 +694,11 @@ struct doq_stream {
|
||||
uint8_t* out;
|
||||
/** if the stream is on the write list */
|
||||
uint8_t on_write_list;
|
||||
/** The mesh area and mesh state, set when this stream's query was
|
||||
* dispatched into the mesh; used to detach the reply on stream close */
|
||||
struct mesh_area* mesh;
|
||||
/** the mesh state for the query, is nonNULL when there is one. */
|
||||
struct mesh_state* mesh_state;
|
||||
/** the prev and next on the write list, if on the list */
|
||||
struct doq_stream* write_prev, *write_next;
|
||||
};
|
||||
@@ -791,7 +801,16 @@ int doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
|
||||
/** send reply for a connection */
|
||||
int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
|
||||
struct sldns_buffer* buf);
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
|
||||
/** add mesh state to doq stream */
|
||||
void doq_stream_add_meshstate(struct doq_stream* stream,
|
||||
struct mesh_area* mesh, struct mesh_state* m);
|
||||
|
||||
/** remove mesh state from doq stream */
|
||||
void doq_stream_remove_mesh_state(struct doq_stream* stream);
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
/** the connection has write interest, wants to write packets */
|
||||
void doq_conn_write_enable(struct doq_conn* conn);
|
||||
|
||||
@@ -813,10 +832,12 @@ struct doq_conn* doq_table_pop_first(struct doq_table* table);
|
||||
* doq check if the timer for the conn needs to be changed.
|
||||
* @param conn: connection, caller must hold lock on it.
|
||||
* @param tv: time value, absolute time, returned.
|
||||
* @param ts: time stamp, absolute time, returned.
|
||||
* @return true if timer needs to be set to tv, false if no change is needed
|
||||
* to the timer. The timer is already set to the right time in that case.
|
||||
*/
|
||||
int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv);
|
||||
int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv,
|
||||
ngtcp2_tstamp* ts);
|
||||
|
||||
/** doq remove timer from tree */
|
||||
void doq_timer_tree_remove(struct doq_table* table, struct doq_timer* timer);
|
||||
@@ -829,11 +850,12 @@ void doq_timer_unset(struct doq_table* table, struct doq_timer* timer);
|
||||
|
||||
/** doq set the timer and add it. */
|
||||
void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
|
||||
struct doq_server_socket* worker_doq_socket, struct timeval* tv);
|
||||
struct doq_server_socket* worker_doq_socket, struct timeval* tv,
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
/** doq find a timeout in the timer tree */
|
||||
struct doq_timer* doq_timer_find_time(struct doq_table* table,
|
||||
struct timeval* tv);
|
||||
ngtcp2_tstamp ts);
|
||||
|
||||
/** doq handle timeout for a connection. Pass conn locked. Returns false for
|
||||
* deletion. */
|
||||
@@ -851,6 +873,9 @@ int doq_table_quic_size_available(struct doq_table* table,
|
||||
|
||||
/** doq get the quic size value */
|
||||
size_t doq_table_quic_size_get(struct doq_table* table);
|
||||
|
||||
/** get a timestamp in nanoseconds */
|
||||
ngtcp2_tstamp doq_get_timestamp_nanosec(void);
|
||||
#endif /* HAVE_NGTCP2 */
|
||||
|
||||
char* set_ip_dscp(int socket, int addrfamily, int ds);
|
||||
@@ -866,8 +891,4 @@ void doq_client_event_cb(int fd, short event, void* arg);
|
||||
/** timer event callback for testcode/doqclient */
|
||||
void doq_client_timer_cb(int fd, short event, void* arg);
|
||||
|
||||
#ifdef HAVE_NGTCP2
|
||||
/** get a timestamp in nanoseconds */
|
||||
ngtcp2_tstamp doq_get_timestamp_nanosec(void);
|
||||
#endif
|
||||
#endif /* LISTEN_DNSPORT_H */
|
||||
|
||||
+106
-75
@@ -56,6 +56,24 @@
|
||||
* with 16 bytes for an A record, a 64K packet has about 4000 max */
|
||||
#define LOCALZONE_RRSET_COUNT_MAX 4096
|
||||
|
||||
static const char* default_zones_reverse_array[] = {
|
||||
"127.in-addr.arpa.", /* reverse ip4 zone */
|
||||
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", /* reverse ip6 zone */
|
||||
0
|
||||
};
|
||||
const char** local_zones_default_reverse = default_zones_reverse_array;
|
||||
|
||||
static const char* default_zones_special_array[] = {
|
||||
"test.", /* RFC 6761 */
|
||||
"invalid.", /* RFC 6761 */
|
||||
"onion.", /* RFC 7686 */
|
||||
"home.arpa.", /* RFC 8375 */
|
||||
"resolver.arpa.", /* RFC 9462 */
|
||||
"service.arpa.", /* RFC 9665 */
|
||||
0
|
||||
};
|
||||
const char** local_zones_default_special = default_zones_special_array;
|
||||
|
||||
/** print all RRsets in local zone */
|
||||
static void
|
||||
local_zone_out(struct local_zone* z)
|
||||
@@ -650,7 +668,7 @@ lz_enter_rr_str(struct local_zones* zones, const char* rr)
|
||||
}
|
||||
labs = dname_count_size_labels(rr_name, &len);
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
|
||||
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type, 1);
|
||||
if(!z) {
|
||||
lock_rw_unlock(&zones->lock);
|
||||
fatal_exit("internal error: no zone for rr %s", rr);
|
||||
@@ -834,7 +852,7 @@ lz_nodefault(struct config_file* cfg, const char* name)
|
||||
|
||||
for(p = cfg->local_zones_nodefault; p; p = p->next) {
|
||||
/* compare zone name, lowercase, compare without ending . */
|
||||
if(strncasecmp(p->str, name, len) == 0 &&
|
||||
if(strncasecmp(p->str, name, len) == 0 &&
|
||||
(strlen(p->str) == len || (strlen(p->str)==len+1 &&
|
||||
p->str[len] == '.')))
|
||||
return 1;
|
||||
@@ -842,6 +860,45 @@ lz_nodefault(struct config_file* cfg, const char* name)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** enter reverse default zone */
|
||||
static int
|
||||
add_reverse_default(struct local_zones* zones, struct config_file* cfg,
|
||||
const char* name)
|
||||
{
|
||||
struct local_zone* z;
|
||||
char str[1024]; /* known long enough */
|
||||
if(lz_exists(zones, name) || lz_nodefault(cfg, name))
|
||||
return 1; /* do not enter default content */
|
||||
if(!(z=lz_enter_zone(zones, name, "static", LDNS_RR_CLASS_IN)))
|
||||
return 0;
|
||||
snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. "
|
||||
"nobody.invalid. 1 3600 1200 604800 10800", name);
|
||||
if(!lz_enter_rr_into_zone(z, str)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name);
|
||||
if(!lz_enter_rr_into_zone(z, str)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
if(strncasecmp("127.in-addr.arpa.", name, 17) == 0) {
|
||||
if(!lz_enter_rr_into_zone(z,
|
||||
"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
} else if(strncasecmp("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", name, 73) == 0) {
|
||||
snprintf(str, sizeof(str), "%s 10800 IN PTR localhost.", name);
|
||||
if(!lz_enter_rr_into_zone(z, str)) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/** enter (AS112) empty default zone */
|
||||
static int
|
||||
add_empty_default(struct local_zones* zones, struct config_file* cfg,
|
||||
@@ -902,72 +959,23 @@ int local_zone_enter_defaults(struct local_zones* zones, struct config_file* cfg
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
/* reverse ip4 zone */
|
||||
if(!lz_exists(zones, "127.in-addr.arpa.") &&
|
||||
!lz_nodefault(cfg, "127.in-addr.arpa.")) {
|
||||
if(!(z=lz_enter_zone(zones, "127.in-addr.arpa.", "static",
|
||||
LDNS_RR_CLASS_IN)) ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"127.in-addr.arpa. 10800 IN NS localhost.") ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"127.in-addr.arpa. 10800 IN SOA localhost. "
|
||||
"nobody.invalid. 1 3600 1200 604800 10800") ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
|
||||
|
||||
/* ip4 and ip6 reverse */
|
||||
for(zstr = local_zones_default_reverse; *zstr; zstr++) {
|
||||
if(!add_reverse_default(zones, cfg, *zstr)) {
|
||||
log_err("out of memory adding default zone");
|
||||
if(z) { lock_rw_unlock(&z->lock); }
|
||||
return 0;
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
/* reverse ip6 zone */
|
||||
if(!lz_exists(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.") &&
|
||||
!lz_nodefault(cfg, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.")) {
|
||||
if(!(z=lz_enter_zone(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", "static",
|
||||
LDNS_RR_CLASS_IN)) ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN NS localhost.") ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN SOA localhost. "
|
||||
"nobody.invalid. 1 3600 1200 604800 10800") ||
|
||||
!lz_enter_rr_into_zone(z,
|
||||
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN PTR localhost.")) {
|
||||
|
||||
/* special-use zones */
|
||||
for(zstr = local_zones_default_special; *zstr; zstr++) {
|
||||
if(!add_empty_default(zones, cfg, *zstr)) {
|
||||
log_err("out of memory adding default zone");
|
||||
if(z) { lock_rw_unlock(&z->lock); }
|
||||
return 0;
|
||||
}
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
/* home.arpa. zone (RFC 8375) */
|
||||
if(!add_empty_default(zones, cfg, "home.arpa.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
/* resolver.arpa. zone (RFC 9462) */
|
||||
if(!add_empty_default(zones, cfg, "resolver.arpa.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
/* service.arpa. zone (draft-ietf-dnssd-srp-25) */
|
||||
if(!add_empty_default(zones, cfg, "service.arpa.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
/* onion. zone (RFC 7686) */
|
||||
if(!add_empty_default(zones, cfg, "onion.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
/* test. zone (RFC 6761) */
|
||||
if(!add_empty_default(zones, cfg, "test.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
/* invalid. zone (RFC 6761) */
|
||||
if(!add_empty_default(zones, cfg, "invalid.")) {
|
||||
log_err("out of memory adding default zone");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* block AS112 zones, unless asked not to */
|
||||
if(!cfg->unblock_lan_zones) {
|
||||
for(zstr = as112_zones; *zstr; zstr++) {
|
||||
@@ -1062,14 +1070,15 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
|
||||
labs = dname_count_size_labels(rr_name, &len);
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
if(!local_zones_lookup(zones, rr_name, len, labs, rr_class,
|
||||
rr_type)) {
|
||||
rr_type, 1)) {
|
||||
/* Check if there is a zone that this could go
|
||||
* under but for different class; created zones are
|
||||
* always for LDNS_RR_CLASS_IN. Create the zone with
|
||||
* a different class but the same configured
|
||||
* local_zone_type. */
|
||||
struct local_zone* z = local_zones_lookup(zones,
|
||||
rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type);
|
||||
rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type,
|
||||
1);
|
||||
if(z) {
|
||||
uint8_t* name = memdup(z->name, z->namelen);
|
||||
size_t znamelen = z->namelen;
|
||||
@@ -1231,28 +1240,48 @@ local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg)
|
||||
|
||||
struct local_zone*
|
||||
local_zones_lookup(struct local_zones* zones,
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype)
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
|
||||
int foradd)
|
||||
{
|
||||
return local_zones_tags_lookup(zones, name, len, labs,
|
||||
dclass, dtype, NULL, 0, 1);
|
||||
dclass, dtype, NULL, 0, 1, foradd);
|
||||
}
|
||||
|
||||
struct local_zone*
|
||||
local_zones_tags_lookup(struct local_zones* zones,
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
|
||||
uint8_t* taglist, size_t taglen, int ignoretags)
|
||||
uint8_t* taglist, size_t taglen, int ignoretags, int foradd)
|
||||
{
|
||||
rbnode_type* res = NULL;
|
||||
struct local_zone *result;
|
||||
struct local_zone key;
|
||||
int m;
|
||||
/* for type DS use a zone higher when on a zonecut */
|
||||
if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) {
|
||||
dname_remove_label(&name, &len);
|
||||
labs--;
|
||||
}
|
||||
key.node.key = &key;
|
||||
key.dclass = dclass;
|
||||
/* for type DS use a zone higher when on a zonecut */
|
||||
if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) {
|
||||
/* If this is at a zone cut, of a local-zone, and it is
|
||||
* of type always_refuse. Then also refuse the type DS
|
||||
* for it. That could make it DNSSEC bogus, but it is
|
||||
* REFUSED anyway. It stops CNAME type answers in the
|
||||
* type DS lookup. */
|
||||
key.name = name;
|
||||
key.namelen = len;
|
||||
key.namelabs = labs;
|
||||
/* For additions and removals, use the ordinary rule,
|
||||
* to remove a label for type DS to locate the parent zone.
|
||||
* That is where the DS RR needs to be put. */
|
||||
if(!foradd &&
|
||||
(result=(struct local_zone*)rbtree_search(
|
||||
&zones->ztree, &key)) != NULL &&
|
||||
result->type == local_zone_always_refuse) {
|
||||
/* The type DS does not go up one label. */
|
||||
return result;
|
||||
} else {
|
||||
dname_remove_label(&name, &len);
|
||||
labs--;
|
||||
}
|
||||
}
|
||||
key.name = name;
|
||||
key.namelen = len;
|
||||
key.namelabs = labs;
|
||||
@@ -1863,7 +1892,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
|
||||
if(view->local_zones &&
|
||||
(z = local_zones_lookup(view->local_zones,
|
||||
qinfo->qname, qinfo->qname_len, labs,
|
||||
qinfo->qclass, qinfo->qtype))) {
|
||||
qinfo->qclass, qinfo->qtype, 0))) {
|
||||
lock_rw_rdlock(&z->lock);
|
||||
lzt = z->type;
|
||||
}
|
||||
@@ -1897,7 +1926,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
if(!(z = local_zones_tags_lookup(zones, qinfo->qname,
|
||||
qinfo->qname_len, labs, qinfo->qclass, qinfo->qtype,
|
||||
taglist, taglen, 0))) {
|
||||
taglist, taglen, 0, 0))) {
|
||||
lock_rw_unlock(&zones->lock);
|
||||
return 0;
|
||||
}
|
||||
@@ -2102,7 +2131,8 @@ local_zones_add_RR(struct local_zones* zones, const char* rr)
|
||||
/* could first try readlock then get writelock if zone does not exist,
|
||||
* but we do not add enough RRs (from multiple threads) to optimize */
|
||||
lock_rw_wrlock(&zones->lock);
|
||||
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
|
||||
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type,
|
||||
1);
|
||||
if(!z) {
|
||||
z = local_zones_add_zone(zones, rr_name, len, labs, rr_class,
|
||||
local_zone_transparent);
|
||||
@@ -2180,7 +2210,8 @@ void local_zones_del_data(struct local_zones* zones,
|
||||
|
||||
/* remove DS */
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS);
|
||||
z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS,
|
||||
1);
|
||||
if(z) {
|
||||
lock_rw_wrlock(&z->lock);
|
||||
d = local_zone_find_data(z, name, len, labs);
|
||||
@@ -2194,7 +2225,7 @@ void local_zones_del_data(struct local_zones* zones,
|
||||
|
||||
/* remove other types */
|
||||
lock_rw_rdlock(&zones->lock);
|
||||
z = local_zones_lookup(zones, name, len, labs, dclass, 0);
|
||||
z = local_zones_lookup(zones, name, len, labs, dclass, 0, 1);
|
||||
if(!z) {
|
||||
/* no such zone, we're done */
|
||||
lock_rw_unlock(&zones->lock);
|
||||
|
||||
+11
-3
@@ -57,6 +57,9 @@ struct sldns_buffer;
|
||||
struct comm_reply;
|
||||
struct config_strlist;
|
||||
|
||||
extern const char** local_zones_default_special;
|
||||
extern const char** local_zones_default_reverse;
|
||||
|
||||
/**
|
||||
* Local zone type
|
||||
* This type determines processing for queries that did not match
|
||||
@@ -262,11 +265,13 @@ void local_zone_delete(struct local_zone* z);
|
||||
* @param taglen: length of taglist.
|
||||
* @param ignoretags: lookup zone by name and class, regardless the
|
||||
* local-zone's tags.
|
||||
* @param foradd: if the lookup is for addition or removal of the type.
|
||||
* Used for type DS. The lookup for answers turns this off.
|
||||
* @return closest local_zone or NULL if no covering zone is found.
|
||||
*/
|
||||
struct local_zone* local_zones_tags_lookup(struct local_zones* zones,
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
|
||||
uint8_t* taglist, size_t taglen, int ignoretags);
|
||||
uint8_t* taglist, size_t taglen, int ignoretags, int foradd);
|
||||
|
||||
/**
|
||||
* Lookup zone that contains the given name, class.
|
||||
@@ -278,10 +283,13 @@ struct local_zone* local_zones_tags_lookup(struct local_zones* zones,
|
||||
* @param dclass: class to lookup.
|
||||
* @param dtype: type of the record, if type DS then a zone higher up is found
|
||||
* pass 0 to just plain find a zone for a name.
|
||||
* @param foradd: if the lookup is for addition or removal of the type.
|
||||
* Used for type DS. The lookup for answers turns this off.
|
||||
* @return closest local_zone or NULL if no covering zone is found.
|
||||
*/
|
||||
struct local_zone* local_zones_lookup(struct local_zones* zones,
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype);
|
||||
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
|
||||
int foradd);
|
||||
|
||||
/**
|
||||
* Debug helper. Print all zones
|
||||
@@ -565,7 +573,7 @@ enum respip_action {
|
||||
respip_always_nxdomain = local_zone_always_nxdomain,
|
||||
/** answer with nodata response */
|
||||
respip_always_nodata = local_zone_always_nodata,
|
||||
/** answer with nodata response */
|
||||
/** drop query */
|
||||
respip_always_deny = local_zone_always_deny,
|
||||
/** RPZ: truncate answer in order to force switch to tcp */
|
||||
respip_truncate = local_zone_truncate,
|
||||
|
||||
+128
-45
@@ -231,6 +231,7 @@ mesh_create(struct module_stack* stack, struct module_env* env)
|
||||
mesh->ans_expired = 0;
|
||||
mesh->ans_cachedb = 0;
|
||||
mesh->num_queries_discard_timeout = 0;
|
||||
mesh->num_queries_replyaddr_limit = 0;
|
||||
mesh->num_queries_wait_limit = 0;
|
||||
mesh->num_dns_error_reports = 0;
|
||||
mesh->max_reply_states = env->cfg->num_queries_per_thread;
|
||||
@@ -296,12 +297,14 @@ int mesh_make_new_space(struct mesh_area* mesh, sldns_buffer* qbuf)
|
||||
if(mesh->num_reply_states < mesh->max_reply_states)
|
||||
return 1;
|
||||
/* try to kick out a jostle-list item */
|
||||
if(m && m->reply_list && m->list_select == mesh_jostle_list) {
|
||||
if(m && m->list_select == mesh_jostle_list) {
|
||||
/* how old is it? */
|
||||
struct timeval age;
|
||||
timeval_subtract(&age, mesh->env->now_tv,
|
||||
&m->reply_list->start_time);
|
||||
if(timeval_smaller(&mesh->jostle_max, &age)) {
|
||||
if(m->has_first_reply_time)
|
||||
timeval_subtract(&age, mesh->env->now_tv,
|
||||
&m->first_reply_time);
|
||||
if(!m->has_first_reply_time ||
|
||||
timeval_smaller(&mesh->jostle_max, &age)) {
|
||||
/* its a goner */
|
||||
log_nametypeclass(VERB_ALGO, "query jostled out to "
|
||||
"make space for a new one",
|
||||
@@ -441,9 +444,18 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
if(!infra_wait_limit_allowed(mesh->env->infra_cache, rep,
|
||||
edns->cookie_valid, mesh->env->cfg)) {
|
||||
verbose(VERB_ALGO, "Too many queries waiting from the IP. "
|
||||
"dropping incoming query.");
|
||||
comm_point_drop_reply(rep);
|
||||
"servfail incoming query.");
|
||||
mesh->num_queries_wait_limit++;
|
||||
edns_opt_list_append_ede(&edns->opt_list_out,
|
||||
mesh->env->scratch, LDNS_EDE_OTHER,
|
||||
"Too many queries queued up and waiting from the IP");
|
||||
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
|
||||
LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
|
||||
edns->opt_list_inplace_cb_out = NULL;
|
||||
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
|
||||
qinfo, qid, qflags, edns);
|
||||
regional_free_all(mesh->env->scratch);
|
||||
comm_point_send_reply(rep);
|
||||
return;
|
||||
}
|
||||
if(!unique)
|
||||
@@ -453,6 +465,10 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
if(!mesh_make_new_space(mesh, rep->c->buffer)) {
|
||||
verbose(VERB_ALGO, "Too many queries. dropping "
|
||||
"incoming query.");
|
||||
if(rep->c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->c->h2_stream);
|
||||
else if(rep->c->type == comm_doq && rep->doq_stream)
|
||||
doq_stream_remove_mesh_state(rep->doq_stream);
|
||||
comm_point_drop_reply(rep);
|
||||
mesh->stats_dropped++;
|
||||
return;
|
||||
@@ -464,8 +480,12 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
if(mesh->num_reply_addrs > mesh->max_reply_states*16) {
|
||||
verbose(VERB_ALGO, "Too many requests queued. "
|
||||
"dropping incoming query.");
|
||||
if(rep->c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->c->h2_stream);
|
||||
else if(rep->c->type == comm_doq && rep->doq_stream)
|
||||
doq_stream_remove_mesh_state(rep->doq_stream);
|
||||
comm_point_drop_reply(rep);
|
||||
mesh->stats_dropped++;
|
||||
mesh->num_queries_replyaddr_limit++;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -536,6 +556,8 @@ 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) {
|
||||
doq_stream_add_meshstate(rep->doq_stream, mesh, s);
|
||||
}
|
||||
/* add serve expired timer if required and not already there */
|
||||
if(timeout && !mesh_serve_expired_init(s, timeout)) {
|
||||
@@ -589,6 +611,8 @@ servfail_mem:
|
||||
qinfo, qid, qflags, edns);
|
||||
if(rep->c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->c->h2_stream);
|
||||
else if(rep->c->type == comm_doq && rep->doq_stream)
|
||||
doq_stream_remove_mesh_state(rep->doq_stream);
|
||||
comm_point_send_reply(rep);
|
||||
if(added)
|
||||
mesh_state_delete(&s->s);
|
||||
@@ -909,8 +933,7 @@ cfg_region_strlist_copy(struct regional* region, struct config_strlist* list)
|
||||
return result;
|
||||
}
|
||||
|
||||
/** Copy the client info to the query region. */
|
||||
static struct respip_client_info*
|
||||
struct respip_client_info*
|
||||
mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
|
||||
{
|
||||
size_t i;
|
||||
@@ -955,6 +978,11 @@ mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
|
||||
cinfo->view->name);
|
||||
if(!client_info->view_name)
|
||||
return NULL;
|
||||
} else if(cinfo->view_name) {
|
||||
client_info->view_name = regional_strdup(region,
|
||||
cinfo->view_name);
|
||||
if(!client_info->view_name)
|
||||
return NULL;
|
||||
}
|
||||
return client_info;
|
||||
}
|
||||
@@ -1022,6 +1050,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
|
||||
mstate->s.no_cache_store = 0;
|
||||
mstate->s.need_refetch = 0;
|
||||
mstate->s.was_ratelimited = 0;
|
||||
mstate->s.error_response_cache = 0;
|
||||
mstate->s.qstarttime = *env->now;
|
||||
|
||||
/* init modules */
|
||||
@@ -1061,6 +1090,14 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
if(!mstate->replies_sent) {
|
||||
struct mesh_reply* rep = mstate->reply_list;
|
||||
struct mesh_cb* cb;
|
||||
/* One http2 stream could bring down its comm_point along with
|
||||
* the other streams which could share the same query. Do all
|
||||
* the http2 stream bookkeeping upfront. */
|
||||
for(; rep; rep=rep->next) {
|
||||
if(rep->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->h2_stream);
|
||||
}
|
||||
rep = mstate->reply_list;
|
||||
/* in tcp_req_info, the mstates linked are removed, but
|
||||
* the reply_list is now NULL, so the remove-from-empty-list
|
||||
* takes no time and also it does not do the mesh accounting */
|
||||
@@ -1068,8 +1105,6 @@ mesh_state_cleanup(struct mesh_state* mstate)
|
||||
for(; rep; rep=rep->next) {
|
||||
infra_wait_limit_dec(mesh->env->infra_cache,
|
||||
&rep->query_reply, mesh->env->cfg);
|
||||
if(rep->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(rep->h2_stream);
|
||||
comm_point_drop_reply(&rep->query_reply);
|
||||
log_assert(mesh->num_reply_addrs > 0);
|
||||
mesh->num_reply_addrs--;
|
||||
@@ -1461,6 +1496,10 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
|
||||
* for HTTP/2 stream to refer to mesh state, in case
|
||||
* connection gets cleanup before HTTP/2 stream close. */
|
||||
r->h2_stream->mesh_state = NULL;
|
||||
#ifdef HAVE_NGTCP2
|
||||
} else if(r->query_reply.doq_stream) {
|
||||
r->query_reply.doq_stream->mesh_state = NULL;
|
||||
#endif
|
||||
}
|
||||
/* send the reply */
|
||||
/* We don't reuse the encoded answer if:
|
||||
@@ -1615,9 +1654,9 @@ static void dns_error_reporting(struct module_qstate* qstate,
|
||||
opt = edns_opt_list_find(qstate->edns_opts_back_in,
|
||||
LDNS_EDNS_REPORT_CHANNEL);
|
||||
if(!opt) return;
|
||||
agent_domain_len = opt->opt_len;
|
||||
agent_domain = opt->opt_data;
|
||||
if(dname_valid(agent_domain, agent_domain_len) < 3) {
|
||||
agent_domain_len = dname_valid(agent_domain, opt->opt_len);
|
||||
if(agent_domain_len < 3) {
|
||||
/* The agent domain needs to be a valid dname that is not the
|
||||
* root; from RFC9567. */
|
||||
return;
|
||||
@@ -1728,28 +1767,41 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
dns_error_reporting(&mstate->s, rep);
|
||||
|
||||
for(r = mstate->reply_list; r; r = r->next) {
|
||||
struct timeval old;
|
||||
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
|
||||
if(mstate->s.env->cfg->discard_timeout != 0 &&
|
||||
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
|
||||
mstate->s.env->cfg->discard_timeout) {
|
||||
/* Drop the reply, it is too old */
|
||||
/* briefly set the reply_list to NULL, so that the
|
||||
* tcp req info cleanup routine that calls the mesh
|
||||
* to deregister the meshstate for it is not done
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
mstate->s.env->mesh->num_queries_discard_timeout++;
|
||||
continue;
|
||||
if(mesh_is_udp(r)) {
|
||||
/* For UDP queries, the old replies are discarded.
|
||||
* This stops a large volume of old replies from
|
||||
* building up.
|
||||
* The stream replies, are not discarded. The
|
||||
* stream is open, the other side is waiting.
|
||||
* Some answer is needed, even if servfail, but the
|
||||
* real reply is ready to go, so that is given. */
|
||||
struct timeval old;
|
||||
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
|
||||
if(mstate->s.env->cfg->discard_timeout != 0 &&
|
||||
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
|
||||
mstate->s.env->cfg->discard_timeout) {
|
||||
/* Drop the reply, it is too old */
|
||||
/* briefly set the reply_list to NULL, so that the
|
||||
* tcp req info cleanup routine that calls the mesh
|
||||
* to deregister the meshstate for it is not done
|
||||
* because the list is NULL and also accounting is not
|
||||
* done there, but instead we do that here. */
|
||||
struct mesh_reply* reply_list = mstate->reply_list;
|
||||
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
|
||||
infra_wait_limit_dec(mstate->s.env->infra_cache,
|
||||
&r->query_reply, mstate->s.env->cfg);
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
else if(r->query_reply.doq_stream)
|
||||
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
|
||||
mstate->s.env->mesh->num_reply_addrs--;
|
||||
mstate->s.env->mesh->num_queries_discard_timeout++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
@@ -1780,9 +1832,13 @@ void mesh_query_done(struct mesh_state* mstate)
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2) {
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
} else if(r->query_reply.doq_stream) {
|
||||
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
|
||||
}
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
|
||||
mstate->s.env->mesh->num_reply_addrs--;
|
||||
} else {
|
||||
struct sldns_buffer* r_buffer = r->query_reply.c->buffer;
|
||||
if(r->query_reply.c->tcp_req_info) {
|
||||
@@ -1961,6 +2017,10 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
r->qid = qid;
|
||||
r->qflags = qflags;
|
||||
r->start_time = *s->s.env->now_tv;
|
||||
if(s->reply_list == NULL && !s->has_first_reply_time) {
|
||||
s->first_reply_time = r->start_time;
|
||||
s->has_first_reply_time = 1;
|
||||
}
|
||||
r->next = s->reply_list;
|
||||
r->qname = regional_alloc_init(s->s.region, qinfo->qname,
|
||||
s->s.qinfo.qname_len);
|
||||
@@ -1969,6 +2029,8 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
|
||||
if(rep->c->use_h2)
|
||||
r->h2_stream = rep->c->h2_stream;
|
||||
else r->h2_stream = NULL;
|
||||
if(rep->c->type != comm_doq)
|
||||
r->query_reply.doq_stream = NULL;
|
||||
|
||||
/* Data related to local alias stored in 'qinfo' (if any) is ephemeral
|
||||
* and can be different for different original queries (even if the
|
||||
@@ -2273,6 +2335,7 @@ mesh_stats_clear(struct mesh_area* mesh)
|
||||
memset(&mesh->rpz_action[0], 0, sizeof(size_t)*UB_STATS_RPZ_ACTION_NUM);
|
||||
mesh->ans_nodata = 0;
|
||||
mesh->num_queries_discard_timeout = 0;
|
||||
mesh->num_queries_replyaddr_limit = 0;
|
||||
mesh->num_queries_wait_limit = 0;
|
||||
mesh->num_dns_error_reports = 0;
|
||||
}
|
||||
@@ -2325,7 +2388,7 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
|
||||
}
|
||||
|
||||
void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
struct comm_point* cp)
|
||||
struct comm_point* cp, struct doq_stream* doq_stream)
|
||||
{
|
||||
struct mesh_reply* n, *prev = NULL;
|
||||
n = m->reply_list;
|
||||
@@ -2333,7 +2396,8 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
* there is no accounting twice */
|
||||
if(!n) return; /* nothing to remove, also no accounting needed */
|
||||
while(n) {
|
||||
if(n->query_reply.c == cp) {
|
||||
if(n->query_reply.c == cp
|
||||
&& (!doq_stream || n->query_reply.doq_stream == doq_stream)) {
|
||||
/* unlink it */
|
||||
if(prev) prev->next = n->next;
|
||||
else m->reply_list = n->next;
|
||||
@@ -2342,6 +2406,14 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
mesh->num_reply_addrs--;
|
||||
infra_wait_limit_dec(mesh->env->infra_cache,
|
||||
&n->query_reply, mesh->env->cfg);
|
||||
/* We may be removing more than one http2 stream (they
|
||||
* share the same comm_point); make sure the streams
|
||||
* 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;
|
||||
#endif
|
||||
|
||||
/* prev = prev; */
|
||||
n = n->next;
|
||||
@@ -2382,9 +2454,10 @@ apply_respip_action(struct module_qstate* qstate,
|
||||
|
||||
/* xxx_deny actions mean dropping the reply, unless the original reply
|
||||
* was redirected to response-ip data. */
|
||||
if((actinfo->action == respip_deny ||
|
||||
if(actinfo->action == respip_always_deny ||
|
||||
((actinfo->action == respip_deny ||
|
||||
actinfo->action == respip_inform_deny) &&
|
||||
*encode_repp == rep)
|
||||
*encode_repp == rep))
|
||||
*encode_repp = NULL;
|
||||
|
||||
return 1;
|
||||
@@ -2449,12 +2522,15 @@ mesh_serve_expired_callback(void* arg)
|
||||
qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep,
|
||||
qstate->env->auth_zones)) {
|
||||
return;
|
||||
} else if(partial_rep &&
|
||||
!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
|
||||
} else if(partial_rep) {
|
||||
if(!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
|
||||
qstate->client_info, must_validate, &encode_rep, qstate->region,
|
||||
qstate->env->auth_zones, qstate->env->views,
|
||||
qstate->env->respip_set)) {
|
||||
return;
|
||||
return;
|
||||
}
|
||||
/* merge succeeded; final reply, no further alias pass */
|
||||
partial_rep = NULL;
|
||||
}
|
||||
if(!encode_rep || alias_rrset) {
|
||||
if(!encode_rep) {
|
||||
@@ -2465,6 +2541,7 @@ mesh_serve_expired_callback(void* arg)
|
||||
partial_rep = encode_rep;
|
||||
}
|
||||
}
|
||||
msg->rep = encode_rep;
|
||||
/* We've found a partial reply ending with an
|
||||
* alias. Replace the lookup qinfo for the
|
||||
* alias target and lookup the cache again to
|
||||
@@ -2491,9 +2568,10 @@ mesh_serve_expired_callback(void* arg)
|
||||
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
|
||||
|
||||
for(r = mstate->reply_list; r; r = r->next) {
|
||||
struct timeval old;
|
||||
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
|
||||
if(mstate->s.env->cfg->discard_timeout != 0 &&
|
||||
if(mesh_is_udp(r)) {
|
||||
struct timeval old;
|
||||
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
|
||||
if(mstate->s.env->cfg->discard_timeout != 0 &&
|
||||
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
|
||||
mstate->s.env->cfg->discard_timeout) {
|
||||
/* Drop the reply, it is too old */
|
||||
@@ -2509,10 +2587,15 @@ mesh_serve_expired_callback(void* arg)
|
||||
mstate->reply_list = NULL;
|
||||
if(r->query_reply.c->use_h2)
|
||||
http2_stream_remove_mesh_state(r->h2_stream);
|
||||
else if(r->query_reply.doq_stream)
|
||||
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
|
||||
comm_point_drop_reply(&r->query_reply);
|
||||
mstate->reply_list = reply_list;
|
||||
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
|
||||
mstate->s.env->mesh->num_reply_addrs--;
|
||||
mstate->s.env->mesh->num_queries_discard_timeout++;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
|
||||
+15
-1
@@ -141,6 +141,8 @@ struct mesh_area {
|
||||
size_t rpz_action[UB_STATS_RPZ_ACTION_NUM];
|
||||
/** stats, number of queries removed due to discard-timeout */
|
||||
size_t num_queries_discard_timeout;
|
||||
/** stats, number of queries removed due to replyaddr limit */
|
||||
size_t num_queries_replyaddr_limit;
|
||||
/** stats, number of queries removed due to wait-limit */
|
||||
size_t num_queries_wait_limit;
|
||||
/** stats, number of dns error reports generated */
|
||||
@@ -189,6 +191,12 @@ struct mesh_state {
|
||||
struct module_qstate s;
|
||||
/** the list of replies to clients for the results */
|
||||
struct mesh_reply* reply_list;
|
||||
/** if it has a first reply time */
|
||||
int has_first_reply_time;
|
||||
/** wall-clock time the first client reply was attached;
|
||||
* used by mesh_make_new_space() so duplicate retransmits
|
||||
* cannot reset jostle aging. */
|
||||
struct timeval first_reply_time;
|
||||
/** the list of callbacks for the results */
|
||||
struct mesh_cb* cb_list;
|
||||
/** set of superstates (that want this state's result)
|
||||
@@ -675,9 +683,11 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
|
||||
* @param mesh: to update the counters.
|
||||
* @param m: the mesh state.
|
||||
* @param cp: the comm_point to remove from the list.
|
||||
* @param doq_stream: if not NULL, it specifies the doq_stream to match
|
||||
* for the delete.
|
||||
*/
|
||||
void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
|
||||
struct comm_point* cp);
|
||||
struct comm_point* cp, struct doq_stream* doq_stream);
|
||||
|
||||
/** Callback for when the serve expired client timer has run out. Tries to
|
||||
* find an expired answer in the cache and reply that to the client.
|
||||
@@ -728,4 +738,8 @@ void mesh_respond_serve_expired(struct mesh_state* mstate);
|
||||
void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo,
|
||||
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg);
|
||||
|
||||
/** Copy the client info to the query region. */
|
||||
struct respip_client_info* mesh_copy_client_info(struct regional* region,
|
||||
struct respip_client_info* cinfo);
|
||||
|
||||
#endif /* SERVICES_MESH_H */
|
||||
|
||||
+379
-74
@@ -160,6 +160,19 @@ reuse_cmp_addrportssl(const void* key1, const void* key2)
|
||||
return 1;
|
||||
if(!r1->is_ssl && r2->is_ssl)
|
||||
return -1;
|
||||
|
||||
/* compare tls_auth_name if SSL-enabled */
|
||||
if(r1->is_ssl) {
|
||||
if(r1->tls_auth_name && !r2->tls_auth_name)
|
||||
return 1;
|
||||
if(!r1->tls_auth_name && r2->tls_auth_name)
|
||||
return -1;
|
||||
if(r1->tls_auth_name && r2->tls_auth_name) {
|
||||
r = strcmp(r1->tls_auth_name, r2->tls_auth_name);
|
||||
if(r != 0)
|
||||
return r;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -195,6 +208,7 @@ static void
|
||||
waiting_tcp_delete(struct waiting_tcp* w)
|
||||
{
|
||||
if(!w) return;
|
||||
free(w->tls_auth_name);
|
||||
if(w->timer)
|
||||
comm_timer_delete(w->timer);
|
||||
free(w);
|
||||
@@ -531,7 +545,7 @@ reuse_tcp_insert(struct outside_network* outnet, struct pending_tcp* pend_tcp)
|
||||
/** find reuse tcp stream to destination for query, or NULL if none */
|
||||
static struct reuse_tcp*
|
||||
reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
|
||||
socklen_t addrlen, int use_ssl)
|
||||
socklen_t addrlen, int use_ssl, char* tls_auth_name)
|
||||
{
|
||||
struct waiting_tcp key_w;
|
||||
struct pending_tcp key_p;
|
||||
@@ -545,8 +559,10 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
|
||||
key_p.c = &c;
|
||||
key_p.reuse.pending = &key_p;
|
||||
key_p.reuse.node.key = &key_p.reuse;
|
||||
if(use_ssl)
|
||||
if(use_ssl) {
|
||||
key_p.reuse.is_ssl = 1;
|
||||
key_p.reuse.tls_auth_name = tls_auth_name;
|
||||
}
|
||||
if(addrlen > (socklen_t)sizeof(key_p.reuse.addr))
|
||||
return NULL;
|
||||
memmove(&key_p.reuse.addr, addr, addrlen);
|
||||
@@ -646,6 +662,7 @@ static int
|
||||
outnet_tcp_take_into_use(struct waiting_tcp* w)
|
||||
{
|
||||
struct pending_tcp* pend = w->outnet->tcp_free;
|
||||
char* tls_auth_name = NULL;
|
||||
int s;
|
||||
log_assert(pend);
|
||||
log_assert(w->pkt);
|
||||
@@ -746,7 +763,22 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
|
||||
comm_point_tcp_win_bio_cb(pend->c, pend->c->ssl);
|
||||
#endif
|
||||
pend->c->ssl_shake_state = comm_ssl_shake_write;
|
||||
if(!set_auth_name_on_ssl(pend->c->ssl, w->tls_auth_name,
|
||||
if(w->tls_auth_name) {
|
||||
/* strdup the auth name, while not linked the list yet,
|
||||
* in case of failure, easy cleanup. */
|
||||
tls_auth_name = strdup(w->tls_auth_name);
|
||||
if(!tls_auth_name) {
|
||||
log_err("out of memory: alloc tls auth name");
|
||||
pend->c->fd = s;
|
||||
#ifdef HAVE_SSL
|
||||
SSL_free(pend->c->ssl);
|
||||
#endif
|
||||
pend->c->ssl = NULL;
|
||||
comm_point_close(pend->c);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(!set_auth_name_on_ssl(pend->c->ssl, tls_auth_name,
|
||||
w->outnet->tls_use_sni)) {
|
||||
pend->c->fd = s;
|
||||
#ifdef HAVE_SSL
|
||||
@@ -754,6 +786,7 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
|
||||
#endif
|
||||
pend->c->ssl = NULL;
|
||||
comm_point_close(pend->c);
|
||||
free(tls_auth_name);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -778,9 +811,20 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
|
||||
if(pend->reuse.node.key)
|
||||
reuse_tcp_remove_tree_list(w->outnet, &pend->reuse);
|
||||
|
||||
if(pend->c->ssl)
|
||||
if(pend->c->ssl) {
|
||||
pend->reuse.is_ssl = 1;
|
||||
else pend->reuse.is_ssl = 0;
|
||||
if(pend->reuse.tls_auth_name)
|
||||
free(pend->reuse.tls_auth_name);
|
||||
pend->reuse.tls_auth_name = tls_auth_name;
|
||||
tls_auth_name = NULL;
|
||||
} else {
|
||||
pend->reuse.is_ssl = 0;
|
||||
if(pend->reuse.tls_auth_name)
|
||||
free(pend->reuse.tls_auth_name);
|
||||
pend->reuse.tls_auth_name = NULL;
|
||||
}
|
||||
/* free tls auth name if nonNULL */
|
||||
free(tls_auth_name);
|
||||
/* insert in reuse by address tree if not already inserted there */
|
||||
(void)reuse_tcp_insert(w->outnet, pend);
|
||||
reuse_tree_by_id_insert(&pend->reuse, w);
|
||||
@@ -969,7 +1013,7 @@ use_free_buffer(struct outside_network* outnet)
|
||||
(!outnet->tcp_reuse_first && !outnet->tcp_reuse_last) ||
|
||||
(outnet->tcp_reuse_first && outnet->tcp_reuse_last));
|
||||
reuse = reuse_tcp_find(outnet, &w->addr, w->addrlen,
|
||||
w->ssl_upstream);
|
||||
w->ssl_upstream, w->tls_auth_name);
|
||||
/* re-select an ID when moving to a new TCP buffer */
|
||||
w->id = tcp_select_id(outnet, reuse);
|
||||
LDNS_ID_SET(w->pkt, w->id);
|
||||
@@ -1198,6 +1242,10 @@ decommission_pending_tcp(struct outside_network* outnet,
|
||||
/* needs unlink from the reuse tree to get deleted */
|
||||
reuse_tcp_remove_tree_list(outnet, &pend->reuse);
|
||||
}
|
||||
if(pend->reuse.tls_auth_name) {
|
||||
free(pend->reuse.tls_auth_name);
|
||||
pend->reuse.tls_auth_name = NULL;
|
||||
}
|
||||
/* free SSL structure after remove from outnet tcp reuse tree,
|
||||
* because the c->ssl null or not is used for sorting in the tree */
|
||||
if(pend->c->ssl) {
|
||||
@@ -1433,7 +1481,7 @@ portcomm_loweruse(struct outside_network* outnet, struct port_comm* pc)
|
||||
pif = pc->pif;
|
||||
log_assert(pif->inuse > 0);
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pif->avail_ports[pif->avail_total - pif->inuse] = pc->number;
|
||||
shared_ports_return_port(outnet->shared_ports, pif->shpif, pc->number);
|
||||
#endif
|
||||
pif->inuse--;
|
||||
pif->out[pc->index] = pif->out[pif->inuse];
|
||||
@@ -1647,19 +1695,19 @@ create_pending_tcp(struct outside_network* outnet, size_t bufsize)
|
||||
}
|
||||
|
||||
/** setup an outgoing interface, ready address */
|
||||
static int setup_if(struct port_if* pif, const char* addrstr,
|
||||
int* avail, int numavail, size_t numfd)
|
||||
static int setup_if(struct port_if* pif, const char* addrstr, size_t numfd,
|
||||
struct shared_ports* shp)
|
||||
{
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pif->avail_total = numavail;
|
||||
pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int));
|
||||
if(!pif->avail_ports)
|
||||
return 0;
|
||||
#endif
|
||||
if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) &&
|
||||
!netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT,
|
||||
&pif->addr, &pif->addrlen, &pif->pfxlen))
|
||||
return 0;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pif->shpif = shared_ports_find_if(shp, &pif->addr, pif->addrlen,
|
||||
pif->pfxlen);
|
||||
#else
|
||||
(void)shp;
|
||||
#endif
|
||||
pif->maxout = (int)numfd;
|
||||
pif->inuse = 0;
|
||||
pif->out = (struct port_comm**)calloc(numfd,
|
||||
@@ -1673,12 +1721,12 @@ struct outside_network*
|
||||
outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
size_t num_ports, char** ifs, int num_ifs, int do_ip4,
|
||||
int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra,
|
||||
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
||||
int numavailports, size_t unwanted_threshold, int tcp_mss,
|
||||
struct ub_randstate* rnd, int use_caps_for_id,
|
||||
size_t unwanted_threshold, int tcp_mss,
|
||||
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
|
||||
void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv,
|
||||
int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout,
|
||||
int tcp_auth_query_timeout)
|
||||
int tcp_auth_query_timeout, struct shared_ports* shared_ports)
|
||||
{
|
||||
struct outside_network* outnet = (struct outside_network*)
|
||||
calloc(1, sizeof(struct outside_network));
|
||||
@@ -1713,6 +1761,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
outnet->do_udp = do_udp;
|
||||
outnet->tcp_mss = tcp_mss;
|
||||
outnet->ip_dscp = dscp;
|
||||
outnet->shared_ports = shared_ports;
|
||||
#ifndef S_SPLINT_S
|
||||
if(delayclose) {
|
||||
outnet->delayclose = 1;
|
||||
@@ -1723,7 +1772,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
if(udp_connect) {
|
||||
outnet->udp_connect = 1;
|
||||
}
|
||||
if(numavailports == 0 || num_ports == 0) {
|
||||
if(num_ports == 0) {
|
||||
log_err("no outgoing ports available");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
@@ -1784,13 +1833,13 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
/* allocate interfaces */
|
||||
if(num_ifs == 0) {
|
||||
if(do_ip4 && !setup_if(&outnet->ip4_ifs[0], "0.0.0.0",
|
||||
availports, numavailports, num_ports)) {
|
||||
num_ports, outnet->shared_ports)) {
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
}
|
||||
if(do_ip6 && !setup_if(&outnet->ip6_ifs[0], "::",
|
||||
availports, numavailports, num_ports)) {
|
||||
num_ports, outnet->shared_ports)) {
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
@@ -1801,7 +1850,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
for(i=0; i<num_ifs; i++) {
|
||||
if(str_is_ip6(ifs[i]) && do_ip6) {
|
||||
if(!setup_if(&outnet->ip6_ifs[done_6], ifs[i],
|
||||
availports, numavailports, num_ports)){
|
||||
num_ports, outnet->shared_ports)){
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
@@ -1810,7 +1859,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
|
||||
}
|
||||
if(!str_is_ip6(ifs[i]) && do_ip4) {
|
||||
if(!setup_if(&outnet->ip4_ifs[done_4], ifs[i],
|
||||
availports, numavailports, num_ports)){
|
||||
num_ports, outnet->shared_ports)){
|
||||
log_err("malloc failed");
|
||||
outside_network_delete(outnet);
|
||||
return NULL;
|
||||
@@ -1888,9 +1937,6 @@ outside_network_delete(struct outside_network* outnet)
|
||||
comm_point_delete(pc->cp);
|
||||
free(pc);
|
||||
}
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
free(outnet->ip4_ifs[i].avail_ports);
|
||||
#endif
|
||||
free(outnet->ip4_ifs[i].out);
|
||||
}
|
||||
free(outnet->ip4_ifs);
|
||||
@@ -1904,9 +1950,6 @@ outside_network_delete(struct outside_network* outnet)
|
||||
comm_point_delete(pc->cp);
|
||||
free(pc);
|
||||
}
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
free(outnet->ip6_ifs[i].avail_ports);
|
||||
#endif
|
||||
free(outnet->ip6_ifs[i].out);
|
||||
}
|
||||
free(outnet->ip6_ifs);
|
||||
@@ -1922,6 +1965,10 @@ outside_network_delete(struct outside_network* outnet)
|
||||
* the tcp conn is working on */
|
||||
decommission_pending_tcp(outnet, pend);
|
||||
}
|
||||
if(pend->reuse.tls_auth_name) {
|
||||
free(pend->reuse.tls_auth_name);
|
||||
pend->reuse.tls_auth_name = NULL;
|
||||
}
|
||||
comm_point_delete(outnet->tcp_conns[i]->c);
|
||||
free(outnet->tcp_conns[i]);
|
||||
outnet->tcp_conns[i] = NULL;
|
||||
@@ -2112,7 +2159,10 @@ static int
|
||||
select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
int num_if, struct port_if* ifs)
|
||||
{
|
||||
int my_if, my_port, fd, portno, inuse, tries=0;
|
||||
int my_if, fd, portno, inuse, tries=0;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
int reused;
|
||||
#endif
|
||||
struct port_if* pif;
|
||||
/* randomly select interface and port */
|
||||
if(num_if == 0) {
|
||||
@@ -2126,37 +2176,35 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
my_if = ub_random_max(outnet->rnd, num_if);
|
||||
pif = &ifs[my_if];
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
if(outnet->udp_connect) {
|
||||
/* if we connect() we cannot reuse fds for a port */
|
||||
if(pif->inuse >= pif->avail_total) {
|
||||
tries++;
|
||||
if(tries < MAX_PORT_RETRY)
|
||||
continue;
|
||||
log_err("failed to find an open port, drop msg");
|
||||
return 0;
|
||||
}
|
||||
my_port = pif->inuse + ub_random_max(outnet->rnd,
|
||||
pif->avail_total - pif->inuse);
|
||||
} else {
|
||||
my_port = ub_random_max(outnet->rnd, pif->avail_total);
|
||||
if(my_port < pif->inuse) {
|
||||
/* port already open */
|
||||
pend->pc = pif->out[my_port];
|
||||
verbose(VERB_ALGO, "using UDP if=%d port=%d",
|
||||
my_if, pend->pc->number);
|
||||
break;
|
||||
}
|
||||
if(!shared_ports_fetch_random(outnet->shared_ports,
|
||||
pif->shpif, outnet->rnd, outnet->udp_connect,
|
||||
pif->inuse, &portno, &reused)) {
|
||||
tries++;
|
||||
if(tries < MAX_PORT_RETRY)
|
||||
continue;
|
||||
log_err("failed to find an open port, drop msg");
|
||||
return 0;
|
||||
}
|
||||
if(reused) {
|
||||
/* port already open */
|
||||
log_assert(portno < pif->inuse);
|
||||
pend->pc = pif->out[portno];
|
||||
verbose(VERB_ALGO, "using UDP if=%d port=%d",
|
||||
my_if, pend->pc->number);
|
||||
break;
|
||||
}
|
||||
/* try to open new port, if fails, loop to try again */
|
||||
log_assert(pif->inuse < pif->maxout);
|
||||
portno = pif->avail_ports[my_port - pif->inuse];
|
||||
#else
|
||||
my_port = portno = 0;
|
||||
portno = 0;
|
||||
#endif
|
||||
/* try to open new port, if fails, loop to try again */
|
||||
fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen,
|
||||
portno, &inuse, outnet->rnd, outnet->ip_dscp);
|
||||
if(fd == -1 && !inuse) {
|
||||
/* nonrecoverable error making socket */
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
shared_ports_return_port(outnet->shared_ports,
|
||||
pif->shpif, portno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
if(fd != -1) {
|
||||
@@ -2173,6 +2221,11 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
pend->addrlen);
|
||||
}
|
||||
sock_close(fd);
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
shared_ports_return_port(
|
||||
outnet->shared_ports,
|
||||
pif->shpif, portno);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
@@ -2190,14 +2243,14 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
|
||||
|
||||
/* grab port in interface */
|
||||
pif->out[pif->inuse] = pend->pc;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pif->avail_ports[my_port - pif->inuse] =
|
||||
pif->avail_ports[pif->avail_total-pif->inuse-1];
|
||||
#endif
|
||||
pif->inuse++;
|
||||
break;
|
||||
}
|
||||
/* failed, already in use */
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
shared_ports_return_port(outnet->shared_ports, pif->shpif,
|
||||
portno);
|
||||
#endif
|
||||
verbose(VERB_QUERY, "port %d in use, trying another", portno);
|
||||
tries++;
|
||||
if(tries == MAX_PORT_RETRY) {
|
||||
@@ -2447,7 +2500,7 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
|
||||
/* find out if a reused stream to the target exists */
|
||||
/* if so, take it into use */
|
||||
reuse = reuse_tcp_find(sq->outnet, &sq->addr, sq->addrlen,
|
||||
sq->ssl_upstream);
|
||||
sq->ssl_upstream, sq->tls_auth_name);
|
||||
if(reuse) {
|
||||
log_reuse_tcp(VERB_CLIENT, "pending_tcp_query: found reuse", reuse);
|
||||
log_assert(reuse->pending);
|
||||
@@ -2489,7 +2542,16 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
|
||||
w->cb = callback;
|
||||
w->cb_arg = callback_arg;
|
||||
w->ssl_upstream = sq->ssl_upstream;
|
||||
w->tls_auth_name = sq->tls_auth_name;
|
||||
if(sq->tls_auth_name) {
|
||||
w->tls_auth_name = strdup(sq->tls_auth_name);
|
||||
if(!w->tls_auth_name) {
|
||||
comm_timer_delete(w->timer);
|
||||
free(w);
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
w->tls_auth_name = NULL;
|
||||
}
|
||||
w->timeout = timeout;
|
||||
w->id_node.key = NULL;
|
||||
w->write_wait_prev = NULL;
|
||||
@@ -3579,13 +3641,16 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
|
||||
{
|
||||
struct sockaddr_storage* addr;
|
||||
socklen_t addrlen;
|
||||
int i, try, pnum, dscp;
|
||||
int i, try, dscp;
|
||||
struct port_if* pif;
|
||||
|
||||
/* create fd */
|
||||
dscp = outnet->ip_dscp;
|
||||
for(try = 0; try<1000; try++) {
|
||||
int port = 0;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
int reused = 0;
|
||||
#endif
|
||||
int freebind = 0;
|
||||
int noproto = 0;
|
||||
int inuse = 0;
|
||||
@@ -3614,16 +3679,18 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
|
||||
addr = &pif->addr;
|
||||
addrlen = pif->addrlen;
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
pnum = ub_random_max(outnet->rnd, pif->avail_total);
|
||||
if(pnum < pif->inuse) {
|
||||
/* port already open */
|
||||
port = pif->out[pnum]->number;
|
||||
} else {
|
||||
/* unused ports in start part of array */
|
||||
port = pif->avail_ports[pnum - pif->inuse];
|
||||
if(!shared_ports_fetch_random(outnet->shared_ports,
|
||||
pif->shpif, outnet->rnd, 0, pif->inuse,
|
||||
&port, &reused)) {
|
||||
/* try again, perhaps another interface. */
|
||||
continue;
|
||||
}
|
||||
if(reused) {
|
||||
log_assert(port < pif->inuse);
|
||||
port = pif->out[port]->number;
|
||||
}
|
||||
#else
|
||||
pnum = port = 0;
|
||||
port = 0;
|
||||
#endif
|
||||
if(addr_is_ip6(to_addr, to_addrlen)) {
|
||||
struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr;
|
||||
@@ -3638,6 +3705,14 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
|
||||
(struct sockaddr*)addr, addrlen, 1, &inuse, &noproto,
|
||||
0, 0, 0, NULL, 0, freebind, 0, dscp);
|
||||
}
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
if(!reused) {
|
||||
/* Return the port to the pool, since the caller does
|
||||
* not keep track of it, also have done fd, and bind. */
|
||||
shared_ports_return_port(outnet->shared_ports,
|
||||
pif->shpif, port);
|
||||
}
|
||||
#endif
|
||||
if(fd != -1) {
|
||||
return fd;
|
||||
}
|
||||
@@ -3868,11 +3943,7 @@ if_get_mem(struct port_if* pif)
|
||||
{
|
||||
size_t s;
|
||||
int i;
|
||||
s = sizeof(*pif) +
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
sizeof(int)*pif->avail_total +
|
||||
#endif
|
||||
sizeof(struct port_comm*)*pif->maxout;
|
||||
s = sizeof(*pif) + sizeof(struct port_comm*)*pif->maxout;
|
||||
for(i=0; i<pif->inuse; i++)
|
||||
s += sizeof(*pif->out[i]) +
|
||||
comm_point_get_mem(pif->out[i]->cp);
|
||||
@@ -3960,3 +4031,237 @@ serviced_get_mem(struct serviced_query* sq)
|
||||
return s;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/** Setup shared port interface */
|
||||
static int shared_ports_setup_if(struct shared_ports_if* shpif, char* str,
|
||||
int* availports, int numavailports)
|
||||
{
|
||||
shpif->avail_ports = (int*)memdup(availports,
|
||||
(size_t)numavailports*sizeof(int));
|
||||
if(!shpif->avail_ports)
|
||||
return 0;
|
||||
shpif->avail_total = numavailports;
|
||||
shpif->inuse = 0;
|
||||
shpif->pfxlen = 0;
|
||||
if(!ipstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr, &shpif->addrlen) &&
|
||||
!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr,
|
||||
&shpif->addrlen, &shpif->pfxlen))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/** Allocate shared ports interfaces */
|
||||
static int shared_ports_alloc_ifs(struct shared_ports* shp, char** ifs,
|
||||
int num_ifs, int do_ip4, int do_ip6, int* availports,
|
||||
int numavailports)
|
||||
{
|
||||
#ifndef INET6
|
||||
do_ip6 = 0;
|
||||
#endif
|
||||
calc_num46(ifs, num_ifs, do_ip4, do_ip6,
|
||||
&shp->num_ip4, &shp->num_ip6);
|
||||
if(shp->num_ip4 != 0) {
|
||||
if(!(shp->ip4_ifs = (struct shared_ports_if*)calloc(
|
||||
(size_t)shp->num_ip4,
|
||||
sizeof(struct shared_ports_if))))
|
||||
return 0;
|
||||
}
|
||||
if(shp->num_ip6 != 0) {
|
||||
if(!(shp->ip6_ifs = (struct shared_ports_if*)calloc(
|
||||
(size_t)shp->num_ip6,
|
||||
sizeof(struct shared_ports_if))))
|
||||
return 0;
|
||||
}
|
||||
if(num_ifs == 0) {
|
||||
if(do_ip4 && !shared_ports_setup_if(&shp->ip4_ifs[0],
|
||||
"0.0.0.0", availports, numavailports))
|
||||
return 0;
|
||||
if(do_ip6 && !shared_ports_setup_if(&shp->ip6_ifs[0],
|
||||
"::", availports, numavailports))
|
||||
return 0;
|
||||
} else {
|
||||
size_t done_4 = 0, done_6 = 0;
|
||||
int i;
|
||||
for(i=0; i<num_ifs; i++) {
|
||||
if(str_is_ip6(ifs[i]) && do_ip6) {
|
||||
if(!shared_ports_setup_if(&shp->ip6_ifs[done_6],
|
||||
ifs[i], availports, numavailports))
|
||||
return 0;
|
||||
done_6++;
|
||||
}
|
||||
if(!str_is_ip6(ifs[i]) && do_ip4) {
|
||||
if(!shared_ports_setup_if(&shp->ip4_ifs[done_4],
|
||||
ifs[i], availports, numavailports))
|
||||
return 0;
|
||||
done_4++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4,
|
||||
int do_ip6, int* availports, int numavailports)
|
||||
{
|
||||
struct shared_ports* shp = calloc(1, sizeof(*shp));
|
||||
if(!shp) {
|
||||
log_err("malloc failed");
|
||||
return NULL;
|
||||
}
|
||||
lock_basic_init(&shp->lock);
|
||||
lock_protect(&shp->lock, shp, sizeof(*shp));
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/* Allocate interfaces */
|
||||
if(!shared_ports_alloc_ifs(shp, ifs, num_ifs, do_ip4, do_ip6,
|
||||
availports, numavailports)) {
|
||||
log_err("malloc failed");
|
||||
shared_ports_delete(shp);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
(void)ifs; (void)num_ifs; (void)do_ip4; (void)do_ip6;
|
||||
(void)availports; (void)numavailports;
|
||||
#endif
|
||||
return shp;
|
||||
}
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/** Delete shared ports interface structure */
|
||||
static void shared_ports_if_delete(struct shared_ports_if* shpif)
|
||||
{
|
||||
if(!shpif)
|
||||
return;
|
||||
free(shpif->avail_ports);
|
||||
}
|
||||
#endif
|
||||
|
||||
void shared_ports_delete(struct shared_ports* shp)
|
||||
{
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
int i;
|
||||
#endif
|
||||
if(!shp)
|
||||
return;
|
||||
lock_basic_destroy(&shp->lock);
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
for(i=0; i<shp->num_ip4; i++) {
|
||||
shared_ports_if_delete(&shp->ip4_ifs[i]);
|
||||
}
|
||||
free(shp->ip4_ifs);
|
||||
for(i=0; i<shp->num_ip6; i++) {
|
||||
shared_ports_if_delete(&shp->ip6_ifs[i]);
|
||||
}
|
||||
free(shp->ip6_ifs);
|
||||
#endif
|
||||
free(shp);
|
||||
}
|
||||
|
||||
struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen)
|
||||
{
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
struct shared_ports_if* ret, *ifs = NULL;
|
||||
int i, num_ifs = 0;
|
||||
lock_basic_lock(&shp->lock);
|
||||
if(addr_is_ip6(addr, addrlen)) {
|
||||
ifs = shp->ip6_ifs;
|
||||
num_ifs = shp->num_ip6;
|
||||
} else {
|
||||
ifs = shp->ip4_ifs;
|
||||
num_ifs = shp->num_ip4;
|
||||
}
|
||||
for(i=0; i<num_ifs; i++) {
|
||||
if(sockaddr_cmp(addr, addrlen, &ifs[i].addr,
|
||||
ifs[i].addrlen) == 0
|
||||
&& pfxlen == ifs[i].pfxlen) {
|
||||
ret = &ifs[i];
|
||||
lock_basic_unlock(&shp->lock);
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
lock_basic_unlock(&shp->lock);
|
||||
return NULL;
|
||||
#else
|
||||
(void)shp; (void)addr; (void)addrlen; (void)pfxlen;
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
int shared_ports_fetch_random(struct shared_ports* shp,
|
||||
struct shared_ports_if* shpif, struct ub_randstate* rnd,
|
||||
int udp_connect, int reusenum, int* port, int* reused)
|
||||
{
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
int portno = 0, my_port = 0;
|
||||
if(!shpif)
|
||||
return 0;
|
||||
lock_basic_lock(&shp->lock);
|
||||
if(udp_connect) {
|
||||
/* if we connect() we cannot reuse fds for a port. */
|
||||
if(shpif->inuse >= shpif->avail_total) {
|
||||
lock_basic_unlock(&shp->lock);
|
||||
return 0;
|
||||
}
|
||||
my_port = ub_random_max(rnd,
|
||||
shpif->avail_total - shpif->inuse);
|
||||
} else {
|
||||
/* select from free ports and open ports on this thread. */
|
||||
if(shpif->inuse >= shpif->avail_total) {
|
||||
lock_basic_unlock(&shp->lock);
|
||||
if(reusenum == 0) {
|
||||
return 0;
|
||||
}
|
||||
my_port = ub_random_max(rnd, reusenum);
|
||||
*port = my_port;
|
||||
*reused = 1;
|
||||
return 1;
|
||||
}
|
||||
my_port = ub_random_max(rnd, shpif->avail_total - shpif->inuse
|
||||
+ reusenum);
|
||||
if(my_port < reusenum) {
|
||||
/* port already open */
|
||||
lock_basic_unlock(&shp->lock);
|
||||
*port = my_port;
|
||||
*reused = 1;
|
||||
return 1;
|
||||
}
|
||||
my_port -= reusenum;
|
||||
}
|
||||
log_assert(shpif->inuse < shpif->avail_total);
|
||||
log_assert(my_port >= 0 && my_port < shpif->avail_total);
|
||||
portno = shpif->avail_ports[my_port];
|
||||
shpif->avail_ports[my_port] =
|
||||
shpif->avail_ports[shpif->avail_total-shpif->inuse-1];
|
||||
shpif->inuse++;
|
||||
lock_basic_unlock(&shp->lock);
|
||||
*port = portno;
|
||||
*reused = 0;
|
||||
return 1;
|
||||
#else
|
||||
(void)shp; (void)shpif; (void)rnd; (void)udp_connect;
|
||||
(void)reusenum;
|
||||
*port = 0;
|
||||
*reused = 0;
|
||||
return 1;
|
||||
#endif
|
||||
}
|
||||
|
||||
void shared_ports_return_port(struct shared_ports* shp,
|
||||
struct shared_ports_if* shpif, int port)
|
||||
{
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
if(!shpif)
|
||||
return;
|
||||
lock_basic_lock(&shp->lock);
|
||||
log_assert(shpif->inuse > 0);
|
||||
shpif->avail_ports[shpif->avail_total - shpif->inuse] = port;
|
||||
shpif->inuse--;
|
||||
lock_basic_unlock(&shp->lock);
|
||||
#else
|
||||
(void)shp; (void)shpif; (void)port;
|
||||
#endif
|
||||
}
|
||||
|
||||
+103
-11
@@ -48,6 +48,10 @@
|
||||
#include "util/regional.h"
|
||||
#include "util/netevent.h"
|
||||
#include "dnstap/dnstap_config.h"
|
||||
#ifdef __QNX__
|
||||
/* For struct timeval */
|
||||
#include <sys/time.h>
|
||||
#endif /* __QNX__ */
|
||||
struct pending;
|
||||
struct pending_timeout;
|
||||
struct ub_randstate;
|
||||
@@ -66,6 +70,8 @@ struct module_env;
|
||||
struct module_qstate;
|
||||
struct query_info;
|
||||
struct config_file;
|
||||
struct shared_ports;
|
||||
struct shared_ports_if;
|
||||
|
||||
/**
|
||||
* Send queries to outside servers and wait for answers from servers.
|
||||
@@ -115,6 +121,9 @@ struct outside_network {
|
||||
int udp_connect;
|
||||
/** number of udp packets sent. */
|
||||
size_t num_udp_outgoing;
|
||||
/** the shared ports structure, with random ports numbers.
|
||||
* This is a reference to the member in the daemon structure. */
|
||||
struct shared_ports* shared_ports;
|
||||
|
||||
/** array of outgoing IP4 interfaces */
|
||||
struct port_if* ip4_ifs;
|
||||
@@ -207,11 +216,8 @@ struct port_if {
|
||||
int pfxlen;
|
||||
|
||||
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
|
||||
/** the available ports array. These are unused.
|
||||
* Only the first total-inuse part is filled. */
|
||||
int* avail_ports;
|
||||
/** the total number of available ports (size of the array) */
|
||||
int avail_total;
|
||||
/** the shared port numbers for this interface. */
|
||||
struct shared_ports_if* shpif;
|
||||
#endif
|
||||
|
||||
/** array of the commpoints currently in use.
|
||||
@@ -241,6 +247,42 @@ struct port_comm {
|
||||
struct comm_point* cp;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared ports, the list of ports shared across threads
|
||||
*/
|
||||
struct shared_ports {
|
||||
/** mutex on the ports */
|
||||
lock_basic_type lock;
|
||||
/** array of IP4 interfaces */
|
||||
struct shared_ports_if* ip4_ifs;
|
||||
/** number of outgoing IP4 interfaces */
|
||||
int num_ip4;
|
||||
/** array of IP6 interfaces */
|
||||
struct shared_ports_if* ip6_ifs;
|
||||
/** number of outgoing IP6 interfaces */
|
||||
int num_ip6;
|
||||
};
|
||||
|
||||
/**
|
||||
* Shared ports for an interface.
|
||||
*/
|
||||
struct shared_ports_if {
|
||||
/** address ready to allocate new socket (except port no). */
|
||||
struct sockaddr_storage addr;
|
||||
/** length of addr field */
|
||||
socklen_t addrlen;
|
||||
/** if a netblock, the prefix */
|
||||
int pfxlen;
|
||||
|
||||
/** the available ports array. These are unused.
|
||||
* Only the first total-inuse part is filled. */
|
||||
int* avail_ports;
|
||||
/** the total number of available ports (size of the array) */
|
||||
int avail_total;
|
||||
/** the number in use. */
|
||||
int inuse;
|
||||
};
|
||||
|
||||
/**
|
||||
* Reuse TCP connection, still open can be used again.
|
||||
*/
|
||||
@@ -260,6 +302,9 @@ struct reuse_tcp {
|
||||
socklen_t addrlen;
|
||||
/** also key for tcp_reuse tree, if ssl is used */
|
||||
int is_ssl;
|
||||
/** If is_ssl is enabled, tls_auth_name is part of the key for
|
||||
* tcp_reuse tree. If the string is NULL, it without a tls_auth_name */
|
||||
char* tls_auth_name;
|
||||
/** lru chain, so that the oldest can be removed to get a new
|
||||
* connection when all are in (re)use. oldest is last in list.
|
||||
* The lru only contains empty connections waiting for reuse,
|
||||
@@ -412,7 +457,7 @@ struct waiting_tcp {
|
||||
void* cb_arg;
|
||||
/** if it uses ssl upstream */
|
||||
int ssl_upstream;
|
||||
/** ref to the tls_auth_name from the serviced_query */
|
||||
/** owned copy of the tls_auth_name (malloced) */
|
||||
char* tls_auth_name;
|
||||
/** the packet was involved in an error, to stop looping errors */
|
||||
int error_count;
|
||||
@@ -544,8 +589,6 @@ struct serviced_query {
|
||||
* @param infra: pointer to infra cached used for serviced queries.
|
||||
* @param rnd: stored to create random numbers for serviced queries.
|
||||
* @param use_caps_for_id: enable to use 0x20 bits to encode id randomness.
|
||||
* @param availports: array of available ports.
|
||||
* @param numavailports: number of available ports in array.
|
||||
* @param unwanted_threshold: when to take defensive action.
|
||||
* @param unwanted_action: the action to take.
|
||||
* @param unwanted_param: user parameter to action.
|
||||
@@ -560,17 +603,18 @@ struct serviced_query {
|
||||
* @param max_reuse_tcp_queries: max number of queries on a reuse connection.
|
||||
* @param tcp_reuse_timeout: timeout for REUSE entries in milliseconds.
|
||||
* @param tcp_auth_query_timeout: timeout in milliseconds for TCP queries to auth servers.
|
||||
* @param shared_ports: the shared_ports structure.
|
||||
* @return: the new structure (with no pending answers) or NULL on error.
|
||||
*/
|
||||
struct outside_network* outside_network_create(struct comm_base* base,
|
||||
size_t bufsize, size_t num_ports, char** ifs, int num_ifs,
|
||||
int do_ip4, int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra,
|
||||
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
|
||||
int numavailports, size_t unwanted_threshold, int tcp_mss,
|
||||
struct ub_randstate* rnd, int use_caps_for_id,
|
||||
size_t unwanted_threshold, int tcp_mss,
|
||||
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
|
||||
void* sslctx, int delayclose, int tls_use_sni, struct dt_env *dtenv,
|
||||
int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout,
|
||||
int tcp_auth_query_timeout);
|
||||
int tcp_auth_query_timeout, struct shared_ports* shared_ports);
|
||||
|
||||
/**
|
||||
* Delete outside_network structure.
|
||||
@@ -812,6 +856,54 @@ struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
|
||||
/** connect tcp connection to addr, 0 on failure */
|
||||
int outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen);
|
||||
|
||||
/**
|
||||
* Create new shared ports structure.
|
||||
* @param ifs: interface names (or NULL for default interface).
|
||||
* These interfaces must be able to access all authoritative servers.
|
||||
* @param num_ifs: number of names in array ifs.
|
||||
* @param do_ip4: service IP4.
|
||||
* @param do_ip6: service IP6.
|
||||
* @param availports: array of available ports.
|
||||
* @param numavailports: number of available ports in array.
|
||||
* @return new, or NULL on failure.
|
||||
*/
|
||||
struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4,
|
||||
int do_ip6, int* availports, int numavailports);
|
||||
|
||||
/**
|
||||
* Delete shared ports structure.
|
||||
* @param shp: shared ports structure.
|
||||
*/
|
||||
void shared_ports_delete(struct shared_ports* shp);
|
||||
|
||||
/** Find interface in shared ports. */
|
||||
struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp,
|
||||
struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen);
|
||||
|
||||
/**
|
||||
* Get a shared port from the list of random ports.
|
||||
* @param shp: shared ports structure.
|
||||
* @param shpif: the shared ports interface.
|
||||
* @param rnd: used to make random numbers.
|
||||
* @param udp_connect: set to true if no reuse is possible.
|
||||
* @param reusenum: number of ports that can be reused (already open).
|
||||
* @param port: the port number is returned.
|
||||
* @param reused: if the port numer is reused, returned.
|
||||
* @return false on failure. That can mean no more free ports to use.
|
||||
*/
|
||||
int shared_ports_fetch_random(struct shared_ports* shp,
|
||||
struct shared_ports_if* shpif, struct ub_randstate* rnd,
|
||||
int udp_connect, int reusenum, int* port, int* reused);
|
||||
|
||||
/**
|
||||
* Return a shared port to the list of random ports.
|
||||
* @param shp: shared ports structure.
|
||||
* @param shpif: the shared ports interface.
|
||||
* @param port: port number to return to be used again.
|
||||
*/
|
||||
void shared_ports_return_port(struct shared_ports* shp,
|
||||
struct shared_ports_if* shpif, int port);
|
||||
|
||||
/** callback for incoming udp answers from the network */
|
||||
int outnet_udp_cb(struct comm_point* c, void* arg, int error,
|
||||
struct comm_reply *reply_info);
|
||||
|
||||
+7
-4
@@ -153,6 +153,7 @@ rpz_type_ignored(uint16_t rr_type)
|
||||
case LDNS_RR_TYPE_SOA:
|
||||
case LDNS_RR_TYPE_NS:
|
||||
case LDNS_RR_TYPE_DNAME:
|
||||
case LDNS_RR_TYPE_ZONEMD:
|
||||
/* all DNSSEC-related RRs must be ignored */
|
||||
case LDNS_RR_TYPE_DNSKEY:
|
||||
case LDNS_RR_TYPE_DS:
|
||||
@@ -2468,6 +2469,7 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
|
||||
{
|
||||
struct auth_zones* az;
|
||||
struct auth_zone* a;
|
||||
struct dns_msg* ret = NULL;
|
||||
struct clientip_synthesized_rr* raddr = NULL;
|
||||
struct rpz* r = NULL;
|
||||
struct local_zone* z = NULL;
|
||||
@@ -2511,13 +2513,11 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
|
||||
z = rpz_delegation_point_zone_lookup(is->dp, r->nsdname_zones,
|
||||
is->qchase.qclass, &match);
|
||||
if(z != NULL) {
|
||||
lock_rw_unlock(&a->lock);
|
||||
break;
|
||||
}
|
||||
|
||||
raddr = rpz_delegation_point_ipbased_trigger_lookup(r, is);
|
||||
if(raddr != NULL) {
|
||||
lock_rw_unlock(&a->lock);
|
||||
break;
|
||||
}
|
||||
lock_rw_unlock(&a->lock);
|
||||
@@ -2532,9 +2532,12 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
|
||||
if(z) {
|
||||
lock_rw_unlock(&z->lock);
|
||||
}
|
||||
return rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a);
|
||||
ret = rpz_apply_nsip_trigger(ms, &is->qchase, r, raddr, a);
|
||||
} else {
|
||||
ret = rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a);
|
||||
}
|
||||
return rpz_apply_nsdname_trigger(ms, &is->qchase, r, z, &match, a);
|
||||
lock_rw_unlock(&a->lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
|
||||
|
||||
+3
-1
@@ -480,11 +480,13 @@ enum sldns_enum_ede_code
|
||||
LDNS_EDE_TOO_EARLY = 26,
|
||||
LDNS_EDE_UNSUPPORTED_NSEC3_ITERATIONS = 27,
|
||||
LDNS_EDE_BADPROXYPOLICY = 28,
|
||||
LDNS_EDE_SYNTHESIZED = 29
|
||||
LDNS_EDE_SYNTHESIZED = 29,
|
||||
LDNS_EDE_INVALID_QUERY_TYPE = 30
|
||||
};
|
||||
typedef enum sldns_enum_ede_code sldns_ede_code;
|
||||
|
||||
#define LDNS_EDNS_MASK_DO_BIT 0x8000
|
||||
#define LDNS_EDNS_MASK_CO_BIT 0x4000
|
||||
|
||||
/** TSIG and TKEY extended rcodes (16bit), 0-15 are the normal rcodes. */
|
||||
#define LDNS_TSIG_ERROR_NOERROR 0
|
||||
|
||||
@@ -233,6 +233,7 @@ static sldns_lookup_table sldns_edns_ede_codes_data[] = {
|
||||
{ LDNS_EDE_UNSUPPORTED_NSEC3_ITERATIONS, "Unsupported NSEC3 Iterations Value" },
|
||||
{ LDNS_EDE_BADPROXYPOLICY, "Unable to Conform to Policy" },
|
||||
{ LDNS_EDE_SYNTHESIZED, "Synthesized Answer" },
|
||||
{ LDNS_EDE_INVALID_QUERY_TYPE, "Invalid Query Type" },
|
||||
{ 0, NULL}
|
||||
};
|
||||
sldns_lookup_table* sldns_edns_ede_codes = sldns_edns_ede_codes_data;
|
||||
@@ -2485,6 +2486,8 @@ int sldns_wire2str_edns_scan(uint8_t** data, size_t* data_len, char** str,
|
||||
w += sldns_str_print(str, str_len, " flags:");
|
||||
if((edns_bits & LDNS_EDNS_MASK_DO_BIT))
|
||||
w += sldns_str_print(str, str_len, " do");
|
||||
if((edns_bits & LDNS_EDNS_MASK_CO_BIT))
|
||||
w += sldns_str_print(str, str_len, " co");
|
||||
/* the extended rcode is the value set, shifted four bits,
|
||||
* and or'd with the original rcode */
|
||||
if(ext_rcode) {
|
||||
|
||||
@@ -2430,12 +2430,20 @@ int main(int argc, char* argv[])
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
|
||||
if(dolist) do_list_builtin();
|
||||
|
||||
@@ -44,6 +44,7 @@
|
||||
|
||||
#include "config.h"
|
||||
#include <ctype.h>
|
||||
#include "util/as112.h"
|
||||
#include "util/log.h"
|
||||
#include "util/config_file.h"
|
||||
#include "util/module.h"
|
||||
@@ -188,11 +189,56 @@ donotquerylocalhostcheck(struct config_file* cfg)
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
nodefaultzonescheck(struct config_file* cfg)
|
||||
{
|
||||
struct config_strlist* d;
|
||||
const char** zstr;
|
||||
size_t len;
|
||||
|
||||
#define COMPARE_ZONE_NAME(confname, builtname, len) \
|
||||
(strncasecmp(confname, builtname, (len)) == 0 && \
|
||||
(strlen(confname) == (len) || \
|
||||
(strlen(confname) == (len) + 1 \
|
||||
&& confname[(len)] == '.')))
|
||||
|
||||
for(d = cfg->local_zones_nodefault; d; d = d->next) {
|
||||
if(!cfg->unblock_lan_zones) {
|
||||
for(zstr = as112_zones; *zstr; zstr++) {
|
||||
len = strlen(*zstr) - 1; /* trailing '.' */
|
||||
if(COMPARE_ZONE_NAME(d->str, *zstr, len))
|
||||
goto default_continue;
|
||||
}
|
||||
}
|
||||
for(zstr = local_zones_default_special; *zstr; zstr++) {
|
||||
len = strlen(*zstr) - 1; /* trailing '.' */
|
||||
if(COMPARE_ZONE_NAME(d->str, *zstr, len))
|
||||
goto default_continue;
|
||||
}
|
||||
for(zstr = local_zones_default_reverse; *zstr; zstr++) {
|
||||
len = strlen(*zstr) - 1; /* trailing '.' */
|
||||
if(COMPARE_ZONE_NAME(d->str, *zstr, len))
|
||||
goto default_continue;
|
||||
}
|
||||
if(COMPARE_ZONE_NAME(d->str, "localhost.", 10 - 1))
|
||||
goto default_continue;
|
||||
fprintf(stderr, "unbound-checkconf: warning: local-zone: '%s' "
|
||||
"is configured as 'nodefault' but there is no such "
|
||||
"default local-zone. Check the unbound.conf "
|
||||
"documentation for default configured local-zones.\n",
|
||||
d->str);
|
||||
default_continue:
|
||||
; /* statement to jump to, for older gcc. */
|
||||
}
|
||||
#undef COMPARE_ZONE_NAME
|
||||
}
|
||||
|
||||
/** check localzones */
|
||||
static void
|
||||
localzonechecks(struct config_file* cfg)
|
||||
{
|
||||
struct local_zones* zs;
|
||||
nodefaultzonescheck(cfg);
|
||||
if(!(zs = local_zones_create()))
|
||||
fatal_exit("out of memory");
|
||||
if(!local_zones_apply_cfg(zs, cfg))
|
||||
|
||||
@@ -236,6 +236,8 @@ static void pr_stats(const char* nm, struct ub_stats_info* s)
|
||||
s->svr.num_queries_cookie_invalid);
|
||||
PR_UL_NM("num.queries_discard_timeout",
|
||||
s->svr.num_queries_discard_timeout);
|
||||
PR_UL_NM("num.queries_replyaddr_limit",
|
||||
s->svr.num_queries_replyaddr_limit);
|
||||
PR_UL_NM("num.queries_wait_limit", s->svr.num_queries_wait_limit);
|
||||
PR_UL_NM("num.cachehits",
|
||||
s->svr.num_queries - s->svr.num_queries_missed_cache);
|
||||
@@ -263,6 +265,7 @@ static void pr_stats(const char* nm, struct ub_stats_info* s)
|
||||
PR_UL_NM("requestlist.exceeded", s->mesh_dropped);
|
||||
PR_UL_NM("requestlist.current.all", s->mesh_num_states);
|
||||
PR_UL_NM("requestlist.current.user", s->mesh_num_reply_states);
|
||||
PR_UL_NM("requestlist.current.replies", s->mesh_num_reply_addrs);
|
||||
#ifndef S_SPLINT_S
|
||||
sumwait.tv_sec = s->mesh_replies_sum_wait_sec;
|
||||
sumwait.tv_usec = s->mesh_replies_sum_wait_usec;
|
||||
@@ -1049,12 +1052,20 @@ int main(int argc, char* argv[])
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
|
||||
if(!RAND_status()) {
|
||||
|
||||
+10
-2
@@ -521,12 +521,20 @@ int main(int argc, char* argv[])
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#endif /* HAVE_SSL */
|
||||
#ifdef HAVE_NSS
|
||||
|
||||
@@ -128,6 +128,12 @@ worker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void
|
||||
libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
struct outbound_entry* libworker_send_query(
|
||||
struct query_info* ATTR_UNUSED(qinfo), uint16_t ATTR_UNUSED(flags),
|
||||
int ATTR_UNUSED(dnssec), int ATTR_UNUSED(want_dnssec),
|
||||
|
||||
+10
-2
@@ -488,12 +488,20 @@ int main(int argc, char** argv)
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#endif /* HAVE_SSL */
|
||||
|
||||
|
||||
@@ -360,6 +360,7 @@ typedef pthread_key_t ub_thread_key_type;
|
||||
#define ub_thread_key_create(key, f) LOCKRET(pthread_key_create(key, f))
|
||||
#define ub_thread_key_set(key, v) LOCKRET(pthread_setspecific(key, v))
|
||||
#define ub_thread_key_get(key) pthread_getspecific(key)
|
||||
#define ub_thread_setname(thread, name) /* nop */
|
||||
|
||||
#endif /* USE_THREAD_DEBUG */
|
||||
#endif /* TESTCODE_CHECK_LOCKS_H */
|
||||
|
||||
+10
-2
@@ -642,12 +642,20 @@ int main(int argc, char** argv)
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
}
|
||||
run(h2_session, port, no_tls, argc, argv);
|
||||
|
||||
@@ -1519,9 +1519,9 @@ doq_client_send_pkt(struct doq_client_data* data, uint32_t ecn, uint8_t* buf,
|
||||
}
|
||||
log_err("doq sendmsg: %s", strerror(errno));
|
||||
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
|
||||
ngtcp2_ccerr_set_application_error(&data->ccerr, -1, NULL, 0);
|
||||
ngtcp2_ccerr_set_application_error(&data->ccerr, 1, NULL, 0);
|
||||
#else
|
||||
ngtcp2_connection_close_error_set_application_error(&data->last_error, -1, NULL, 0);
|
||||
ngtcp2_connection_close_error_set_application_error(&data->last_error, 1, NULL, 0);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
@@ -2255,7 +2255,7 @@ create_doq_client_data(const char* svr, int port, struct ub_event_base* base,
|
||||
/* Initialize the ossl crypto, it is harmless to call twice,
|
||||
* and this is before use of doq connections. */
|
||||
if(ngtcp2_crypto_ossl_init() != 0)
|
||||
fatal_exit("ngtcp2_crypto_oss_init failed");
|
||||
fatal_exit("ngtcp2_crypto_ossl_init failed");
|
||||
#elif defined(HAVE_NGTCP2_CRYPTO_QUICTLS_INIT)
|
||||
if(ngtcp2_crypto_quictls_init() != 0)
|
||||
fatal_exit("ngtcp2_crypto_quictls_init failed");
|
||||
@@ -2671,6 +2671,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
|
||||
{
|
||||
log_assert(0);
|
||||
}
|
||||
|
||||
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
|
||||
{
|
||||
log_assert(0);
|
||||
|
||||
+27
-3
@@ -1126,15 +1126,16 @@ outside_network_create(struct comm_base* base, size_t bufsize,
|
||||
int ATTR_UNUSED(dscp),
|
||||
struct infra_cache* infra,
|
||||
struct ub_randstate* ATTR_UNUSED(rnd),
|
||||
int ATTR_UNUSED(use_caps_for_id), int* ATTR_UNUSED(availports),
|
||||
int ATTR_UNUSED(numavailports), size_t ATTR_UNUSED(unwanted_threshold),
|
||||
int ATTR_UNUSED(use_caps_for_id),
|
||||
size_t ATTR_UNUSED(unwanted_threshold),
|
||||
int ATTR_UNUSED(outgoing_tcp_mss),
|
||||
void (*unwanted_action)(void*), void* ATTR_UNUSED(unwanted_param),
|
||||
int ATTR_UNUSED(do_udp), void* ATTR_UNUSED(sslctx),
|
||||
int ATTR_UNUSED(delayclose), int ATTR_UNUSED(tls_use_sni),
|
||||
struct dt_env* ATTR_UNUSED(dtenv), int ATTR_UNUSED(udp_connect),
|
||||
int ATTR_UNUSED(max_reuse_tcp_queries), int ATTR_UNUSED(tcp_reuse_timeout),
|
||||
int ATTR_UNUSED(tcp_auth_query_timeout))
|
||||
int ATTR_UNUSED(tcp_auth_query_timeout),
|
||||
struct shared_ports* ATTR_UNUSED(shared_ports))
|
||||
{
|
||||
struct replay_runtime* runtime = (struct replay_runtime*)base;
|
||||
struct outside_network* outnet = calloc(1,
|
||||
@@ -1980,6 +1981,20 @@ int outnet_tcp_connect(int ATTR_UNUSED(s), struct sockaddr_storage* ATTR_UNUSED(
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct shared_ports* shared_ports_create(char** ATTR_UNUSED(ifs),
|
||||
int ATTR_UNUSED(num_ifs), int ATTR_UNUSED(do_ip4),
|
||||
int ATTR_UNUSED(do_ip6), int* ATTR_UNUSED(availports),
|
||||
int ATTR_UNUSED(numavailports))
|
||||
{
|
||||
return calloc(1, sizeof(struct shared_ports));
|
||||
}
|
||||
|
||||
void shared_ports_delete(struct shared_ports* shp)
|
||||
{
|
||||
if(!shp) return;
|
||||
free(shp);
|
||||
}
|
||||
|
||||
int tcp_req_info_add_meshstate(struct tcp_req_info* ATTR_UNUSED(req),
|
||||
struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m))
|
||||
{
|
||||
@@ -2021,6 +2036,15 @@ void http2_stream_remove_mesh_state(struct http2_stream* ATTR_UNUSED(h2_stream))
|
||||
{
|
||||
}
|
||||
|
||||
void doq_stream_add_meshstate(struct doq_stream* ATTR_UNUSED(stream),
|
||||
struct mesh_area* ATTR_UNUSED(mesh), struct mesh_state* ATTR_UNUSED(m))
|
||||
{
|
||||
}
|
||||
|
||||
void doq_stream_remove_mesh_state(struct doq_stream* ATTR_UNUSED(stream))
|
||||
{
|
||||
}
|
||||
|
||||
void fast_reload_service_cb(int ATTR_UNUSED(fd), short ATTR_UNUSED(event),
|
||||
void* ATTR_UNUSED(arg))
|
||||
{
|
||||
|
||||
@@ -141,6 +141,13 @@ if test -f $done; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# always clear the skip mark file in case something changed in the environment
|
||||
# in between runs
|
||||
if test -f $skip; then
|
||||
echo "minitdir $skip exists; removing."
|
||||
rm $skip
|
||||
fi
|
||||
|
||||
# Copy
|
||||
if test $quiet = 0; then
|
||||
echo "minitdir copy $1 to $dir"
|
||||
|
||||
+31
-6
@@ -160,11 +160,26 @@ read_ssl_line(SSL* ssl, char* buf, size_t len)
|
||||
return 0;
|
||||
}
|
||||
if((r = SSL_read(ssl, buf+n, 1)) <= 0) {
|
||||
if(SSL_get_error(ssl, r) == SSL_ERROR_ZERO_RETURN) {
|
||||
int e = SSL_get_error(ssl, r);
|
||||
if(e == SSL_ERROR_ZERO_RETURN) {
|
||||
/* EOF */
|
||||
break;
|
||||
} else if(e == SSL_ERROR_WANT_READ) {
|
||||
continue;
|
||||
} else if(e == SSL_ERROR_WANT_WRITE) {
|
||||
continue;
|
||||
} else if(e == SSL_ERROR_SYSCALL) {
|
||||
if(verb) printf("could not SSL_read %s\n",
|
||||
strerror(errno));
|
||||
} else if(e == SSL_ERROR_SSL) {
|
||||
int er = ERR_peek_error();
|
||||
if(er)
|
||||
printf("could not SSL_read: %s\n",
|
||||
ERR_reason_error_string(er));
|
||||
} else {
|
||||
if(verb) printf("could not SSL_read "
|
||||
"(SSL_get_error %d)\n", e);
|
||||
}
|
||||
if(verb) printf("could not SSL_read\n");
|
||||
return 0;
|
||||
}
|
||||
if(endnl && buf[n] == '\n') {
|
||||
@@ -222,7 +237,8 @@ read_http_headers(SSL* ssl, char* file, size_t flen, char* host, size_t hlen,
|
||||
if(verb>=2) printf("read: %s\n", buf);
|
||||
if(buf[0] == 0) {
|
||||
int e = ERR_peek_error();
|
||||
printf("error string: %s\n", ERR_reason_error_string(e));
|
||||
if(e)
|
||||
printf("error string: %s\n", ERR_reason_error_string(e));
|
||||
return 1;
|
||||
}
|
||||
if(!process_one_header(buf, file, flen, host, hlen, vs))
|
||||
@@ -246,7 +262,8 @@ setup_ctx(char* key, char* cert)
|
||||
#endif
|
||||
if(!SSL_CTX_use_certificate_chain_file(ctx, cert)) {
|
||||
int e = ERR_peek_error();
|
||||
printf("error string: %s\n", ERR_reason_error_string(e));
|
||||
if(e)
|
||||
printf("error string: %s\n", ERR_reason_error_string(e));
|
||||
print_exit("cannot read cert");
|
||||
}
|
||||
if(!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM))
|
||||
@@ -673,12 +690,20 @@ int main(int argc, char* argv[])
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
|
||||
do_service(addr, port, key, cert);
|
||||
|
||||
+12
-2
@@ -59,12 +59,16 @@ static void usage(char* argv[])
|
||||
/** read hex input */
|
||||
static void read_input(sldns_buffer* pkt, FILE* in)
|
||||
{
|
||||
char buf[102400];
|
||||
/* Buffer for 64Kib packet, in hex, with spaces and comments. */
|
||||
char buf[1024000];
|
||||
char* np = buf;
|
||||
while(fgets(np, (int)sizeof(buf) - (np-buf), in)) {
|
||||
if(buf[0] == ';') /* comment */
|
||||
continue;
|
||||
np = &np[strlen(np)];
|
||||
if((size_t)(np-buf) >= sizeof(buf)-1)
|
||||
fatal_exit("input too large (%lu bytes)",
|
||||
(unsigned long)sizeof(buf));
|
||||
}
|
||||
hex_to_buf(pkt, buf);
|
||||
}
|
||||
@@ -188,10 +192,16 @@ static void analyze(sldns_buffer* pkt)
|
||||
/** main program for pktview */
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
sldns_buffer* pkt = sldns_buffer_new(65553);
|
||||
sldns_buffer* pkt;
|
||||
|
||||
log_init(NULL, 0, NULL);
|
||||
log_ident_set("pktview");
|
||||
|
||||
if(argc != 1) {
|
||||
usage(argv);
|
||||
}
|
||||
|
||||
pkt = sldns_buffer_new(65553);
|
||||
if(!pkt) fatal_exit("out of memory");
|
||||
|
||||
read_input(pkt, stdin);
|
||||
|
||||
@@ -142,6 +142,10 @@
|
||||
#include "util/netevent.h"
|
||||
#include "testcode/testpkts.h"
|
||||
#include "util/rbtree.h"
|
||||
#ifdef __QNX__
|
||||
/* For struct timeval */
|
||||
#include <sys/time.h>
|
||||
#endif /* __QNX__ */
|
||||
struct replay_answer;
|
||||
struct replay_moment;
|
||||
struct replay_range;
|
||||
|
||||
+10
-2
@@ -652,12 +652,20 @@ int main(int argc, char** argv)
|
||||
#else
|
||||
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
|
||||
| OPENSSL_INIT_ADD_ALL_DIGESTS
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
|
||||
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
|
||||
(void)SSL_library_init();
|
||||
#else
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
|
||||
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
|
||||
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
|
||||
| OPENSSL_INIT_NO_LOAD_CONFIG
|
||||
# endif
|
||||
, NULL);
|
||||
#endif
|
||||
}
|
||||
send_em(svr, pp2_client, udp, usessl, noanswer, onarrival, delay, argc, argv);
|
||||
|
||||
+41
-9
@@ -135,6 +135,8 @@ static void matchline(char* line, struct entry* e)
|
||||
e->match_ttl = 1;
|
||||
} else if(str_keyword(&parse, "DO")) {
|
||||
e->match_do = 1;
|
||||
} else if(str_keyword(&parse, "CO")) {
|
||||
e->match_co = 1;
|
||||
} else if(str_keyword(&parse, "noedns")) {
|
||||
e->match_noedns = 1;
|
||||
} else if(str_keyword(&parse, "ednsdata")) {
|
||||
@@ -178,7 +180,7 @@ static void matchline(char* line, struct entry* e)
|
||||
|
||||
/** parse REPLY line */
|
||||
static void replyline(char* line, uint8_t* reply, size_t reply_len,
|
||||
int* do_flag)
|
||||
int* do_flag, int* co_flag)
|
||||
{
|
||||
char* parse = line;
|
||||
if(reply_len < LDNS_HEADER_SIZE) error("packet too short for header");
|
||||
@@ -236,6 +238,8 @@ static void replyline(char* line, uint8_t* reply, size_t reply_len,
|
||||
LDNS_AD_SET(reply);
|
||||
} else if(str_keyword(&parse, "DO")) {
|
||||
*do_flag = 1;
|
||||
} else if(str_keyword(&parse, "CO")) {
|
||||
*co_flag = 1;
|
||||
} else {
|
||||
error("could not parse REPLY: '%s'", parse);
|
||||
}
|
||||
@@ -289,6 +293,7 @@ static struct entry* new_entry(void)
|
||||
e->match_all_noedns = 0;
|
||||
e->match_ttl = 0;
|
||||
e->match_do = 0;
|
||||
e->match_co = 0;
|
||||
e->match_noedns = 0;
|
||||
e->match_serial = 0;
|
||||
e->ixfr_soa_serial = 0;
|
||||
@@ -521,15 +526,17 @@ static void add_rr(char* rrstr, uint8_t* pktbuf, size_t pktsize,
|
||||
|
||||
/* add EDNS 4096 opt record */
|
||||
static void
|
||||
add_edns(uint8_t* pktbuf, size_t pktsize, int do_flag, uint8_t *ednsdata,
|
||||
uint16_t ednslen, size_t* pktlen)
|
||||
add_edns(uint8_t* pktbuf, size_t pktsize, int do_flag, int co_flag,
|
||||
uint8_t *ednsdata, uint16_t ednslen, size_t* pktlen)
|
||||
{
|
||||
uint8_t edns[] = {0x00, /* root label */
|
||||
0x00, LDNS_RR_TYPE_OPT, /* type */
|
||||
0x04, 0xD0, /* class is UDPSIZE 1232 */
|
||||
0x00, /* TTL[0] is ext rcode */
|
||||
0x00, /* TTL[1] is edns version */
|
||||
(uint8_t)(do_flag?0x80:0x00), 0x00, /* TTL[2-3] is edns flags, DO */
|
||||
(uint8_t)(do_flag?0x80:0x00)
|
||||
| (uint8_t)(co_flag?0x40:0x00)
|
||||
, 0x00, /* TTL[2-3] is edns flags, DO */
|
||||
(uint8_t)((ednslen >> 8) & 0xff),
|
||||
(uint8_t)(ednslen & 0xff), /* rdatalength */
|
||||
};
|
||||
@@ -561,6 +568,7 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate,
|
||||
uint8_t pktbuf[MAX_PACKETLEN];
|
||||
size_t pktlen = LDNS_HEADER_SIZE;
|
||||
int do_flag = 0; /* DO flag in EDNS */
|
||||
int co_flag = 0; /* CO flag in EDNS */
|
||||
memset(pktbuf, 0, pktlen); /* ID = 0, FLAGS="", and rr counts 0 */
|
||||
|
||||
while(fgets(line, (int)sizeof(line), in) != NULL) {
|
||||
@@ -598,7 +606,7 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate,
|
||||
if(str_keyword(&parse, "MATCH")) {
|
||||
matchline(parse, current);
|
||||
} else if(str_keyword(&parse, "REPLY")) {
|
||||
replyline(parse, pktbuf, pktlen, &do_flag);
|
||||
replyline(parse, pktbuf, pktlen, &do_flag, &co_flag);
|
||||
} else if(str_keyword(&parse, "ADJUST")) {
|
||||
adjustline(parse, current, cur_reply);
|
||||
} else if(str_keyword(&parse, "EXTRA_PACKET")) {
|
||||
@@ -654,15 +662,16 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate,
|
||||
if(hex_ednsdata_buffer)
|
||||
sldns_buffer_free(hex_ednsdata_buffer);
|
||||
if(pktlen != 0) {
|
||||
if(do_flag || cur_reply->raw_ednsdata) {
|
||||
if(do_flag || co_flag
|
||||
|| cur_reply->raw_ednsdata) {
|
||||
if(cur_reply->raw_ednsdata &&
|
||||
sldns_buffer_limit(cur_reply->raw_ednsdata))
|
||||
add_edns(pktbuf, sizeof(pktbuf), do_flag,
|
||||
add_edns(pktbuf, sizeof(pktbuf), do_flag, co_flag,
|
||||
sldns_buffer_begin(cur_reply->raw_ednsdata),
|
||||
(uint16_t)sldns_buffer_limit(cur_reply->raw_ednsdata),
|
||||
&pktlen);
|
||||
else
|
||||
add_edns(pktbuf, sizeof(pktbuf), do_flag,
|
||||
add_edns(pktbuf, sizeof(pktbuf), do_flag, co_flag,
|
||||
NULL, 0, &pktlen);
|
||||
}
|
||||
cur_reply->reply_pkt = memdup(pktbuf, pktlen);
|
||||
@@ -909,6 +918,22 @@ get_do_flag(uint8_t* pkt, size_t len)
|
||||
return (int)(edns_bits&LDNS_EDNS_MASK_DO_BIT);
|
||||
}
|
||||
|
||||
/** return true if the CO flag is set */
|
||||
static int
|
||||
get_co_flag(uint8_t* pkt, size_t len)
|
||||
{
|
||||
uint16_t edns_bits;
|
||||
uint8_t* walk = pkt;
|
||||
size_t walk_len = len;
|
||||
if(!pkt_find_edns_opt(&walk, &walk_len)) {
|
||||
return 0;
|
||||
}
|
||||
if(walk_len < 6)
|
||||
return 0; /* malformed */
|
||||
edns_bits = sldns_read_uint16(walk+4);
|
||||
return (int)(edns_bits&LDNS_EDNS_MASK_CO_BIT);
|
||||
}
|
||||
|
||||
/** Snips the specified EDNS option out of the OPT record and puts it in the
|
||||
* provided buffer. The buffer should be able to hold any opt data ie 65535.
|
||||
* Returns the length of the option written,
|
||||
@@ -1654,6 +1679,10 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
|
||||
verbose(3, "no DO bit set\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_co && !get_co_flag(query_pkt, len)) {
|
||||
verbose(3, "no CO bit set\n");
|
||||
continue;
|
||||
}
|
||||
if(p->match_noedns && get_has_edns(query_pkt, len)) {
|
||||
verbose(3, "bad; EDNS OPT present\n");
|
||||
continue;
|
||||
@@ -1745,11 +1774,14 @@ adjust_packet(struct entry* match, uint8_t** answer_pkt, size_t *answer_len,
|
||||
memmove(res+LDNS_HEADER_SIZE+dlen+4,
|
||||
orig+LDNS_HEADER_SIZE+olen+4,
|
||||
reslen-(LDNS_HEADER_SIZE+dlen+4));
|
||||
} else if(origlen == 0) {
|
||||
res = NULL;
|
||||
reslen = 0;
|
||||
} else {
|
||||
res = memdup(orig, origlen);
|
||||
reslen = origlen;
|
||||
}
|
||||
if(!res) {
|
||||
if(!res && reslen > 0) {
|
||||
verbose(1, "out of memory; send without adjust\n");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -218,6 +218,8 @@ struct entry {
|
||||
uint8_t match_ttl;
|
||||
/** match DO bit */
|
||||
uint8_t match_do;
|
||||
/** match CO bit */
|
||||
uint8_t match_co;
|
||||
/** match absence of EDNS OPT record in query */
|
||||
uint8_t match_noedns;
|
||||
/** match edns data field given in hex */
|
||||
|
||||
@@ -207,7 +207,11 @@ rr_test_file(const char* input, const char* check)
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
|
||||
#ifndef __QNX__
|
||||
#define SRCDIRSTR xstr(SRCDIR)
|
||||
#else /* !__QNX__ */
|
||||
#define SRCDIRSTR "."
|
||||
#endif /* __QNX__ */
|
||||
|
||||
/** read rrs to and from string, to and from wireformat */
|
||||
static void
|
||||
|
||||
+59
-3
@@ -283,7 +283,7 @@ net_test(void)
|
||||
unit_assert(strcmp(astr, "1.2.3.0") == 0);
|
||||
unit_assert(ntohs(((struct sockaddr_in*)&a)->sin_port)==53);
|
||||
|
||||
res = netblockstrtoaddr("2001:DB8:33:44::/64", 53,
|
||||
res = netblockstrtoaddr("2001:db8:33:44::/64", 53,
|
||||
&a, &alen, &net);
|
||||
unit_assert(res!=0 && net == 64);
|
||||
addr_to_str(&a, alen, astr, sizeof(astr));
|
||||
@@ -1092,7 +1092,7 @@ static void edns_ede_encode_notxt_fit_test( struct query_info* qinfo,
|
||||
{
|
||||
struct edns_data edns;
|
||||
sldns_buffer* pkt;
|
||||
uint16_t edns_field_size, ede_txt_size;
|
||||
size_t edns_field_size, ede_txt_size;
|
||||
int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
|
||||
int found_other_edns = 0;
|
||||
edns_ede_encode_setup(&edns, region);
|
||||
@@ -1123,7 +1123,7 @@ static void edns_ede_encode_no_fit_test( struct query_info* qinfo,
|
||||
{
|
||||
struct edns_data edns;
|
||||
sldns_buffer* pkt;
|
||||
uint16_t edns_field_size, ede_size, ede_txt_size;
|
||||
size_t edns_field_size, ede_size, ede_txt_size;
|
||||
int found_ede = 0, found_ede_other = 0, found_ede_txt = 0;
|
||||
int found_other_edns = 0;
|
||||
edns_ede_encode_setup(&edns, region);
|
||||
@@ -1282,6 +1282,61 @@ static void localzone_test(void)
|
||||
localzone_parents_test();
|
||||
}
|
||||
|
||||
#include "services/mesh.h"
|
||||
/** mesh unit tests */
|
||||
static void mesh_test(void)
|
||||
{
|
||||
struct regional* r2, *r3;
|
||||
struct respip_client_info* c1, *c2, *c3;
|
||||
unit_show_func("services/mesh.c", "mesh_copy_client_info");
|
||||
r2 = regional_create();
|
||||
r3 = regional_create();
|
||||
if(!r2 || !r3) fatal_exit("out of memory");
|
||||
|
||||
c1 = calloc(1, sizeof(*c1));
|
||||
if(!c1) fatal_exit("out of memory");
|
||||
c1->view = calloc(1, sizeof(*c1->view));
|
||||
if(!c1->view) fatal_exit("out of memory");
|
||||
c1->view->name = strdup("view1");
|
||||
if(!c1->view->name) fatal_exit("out of memory");
|
||||
|
||||
c2 = mesh_copy_client_info(r2, c1);
|
||||
if(!c2) fatal_exit("out of memory");
|
||||
c3 = mesh_copy_client_info(r3, c2);
|
||||
if(!c3) fatal_exit("out of memory");
|
||||
|
||||
unit_assert(strcmp(c1->view->name, c2->view_name) == 0);
|
||||
unit_assert(strcmp(c1->view->name, c3->view_name) == 0);
|
||||
|
||||
/* make sure that the c3 view_name is in the r3 region. */
|
||||
unit_assert(r3->next == NULL); /* only the first chunk present atm */
|
||||
if(strlen(c3->view_name) >= r3->large_object_size) {
|
||||
char* a = r3->large_list;
|
||||
int found = 0;
|
||||
while(a) {
|
||||
if(strcmp(c3->view_name,
|
||||
a + /* ALIGNEMENT */ sizeof(uint64_t)) == 0) {
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
a = *(char**)a;
|
||||
}
|
||||
unit_assert(found == 1);
|
||||
} else {
|
||||
/* The allocation is expected in the r3 region first chunk */
|
||||
unit_assert((uint8_t*)c3->view_name < ((uint8_t*)r3)+r3->first_size);
|
||||
}
|
||||
|
||||
regional_destroy(r2);
|
||||
/* ASAN should complain for the freed access below */
|
||||
unit_assert(strcmp(c1->view->name, c3->view_name) == 0);
|
||||
|
||||
regional_destroy(r3);
|
||||
free(c1->view->name);
|
||||
free(c1->view);
|
||||
free(c1);
|
||||
}
|
||||
|
||||
void unit_show_func(const char* file, const char* func)
|
||||
{
|
||||
printf("test %s:%s\n", file, func);
|
||||
@@ -1356,6 +1411,7 @@ main(int argc, char* argv[])
|
||||
msgparse_test();
|
||||
edns_ede_answer_encode_test();
|
||||
localzone_test();
|
||||
mesh_test();
|
||||
#ifdef CLIENT_SUBNET
|
||||
ecs_test();
|
||||
#endif /* CLIENT_SUBNET */
|
||||
|
||||
@@ -498,7 +498,11 @@ testfromdrillfile(sldns_buffer* pkt, struct alloc_cache* alloc,
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
|
||||
#ifndef __QNX__
|
||||
#define SRCDIRSTR xstr(SRCDIR)
|
||||
#else /* !__QNX__ */
|
||||
#define SRCDIRSTR "."
|
||||
#endif /* __QNX__ */
|
||||
|
||||
void msgparse_test(void)
|
||||
{
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "config.h"
|
||||
#include "testcode/unitmain.h"
|
||||
#include "util/log.h"
|
||||
#include "util/net_help.h"
|
||||
#include "util/random.h"
|
||||
#include "services/outside_network.h"
|
||||
|
||||
@@ -479,6 +480,278 @@ static void reuse_write_wait_test(void)
|
||||
check_reuse_write_wait_removal(1, &reuse, store, 0, 1);
|
||||
}
|
||||
|
||||
static void shared_port_test_ifs(void)
|
||||
{
|
||||
struct shared_ports* shp;
|
||||
struct shared_ports_if* shpif;
|
||||
char* ifs[] = {"1.2.3.4", "1.2.3.5", "::1:2", "::1:3"};
|
||||
int availports[] = {1, 2, 3, 4};
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
shp = shared_ports_create(ifs, 4, 1, 1, availports, 4);
|
||||
unit_assert(shp);
|
||||
|
||||
if(!ipstrtoaddr("1.2.3.4", UNBOUND_DNS_PORT, &addr, &addrlen))
|
||||
log_err("could not parse");
|
||||
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
|
||||
unit_assert(shpif);
|
||||
|
||||
if(!ipstrtoaddr("1.2.3.5", UNBOUND_DNS_PORT, &addr, &addrlen))
|
||||
log_err("could not parse");
|
||||
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
|
||||
unit_assert(shpif);
|
||||
|
||||
if(!ipstrtoaddr("::1:2", UNBOUND_DNS_PORT, &addr, &addrlen))
|
||||
log_err("could not parse");
|
||||
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
|
||||
unit_assert(shpif);
|
||||
|
||||
if(!ipstrtoaddr("::1:3", UNBOUND_DNS_PORT, &addr, &addrlen))
|
||||
log_err("could not parse");
|
||||
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
|
||||
unit_assert(shpif);
|
||||
|
||||
shared_ports_delete(shp);
|
||||
}
|
||||
|
||||
/** See if a port is on the shared_ports ports list */
|
||||
static int
|
||||
pif_list_contains(struct shared_ports_if* shpif, int item)
|
||||
{
|
||||
int i;
|
||||
unit_assert(shpif->inuse >= 0 && shpif->inuse <= shpif->avail_total);
|
||||
for(i=0; i< shpif->avail_total - shpif->inuse; i++) {
|
||||
if(shpif->avail_ports[i] == item)
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** See if a number of ports are on the shared_ports list */
|
||||
static int
|
||||
pif_list_contains_items(struct shared_ports_if* shpif, int item1,
|
||||
int item2, int item3, int item4)
|
||||
{
|
||||
if(item1 != -1 && !pif_list_contains(shpif, item1))
|
||||
return 0;
|
||||
if(item2 != -1 && !pif_list_contains(shpif, item2))
|
||||
return 0;
|
||||
if(item3 != -1 && !pif_list_contains(shpif, item3))
|
||||
return 0;
|
||||
if(item4 != -1 && !pif_list_contains(shpif, item4))
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void shared_port_test_port(void)
|
||||
{
|
||||
struct shared_ports* shp;
|
||||
struct shared_ports_if* shpif;
|
||||
char* ifs[] = {"1.2.3.4", "1.2.3.5"};
|
||||
int availports[] = {1, 2, 3, 4};
|
||||
struct sockaddr_storage addr;
|
||||
socklen_t addrlen;
|
||||
int p1, p2, p3, reused;
|
||||
struct ub_randstate* rnd;
|
||||
|
||||
rnd = ub_initstate(NULL);
|
||||
unit_assert(rnd);
|
||||
|
||||
shp = shared_ports_create(ifs, 2, 1, 1, availports, 4);
|
||||
unit_assert(shp);
|
||||
|
||||
if(!ipstrtoaddr("1.2.3.4", UNBOUND_DNS_PORT, &addr, &addrlen))
|
||||
log_err("could not parse");
|
||||
shpif = shared_ports_find_if(shp, &addr, addrlen, 0);
|
||||
unit_assert(shpif);
|
||||
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 0);
|
||||
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
|
||||
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
unit_assert(!pif_list_contains(shpif, p1));
|
||||
if(p1 != 1) unit_assert(pif_list_contains(shpif, 1));
|
||||
if(p1 != 2) unit_assert(pif_list_contains(shpif, 2));
|
||||
if(p1 != 3) unit_assert(pif_list_contains(shpif, 3));
|
||||
if(p1 != 4) unit_assert(pif_list_contains(shpif, 4));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 1);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p1);
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 0);
|
||||
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
|
||||
|
||||
/* pick up two items */
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p2, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p2 != 0);
|
||||
unit_assert(!pif_list_contains(shpif, p1));
|
||||
unit_assert(!pif_list_contains(shpif, p2));
|
||||
if(p1 != 1 && p2 != 1) unit_assert(pif_list_contains(shpif, 1));
|
||||
if(p1 != 2 && p2 != 2) unit_assert(pif_list_contains(shpif, 2));
|
||||
if(p1 != 3 && p2 != 3) unit_assert(pif_list_contains(shpif, 3));
|
||||
if(p1 != 4 && p2 != 4) unit_assert(pif_list_contains(shpif, 4));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 2);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p1);
|
||||
unit_assert(pif_list_contains(shpif, p1));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 1);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p2);
|
||||
unit_assert(pif_list_contains(shpif, p2));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 0);
|
||||
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
|
||||
|
||||
/* pick up three items */
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p2, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p2 != 0);
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p3, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p3 != 0);
|
||||
unit_assert(!pif_list_contains(shpif, p1));
|
||||
unit_assert(!pif_list_contains(shpif, p2));
|
||||
unit_assert(!pif_list_contains(shpif, p3));
|
||||
if(p1 != 1 && p2 != 1 && p3 != 1)
|
||||
unit_assert(pif_list_contains(shpif, 1));
|
||||
if(p1 != 2 && p2 != 2 && p3 != 2)
|
||||
unit_assert(pif_list_contains(shpif, 2));
|
||||
if(p1 != 3 && p2 != 3 && p3 != 3)
|
||||
unit_assert(pif_list_contains(shpif, 3));
|
||||
if(p1 != 4 && p2 != 4 && p3 != 4)
|
||||
unit_assert(pif_list_contains(shpif, 4));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 3);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p1);
|
||||
unit_assert(pif_list_contains(shpif, p1));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 2);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p2);
|
||||
unit_assert(pif_list_contains(shpif, p2));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 1);
|
||||
|
||||
shared_ports_return_port(shp, shpif, p3);
|
||||
unit_assert(pif_list_contains(shpif, p3));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 0);
|
||||
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
|
||||
|
||||
/* pick up all four items */
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0, 0, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 0);
|
||||
unit_assert(p1 != 0);
|
||||
unit_assert(!pif_list_contains(shpif, 1));
|
||||
unit_assert(!pif_list_contains(shpif, 2));
|
||||
unit_assert(!pif_list_contains(shpif, 3));
|
||||
unit_assert(!pif_list_contains(shpif, 4));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 4);
|
||||
|
||||
/* more fetches fail, it is fully inuse. */
|
||||
unit_assert(!shared_ports_fetch_random(shp, shpif, rnd, 0, 0, &p2,
|
||||
&reused));
|
||||
unit_assert(!shared_ports_fetch_random(shp, shpif, rnd, 0, 0, &p3,
|
||||
&reused));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 4);
|
||||
|
||||
/* reuse is then always the case */
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0 /* can reuse */, 4 /* reusenum */, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 1);
|
||||
unit_assert(p1 >= 0 && p1 < 4 /* reusenum */);
|
||||
|
||||
if(!shared_ports_fetch_random(shp, shpif, rnd,
|
||||
0 /* can reuse */, 4 /* reusenum */, &p1, &reused)) {
|
||||
unit_assert(0); /* should succeed */
|
||||
}
|
||||
unit_assert(reused == 1);
|
||||
unit_assert(p1 >= 0 && p1 < 4 /* reusenum */);
|
||||
|
||||
/* return all the ports */
|
||||
shared_ports_return_port(shp, shpif, 1);
|
||||
unit_assert(pif_list_contains(shpif, 1));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 3);
|
||||
shared_ports_return_port(shp, shpif, 2);
|
||||
unit_assert(pif_list_contains(shpif, 2));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 2);
|
||||
shared_ports_return_port(shp, shpif, 3);
|
||||
unit_assert(pif_list_contains(shpif, 3));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 1);
|
||||
shared_ports_return_port(shp, shpif, 4);
|
||||
unit_assert(pif_list_contains(shpif, 4));
|
||||
unit_assert(shpif->avail_total == 4);
|
||||
unit_assert(shpif->inuse == 0);
|
||||
unit_assert(pif_list_contains_items(shpif, 1, 2, 3, 4));
|
||||
|
||||
shared_ports_delete(shp);
|
||||
ub_randfree(rnd);
|
||||
}
|
||||
|
||||
void tcpreuse_test(void)
|
||||
{
|
||||
unit_show_feature("tcp_reuse");
|
||||
@@ -486,4 +759,7 @@ void tcpreuse_test(void)
|
||||
tcp_reuse_tree_list_test();
|
||||
waiting_tcp_list_test();
|
||||
reuse_write_wait_test();
|
||||
unit_show_feature("shared_ports");
|
||||
shared_port_test_ifs();
|
||||
shared_port_test_port();
|
||||
}
|
||||
|
||||
+34
-13
@@ -513,8 +513,11 @@ nsec3_hash_test(const char* fname)
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
|
||||
#ifndef __QNX__
|
||||
#define SRCDIRSTR xstr(SRCDIR)
|
||||
|
||||
#else /* !__QNX__ */
|
||||
#define SRCDIRSTR "."
|
||||
#endif /* __QNX__ */
|
||||
#if defined(HAVE_SSL) && defined(USE_SHA1)
|
||||
/* Detect if openssl is configured to disable RSASHA1 signatures,
|
||||
* with the rh-allow-sha1-signatures disabled. */
|
||||
@@ -631,6 +634,7 @@ rh_allow_sha1_signatures_disabled(void)
|
||||
void
|
||||
verify_test(void)
|
||||
{
|
||||
int do_sha1 = 1;
|
||||
unit_show_feature("signature verify");
|
||||
|
||||
#if defined(HAVE_SSL) && defined(USE_SHA1)
|
||||
@@ -643,27 +647,40 @@ verify_test(void)
|
||||
#else
|
||||
_putenv("OPENSSL_ENABLE_SHA1_SIGNATURES=1");
|
||||
#endif
|
||||
do_sha1 = 1;
|
||||
}
|
||||
#ifdef HAVE_EVP_DEFAULT_PROPERTIES_IS_FIPS_ENABLED
|
||||
if (EVP_default_properties_is_fips_enabled(NULL))
|
||||
do_sha1 = 0;
|
||||
#endif
|
||||
#endif /* HAVE_SSL and USE_SHA1 */
|
||||
|
||||
#ifdef USE_SHA1
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.1", "20070818005004");
|
||||
if(do_sha1) {
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.1", "20070818005004");
|
||||
}
|
||||
#endif
|
||||
#if defined(USE_DSA) && defined(USE_SHA1)
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.2", "20080414005004");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.3", "20080416005004");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.4", "20080416005004");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.5", "20080416005004");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.6", "20080416005004");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.7", "20070829144150");
|
||||
if(do_sha1) {
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.2", "20080414005004");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.3", "20080416005004");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.4", "20080416005004");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.5", "20080416005004");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.6", "20080416005004");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.7", "20070829144150");
|
||||
}
|
||||
#endif /* USE_DSA */
|
||||
#ifdef USE_SHA1
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.8", "20070829144150");
|
||||
if(do_sha1) {
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.8", "20070829144150");
|
||||
}
|
||||
#endif
|
||||
#if (defined(HAVE_EVP_SHA256) || defined(HAVE_NSS) || defined(HAVE_NETTLE)) && defined(USE_SHA2)
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256", "20070829144150");
|
||||
# ifdef USE_SHA1
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_sigs.sha1_and_256", "20070829144150");
|
||||
if(do_sha1) {
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_sigs.sha1_and_256", "20070829144150");
|
||||
}
|
||||
# endif
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_sigs.rsasha256_draft", "20090101000000");
|
||||
#endif
|
||||
@@ -672,8 +689,10 @@ verify_test(void)
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_signatures.9", "20171215000000");
|
||||
#endif
|
||||
#ifdef USE_SHA1
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_sigs.hinfo", "20090107100022");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_sigs.revoked", "20080414005004");
|
||||
if(do_sha1) {
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_sigs.hinfo", "20090107100022");
|
||||
verifytest_file(SRCDIRSTR "/testdata/test_sigs.revoked", "20080414005004");
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_GOST
|
||||
if(sldns_key_EVP_load_gost_id())
|
||||
@@ -699,7 +718,9 @@ verify_test(void)
|
||||
}
|
||||
#endif
|
||||
#ifdef USE_SHA1
|
||||
dstest_file(SRCDIRSTR "/testdata/test_ds.sha1");
|
||||
if(do_sha1) {
|
||||
dstest_file(SRCDIRSTR "/testdata/test_ds.sha1");
|
||||
}
|
||||
#endif
|
||||
nsectest();
|
||||
nsec3_hash_test(SRCDIRSTR "/testdata/test_nsec3_hash.1");
|
||||
|
||||
@@ -50,7 +50,11 @@
|
||||
|
||||
#define xstr(s) str(s)
|
||||
#define str(s) #s
|
||||
#ifndef __QNX__
|
||||
#define SRCDIRSTR xstr(SRCDIR)
|
||||
#else /* !__QNX__ */
|
||||
#define SRCDIRSTR "."
|
||||
#endif /* __QNX__ */
|
||||
|
||||
/** Add zone from file for testing */
|
||||
struct auth_zone* authtest_addzone(struct auth_zones* az, const char* name,
|
||||
|
||||
Vendored
+1
-1
@@ -24,7 +24,7 @@ server:
|
||||
# specify every interface on a new 'interface:' labelled line.
|
||||
interface: 192.0.2.153
|
||||
interface: 192.0.2.154
|
||||
interface: 2001:DB8::5
|
||||
interface: 2001:db8::5
|
||||
|
||||
# port to answer queries from
|
||||
port: 53
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user