Compare commits

...
Author SHA1 Message Date
TCY16 b3ea58dffb intermediate commit V3; Working up to test 2023-01-31 15:54:02 +01:00
TCY16 5143108457 add handover text and tests 2022-12-09 21:48:25 +01:00
TCY16 11106a726b intermediate commit v2; now with seemingly working private cookies 2022-12-09 15:29:52 +01:00
Willem Toorop 8df26b132b Merge branch 'master' into devel/merge-master-into-downstream-cookies 2022-11-07 17:09:20 +00:00
George Thessalonikefs f531faf163 Changelog entry for #767
- Merge #767 from jonathangray: consistently use IPv4/IPv6 in
    unbound.conf.5.
2022-10-21 15:49:56 +02:00
Yorgos ThessalonikefsandGitHub c0c9acccfd Merge pull request #767 from jonathangray/man
consistently use IPv4/IPv6 in unbound.conf.5
2022-10-21 15:46:45 +02:00
W.C.A. Wijngaards 17e5dd6131 - Fix that cachedb does not store failures in the external cache. 2022-10-21 10:11:47 +02:00
TCY16 eb85f34351 intermediate commit 2022-10-18 15:25:47 +02:00
George Thessalonikefs e9107907e5 - Clarify the use of MAX_SENT_COUNT in the iterator code. 2022-10-18 12:29:07 +02:00
W.C.A. Wijngaards ba8642aeb7 - testcode/dohclient sets log identity to its name. 2022-10-17 16:00:43 +02:00
W.C.A. Wijngaards 5ffa4d7232 - In unit test, print python script name list correctly. 2022-10-14 16:49:57 +02:00
W.C.A. Wijngaards 2571d00535 Changelog note for #768
- Merge #768 from fobser: Arithmetic on a pointer to void is a GNU
  extension.
2022-10-14 16:22:17 +02:00
Wouter WijngaardsandGitHub f9a563d495 Merge pull request #768 from fobser/void_math
Arithmetic on a pointer to void is a GNU extension.
2022-10-14 16:21:14 +02:00
Florian Obser 08dcae0dab Arithmetic on a pointer to void is a GNU extension. 2022-10-14 13:56:32 +02:00
W.C.A. Wijngaards 5ac1bc13cb - Tag for 1.17.0 release. The code repository continues with 1.17.1. 2022-10-13 09:34:44 +02:00
W.C.A. Wijngaards f5e1ef650d Merge branch 'branch-1.17.0' 2022-10-13 09:32:22 +02:00
George Thessalonikefs d25e0cd9b0 - Fix PROXYv2 header read for TCP connections when no proxied addresses
are provided.
2022-10-11 17:39:30 +02:00
Jonathan Gray 4f27799456 consistently use IPv4/IPv6 2022-10-10 19:14:58 +11:00
W.C.A. Wijngaards 97d1cff315 Changelog note for tag for 1.17.0rc1 release. 2022-10-07 13:29:33 +02:00
George Thessalonikefs a4631a3ecf - Fix unit test to properly test the reuse_write_wait_pop function. 2022-10-07 11:29:46 +02:00
George Thessalonikefs 2569b12b9c - Fix to stop possible loops in the tcp reuse code (write_wait list
and tcp_wait list). Based on analysis and patch from Prad Seniappan
  and Karthik Umashankar.
2022-10-07 11:25:36 +02:00
W.C.A. Wijngaards bf1cce6f9b - Fix proxy length debug output printout typecasts. 2022-10-06 15:53:21 +02:00
W.C.A. Wijngaards b043bc5eb4 - Fix to stop responses with TC flag from resulting in partial
responses. It retries to fetch the data elsewhere, or fails the
  query and in depth fix removes the TC flag from the cached item.
2022-10-06 10:01:09 +02:00
George Thessalonikefs d122617dd4 - Fix checkconf test for dnscrypt and proxy port. 2022-10-05 22:03:01 +02:00
W.C.A. Wijngaards 6b8181acb7 - Fix dnscrypt compile for proxy protocol code changes. 2022-10-05 14:09:12 +02:00
George Thessalonikefs f609a45354 - Make ede.tdir test more predictable by using static data. 2022-10-05 02:44:50 +02:00
George Thessalonikefs 60db1111c0 - Use DEBUG_TDIR from environment in mini_tdir.sh for debugging.
- Fix string comparison in mini_tdir.sh.
2022-10-05 01:13:29 +02:00
George Thessalonikefs 40b2b3a6f3 Changelog entry for #764
- Merge #764: Leniency for target discovery when under load (for
  NRDelegation changes).
2022-10-04 22:24:18 +02:00
Yorgos ThessalonikefsandGitHub f1d263a318 Leniency for target discovery when under load (for NRDelegation changes) (#764)
* - Introduce leniency for target discovery when under load.

* - Allow for easier testing (to be reverted).

* - Happy compiler.

* - Precheck access to target_fetch_policy.

* - Do not mark a nameserver as resolved when one of A/AAAA is negative.

* - Update fetch_glue.rpl test for (possible) outstanding queries.

* - Update fetch_glue_cname.rpl test for possible outstanding queries.

* - Better fix for fetch_glue_cname.rpl.

* - Fix iter_emptydp_for_glue.rpl to match the referral.

* - Disabled the nxns tests for now (to be reverted).

* - Update iter_recurse.rpl for possible outstanding queries.

* Revert "- Disabled the nxns tests for now (to be reverted)."

This reverts commit 34a9c13a90.

* Revert "- Allow for easier testing (to be reverted)."

This reverts commit b6dfe35e1d.
2022-10-04 22:21:08 +02:00
W.C.A. Wijngaards f0614a57f8 - Fix to clean up after the acl_interface unit test. 2022-10-04 16:59:10 +02:00
W.C.A. Wijngaards bf7a2884fb - Fix static analysis report to remove dead code from the
rpz_callback_from_iterator_module function.
2022-10-04 09:08:11 +02:00
W.C.A. Wijngaards c0eaadfc42 - Fix to close errno block in comm_point_tcp_handle_read outside of
ifdef.
2022-10-03 16:21:39 +02:00
George Thessalonikefs 22e43aa631 Changelog entry for #760
- Merge #760: PROXYv2 downstream support. (New proxy-protocol-port
  configuration option).
2022-10-03 15:34:22 +02:00
Yorgos ThessalonikefsandGitHub c4e51a4cfe PROXYv2 downstream support (#760) 2022-10-03 15:29:47 +02:00
W.C.A. Wijngaards 7d96a7e3fe - Fix windows compile, the identifier interface is defined in headers. 2022-10-03 15:03:50 +02:00
W.C.A. Wijngaards 9842fbf760 - Fix test tdir skip report printout. 2022-10-03 10:26:30 +02:00
W.C.A. Wijngaards a102fb1df8 - Fix to remove erroneous TC flag from TCP upstream. 2022-10-03 09:53:41 +02:00
Willem Toorop bd2c202674 The generated lexer and parser sources for configuring cookies 2022-09-28 10:34:06 +02:00
Willem Toorop 75f3fbdd65 Downstream DNS Cookies a la RFC7873 and RFC9018
Create server cookies for clients that send client cookies.
Needs to be turned on in the config file with:

	answer-cookie: yes

A cookie-secret can be configured for anycast setups.
Also adds an access control list that will allow queries with
either a valid cookie or over a stateful transport.
2022-09-28 10:28:19 +02:00
Willem Toorop 71f23ef354 extended_error_encode() for extended errors 2022-09-28 09:57:56 +02:00
George Thessalonikefs 5b98816751 - Better output for skipped tdir tests. 2022-09-26 15:51:28 +02:00
W.C.A. Wijngaards e93c75a5d4 - Fix doxygen warning in respip.h. 2022-09-21 15:23:04 +02:00
W.C.A. Wijngaards 8e18f11965 - This patch was released in 1.16.3, the code repository continues
with the previous features and fixes for 1.17.0.
2022-09-21 12:16:13 +02:00
W.C.A. Wijngaards e3871ca907 Merge branch 'branch-1.16.3' 2022-09-21 12:11:26 +02:00
W.C.A. Wijngaards 137719522a - Patch for CVE-2022-3204 Non-Responsive Delegation Attack. 2022-09-21 11:10:38 +02:00
W.C.A. Wijngaards bd3c5702a7 branch for 1.16.3 release. 2022-09-21 11:09:03 +02:00
Philip-NLnetLabsandGitHub f68e252345 Merge pull request #757 from NLnetLabs/philip-issue-749
Philip issue 749
2022-09-20 15:07:14 +02:00
Philip Homburg 1e5158045f Merge branch 'ryndia-issue-749' into philip-issue-749 2022-09-20 14:48:57 +02:00
George Thessalonikefs 99e12ae4b5 - Remove unused testcode/mini_tpkg.sh file. 2022-09-20 14:47:24 +02:00
Philip Homburg 5f3b460586 Align with version 1.58 on cvsweb.openbsd.org 2022-09-20 14:47:19 +02:00
George Thessalonikefs 9b1647ebae - Convert tdir tests to use the new skip_test functionality. 2022-09-20 14:45:20 +02:00
George Thessalonikefs 307805b64f Changelog entry for #753:
- Merge #753: ACL per interface. (New interface-* configuration
  options).
2022-09-20 11:36:01 +02:00
Yorgos ThessalonikefsandGitHub f02d6bddd1 Merge pull request #753 from NLnetLabs/acl_interface
ACL per interface
2022-09-16 16:45:59 +02:00
eb02170338 Apply suggestions from code review
Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com>
2022-09-16 14:43:23 +02:00
George Thessalonikefs d301bfe4a2 - ACL per interface: refactor, complete testing and a bugfix for
interface names.
2022-09-11 20:57:41 +02:00
George Thessalonikefs fc123303ac - Add functionality to skip tdir tests from the .pre file;
- Initial tests for interface-* options.
2022-09-11 20:21:32 +02:00
George Thessalonikefs aec33b3d63 Documentation for interface-* options. 2022-09-11 20:21:32 +02:00
George Thessalonikefs 7e9fd2114b Cleared error messages for interface-* options. 2022-09-11 20:21:32 +02:00
George Thessalonikefs c30bdff939 Initial commit for interface based ACL. 2022-09-11 20:21:32 +02:00
ryndiaandGitHub cfc656294e Update arc4random.c 2022-09-07 20:16:20 +04:00
TCY16 730b55c94a add privacy aware cookies. This breaks the rpl test 2022-09-02 15:49:17 +02:00
W.C.A. Wijngaards 007db2c327 - Fix to check pthread_t size after pthread has been detected. 2022-09-02 10:21:00 +02:00
W.C.A. Wijngaards 5bbaf78c3f - Remove include that was there for debug purposes. 2022-09-02 10:11:23 +02:00
W.C.A. Wijngaards 57230d7f22 - Fix to log a verbose message at operational notice level if a
thread is not responding, to stats requests. It is logged with
  thread identifiers.
2022-09-01 15:14:20 +02:00
W.C.A. Wijngaards d66e1cccf8 - Fix to set out of file descriptor warning to operational verbosity. 2022-09-01 14:01:56 +02:00
W.C.A. Wijngaards 2450b4653a - Slow down log frequency of write wait failures. 2022-09-01 14:00:29 +02:00
W.C.A. Wijngaards eb3378396f - Fix to update config tests to fix checking if nonblocking sockets
work on OpenBSD.
2022-09-01 09:16:05 +02:00
W.C.A. Wijngaards 1f5cc25974 - Fix for wait for udp send to stop when packet is successfully sent. 2022-08-31 16:45:15 +02:00
W.C.A. Wijngaards ec5812a748 - Fix to wait for blocked write on UDP sockets, with a timeout if it
takes too long the packet is dropped.
2022-08-31 11:54:11 +02:00
W.C.A. Wijngaards 10a5a5880a - Patch from Vadim Fedorenko that adds MSG_DONTWAIT to receive
operations, so that instruction reordering does not cause mistakenly
  blocking socket operations.
2022-08-31 10:11:25 +02:00
W.C.A. Wijngaards 2fa1c17cd9 - Fix to avoid process wide fcntl calls mixed with nonblocking
operations after a blocked write.
2022-08-31 10:09:39 +02:00
W.C.A. Wijngaards e6f878ee71 - Fix #741: systemd socket activation fails on IPv6. 2022-08-22 09:12:08 +02:00
W.C.A. Wijngaards dc6c04b243 - Fix to log accept error ENFILE and EMFILE errno, but slowly, once
per 10 seconds. Also log accept failures when no slow down is used.
2022-08-12 09:54:29 +02:00
TCY16 bb2d70ce31 Merge branch 'master' into features/upstream-cookies 2022-08-08 11:25:20 +02:00
W.C.A. Wijngaards ef57f8bd51 - Fix #734 [FR] enable unbound-checkconf to detect more (basic)
errors.
2022-08-05 14:41:05 +02:00
W.C.A. Wijngaards fbe8e3b0b2 - Fix ratelimit inconsistency, for ip-ratelimits the value is the
amount allowed, like for ratelimits.
2022-08-04 11:33:37 +02:00
W.C.A. Wijngaards 1c164ab442 Changelog note for #730
- Merge #730 from luisdallos: Fix startup failure on Windows 8.1 due
  to unsupported IPV6_USER_MTU socket option being set.
2022-08-02 16:12:31 +02:00
Wouter WijngaardsandGitHub e738ec31ca Merge pull request #730 from luisdallos/win81-unsup-sockopt-fix
Fix startup failure on Windows 8.1 due to unsupported IPV6_USER_MTU socket option being set
2022-08-02 16:12:16 +02:00
W.C.A. Wijngaards 07b073ddb3 - Fix unittest for edns subnet change. 2022-08-02 14:43:57 +02:00
W.C.A. Wijngaards 0f08cc6d55 - Fix edns subnet so that scope 0 answers only match sourcemask 0
queries for answers from cache if from a query with sourcemask 0.
2022-08-02 14:13:55 +02:00
Luis Dallos 7d3c6f1c43 Fix startup failure on Windows 8.1 due to unsupported IPV6_USER_MTU socket option being set
Newer mingw-w64 (starting from 8.0.1) introduces support for `IPV6_USER_MTU` socket
option [1], which is not supported on Windows 8.1 and older [2]. As there is no way
to avoid this socket option from being picked at compile time when targeting older
versions of Windows, check for `setsockopt(..., IPV6_USER_MTU, ...)` failures at
runtime in order to avoid startup failure on those versions of Windows where the
`IPV6_USER_MTU` socket option is unsupported.

[1]: mirror/mingw-w64@e30bff4
[2]: `WSAGetLastError()` returns `WSAENOPROTOOPT` (`Bad protocol option`) error code
2022-08-01 23:03:24 -04:00
W.C.A. Wijngaards cd22fdc28d - Fix #728: alloc_reg_obtain() core dump. Stop double
alloc_reg_release when serviced_create fails.
2022-08-01 16:45:41 +02:00
W.C.A. Wijngaards 5ae48f85c0 - The code repo continues with 1.16.3. 2022-08-01 15:17:10 +02:00
W.C.A. Wijngaards cbed768b8f - Tests for ghost domain fixes. 2022-08-01 13:26:22 +02:00
W.C.A. Wijngaards f6753a0f10 - Fix the novel ghost domain issues CVE-2022-30698 and CVE-2022-30699. 2022-08-01 13:24:40 +02:00
George Thessalonikefs efdd70c7b5 - Cleanup some comments and TODO text. 2022-07-23 19:55:15 +02:00
TCY16 b5acecc1f6 implement @wcawijngaards' review comments 2022-07-20 16:36:58 +03:00
W.C.A. Wijngaards f993ffbb07 Changelog note for #718
- Merge #718: Introduce infra-cache-max-rtt option to config max
  retransmit timeout.
2022-07-19 15:19:12 +02:00
Wouter WijngaardsandGitHub ef9bb0213b Merge pull request #718 from hunts/make_rtt_max_timeout_configurable
Introduce infra-cache-max-rtt option to config max retransmit timeout
2022-07-19 15:15:34 +02:00
George Thessalonikefs 309e23515e - Update documentation for 'outbound-msg-retry:'. 2022-07-19 12:47:01 +02:00
Minghang Chen 249efd4285 Introduce infra-cache-max-rtt option to config max retransmit timeout
Added the option and let it default to 120 seconds so that it won't change
current behavior.

Related-to #717
2022-07-16 01:46:18 -07:00
W.C.A. Wijngaards 12cd495d55 - iana portlist update. 2022-07-15 09:20:25 +02:00
W.C.A. Wijngaards 33bd49af81 - Merge PR 714: Avoid treat normal hosts as unresponsive servers.
And fixup the lock code.
2022-07-15 08:51:31 +02:00
Wouter WijngaardsandGitHub 6e50c46102 Merge pull request #714 from hunts/rtt-of-expired-host
Avoid treat normal hosts as unresponsive servers
2022-07-15 08:49:51 +02:00
Hunts Chen 88bf803297 Avoid treat normal hosts as unresponsive servers
This is a fix for issue #713

When infra-keep-probing is on, all hosts with expired entries were treated as
unresponsive servers and thus causing problems (see #713).

This commit change that, so that normal hosts with expired entries are treated
as unknown servers.
2022-07-14 10:16:13 -07:00
George Thessalonikefs 9e4a17baaf - For windows crosscompile, fix setting the IPV6_MTU socket option
equivalent (IPV6_USER_MTU); allows cross compiling with latest
  cross-compiler versions.
2022-07-12 17:17:59 +02:00
W.C.A. Wijngaards 2abd6f7d58 - Fix dname count in sldns parse type descriptor for SVCB and HTTPS. 2022-07-12 13:29:51 +02:00
W.C.A. Wijngaards 7696398231 - Fix verbose EDE error printout. 2022-07-11 13:13:51 +02:00
Wouter WijngaardsandGitHub 886ffcc155 Merge pull request #711 from NLnetLabs/add-security.md
add SECURITY.md, based on krill
2022-07-11 11:37:28 +02:00
W.C.A. Wijngaards a45ced7739 - This became 1.16.1 on 11 July 2022.
The code repo continues with version 1.16.2 under development.
2022-07-11 11:34:54 +02:00
maertsenandGitHub 125983558b add SECURITY.md, based on krill 2022-07-05 16:39:04 +02:00
TCY16 0d3823f3b3 fix test and add mapage entry 2022-07-01 15:39:13 +02:00
TCY16 aebf1db116 add step in rpl to verify the updated server cookie and fix bug with unupdated rdlen 2022-06-20 15:41:11 +02:00
TCY16 303aa68b58 fix incorrect copy error 2022-06-20 14:12:19 +02:00
TCY16 a5ca3850aa fix memory alloc bug for the testcase and c89 style 2022-06-17 15:52:45 +02:00
TCY16 69411ff125 make upstream cookies configurable 2022-06-15 14:31:24 +02:00
TCY16 d26c286da8 add the 3 teststeps for upstream cookies 2022-06-15 14:01:58 +02:00
TCY16 069660af48 add unit test for server cookie init 2022-06-14 15:36:25 +02:00
TCY16 e7b480a0a2 add verification of the client cookie in the response and add cookie in the rrdef enum 2022-06-08 13:55:26 +02:00
TCY16 9a9f3e4118 Merge branch 'master' of github.com:NLnetLabs/unbound into features/upstream-cookies 2022-05-30 15:38:18 +02:00
TCY16 10dee6cee1 create random cookies by creating and storing a random state in infra_cache 2022-05-19 14:55:26 +02:00
TCY16 44af84dfc9 store complete cookie when receiving from downstream. Add function through search through an edns_option list 2022-05-19 13:24:00 +02:00
TCY16 23e04d7f39 add functionality to store the client cookie and attach both client and server cookie to the upstream query 2022-05-16 15:33:56 +02:00
247 changed files with 16652 additions and 9383 deletions
+10 -6
View File
@@ -128,9 +128,9 @@ util/config_file.c util/configlexer.c util/configparser.c \
util/shm_side/shm_main.c services/authzone.c \
util/fptr_wlist.c util/locks.c util/log.c util/mini_event.c util/module.c \
util/netevent.c util/net_help.c util/random.c util/rbtree.c util/regional.c \
util/rtt.c util/edns.c util/storage/dnstree.c util/storage/lookup3.c \
util/rtt.c util/siphash.c util/edns.c util/storage/dnstree.c util/storage/lookup3.c \
util/storage/lruhash.c util/storage/slabhash.c util/tcp_conn_limit.c \
util/timehist.c util/tube.c \
util/timehist.c util/tube.c util/proxy_protocol.c \
util/ub_event.c util/ub_event_pluggable.c util/winsock_event.c \
validator/autotrust.c validator/val_anchor.c validator/validator.c \
validator/val_kcache.c validator/val_kentry.c validator/val_neg.c \
@@ -145,10 +145,10 @@ as112.lo msgparse.lo msgreply.lo packed_rrset.lo iterator.lo iter_delegpt.lo \
iter_donotq.lo iter_fwd.lo iter_hints.lo iter_priv.lo iter_resptype.lo \
iter_scrub.lo iter_utils.lo localzone.lo mesh.lo modstack.lo view.lo \
outbound_list.lo alloc.lo config_file.lo configlexer.lo configparser.lo \
fptr_wlist.lo edns.lo locks.lo log.lo mini_event.lo module.lo net_help.lo \
fptr_wlist.lo siphash.lo edns.lo locks.lo log.lo mini_event.lo module.lo net_help.lo \
random.lo rbtree.lo regional.lo rtt.lo dnstree.lo lookup3.lo lruhash.lo \
slabhash.lo tcp_conn_limit.lo timehist.lo tube.lo winsock_event.lo \
autotrust.lo val_anchor.lo rpz.lo \
autotrust.lo val_anchor.lo rpz.lo proxy_protocol.lo \
validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \
val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo $(CACHEDB_OBJ) authzone.lo \
$(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \
@@ -915,7 +915,8 @@ config_file.lo config_file.o: $(srcdir)/util/config_file.c config.h $(srcdir)/ut
configlexer.lo configlexer.o: util/configlexer.c config.h $(srcdir)/util/configyyrename.h \
$(srcdir)/util/config_file.h util/configparser.h
configparser.lo configparser.o: util/configparser.c config.h $(srcdir)/util/configyyrename.h \
$(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h
$(srcdir)/util/config_file.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h $(srcdir)/sldns/str2wire.h \
$(srcdir)/sldns/rrdef.h
shm_main.lo shm_main.o: $(srcdir)/util/shm_side/shm_main.c config.h $(srcdir)/util/shm_side/shm_main.h \
$(srcdir)/libunbound/unbound.h $(srcdir)/daemon/daemon.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
$(srcdir)/util/alloc.h $(srcdir)/services/modstack.h \
@@ -984,6 +985,8 @@ netevent.lo netevent.o: $(srcdir)/util/netevent.c config.h $(srcdir)/util/neteve
$(srcdir)/sldns/sbuffer.h $(srcdir)/util/config_file.h $(srcdir)/services/authzone.h $(srcdir)/daemon/stats.h \
$(srcdir)/util/timehist.h $(srcdir)/libunbound/unbound.h $(srcdir)/respip/respip.h $(srcdir)/sldns/str2wire.h \
$(srcdir)/dnstap/dnstap.h $(srcdir)/services/listen_dnsport.h
proxy_protocol.lo proxy_protocol.o: $(srcdir)/util/proxy_protocol.c config.h \
$(srcdir)/util/proxy_protocol.h $(srcdir)/sldns/sbuffer.h
net_help.lo net_help.o: $(srcdir)/util/net_help.c config.h $(srcdir)/util/net_help.h $(srcdir)/util/log.h \
$(srcdir)/util/data/dname.h $(srcdir)/util/storage/lruhash.h $(srcdir)/util/locks.h $(srcdir)/util/module.h \
$(srcdir)/util/data/msgreply.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/msgparse.h \
@@ -1004,6 +1007,7 @@ rtt.lo rtt.o: $(srcdir)/util/rtt.c config.h $(srcdir)/util/rtt.h $(srcdir)/itera
$(srcdir)/services/outbound_list.h $(srcdir)/util/data/msgreply.h $(srcdir)/util/storage/lruhash.h \
$(srcdir)/util/locks.h $(srcdir)/util/log.h $(srcdir)/util/data/packed_rrset.h $(srcdir)/util/module.h \
$(srcdir)/util/data/msgparse.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h
siphash.lo siphash.o: $(srcdir)/util/siphash.c
edns.lo edns.o: $(srcdir)/util/edns.c config.h $(srcdir)/util/edns.h $(srcdir)/util/storage/dnstree.h \
$(srcdir)/util/rbtree.h $(srcdir)/util/config_file.h $(srcdir)/util/netevent.h $(srcdir)/dnscrypt/dnscrypt.h \
$(srcdir)/util/net_help.h $(srcdir)/util/log.h $(srcdir)/util/regional.h \
@@ -1512,7 +1516,7 @@ asynclook.lo asynclook.o: $(srcdir)/testcode/asynclook.c config.h $(srcdir)/libu
$(srcdir)/services/modstack.h $(srcdir)/libunbound/unbound-event.h $(srcdir)/util/data/packed_rrset.h \
$(srcdir)/util/storage/lruhash.h $(srcdir)/sldns/rrdef.h
streamtcp.lo streamtcp.o: $(srcdir)/testcode/streamtcp.c config.h $(srcdir)/util/locks.h $(srcdir)/util/log.h \
$(srcdir)/util/net_help.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/msgparse.h \
$(srcdir)/util/net_help.h $(srcdir)/util/proxy_protocol.h $(srcdir)/util/data/msgencode.h $(srcdir)/util/data/msgparse.h \
$(srcdir)/util/storage/lruhash.h $(srcdir)/sldns/pkthdr.h $(srcdir)/sldns/rrdef.h $(srcdir)/util/data/msgreply.h \
$(srcdir)/util/data/packed_rrset.h $(srcdir)/util/data/dname.h $(srcdir)/sldns/sbuffer.h \
$(srcdir)/sldns/str2wire.h $(srcdir)/sldns/wire2str.h
+31
View File
@@ -0,0 +1,31 @@
# Security Policy
## Supported Versions
NLnet Labs adheres to the straightforward, semantic versioning scheme that is
commonly used in the software industry.
Support is provided in respect of the latest release, i.e. releases with the
highest minor and patch version level. We do not backport security fixes to
older (minor) versions. In the event a new major version is released (e.g. from
3.2.18 to 4.0.0), support will also be provided on the latest minor version of
the previous major version (3.2.18) for a period of one year from the release of
the new major version (4.0.0).
In the event that, during this period, a new patch or minor version of the
previous major version is released, then support on these versions will only be
provided for the remainder of the one-year-period.
You can find detailed information on our software support policy here:
https://www.nlnetlabs.nl/support/software-support-policy/
## Reporting a Vulnerability
We take security very seriously. If you have discovered a security vulnerability
in one of our projects and you would like to report it to us, you can send an
encrypted message to our Security Entry Point.
Details are described here:
https://www.nlnetlabs.nl/security-report/
+5 -1
View File
@@ -2,7 +2,8 @@
# Copyright 2009, Wouter Wijngaards, NLnet Labs.
# BSD licensed.
#
# Version 43
# Version 44
# 2022-09-01 fix checking if nonblocking sockets work on OpenBSD.
# 2021-08-17 fix sed script in ssldir split handling.
# 2021-08-17 fix for openssl to detect split version, with ssldir_include
# and ssldir_lib output directories.
@@ -963,6 +964,9 @@ AC_LANG_SOURCE([[
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
+10 -1
View File
@@ -390,6 +390,15 @@ prep_data(struct module_qstate* qstate, struct sldns_buffer* buf)
if(!qstate->return_msg || !qstate->return_msg->rep)
return 0;
/* do not store failures like SERVFAIL in the cachedb, this avoids
* overwriting expired, valid, content with broken content. */
if(FLAGS_GET_RCODE(qstate->return_msg->rep->flags) !=
LDNS_RCODE_NOERROR &&
FLAGS_GET_RCODE(qstate->return_msg->rep->flags) !=
LDNS_RCODE_NXDOMAIN &&
FLAGS_GET_RCODE(qstate->return_msg->rep->flags) !=
LDNS_RCODE_YXDOMAIN)
return 0;
/* We don't store the reply if its TTL is 0 unless serve-expired is
* enabled. Such a reply won't be reusable and simply be a waste for
* the backend. It's also compatible with the default behavior of
@@ -662,7 +671,7 @@ cachedb_intcache_store(struct module_qstate* qstate)
return;
(void)dns_cache_store(qstate->env, &qstate->qinfo,
qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0,
qstate->region, store_flags);
qstate->region, store_flags, qstate->qstarttime);
}
/**
+7 -1
View File
@@ -57,6 +57,8 @@
#define BLOCKSZ 64
#define RSBUFSZ (16*BLOCKSZ)
#define REKEY_BASE (1024*1024) /* NB. should be a power of 2 */
/* Marked MAP_INHERIT_ZERO, so zero'd out in fork children. */
static struct {
size_t rs_have; /* valid bytes at end of rs_buf */
@@ -179,6 +181,7 @@ static void
_rs_stir(void)
{
u_char rnd[KEYSZ + IVSZ];
uint32_t rekey_fuzz = 0;
if (getentropy(rnd, sizeof rnd) == -1) {
if(errno != ENOSYS ||
@@ -201,7 +204,10 @@ _rs_stir(void)
rs->rs_have = 0;
memset(rsx->rs_buf, 0, sizeof(rsx->rs_buf));
rs->rs_count = 1600000;
/* rekey interval should not be predictable */
chacha_encrypt_bytes(&rsx->rs_chacha, (uint8_t *)&rekey_fuzz,
(uint8_t *)&rekey_fuzz, sizeof(rekey_fuzz));
rs->rs_count = REKEY_BASE + (rekey_fuzz % REKEY_BASE);
}
static inline void
+15
View File
@@ -298,6 +298,9 @@
/* Define to 1 if you have the `getrlimit' function. */
#undef HAVE_GETRLIMIT
/* Define to 1 if you have the `gettid' function. */
#undef HAVE_GETTID
/* Define to 1 if you have the `glob' function. */
#undef HAVE_GLOB
@@ -457,6 +460,12 @@
/* Define to 1 if you have the `OSSL_PARAM_BLD_new' function. */
#undef HAVE_OSSL_PARAM_BLD_NEW
/* Define to 1 if you have the `poll' function. */
#undef HAVE_POLL
/* Define to 1 if you have the <poll.h> header file. */
#undef HAVE_POLL_H
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
@@ -800,12 +809,18 @@
/* Shared data */
#undef SHARE_DIR
/* The size of `pthread_t', as computed by sizeof. */
#undef SIZEOF_PTHREAD_T
/* The size of `size_t', as computed by sizeof. */
#undef SIZEOF_SIZE_T
/* The size of `time_t', as computed by sizeof. */
#undef SIZEOF_TIME_T
/* The size of `unsigned long', as computed by sizeof. */
#undef SIZEOF_UNSIGNED_LONG
/* define if (v)snprintf does not return length needed, (but length used) */
#undef SNPRINTF_RET_BROKEN
Vendored
+87 -14
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.69 for unbound 1.16.1.
# Generated by GNU Autoconf 2.69 for unbound 1.17.1.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>.
#
@@ -591,8 +591,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
PACKAGE_VERSION='1.16.1'
PACKAGE_STRING='unbound 1.16.1'
PACKAGE_VERSION='1.17.1'
PACKAGE_STRING='unbound 1.17.1'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
PACKAGE_URL=''
@@ -1477,7 +1477,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.16.1 to adapt to many kinds of systems.
\`configure' configures unbound 1.17.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1543,7 +1543,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of unbound 1.16.1:";;
short | recursive ) echo "Configuration of unbound 1.17.1:";;
esac
cat <<\_ACEOF
@@ -1785,7 +1785,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
unbound configure 1.16.1
unbound configure 1.17.1
generated by GNU Autoconf 2.69
Copyright (C) 2012 Free Software Foundation, Inc.
@@ -2494,7 +2494,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.16.1, which was
It was created by unbound $as_me 1.17.1, which was
generated by GNU Autoconf 2.69. Invocation command line was
$ $0 $@
@@ -2844,13 +2844,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
UNBOUND_VERSION_MAJOR=1
UNBOUND_VERSION_MINOR=16
UNBOUND_VERSION_MINOR=17
UNBOUND_VERSION_MICRO=1
LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=17
LIBUNBOUND_REVISION=21
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -2935,6 +2935,10 @@ LIBUNBOUND_AGE=1
# 1.15.0 had 9:15:1
# 1.16.0 had 9:16:1
# 1.16.1 had 9:17:1
# 1.16.2 had 9:18:1
# 1.16.3 had 9:19:1
# 1.17.0 had 9:20:1
# 1.17.1 had 9:21:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -14770,7 +14774,7 @@ fi
fi
# Checks for header files.
for ac_header in stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h
for ac_header in stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h
do :
as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
@@ -16029,6 +16033,9 @@ else
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_SYS_SELECT_H
#include <sys/select.h>
#endif
#ifdef HAVE_SYS_SOCKET_H
#include <sys/socket.h>
#endif
@@ -17099,6 +17106,72 @@ _ACEOF
fi
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of unsigned long" >&5
$as_echo_n "checking size of unsigned long... " >&6; }
if ${ac_cv_sizeof_unsigned_long+:} false; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (unsigned long))" "ac_cv_sizeof_unsigned_long" "$ac_includes_default"; then :
else
if test "$ac_cv_type_unsigned_long" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (unsigned long)
See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_unsigned_long=0
fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_unsigned_long" >&5
$as_echo "$ac_cv_sizeof_unsigned_long" >&6; }
cat >>confdefs.h <<_ACEOF
#define SIZEOF_UNSIGNED_LONG $ac_cv_sizeof_unsigned_long
_ACEOF
# The cast to long int works around a bug in the HP C Compiler
# version HP92453-01 B.11.11.23709.GP, which incorrectly rejects
# declarations like `int a3[[(sizeof (unsigned char)) >= 0]];'.
# This bug is HP SR number 8606223364.
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking size of pthread_t" >&5
$as_echo_n "checking size of pthread_t... " >&6; }
if ${ac_cv_sizeof_pthread_t+:} false; then :
$as_echo_n "(cached) " >&6
else
if ac_fn_c_compute_int "$LINENO" "(long int) (sizeof (pthread_t))" "ac_cv_sizeof_pthread_t" "$ac_includes_default"; then :
else
if test "$ac_cv_type_pthread_t" = yes; then
{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
as_fn_error 77 "cannot compute sizeof (pthread_t)
See \`config.log' for more details" "$LINENO" 5; }
else
ac_cv_sizeof_pthread_t=0
fi
fi
fi
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_sizeof_pthread_t" >&5
$as_echo "$ac_cv_sizeof_pthread_t" >&6; }
cat >>confdefs.h <<_ACEOF
#define SIZEOF_PTHREAD_T $ac_cv_sizeof_pthread_t
_ACEOF
if echo "$CFLAGS" | $GREP -e "-pthread" >/dev/null; then
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if -pthread unused during linking" >&5
@@ -20589,7 +20662,7 @@ if test "$ac_res" != no; then :
fi
for ac_func in tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex
for ac_func in tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid
do :
as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var"
@@ -22013,7 +22086,7 @@ _ACEOF
version=1.16.1
version=1.17.1
date=`date +'%b %e, %Y'`
@@ -22532,7 +22605,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.16.1, which was
This file was extended by unbound $as_me 1.17.1, which was
generated by GNU Autoconf 2.69. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -22598,7 +22671,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
unbound config.status 1.16.1
unbound config.status 1.17.1
configured by $0, generated by GNU Autoconf 2.69,
with options \\"\$ac_cs_config\\"
+10 -4
View File
@@ -10,7 +10,7 @@ sinclude(dnscrypt/dnscrypt.m4)
# must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1])
m4_define([VERSION_MINOR],[16])
m4_define([VERSION_MINOR],[17])
m4_define([VERSION_MICRO],[1])
AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound])
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
@@ -18,7 +18,7 @@ AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=17
LIBUNBOUND_REVISION=21
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -103,6 +103,10 @@ LIBUNBOUND_AGE=1
# 1.15.0 had 9:15:1
# 1.16.0 had 9:16:1
# 1.16.1 had 9:17:1
# 1.16.2 had 9:18:1
# 1.16.3 had 9:19:1
# 1.17.0 had 9:20:1
# 1.17.1 had 9:21:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -395,7 +399,7 @@ PKG_PROG_PKG_CONFIG
fi
# Checks for header files.
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_HEADERS([stdarg.h stdbool.h netinet/in.h netinet/tcp.h sys/param.h sys/select.h sys/socket.h sys/un.h sys/uio.h sys/resource.h arpa/inet.h syslog.h netdb.h sys/wait.h pwd.h glob.h grp.h login_cap.h winsock2.h ws2tcpip.h endian.h sys/endian.h libkern/OSByteOrder.h sys/ipc.h sys/shm.h ifaddrs.h poll.h],,, [AC_INCLUDES_DEFAULT])
# net/if.h portability for Darwin see:
# https://www.gnu.org/software/autoconf/manual/autoconf-2.69/html_node/Header-Portability.html
AC_CHECK_HEADERS([net/if.h],,, [
@@ -605,6 +609,8 @@ if test x_$withval != x_no; then
CC="$PTHREAD_CC"
ub_have_pthreads=yes
AC_CHECK_TYPES([pthread_spinlock_t, pthread_rwlock_t],,,[#include <pthread.h>])
AC_CHECK_SIZEOF([unsigned long])
AC_CHECK_SIZEOF(pthread_t)
if echo "$CFLAGS" | $GREP -e "-pthread" >/dev/null; then
AC_MSG_CHECKING([if -pthread unused during linking])
@@ -1642,7 +1648,7 @@ AC_LINK_IFELSE([AC_LANG_PROGRAM([
AC_MSG_RESULT(no))
AC_SEARCH_LIBS([setusercontext], [util])
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex])
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob initgroups strftime localtime_r setusercontext _beginthreadex endservent endprotoent fsync shmget accept4 getifaddrs if_nametoindex poll gettid])
AC_CHECK_FUNCS([setresuid],,[AC_CHECK_FUNCS([setreuid])])
AC_CHECK_FUNCS([setresgid],,[AC_CHECK_FUNCS([setregid])])
+389 -88
View File
@@ -46,9 +46,10 @@
#include "util/config_file.h"
#include "util/net_help.h"
#include "services/localzone.h"
#include "services/listen_dnsport.h"
#include "sldns/str2wire.h"
struct acl_list*
struct acl_list*
acl_list_create(void)
{
struct acl_list* acl = (struct acl_list*)calloc(1,
@@ -63,10 +64,10 @@ acl_list_create(void)
return acl;
}
void
void
acl_list_delete(struct acl_list* acl)
{
if(!acl)
if(!acl)
return;
regional_destroy(acl->region);
free(acl);
@@ -74,8 +75,8 @@ acl_list_delete(struct acl_list* acl)
/** insert new address into acl_list structure */
static struct acl_addr*
acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
socklen_t addrlen, int net, enum acl_access control,
acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
socklen_t addrlen, int net, enum acl_access control,
int complain_duplicates)
{
struct acl_addr* node = regional_alloc_zero(acl->region,
@@ -90,6 +91,33 @@ acl_list_insert(struct acl_list* acl, struct sockaddr_storage* addr,
return node;
}
/** parse str to acl_access enum */
static int
parse_acl_access(const char* str, enum acl_access* control)
{
if(strcmp(str, "allow") == 0)
*control = acl_allow;
else if(strcmp(str, "deny") == 0)
*control = acl_deny;
else if(strcmp(str, "refuse") == 0)
*control = acl_refuse;
else if(strcmp(str, "deny_non_local") == 0)
*control = acl_deny_non_local;
else if(strcmp(str, "refuse_non_local") == 0)
*control = acl_refuse_non_local;
else if(strcmp(str, "allow_snoop") == 0)
*control = acl_allow_snoop;
else if(strcmp(str, "allow_setrd") == 0)
*control = acl_allow_setrd;
else if (strcmp(str, "allow_cookie") == 0)
*control = acl_allow_cookie;
else {
log_err("access control type %s unknown", str);
return 0;
}
return 1;
}
/** apply acl_list string */
static int
acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
@@ -99,29 +127,14 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
int net;
socklen_t addrlen;
enum acl_access control;
if(strcmp(s2, "allow") == 0)
control = acl_allow;
else if(strcmp(s2, "deny") == 0)
control = acl_deny;
else if(strcmp(s2, "refuse") == 0)
control = acl_refuse;
else if(strcmp(s2, "deny_non_local") == 0)
control = acl_deny_non_local;
else if(strcmp(s2, "refuse_non_local") == 0)
control = acl_refuse_non_local;
else if(strcmp(s2, "allow_snoop") == 0)
control = acl_allow_snoop;
else if(strcmp(s2, "allow_setrd") == 0)
control = acl_allow_setrd;
else {
log_err("access control type %s unknown", str);
if(!parse_acl_access(s2, &control)) {
return 0;
}
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
log_err("cannot parse access control: %s %s", str, s2);
return 0;
}
if(!acl_list_insert(acl, &addr, addrlen, net, control,
if(!acl_list_insert(acl, &addr, addrlen, net, control,
complain_duplicates)) {
log_err("out of memory");
return 0;
@@ -131,19 +144,27 @@ acl_list_str_cfg(struct acl_list* acl, const char* str, const char* s2,
/** find or create node (NULL on parse or error) */
static struct acl_addr*
acl_find_or_create(struct acl_list* acl, const char* str)
acl_find_or_create_str2addr(struct acl_list* acl, const char* str,
int is_interface, int port)
{
struct acl_addr* node;
struct sockaddr_storage addr;
int net;
socklen_t addrlen;
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
log_err("cannot parse netblock: %s", str);
return NULL;
int net = (str_is_ip6(str)?128:32);
if(is_interface) {
if(!extstrtoaddr(str, &addr, &addrlen, port)) {
log_err("cannot parse interface: %s", str);
return NULL;
}
} else {
if(!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &addr, &addrlen, &net)) {
log_err("cannot parse netblock: %s", str);
return NULL;
}
}
/* find or create node */
if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, &addr,
addrlen, net))) {
addrlen, net)) && !is_interface) {
/* create node, type 'allow' since otherwise tags are
* pointless, can override with specific access-control: cfg */
if(!(node=(struct acl_addr*)acl_list_insert(acl, &addr,
@@ -155,14 +176,65 @@ acl_find_or_create(struct acl_list* acl, const char* str)
return node;
}
/** find or create node (NULL on error) */
static struct acl_addr*
acl_find_or_create(struct acl_list* acl, struct sockaddr_storage* addr,
socklen_t addrlen, enum acl_access control)
{
struct acl_addr* node;
int net = (addr_is_ip6(addr, addrlen)?128:32);
/* find or create node */
if(!(node=(struct acl_addr*)addr_tree_find(&acl->tree, addr,
addrlen, net))) {
/* create node;
* can override with specific access-control: cfg */
if(!(node=(struct acl_addr*)acl_list_insert(acl, addr,
addrlen, net, control, 1))) {
log_err("out of memory");
return NULL;
}
}
return node;
}
/** apply acl_interface string */
static int
acl_interface_str_cfg(struct acl_list* acl_interface, const char* iface,
const char* s2, int port)
{
struct acl_addr* node;
enum acl_access control;
if(!parse_acl_access(s2, &control)) {
return 0;
}
if(!(node=acl_find_or_create_str2addr(acl_interface, iface, 1, port))) {
log_err("cannot update ACL on non-configured interface: %s %d",
iface, port);
return 0;
}
node->control = control;
return 1;
}
struct acl_addr*
acl_interface_insert(struct acl_list* acl_interface,
struct sockaddr_storage* addr, socklen_t addrlen,
enum acl_access control)
{
return acl_find_or_create(acl_interface, addr, addrlen, control);
}
/** apply acl_tag string */
static int
acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap,
size_t bitmaplen)
size_t bitmaplen, int is_interface, int port)
{
struct acl_addr* node;
if(!(node=acl_find_or_create(acl, str)))
if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
if(is_interface)
log_err("non-configured interface: %s", str);
return 0;
}
node->taglen = bitmaplen;
node->taglist = regional_alloc_init(acl->region, bitmap, bitmaplen);
if(!node->taglist) {
@@ -175,11 +247,14 @@ acl_list_tags_cfg(struct acl_list* acl, const char* str, uint8_t* bitmap,
/** apply acl_view string */
static int
acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2,
struct views* vs)
struct views* vs, int is_interface, int port)
{
struct acl_addr* node;
if(!(node=acl_find_or_create(acl, str)))
if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
if(is_interface)
log_err("non-configured interface: %s", str);
return 0;
}
node->view = views_find_view(vs, str2, 0 /* get read lock*/);
if(!node->view) {
log_err("no view with name: %s", str2);
@@ -192,13 +267,17 @@ acl_list_view_cfg(struct acl_list* acl, const char* str, const char* str2,
/** apply acl_tag_action string */
static int
acl_list_tag_action_cfg(struct acl_list* acl, struct config_file* cfg,
const char* str, const char* tag, const char* action)
const char* str, const char* tag, const char* action,
int is_interface, int port)
{
struct acl_addr* node;
int tagid;
enum localzone_type t;
if(!(node=acl_find_or_create(acl, str)))
if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
if(is_interface)
log_err("non-configured interface: %s", str);
return 0;
}
/* allocate array if not yet */
if(!node->tag_actions) {
node->tag_actions = (uint8_t*)regional_alloc_zero(acl->region,
@@ -281,13 +360,17 @@ check_data(const char* data, const struct config_strlist* head)
/** apply acl_tag_data string */
static int
acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg,
const char* str, const char* tag, const char* data)
const char* str, const char* tag, const char* data,
int is_interface, int port)
{
struct acl_addr* node;
int tagid;
char* dupdata;
if(!(node=acl_find_or_create(acl, str)))
if(!(node=acl_find_or_create_str2addr(acl, str, is_interface, port))) {
if(is_interface)
log_err("non-configured interface: %s", str);
return 0;
}
/* allocate array if not yet */
if(!node->tag_datas) {
node->tag_datas = (struct config_strlist**)regional_alloc_zero(
@@ -329,11 +412,11 @@ acl_list_tag_data_cfg(struct acl_list* acl, struct config_file* cfg,
}
/** read acl_list config */
static int
read_acl_list(struct acl_list* acl, struct config_file* cfg)
static int
read_acl_list(struct acl_list* acl, struct config_str2list* acls)
{
struct config_str2list* p;
for(p = cfg->acls; p; p = p->next) {
for(p = acls; p; p = p->next) {
log_assert(p->str && p->str2);
if(!acl_list_str_cfg(acl, p->str, p->str2, 1))
return 0;
@@ -341,15 +424,38 @@ read_acl_list(struct acl_list* acl, struct config_file* cfg)
return 1;
}
/** read acl tags config */
static int
read_acl_tags(struct acl_list* acl, struct config_file* cfg)
/** read acl view config */
static int
read_acl_view(struct acl_list* acl, struct config_str2list** acl_view,
struct views* v)
{
struct config_strbytelist* np, *p = cfg->acl_tags;
cfg->acl_tags = NULL;
struct config_str2list* np, *p = *acl_view;
*acl_view = NULL;
while(p) {
log_assert(p->str && p->str2);
if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len)) {
if(!acl_list_view_cfg(acl, p->str, p->str2, v, 0, 0)) {
config_deldblstrlist(p);
return 0;
}
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p);
p = np;
}
return 1;
}
/** read acl tags config */
static int
read_acl_tags(struct acl_list* acl, struct config_strbytelist** acl_tags)
{
struct config_strbytelist* np, *p = *acl_tags;
*acl_tags = NULL;
while(p) {
log_assert(p->str && p->str2);
if(!acl_list_tags_cfg(acl, p->str, p->str2, p->str2len, 0, 0)) {
config_del_strbytelist(p);
return 0;
}
@@ -363,38 +469,18 @@ read_acl_tags(struct acl_list* acl, struct config_file* cfg)
return 1;
}
/** read acl view config */
static int
read_acl_view(struct acl_list* acl, struct config_file* cfg, struct views* v)
{
struct config_str2list* np, *p = cfg->acl_view;
cfg->acl_view = NULL;
while(p) {
log_assert(p->str && p->str2);
if(!acl_list_view_cfg(acl, p->str, p->str2, v)) {
return 0;
}
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p);
p = np;
}
return 1;
}
/** read acl tag actions config */
static int
read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg)
static int
read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg,
struct config_str3list** acl_tag_actions)
{
struct config_str3list* p, *np;
p = cfg->acl_tag_actions;
cfg->acl_tag_actions = NULL;
p = *acl_tag_actions;
*acl_tag_actions = NULL;
while(p) {
log_assert(p->str && p->str2 && p->str3);
if(!acl_list_tag_action_cfg(acl, cfg, p->str, p->str2,
p->str3)) {
p->str3, 0, 0)) {
config_deltrplstrlist(p);
return 0;
}
@@ -410,15 +496,17 @@ read_acl_tag_actions(struct acl_list* acl, struct config_file* cfg)
}
/** read acl tag datas config */
static int
read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg)
static int
read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg,
struct config_str3list** acl_tag_datas)
{
struct config_str3list* p, *np;
p = cfg->acl_tag_datas;
cfg->acl_tag_datas = NULL;
p = *acl_tag_datas;
*acl_tag_datas = NULL;
while(p) {
log_assert(p->str && p->str2 && p->str3);
if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3)) {
if(!acl_list_tag_data_cfg(acl, cfg, p->str, p->str2, p->str3,
0, 0)) {
config_deltrplstrlist(p);
return 0;
}
@@ -433,30 +521,27 @@ read_acl_tag_datas(struct acl_list* acl, struct config_file* cfg)
return 1;
}
int
int
acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
struct views* v)
{
regional_free_all(acl->region);
addr_tree_init(&acl->tree);
if(!read_acl_list(acl, cfg))
if(!read_acl_list(acl, cfg->acls))
return 0;
if(!read_acl_view(acl, cfg, v))
if(!read_acl_view(acl, &cfg->acl_view, v))
return 0;
if(!read_acl_tags(acl, cfg))
if(!read_acl_tags(acl, &cfg->acl_tags))
return 0;
if(!read_acl_tag_actions(acl, cfg))
if(!read_acl_tag_actions(acl, cfg, &cfg->acl_tag_actions))
return 0;
if(!read_acl_tag_datas(acl, cfg))
if(!read_acl_tag_datas(acl, cfg, &cfg->acl_tag_datas))
return 0;
/* insert defaults, with '0' to ignore them if they are duplicates */
if(!acl_list_str_cfg(acl, "0.0.0.0/0", "refuse", 0))
return 0;
/* the 'refuse' defaults for /0 are now done per interface instead */
if(!acl_list_str_cfg(acl, "127.0.0.0/8", "allow", 0))
return 0;
if(cfg->do_ip6) {
if(!acl_list_str_cfg(acl, "::0/0", "refuse", 0))
return 0;
if(!acl_list_str_cfg(acl, "::1", "allow", 0))
return 0;
if(!acl_list_str_cfg(acl, "::ffff:127.0.0.1", "allow", 0))
@@ -466,7 +551,223 @@ acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
return 1;
}
enum acl_access
int
acl_interface_compare(const void* k1, const void* k2)
{
struct addr_tree_node* n1 = (struct addr_tree_node*)k1;
struct addr_tree_node* n2 = (struct addr_tree_node*)k2;
return sockaddr_cmp(&n1->addr, n1->addrlen, &n2->addr,
n2->addrlen);
/* We don't care about comparing node->net. All addresses in the
* acl_interface tree have either 32 (ipv4) or 128 (ipv6). */
}
void
acl_interface_init(struct acl_list* acl_interface)
{
regional_free_all(acl_interface->region);
/* We want comparison in the tree to include only address and port.
* We don't care about comparing node->net. All addresses in the
* acl_interface->tree should have either 32 (ipv4) or 128 (ipv6).
* Initialise with the appropriate compare function but keep treating
* it as an addr_tree. */
addr_tree_addrport_init(&acl_interface->tree);
}
static int
read_acl_interface_action(struct acl_list* acl_interface,
struct config_str2list* acls, int port)
{
struct config_str2list* p;
for(p = acls; p; p = p->next) {
char** resif = NULL;
int num_resif = 0;
int i;
log_assert(p->str && p->str2);
if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif))
return 0;
for(i = 0; i<num_resif; i++) {
if(!acl_interface_str_cfg(acl_interface, resif[i], p->str2, port)){
config_del_strarray(resif, num_resif);
return 0;
}
}
config_del_strarray(resif, num_resif);
}
return 1;
}
/** read acl view config for interface */
static int
read_acl_interface_view(struct acl_list* acl_interface,
struct config_str2list** acl_view,
struct views* v, int port)
{
struct config_str2list* np, *p = *acl_view;
*acl_view = NULL;
while(p) {
char** resif = NULL;
int num_resif = 0;
int i;
log_assert(p->str && p->str2);
if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
config_deldblstrlist(p);
return 0;
}
for(i = 0; i<num_resif; i++) {
if(!acl_list_view_cfg(acl_interface, resif[i], p->str2,
v, 1, port)) {
config_del_strarray(resif, num_resif);
config_deldblstrlist(p);
return 0;
}
}
config_del_strarray(resif, num_resif);
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p);
p = np;
}
return 1;
}
/** read acl tags config for interface */
static int
read_acl_interface_tags(struct acl_list* acl_interface,
struct config_strbytelist** acl_tags, int port)
{
struct config_strbytelist* np, *p = *acl_tags;
*acl_tags = NULL;
while(p) {
char** resif = NULL;
int num_resif = 0;
int i;
log_assert(p->str && p->str2);
if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
config_del_strbytelist(p);
return 0;
}
for(i = 0; i<num_resif; i++) {
if(!acl_list_tags_cfg(acl_interface, resif[i], p->str2,
p->str2len, 1, port)) {
config_del_strbytelist(p);
config_del_strarray(resif, num_resif);
return 0;
}
}
config_del_strarray(resif, num_resif);
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p);
p = np;
}
return 1;
}
/** read acl tag actions config for interface*/
static int
read_acl_interface_tag_actions(struct acl_list* acl_interface,
struct config_file* cfg,
struct config_str3list** acl_tag_actions, int port)
{
struct config_str3list* p, *np;
p = *acl_tag_actions;
*acl_tag_actions = NULL;
while(p) {
char** resif = NULL;
int num_resif = 0;
int i;
log_assert(p->str && p->str2 && p->str3);
if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
config_deltrplstrlist(p);
return 0;
}
for(i = 0; i<num_resif; i++) {
if(!acl_list_tag_action_cfg(acl_interface, cfg,
resif[i], p->str2, p->str3, 1, port)) {
config_deltrplstrlist(p);
config_del_strarray(resif, num_resif);
return 0;
}
}
config_del_strarray(resif, num_resif);
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p->str3);
free(p);
p = np;
}
return 1;
}
/** read acl tag datas config for interface */
static int
read_acl_interface_tag_datas(struct acl_list* acl_interface,
struct config_file* cfg,
struct config_str3list** acl_tag_datas, int port)
{
struct config_str3list* p, *np;
p = *acl_tag_datas;
*acl_tag_datas = NULL;
while(p) {
char** resif = NULL;
int num_resif = 0;
int i;
log_assert(p->str && p->str2 && p->str3);
if(!resolve_interface_names(&p->str, 1, NULL, &resif, &num_resif)) {
config_deltrplstrlist(p);
return 0;
}
for(i = 0; i<num_resif; i++) {
if(!acl_list_tag_data_cfg(acl_interface, cfg,
resif[i], p->str2, p->str3, 1, port)) {
config_deltrplstrlist(p);
config_del_strarray(resif, num_resif);
return 0;
}
}
config_del_strarray(resif, num_resif);
/* free the items as we go to free up memory */
np = p->next;
free(p->str);
free(p->str2);
free(p->str3);
free(p);
p = np;
}
return 1;
}
int
acl_interface_apply_cfg(struct acl_list* acl_interface, struct config_file* cfg,
struct views* v)
{
if(!read_acl_interface_action(acl_interface, cfg->interface_actions,
cfg->port))
return 0;
if(!read_acl_interface_view(acl_interface, &cfg->interface_view, v,
cfg->port))
return 0;
if(!read_acl_interface_tags(acl_interface, &cfg->interface_tags,
cfg->port))
return 0;
if(!read_acl_interface_tag_actions(acl_interface, cfg,
&cfg->interface_tag_actions, cfg->port))
return 0;
if(!read_acl_interface_tag_datas(acl_interface, cfg,
&cfg->interface_tag_datas, cfg->port))
return 0;
addr_tree_init_parents(&acl_interface->tree);
return 1;
}
enum acl_access
acl_get_control(struct acl_addr* acl)
{
if(acl) return acl->control;
@@ -481,7 +782,7 @@ acl_addr_lookup(struct acl_list* acl, struct sockaddr_storage* addr,
addr, addrlen);
}
size_t
size_t
acl_list_get_mem(struct acl_list* acl)
{
if(!acl) return 0;
+39 -4
View File
@@ -36,7 +36,7 @@
/**
* \file
*
* This file keeps track of the list of clients that are allowed to
* This file keeps track of the list of clients that are allowed to
* access the server.
*/
@@ -65,7 +65,9 @@ enum acl_access {
/** allow full access for all queries, recursion and cache snooping */
acl_allow_snoop,
/** allow full access for recursion queries and set RD flag regardless of request */
acl_allow_setrd
acl_allow_setrd,
/** allow full access if valid cookie present or stateful transport */
acl_allow_cookie
};
/**
@@ -74,7 +76,7 @@ enum acl_access {
struct acl_list {
/** regional for allocation */
struct regional* region;
/**
/**
* Tree of the addresses that are allowed/blocked.
* contents of type acl_addr.
*/
@@ -108,7 +110,7 @@ struct acl_addr {
};
/**
* Create acl structure
* Create acl structure
* @return new structure or NULL on error.
*/
struct acl_list* acl_list_create(void);
@@ -119,6 +121,20 @@ struct acl_list* acl_list_create(void);
*/
void acl_list_delete(struct acl_list* acl);
/**
* Insert interface in the acl_list. This should happen when the listening
* interface is setup.
* @param acl_interface: acl_list to insert to.
* @param addr: interface IP.
* @param addrlen: length of the interface IP.
* @param control: acl_access.
* @return new structure or NULL on error.
*/
struct acl_addr*
acl_interface_insert(struct acl_list* acl_interface,
struct sockaddr_storage* addr, socklen_t addrlen,
enum acl_access control);
/**
* Process access control config.
* @param acl: where to store.
@@ -129,6 +145,25 @@ void acl_list_delete(struct acl_list* acl);
int acl_list_apply_cfg(struct acl_list* acl, struct config_file* cfg,
struct views* v);
/** compare ACL interface "addr_tree" nodes (+port) */
int acl_interface_compare(const void* k1, const void* k2);
/**
* Initialise (also clean) the acl_interface struct.
* @param acl_interface: where to store.
*/
void acl_interface_init(struct acl_list* acl_interface);
/**
* Process interface control config.
* @param acl_interface: where to store.
* @param cfg: config options.
* @param v: views structure
* @return 0 on error.
*/
int acl_interface_apply_cfg(struct acl_list* acl_interface, struct config_file* cfg,
struct views* v);
/**
* Lookup access control status for acl structure.
* @param acl: structure for acl storage.
+3 -2
View File
@@ -679,7 +679,8 @@ load_msg(RES* ssl, sldns_buffer* buf, struct worker* worker)
if(!go_on)
return 1; /* skip this one, not all references satisfied */
if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags)) {
if(!dns_cache_store(&worker->env, &qinf, &rep, 0, 0, 0, NULL, flags,
*worker->env.now)) {
log_warn("error out of memory");
return 0;
}
@@ -850,7 +851,7 @@ int print_deleg_lookup(RES* ssl, struct worker* worker, uint8_t* nm,
while(1) {
dp = dns_cache_find_delegation(&worker->env, nm, nmlen,
qinfo.qtype, qinfo.qclass, region, &msg,
*worker->env.now);
*worker->env.now, 0, NULL, 0);
if(!dp) {
return ssl_printf(ssl, "no delegation from "
"cache; goes to configured roots\n");
+60 -1
View File
@@ -96,6 +96,9 @@
#ifdef HAVE_SYSTEMD
#include <systemd/sd-daemon.h>
#endif
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
/** How many quit requests happened. */
static int sig_record_quit = 0;
@@ -271,8 +274,17 @@ daemon_init(void)
free(daemon);
return NULL;
}
daemon->acl_interface = acl_list_create();
if(!daemon->acl_interface) {
acl_list_delete(daemon->acl);
edns_known_options_delete(daemon->env);
free(daemon->env);
free(daemon);
return NULL;
}
daemon->tcl = tcl_list_create();
if(!daemon->tcl) {
acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
edns_known_options_delete(daemon->env);
free(daemon->env);
@@ -284,6 +296,7 @@ daemon_init(void)
log_err("gettimeofday: %s", strerror(errno));
daemon->time_last_stat = daemon->time_boot;
if((daemon->env->auth_zones = auth_zones_create()) == 0) {
acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
tcl_list_delete(daemon->tcl);
edns_known_options_delete(daemon->env);
@@ -293,6 +306,7 @@ daemon_init(void)
}
if(!(daemon->env->edns_strings = edns_strings_create())) {
auth_zones_delete(daemon->env->auth_zones);
acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
tcl_list_delete(daemon->tcl);
edns_known_options_delete(daemon->env);
@@ -303,6 +317,29 @@ daemon_init(void)
return daemon;
}
static int setup_acl_for_ports(struct acl_list* list,
struct listen_port* port_list)
{
struct acl_addr* acl_node;
struct addrinfo* addr;
for(; port_list; port_list=port_list->next) {
if(!port_list->socket) {
/* This is mainly for testbound where port_list is
* empty. */
continue;
}
addr = port_list->socket->addr;
if(!(acl_node = acl_interface_insert(list,
(struct sockaddr_storage*)addr->ai_addr,
(socklen_t)addr->ai_addrlen,
acl_refuse))) {
return 0;
}
port_list->socket->acl = acl_node;
}
return 1;
}
int
daemon_open_shared_ports(struct daemon* daemon)
{
@@ -320,6 +357,8 @@ daemon_open_shared_ports(struct daemon* daemon)
free(daemon->ports);
daemon->ports = NULL;
}
/* clean acl_interface */
acl_interface_init(daemon->acl_interface);
if(!resolve_interface_names(daemon->cfg->ifs,
daemon->cfg->num_ifs, NULL, &resif, &num_resif))
return 0;
@@ -329,7 +368,8 @@ daemon_open_shared_ports(struct daemon* daemon)
daemon->reuseport = 1;
#endif
/* try to use reuseport */
p0 = listening_ports_open(daemon->cfg, resif, num_resif, &daemon->reuseport);
p0 = listening_ports_open(daemon->cfg, resif, num_resif,
&daemon->reuseport);
if(!p0) {
listening_ports_free(p0);
config_del_strarray(resif, num_resif);
@@ -350,6 +390,12 @@ daemon_open_shared_ports(struct daemon* daemon)
return 0;
}
daemon->ports[0] = p0;
if(!setup_acl_for_ports(daemon->acl_interface,
daemon->ports[0])) {
listening_ports_free(p0);
config_del_strarray(resif, num_resif);
return 0;
}
if(daemon->reuseport) {
/* continue to use reuseport */
for(i=1; i<daemon->num_ports; i++) {
@@ -365,6 +411,15 @@ daemon_open_shared_ports(struct daemon* daemon)
config_del_strarray(resif, num_resif);
return 0;
}
if(!setup_acl_for_ports(daemon->acl_interface,
daemon->ports[i])) {
for(i=0; i<daemon->num_ports; i++)
listening_ports_free(daemon->ports[i]);
free(daemon->ports);
daemon->ports = NULL;
config_del_strarray(resif, num_resif);
return 0;
}
}
}
config_del_strarray(resif, num_resif);
@@ -604,6 +659,9 @@ daemon_fork(struct daemon* daemon)
if(!acl_list_apply_cfg(daemon->acl, daemon->cfg, daemon->views))
fatal_exit("Could not setup access control list");
if(!acl_interface_apply_cfg(daemon->acl_interface, daemon->cfg,
daemon->views))
fatal_exit("Could not setup interface control list");
if(!tcl_list_apply_cfg(daemon->tcl, daemon->cfg))
fatal_exit("Could not setup TCP connection limits");
if(daemon->cfg->dnscrypt) {
@@ -780,6 +838,7 @@ daemon_delete(struct daemon* daemon)
ub_randfree(daemon->rand);
alloc_clear(&daemon->superalloc);
acl_list_delete(daemon->acl);
acl_list_delete(daemon->acl_interface);
tcl_list_delete(daemon->tcl);
listen_desetup_locks();
free(daemon->chroot);
+2
View File
@@ -113,6 +113,8 @@ struct daemon {
struct module_stack mods;
/** access control, which client IPs are allowed to connect */
struct acl_list* acl;
/** access control, which interfaces are allowed to connect */
struct acl_list* acl_interface;
/** TCP connection limit, limit connections from client IPs */
struct tcl_list* tcl;
/** local authority zones */
+3 -3
View File
@@ -494,8 +494,8 @@ int remote_accept_callback(struct comm_point* c, void* arg, int err,
n->c->do_not_close = 0;
comm_point_stop_listening(n->c);
comm_point_start_listening(n->c, -1, REMOTE_CONTROL_TCP_TIMEOUT);
memcpy(&n->c->repinfo.addr, &addr, addrlen);
n->c->repinfo.addrlen = addrlen;
memcpy(&n->c->repinfo.remote_addr, &addr, addrlen);
n->c->repinfo.remote_addrlen = addrlen;
if(rc->use_cert) {
n->shake_state = rc_hs_read;
n->ssl = SSL_new(rc->ctx);
@@ -3304,7 +3304,7 @@ remote_handshake_later(struct daemon_remote* rc, struct rc_state* s,
if(r == 0)
log_err("remote control connection closed prematurely");
log_addr(VERB_OPS, "failed connection from",
&s->c->repinfo.addr, s->c->repinfo.addrlen);
&s->c->repinfo.remote_addr, s->c->repinfo.remote_addrlen);
log_crypto_err("remote control failed ssl");
clean_point(rc, s);
}
+26 -1
View File
@@ -70,6 +70,9 @@
#include <openssl/ssl.h>
#endif
/** How long to wait for threads to transmit statistics, in msec. */
#define STATS_THREAD_WAIT 60000
/** add timers and the values do not overflow or become negative */
static void
stats_timeval_add(long long* d_sec, long long* d_usec, long long add_sec, long long add_usec)
@@ -380,6 +383,28 @@ void server_stats_obtain(struct worker* worker, struct worker* who,
worker_send_cmd(who, worker_cmd_stats);
else worker_send_cmd(who, worker_cmd_stats_noreset);
verbose(VERB_ALGO, "wait for stats reply");
if(tube_wait_timeout(worker->cmd, STATS_THREAD_WAIT) == 0) {
verbose(VERB_OPS, "no response from thread %d"
#ifdef HAVE_GETTID
" LWP %u"
#endif
#if defined(HAVE_PTHREAD) && defined(SIZEOF_PTHREAD_T) && defined(SIZEOF_UNSIGNED_LONG)
# if SIZEOF_PTHREAD_T == SIZEOF_UNSIGNED_LONG
" pthread 0x%lx"
# endif
#endif
,
who->thread_num
#ifdef HAVE_GETTID
, (unsigned)who->thread_tid
#endif
#if defined(HAVE_PTHREAD) && defined(SIZEOF_PTHREAD_T) && defined(SIZEOF_UNSIGNED_LONG)
# if SIZEOF_PTHREAD_T == SIZEOF_UNSIGNED_LONG
, (unsigned long)*((unsigned long*)&who->thr_id)
# endif
#endif
);
}
if(!tube_read_msg(worker->cmd, &reply, &len, 0))
fatal_exit("failed to read stats over cmd channel");
if(len != (uint32_t)sizeof(*s))
@@ -496,7 +521,7 @@ void server_stats_insquery(struct ub_server_stats* stats, struct comm_point* c,
stats->qhttps++;
}
}
if(repinfo && addr_is_ip6(&repinfo->addr, repinfo->addrlen))
if(repinfo && addr_is_ip6(&repinfo->remote_addr, repinfo->remote_addrlen))
stats->qipv6++;
if( (flags&BIT_QR) )
stats->qbit_QR++;
+140 -72
View File
@@ -459,7 +459,7 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
dp = dns_cache_find_delegation(&worker->env, qinfo->qname,
qinfo->qname_len, qinfo->qtype, qinfo->qclass,
worker->scratchpad, &msg, timenow);
worker->scratchpad, &msg, timenow, 0, NULL, 0);
if(!dp) { /* no delegation, need to reprime */
return 0;
}
@@ -547,7 +547,8 @@ answer_norec_from_cache(struct worker* worker, struct query_info* qinfo,
static int
apply_respip_action(struct worker* worker, const struct query_info* qinfo,
struct respip_client_info* cinfo, struct reply_info* rep,
struct comm_reply* repinfo, struct ub_packed_rrset_key** alias_rrset,
struct sockaddr_storage* addr, socklen_t addrlen,
struct ub_packed_rrset_key** alias_rrset,
struct reply_info** encode_repp, struct auth_zones* az)
{
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
@@ -574,7 +575,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
if(actinfo.addrinfo) {
respip_inform_print(&actinfo, qinfo->qname,
qinfo->qtype, qinfo->qclass, qinfo->local_alias,
repinfo);
addr, addrlen);
if(worker->stats.extended && actinfo.rpz_used) {
if(actinfo.rpz_disabled)
@@ -703,7 +704,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
*alias_rrset = NULL; /* avoid confusion if caller set it to non-NULL */
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
repinfo, alias_rrset,
&repinfo->client_addr, repinfo->client_addrlen, alias_rrset,
&encode_rep, worker->env.auth_zones)) {
goto bail_out;
} else if(partial_rep &&
@@ -991,12 +992,14 @@ answer_chaos(struct worker* w, struct query_info* qinfo,
* @param w: worker
* @param qinfo: query info. Pointer into packet buffer.
* @param edns: edns info from query.
* @param repinfo: reply info with source address.
* @param addr: client address.
* @param addrlen: client address length.
* @param pkt: packet buffer.
*/
static void
answer_notify(struct worker* w, struct query_info* qinfo,
struct edns_data* edns, sldns_buffer* pkt, struct comm_reply* repinfo)
answer_notify(struct worker* w, struct query_info* qinfo,
struct edns_data* edns, sldns_buffer* pkt,
struct sockaddr_storage* addr, socklen_t addrlen)
{
int refused = 0;
int rcode = LDNS_RCODE_NOERROR;
@@ -1005,8 +1008,8 @@ answer_notify(struct worker* w, struct query_info* qinfo,
if(!w->env.auth_zones) return;
has_serial = auth_zone_parse_notify_serial(pkt, &serial);
if(auth_zones_notify(w->env.auth_zones, &w->env, qinfo->qname,
qinfo->qname_len, qinfo->qclass, &repinfo->addr,
repinfo->addrlen, has_serial, serial, &refused)) {
qinfo->qname_len, qinfo->qclass, addr,
addrlen, has_serial, serial, &refused)) {
rcode = LDNS_RCODE_NOERROR;
} else {
if(refused)
@@ -1031,7 +1034,7 @@ answer_notify(struct worker* w, struct query_info* qinfo,
"servfail for NOTIFY %sfor %s from", sr, zname);
else snprintf(buf, sizeof(buf),
"received NOTIFY %sfor %s from", sr, zname);
log_addr(VERB_DETAIL, buf, &repinfo->addr, repinfo->addrlen);
log_addr(VERB_DETAIL, buf, addr, addrlen);
}
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
@@ -1051,8 +1054,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
{
if(acl == deny) {
if(verbosity >= VERB_ALGO) {
log_acl_action("dropped", &repinfo->addr,
repinfo->addrlen, acl, acladdr);
log_acl_action("dropped", &repinfo->client_addr,
repinfo->client_addrlen, acl, acladdr);
log_buf(VERB_ALGO, "dropped", c->buffer);
}
comm_point_drop_reply(repinfo);
@@ -1063,8 +1066,8 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
size_t opt_rr_mark;
if(verbosity >= VERB_ALGO) {
log_acl_action("refused", &repinfo->addr,
repinfo->addrlen, acl, acladdr);
log_acl_action("refused", &repinfo->client_addr,
repinfo->client_addrlen, acl, acladdr);
log_buf(VERB_ALGO, "refuse", c->buffer);
}
@@ -1224,12 +1227,24 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
}
static int
deny_refuse_all(struct comm_point* c, enum acl_access acl,
deny_refuse_all(struct comm_point* c, enum acl_access* acl,
struct worker* worker, struct comm_reply* repinfo,
struct acl_addr* acladdr, int ede)
struct acl_addr** acladdr, int ede, int check_proxy)
{
return deny_refuse(c, acl, acl_deny, acl_refuse, worker, repinfo,
acladdr, ede);
if(check_proxy) {
*acladdr = acl_addr_lookup(worker->daemon->acl,
&repinfo->remote_addr, repinfo->remote_addrlen);
} else {
*acladdr = acl_addr_lookup(worker->daemon->acl,
&repinfo->client_addr, repinfo->client_addrlen);
}
/* If there is no ACL based on client IP use the interface ACL. */
if(!(*acladdr) && c->socket) {
*acladdr = c->socket->acl;
}
*acl = acl_get_control(*acladdr);
return deny_refuse(c, *acl, acl_deny, acl_refuse, worker, repinfo,
*acladdr, ede);
}
static int
@@ -1241,7 +1256,7 @@ deny_refuse_non_local(struct comm_point* c, enum acl_access acl,
worker, repinfo, acladdr, ede);
}
int
int
worker_handle_request(struct comm_point* c, void* arg, int error,
struct comm_reply* repinfo)
{
@@ -1286,16 +1301,16 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
if(worker_check_request(c->buffer, worker) != 0) {
verbose(VERB_ALGO,
"dnscrypt: worker check request: bad query.");
log_addr(VERB_CLIENT,"from",&repinfo->addr,
repinfo->addrlen);
log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
repinfo->client_addrlen);
comm_point_drop_reply(repinfo);
return 0;
}
if(!query_info_parse(&qinfo, c->buffer)) {
verbose(VERB_ALGO,
"dnscrypt: worker parse request: formerror.");
log_addr(VERB_CLIENT, "from", &repinfo->addr,
repinfo->addrlen);
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
comm_point_drop_reply(repinfo);
return 0;
}
@@ -1323,25 +1338,30 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
* sending src (client)/dst (local service) addresses over DNSTAP from incoming request handler
*/
if(worker->dtenv.log_client_query_messages) {
log_addr(VERB_ALGO, "request from client", &repinfo->addr, repinfo->addrlen);
log_addr(VERB_ALGO, "request from client", &repinfo->client_addr, repinfo->client_addrlen);
log_addr(VERB_ALGO, "to local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
dt_msg_send_client_query(&worker->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
dt_msg_send_client_query(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
}
#endif
acladdr = acl_addr_lookup(worker->daemon->acl, &repinfo->addr,
repinfo->addrlen);
acl = acl_get_control(acladdr);
if((ret=deny_refuse_all(c, acl, worker, repinfo, acladdr,
worker->env.cfg->ede)) != -1)
{
/* Check deny/refuse ACLs */
if(repinfo->is_proxied) {
if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
worker->env.cfg->ede, 1)) != -1) {
if(ret == 1)
goto send_reply;
return ret;
}
}
if((ret=deny_refuse_all(c, &acl, worker, repinfo, &acladdr,
worker->env.cfg->ede, 0)) != -1) {
if(ret == 1)
goto send_reply;
return ret;
}
if((ret=worker_check_request(c->buffer, worker)) != 0) {
verbose(VERB_ALGO, "worker check request: bad query.");
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
if(ret != -1) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
@@ -1353,20 +1373,24 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
worker->stats.num_queries++;
/* check if this query should be dropped based on source ip rate limiting */
if(!infra_ip_ratelimit_inc(worker->env.infra_cache, repinfo,
/* check if this query should be dropped based on source ip rate limiting
* NOTE: we always check the repinfo->client_address. IP ratelimiting is
* implicitly disabled for proxies. */
if(!infra_ip_ratelimit_inc(worker->env.infra_cache,
&repinfo->client_addr, repinfo->client_addrlen,
*worker->env.now,
worker->env.cfg->ip_ratelimit_backoff, c->buffer)) {
/* See if we are passed through with slip factor */
if(worker->env.cfg->ip_ratelimit_factor != 0 &&
ub_random_max(worker->env.rnd,
worker->env.cfg->ip_ratelimit_factor) == 0) {
worker->env.cfg->ip_ratelimit_factor) == 0) {
char addrbuf[128];
addr_to_str(&repinfo->addr, repinfo->addrlen,
addrbuf, sizeof(addrbuf));
verbose(VERB_QUERY, "ip_ratelimit allowed through for ip address %s because of slip in ip_ratelimit_factor",
addrbuf);
addr_to_str(&repinfo->client_addr,
repinfo->client_addrlen, addrbuf,
sizeof(addrbuf));
verbose(VERB_QUERY, "ip_ratelimit allowed through for "
"ip address %s because of slip in "
"ip_ratelimit_factor", addrbuf);
} else {
worker->stats.num_queries_ip_ratelimited++;
comm_point_drop_reply(repinfo);
@@ -1377,7 +1401,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
/* see if query is in the cache */
if(!query_info_parse(&qinfo, c->buffer)) {
verbose(VERB_ALGO, "worker parse request: formerror.");
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
memset(&qinfo, 0, sizeof(qinfo)); /* zero qinfo.qname */
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
comm_point_drop_reply(repinfo);
@@ -1391,13 +1416,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}
if(worker->env.cfg->log_queries) {
char ip[128];
addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip));
log_query_in(ip, qinfo.qname, qinfo.qtype, qinfo.qclass);
}
if(qinfo.qtype == LDNS_RR_TYPE_AXFR ||
qinfo.qtype == LDNS_RR_TYPE_IXFR) {
verbose(VERB_ALGO, "worker request: refused zone transfer.");
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
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),
@@ -1414,7 +1440,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
qinfo.qtype == LDNS_RR_TYPE_MAILB ||
(qinfo.qtype >= 128 && qinfo.qtype <= 248)) {
verbose(VERB_ALGO, "worker request: formerror for meta-type.");
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
comm_point_drop_reply(repinfo);
return 0;
@@ -1428,15 +1455,16 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}
goto send_reply;
}
if((ret=parse_edns_from_query_pkt(c->buffer, &edns, worker->env.cfg, c,
worker->scratchpad)) != 0) {
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)) != 0) {
struct edns_data reply_edns;
verbose(VERB_ALGO, "worker parse edns: formerror.");
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
memset(&reply_edns, 0, sizeof(reply_edns));
reply_edns.edns_present = 1;
reply_edns.udp_size = EDNS_ADVERTISED_SIZE;
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer), ret);
error_encode(c->buffer, ret, &qinfo,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns);
@@ -1445,22 +1473,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}
if(edns.edns_present) {
if(edns.edns_version != 0) {
edns.ext_rcode = (uint8_t)(EDNS_RCODE_BADVERS>>4);
edns.edns_version = EDNS_ADVERTISED_VERSION;
edns.udp_size = EDNS_ADVERTISED_SIZE;
edns.bits &= EDNS_DO;
edns.opt_list_in = NULL;
edns.opt_list_out = NULL;
edns.opt_list_inplace_cb_out = NULL;
edns.padding_block_size = 0;
verbose(VERB_ALGO, "query with bad edns version.");
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
error_encode(c->buffer, EDNS_RCODE_BADVERS&0xf, &qinfo,
log_addr( VERB_CLIENT, "from",&repinfo->remote_addr
, repinfo->remote_addrlen);
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), NULL);
if(sldns_buffer_capacity(c->buffer) >=
sldns_buffer_limit(c->buffer)+calc_edns_field_size(&edns))
attach_edns_record(c->buffer, &edns);
sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns);
regional_free_all(worker->scratchpad);
goto send_reply;
}
@@ -1468,21 +1489,62 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
worker->daemon->cfg->harden_short_bufsize) {
verbose(VERB_QUERY, "worker request: EDNS bufsize %d ignored",
(int)edns.udp_size);
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
edns.udp_size = NORMAL_UDP_SIZE;
}
}
/* "if, else if" sequence below deals with downstream DNS Cookies */
if (acl != acl_allow_cookie)
; /* pass; No cookie downstream processing whatsoever */
else if (edns.cookie_valid)
; /* pass; Valid cookie is good! */
else if (c->type != comm_udp)
; /* pass; Stateful transport */
else if (edns.cookie_present) {
/* Cookie present, but not valid: Cookie was bad! */
extended_error_encode(c->buffer,
LDNS_EXT_RCODE_BADCOOKIE, &qinfo,
*(uint16_t*)(void *)
sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2),
0, &edns);
regional_free_all(worker->scratchpad);
goto send_reply;
} else {
/* Cookie requered, but no cookie present on UDP */
verbose(VERB_ALGO, "worker request: "
"need cookie or stateful transport");
log_addr(VERB_ALGO, "from",&repinfo->remote_addr
, repinfo->remote_addrlen);
EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
worker->scratchpad, LDNS_EDE_OTHER,
"DNS Cookie needed for UDP replies");
error_encode(c->buffer,
(LDNS_RCODE_REFUSED|BIT_TC), &qinfo,
*(uint16_t*)(void *)
sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2),
&edns);
regional_free_all(worker->scratchpad);
goto send_reply;
}
if(edns.udp_size > worker->daemon->cfg->max_udp_size &&
c->type == comm_udp) {
verbose(VERB_QUERY,
"worker request: max UDP reply size modified"
" (%d to max-udp-size)", (int)edns.udp_size);
log_addr(VERB_CLIENT,"from",&repinfo->addr, repinfo->addrlen);
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
edns.udp_size = worker->daemon->cfg->max_udp_size;
}
if(edns.udp_size < LDNS_HEADER_SIZE) {
verbose(VERB_ALGO, "worker request: edns is too small.");
log_addr(VERB_CLIENT, "from", &repinfo->addr, repinfo->addrlen);
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_TC_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
@@ -1506,7 +1568,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}
if(LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) ==
LDNS_PACKET_NOTIFY) {
answer_notify(worker, &qinfo, &edns, c->buffer, repinfo);
answer_notify(worker, &qinfo, &edns, c->buffer,
&repinfo->client_addr, repinfo->client_addrlen);
regional_free_all(worker->scratchpad);
goto send_reply;
}
@@ -1582,7 +1645,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
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->addr, repinfo->addrlen);
&repinfo->client_addr, repinfo->client_addrlen);
goto send_reply;
}
@@ -1722,9 +1785,9 @@ lookup_cache:
if(verbosity >= VERB_CLIENT) {
if(c->type == comm_udp)
log_addr(VERB_CLIENT, "udp request from",
&repinfo->addr, repinfo->addrlen);
&repinfo->client_addr, repinfo->client_addrlen);
else log_addr(VERB_CLIENT, "tcp request from",
&repinfo->addr, repinfo->addrlen);
&repinfo->client_addr, repinfo->client_addrlen);
}
/* grab a work request structure for this new request */
@@ -1756,8 +1819,8 @@ send_reply_rc:
*/
if(worker->dtenv.log_client_response_messages) {
log_addr(VERB_ALGO, "from local addr", (void*)repinfo->c->socket->addr->ai_addr, repinfo->c->socket->addr->ai_addrlen);
log_addr(VERB_ALGO, "response to client", &repinfo->addr, repinfo->addrlen);
dt_msg_send_client_response(&worker->dtenv, &repinfo->addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
log_addr(VERB_ALGO, "response to client", &repinfo->client_addr, repinfo->client_addrlen);
dt_msg_send_client_response(&worker->dtenv, &repinfo->client_addr, (void*)repinfo->c->socket->addr->ai_addr, c->type, c->buffer);
}
#endif
if(worker->env.cfg->log_replies)
@@ -1769,10 +1832,12 @@ send_reply_rc:
/* log original qname, before the local alias was
* used to resolve that CNAME to something else */
qinfo.qname = qinfo.local_alias->rrset->rk.dname;
log_reply_info(NO_VERBOSE, &qinfo, &repinfo->addr, repinfo->addrlen,
log_reply_info(NO_VERBOSE, &qinfo,
&repinfo->client_addr, repinfo->client_addrlen,
tv, 1, c->buffer);
} else {
log_reply_info(NO_VERBOSE, &qinfo, &repinfo->addr, repinfo->addrlen,
log_reply_info(NO_VERBOSE, &qinfo,
&repinfo->client_addr, repinfo->client_addrlen,
tv, 1, c->buffer);
}
}
@@ -1903,6 +1968,9 @@ 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);
+4
View File
@@ -86,6 +86,10 @@ struct worker {
struct daemon* daemon;
/** thread id */
ub_thread_type thr_id;
#ifdef HAVE_GETTID
/** thread tid, the LWP id. */
pid_t thread_tid;
#endif
/** pipe, for commands for this worker */
struct tube* cmd;
/** the event base this worker works with */
+2 -2
View File
@@ -652,7 +652,7 @@ handle_event_moddone(struct module_qstate* qstate, int id)
if ( (!iq || !iq->started_no_cache_store) &&
qstate->return_msg && qstate->return_msg->rep &&
!dns_cache_store(qstate->env, &qstate->qinfo, qstate->return_msg->rep,
0, 0, 0, NULL, qstate->query_flags))
0, 0, 0, NULL, qstate->query_flags, qstate->qstarttime))
log_err("out of memory");
/* do nothing */
@@ -991,7 +991,7 @@ dns64_inform_super(struct module_qstate* qstate, int id,
/* Store the generated response in cache. */
if ( (!super_dq || !super_dq->started_no_cache_store) &&
!dns_cache_store(super->env, &super->qinfo, super->return_msg->rep,
0, 0, 0, NULL, super->query_flags))
0, 0, 0, NULL, super->query_flags, qstate->qstarttime))
log_err("out of memory");
}
+2 -2
View File
@@ -954,7 +954,7 @@ static int dtio_write_more(struct dt_io_thread* dtio)
* -1: continue, >0: number of bytes read into buffer */
static ssize_t receive_bytes(struct dt_io_thread* dtio, void* buf, size_t len) {
ssize_t r;
r = recv(dtio->fd, (void*)buf, len, 0);
r = recv(dtio->fd, (void*)buf, len, MSG_DONTWAIT);
if(r == -1) {
char* to = dtio->socket_path;
if(!to) to = dtio->ip_str;
@@ -1960,7 +1960,7 @@ static int dtio_open_output_tcp(struct dt_io_thread* dtio)
memset(&addr, 0, sizeof(addr));
addrlen = (socklen_t)sizeof(addr);
if(!extstrtoaddr(dtio->ip_str, &addr, &addrlen)) {
if(!extstrtoaddr(dtio->ip_str, &addr, &addrlen, UNBOUND_DNS_PORT)) {
log_err("could not parse IP '%s'", dtio->ip_str);
return 0;
}
+2 -2
View File
@@ -272,7 +272,7 @@ static int make_tcp_accept(char* ip)
memset(&addr, 0, sizeof(addr));
len = (socklen_t)sizeof(addr);
if(!extstrtoaddr(ip, &addr, &len)) {
if(!extstrtoaddr(ip, &addr, &len, UNBOUND_DNS_PORT)) {
log_err("could not parse IP '%s'", ip);
return -1;
}
@@ -617,7 +617,7 @@ static void log_data_frame(uint8_t* pkt, size_t len)
static ssize_t receive_bytes(struct tap_data* data, int fd, void* buf,
size_t len)
{
ssize_t ret = recv(fd, buf, len, 0);
ssize_t ret = recv(fd, buf, len, MSG_DONTWAIT);
if(ret == 0) {
/* closed */
if(verbosity) log_info("dnstap client stream closed from %s",
+163 -1
View File
@@ -1,3 +1,164 @@
21 October 2022: George
- Merge #767 from jonathangray: consistently use IPv4/IPv6 in
unbound.conf.5.
21 October 2022: Wouter
- Fix that cachedb does not store failures in the external cache.
18 October 2022: George
- Clarify the use of MAX_SENT_COUNT in the iterator code.
17 October 2022: Wouter
- testcode/dohclient sets log identity to its name.
14 October 2022: Wouter
- Merge #768 from fobser: Arithmetic on a pointer to void is a GNU
extension.
- In unit test, print python script name list correctly.
13 October 2022: Wouter
- Tag for 1.17.0 release. The code repository continues with 1.17.1.
11 October 2022: George
- Fix PROXYv2 header read for TCP connections when no proxied addresses
are provided.
7 October 2022: Wouter
- Tag for 1.17.0rc1 release.
7 October 2022: George
- Fix to stop possible loops in the tcp reuse code (write_wait list
and tcp_wait list). Based on analysis and patch from Prad Seniappan
and Karthik Umashankar.
- Fix unit test to properly test the reuse_write_wait_pop function.
6 October 2022: Wouter
- Fix to stop responses with TC flag from resulting in partial
responses. It retries to fetch the data elsewhere, or fails the
query and in depth fix removes the TC flag from the cached item.
- Fix proxy length debug output printout typecasts.
5 October 2022: Wouter
- Fix dnscrypt compile for proxy protocol code changes.
5 October 2022: George
- Use DEBUG_TDIR from environment in mini_tdir.sh for debugging.
- Fix string comparison in mini_tdir.sh.
- Make ede.tdir test more predictable by using static data.
- Fix checkconf test for dnscrypt and proxy port.
4 October 2022: George
- Merge #764: Leniency for target discovery when under load (for
NRDelegation changes).
4 October 2022: Wouter
- Fix static analysis report to remove dead code from the
rpz_callback_from_iterator_module function.
- Fix to clean up after the acl_interface unit test.
3 October 2022: George
- Merge #760: PROXYv2 downstream support. (New proxy-protocol-port
configuration option).
3 October 2022: Wouter
- Fix to remove erroneous TC flag from TCP upstream.
- Fix test tdir skip report printout.
- Fix windows compile, the identifier interface is defined in headers.
- Fix to close errno block in comm_point_tcp_handle_read outside of
ifdef.
26 September 2022: George
- Better output for skipped tdir tests.
21 September 2022: Wouter
- Patch for CVE-2022-3204 Non-Responsive Delegation Attack.
- This patch was released in 1.16.3, the code repository continues
with the previous features and fixes for 1.17.0.
- Fix doxygen warning in respip.h.
20 September 2022: George
- Convert tdir tests to use the new skip_test functionality.
- Remove unused testcode/mini_tpkg.sh file.
16 September 2022: George
- Merge #753: ACL per interface. (New interface-* configuration
options).
2 September 2022: Wouter
- Remove include that was there for debug purposes.
- Fix to check pthread_t size after pthread has been detected.
1 September 2022: Wouter
- Fix to update config tests to fix checking if nonblocking sockets
work on OpenBSD.
- Slow down log frequency of write wait failures.
- Fix to set out of file descriptor warning to operational verbosity.
- Fix to log a verbose message at operational notice level if a
thread is not responding, to stats requests. It is logged with
thread identifiers.
31 August 2022: Wouter
- Fix to avoid process wide fcntl calls mixed with nonblocking
operations after a blocked write.
- Patch from Vadim Fedorenko that adds MSG_DONTWAIT to receive
operations, so that instruction reordering does not cause mistakenly
blocking socket operations.
- Fix to wait for blocked write on UDP sockets, with a timeout if it
takes too long the packet is dropped.
- Fix for wait for udp send to stop when packet is successfully sent.
22 August 2022: Wouter
- Fix #741: systemd socket activation fails on IPv6.
12 August 2022: Wouter
- Fix to log accept error ENFILE and EMFILE errno, but slowly, once
per 10 seconds. Also log accept failures when no slow down is used.
5 August 2022: Wouter
- Fix #734 [FR] enable unbound-checkconf to detect more (basic)
errors.
4 August 2022: Wouter
- Fix ratelimit inconsistency, for ip-ratelimits the value is the
amount allowed, like for ratelimits.
2 August 2022: Wouter
- Fix edns subnet so that scope 0 answers only match sourcemask 0
queries for answers from cache if from a query with sourcemask 0.
- Fix unittest for edns subnet change.
- Merge #730 from luisdallos: Fix startup failure on Windows 8.1 due
to unsupported IPV6_USER_MTU socket option being set.
1 August 2022: Wouter
- Fix the novel ghost domain issues CVE-2022-30698 and CVE-2022-30699.
- Tests for ghost domain fixes.
- Tag for 1.16.2 release. The code repo continues with 1.16.3.
- Fix #728: alloc_reg_obtain() core dump. Stop double
alloc_reg_release when serviced_create fails.
19 July 2022: George
- Update documentation for 'outbound-msg-retry:'.
19 July 2022: Wouter
- Merge #718: Introduce infra-cache-max-rtt option to config max
retransmit timeout.
15 July 2022: Wouter
- Merge PR 714: Avoid treat normal hosts as unresponsive servers.
And fixup the lock code.
- iana portlist update.
12 July 2022: George
- For windows crosscompile, fix setting the IPV6_MTU socket option
equivalent (IPV6_USER_MTU); allows cross compiling with latest
cross-compiler versions.
12 July 2022: Wouter
- Fix dname count in sldns parse type descriptor for SVCB and HTTPS.
11 July 2022: Wouter
- Fix verbose EDE error printout.
4 July 2022: George
- Fix bug introduced in 'improve val_sigcrypt.c::algo_needs_missing for
one loop pass'.
@@ -5,7 +166,8 @@
outbound tcp sockets.
4 July 2022: Wouter
- Tag for 1.16.1rc1 release.
- Tag for 1.16.1rc1 release. This became 1.16.1 on 11 July 2022.
The code repo continues with version 1.16.2 under development.
3 July 2022: George
- Merge PR #671 from Petr Menšík: Disable ED25519 and ED448 in FIPS
+66 -6
View File
@@ -17,7 +17,7 @@ server:
# whitespace is not necessary, but looks cleaner.
# verbosity number, 0 is least verbose. 1 is default.
verbosity: 1
# verbosity: 1
# print statistics to the log (for every thread) every N seconds.
# Set to "" or 0 to disable. Default is disabled.
@@ -50,6 +50,7 @@ server:
# interface: 192.0.2.154
# interface: 192.0.2.154@5003
# interface: 2001:DB8::5
# interface: eth0@5003
# enable this feature to copy the source address of queries to reply.
# Socket options are not supported on all platforms. experimental.
@@ -168,7 +169,8 @@ server:
# perform connect for UDP sockets to mitigate ICMP side channel.
# udp-connect: yes
# The number of retries when a non-positive response is received.
# The number of retries, per upstream nameserver in a delegation, when
# a throwaway response (also timeouts) is received.
# outbound-msg-retry: 5
# msec for waiting for an unknown server to reply. Increase if you
@@ -202,6 +204,9 @@ server:
# minimum wait time for responses, increase if uplink is long. In msec.
# infra-cache-min-rtt: 50
# maximum wait time for responses. In msec.
# infra-cache-max-rtt: 120000
# enable to make server probe down hosts more frequently.
# infra-keep-probing: no
@@ -213,7 +218,8 @@ server:
# the maximum number of hosts that are cached (roundtrip, EDNS, lame).
# infra-cache-numhosts: 10000
# define a number of tags here, use with local-zone, access-control.
# define a number of tags here, use with local-zone, access-control,
# interface-*.
# repeat the define-tag statement to add additional tags.
# define-tag: "tag1 tag2 tag3"
@@ -269,9 +275,7 @@ server:
# allow_snoop (recursive and nonrecursive ok)
# deny_non_local (drop queries unless can be answered from local-data)
# refuse_non_local (like deny_non_local but polite error reply).
# access-control: 0.0.0.0/0 refuse
# access-control: 127.0.0.0/8 allow
# access-control: ::0/0 refuse
# access-control: ::1 allow
# access-control: ::ffff:127.0.0.1 allow
@@ -280,7 +284,7 @@ server:
# are tagged with one of these tags.
# access-control-tag: 192.0.2.0/24 "tag2 tag3"
# set action for particular tag for given access control element
# set action for particular tag for given access control element.
# if you have multiple tag values, the tag used to lookup the action
# is the first tag match between access-control-tag and local-zone-tag
# where "first" comes from the order of the define-tag values.
@@ -292,6 +296,58 @@ server:
# Set view for access control element
# access-control-view: 192.0.2.0/24 viewname
# Similar to 'access-control:' but for interfaces.
# Control which listening interfaces are allowed to accept (recursive)
# queries for this server.
# The specified interfaces should be the same as the ones specified in
# 'interface:' followed by the action.
# The actions are the same as 'access-control:' above.
# By default all the interfaces configured are refused.
# Note: any 'access-control*:' setting overrides all 'interface-*:'
# settings for targeted clients.
# 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: eth0@5003 allow
# Similar to 'access-control-tag:' but for interfaces.
# Tag interfaces with a list of tags (in "" with spaces between).
# Interfaces using these tags use localzones that are tagged with one
# of these tags.
# The specified interfaces should be the same as the ones specified in
# 'interface:' followed by the list of tags.
# Note: any 'access-control*:' setting overrides all 'interface-*:'
# settings for targeted clients.
# interface-tag: eth0@5003 "tag2 tag3"
# Similar to 'access-control-tag-action:' but for interfaces.
# Set action for particular tag for a given interface element.
# If you have multiple tag values, the tag used to lookup the action
# is the first tag match between interface-tag and local-zone-tag
# where "first" comes from the order of the define-tag values.
# The specified interfaces should be the same as the ones specified in
# 'interface:' followed by the tag and action.
# Note: any 'access-control*:' setting overrides all 'interface-*:'
# settings for targeted clients.
# interface-tag-action: eth0@5003 tag3 refuse
# Similar to 'access-control-tag-data:' but for interfaces.
# Set redirect data for a particular tag for an interface element.
# The specified interfaces should be the same as the ones specified in
# 'interface:' followed by the tag and the redirect data.
# Note: any 'access-control*:' setting overrides all 'interface-*:'
# settings for targeted clients.
# interface-tag-data: eth0@5003 tag2 "A 127.0.0.1"
# Similar to 'access-control-view:' but for interfaces.
# Set view for an interface element.
# The specified interfaces should be the same as the ones specified in
# 'interface:' followed by the view name.
# Note: any 'access-control*:' setting overrides all 'interface-*:'
# settings for targeted clients.
# interface-view: eth0@5003 viewname
# if given, a chroot(2) is done to the given directory.
# i.e. you can chroot to the working directory, for example,
# for extra security, but make sure all files are in that directory.
@@ -846,6 +902,10 @@ server:
# Disable TLS for DNS-over-HTTP downstream service.
# http-notls-downstream: no
# The interfaces that use these listed port numbers will support and
# expect PROXYv2. For UDP and TCP/TLS interfaces.
# proxy-protocol-port: portno for each of the port numbers.
# DNS64 prefix. Must be specified when DNS64 is use.
# Enable dns64 in module-config. Used to synthesize IPv6 from IPv4.
# dns64-prefix: 64:ff9b::0/96
+97 -11
View File
@@ -118,7 +118,7 @@ The number of threads to create to serve clients. Use 1 for no threading.
.B port: \fI<port number>
The port number, default 53, on which the server responds to queries.
.TP
.B interface: \fI<ip address[@port]>
.B interface: \fI<ip address or interface name [@port]>
Interface to use to connect to the network. This interface is listened to
for queries from clients, and answers to clients are given from it.
Can be given multiple times to work on several interfaces. If none are
@@ -129,7 +129,7 @@ A port number can be specified with @port (without spaces between
interface and port number), if not specified the default port (from
\fBport\fR) is used.
.TP
.B ip\-address: \fI<ip address[@port]>
.B ip\-address: \fI<ip address or interface name [@port]>
Same as interface: (for ease of compatibility with nsd.conf).
.TP
.B interface\-automatic: \fI<yes or no>
@@ -349,7 +349,7 @@ ip\-transparent option is also available.
The value of the Differentiated Services Codepoint (DSCP) in the
differentiated services field (DS) of the outgoing IP packet headers.
The field replaces the outdated IPv4 Type-Of-Service field and the
IPV6 traffic class field.
IPv6 traffic class field.
.TP
.B rrset\-cache\-size: \fI<number>
Number of bytes size of the RRset cache. Default is 4 megabytes.
@@ -395,6 +395,10 @@ Lower limit for dynamic retransmit timeout calculation in infrastructure
cache. Default is 50 milliseconds. Increase this value if using forwarders
needing more time to do recursive name resolution.
.TP
.B infra\-cache\-max\-rtt: \fI<msec>
Upper limit for dynamic retransmit timeout calculation in infrastructure
cache. Default is 2 minutes.
.TP
.B infra\-keep\-probing: \fI<yes or no>
If enabled the server keeps probing hosts that are down, in the one probe
at a time regime. Default is no. Hosts that are down, eg. they did
@@ -412,7 +416,7 @@ Enable or disable whether ip4 queries are answered or issued. Default is yes.
Enable or disable whether ip6 queries are answered or issued. Default is yes.
If disabled, queries are not answered on IPv6, and queries are not sent on
IPv6 to the internet nameservers. With this option you can disable the
ipv6 transport for sending DNS traffic, it does not impact the contents of
IPv6 transport for sending DNS traffic, it does not impact the contents of
the DNS traffic, which may have ip4 and ip6 addresses in it.
.TP
.B prefer\-ip4: \fI<yes or no>
@@ -503,6 +507,15 @@ Enable udp upstream even if do-udp is no. Default is no, and this does not
change anything. Useful for TLS service providers, that want no udp downstream
but use udp to fetch data upstream.
.TP
.B upstream-cookies: \fI<yes or no>
Enable EDNS cookies from upstream connections. DNS Cookies, as specified in
RFC 7873 and 9018 provide a limited-protection transaction security mechanism.
Once a cookie has been exchanged, the resolver and upstream are known to each
other and requests to the upstream can be exempted from rate limiting, for
example. Note that RFC9018 specifies that cookies should not be reused for
multiple outgoing interfaces, which is not supported at this time. The default
is no.
.TP
.B tls\-upstream: \fI<yes or no>
Enabled or disable whether the upstream queries use TLS only for transport.
Default is no. Useful in tunneling scenarios. The TLS contains plain DNS in
@@ -652,6 +665,17 @@ Ignored if the option is not available. Default is yes.
Disable use of TLS for the downstream DNS-over-HTTP connections. Useful for
local back end servers. Default is no.
.TP
.B proxy\-protocol\-port: \fI<portnr>
List port numbers as proxy\-protocol\-port, and when interfaces are defined,
eg. with the @port suffix, as this port number, they support and expect PROXYv2.
In this case the proxy address will only be used for the network communication
and initial ACL (check if the proxy itself is denied/refused by configuration).
The proxied address (if any) will then be used as the true client address and
will be used where applicable for logging, ACL, DNSTAP, RPZ and IP ratelimiting.
PROXYv2 is supported for UDP and TCP/TLS listening interfaces.
There is no support for PROXYv2 on a DoH or DNSCrypt listening interface.
Can list multiple, each on a new statement.
.TP
.B use\-systemd: \fI<yes or no>
Enable or disable systemd socket activation.
Default is no.
@@ -669,8 +693,8 @@ This option is experimental at this time.
.B access\-control: \fI<IP netblock> <action>
The netblock is given as an IP4 or IP6 address with /size appended for a
classless network block. The action can be \fIdeny\fR, \fIrefuse\fR,
\fIallow\fR, \fIallow_setrd\fR, \fIallow_snoop\fR, \fIdeny_non_local\fR or
\fIrefuse_non_local\fR.
\fIallow\fR, \fIallow_setrd\fR, \fIallow_snoop\fR, \fIallow_cookie\fR,
\fIdeny_non_local\fR or \fIrefuse_non_local\fR.
The most specific netblock match is used, if none match \fIdeny\fR is used.
The order of the access\-control statements therefore does not matter.
.IP
@@ -706,6 +730,14 @@ the cache contents (for malicious acts). However, nonrecursive queries can
also be a valuable debugging tool (when you want to examine the cache
contents). In that case use \fIallow_snoop\fR for your administration host.
.IP
When the \fBanswer\-cookie\fR option is enabled, the \fIallow_cookie\fR action
will allow access to UDP queries that contain a valid Server Cookie as
specified in RFC 7873 and RFC9018. UDP queries containing only a Client Cookie
and no Server Cookie, will receive a BADCOOKIE response including a Server
Cookie, allow clients to retry with that Server Cookie. The \fIallow_cookie\fR
will also accept requests over statefull transports, regardless of the precence
of a Cookie and regardless the \fBanswer\-cookie\fR setting.
.IP
By default only localhost is \fIallow\fRed, the rest is \fIrefuse\fRd.
The default is \fIrefuse\fRd, because that is protocol\-friendly. The DNS
protocol is not designed to handle dropped packets due to policy, and
@@ -737,6 +769,46 @@ Set redirect data for particular tag for given access control element.
.B access\-control\-view: \fI<IP netblock> <view name>
Set view for given access control element.
.TP
.B interface\-action: \fI<ip address or interface name [@port]> <action>
Similar to \fBaccess\-control:\fR but for interfaces.
.IP
The action is the same as the ones defined under \fBaccess\-control:\fR.
Interfaces are \fIrefuse\fRd by default.
By default only localhost (the IP netblock, not the loopback interface) is
\fIallow\fRed through the default \fBaccess\-control:\fR behavior.
.IP
Note that the interface needs to be already specified with \fBinterface:\fR
and that any \fBaccess-control*:\fR setting overrides all \fBinterface-*:\fR
settings for targeted clients.
.TP
.B interface\-tag: \fI<ip address or interface name [@port]> <"list of tags">
Similar to \fBaccess\-control-tag:\fR but for interfaces.
.IP
Note that the interface needs to be already specified with \fBinterface:\fR
and that any \fBaccess-control*:\fR setting overrides all \fBinterface-*:\fR
settings for targeted clients.
.TP
.B interface\-tag\-action: \fI<ip address or interface name [@port]> <tag> <action>
Similar to \fBaccess\-control-tag-action:\fR but for interfaces.
.IP
Note that the interface needs to be already specified with \fBinterface:\fR
and that any \fBaccess-control*:\fR setting overrides all \fBinterface-*:\fR
settings for targeted clients.
.TP
.B interface\-tag\-data: \fI<ip address or interface name [@port]> <tag> <"resource record string">
Similar to \fBaccess\-control-tag-data:\fR but for interfaces.
.IP
Note that the interface needs to be already specified with \fBinterface:\fR
and that any \fBaccess-control*:\fR setting overrides all \fBinterface-*:\fR
settings for targeted clients.
.TP
.B interface\-view: \fI<ip address or interface name [@port]> <view name>
Similar to \fBaccess\-control-view:\fR but for interfaces.
.IP
Note that the interface needs to be already specified with \fBinterface:\fR
and that any \fBaccess-control*:\fR setting overrides all \fBinterface-*:\fR
settings for targeted clients.
.TP
.B chroot: \fI<directory>
If chroot is enabled, you should pass the configfile (from the
commandline) as a full path from the original root. After the
@@ -1616,7 +1688,7 @@ This specifies the action data for \fIresponse-ip\fR with action being
to redirect as specified by "\fIresource record string\fR". "Resource
record string" is similar to that of \fIaccess-control-tag-action\fR,
but it must be of either AAAA, A or CNAME types.
If the IP-netblock is an IPv6/IPV4 prefix, the record
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 IP netblocks). If it is CNAME there must not be
more than one \fIresponse-ip-data\fR for the same IP-netblock.
@@ -1758,9 +1830,12 @@ set ip\-ratelimit to a suspicious rate to aggressively limit unusually high
traffic. Default is off.
.TP 5
.B outbound\-msg\-retry: \fI<number>
The number of retries Unbound will do in case of a non positive response is
received. If a forward nameserver is used, this is the number of retries per
forward nameserver in case of throwaway response.
The number of retries, per upstream nameserver in a delegation, that Unbound
will attempt in case a throwaway response is received.
No response (timeout) contributes to the retry counter.
If a forward/stub zone is used, this is the number of retries per nameserver in
the zone.
Default is 5.
.TP 5
.B fast\-server\-permil: \fI<number>
Specify how many times out of 1000 to pick from the set of fastest servers.
@@ -1777,6 +1852,15 @@ Set the number of servers that should be used for fast server selection. Only
use the fastest specified number of servers with the fast\-server\-permil
option, that turns this on or off. The default is to use the fastest 3 servers.
.TP 5
.B answer\-cookie: \fI<yes or no>
Enable to answer to requests containig DNS Cookies as specified in RFC7873 and
RFC9018. Default is no.
.TP 5
.B cookie\-secret: \fI<128 bit hex string>
Server's in an Anycast deployment need to be able to verify each other's
Server Cookies. For this they need to share the secret used to construct
and verify the Server Cookies.
Default is a 128 bits random secret generated at startup time.
.B edns\-client\-string: \fI<IP netblock> <string>
Include an EDNS0 option containing configured ascii string in queries with
destination address matching the configured IP netblock. This configuration
@@ -1816,9 +1900,11 @@ section for options. To setup the correct self\-signed certificates use the
The option is used to enable remote control, default is "no".
If turned off, the server does not listen for control commands.
.TP 5
.B control\-interface: \fI<ip address or path>
.B control\-interface: \fI<ip address or interface name 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 addresses
on that interface are used.
By default localhost (127.0.0.1 and ::1) is listened to.
Use 0.0.0.0 and ::0 to listen to all interfaces.
If you change this and permissions have been dropped, you must restart
+7 -2
View File
@@ -97,6 +97,7 @@ node_create(struct addrtree *tree, void *elem, addrlen_t scope,
tree->node_count++;
node->scope = scope;
node->ttl = ttl;
node->only_match_scope_zero = 0;
node->edge[0] = NULL;
node->edge[1] = NULL;
node->parent_edge = NULL;
@@ -155,6 +156,7 @@ clean_node(struct addrtree *tree, struct addrnode *node)
if (!node->elem) return;
tree->size_bytes -= tree->sizefunc(node->elem);
tree->delfunc(tree->env, node->elem);
node->only_match_scope_zero = 0;
node->elem = NULL;
}
@@ -358,7 +360,7 @@ issub(const addrkey_t *s1, addrlen_t l1,
void
addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
addrlen_t sourcemask, addrlen_t scope, void *elem, time_t ttl,
time_t now)
time_t now, int only_match_scope_zero)
{
struct addrnode *newnode, *node;
struct addredge *edge;
@@ -381,6 +383,7 @@ addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
/* update this node's scope and data */
clean_node(tree, node);
node->ttl = ttl;
node->only_match_scope_zero = only_match_scope_zero;
node->elem = elem;
node->scope = scope;
tree->size_bytes += tree->sizefunc(elem);
@@ -447,6 +450,7 @@ addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
newnode->elem = elem;
newnode->scope = scope;
newnode->ttl = ttl;
newnode->only_match_scope_zero = only_match_scope_zero;
}
tree->size_bytes += node_size(tree, newnode);
@@ -483,7 +487,8 @@ addrtree_find(struct addrtree *tree, const addrkey_t *addr,
/* Current node more specific then question. */
log_assert(depth <= sourcemask);
/* does this node have data? if yes, see if we have a match */
if (node->elem && node->ttl >= now) {
if (node->elem && node->ttl >= now &&
!(sourcemask != 0 && node->only_match_scope_zero)) {
/* saved at wrong depth */;
log_assert(node->scope >= depth);
if (depth == node->scope ||
+6 -1
View File
@@ -95,6 +95,10 @@ struct addrnode {
time_t ttl;
/** Number of significant bits in address. */
addrlen_t scope;
/** Only use the element for queries for subnet/0. Set if the query
* for /0 was answered with scope 0. For query /x answer scope 0,
* they can match anything and this is false. */
int only_match_scope_zero;
/** A node can have 0-2 edges, set to NULL for unused */
struct addredge *edge[2];
/** edge between this node and parent */
@@ -157,11 +161,12 @@ void addrtree_delete(struct addrtree *tree);
* @param scope: Number of significant bits in addr.
* @param elem: data to store in the tree.
* @param ttl: elem is valid up to this time, seconds.
* @param only_match_scope_zero: set for when query /0 has scope /0 answer.
* @param now: Current time in seconds.
*/
void addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
addrlen_t sourcemask, addrlen_t scope, void *elem, time_t ttl,
time_t now);
time_t now, int only_match_scope_zero);
/**
* Find a node containing an element in the tree.
+41 -2
View File
@@ -55,6 +55,7 @@
#include "util/config_file.h"
#include "util/data/msgreply.h"
#include "sldns/sbuffer.h"
#include "sldns/wire2str.h"
#include "iterator/iter_utils.h"
/** externally called */
@@ -331,6 +332,7 @@ update_cache(struct module_qstate *qstate, int id)
struct slabhash *subnet_msg_cache = sne->subnet_msg_cache;
struct ecs_data *edns = &sq->ecs_client_in;
size_t i;
int only_match_scope_zero;
/* We already calculated hash upon lookup (lookup_and_reply) if we were
* allowed to look in the ECS cache */
@@ -392,9 +394,12 @@ update_cache(struct module_qstate *qstate, int id)
reply_info_set_ttls(rep, *qstate->env->now);
rep->flags |= (BIT_RA | BIT_QR); /* fix flags to be sensible for */
rep->flags &= ~(BIT_AA | BIT_CD);/* a reply based on the cache */
if(edns->subnet_source_mask == 0 && edns->subnet_scope_mask == 0)
only_match_scope_zero = 1;
else only_match_scope_zero = 0;
addrtree_insert(tree, (addrkey_t*)edns->subnet_addr,
edns->subnet_source_mask, sq->max_scope, rep,
rep->ttl, *qstate->env->now);
rep->ttl, *qstate->env->now, only_match_scope_zero);
lock_rw_unlock(&lru_entry->lock);
if (need_to_insert) {
@@ -674,6 +679,24 @@ ecs_query_response(struct module_qstate* qstate, struct dns_msg* response,
return 1;
}
/** verbose print edns subnet option in pretty print */
static void
subnet_log_print(const char* s, struct edns_option* ecs_opt)
{
if(verbosity >= VERB_ALGO) {
char buf[256];
char* str = buf;
size_t str_len = sizeof(buf);
if(!ecs_opt) {
verbose(VERB_ALGO, "%s (null)", s);
return;
}
(void)sldns_wire2str_edns_subnet_print(&str, &str_len,
ecs_opt->opt_data, ecs_opt->opt_len);
verbose(VERB_ALGO, "%s %s", s, buf);
}
}
int
ecs_edns_back_parsed(struct module_qstate* qstate, int id,
void* ATTR_UNUSED(cbargs))
@@ -688,6 +711,7 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id,
qstate->env->cfg->client_subnet_opcode)) &&
parse_subnet_option(ecs_opt, &sq->ecs_server_in) &&
sq->subnet_sent && sq->ecs_server_in.subnet_validdata) {
subnet_log_print("answer has edns subnet", ecs_opt);
/* Only skip global cache store if we sent an ECS option
* and received one back. Answers from non-whitelisted
* servers will end up in global cache. Answers for
@@ -736,11 +760,12 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
qstate->ext_state[id] = module_finished;
return;
}
subnet_log_print("query has edns subnet", ecs_opt);
sq->subnet_downstream = 1;
}
else if(qstate->mesh_info->reply_list) {
subnet_option_from_ss(
&qstate->mesh_info->reply_list->query_reply.addr,
&qstate->mesh_info->reply_list->query_reply.client_addr,
&sq->ecs_client_in, qstate->env->cfg);
}
@@ -775,6 +800,13 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
subnet_ecs_opt_list_append(&sq->ecs_client_out,
&qstate->edns_opts_front_out, qstate,
qstate->region);
if(verbosity >= VERB_ALGO) {
subnet_log_print("reply has edns subnet",
edns_opt_list_find(
qstate->edns_opts_front_out,
qstate->env->cfg->
client_subnet_opcode));
}
return;
}
lock_rw_unlock(&sne->biglock);
@@ -823,6 +855,13 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
subnet_ecs_opt_list_append(&sq->ecs_client_out,
&qstate->edns_opts_front_out, qstate,
qstate->region);
if(verbosity >= VERB_ALGO) {
subnet_log_print("reply has edns subnet",
edns_opt_list_find(
qstate->edns_opts_front_out,
qstate->env->cfg->
client_subnet_opcode));
}
}
qstate->no_cache_store = sq->started_no_cache_store;
qstate->no_cache_lookup = sq->started_no_cache_lookup;
+1 -1
View File
@@ -456,7 +456,7 @@ ipsecmod_handle_query(struct module_qstate* qstate,
/* Store A/AAAA in cache. */
if(!dns_cache_store(qstate->env, &qstate->qinfo,
qstate->return_msg->rep, 0, qstate->prefetch_leeway,
0, qstate->region, qstate->query_flags)) {
0, qstate->region, qstate->query_flags, qstate->qstarttime)) {
log_err("ipsecmod: out of memory caching record");
}
qstate->ext_state[id] = module_finished;
+3
View File
@@ -78,6 +78,7 @@ struct delegpt* delegpt_copy(struct delegpt* dp, struct regional* region)
if(!delegpt_add_ns(copy, region, ns->name, ns->lame,
ns->tls_auth_name, ns->port))
return NULL;
copy->nslist->cache_lookup_count = ns->cache_lookup_count;
copy->nslist->resolved = ns->resolved;
copy->nslist->got4 = ns->got4;
copy->nslist->got6 = ns->got6;
@@ -121,6 +122,7 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
ns->namelen = len;
dp->nslist = ns;
ns->name = regional_alloc_init(region, name, ns->namelen);
ns->cache_lookup_count = 0;
ns->resolved = 0;
ns->got4 = 0;
ns->got6 = 0;
@@ -620,6 +622,7 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
}
ns->next = dp->nslist;
dp->nslist = ns;
ns->cache_lookup_count = 0;
ns->resolved = 0;
ns->got4 = 0;
ns->got6 = 0;
+2
View File
@@ -101,6 +101,8 @@ struct delegpt_ns {
uint8_t* name;
/** length of name */
size_t namelen;
/** number of cache lookups for the name */
int cache_lookup_count;
/**
* If the name has been resolved. false if not queried for yet.
* true if the A, AAAA queries have been generated.
+1 -1
View File
@@ -100,7 +100,7 @@ ah(struct delegpt* dp, const char* sv, const char* ip)
return 0;
}
if(!delegpt_add_ns_mlc(dp, dname, 0, NULL, UNBOUND_DNS_PORT) ||
!extstrtoaddr(ip, &addr, &addrlen) ||
!extstrtoaddr(ip, &addr, &addrlen, UNBOUND_DNS_PORT) ||
!delegpt_add_target_mlc(dp, dname, dname_len,
&addr, addrlen, 0, 0)) {
free(dname);
+5 -1
View File
@@ -113,7 +113,11 @@ response_type_from_server(int rdset,
if(!msg || !request)
return RESPONSE_TYPE_THROWAWAY;
/* If the TC flag is set, the response is incomplete. Too large to
* fit even in TCP or so. Discard it, it cannot be retrieved here. */
if((msg->rep->flags & BIT_TC))
return RESPONSE_TYPE_THROWAWAY;
/* If the message is NXDOMAIN, then it answers the question. */
if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN) {
/* make sure its not recursive when we don't want it to */
+5 -4
View File
@@ -70,8 +70,6 @@
/** time when nameserver glue is said to be 'recent' */
#define SUSPICION_RECENT_EXPIRY 86400
/** penalty to validation failed blacklisted IPs */
#define BLACKLIST_PENALTY (USEFUL_SERVER_TOP_TIMEOUT*4)
/** fillup fetch policy array */
static void
@@ -661,10 +659,10 @@ dns_copy_msg(struct dns_msg* from, struct regional* region)
void
iter_dns_store(struct module_env* env, struct query_info* msgqinf,
struct reply_info* msgrep, int is_referral, time_t leeway, int pside,
struct regional* region, uint16_t flags)
struct regional* region, uint16_t flags, time_t qstarttime)
{
if(!dns_cache_store(env, msgqinf, msgrep, is_referral, leeway,
pside, region, flags))
pside, region, flags, qstarttime))
log_err("out of memory: cannot store data in cache");
}
@@ -1211,6 +1209,9 @@ int iter_lookup_parent_glue_from_cache(struct module_env* env,
struct delegpt_ns* ns;
size_t num = delegpt_count_targets(dp);
for(ns = dp->nslist; ns; ns = ns->next) {
if(ns->cache_lookup_count > ITERATOR_NAME_CACHELOOKUP_MAX_PSIDE)
continue;
ns->cache_lookup_count++;
/* get cached parentside A */
akey = rrset_cache_lookup(env->rrset_cache, ns->name,
ns->namelen, LDNS_RR_TYPE_A, qinfo->qclass,
+11 -1
View File
@@ -62,6 +62,15 @@ struct ub_packed_rrset_key;
struct module_stack;
struct outside_network;
/* max number of lookups in the cache for target nameserver names.
* This stops, for large delegations, N*N lookups in the cache. */
#define ITERATOR_NAME_CACHELOOKUP_MAX 3
/* max number of lookups in the cache for parentside glue for nameserver names
* This stops, for larger delegations, N*N lookups in the cache.
* It is a little larger than the nonpside max, so it allows a couple extra
* lookups of parent side glue. */
#define ITERATOR_NAME_CACHELOOKUP_MAX_PSIDE 5
/**
* Process config options and set iterator module state.
* Sets default values if no config is found.
@@ -132,6 +141,7 @@ struct dns_msg* dns_copy_msg(struct dns_msg* from, struct regional* regional);
* can be prefetch-updates.
* @param region: to copy modified (cache is better) rrs back to.
* @param flags: with BIT_CD for dns64 AAAA translated queries.
* @param qstarttime: time of query start.
* return void, because we are not interested in alloc errors,
* the iterator and validator can operate on the results in their
* scratch space (the qstate.region) and are not dependent on the cache.
@@ -140,7 +150,7 @@ struct dns_msg* dns_copy_msg(struct dns_msg* from, struct regional* regional);
*/
void iter_dns_store(struct module_env* env, struct query_info* qinf,
struct reply_info* rep, int is_referral, time_t leeway, int pside,
struct regional* region, uint16_t flags);
struct regional* region, uint16_t flags, time_t qstarttime);
/**
* Select randomly with n/m probability.
+270 -38
View File
@@ -68,9 +68,14 @@
#include "sldns/str2wire.h"
#include "sldns/parseutil.h"
#include "sldns/sbuffer.h"
#include "daemon/worker.h"
/* in msec */
int UNKNOWN_SERVER_NICENESS = 376;
/* in msec */
int USEFUL_SERVER_TOP_TIMEOUT = 120000;
/* Equals USEFUL_SERVER_TOP_TIMEOUT*4 */
int BLACKLIST_PENALTY = (120000*4);
static void target_count_increase_nx(struct iter_qstate* iq, int num);
@@ -251,9 +256,9 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
log_err("out of memory adding missing");
}
delegpt_mark_neg(dpns, qstate->qinfo.qtype);
dpns->resolved = 1; /* mark as failed */
if((dpns->got4 == 2 || !ie->supports_ipv4) &&
(dpns->got6 == 2 || !ie->supports_ipv6)) {
dpns->resolved = 1; /* mark as failed */
target_count_increase_nx(super_iq, 1);
}
}
@@ -371,7 +376,7 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
err.security = sec_status_indeterminate;
verbose(VERB_ALGO, "store error response in message cache");
iter_dns_store(qstate->env, &qstate->qinfo, &err, 0, 0, 0, NULL,
qstate->query_flags);
qstate->query_flags, qstate->qstarttime);
}
return error_response(qstate, id, rcode);
}
@@ -592,15 +597,17 @@ errinf_reply(struct module_qstate* qstate, struct iter_qstate* iq)
{
if(qstate->env->cfg->val_log_level < 2 && !qstate->env->cfg->log_servfail)
return;
if((qstate->reply && qstate->reply->addrlen != 0) ||
(iq->fail_reply && iq->fail_reply->addrlen != 0)) {
if((qstate->reply && qstate->reply->remote_addrlen != 0) ||
(iq->fail_reply && iq->fail_reply->remote_addrlen != 0)) {
char from[256], frm[512];
if(qstate->reply && qstate->reply->addrlen != 0)
addr_to_str(&qstate->reply->addr, qstate->reply->addrlen,
from, sizeof(from));
if(qstate->reply && qstate->reply->remote_addrlen != 0)
addr_to_str(&qstate->reply->remote_addr,
qstate->reply->remote_addrlen, from,
sizeof(from));
else
addr_to_str(&iq->fail_reply->addr, iq->fail_reply->addrlen,
from, sizeof(from));
addr_to_str(&iq->fail_reply->remote_addr,
iq->fail_reply->remote_addrlen, from,
sizeof(from));
snprintf(frm, sizeof(frm), "from %s", from);
errinf(qstate, frm);
}
@@ -1214,6 +1221,15 @@ generate_dnskey_prefetch(struct module_qstate* qstate,
(qstate->query_flags&BIT_RD) && !(qstate->query_flags&BIT_CD)){
return;
}
/* we do not generate this prefetch when the query list is full,
* the query is fetched, if needed, when the validator wants it.
* At that time the validator waits for it, after spawning it.
* This means there is one state that uses cpu and a socket, the
* spawned while this one waits, and not several at the same time,
* if we had created the lookup here. And this helps to keep
* the total load down, but the query still succeeds to resolve. */
if(mesh_jostle_exceeded(qstate->env->mesh))
return;
/* if the DNSKEY is in the cache this lookup will stop quickly */
log_nametypeclass(VERB_ALGO, "schedule dnskey prefetch",
@@ -1485,7 +1501,8 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
iq->dp = dns_cache_find_delegation(qstate->env, delname,
delnamelen, iq->qchase.qtype, iq->qchase.qclass,
qstate->region, &iq->deleg_msg,
*qstate->env->now+qstate->prefetch_leeway);
*qstate->env->now+qstate->prefetch_leeway, 1,
dpname, dpnamelen);
else iq->dp = NULL;
/* If the cache has returned nothing, then we have a
@@ -1777,7 +1794,8 @@ generate_parentside_target_query(struct module_qstate* qstate,
subiq->dp = dns_cache_find_delegation(qstate->env,
name, namelen, qtype, qclass, subq->region,
&subiq->deleg_msg,
*qstate->env->now+subq->prefetch_leeway);
*qstate->env->now+subq->prefetch_leeway,
1, NULL, 0);
/* if no dp, then it's from root, refetch unneeded */
if(subiq->dp) {
subiq->dnssec_expected = iter_indicates_dnssec(
@@ -1905,6 +1923,14 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
return 0;
}
query_count++;
/* If the mesh query list is full, exit the loop here.
* This makes the routine spawn one query at a time,
* and this means there is no query state load
* increase, because the spawned state uses cpu and a
* socket while this state waits for that spawned
* state. Next time we can look up further targets */
if(mesh_jostle_exceeded(qstate->env->mesh))
break;
}
/* Send the A request. */
if(ie->supports_ipv4 &&
@@ -1919,6 +1945,9 @@ query_for_targets(struct module_qstate* qstate, struct iter_qstate* iq,
return 0;
}
query_count++;
/* If the mesh query list is full, exit the loop. */
if(mesh_jostle_exceeded(qstate->env->mesh))
break;
}
/* mark this target as in progress. */
@@ -2079,6 +2108,15 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
}
ns->done_pside6 = 1;
query_count++;
if(mesh_jostle_exceeded(qstate->env->mesh)) {
/* Wait for the lookup; do not spawn multiple
* lookups at a time. */
verbose(VERB_ALGO, "try parent-side glue lookup");
iq->num_target_queries += query_count;
target_count_increase(iq, query_count);
qstate->ext_state[id] = module_wait_subquery;
return 0;
}
}
if(ie->supports_ipv4 && !ns->done_pside4) {
/* Send the A request. */
@@ -2227,6 +2265,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
size_t qout_orig_len = 0;
int sq_check_ratelimit = 1;
int sq_was_ratelimited = 0;
int can_do_promisc = 0;
/* NOTE: a request will encounter this state for each target it
* needs to send a query to. That is, at least one per referral,
@@ -2238,7 +2277,6 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->num_current_queries, iq->sent_count);
/* Make sure that we haven't run away */
/* FIXME: is this check even necessary? */
if(iq->referral_count > MAX_REFERRAL_COUNT) {
verbose(VERB_QUERY, "request has exceeded the maximum "
"number of referrrals with %d", iq->referral_count);
@@ -2555,6 +2593,11 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
&& iq->num_target_queries == 0
&& (!iq->target_count || iq->target_count[TARGET_COUNT_NX]==0)
&& iq->sent_count < TARGET_FETCH_STOP) {
can_do_promisc = 1;
}
/* if the mesh query list is full, then do not waste cpu and sockets to
* fetch promiscuous targets. They can be looked up when needed. */
if(can_do_promisc && !mesh_jostle_exceeded(qstate->env->mesh)) {
tf_policy = ie->target_fetch_policy[iq->depth];
}
@@ -2726,6 +2769,37 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
return 0;
}
/* We have a target. We could have created promiscuous target
* queries but we are currently under pressure (mesh_jostle_exceeded).
* If we are configured to allow promiscuous target queries and haven't
* gone out to the network for a target query for this delegation, then
* it is possible to slip in a promiscuous one with a 1/10 chance. */
if(can_do_promisc && tf_policy == 0 && iq->depth == 0
&& iq->depth < ie->max_dependency_depth
&& ie->target_fetch_policy[iq->depth] != 0
&& iq->dp_target_count == 0
&& !ub_random_max(qstate->env->rnd, 10)) {
int extra = 0;
verbose(VERB_ALGO, "available target exists in cache but "
"attempt to get extra 1 target");
(void)query_for_targets(qstate, iq, ie, id, 1, &extra);
/* errors ignored, these targets are not strictly necessary for
* this result, we do not have to reply with SERVFAIL */
if(extra > 0) {
iq->num_target_queries += extra;
target_count_increase(iq, extra);
check_waiting_queries(iq, qstate, id);
/* undo qname minimise step because we'll get back here
* to do it again */
if(qout_orig && iq->minimise_count > 0) {
iq->minimise_count--;
iq->qinfo_out.qname = qout_orig;
iq->qinfo_out.qname_len = qout_orig_len;
}
return 0;
}
}
/* Do not check ratelimit for forwarding queries or if we already got a
* pass. */
sq_check_ratelimit = (!(iq->chase_flags & BIT_RD) && !iq->ratelimit_ok);
@@ -2833,6 +2907,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
iq->response, &iq->qinfo_out, iq->dp);
iq->chase_to_rd = 0;
/* remove TC flag, if this is erroneously set by TCP upstream */
iq->response->rep->flags &= ~BIT_TC;
if(type == RESPONSE_TYPE_REFERRAL && (iq->chase_flags&BIT_RD) &&
!iq->auth_zone_response) {
/* When forwarding (RD bit is set), we handle referrals
@@ -2856,8 +2932,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
* use dnssec-lame-bypass if it needs to query there.*/
if(qstate->reply) {
struct delegpt_addr* a = delegpt_find_addr(
iq->dp, &qstate->reply->addr,
qstate->reply->addrlen);
iq->dp, &qstate->reply->remote_addr,
qstate->reply->remote_addrlen);
if(a) a->dnsseclame = 1;
}
/* test the answer is from the zone we expected,
@@ -2943,7 +3019,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iq->qchase.qtype != iq->response->qinfo.qtype,
qstate->prefetch_leeway,
iq->dp&&iq->dp->has_parent_side_NS,
qstate->region, qstate->query_flags);
qstate->region, qstate->query_flags,
qstate->qstarttime);
/* close down outstanding requests to be discarded */
outbound_list_clear(&iq->outlist);
iq->num_current_queries = 0;
@@ -2952,9 +3029,9 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
(*qstate->env->detach_subs)(qstate);
iq->num_target_queries = 0;
if(qstate->reply)
sock_list_insert(&qstate->reply_origin,
&qstate->reply->addr, qstate->reply->addrlen,
qstate->region);
sock_list_insert(&qstate->reply_origin,
&qstate->reply->remote_addr,
qstate->reply->remote_addrlen, qstate->region);
if(iq->minimisation_state != DONOT_MINIMISE_STATE
&& !(iq->chase_flags & BIT_RD)) {
if(FLAGS_GET_RCODE(iq->response->rep->flags) !=
@@ -3032,7 +3109,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
/* Store the referral under the current query */
/* no prefetch-leeway, since its not the answer */
iter_dns_store(qstate->env, &iq->response->qinfo,
iq->response->rep, 1, 0, 0, NULL, 0);
iq->response->rep, 1, 0, 0, NULL, 0,
qstate->qstarttime);
if(iq->store_parent_NS)
iter_store_parentside_NS(qstate->env,
iq->response->rep);
@@ -3146,7 +3224,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iter_dns_store(qstate->env, &iq->response->qinfo,
iq->response->rep, 1, qstate->prefetch_leeway,
iq->dp&&iq->dp->has_parent_side_NS, NULL,
qstate->query_flags);
qstate->query_flags, qstate->qstarttime);
/* set the current request's qname to the new value. */
iq->qchase.qname = sname;
iq->qchase.qname_len = snamelen;
@@ -3208,9 +3286,9 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
(*qstate->env->detach_subs)(qstate);
iq->num_target_queries = 0;
if(qstate->reply)
sock_list_insert(&qstate->reply_origin,
&qstate->reply->addr, qstate->reply->addrlen,
qstate->region);
sock_list_insert(&qstate->reply_origin,
&qstate->reply->remote_addr,
qstate->reply->remote_addrlen, qstate->region);
verbose(VERB_ALGO, "cleared outbound list for query restart");
/* go to INIT_REQUEST_STATE for new qname. */
return next_state(iq, INIT_REQUEST_STATE);
@@ -3224,9 +3302,10 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
} else if(qstate->reply) {
/* need addr for lameness cache, but we may have
* gotten this from cache, so test to be sure */
if(!infra_set_lame(qstate->env->infra_cache,
&qstate->reply->addr, qstate->reply->addrlen,
iq->dp->name, iq->dp->namelen,
if(!infra_set_lame(qstate->env->infra_cache,
&qstate->reply->remote_addr,
qstate->reply->remote_addrlen,
iq->dp->name, iq->dp->namelen,
*qstate->env->now, dnsseclame, 0,
iq->qchase.qtype))
log_err("mark host lame: out of memory");
@@ -3243,8 +3322,9 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
* gotten this from cache, so test to be sure */
verbose(VERB_DETAIL, "mark as REC_LAME");
if(!infra_set_lame(qstate->env->infra_cache,
&qstate->reply->addr, qstate->reply->addrlen,
iq->dp->name, iq->dp->namelen,
&qstate->reply->remote_addr,
qstate->reply->remote_addrlen,
iq->dp->name, iq->dp->namelen,
*qstate->env->now, 0, 1, iq->qchase.qtype))
log_err("mark host lame: out of memory");
}
@@ -3485,12 +3565,13 @@ processTargetResponse(struct module_qstate* qstate, int id,
} else {
verbose(VERB_ALGO, "iterator TargetResponse failed");
delegpt_mark_neg(dpns, qstate->qinfo.qtype);
dpns->resolved = 1; /* fail the target */
if((dpns->got4 == 2 || !ie->supports_ipv4) &&
(dpns->got6 == 2 || !ie->supports_ipv6) &&
(dpns->got6 == 2 || !ie->supports_ipv6)) {
dpns->resolved = 1; /* fail the target */
/* do not count cached answers */
(qstate->reply_origin && qstate->reply_origin->len != 0)) {
target_count_increase_nx(foriq, 1);
if(qstate->reply_origin && qstate->reply_origin->len != 0) {
target_count_increase_nx(foriq, 1);
}
}
}
}
@@ -3752,7 +3833,8 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
iter_dns_store(qstate->env, &qstate->qinfo,
iq->response->rep, 0, qstate->prefetch_leeway,
iq->dp&&iq->dp->has_parent_side_NS,
qstate->region, qstate->query_flags);
qstate->region, qstate->query_flags,
qstate->qstarttime);
}
}
qstate->return_rcode = LDNS_RCODE_NOERROR;
@@ -3863,6 +3945,79 @@ process_request(struct module_qstate* qstate, struct iter_qstate* iq,
iter_handle(qstate, iq, ie, id);
}
/** find the bound addr in the list of interfaces */
static int
get_bound_ip_if(struct outside_network* outnet,
struct sockaddr_storage *bound_addr, socklen_t bound_addrlen,
struct port_if* pif_return)
{
int i = 0;
struct port_if* pif_list;
int pif_list_len;
/* Get the list of interfaces and check that that list isn't just the
* "any" address */
if(addr_is_ip6(bound_addr, bound_addrlen)) {
pif_list = outnet->ip6_ifs;
pif_list_len = outnet->num_ip6;
// @TODO fix IPv6
} else {
pif_list = outnet->ip4_ifs;
pif_list_len = outnet->num_ip4;
struct sockaddr_storage addr_any;
socklen_t addr_any_len = 0;
struct sockaddr_storage addr_new;
socklen_t addr_new_len = 0;
if (!ipstrtoaddr("0.0.0.0", 0, &addr_any, &addr_any_len)) {
/* this shouldn't fail */
return 0;
}
log_addr(VERB_DETAIL, "!!!!! outnet->ip4_ifs->addr", &outnet->ip4_ifs->addr, bound_addrlen);
log_addr(VERB_DETAIL, "!!!!! addr_any", &addr_any, addr_any_len);
/* if we let the kernel decide the IP, fill in
* the previously used */
if (pif_list_len == 1 &&
sockaddr_cmp_addr(&outnet->ip4_ifs->addr, outnet->ip4_ifs->addrlen,
&addr_any, addr_any_len) == 0) {
/* return the interface from the list, but substitute the
* previously used address */
memcpy(pif_return, outnet->ip4_ifs, sizeof(struct port_if));
memcpy(&pif_return->addr, &addr_new, addr_new_len);
pif_return->addrlen = addr_new_len;
log_addr(VERB_DETAIL, "!!!!! get_bound_ip_if: addr from"
" ip4_ifs == 0.0.0.0, new is:", &pif_return->addr, outnet->ip4_ifs->addrlen);
return 1;
}
}
if (pif_list_len == 0) {
return 0;
}
for (i = 0; i < pif_list_len; i++) {
struct port_if *iface = &pif_list[i];
if (iface->addrlen == bound_addrlen &&
memcmp(&iface->addr, bound_addr, bound_addrlen)) {
memcpy(pif_return, iface, sizeof(struct port_if));
return 1;
}
}
return 0;
}
/** process authoritative server reply */
static void
process_response(struct module_qstate* qstate, struct iter_qstate* iq,
@@ -3871,11 +4026,34 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
{
struct msg_parse* prs;
struct edns_data edns;
struct edns_option* cookie;
sldns_buffer* pkt;
verbose(VERB_ALGO, "process_response: new external response event");
iq->response = NULL;
iq->state = QUERY_RESP_STATE;
if (event == module_event_interface_not_available) {
log_err("!!!!! process_response:event == module_event_interface_not_available");
}
if (!qstate->reply) {
log_err("!!!!! !qstate->reply");
}
// @TODO set renewed cookie here with infra_set_server_cookie, then bail out
if(qstate->env->cfg->upstream_cookies && event == module_event_interface_not_available) {
struct edns_cookie cookie;
// @TODO make into renew cookie function
infra_get_cookie(qstate->env->infra_cache, &qstate->reply->remote_addr,
qstate->reply->remote_addrlen, iq->dp->name, iq->dp->namelen,
*qstate->env->now, &cookie, 1);
log_err("!!!!!! interface unavailbale, renewing cookie");
goto handle_it;
}
if(event == module_event_noreply || event == module_event_error) {
if(event == module_event_noreply && iq->timeout_count >= 3 &&
qstate->env->cfg->use_caps_bits_for_id &&
@@ -3896,8 +4074,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
}
goto handle_it;
}
if( (event != module_event_reply && event != module_event_capsfail)
|| !qstate->reply) {
if( (event != module_event_reply && event != module_event_capsfail
&& event != module_event_interface_not_available) || !qstate->reply) {
log_err("Bad event combined with response");
outbound_list_remove(&iq->outlist, outbound);
errinf(qstate, "module iterator received wrong internal event with a response message");
@@ -3930,7 +4108,61 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
goto handle_it;
}
/* Copy the edns options we may got from the back end */
/* handle the upstream response cookie if enabled */
if(qstate->env->cfg->upstream_cookies) {
if (edns.opt_list_in &&
(cookie = edns_list_get_option(edns.opt_list_in,
LDNS_EDNS_COOKIE))){
struct sockaddr_storage bound_addr;
socklen_t bound_addrlen = sizeof(struct sockaddr);
struct port_if pif;
struct port_if *pif_ptr = &pif;
/* Get the outgoing interface to store with the cookie */
if(event != module_event_interface_not_available &&
getsockname(qstate->reply->c->fd,
(struct sockaddr *) &bound_addr,
&bound_addrlen) != -1) {
log_addr(VERB_DETAIL, "!!!!! iterator:udp socket:", &bound_addr, bound_addrlen);
if (!(get_bound_ip_if(qstate->env->worker->back,
&bound_addr, bound_addrlen, pif_ptr))) {
pif.addrlen = 0;
}
log_addr(VERB_DETAIL, "!!!!! iterator:pif addr:", &pif.addr, pif.addrlen);
} else {
/* Set to zero so the cookie gets renewed */
pif.addrlen = 0;
}
/* verify this is a 'complete cookie' (client+server)
* (RFC9018) with the length and store the complete
* cookie in the infra_cache. Do nothing when the cookie
* is already known and update when the server cookie
* changed */
if (cookie->opt_len == 24 &&
infra_set_server_cookie(qstate->env->infra_cache,
&qstate->reply->remote_addr,
qstate->reply->remote_addrlen,
iq->dp->name, iq->dp->namelen, pif_ptr,
cookie) >= 0) {
// @TODO do something
} else {
log_info("upstream response server cookie is not "
"added to cache; dropping response");
goto handle_it;
}
} else {
//@TODO think about what we do if we did send a cookie
// but did not get one back? for now we log_err()
log_err("upstream has not responded with a cookie");
}
}
/* Copy the edns options we may have gotten from the back end */
if(edns.opt_list_in) {
qstate->edns_opts_back_in = edns_opt_copy_region(edns.opt_list_in,
qstate->region);
@@ -3971,8 +4203,8 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
if(!iq->response)
goto handle_it;
log_query_info(VERB_DETAIL, "response for", &qstate->qinfo);
log_name_addr(VERB_DETAIL, "reply from", iq->dp->name,
&qstate->reply->addr, qstate->reply->addrlen);
log_name_addr(VERB_DETAIL, "reply from", iq->dp->name,
&qstate->reply->remote_addr, qstate->reply->remote_addrlen);
if(verbosity >= VERB_ALGO)
log_dns_msg("incoming scrubbed packet:", &iq->response->qinfo,
iq->response->rep);
+10 -7
View File
@@ -67,7 +67,8 @@ struct rbtree_type;
#define MAX_RESTART_COUNT 11
/** max number of referrals. Makes sure resolver does not run away */
#define MAX_REFERRAL_COUNT 130
/** max number of queries-sent-out. Make sure large NS set does not loop */
/** max number of queries-sent-out. Make sure large NS set does not loop.
* Resets on query restarts (e.g., CNAMES) and referrals. */
#define MAX_SENT_COUNT 32
/** max number of queries for which to perform dnsseclameness detection,
* (rrsigs missing detection) after that, just pick up that response */
@@ -94,15 +95,17 @@ struct rbtree_type;
extern int UNKNOWN_SERVER_NICENESS;
/** maximum timeout before a host is deemed unsuitable, in msec.
* After host_ttl this will be timed out and the host will be tried again.
* Equals RTT_MAX_TIMEOUT
*/
#define USEFUL_SERVER_TOP_TIMEOUT 120000
* Equals RTT_MAX_TIMEOUT, and thus when RTT_MAX_TIMEOUT is overwritten by
* config infra_cache_max_rtt, it will be overwritten as well. */
extern int USEFUL_SERVER_TOP_TIMEOUT;
/** penalty to validation failed blacklisted IPs
* Equals USEFUL_SERVER_TOP_TIMEOUT*4, and thus when RTT_MAX_TIMEOUT is
* overwritten by config infra_cache_max_rtt, it will be overwritten as well. */
extern int BLACKLIST_PENALTY;
/** RTT band, within this amount from the best, servers are chosen randomly.
* Chosen so that the UNKNOWN_SERVER_NICENESS falls within the band of a
* fast server, this causes server exploration as a side benefit. msec. */
#define RTT_BAND 400
/** Start value for blacklisting a host, 2*USEFUL_SERVER_TOP_TIMEOUT in sec */
#define INFRA_BACKOFF_INITIAL 240
/**
* Global state for the iterator.
@@ -322,7 +325,7 @@ struct iter_qstate {
/** the number of times this query has been restarted. */
int query_restart_count;
/** the number of times this query as followed a referral. */
/** the number of times this query has followed a referral. */
int referral_count;
/** number of queries fired off */
+2 -2
View File
@@ -951,7 +951,7 @@ ub_ctx_set_fwd(struct ub_ctx* ctx, const char* addr)
lock_basic_unlock(&ctx->cfglock);
/* check syntax for addr */
if(!extstrtoaddr(addr, &storage, &stlen)) {
if(!extstrtoaddr(addr, &storage, &stlen, UNBOUND_DNS_PORT)) {
errno=EINVAL;
return UB_SYNTAX;
}
@@ -1031,7 +1031,7 @@ int ub_ctx_set_stub(struct ub_ctx* ctx, const char* zone, const char* addr,
if(addr) {
struct sockaddr_storage storage;
socklen_t stlen;
if(!extstrtoaddr(addr, &storage, &stlen)) {
if(!extstrtoaddr(addr, &storage, &stlen, UNBOUND_DNS_PORT)) {
errno=EINVAL;
return UB_SYNTAX;
}
+2
View File
@@ -604,6 +604,8 @@ setup_qinfo_edns(struct libworker* w, struct ctx_query* q,
edns->opt_list_out = NULL;
edns->opt_list_inplace_cb_out = NULL;
edns->padding_block_size = 0;
edns->cookie_present = 0;
edns->cookie_valid = 0;
if(sldns_buffer_capacity(w->back->udp_buff) < 65535)
edns->udp_size = (uint16_t)sldns_buffer_capacity(
w->back->udp_buff);
+5 -4
View File
@@ -609,9 +609,9 @@ struct mesh_reply {
struct comm_reply query_reply;
};
%rename(_addr) comm_reply::addr;
%rename(_addr) comm_reply::client_addr;
struct comm_reply {
struct sockaddr_storage addr;
struct sockaddr_storage client_addr;
};
%extend comm_reply {
@@ -1375,7 +1375,8 @@ int set_return_msg(struct module_qstate* qstate,
/* Functions which we will need to lookup delegations */
struct delegpt* dns_cache_find_delegation(struct module_env* env,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
struct regional* region, struct dns_msg** msg, uint32_t timenow);
struct regional* region, struct dns_msg** msg, uint32_t timenow,
int noexpiredabove, uint8_t* expiretop, size_t expiretoplen);
int iter_dp_is_useless(struct query_info* qinfo, uint16_t qflags,
struct delegpt* dp, int supports_ipv4, int supports_ipv6);
struct iter_hints_stub* hints_lookup_stub(struct iter_hints* hints,
@@ -1404,7 +1405,7 @@ struct delegpt* find_delegation(struct module_qstate* qstate, char *nm, size_t n
qinfo.qclass = LDNS_RR_CLASS_IN;
while(1) {
dp = dns_cache_find_delegation(qstate->env, (uint8_t*)nm, nmlen, qinfo.qtype, qinfo.qclass, region, &msg, timenow);
dp = dns_cache_find_delegation(qstate->env, (uint8_t*)nm, nmlen, qinfo.qtype, qinfo.qclass, region, &msg, timenow, 0, NULL, 0);
if(!dp)
return NULL;
if(iter_dp_is_useless(&qinfo, BIT_RD, dp,
+6 -5
View File
@@ -72,7 +72,8 @@ int storeQueryInCache(struct module_qstate* qstate, struct query_info* qinfo,
}
return dns_cache_store(qstate->env, qinfo, msgrep, is_referral,
qstate->prefetch_leeway, 0, NULL, qstate->query_flags);
qstate->prefetch_leeway, 0, NULL, qstate->query_flags,
qstate->qstarttime);
}
/* Invalidate the message associated with query_info stored in message cache */
@@ -171,14 +172,14 @@ int createResponse(struct module_qstate* qstate, sldns_buffer* pkt)
}
/* Convert reply->addr to string */
/* Convert reply->client_addr to string */
void reply_addr2str(struct comm_reply* reply, char* dest, int maxlen)
{
int af = (int)((struct sockaddr_in*) &(reply->addr))->sin_family;
void* sinaddr = &((struct sockaddr_in*) &(reply->addr))->sin_addr;
int af = (int)((struct sockaddr_in*) &(reply->client_addr))->sin_family;
void* sinaddr = &((struct sockaddr_in*) &(reply->client_addr))->sin_addr;
if(af == AF_INET6)
sinaddr = &((struct sockaddr_in6*)&(reply->addr))->sin6_addr;
sinaddr = &((struct sockaddr_in6*)&(reply->client_addr))->sin6_addr;
dest[0] = 0;
if (inet_ntop(af, sinaddr, dest, (socklen_t)maxlen) == 0)
return;
+5 -5
View File
@@ -1290,7 +1290,7 @@ respip_set_is_empty(const struct respip_set* set)
void
respip_inform_print(struct respip_action_info* respip_actinfo, uint8_t* qname,
uint16_t qtype, uint16_t qclass, struct local_rrset* local_alias,
struct comm_reply* repinfo)
struct sockaddr_storage* addr, socklen_t addrlen)
{
char srcip[128], respip[128], txt[512];
unsigned port;
@@ -1300,10 +1300,10 @@ respip_inform_print(struct respip_action_info* respip_actinfo, uint8_t* qname,
if(local_alias)
qname = local_alias->rrset->rk.dname;
port = (unsigned)((repinfo->addr.ss_family == AF_INET) ?
ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port) :
ntohs(((struct sockaddr_in6*)&repinfo->addr)->sin6_port));
addr_to_str(&repinfo->addr, repinfo->addrlen, srcip, sizeof(srcip));
port = (unsigned)((addr->ss_family == AF_INET) ?
ntohs(((struct sockaddr_in*)addr)->sin_port) :
ntohs(((struct sockaddr_in6*)addr)->sin6_port));
addr_to_str(addr, addrlen, srcip, sizeof(srcip));
addr_to_str(&respip_addr->addr, respip_addr->addrlen,
respip, sizeof(respip));
if(respip_actinfo->rpz_log) {
+4 -2
View File
@@ -251,11 +251,13 @@ int respip_set_is_empty(const struct respip_set* set);
* @param local_alias: set to a local alias if the query matches an alias in
* a local zone. In this case its owner name will be considered the actual
* query name.
* @param repinfo: reply info containing the client's source address and port.
* @param addr: the client's source address and port.
* @param addrlen: the client's source address length.
*/
void respip_inform_print(struct respip_action_info* respip_actinfo,
uint8_t* qname, uint16_t qtype, uint16_t qclass,
struct local_rrset* local_alias, struct comm_reply* repinfo);
struct local_rrset* local_alias, struct sockaddr_storage* addr,
socklen_t addrlen);
/**
* Find resp_addr in tree, create and add to tree if it does not exist.
+7 -4
View File
@@ -3699,7 +3699,7 @@ addr_matches_master(struct auth_master* master, struct sockaddr_storage* addr,
/* compare address (but not port number, that is the destination
* port of the master, the port number of the received notify is
* allowed to by any port on that master) */
if(extstrtoaddr(master->host, &a, &alen) &&
if(extstrtoaddr(master->host, &a, &alen, UNBOUND_DNS_PORT) &&
sockaddr_cmp_addr(addr, addrlen, &a, alen)==0) {
*fromhost = master;
return 1;
@@ -5381,7 +5381,7 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
struct edns_data edns;
sldns_buffer* buf = env->scratch_buffer;
if(!master) return 0;
if(extstrtoaddr(master->host, &addr, &addrlen)) {
if(extstrtoaddr(master->host, &addr, &addrlen, UNBOUND_DNS_PORT)) {
/* not needed, host is in IP addr format */
return 0;
}
@@ -5419,6 +5419,8 @@ xfr_transfer_lookup_host(struct auth_xfer* xfr, struct module_env* env)
edns.opt_list_out = NULL;
edns.opt_list_inplace_cb_out = NULL;
edns.padding_block_size = 0;
edns.cookie_present = 0;
edns.cookie_valid = 0;
if(sldns_buffer_capacity(buf) < 65535)
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
else edns.udp_size = 65535;
@@ -6572,7 +6574,7 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
struct edns_data edns;
sldns_buffer* buf = env->scratch_buffer;
if(!master) return 0;
if(extstrtoaddr(master->host, &addr, &addrlen)) {
if(extstrtoaddr(master->host, &addr, &addrlen, UNBOUND_DNS_PORT)) {
/* not needed, host is in IP addr format */
return 0;
}
@@ -6612,6 +6614,8 @@ xfr_probe_lookup_host(struct auth_xfer* xfr, struct module_env* env)
edns.opt_list_out = NULL;
edns.opt_list_inplace_cb_out = NULL;
edns.padding_block_size = 0;
edns.cookie_present = 0;
edns.cookie_valid = 0;
if(sldns_buffer_capacity(buf) < 65535)
edns.udp_size = (uint16_t)sldns_buffer_capacity(buf);
else edns.udp_size = 65535;
@@ -8189,7 +8193,6 @@ auth_zone_verify_zonemd_key_with_ds(struct auth_zone* z,
keystorage->rk.type = htons(LDNS_RR_TYPE_DNSKEY);
keystorage->rk.rrset_class = htons(z->dclass);
auth_zone_log(z->name, VERB_QUERY, "zonemd: verify zone DNSKEY with DS");
// @TODO add EDE here? we currently just pass NULL
sec = val_verify_DNSKEY_with_DS(env, ve, keystorage, ds, sigalg,
why_bogus, NULL, NULL);
regional_free_all(env->scratch);
+99 -15
View File
@@ -68,11 +68,16 @@
* in a prefetch situation to be updated (without becoming sticky).
* @param qrep: update rrsets here if cache is better
* @param region: for qrep allocs.
* @param qstarttime: time when delegations were looked up, this is perhaps
* earlier than the time in now. The time is used to determine if RRsets
* of type NS have expired, so that they can only be updated using
* lookups of delegation points that did not use them, since they had
* expired then.
*/
static void
store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
time_t leeway, int pside, struct reply_info* qrep,
struct regional* region)
struct regional* region, time_t qstarttime)
{
size_t i;
/* see if rrset already exists in cache, if not insert it. */
@@ -81,8 +86,8 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
rep->ref[i].id = rep->rrsets[i]->id;
/* update ref if it was in the cache */
switch(rrset_cache_update(env->rrset_cache, &rep->ref[i],
env->alloc, now + ((ntohs(rep->ref[i].key->rk.type)==
LDNS_RR_TYPE_NS && !pside)?0:leeway))) {
env->alloc, ((ntohs(rep->ref[i].key->rk.type)==
LDNS_RR_TYPE_NS && !pside)?qstarttime:now + leeway))) {
case 0: /* ref unchanged, item inserted */
break;
case 2: /* ref updated, cache is superior */
@@ -155,7 +160,8 @@ msg_del_servfail(struct module_env* env, struct query_info* qinfo,
void
dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
hashvalue_type hash, struct reply_info* rep, time_t leeway, int pside,
struct reply_info* qrep, uint32_t flags, struct regional* region)
struct reply_info* qrep, uint32_t flags, struct regional* region,
time_t qstarttime)
{
struct msgreply_entry* e;
time_t ttl = rep->ttl;
@@ -170,7 +176,8 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
/* there was a reply_info_sortref(rep) here but it seems to be
* unnecessary, because the cache gets locked per rrset. */
reply_info_set_ttls(rep, *env->now);
store_rrsets(env, rep, *env->now, leeway, pside, qrep, region);
store_rrsets(env, rep, *env->now, leeway, pside, qrep, region,
qstarttime);
if(ttl == 0 && !(flags & DNSCACHE_STORE_ZEROTTL)) {
/* we do not store the message, but we did store the RRs,
* which could be useful for delegation information */
@@ -194,10 +201,51 @@ dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
slabhash_insert(env->msg_cache, hash, &e->entry, rep, env->alloc);
}
/** see if an rrset is expired above the qname, return upper qname. */
static int
rrset_expired_above(struct module_env* env, uint8_t** qname, size_t* qnamelen,
uint16_t searchtype, uint16_t qclass, time_t now, uint8_t* expiretop,
size_t expiretoplen)
{
struct ub_packed_rrset_key *rrset;
uint8_t lablen;
while(*qnamelen > 0) {
/* look one label higher */
lablen = **qname;
*qname += lablen + 1;
*qnamelen -= lablen + 1;
if(*qnamelen <= 0)
break;
/* looks up with a time of 0, to see expired entries */
if((rrset = rrset_cache_lookup(env->rrset_cache, *qname,
*qnamelen, searchtype, qclass, 0, 0, 0))) {
struct packed_rrset_data* data =
(struct packed_rrset_data*)rrset->entry.data;
if(now > data->ttl) {
/* it is expired, this is not wanted */
lock_rw_unlock(&rrset->entry.lock);
log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass);
return 1;
}
/* it is not expired, continue looking */
lock_rw_unlock(&rrset->entry.lock);
}
/* do not look above the expiretop. */
if(expiretop && *qnamelen == expiretoplen &&
query_dname_compare(*qname, expiretop)==0)
break;
}
return 0;
}
/** find closest NS or DNAME and returns the rrset (locked) */
static struct ub_packed_rrset_key*
find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
uint16_t qclass, time_t now, uint16_t searchtype, int stripfront)
uint16_t qclass, time_t now, uint16_t searchtype, int stripfront,
int noexpiredabove, uint8_t* expiretop, size_t expiretoplen)
{
struct ub_packed_rrset_key *rrset;
uint8_t lablen;
@@ -212,8 +260,40 @@ 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)))
return rrset;
qnamelen, searchtype, qclass, 0, now, 0))) {
uint8_t* origqname = qname;
size_t origqnamelen = qnamelen;
if(!noexpiredabove)
return rrset;
/* if expiretop set, do not look above it, but
* qname is equal, so the just found result is also
* the nonexpired above part. */
if(expiretop && qnamelen == expiretoplen &&
query_dname_compare(qname, expiretop)==0)
return rrset;
/* check for expiry, but we have to let go of the rrset
* for the lock ordering */
lock_rw_unlock(&rrset->entry.lock);
/* the expired_above function always takes off one
* label (if qnamelen>0) and returns the final qname
* where it searched, so we can continue from there
* turning the O N*N search into O N. */
if(!rrset_expired_above(env, &qname, &qnamelen,
searchtype, qclass, now, expiretop,
expiretoplen)) {
/* we want to return rrset, but it may be
* gone from cache, if so, just loop like
* it was not in the cache in the first place.
*/
if((rrset = rrset_cache_lookup(env->
rrset_cache, origqname, origqnamelen,
searchtype, qclass, 0, now, 0))) {
return rrset;
}
}
log_nametypeclass(VERB_ALGO, "ignoring rrset because expired rrsets exist above it", origqname, searchtype, qclass);
continue;
}
/* snip off front label */
lablen = *qname;
@@ -324,6 +404,9 @@ cache_fill_missing(struct module_env* env, uint16_t qclass,
struct ub_packed_rrset_key* akey;
time_t now = *env->now;
for(ns = dp->nslist; ns; ns = ns->next) {
if(ns->cache_lookup_count > ITERATOR_NAME_CACHELOOKUP_MAX)
continue;
ns->cache_lookup_count++;
akey = rrset_cache_lookup(env->rrset_cache, ns->name,
ns->namelen, LDNS_RR_TYPE_A, qclass, 0, now, 0);
if(akey) {
@@ -462,7 +545,8 @@ dns_msg_ansadd(struct dns_msg* msg, struct regional* region,
struct delegpt*
dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
size_t qnamelen, uint16_t qtype, uint16_t qclass,
struct regional* region, struct dns_msg** msg, time_t now)
struct regional* region, struct dns_msg** msg, time_t now,
int noexpiredabove, uint8_t* expiretop, size_t expiretoplen)
{
/* try to find closest NS rrset */
struct ub_packed_rrset_key* nskey;
@@ -470,7 +554,7 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
struct delegpt* dp;
nskey = find_closest_of_type(env, qname, qnamelen, qclass, now,
LDNS_RR_TYPE_NS, 0);
LDNS_RR_TYPE_NS, 0, noexpiredabove, expiretop, expiretoplen);
if(!nskey) /* hope the caller has hints to prime or something */
return NULL;
nsdata = (struct packed_rrset_data*)nskey->entry.data;
@@ -840,7 +924,7 @@ dns_cache_lookup(struct module_env* env,
* consistent with the DNAME */
if(!no_partial &&
(rrset=find_closest_of_type(env, qname, qnamelen, qclass, now,
LDNS_RR_TYPE_DNAME, 1))) {
LDNS_RR_TYPE_DNAME, 1, 0, NULL, 0))) {
/* synthesize a DNAME+CNAME message based on this */
enum sec_status sec_status = sec_status_unchecked;
struct dns_msg* msg = synth_dname_msg(rrset, region, now, &k,
@@ -973,7 +1057,7 @@ dns_cache_lookup(struct module_env* env,
int
dns_cache_store(struct module_env* env, struct query_info* msgqinf,
struct reply_info* msgrep, int is_referral, time_t leeway, int pside,
struct regional* region, uint32_t flags)
struct regional* region, uint32_t flags, time_t qstarttime)
{
struct reply_info* rep = NULL;
/* alloc, malloc properly (not in region, like msg is) */
@@ -996,9 +1080,9 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
/*ignore ret: it was in the cache, ref updated */
/* no leeway for typeNS */
(void)rrset_cache_update(env->rrset_cache, &ref,
env->alloc, *env->now +
env->alloc,
((ntohs(ref.key->rk.type)==LDNS_RR_TYPE_NS
&& !pside) ? 0:leeway));
&& !pside) ? qstarttime:*env->now + leeway));
}
free(rep);
return 1;
@@ -1020,7 +1104,7 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
rep->flags &= ~(BIT_AA | BIT_CD);
h = query_info_hash(&qinf, (uint16_t)flags);
dns_cache_store_msg(env, &qinf, h, rep, leeway, pside, msgrep,
flags, region);
flags, region, qstarttime);
/* qname is used inside query_info_entrysetup, and set to
* NULL. If it has not been used, free it. free(0) is safe. */
free(qinf.qname);
+15 -3
View File
@@ -88,11 +88,13 @@ struct dns_msg {
* @param flags: flags with BIT_CD for AAAA queries in dns64 translation.
* The higher 16 bits are used internally to customize the cache policy.
* (See DNSCACHE_STORE_xxx flags).
* @param qstarttime: time when the query was started, and thus when the
* delegations were looked up.
* @return 0 on alloc error (out of memory).
*/
int dns_cache_store(struct module_env* env, struct query_info* qinf,
struct reply_info* rep, int is_referral, time_t leeway, int pside,
struct regional* region, uint32_t flags);
struct regional* region, uint32_t flags, time_t qstarttime);
/**
* Store message in the cache. Stores in message cache and rrset cache.
@@ -112,11 +114,14 @@ int dns_cache_store(struct module_env* env, struct query_info* qinf,
* can be updated to full TTL even in prefetch situations.
* @param qrep: message that can be altered with better rrs from cache.
* @param flags: customization flags for the cache policy.
* @param qstarttime: time when the query was started, and thus when the
* delegations were looked up.
* @param region: to allocate into for qmsg.
*/
void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
hashvalue_type hash, struct reply_info* rep, time_t leeway, int pside,
struct reply_info* qrep, uint32_t flags, struct regional* region);
struct reply_info* qrep, uint32_t flags, struct regional* region,
time_t qstarttime);
/**
* Find a delegation from the cache.
@@ -129,11 +134,18 @@ void dns_cache_store_msg(struct module_env* env, struct query_info* qinfo,
* @param msg: if not NULL, delegation message is returned here, synthesized
* from the cache.
* @param timenow: the time now, for checking if TTL on cache entries is OK.
* @param noexpiredabove: if set, no expired NS rrsets above the one found
* are tolerated. It only returns delegations where the delegations above
* it are valid.
* @param expiretop: if not NULL, name where check for expiry ends for
* noexpiredabove.
* @param expiretoplen: length of expiretop dname.
* @return new delegation or NULL on error or if not found in cache.
*/
struct delegpt* dns_cache_find_delegation(struct module_env* env,
uint8_t* qname, size_t qnamelen, uint16_t qtype, uint16_t qclass,
struct regional* region, struct dns_msg** msg, time_t timenow);
struct regional* region, struct dns_msg** msg, time_t timenow,
int noexpiredabove, uint8_t* expiretop, size_t expiretoplen);
/**
* generate dns_msg from cached message
+217 -28
View File
@@ -230,7 +230,7 @@ setup_domain_limits(struct infra_cache* infra, struct config_file* cfg)
}
struct infra_cache*
infra_create(struct config_file* cfg)
infra_create(struct config_file* cfg, struct ub_randstate* rnd)
{
struct infra_cache* infra = (struct infra_cache*)calloc(1,
sizeof(struct infra_cache));
@@ -270,6 +270,11 @@ infra_create(struct config_file* cfg)
infra_delete(infra);
return NULL;
}
if (!rnd) {
infra_delete(infra);
return NULL;
}
infra->random_state = rnd;
return infra;
}
@@ -299,7 +304,7 @@ infra_adjust(struct infra_cache* infra, struct config_file* cfg)
{
size_t maxmem;
if(!infra)
return infra_create(cfg);
return infra_create(cfg, ub_initstate(NULL));
infra->host_ttl = cfg->host_ttl;
infra->infra_keep_probing = cfg->infra_keep_probing;
infra_dp_ratelimit = cfg->ratelimit;
@@ -315,7 +320,7 @@ infra_adjust(struct infra_cache* infra, struct config_file* cfg)
!slabhash_is_size(infra->client_ip_rates, cfg->ip_ratelimit_size,
cfg->ip_ratelimit_slabs)) {
infra_delete(infra);
infra = infra_create(cfg);
infra = infra_create(cfg, ub_initstate(NULL));
} else {
/* reapply domain limits */
traverse_postorder(&infra->domain_limits, domain_limit_free,
@@ -378,17 +383,36 @@ infra_lookup_nottl(struct infra_cache* infra, struct sockaddr_storage* addr,
return slabhash_lookup(infra->hosts, k.entry.hash, &k, wr);
}
/* helper function to fill in random data into the client cookie*/
void infra_fill_client_cookie_random(struct infra_cache* infra,
uint8_t* data) {
int i;
for (i = 0; i < 8; i++) {
data[i] = ub_random_max(infra->random_state, 256);
}
}
/** init the data elements */
static void
data_entry_init(struct infra_cache* infra, struct lruhash_entry* e,
time_t timenow)
{
struct infra_data* data = (struct infra_data*)e->data;
struct infra_data* data;
uint8_t client_cookie_data[8] = {0,0,0,0,0,0,0,0};
infra_fill_client_cookie_random(infra, client_cookie_data);
data = (struct infra_data*)e->data;
data->ttl = timenow + infra->host_ttl;
rtt_init(&data->rtt);
data->edns_version = 0;
data->edns_lame_known = 0;
data->probedelay = 0;
/* set EDNS cookie to zero, as this also sets the starting state*/
memset(&data->cookie, 0, sizeof(struct edns_cookie));
data->cookie.pif.out = NULL;
memcpy(data->cookie.data.cookie, client_cookie_data, 8);
data->isdnsseclame = 0;
data->rec_lame = 0;
data->lame_type_A = 0;
@@ -459,7 +483,11 @@ infra_host(struct infra_cache* infra, struct sockaddr_storage* addr,
if(e) {
/* if its still there we have a writelock, init */
/* re-initialise */
/* do not touch lameness, it may be valid still */
// @TODO check if "do not touch lameness" is still true
/* do not touch lameness, it may be valid still.
* Also don't touch the cookie, as the cookie logic
* will be handled by the server. */
data_entry_init(infra, e, timenow);
wr = 1;
/* TOP_TIMEOUT remains on reuse */
@@ -685,6 +713,170 @@ infra_edns_update(struct infra_cache* infra, struct sockaddr_storage* addr,
return 1;
}
int
infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t* name, size_t namelen,
time_t timenow, struct edns_cookie* cookie, int renew)
{
struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
name, namelen, 1);
struct infra_data* data;
int needtoinsert = 0;
if(!e) {
if(!(e = new_entry(infra, addr, addrlen, name, namelen, timenow))) {
return 0;
}
needtoinsert = 1;
} else if(((struct infra_data*)e->data)->ttl < timenow) {
/* EDNS cookies have their own timeout logic controlled by the
* upstream, so we just copy the cookie from the old cache entry */
struct edns_cookie c = ((struct infra_data*)e->data)->cookie;
/* create new cookie if the cache TTL expired, keep the cookie */
data_entry_init(infra, e, timenow);
((struct infra_data*)e->data)->cookie = c;
}
data = (struct infra_data*) e->data;
/* renew cookie if the address that is stored isn't available */
if (renew == 1 || (data->cookie.pif.addrlen == 0 &&
data->cookie.state == SERVER_COOKIE_LEARNED)) {
infra_fill_client_cookie_random(infra, (uint8_t*) &data->cookie.data);
data->cookie.state = SERVER_COOKIE_UNKNOWN;
}
memcpy(cookie, &data->cookie, sizeof(struct edns_cookie));
if(needtoinsert) {
slabhash_insert(infra->hosts, e->hash, e, e->data, NULL);
} else {
lock_rw_unlock(&e->lock);
}
return 1;
}
int
infra_set_server_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t* name, size_t namelen, struct port_if *pif,
struct edns_option* cookie)
{
struct lruhash_entry* e = infra_lookup_nottl(infra, addr, addrlen,
name, namelen, 1);
struct infra_data* data;
/* cookie length verification should be checked and handled by caller */
assert(cookie->opt_len == 24);
/* the client cookie was set on the outgoing upstream, so the entry
* should exists here. This can be false if the cookie has fallen
* out of cache */
if (!(e)) {
/* No need to insert a new cookie/entry here, this will be
* done with an outgoing request */
return 0;
}
data = (struct infra_data*) e->data;
if (data->cookie.state == COOKIE_NOT_SUPPORTED) {
/* we known this upstream doesn't support cookies; the state
* remains unchanged */
lock_rw_unlock(&e->lock);
return 1;
} else if (data->cookie.state == SERVER_COOKIE_LEARNED) {
/* wrong client cookie; don't store the server cookie */
if (!(memcmp(data->cookie.data.cookie,
cookie->opt_data+4, 8))) {
/* the state of the cookie remains unchanged as we will
* drop this upstream response */
verbose(VERB_ALGO, "wrong client cookie from upstream"
" with previously seen cookie");
lock_rw_unlock(&e->lock);
return -1;
}
/* We set the local pif addrlen to 0 if the interface is not found
* so it must be unequal to the stored addrlen */
if (data->cookie.pif.addrlen != pif->addrlen &&
pif->addrlen == 0){
/* don't change the status, but change to cookie length
* so it gets renewed during the lookup (which is
* where all the cookie creation happens) */
data->cookie.pif.addrlen = 0;
lock_rw_unlock(&e->lock);
log_info("the interface to the upstream response server "
"that was bound to this EDNS cookie has changed;"
" renewing cookie");
return 0;
}
/* the server cookie has changed, but the client cookie has not
* so we update the server cookie */
if (memcmp(data->cookie.data.cookie+8,
cookie->opt_data+12, 16) != 0) {
memcpy(data->cookie.data.cookie, cookie->opt_data, 24);
/* the cookie state remains unchanged*/
verbose(VERB_ALGO, "update new server cookie from upstream");
lock_rw_unlock(&e->lock);
/* log_hex() uses the verbosity levels of verbose() */
log_hex("complete cookie: ", cookie->opt_data,
cookie->opt_len);
return 1;
}
/* both the complete cookies are identical, so the state
* remains unchanged */
verbose(VERB_ALGO, "correctly received indentical cookie from"
" upstream; don't update");
lock_rw_unlock(&e->lock);
/* log_hex() uses the verbosity levels of verbose() */
log_hex("complete cookie: ", cookie->opt_data,
cookie->opt_len);
return 1;
} else { /* cookie state == SERVER_COOKIE_UNKNOWN */
/* wrong client cookie; don't store the server cookie */
if (!(memcmp(data->cookie.data.cookie,
cookie->opt_data+4, 8))) {
/* the state of the cookie remains unchanged as we will
* drop this upstream response */
verbose(VERB_ALGO, "wrong client cookie from upstream");
lock_rw_unlock(&e->lock);
return -1;
}
/* store the server cookie */
memcpy(data->cookie.data.cookie, cookie->opt_data, 24);
data->cookie.state = SERVER_COOKIE_LEARNED;
/* store the inbound interface we receive this cookie on */
if (pif->addrlen > 0) {
memcpy(&data->cookie.pif,
pif, sizeof(struct port_if));
data->cookie.pif.addrlen = pif->addrlen;
}
verbose(VERB_QUERY, "storing received server cookie from upstream");
lock_rw_unlock(&e->lock);
/* log_hex() uses the verbosity levels of verbose() */
log_hex("complete cookie: ", cookie->opt_data,
cookie->opt_len);
return 1;
}
}
int
infra_get_lame_rtt(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
@@ -721,13 +913,13 @@ infra_get_lame_rtt(struct infra_cache* infra,
else *rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
}
}
/* expired entry */
if(timenow > host->ttl) {
/* expired entry */
/* see if this can be a re-probe of an unresponsive server */
/* minus 1000 because that is outside of the RTTBAND, so
* blacklisted servers stay blacklisted if this is chosen */
if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT ||
infra->infra_keep_probing) {
if(host->rtt.rto >= USEFUL_SERVER_TOP_TIMEOUT) {
lock_rw_unlock(&e->lock);
*rtt = USEFUL_SERVER_TOP_TIMEOUT-1000;
*lame = 0;
@@ -834,14 +1026,13 @@ static struct lruhash_entry* infra_find_ratedata(struct infra_cache* infra,
/** find data item in array for ip addresses */
static struct lruhash_entry* infra_find_ip_ratedata(struct infra_cache* infra,
struct comm_reply* repinfo, int wr)
struct sockaddr_storage* addr, socklen_t addrlen, int wr)
{
struct ip_rate_key key;
hashvalue_type h = hash_addr(&(repinfo->addr),
repinfo->addrlen, 0);
hashvalue_type h = hash_addr(addr, addrlen, 0);
memset(&key, 0, sizeof(key));
key.addr = repinfo->addr;
key.addrlen = repinfo->addrlen;
key.addr = *addr;
key.addrlen = addrlen;
key.entry.hash = h;
return slabhash_lookup(infra->client_ip_rates, h, &key, wr);
}
@@ -876,10 +1067,9 @@ static void infra_create_ratedata(struct infra_cache* infra,
/** create rate data item for ip address */
static void infra_ip_create_ratedata(struct infra_cache* infra,
struct comm_reply* repinfo, time_t timenow)
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow)
{
hashvalue_type h = hash_addr(&(repinfo->addr),
repinfo->addrlen, 0);
hashvalue_type h = hash_addr(addr, addrlen, 0);
struct ip_rate_key* k = (struct ip_rate_key*)calloc(1, sizeof(*k));
struct ip_rate_data* d = (struct ip_rate_data*)calloc(1, sizeof(*d));
if(!k || !d) {
@@ -887,8 +1077,8 @@ static void infra_ip_create_ratedata(struct infra_cache* infra,
free(d);
return; /* alloc failure */
}
k->addr = repinfo->addr;
k->addrlen = repinfo->addrlen;
k->addr = *addr;
k->addrlen = addrlen;
lock_rw_init(&k->entry.lock);
k->entry.hash = h;
k->entry.key = k;
@@ -985,8 +1175,8 @@ int infra_ratelimit_inc(struct infra_cache* infra, uint8_t* name,
sldns_wire2str_class_buf(qinfo->qclass, cs, sizeof(cs));
ip[0]=0;
if(replylist) {
addr_to_str((struct sockaddr_storage *)&replylist->addr,
replylist->addrlen, ip, sizeof(ip));
addr_to_str((struct sockaddr_storage *)&replylist->remote_addr,
replylist->remote_addrlen, ip, sizeof(ip));
verbose(VERB_OPS, "ratelimit exceeded %s %d query %s %s %s from %s", buf, lim, qnm, cs, ts, ip);
} else {
verbose(VERB_OPS, "ratelimit exceeded %s %d query %s %s %s", buf, lim, qnm, cs, ts);
@@ -1040,7 +1230,7 @@ int infra_ratelimit_exceeded(struct infra_cache* infra, uint8_t* name,
max = infra_rate_max(entry->data, timenow, backoff);
lock_rw_unlock(&entry->lock);
return (max >= lim);
return (max > lim);
}
size_t
@@ -1054,8 +1244,8 @@ infra_get_mem(struct infra_cache* infra)
}
int infra_ip_ratelimit_inc(struct infra_cache* infra,
struct comm_reply* repinfo, time_t timenow, int backoff,
struct sldns_buffer* buffer)
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow,
int backoff, struct sldns_buffer* buffer)
{
int max;
struct lruhash_entry* entry;
@@ -1065,7 +1255,7 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra,
return 1;
}
/* find or insert ratedata */
entry = infra_find_ip_ratedata(infra, repinfo, 1);
entry = infra_find_ip_ratedata(infra, addr, addrlen, 1);
if(entry) {
int premax = infra_rate_max(entry->data, timenow, backoff);
int* cur = infra_rate_give_second(entry->data, timenow);
@@ -1073,10 +1263,9 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra,
max = infra_rate_max(entry->data, timenow, backoff);
lock_rw_unlock(&entry->lock);
if(premax < infra_ip_ratelimit && max >= infra_ip_ratelimit) {
if(premax <= infra_ip_ratelimit && max > infra_ip_ratelimit) {
char client_ip[128], qnm[LDNS_MAX_DOMAINLEN+1+12+12];
addr_to_str((struct sockaddr_storage *)&repinfo->addr,
repinfo->addrlen, client_ip, sizeof(client_ip));
addr_to_str(addr, addrlen, client_ip, sizeof(client_ip));
qnm[0]=0;
if(sldns_buffer_limit(buffer)>LDNS_HEADER_SIZE &&
LDNS_QDCOUNT(sldns_buffer_begin(buffer))!=0) {
@@ -1101,6 +1290,6 @@ int infra_ip_ratelimit_inc(struct infra_cache* infra,
}
/* create */
infra_ip_create_ratedata(infra, repinfo, timenow);
infra_ip_create_ratedata(infra, addr, addrlen, timenow);
return 1;
}
+90 -4
View File
@@ -49,9 +49,51 @@
#include "util/rtt.h"
#include "util/netevent.h"
#include "util/data/msgreply.h"
#include "services/outside_network.h"
struct slabhash;
struct config_file;
/* COOKIE @TODO move this to correct spot */
/**
* The actual EDNS cookie data. Note that the cookie can be filled with the
* just 'client' section, or with the 'complete' cookie depending on the state
* governed by the edns_cookie_state.
* The commented struct provides insight on how the bytes in the struct are
* structured.
*/
struct edns_cookie_data {
uint8_t cookie[24];
/* struct {
uint8_t client[8];
uint8_t version;
uint8_t reserved[3];
uint32_t timestamp;
uint8_t hash[8];
} components; */
};
/**
* The different states the EDNS cookie can be in
*/
enum edns_cookie_state
{
SERVER_COOKIE_UNKNOWN = 0, /* server cookie unknown, client cookie known */
SERVER_COOKIE_LEARNED = 1, /* server (and client) cookie known */
COOKIE_NOT_SUPPORTED = 2, /* upstream does not supported EDNS/cookies */
};
/**
* Structure for an EDNS cookie (RFC9018), it's internal state, and the
* the outgoing address that we bind this cookie to for privacy (RFC9018)
*/
struct edns_cookie {
enum edns_cookie_state state;
struct edns_cookie_data data;
struct port_if pif;
};
/**
* Host information kept for every server, per zone.
*/
@@ -88,6 +130,9 @@ struct infra_data {
* and cause a timeout */
uint8_t edns_lame_known;
/* The EDNS cookie containing the cookie and the internal state */
struct edns_cookie cookie;
/** is the host lame (does not serve the zone authoritatively),
* or is the host dnssec lame (does not serve DNSSEC data) */
uint8_t isdnsseclame;
@@ -122,6 +167,8 @@ struct infra_cache {
rbtree_type domain_limits;
/** hash table with query rates per client ip: ip_rate_key, ip_rate_data */
struct slabhash* client_ip_rates;
/** random state used in new entries for creating EDNS cookies (RFC9018) */
struct ub_randstate* random_state;
};
/** ratelimit, unless overridden by domain_limits, 0 is off */
@@ -196,7 +243,7 @@ struct rate_data {
* @param cfg: config parameters or NULL for defaults.
* @return: new infra cache, or NULL.
*/
struct infra_cache* infra_create(struct config_file* cfg);
struct infra_cache* infra_create(struct config_file* cfg, struct ub_randstate* rnd);
/**
* Delete infra cache.
@@ -318,6 +365,44 @@ int infra_edns_update(struct infra_cache* infra,
struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* name, size_t namelen, int edns_version, time_t timenow);
/**
* Find and return the cookie from the infra cache data. Creates an entry in
* the cache if there isn't one.
* @param infra: infrastructure cache.
* @param addr: host address.
* @param addrlen: length of addr.
* @param name: name of zone
* @param namelen: length of name
* @param timenow: what time it is now.
* @param pif: the interface which contains the outgoing address that we bind to
* @param cookie: the cookie that is retrieved from cache on success.
* @return: 0 on error, cookie pointer remains unchanged then.
*/
int infra_get_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t* name, size_t namelen,
time_t timenow, struct edns_cookie* cookie, int renew); //@TODO fix/remove renew?
/**
* Find the cookie entry in the cache and update it with to make a 'complete cookie'
* (client+server) (RFC9018). This function asserts that the cookie param contains
* a complete cookie with a length of 24 bytes. If the cache entry isn't found
* a new one will be inserted.
* @param infra: infrastructure cache.
* @param addr: host address.
* @param addrlen: length of addr.
* @param name: name of zone
* @param namelen: length of name
* @param timenow: what time it is now.
* @param pif: the interface which contains the outgoing address that we bind to
* @param cookie: the EDNS cookie option we want to store.
* @return -1 if the wrong client cookie is found, 0 if the entry isn't found in
* the cache and a new one is inserted, 1 if the complete cookie is inserted
* or unchanged.
*/
int infra_set_server_cookie(struct infra_cache* infra, struct sockaddr_storage* addr,
socklen_t addrlen, uint8_t* name, size_t namelen, struct port_if *pif,
struct edns_option* cookie);
/**
* Get Lameness information and average RTT if host is in the cache.
* This information is to be used for server selection.
@@ -416,15 +501,16 @@ int infra_find_ratelimit(struct infra_cache* infra, uint8_t* name,
/** Update query ratelimit hash and decide
* whether or not a query should be dropped.
* @param infra: infra cache
* @param repinfo: information about client
* @param addr: client address
* @param addrlen: client address length
* @param timenow: what time it is now.
* @param backoff: if backoff is enabled.
* @param buffer: with query for logging.
* @return 1 if it could be incremented. 0 if the increment overshot the
* ratelimit and the query should be dropped. */
int infra_ip_ratelimit_inc(struct infra_cache* infra,
struct comm_reply* repinfo, time_t timenow, int backoff,
struct sldns_buffer* buffer);
struct sockaddr_storage* addr, socklen_t addrlen, time_t timenow,
int backoff, struct sldns_buffer* buffer);
/**
* Get memory used by the infra cache.
+102 -45
View File
@@ -124,12 +124,12 @@ verbose_print_addr(struct addrinfo *addr)
(void)strlcpy(buf, "(null)", sizeof(buf));
}
buf[sizeof(buf)-1] = 0;
verbose(VERB_ALGO, "creating %s%s socket %s %d",
verbose(VERB_ALGO, "creating %s%s socket %s %d",
addr->ai_socktype==SOCK_DGRAM?"udp":
addr->ai_socktype==SOCK_STREAM?"tcp":"otherproto",
addr->ai_family==AF_INET?"4":
addr->ai_family==AF_INET6?"6":
"_otherfam", buf,
"_otherfam", buf,
ntohs(((struct sockaddr_in*)addr->ai_addr)->sin_port));
}
}
@@ -140,7 +140,9 @@ verbose_print_unbound_socket(struct unbound_socket* ub_sock)
if(verbosity >= VERB_ALGO) {
log_info("listing of unbound_socket structure:");
verbose_print_addr(ub_sock->addr);
log_info("s is: %d, fam is: %s", ub_sock->s, ub_sock->fam == AF_INET?"AF_INET":"AF_INET6");
log_info("s is: %d, fam is: %s, acl: %s", ub_sock->s,
ub_sock->fam == AF_INET?"AF_INET":"AF_INET6",
ub_sock->acl?"yes":"no");
}
}
@@ -458,7 +460,14 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
int action;
# endif
# if defined(IPV6_V6ONLY)
if(v6only) {
if(v6only
# ifdef HAVE_SYSTEMD
/* Systemd wants to control if the socket is v6 only
* or both, with BindIPv6Only=default, ipv6-only or
* both in systemd.socket, so it is not set here. */
&& !got_fd_from_systemd
# endif
) {
int val=(v6only==2)?0:1;
if (setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(void*)&val, (socklen_t)sizeof(val)) < 0) {
@@ -490,6 +499,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
return -1;
}
# elif defined(IPV6_MTU)
# ifndef USE_WINSOCK
/*
* On Linux, to send no larger than 1280, the PMTUD is
* disabled by default for datagrams anyway, so we set
@@ -497,13 +507,29 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
*/
if (setsockopt(s, IPPROTO_IPV6, IPV6_MTU,
(void*)&mtu, (socklen_t)sizeof(mtu)) < 0) {
log_err("setsockopt(..., IPV6_MTU, ...) failed: %s",
log_err("setsockopt(..., IPV6_MTU, ...) failed: %s",
sock_strerror(errno));
sock_close(s);
*noproto = 0;
*inuse = 0;
return -1;
}
# elif defined(IPV6_USER_MTU)
/* As later versions of the mingw crosscompiler define
* IPV6_MTU, do the same for windows but use IPV6_USER_MTU
* instead which is writable; IPV6_MTU is readonly there. */
if (setsockopt(s, IPPROTO_IPV6, IPV6_USER_MTU,
(void*)&mtu, (socklen_t)sizeof(mtu)) < 0) {
if (WSAGetLastError() != WSAENOPROTOOPT) {
log_err("setsockopt(..., IPV6_USER_MTU, ...) failed: %s",
wsa_strerror(WSAGetLastError()));
sock_close(s);
*noproto = 0;
*inuse = 0;
return -1;
}
}
# endif /* USE_WINSOCK */
# endif /* IPv6 MTU */
# if defined(IPV6_MTU_DISCOVER) && defined(IP_PMTUDISC_DONT)
# if defined(IP_PMTUDISC_OMIT)
@@ -613,7 +639,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
&& !(errno == EADDRNOTAVAIL && verbosity < 4 && !listen)
#endif
) {
log_err_addr("can't bind socket", strerror(errno),
log_err_addr("1can't bind socket", strerror(errno),
(struct sockaddr_storage*)addr, addrlen);
}
#endif /* EADDRINUSE */
@@ -621,7 +647,7 @@ create_udp_sock(int family, int socktype, struct sockaddr* addr,
if(WSAGetLastError() != WSAEADDRINUSE &&
WSAGetLastError() != WSAEADDRNOTAVAIL &&
!(WSAGetLastError() == WSAEACCES && verbosity < 4 && !listen)) {
log_err_addr("can't bind socket",
log_err_addr("2can't bind socket",
wsa_strerror(WSAGetLastError()),
(struct sockaddr_storage*)addr, addrlen);
}
@@ -759,7 +785,14 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
(void)reuseport;
#endif /* defined(SO_REUSEPORT) */
#if defined(IPV6_V6ONLY)
if(addr->ai_family == AF_INET6 && v6only) {
if(addr->ai_family == AF_INET6 && v6only
# ifdef HAVE_SYSTEMD
/* Systemd wants to control if the socket is v6 only
* or both, with BindIPv6Only=default, ipv6-only or
* both in systemd.socket, so it is not set here. */
&& !got_fd_from_systemd
# endif
) {
if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
(void*)&on, (socklen_t)sizeof(on)) < 0) {
log_err("setsockopt(..., IPV6_V6ONLY, ...) failed: %s",
@@ -807,12 +840,12 @@ create_tcp_accept_sock(struct addrinfo *addr, int v6only, int* noproto,
if(addr->ai_family==AF_INET6 && errno==EINVAL)
*noproto = 1;
else {
log_err_addr("can't bind socket", strerror(errno),
log_err_addr("3can't bind socket", strerror(errno),
(struct sockaddr_storage*)addr->ai_addr,
addr->ai_addrlen);
}
#else
log_err_addr("can't bind socket",
log_err_addr("4can't bind socket",
wsa_strerror(WSAGetLastError()),
(struct sockaddr_storage*)addr->ai_addr,
addr->ai_addrlen);
@@ -1015,6 +1048,7 @@ make_sock(int stype, const char* ifname, const char* port,
ub_sock->addr = res;
ub_sock->s = s;
ub_sock->fam = hints->ai_family;
ub_sock->acl = NULL;
return s;
}
@@ -1059,11 +1093,13 @@ make_sock_port(int stype, const char* ifname, const char* port,
* @param list: list head. changed.
* @param s: fd.
* @param ftype: if fd is UDP.
* @param pp2_enabled: if PROXYv2 is enabled for this port.
* @param ub_sock: socket with address.
* @return false on failure. list in unchanged then.
*/
static int
port_insert(struct listen_port** list, int s, enum listen_type ftype, struct unbound_socket* ub_sock)
port_insert(struct listen_port** list, int s, enum listen_type ftype,
int pp2_enabled, struct unbound_socket* ub_sock)
{
struct listen_port* item = (struct listen_port*)malloc(
sizeof(struct listen_port));
@@ -1072,6 +1108,7 @@ port_insert(struct listen_port** list, int s, enum listen_type ftype, struct unb
item->next = *list;
item->fd = s;
item->ftype = ftype;
item->pp2_enabled = pp2_enabled;
item->socket = ub_sock;
*list = item;
return 1;
@@ -1167,6 +1204,7 @@ if_is_ssl(const char* ifname, const char* port, int ssl_port,
* @param ssl_port: ssl service port number
* @param tls_additional_port: list of additional ssl service port numbers.
* @param https_port: DoH service port number
* @param proxy_protocol_port: list of PROXYv2 port numbers.
* @param reuseport: try to set SO_REUSEPORT if nonNULL and true.
* set to false on exit if reuseport failed due to no kernel support.
* @param transparent: set IP_TRANSPARENT socket option.
@@ -1179,34 +1217,39 @@ if_is_ssl(const char* ifname, const char* port, int ssl_port,
* @return: returns false on error.
*/
static int
ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
struct addrinfo *hints, const char* port, struct listen_port** list,
size_t rcv, size_t snd, int ssl_port,
struct config_strlist* tls_additional_port, int https_port,
struct config_strlist* proxy_protocol_port,
int* reuseport, int transparent, int tcp_mss, int freebind,
int http2_nodelay, int use_systemd, int dnscrypt_port, int dscp)
{
int s, noip6=0;
int is_https = if_is_https(ifname, port, https_port);
int is_dnscrypt = if_is_dnscrypt(ifname, port, dnscrypt_port);
int is_pp2 = if_is_pp2(ifname, port, proxy_protocol_port);
int nodelay = is_https && http2_nodelay;
struct unbound_socket* ub_sock;
#ifdef USE_DNSCRYPT
int is_dnscrypt = ((strchr(ifname, '@') &&
atoi(strchr(ifname, '@')+1) == dnscrypt_port) ||
(!strchr(ifname, '@') && atoi(port) == dnscrypt_port));
#else
int is_dnscrypt = 0;
(void)dnscrypt_port;
#endif
if(!do_udp && !do_tcp)
return 0;
if(is_pp2) {
if(is_dnscrypt) {
fatal_exit("PROXYv2 and DNSCrypt combination not "
"supported!");
} else if(is_https) {
fatal_exit("PROXYv2 and DoH combination not "
"supported!");
}
}
if(do_auto) {
ub_sock = calloc(1, sizeof(struct unbound_socket));
if(!ub_sock)
return 0;
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
&noip6, rcv, snd, reuseport, transparent,
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) {
freeaddrinfo(ub_sock->addr);
@@ -1224,8 +1267,9 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
free(ub_sock);
return 0;
}
if(!port_insert(list, s,
is_dnscrypt?listen_type_udpancil_dnscrypt:listen_type_udpancil, ub_sock)) {
if(!port_insert(list, s, is_dnscrypt
?listen_type_udpancil_dnscrypt:listen_type_udpancil,
is_pp2, ub_sock)) {
sock_close(s);
freeaddrinfo(ub_sock->addr);
free(ub_sock);
@@ -1236,7 +1280,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if(!ub_sock)
return 0;
/* regular udp socket */
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
&noip6, rcv, snd, reuseport, transparent,
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock)) == -1) {
freeaddrinfo(ub_sock->addr);
@@ -1247,8 +1291,9 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
}
return 0;
}
if(!port_insert(list, s,
is_dnscrypt?listen_type_udp_dnscrypt:listen_type_udp, ub_sock)) {
if(!port_insert(list, s, is_dnscrypt
?listen_type_udp_dnscrypt:listen_type_udp,
is_pp2, ub_sock)) {
sock_close(s);
freeaddrinfo(ub_sock->addr);
free(ub_sock);
@@ -1270,7 +1315,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
port_type = listen_type_tcp_dnscrypt;
else
port_type = listen_type_tcp;
if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1,
if((s = make_sock_port(SOCK_STREAM, ifname, port, hints, 1,
&noip6, 0, 0, reuseport, transparent, tcp_mss, nodelay,
freebind, use_systemd, dscp, ub_sock)) == -1) {
freeaddrinfo(ub_sock->addr);
@@ -1283,7 +1328,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
}
if(is_ssl)
verbose(VERB_ALGO, "setup TCP for SSL service");
if(!port_insert(list, s, port_type, ub_sock)) {
if(!port_insert(list, s, port_type, is_pp2, ub_sock)) {
sock_close(s);
freeaddrinfo(ub_sock->addr);
free(ub_sock);
@@ -1372,14 +1417,16 @@ listen_create(struct comm_base* base, struct listen_port* ports,
if(ports->ftype == listen_type_udp ||
ports->ftype == listen_type_udp_dnscrypt) {
cp = comm_point_create_udp(base, ports->fd,
front->udp_buff, cb, cb_arg, ports->socket);
front->udp_buff, ports->pp2_enabled, cb,
cb_arg, ports->socket);
} else if(ports->ftype == listen_type_tcp ||
ports->ftype == listen_type_tcp_dnscrypt) {
cp = comm_point_create_tcp(base, ports->fd,
tcp_accept_count, tcp_idle_timeout,
harden_large_queries, 0, NULL,
tcp_conn_limit, bufsize, front->udp_buff,
ports->ftype, cb, cb_arg, ports->socket);
ports->ftype, ports->pp2_enabled, cb, cb_arg,
ports->socket);
} else if(ports->ftype == listen_type_ssl ||
ports->ftype == listen_type_http) {
cp = comm_point_create_tcp(base, ports->fd,
@@ -1387,7 +1434,8 @@ listen_create(struct comm_base* base, struct listen_port* ports,
harden_large_queries,
http_max_streams, http_endpoint,
tcp_conn_limit, bufsize, front->udp_buff,
ports->ftype, cb, cb_arg, ports->socket);
ports->ftype, ports->pp2_enabled, cb, cb_arg,
ports->socket);
if(ports->ftype == listen_type_http) {
if(!sslctx && !http_notls) {
log_warn("HTTPS port configured, but "
@@ -1413,7 +1461,8 @@ listen_create(struct comm_base* base, struct listen_port* ports,
} else if(ports->ftype == listen_type_udpancil ||
ports->ftype == listen_type_udpancil_dnscrypt) {
cp = comm_point_create_udp_ancil(base, ports->fd,
front->udp_buff, cb, cb_arg, ports->socket);
front->udp_buff, ports->pp2_enabled, cb,
cb_arg, ports->socket);
}
if(!cp) {
log_err("can't create commpoint");
@@ -1685,7 +1734,7 @@ int resolve_interface_names(char** ifs, int num_ifs,
#endif /* HAVE_GETIFADDRS */
}
struct listen_port*
struct listen_port*
listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
int* reuseport)
{
@@ -1748,7 +1797,9 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
&hints, portbuf, &list,
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, cfg->tls_additional_port,
cfg->https_port, reuseport, cfg->ip_transparent,
cfg->https_port,
cfg->proxy_protocol_port,
reuseport, cfg->ip_transparent,
cfg->tcp_mss, cfg->ip_freebind,
cfg->http_nodelay, cfg->use_systemd,
cfg->dnscrypt_port, cfg->ip_dscp)) {
@@ -1763,7 +1814,9 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
&hints, portbuf, &list,
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, cfg->tls_additional_port,
cfg->https_port, reuseport, cfg->ip_transparent,
cfg->https_port,
cfg->proxy_protocol_port,
reuseport, cfg->ip_transparent,
cfg->tcp_mss, cfg->ip_freebind,
cfg->http_nodelay, cfg->use_systemd,
cfg->dnscrypt_port, cfg->ip_dscp)) {
@@ -1776,12 +1829,13 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
}
if(do_ip6) {
hints.ai_family = AF_INET6;
if(!ports_create_if(do_auto?"::0":"::1",
do_auto, cfg->do_udp, do_tcp,
if(!ports_create_if(do_auto?"::0":"::1",
do_auto, cfg->do_udp, do_tcp,
&hints, portbuf, &list,
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, cfg->tls_additional_port,
cfg->https_port, reuseport, cfg->ip_transparent,
cfg->https_port, cfg->proxy_protocol_port,
reuseport, cfg->ip_transparent,
cfg->tcp_mss, cfg->ip_freebind,
cfg->http_nodelay, cfg->use_systemd,
cfg->dnscrypt_port, cfg->ip_dscp)) {
@@ -1791,12 +1845,13 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
}
if(do_ip4) {
hints.ai_family = AF_INET;
if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1",
do_auto, cfg->do_udp, do_tcp,
if(!ports_create_if(do_auto?"0.0.0.0":"127.0.0.1",
do_auto, cfg->do_udp, do_tcp,
&hints, portbuf, &list,
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, cfg->tls_additional_port,
cfg->https_port, reuseport, cfg->ip_transparent,
cfg->https_port, cfg->proxy_protocol_port,
reuseport, cfg->ip_transparent,
cfg->tcp_mss, cfg->ip_freebind,
cfg->http_nodelay, cfg->use_systemd,
cfg->dnscrypt_port, cfg->ip_dscp)) {
@@ -1810,10 +1865,11 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
continue;
hints.ai_family = AF_INET6;
if(!ports_create_if(ifs[i], 0, cfg->do_udp,
do_tcp, &hints, portbuf, &list,
do_tcp, &hints, portbuf, &list,
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, cfg->tls_additional_port,
cfg->https_port, reuseport, cfg->ip_transparent,
cfg->https_port, cfg->proxy_protocol_port,
reuseport, cfg->ip_transparent,
cfg->tcp_mss, cfg->ip_freebind,
cfg->http_nodelay, cfg->use_systemd,
cfg->dnscrypt_port, cfg->ip_dscp)) {
@@ -1825,10 +1881,11 @@ listening_ports_open(struct config_file* cfg, char** ifs, int num_ifs,
continue;
hints.ai_family = AF_INET;
if(!ports_create_if(ifs[i], 0, cfg->do_udp,
do_tcp, &hints, portbuf, &list,
do_tcp, &hints, portbuf, &list,
cfg->so_rcvbuf, cfg->so_sndbuf,
cfg->ssl_port, cfg->tls_additional_port,
cfg->https_port, reuseport, cfg->ip_transparent,
cfg->https_port, cfg->proxy_protocol_port,
reuseport, cfg->ip_transparent,
cfg->tcp_mss, cfg->ip_freebind,
cfg->http_nodelay, cfg->use_systemd,
cfg->dnscrypt_port, cfg->ip_dscp)) {
+10 -4
View File
@@ -43,6 +43,7 @@
#define LISTEN_DNSPORT_H
#include "util/netevent.h"
#include "daemon/acl_list.h"
#ifdef HAVE_NGHTTP2_NGHTTP2_H
#include <nghttp2/nghttp2.h>
#endif
@@ -107,11 +108,13 @@ enum listen_type {
*/
struct unbound_socket {
/** socket-address structure */
struct addrinfo * addr;
struct addrinfo* addr;
/** socket descriptor returned by socket() syscall */
int s;
int s;
/** address family (AF_INET/IF_INET6) */
int fam;
int fam;
/** ACL on the socket (listening interface) */
struct acl_addr* acl;
};
/**
@@ -125,7 +128,10 @@ struct listen_port {
int fd;
/** type of file descriptor, udp or tcp */
enum listen_type ftype;
/** fill in unbpound_socket structure for every opened socket at Unbound startup */
/** if the port should support PROXYv2 */
int pp2_enabled;
/** fill in unbound_socket structure for every opened socket at
* Unbound startup */
struct unbound_socket* socket;
};
+7 -5
View File
@@ -1744,13 +1744,13 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
/** print log information for an inform zone query */
static void
lz_inform_print(struct local_zone* z, struct query_info* qinfo,
struct comm_reply* repinfo)
struct sockaddr_storage* addr, socklen_t addrlen)
{
char ip[128], txt[512];
char zname[LDNS_MAX_DOMAINLEN+1];
uint16_t port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
uint16_t port = ntohs(((struct sockaddr_in*)addr)->sin_port);
dname_str(z->name, zname);
addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
addr_to_str(addr, addrlen, ip, sizeof(ip));
snprintf(txt, sizeof(txt), "%s %s %s@%u", zname, local_zone_type2str(z->type), ip,
(unsigned)port);
log_nametypeclass(NO_VERBOSE, txt, qinfo->qname, qinfo->qtype, qinfo->qclass);
@@ -1765,7 +1765,8 @@ lz_type(uint8_t *taglist, size_t taglen, uint8_t *taglist2, size_t taglen2,
struct local_zone_override* lzo;
if(repinfo && override_tree) {
lzo = (struct local_zone_override*)addr_tree_lookup(
override_tree, &repinfo->addr, repinfo->addrlen);
override_tree, &repinfo->client_addr,
repinfo->client_addrlen);
if(lzo && lzo->type) {
verbose(VERB_ALGO, "local zone override to type %s",
local_zone_type2str(lzo->type));
@@ -1888,7 +1889,8 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
lzt == local_zone_inform_deny ||
lzt == local_zone_inform_redirect)
&& repinfo)
lz_inform_print(z, qinfo, repinfo);
lz_inform_print(z, qinfo, &repinfo->client_addr,
repinfo->client_addrlen);
if(lzt != local_zone_always_refuse
&& lzt != local_zone_always_transparent
+18 -5
View File
@@ -806,7 +806,7 @@ static void mesh_schedule_prefetch_subnet(struct mesh_area* mesh,
/* Fake the ECS data from the client's IP */
struct ecs_data ecs;
memset(&ecs, 0, sizeof(ecs));
subnet_option_from_ss(&rep->addr, &ecs, mesh->env->cfg);
subnet_option_from_ss(&rep->client_addr, &ecs, mesh->env->cfg);
if(ecs.subnet_validdata == 0) {
log_err("prefetch_subnet subnet_option_from_ss: invalid data");
return;
@@ -886,6 +886,8 @@ void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
event = module_event_noreply;
if(what == NETEVENT_CAPSFAIL)
event = module_event_capsfail;
if(what == NETEVENT_BOUND_INTERFACE_NOT_AVAILABLE)
event = module_event_interface_not_available;
}
mesh_run(mesh, e->qstate->mesh_info, event, e);
}
@@ -954,6 +956,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.qstarttime = *env->now;
/* init modules */
for(i=0; i<env->mesh->mods.num; i++) {
@@ -1487,8 +1490,9 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
}
/* Log reply sent */
if(m->s.env->cfg->log_replies) {
log_reply_info(NO_VERBOSE, &m->s.qinfo, &r->query_reply.addr,
r->query_reply.addrlen, duration, 0, r_buffer);
log_reply_info(NO_VERBOSE, &m->s.qinfo,
&r->query_reply.client_addr,
r->query_reply.client_addrlen, duration, 0, r_buffer);
}
}
@@ -1529,7 +1533,8 @@ void mesh_query_done(struct mesh_state* mstate)
respip_inform_print(mstate->s.respip_action_info,
r->qname, mstate->s.qinfo.qtype,
mstate->s.qinfo.qclass, r->local_alias,
&r->query_reply);
&r->query_reply.client_addr,
r->query_reply.client_addrlen);
if(mstate->s.env->cfg->stat_extended &&
mstate->s.respip_action_info->rpz_used) {
if(mstate->s.respip_action_info->rpz_disabled)
@@ -2179,7 +2184,8 @@ mesh_serve_expired_callback(void* arg)
if(actinfo.addrinfo) {
respip_inform_print(&actinfo, r->qname,
qstate->qinfo.qtype, qstate->qinfo.qclass,
r->local_alias, &r->query_reply);
r->local_alias, &r->query_reply.client_addr,
r->query_reply.client_addrlen);
if(qstate->env->cfg->stat_extended && actinfo.rpz_used) {
if(actinfo.rpz_disabled)
@@ -2239,3 +2245,10 @@ mesh_serve_expired_callback(void* arg)
mesh_do_callback(mstate, LDNS_RCODE_NOERROR, msg->rep, c, &tv);
}
}
int mesh_jostle_exceeded(struct mesh_area* mesh)
{
if(mesh->all.count < mesh->max_reply_states)
return 0;
return 1;
}
+11
View File
@@ -685,4 +685,15 @@ struct dns_msg*
mesh_serve_expired_lookup(struct module_qstate* qstate,
struct query_info* lookup_qinfo);
/**
* See if the mesh has space for more queries. You can allocate queries
* anyway, but this checks for the allocated space.
* @param mesh: mesh area.
* @return true if the query list is full.
* It checks the number of all queries, not just number of reply states,
* that have a client address. So that spawned queries count too,
* that were created by the iterator, or other modules.
*/
int mesh_jostle_exceeded(struct mesh_area* mesh);
#endif /* SERVICES_MESH_H */
+174 -82
View File
@@ -86,10 +86,6 @@ static void serviced_tcp_initiate(struct serviced_query* sq, sldns_buffer* buff)
static int randomize_and_send_udp(struct pending* pend, sldns_buffer* packet,
int timeout);
/** remove waiting tcp from the outnet waiting list */
static void waiting_list_remove(struct outside_network* outnet,
struct waiting_tcp* w);
/** select a DNS ID for a TCP stream */
static uint16_t tcp_select_id(struct outside_network* outnet,
struct reuse_tcp* reuse);
@@ -372,7 +368,8 @@ log_reuse_tcp(enum verbosity_value v, const char* msg, struct reuse_tcp* reuse)
}
/** pop the first element from the writewait list */
static struct waiting_tcp* reuse_write_wait_pop(struct reuse_tcp* reuse)
struct waiting_tcp*
reuse_write_wait_pop(struct reuse_tcp* reuse)
{
struct waiting_tcp* w = reuse->write_wait_first;
if(!w)
@@ -390,8 +387,8 @@ static struct waiting_tcp* reuse_write_wait_pop(struct reuse_tcp* reuse)
}
/** remove the element from the writewait list */
static void reuse_write_wait_remove(struct reuse_tcp* reuse,
struct waiting_tcp* w)
void
reuse_write_wait_remove(struct reuse_tcp* reuse, struct waiting_tcp* w)
{
log_assert(w);
log_assert(w->write_wait_queued);
@@ -415,8 +412,8 @@ static void reuse_write_wait_remove(struct reuse_tcp* reuse,
}
/** push the element after the last on the writewait list */
static void reuse_write_wait_push_back(struct reuse_tcp* reuse,
struct waiting_tcp* w)
void
reuse_write_wait_push_back(struct reuse_tcp* reuse, struct waiting_tcp* w)
{
if(!w) return;
log_assert(!w->write_wait_queued);
@@ -427,7 +424,9 @@ static void reuse_write_wait_push_back(struct reuse_tcp* reuse,
w->write_wait_prev = reuse->write_wait_last;
} else {
reuse->write_wait_first = w;
w->write_wait_prev = NULL;
}
w->write_wait_next = NULL;
reuse->write_wait_last = w;
w->write_wait_queued = 1;
}
@@ -721,12 +720,12 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
pend->next_free = NULL;
pend->query = w;
pend->reuse.outnet = w->outnet;
pend->c->repinfo.addrlen = w->addrlen;
pend->c->repinfo.remote_addrlen = w->addrlen;
pend->c->tcp_more_read_again = &pend->reuse.cp_more_read_again;
pend->c->tcp_more_write_again = &pend->reuse.cp_more_write_again;
pend->reuse.cp_more_read_again = 0;
pend->reuse.cp_more_write_again = 0;
memcpy(&pend->c->repinfo.addr, &w->addr, w->addrlen);
memcpy(&pend->c->repinfo.remote_addr, &w->addr, w->addrlen);
pend->reuse.pending = pend;
/* Remove from tree in case the is_ssl will be different and causes the
@@ -810,20 +809,50 @@ reuse_tcp_lru_snip(struct outside_network* outnet)
return reuse;
}
/** call callback on waiting_tcp, if not NULL */
static void
waiting_tcp_callback(struct waiting_tcp* w, struct comm_point* c, int error,
struct comm_reply* reply_info)
/** remove waiting tcp from the outnet waiting list */
void
outnet_waiting_tcp_list_remove(struct outside_network* outnet, struct waiting_tcp* w)
{
if(w && w->cb) {
fptr_ok(fptr_whitelist_pending_tcp(w->cb));
(void)(*w->cb)(c, w->cb_arg, error, reply_info);
struct waiting_tcp* p = outnet->tcp_wait_first, *prev = NULL;
w->on_tcp_waiting_list = 0;
while(p) {
if(p == w) {
/* remove w */
if(prev)
prev->next_waiting = w->next_waiting;
else outnet->tcp_wait_first = w->next_waiting;
if(outnet->tcp_wait_last == w)
outnet->tcp_wait_last = prev;
w->next_waiting = NULL;
return;
}
prev = p;
p = p->next_waiting;
}
/* outnet_waiting_tcp_list_remove is currently called only with items
* that are already in the waiting list. */
log_assert(0);
}
/** pop the first waiting tcp from the outnet waiting list */
struct waiting_tcp*
outnet_waiting_tcp_list_pop(struct outside_network* outnet)
{
struct waiting_tcp* w = outnet->tcp_wait_first;
if(!outnet->tcp_wait_first) return NULL;
log_assert(w->on_tcp_waiting_list);
outnet->tcp_wait_first = w->next_waiting;
if(outnet->tcp_wait_last == w)
outnet->tcp_wait_last = NULL;
w->on_tcp_waiting_list = 0;
w->next_waiting = NULL;
return w;
}
/** add waiting_tcp element to the outnet tcp waiting list */
static void
outnet_add_tcp_waiting(struct outside_network* outnet, struct waiting_tcp* w)
void
outnet_waiting_tcp_list_add(struct outside_network* outnet,
struct waiting_tcp* w, int set_timer)
{
struct timeval tv;
log_assert(!w->on_tcp_waiting_list);
@@ -835,16 +864,18 @@ outnet_add_tcp_waiting(struct outside_network* outnet, struct waiting_tcp* w)
else outnet->tcp_wait_first = w;
outnet->tcp_wait_last = w;
w->on_tcp_waiting_list = 1;
if(set_timer) {
#ifndef S_SPLINT_S
tv.tv_sec = w->timeout/1000;
tv.tv_usec = (w->timeout%1000)*1000;
tv.tv_sec = w->timeout/1000;
tv.tv_usec = (w->timeout%1000)*1000;
#endif
comm_timer_set(w->timer, &tv);
comm_timer_set(w->timer, &tv);
}
}
/** add waiting_tcp element as first to the outnet tcp waiting list */
static void
outnet_add_tcp_waiting_first(struct outside_network* outnet,
void
outnet_waiting_tcp_list_add_first(struct outside_network* outnet,
struct waiting_tcp* w, int reset_timer)
{
struct timeval tv;
@@ -869,6 +900,17 @@ outnet_add_tcp_waiting_first(struct outside_network* outnet,
(outnet->tcp_reuse_first && outnet->tcp_reuse_last));
}
/** call callback on waiting_tcp, if not NULL */
static void
waiting_tcp_callback(struct waiting_tcp* w, struct comm_point* c, int error,
struct comm_reply* reply_info)
{
if(w && w->cb) {
fptr_ok(fptr_whitelist_pending_tcp(w->cb));
(void)(*w->cb)(c, w->cb_arg, error, reply_info);
}
}
/** see if buffers can be used to service TCP queries */
static void
use_free_buffer(struct outside_network* outnet)
@@ -879,15 +921,10 @@ use_free_buffer(struct outside_network* outnet)
struct pending_tcp* pend_tcp = NULL;
#endif
struct reuse_tcp* reuse = NULL;
w = outnet->tcp_wait_first;
log_assert(w->on_tcp_waiting_list);
outnet->tcp_wait_first = w->next_waiting;
if(outnet->tcp_wait_last == w)
outnet->tcp_wait_last = NULL;
w = outnet_waiting_tcp_list_pop(outnet);
log_assert(
(!outnet->tcp_reuse_first && !outnet->tcp_reuse_last) ||
(outnet->tcp_reuse_first && outnet->tcp_reuse_last));
w->on_tcp_waiting_list = 0;
reuse = reuse_tcp_find(outnet, &w->addr, w->addrlen,
w->ssl_upstream);
/* re-select an ID when moving to a new TCP buffer */
@@ -934,7 +971,7 @@ use_free_buffer(struct outside_network* outnet)
#endif
} else {
/* no reuse and no free buffer, put back at the start */
outnet_add_tcp_waiting_first(outnet, w, 0);
outnet_waiting_tcp_list_add_first(outnet, w, 0);
break;
}
#ifdef USE_DNSTAP
@@ -1008,7 +1045,7 @@ reuse_move_writewait_away(struct outside_network* outnet,
* fail the query */
w->error_count ++;
reuse_tree_by_id_delete(&pend->reuse, w);
outnet_add_tcp_waiting(outnet, w);
outnet_waiting_tcp_list_add(outnet, w, 1);
}
while((w = reuse_write_wait_pop(&pend->reuse)) != NULL) {
if(verbosity >= VERB_CLIENT && w->pkt_len > 12+2+2 &&
@@ -1019,7 +1056,7 @@ reuse_move_writewait_away(struct outside_network* outnet,
verbose(VERB_CLIENT, "reuse_move_writewait_away item %s", buf);
}
reuse_tree_by_id_delete(&pend->reuse, w);
outnet_add_tcp_waiting(outnet, w);
outnet_waiting_tcp_list_add(outnet, w, 1);
}
}
@@ -1036,7 +1073,8 @@ reuse_tcp_remove_tree_list(struct outside_network* outnet,
char buf[256];
addr_to_str(&reuse->addr, reuse->addrlen, buf,
sizeof(buf));
log_err("reuse tcp delete: node not present, internal error, %s ssl %d lru %d", buf, reuse->is_ssl, reuse->item_on_lru_list);
log_err("reuse tcp delete: node not present, internal error, %s ssl "
"%d lru %d", buf, reuse->is_ssl, reuse->item_on_lru_list);
}
reuse->node.key = NULL;
/* defend against loops on broken tree by zeroing the
@@ -1381,6 +1419,7 @@ outnet_send_wait_udp(struct outside_network* outnet)
pend->pkt_len = 0;
log_assert(!pend->sq->busy);
pend->sq->busy = 1;
if(!randomize_and_send_udp(pend, outnet->udp_buff,
pend->timeout)) {
/* callback error on pending */
@@ -1405,6 +1444,11 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
struct pending* p;
verbose(VERB_ALGO, "answer cb");
log_err("!!!!! outnet_udp_cb: HERE, error: %d", error);
// @TODO this is the function where we find the failed kernel call
if(error != NETEVENT_NOERROR) {
verbose(VERB_QUERY, "outnetudp got udp error %d", error);
return 0;
@@ -1417,11 +1461,11 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
/* setup lookup key */
key.id = (unsigned)LDNS_ID_WIRE(sldns_buffer_begin(c->buffer));
memcpy(&key.addr, &reply_info->addr, reply_info->addrlen);
key.addrlen = reply_info->addrlen;
memcpy(&key.addr, &reply_info->remote_addr, reply_info->remote_addrlen);
key.addrlen = reply_info->remote_addrlen;
verbose(VERB_ALGO, "Incoming reply id = %4.4x", key.id);
log_addr(VERB_ALGO, "Incoming reply addr =",
&reply_info->addr, reply_info->addrlen);
&reply_info->remote_addr, reply_info->remote_addrlen);
/* find it, see if this thing is a valid query response */
verbose(VERB_ALGO, "lookup size is %d entries", (int)outnet->pending->count);
@@ -1446,6 +1490,7 @@ outnet_udp_cb(struct comm_point* c, void* arg, int error,
verbose(VERB_ALGO, "received udp reply.");
log_buf(VERB_ALGO, "udp message", c->buffer);
if(p->pc->cp != c) {
verbose(VERB_QUERY, "received reply id,addr on wrong port. "
"dropped.");
@@ -1690,7 +1735,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
return NULL;
}
pc->cp = comm_point_create_udp(outnet->base, -1,
outnet->udp_buff, outnet_udp_cb, outnet, NULL);
outnet->udp_buff, 0, outnet_udp_cb, outnet, NULL);
if(!pc->cp) {
log_err("malloc failed");
free(pc);
@@ -1936,6 +1981,9 @@ udp_sockport(struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen,
int port, int* inuse, struct ub_randstate* rnd, int dscp)
{
int fd, noproto;
log_err("!!!!! udp_sockport: HERE!");
if(addr_is_ip6(addr, addrlen)) {
int freebind = 0;
struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr;
@@ -2016,7 +2064,6 @@ static int udp_connect_needs_log(int err)
return 1;
}
/** Select random interface and port */
static int
select_ifport(struct outside_network* outnet, struct pending* pend,
@@ -2030,11 +2077,21 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
"outgoing interfaces of that family");
return 0;
}
log_assert(outnet->unused_fds);
tries = 0;
while(1) {
my_if = ub_random_max(outnet->rnd, num_if);
pif = &ifs[my_if];
/* if we have a bound IP address for the EDNS cookie in the
* message, use that interface */
if (!(pend->sq->bound_interface)) {
my_if = ub_random_max(outnet->rnd, num_if);
pif = &ifs[my_if];
} else {
pif = pend->sq->bound_interface;
log_err("!!!!! select_ifport:bound_addrlen: %d", pif->addrlen);
log_addr(VERB_OPS, "!!!!! select_ifport:bound_addrlen:", &pif->addr, pif->addrlen);
}
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(outnet->udp_connect) {
/* if we connect() we cannot reuse fds for a port */
@@ -2057,6 +2114,9 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
break;
}
}
log_err("!!!!! select_ifport:pif->inuse: %d, pif->maxout: %d", pif->inuse, pif->maxout);
/* 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];
@@ -2066,6 +2126,15 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen,
portno, &inuse, outnet->rnd, outnet->ip_dscp);
if(fd == -1 && !inuse) {
log_err("!!!! select_ifport:nonrecoverable error making socket");
/* we need to retry sending this message with a cookie
* without a bound interface. The cookie needs to be
* changed as to not leak the client cookie part that
* is linked to this outgoing interface. */
if (pend->sq->bound_interface != NULL) {
pend->sq->bound_interface_failed = 1;
}
/* nonrecoverable error making socket */
return 0;
}
@@ -2192,6 +2261,7 @@ pending_udp_query(struct serviced_query* sq, struct sldns_buffer* packet,
pend->cb = cb;
pend->cb_arg = cb_arg;
pend->node.key = pend;
pend->timer = comm_timer_create(sq->outnet->base, pending_udp_timer_cb,
pend);
if(!pend->timer) {
@@ -2237,7 +2307,7 @@ outnet_tcptimer(void* arg)
verbose(VERB_CLIENT, "outnet_tcptimer");
if(w->on_tcp_waiting_list) {
/* it is on the waiting list */
waiting_list_remove(outnet, w);
outnet_waiting_tcp_list_remove(outnet, w);
waiting_tcp_callback(w, NULL, NETEVENT_TIMEOUT, NULL);
waiting_tcp_delete(w);
} else {
@@ -2464,7 +2534,7 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
#ifdef USE_DNSTAP
w->sq = sq;
#endif
outnet_add_tcp_waiting(sq->outnet, w);
outnet_waiting_tcp_list_add(sq->outnet, w, 1);
}
return w;
}
@@ -2528,6 +2598,7 @@ serviced_timer_cb(void* arg)
* will get attached by the time we get an answer. */
return;
delete:
log_err("!!!!! serviced_timer_cb:delete serviced_udp_send");
serviced_callbacks(sq, NETEVENT_CLOSED, NULL, NULL);
}
@@ -2538,15 +2609,17 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* zone, size_t zonelen, int qtype, struct edns_option* opt_list,
size_t pad_queries_block_size, struct alloc_cache* alloc,
struct regional* region)
struct port_if* bound_interface, struct regional* region)
{
struct serviced_query* sq = (struct serviced_query*)malloc(sizeof(*sq));
struct timeval t;
#ifdef UNBOUND_DEBUG
rbnode_type* ins;
#endif
if(!sq)
if(!sq) {
alloc_reg_release(alloc, region);
return NULL;
}
sq->node.key = sq;
sq->alloc = alloc;
sq->region = region;
@@ -2599,6 +2672,18 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
sq->status = serviced_initial;
sq->retry = 0;
sq->to_be_deleted = 0;
if (bound_interface != NULL) {
sq->bound_interface = regional_alloc_init(region,
bound_interface, sizeof(struct port_if));
if (!sq->bound_interface) {
alloc_reg_release(alloc, region);
free(sq);
return NULL;
}
} else {
sq->bound_interface = NULL;
}
sq->bound_interface_failed = 0;
sq->padding_block_size = pad_queries_block_size;
#ifdef UNBOUND_DEBUG
ins =
@@ -2610,30 +2695,6 @@ serviced_create(struct outside_network* outnet, sldns_buffer* buff, int dnssec,
return sq;
}
/** remove waiting tcp from the outnet waiting list */
static void
waiting_list_remove(struct outside_network* outnet, struct waiting_tcp* w)
{
struct waiting_tcp* p = outnet->tcp_wait_first, *prev = NULL;
w->on_tcp_waiting_list = 0;
while(p) {
if(p == w) {
/* remove w */
if(prev)
prev->next_waiting = w->next_waiting;
else outnet->tcp_wait_first = w->next_waiting;
if(outnet->tcp_wait_last == w)
outnet->tcp_wait_last = prev;
return;
}
prev = p;
p = p->next_waiting;
}
/* waiting_list_remove is currently called only with items that are
* already in the waiting list. */
log_assert(0);
}
/** reuse tcp stream, remove serviced query from stream,
* return true if the stream is kept, false if it is to be closed */
static int
@@ -2728,7 +2789,7 @@ serviced_delete(struct serviced_query* sq)
sq->pending = NULL;
} else {
verbose(VERB_CLIENT, "serviced_delete: tcpwait");
waiting_list_remove(sq->outnet, w);
outnet_waiting_tcp_list_remove(sq->outnet, w);
if(!w->in_cb_and_decommission)
waiting_tcp_delete(w);
}
@@ -2989,6 +3050,12 @@ serviced_callbacks(struct serviced_query* sq, int error, struct comm_point* c,
}
sq->outnet->svcd_overhead = backlen;
}
/* set the error to retry the cookie with a new client cookie set */
if (sq->bound_interface != NULL && sq->bound_interface_failed) {
error = NETEVENT_BOUND_INTERFACE_NOT_AVAILABLE;
}
/* test the actual sq->cblist, because the next elem could be deleted*/
while((p=sq->cblist) != NULL) {
sq->cblist = p->next; /* remove this element */
@@ -3101,8 +3168,8 @@ serviced_tcp_callback(struct comm_point* c, void* arg, int error,
rep = &r2;
r2.c = c;
}
memcpy(&rep->addr, &sq->addr, sq->addrlen);
rep->addrlen = sq->addrlen;
memcpy(&rep->remote_addr, &sq->addr, sq->addrlen);
rep->remote_addrlen = sq->addrlen;
serviced_callbacks(sq, error, c, rep);
return 0;
}
@@ -3355,9 +3422,11 @@ outnet_serviced_query(struct outside_network* outnet,
struct service_callback* cb;
struct edns_string_addr* client_string_addr;
struct regional* region;
struct edns_cookie cookie;
struct edns_option* backed_up_opt_list = qstate->edns_opts_back_out;
struct edns_option* per_upstream_opt_list = NULL;
time_t timenow = 0;
struct port_if* pif = NULL;
/* If we have an already populated EDNS option list make a copy since
* we may now add upstream specific EDNS options. */
@@ -3394,6 +3463,28 @@ outnet_serviced_query(struct outside_network* outnet,
client_string_addr->string, region);
}
if (env->cfg->upstream_cookies &&
infra_get_cookie(env->infra_cache, addr, addrlen, zone, zonelen,
*env->now, &cookie, 0)) {
if (cookie.state == SERVER_COOKIE_LEARNED) {
/* We known the complete cookie, so we attach it */
edns_opt_list_append(&per_upstream_opt_list, LDNS_EDNS_COOKIE,
24, cookie.data.cookie, region);
if (cookie.pif.addrlen > 0) {
pif = &cookie.pif;
log_addr(VERB_DETAIL, "!!!!! outnet_serviced_query:pif addr:", &cookie.pif.addr, cookie.pif.addrlen);
}
} else if (cookie.state == SERVER_COOKIE_UNKNOWN) {
/* We know just client cookie, so we attach it */
edns_opt_list_append(&per_upstream_opt_list, LDNS_EDNS_COOKIE,
8, cookie.data.cookie, region);
} /* We ignore COOKIE_NOT_SUPPORTED */
}
serviced_gen_query(buff, qinfo->qname, qinfo->qname_len, qinfo->qtype,
qinfo->qclass, flags);
sq = lookup_serviced(outnet, buff, dnssec, addr, addrlen,
@@ -3426,13 +3517,12 @@ outnet_serviced_query(struct outside_network* outnet,
per_upstream_opt_list,
( ssl_upstream && env->cfg->pad_queries
? env->cfg->pad_queries_block_size : 0 ),
env->alloc, region);
env->alloc, pif, region);
if(!sq) {
if(check_ratelimit) {
infra_ratelimit_dec(env->infra_cache,
zone, zonelen, timenow);
}
alloc_reg_release(env->alloc, region);
return NULL;
}
if(!(cb = (struct service_callback*)regional_alloc(
@@ -3517,7 +3607,8 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
if(outnet->num_ip6 == 0) {
char to[64];
addr_to_str(to_addr, to_addrlen, to, sizeof(to));
verbose(VERB_QUERY, "need ipv6 to send, but no ipv6 outgoing interfaces, for %s", to);
verbose(VERB_QUERY, "need ipv6 to send, but no ipv6 outgoing "
"interfaces, for %s", to);
return -1;
}
i = ub_random_max(outnet->rnd, outnet->num_ip6);
@@ -3526,7 +3617,8 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
if(outnet->num_ip4 == 0) {
char to[64];
addr_to_str(to_addr, to_addrlen, to, sizeof(to));
verbose(VERB_QUERY, "need ipv4 to send, but no ipv4 outgoing interfaces, for %s", to);
verbose(VERB_QUERY, "need ipv4 to send, but no ipv4 outgoing "
"interfaces, for %s", to);
return -1;
}
i = ub_random_max(outnet->rnd, outnet->num_ip4);
@@ -3581,7 +3673,7 @@ outnet_comm_point_for_udp(struct outside_network* outnet,
if(fd == -1) {
return NULL;
}
cp = comm_point_create_udp(outnet->base, fd, outnet->udp_buff,
cp = comm_point_create_udp(outnet->base, fd, outnet->udp_buff, 0,
cb, cb_arg, NULL);
if(!cp) {
log_err("malloc failure");
@@ -3669,8 +3761,8 @@ outnet_comm_point_for_tcp(struct outside_network* outnet,
close(fd);
return 0;
}
cp->repinfo.addrlen = to_addrlen;
memcpy(&cp->repinfo.addr, to_addr, to_addrlen);
cp->repinfo.remote_addrlen = to_addrlen;
memcpy(&cp->repinfo.remote_addr, to_addr, to_addrlen);
/* setup for SSL (if needed) */
if(ssl) {
@@ -3745,8 +3837,8 @@ outnet_comm_point_for_http(struct outside_network* outnet,
close(fd);
return 0;
}
cp->repinfo.addrlen = to_addrlen;
memcpy(&cp->repinfo.addr, to_addr, to_addrlen);
cp->repinfo.remote_addrlen = to_addrlen;
memcpy(&cp->repinfo.remote_addr, to_addr, to_addrlen);
/* setup for SSL (if needed) */
if(ssl) {
+31
View File
@@ -527,6 +527,13 @@ struct serviced_query {
struct comm_timer* timer;
/** true if serviced_query is currently doing net I/O and may block */
int busy;
/** interface bound to the EDNS cookie @TODO fix this */
struct port_if* bound_interface;
/** flag to create a retry when the opening of the socket on the
* bound interface failed. This enables rewriting of the cookie without
* leaking the previously sent client cookie */
int bound_interface_failed;
};
/**
@@ -718,6 +725,30 @@ struct reuse_tcp* reuse_tcp_lru_snip(struct outside_network* outnet);
/** delete readwait waiting_tcp elements, deletes the elements in the list */
void reuse_del_readwait(rbtree_type* tree_by_id);
/** remove waiting tcp from the outnet waiting list */
void outnet_waiting_tcp_list_remove(struct outside_network* outnet,
struct waiting_tcp* w);
/** pop the first waiting tcp from the outnet waiting list */
struct waiting_tcp* outnet_waiting_tcp_list_pop(struct outside_network* outnet);
/** add waiting_tcp element to the outnet tcp waiting list */
void outnet_waiting_tcp_list_add(struct outside_network* outnet,
struct waiting_tcp* w, int set_timer);
/** add waiting_tcp element as first to the outnet tcp waiting list */
void outnet_waiting_tcp_list_add_first(struct outside_network* outnet,
struct waiting_tcp* w, int reset_timer);
/** pop the first element from the writewait list */
struct waiting_tcp* reuse_write_wait_pop(struct reuse_tcp* reuse);
/** remove the element from the writewait list */
void reuse_write_wait_remove(struct reuse_tcp* reuse, struct waiting_tcp* w);
/** push the element after the last on the writewait list */
void reuse_write_wait_push_back(struct reuse_tcp* reuse, struct waiting_tcp* w);
/** get TCP file descriptor for address, returns -1 on failure,
* tcp_mss is 0 or maxseg size to set for TCP packets. */
int outnet_get_tcp_fd(struct sockaddr_storage* addr, socklen_t addrlen,
+15 -13
View File
@@ -1392,11 +1392,13 @@ log_rpz_apply(char* trigger, uint8_t* dname, struct addr_tree_node* addrnode,
dnamestr[0]=0;
}
if(repinfo) {
addr_to_str(&repinfo->addr, repinfo->addrlen, ip, sizeof(ip));
port = ntohs(((struct sockaddr_in*)&repinfo->addr)->sin_port);
addr_to_str(&repinfo->client_addr, repinfo->client_addrlen, ip, sizeof(ip));
port = ntohs(((struct sockaddr_in*)&repinfo->client_addr)->sin_port);
} else if(ms && ms->mesh_info && ms->mesh_info->reply_list) {
addr_to_str(&ms->mesh_info->reply_list->query_reply.addr, ms->mesh_info->reply_list->query_reply.addrlen, ip, sizeof(ip));
port = ntohs(((struct sockaddr_in*)&ms->mesh_info->reply_list->query_reply.addr)->sin_port);
addr_to_str(&ms->mesh_info->reply_list->query_reply.client_addr,
ms->mesh_info->reply_list->query_reply.client_addrlen,
ip, sizeof(ip));
port = ntohs(((struct sockaddr_in*)&ms->mesh_info->reply_list->query_reply.client_addr)->sin_port);
} else {
ip[0]=0;
port = 0;
@@ -1468,7 +1470,9 @@ rpz_resolve_client_action_and_zone(struct auth_zones* az, struct query_info* qin
}
z = rpz_find_zone(r->local_zones, qinfo->qname, qinfo->qname_len,
qinfo->qclass, 0, 0, 0);
node = rpz_ipbased_trigger_lookup(r->client_set, &repinfo->addr, repinfo->addrlen, "clientip");
node = rpz_ipbased_trigger_lookup(r->client_set,
&repinfo->client_addr, repinfo->client_addrlen,
"clientip");
if((z || node) && r->action_override == RPZ_DISABLED_ACTION) {
if(r->log)
log_rpz_apply((node?"clientip":"qname"),
@@ -2164,18 +2168,16 @@ rpz_callback_from_iterator_module(struct module_qstate* ms, struct iter_qstate*
lock_rw_unlock(&az->rpz_lock);
if(raddr == NULL && z == NULL) { return NULL; }
else if(raddr != NULL) {
if(raddr == NULL && z == NULL)
return NULL;
if(raddr != NULL) {
if(z) {
lock_rw_unlock(&z->lock);
}
return rpz_apply_nsip_trigger(ms, r, raddr, a);
} else if(z != NULL) {
if(raddr) {
lock_rw_unlock(&raddr->lock);
}
return rpz_apply_nsdname_trigger(ms, r, z, &match, a);
} else { return NULL; }
}
return rpz_apply_nsdname_trigger(ms, r, z, &match, a);
}
struct dns_msg* rpz_callback_from_iterator_cname(struct module_qstate* ms,
+3 -2
View File
@@ -66,8 +66,9 @@ views_create(void)
return v;
}
/** This prototype is defined in in respip.h, but we want to avoid
* unnecessary dependencies */
/* \noop (ignore this comment for doxygen)
* This prototype is defined in in respip.h, but we want to avoid
* unnecessary dependencies */
void respip_set_delete(struct respip_set *set);
void
+2 -2
View File
@@ -381,9 +381,9 @@ static sldns_rr_descriptor rdata_field_descriptors[] = {
/* 63 */
{LDNS_RR_TYPE_ZONEMD, "ZONEMD", 4, 4, type_zonemd_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
/* 64 */
{LDNS_RR_TYPE_SVCB, "SVCB", 2, 2, type_svcb_wireformat, LDNS_RDF_TYPE_SVCPARAM, LDNS_RR_NO_COMPRESS, 0 },
{LDNS_RR_TYPE_SVCB, "SVCB", 2, 2, type_svcb_wireformat, LDNS_RDF_TYPE_SVCPARAM, LDNS_RR_NO_COMPRESS, 1 },
/* 65 */
{LDNS_RR_TYPE_HTTPS, "HTTPS", 2, 2, type_svcb_wireformat, LDNS_RDF_TYPE_SVCPARAM, LDNS_RR_NO_COMPRESS, 0 },
{LDNS_RR_TYPE_HTTPS, "HTTPS", 2, 2, type_svcb_wireformat, LDNS_RDF_TYPE_SVCPARAM, LDNS_RR_NO_COMPRESS, 1 },
{(enum sldns_enum_rr_type)0, "TYPE66", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
{(enum sldns_enum_rr_type)0, "TYPE67", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
{(enum sldns_enum_rr_type)0, "TYPE68", 1, 1, type_0_wireformat, LDNS_RDF_TYPE_NONE, LDNS_RR_NO_COMPRESS, 0 },
+4
View File
@@ -433,6 +433,7 @@ enum sldns_enum_edns_option
LDNS_EDNS_DHU = 6, /* RFC6975 */
LDNS_EDNS_N3U = 7, /* RFC6975 */
LDNS_EDNS_CLIENT_SUBNET = 8, /* RFC7871 */
LDNS_EDNS_COOKIE = 10, /* RFC7873 */
LDNS_EDNS_KEEPALIVE = 11, /* draft-ietf-dnsop-edns-tcp-keepalive*/
LDNS_EDNS_PADDING = 12, /* RFC7830 */
LDNS_EDNS_EDE = 15, /* RFC8914 */
@@ -482,6 +483,9 @@ typedef enum sldns_enum_ede_code sldns_ede_code;
#define LDNS_TSIG_ERROR_BADNAME 20
#define LDNS_TSIG_ERROR_BADALG 21
/** DNS Cookie extended rcode */
#define LDNS_EXT_RCODE_BADCOOKIE 23
/**
* Contains all information about resource record types.
*
+2 -1
View File
@@ -192,6 +192,7 @@ static sldns_lookup_table sldns_edns_options_data[] = {
{ 6, "DHU" },
{ 7, "N3U" },
{ 8, "edns-client-subnet" },
{ 10, "Cookie" },
{ 11, "edns-tcp-keepalive"},
{ 12, "Padding" },
{ 15, "EDE"},
@@ -1071,7 +1072,7 @@ static int sldns_wire2str_svcparam_mandatory2str(char** s,
assert(data_len > 0);
if (data_len % sizeof(uint16_t))
return -1; // wireformat error, data_len must be multiple of shorts
return -1; /* wireformat error, data_len must be multiple of shorts */
w += sldns_str_print(s, slen, "=");
w += sldns_print_svcparamkey(s, slen, sldns_read_uint16(data));
data += 2;
+16 -2
View File
@@ -316,7 +316,7 @@ warn_hosts(const char* typ, struct config_stub* list)
struct config_strlist* h;
for(s=list; s; s=s->next) {
for(h=s->hosts; h; h=h->next) {
if(extstrtoaddr(h->str, &a, &alen)) {
if(extstrtoaddr(h->str, &a, &alen, UNBOUND_DNS_PORT)) {
fprintf(stderr, "unbound-checkconf: warning:"
" %s %s: \"%s\" is an IP%s address, "
"and when looked up as a host name "
@@ -338,6 +338,8 @@ interfacechecks(struct config_file* cfg)
int i, j, i2, j2;
char*** resif = NULL;
int* num_resif = NULL;
char portbuf[32];
snprintf(portbuf, sizeof(portbuf), "%d", cfg->port);
if(cfg->num_ifs != 0) {
resif = (char***)calloc(cfg->num_ifs, sizeof(char**));
@@ -359,9 +361,21 @@ interfacechecks(struct config_file* cfg)
fatal_exit("could not resolve interface names, for %s",
cfg->ifs[i]);
}
/* check for port combinations that are not supported */
if(if_is_pp2(resif[i][0], portbuf, cfg->proxy_protocol_port)) {
if(if_is_dnscrypt(resif[i][0], portbuf,
cfg->dnscrypt_port)) {
fatal_exit("PROXYv2 and DNSCrypt combination not "
"supported!");
} else if(if_is_https(resif[i][0], portbuf,
cfg->https_port)) {
fatal_exit("PROXYv2 and DoH combination not "
"supported!");
}
}
/* search for duplicates in the returned addresses */
for(j=0; j<num_resif[i]; j++) {
if(!extstrtoaddr(resif[i][j], &a, &alen)) {
if(!extstrtoaddr(resif[i][j], &a, &alen, cfg->port)) {
if(strcmp(cfg->ifs[i], resif[i][j]) != 0)
fatal_exit("cannot parse interface address '%s' from the interface specified as '%s'",
resif[i][j], cfg->ifs[i]);
+2 -2
View File
@@ -601,7 +601,7 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
struct sockaddr_storage addr2;
socklen_t addrlen2;
if(extstrtoaddr(cfg->control_ifs.first->str, &addr2,
&addrlen2)) {
&addrlen2, UNBOUND_DNS_PORT)) {
svr = cfg->control_ifs.first->str;
} else {
if(!resolve_interface_names(NULL, 0,
@@ -629,7 +629,7 @@ contact_server(const char* svr, struct config_file* cfg, int statuscmd)
svr = "::1";
}
if(strchr(svr, '@')) {
if(!extstrtoaddr(svr, &addr, &addrlen))
if(!extstrtoaddr(svr, &addr, &addrlen, UNBOUND_DNS_PORT))
fatal_exit("could not parse IP@port: %s", svr);
#ifdef HAVE_SYS_UN_H
} else if(svr[0] == '/') {
+1 -1
View File
@@ -974,7 +974,7 @@ service(const char* bind_str, int bindport, const char* serv_str,
dl_tv_add(&reuse, &delay);
if(reuse.tv_sec == 0)
reuse.tv_sec = 1;
if(!extstrtoaddr(serv_str, &srv_addr, &srv_len)) {
if(!extstrtoaddr(serv_str, &srv_addr, &srv_len, UNBOUND_DNS_PORT)) {
printf("cannot parse forward address: %s\n", serv_str);
exit(1);
}
+2
View File
@@ -16,6 +16,7 @@ NEED_WHOAMI='07-confroot.tdir'
NEED_IPV6='fwd_ancil.tdir fwd_tcp_tc6.tdir stub_udp6.tdir edns_cache.tdir'
NEED_NOMINGW='tcp_sigpipe.tdir 07-confroot.tdir 08-host-lib.tdir fwd_ancil.tdir'
NEED_DNSCRYPT_PROXY='dnscrypt_queries.tdir dnscrypt_queries_chacha.tdir'
NEED_UNSHARE='acl_interface.tdir proxy_protocol.tdir'
# test if dig and ldns-testns are available.
test_tool_avail "dig"
@@ -50,6 +51,7 @@ for test in `ls -d *.tdir`; do
skip_if_in_list $test "$NEED_NC" "nc"
skip_if_in_list $test "$NEED_WHOAMI" "whoami"
skip_if_in_list $test "$NEED_DNSCRYPT_PROXY" "dnscrypt-proxy"
skip_if_in_list $test "$NEED_UNSHARE" "unshare"
if echo $NEED_IPV6 | grep $test >/dev/null; then
if test "$HAVE_IPV6" = no; then
+1
View File
@@ -573,6 +573,7 @@ int main(int argc, char** argv)
#endif
checklock_start();
log_init(0, 0, 0);
log_ident_set("dohclient");
h2_session = http2_session_create();
if(!h2_session) fatal_exit("out of memory");
+36 -9
View File
@@ -384,8 +384,8 @@ answer_callback_from_entry(struct replay_runtime* runtime,
fill_buffer_with_reply(c.buffer, entry, pend->pkt, pend->pkt_len,
pend->tcp_pkt_counter);
repinfo.c = &c;
repinfo.addrlen = pend->addrlen;
memcpy(&repinfo.addr, &pend->addr, pend->addrlen);
repinfo.remote_addrlen = pend->addrlen;
memcpy(&repinfo.remote_addr, &pend->addr, pend->addrlen);
if(!pend->serviced) {
if(entry && entry->reply_list->next &&
pend->tcp_pkt_counter < count_reply_packets(entry)) {
@@ -415,7 +415,7 @@ answer_check_it(struct replay_runtime* runtime)
tr = transport_udp;
if((runtime->now->addrlen == 0 || sockaddr_cmp(
&runtime->now->addr, runtime->now->addrlen,
&ans->repinfo.addr, ans->repinfo.addrlen) == 0) &&
&ans->repinfo.remote_addr, ans->repinfo.remote_addrlen) == 0) &&
find_match(runtime->now->match, ans->pkt,
ans->pkt_len, tr)) {
log_info("testbound matched event entry from line %d",
@@ -453,10 +453,12 @@ fake_front_query(struct replay_runtime* runtime, struct replay_moment *todo)
repinfo.c = (struct comm_point*)calloc(1, sizeof(struct comm_point));
if(!repinfo.c)
fatal_exit("out of memory in fake_front_query");
repinfo.addrlen = (socklen_t)sizeof(struct sockaddr_in);
repinfo.remote_addrlen = (socklen_t)sizeof(struct sockaddr_in);
if(todo->addrlen != 0) {
repinfo.addrlen = todo->addrlen;
memcpy(&repinfo.addr, &todo->addr, todo->addrlen);
repinfo.remote_addrlen = todo->addrlen;
memcpy(&repinfo.remote_addr, &todo->addr, todo->addrlen);
repinfo.client_addrlen = todo->addrlen;
memcpy(&repinfo.client_addr, &todo->addr, todo->addrlen);
}
repinfo.c->fd = -1;
repinfo.c->ev = (struct internal_event*)runtime;
@@ -510,8 +512,8 @@ fake_pending_callback(struct replay_runtime* runtime,
p->pkt_len, p->tcp_pkt_counter);
}
repinfo.c = &c;
repinfo.addrlen = p->addrlen;
memcpy(&repinfo.addr, &p->addr, p->addrlen);
repinfo.remote_addrlen = p->addrlen;
memcpy(&repinfo.remote_addr, &p->addr, p->addrlen);
if(!p->serviced) {
if(todo->match && todo->match->reply_list->next && !error &&
p->tcp_pkt_counter < count_reply_packets(todo->match)) {
@@ -1226,6 +1228,9 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
struct edns_option* backed_up_opt_list =
qstate->edns_opts_back_out;
struct edns_option* per_upstream_opt_list = NULL;
struct edns_cookie cookie;
struct port_if* pif;
/* If we have an already populated EDNS option list make a copy
* since we may now add upstream specific EDNS options. */
if(qstate->edns_opts_back_out) {
@@ -1254,6 +1259,25 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
client_string_addr->string_len,
client_string_addr->string, qstate->region);
}
if (qstate->env->cfg->upstream_cookies &&
infra_get_cookie(env->infra_cache, addr, addrlen,
zone, zonelen, *env->now, outnet, &pif, &cookie)) {
if (cookie.state == SERVER_COOKIE_LEARNED) {
/* We known the complete cookie, so we attach it */
edns_opt_list_append(&per_upstream_opt_list,
LDNS_EDNS_COOKIE, 24, cookie.data.cookie,
qstate->region);
} else if (cookie.state == SERVER_COOKIE_UNKNOWN) {
/* We know just client cookie, so we attach it */
edns_opt_list_append(&per_upstream_opt_list,
LDNS_EDNS_COOKIE, 8,
cookie.data.cookie,
qstate->region);
} /* We ignore COOKIE_NOT_SUPPORTED */
}
/* add edns */
edns.edns_present = 1;
edns.ext_rcode = 0;
@@ -1263,6 +1287,8 @@ struct serviced_query* outnet_serviced_query(struct outside_network* outnet,
if(dnssec)
edns.bits = EDNS_DO;
edns.padding_block_size = 0;
edns.cookie_present = 0;
edns.cookie_valid = 0;
edns.opt_list_in = NULL;
edns.opt_list_out = per_upstream_opt_list;
edns.opt_list_inplace_cb_out = NULL;
@@ -1344,7 +1370,7 @@ struct listen_port* listening_ports_open(struct config_file* ATTR_UNUSED(cfg),
char** ATTR_UNUSED(ifs), int ATTR_UNUSED(num_ifs),
int* ATTR_UNUSED(reuseport))
{
return calloc(1, 1);
return calloc(1, sizeof(struct listen_port));
}
void listening_ports_free(struct listen_port* list)
@@ -1663,6 +1689,7 @@ int create_udp_sock(int ATTR_UNUSED(family), int ATTR_UNUSED(socktype),
struct comm_point* comm_point_create_udp(struct comm_base *ATTR_UNUSED(base),
int ATTR_UNUSED(fd), sldns_buffer* ATTR_UNUSED(buffer),
int ATTR_UNUSED(pp2_enabled),
comm_point_callback_type* ATTR_UNUSED(callback),
void* ATTR_UNUSED(callback_arg),
struct unbound_socket* ATTR_UNUSED(socket))
+27 -11
View File
@@ -8,6 +8,7 @@ fi
# This will keep the temporary directory around and return 1 when the test failed.
DEBUG=0
test -n "$DEBUG_TDIR" && DEBUG=1
quiet=0
if test "$1" = "-q"; then
@@ -17,9 +18,9 @@ fi
if test "$1" = "clean"; then
if test $quiet = 0; then
echo "rm -f result.* .done* .tdir.var.master .tdir.var.test"
echo "rm -f result.* .done* .skip* .tdir.var.master .tdir.var.test"
fi
rm -f result.* .done* .tdir.var.master .tdir.var.test
rm -f result.* .done* .skip* .tdir.var.master .tdir.var.test
exit 0
fi
if test "$1" = "fake"; then
@@ -54,12 +55,15 @@ if test "$1" = "-f" && test "$2" = "report"; then
echo "** PASSED ** $timelen $name: $desc"
pass=`expr $pass + 1`
fi
elif test -f ".skip-$name"; then
echo ".. SKIPPED.. $timelen $name: $desc"
skip=`expr $skip + 1`
else
if test -f "result.$name"; then
echo "!! FAILED !! $timelen $name: $desc"
fail=`expr $fail + 1`
else
echo ".> SKIPPED<< $timelen $name: $desc"
echo ".. SKIPPED.. $timelen $name: $desc"
skip=`expr $skip + 1`
fi
fi
@@ -81,11 +85,17 @@ if test "$1" = "report" || test "$2" = "report"; then
if test $quiet = 0; then
echo "** PASSED ** : $name"
fi
elif test -f ".skip-$name"; then
if test $quiet = 0; then
echo ".. SKIPPED.. : $name"
fi
else
if test -f "result.$name"; then
echo "!! FAILED !! : $name"
else
echo ">> SKIPPED<< : $name"
if test $quiet = 0; then
echo ".. SKIPPED.. : $name"
fi
fi
fi
done
@@ -116,6 +126,7 @@ name=`basename $1 .tdir`
dir=$name.$$
result=result.$name
done=.done-$name
skip=.skip-$name
success="no"
if test -x "`which bash`"; then
shell="bash"
@@ -124,8 +135,8 @@ else
fi
# check already done
if test -f .done-$name; then
echo "minitdir .done-$name exists. skip test."
if test -f $done; then
echo "minitdir $done exists. skip test."
exit 0
fi
@@ -151,11 +162,16 @@ if test -f $name.pre; then
fi
echo "minitdir exe $name.pre" >> $result
$shell $name.pre $args >> $result
if test $? -ne 0; then
exit_value=$?
if test $exit_value -eq 3; then
echo "$name: SKIPPED" >> $result
echo "$name: SKIPPED" > ../$skip
echo "$name: SKIPPED"
elif test $exit_value -ne 0; then
echo "Warning: $name.pre did not exit successfully"
fi
fi
if test -f $name.test; then
if test -f $name.test -a ! -f ../$skip; then
if test $quiet = 0; then
echo "minitdir exe $name.test"
fi
@@ -167,14 +183,14 @@ if test -f $name.test; then
success="no"
else
echo "$name: PASSED" >> $result
echo "$name: PASSED" > ../.done-$name
echo "$name: PASSED" > ../$done
if test $quiet = 0; then
echo "$name: PASSED"
fi
success="yes"
fi
fi
if test -f $name.post; then
if test -f $name.post -a ! -f ../$skip; then
if test $quiet = 0; then
echo "minitdir exe $name.post"
fi
@@ -198,7 +214,7 @@ if test $DEBUG -eq 0; then
rm -rf $dir
fi
else
if test $success == "no"; then
if test $success = "no"; then
exit 1
fi
exit 0
-128
View File
@@ -1,128 +0,0 @@
# tpkg that only exes the files.
args="../.."
if test "$1" = "-a"; then
args=$2
shift
shift
fi
if test "$1" = "clean"; then
echo "rm -f result.* .done* .tpkg.var.master .tpkg.var.test"
rm -f result.* .done* .tpkg.var.master .tpkg.var.test
exit 0
fi
if test "$1" = "fake"; then
echo "minitpkg fake $2"
echo "fake" > .done-`basename $2 .tpkg`
exit 0
fi
if test "$1" = "report" || test "$2" = "report"; then
echo "Minitpkg Report"
for result in *.tpkg; do
name=`basename $result .tpkg`
if test -f ".done-$name"; then
if test "$1" != "-q"; then
echo "** PASSED ** : $name"
fi
else
if test -f "result.$name"; then
echo "!! FAILED !! : $name"
else
echo ">> SKIPPED<< : $name"
fi
fi
done
exit 0
fi
if test "$1" != 'exe'; then
# usage
echo "mini tpkg. Reduced functionality for old shells."
echo " tpkg exe <file>"
echo " tpkg fake <file>"
echo " tpkg clean"
echo " tpkg [-q] report"
exit 1
fi
shift
# do not execute if the disk is too full
#DISKLIMIT=100000
# This check is not portable (to Solaris 10).
#avail=`df . | tail -1 | awk '{print $4}'`
#if test "$avail" -lt "$DISKLIMIT"; then
#echo "minitpkg: The disk is too full! Only $avail."
#exit 1
#fi
name=`basename $1 .tpkg`
dir=$name.$$
result=result.$name
done=.done-$name
success="no"
if test -x "`which bash`"; then
shell="bash"
else
shell="sh"
fi
# check already done
if test -f .done-$name; then
echo "minitpkg .done-$name exists. skip test."
exit 0
fi
# Extract
echo "minitpkg extract $1 to $dir"
mkdir $dir
gzip -cd $name.tpkg | (cd $dir; tar xf -)
cd $dir
mv $name.dir/* .
# EXE
echo "minitpkg exe $name" > $result
grep "Description:" $name.dsc >> $result 2>&1
echo "DateRunStart: "`date "+%s" 2>/dev/null` >> $result
if test -f $name.pre; then
echo "minitpkg exe $name.pre"
echo "minitpkg exe $name.pre" >> $result
$shell $name.pre $args >> $result
if test $? -ne 0; then
echo "Warning: $name.pre did not exit successfully"
fi
fi
if test -f $name.test; then
echo "minitpkg exe $name.test"
echo "minitpkg exe $name.test" >> $result
$shell $name.test $args >>$result 2>&1
if test $? -ne 0; then
echo "$name: FAILED" >> $result
echo "$name: FAILED"
success="no"
else
echo "$name: PASSED" >> $result
echo "$name: PASSED" > ../.done-$name
echo "$name: PASSED"
success="yes"
fi
fi
if test -f $name.post; then
echo "minitpkg exe $name.post"
echo "minitpkg exe $name.post" >> $result
$shell $name.post $args >> $result
if test $? -ne 0; then
echo "Warning: $name.post did not exit successfully"
fi
fi
echo "DateRunEnd: "`date "+%s" 2>/dev/null` >> $result
mv $result ..
cd ..
rm -rf $dir
# compat for windows where deletion may not succeed initially (files locked
# by processes that still have to exit).
if test $? -eq 1; then
echo "minitpkg waiting for processes to terminate"
sleep 2 # some time to exit, and try again
rm -rf $dir
fi
+1 -1
View File
@@ -618,7 +618,7 @@ int main(int argc, char* argv[])
printf("error: pass server IP address on commandline.\n");
usage(nm);
}
if(!extstrtoaddr(argv[0], &info.dest, &info.destlen)) {
if(!extstrtoaddr(argv[0], &info.dest, &info.destlen, UNBOUND_DNS_PORT)) {
printf("Could not parse ip: %s\n", argv[0]);
exit(1);
}
+7 -4
View File
@@ -179,7 +179,8 @@ replay_range_read(char* remain, FILE* in, const char* name,
while(isspace((unsigned char)*parse))
parse++;
strip_end_white(parse);
if(!extstrtoaddr(parse, &rng->addr, &rng->addrlen)) {
if(!extstrtoaddr(parse, &rng->addr, &rng->addrlen,
UNBOUND_DNS_PORT)) {
log_err("Line %d: could not read ADDRESS: %s",
pstate->lineno, parse);
free(rng);
@@ -287,7 +288,8 @@ replay_moment_read(char* remain, FILE* in, const char* name,
} else if(parse_keyword(&remain, "QUERY")) {
mom->evt_type = repevt_front_query;
readentry = 1;
if(!extstrtoaddr("127.0.0.1", &mom->addr, &mom->addrlen))
if(!extstrtoaddr("127.0.0.1", &mom->addr, &mom->addrlen,
UNBOUND_DNS_PORT))
fatal_exit("internal error");
} else if(parse_keyword(&remain, "CHECK_ANSWER")) {
mom->evt_type = repevt_front_reply;
@@ -354,7 +356,7 @@ replay_moment_read(char* remain, FILE* in, const char* name,
m++;
while(isspace((unsigned char)*m))
m++;
if(!extstrtoaddr(s, &mom->addr, &mom->addrlen))
if(!extstrtoaddr(s, &mom->addr, &mom->addrlen, UNBOUND_DNS_PORT))
fatal_exit("bad infra_rtt address %s", s);
strip_end_white(m);
mom->variable = strdup(remain);
@@ -372,7 +374,8 @@ replay_moment_read(char* remain, FILE* in, const char* name,
while(isspace((unsigned char)*remain))
remain++;
strip_end_white(remain);
if(!extstrtoaddr(remain, &mom->addr, &mom->addrlen)) {
if(!extstrtoaddr(remain, &mom->addr, &mom->addrlen,
UNBOUND_DNS_PORT)) {
log_err("line %d: could not parse ADDRESS: %s",
pstate->lineno, remain);
free(mom);
+101 -27
View File
@@ -49,6 +49,7 @@
#include "util/locks.h"
#include "util/log.h"
#include "util/net_help.h"
#include "util/proxy_protocol.h"
#include "util/data/msgencode.h"
#include "util/data/msgparse.h"
#include "util/data/msgreply.h"
@@ -71,6 +72,7 @@ static void usage(char* argv[])
printf("usage: %s [options] name type class ...\n", argv[0]);
printf(" sends the name-type-class queries over TCP.\n");
printf("-f server what ipaddr@portnr to send the queries to\n");
printf("-p client what ipaddr@portnr to include in PROXYv2\n");
printf("-u use UDP. No retries are attempted.\n");
printf("-n do not wait for an answer.\n");
printf("-a print answers as they arrive.\n");
@@ -82,18 +84,17 @@ static void usage(char* argv[])
/** open TCP socket to svr */
static int
open_svr(const char* svr, int udp)
open_svr(const char* svr, int udp, struct sockaddr_storage* addr,
socklen_t* addrlen)
{
struct sockaddr_storage addr;
socklen_t addrlen;
int fd = -1;
/* svr can be ip@port */
memset(&addr, 0, sizeof(addr));
if(!extstrtoaddr(svr, &addr, &addrlen)) {
memset(addr, 0, sizeof(*addr));
if(!extstrtoaddr(svr, addr, addrlen, UNBOUND_DNS_PORT)) {
printf("fatal: bad server specs '%s'\n", svr);
exit(1);
}
fd = socket(addr_is_ip6(&addr, addrlen)?PF_INET6:PF_INET,
fd = socket(addr_is_ip6(addr, *addrlen)?PF_INET6:PF_INET,
udp?SOCK_DGRAM:SOCK_STREAM, 0);
if(fd == -1) {
#ifndef USE_WINSOCK
@@ -103,7 +104,7 @@ open_svr(const char* svr, int udp)
#endif
exit(1);
}
if(connect(fd, (struct sockaddr*)&addr, addrlen) < 0) {
if(connect(fd, (struct sockaddr*)addr, *addrlen) < 0) {
#ifndef USE_WINSOCK
perror("connect() error");
#else
@@ -116,11 +117,12 @@ open_svr(const char* svr, int udp)
/** write a query over the TCP fd */
static void
write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
sldns_buffer* proxy_buf, int pp2_parsed,
const char* strname, const char* strtype, const char* strclass)
{
struct query_info qinfo;
uint16_t len;
size_t proxy_buf_limit = sldns_buffer_limit(proxy_buf);
/* qname */
qinfo.qname = sldns_str2wire_dname(strname, &qinfo.qname_len);
if(!qinfo.qname) {
@@ -152,9 +154,27 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
attach_edns_record(buf, &edns);
}
/* we need to send the PROXYv2 information in every UDP message */
if(udp && pp2_parsed) {
/* append the proxy_buf with the buf's content
* and use that for sending */
if(sldns_buffer_capacity(proxy_buf) <
sldns_buffer_limit(proxy_buf) +
sldns_buffer_limit(buf)) {
printf("buffer too small for packet + proxy");
exit(1);
}
sldns_buffer_clear(proxy_buf);
sldns_buffer_skip(proxy_buf, proxy_buf_limit);
sldns_buffer_write(proxy_buf, sldns_buffer_begin(buf),
sldns_buffer_limit(buf));
sldns_buffer_flip(proxy_buf);
buf = proxy_buf;
}
/* send it */
if(!udp) {
len = (uint16_t)sldns_buffer_limit(buf);
uint16_t len = (uint16_t)sldns_buffer_limit(buf);
len = htons(len);
if(ssl) {
if(SSL_write(ssl, (void*)&len, (int)sizeof(len)) <= 0) {
@@ -167,7 +187,7 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
#ifndef USE_WINSOCK
perror("send() len failed");
#else
printf("send len: %s\n",
printf("send len: %s\n",
wsa_strerror(WSAGetLastError()));
#endif
exit(1);
@@ -182,17 +202,20 @@ write_q(int fd, int udp, SSL* ssl, sldns_buffer* buf, uint16_t id,
}
} else {
if(send(fd, (void*)sldns_buffer_begin(buf),
sldns_buffer_limit(buf), 0) <
sldns_buffer_limit(buf), 0) <
(ssize_t)sldns_buffer_limit(buf)) {
#ifndef USE_WINSOCK
perror("send() data failed");
#else
printf("send data: %s\n", wsa_strerror(WSAGetLastError()));
printf("send data: %s\n",
wsa_strerror(WSAGetLastError()));
#endif
exit(1);
}
}
/* reset the proxy_buf for next packet */
sldns_buffer_set_limit(proxy_buf, proxy_buf_limit);
free(qinfo.qname);
}
@@ -224,7 +247,7 @@ recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
#ifndef USE_WINSOCK
perror("read() len failed");
#else
printf("read len: %s\n",
printf("read len: %s\n",
wsa_strerror(WSAGetLastError()));
#endif
exit(1);
@@ -243,12 +266,12 @@ recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
if(r != (int)len)
fatal_exit("ssl_read %d of %d", r, len);
} else {
if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) <
if(recv(fd, (void*)sldns_buffer_begin(buf), len, 0) <
(ssize_t)len) {
#ifndef USE_WINSOCK
perror("read() data failed");
#else
printf("read data: %s\n",
printf("read data: %s\n",
wsa_strerror(WSAGetLastError()));
#endif
exit(1);
@@ -257,12 +280,12 @@ recv_one(int fd, int udp, SSL* ssl, sldns_buffer* buf)
} else {
ssize_t l;
sldns_buffer_clear(buf);
if((l=recv(fd, (void*)sldns_buffer_begin(buf),
if((l=recv(fd, (void*)sldns_buffer_begin(buf),
sldns_buffer_capacity(buf), 0)) < 0) {
#ifndef USE_WINSOCK
perror("read() data failed");
#else
printf("read data: %s\n",
printf("read data: %s\n",
wsa_strerror(WSAGetLastError()));
#endif
exit(1);
@@ -324,17 +347,40 @@ static int get_random(void)
return (int)arc4random();
}
/* parse the pp2_client and populate the proxy_buffer
* It doesn't populate the destination parts. */
static int parse_pp2_client(const char* pp2_client, int udp,
sldns_buffer* proxy_buf)
{
struct sockaddr_storage pp2_addr;
socklen_t pp2_addrlen = 0;
memset(&pp2_addr, 0, sizeof(pp2_addr));
if(*pp2_client == 0) return 0;
if(!extstrtoaddr(pp2_client, &pp2_addr, &pp2_addrlen, UNBOUND_DNS_PORT)) {
printf("fatal: bad proxy client specs '%s'\n", pp2_client);
exit(1);
}
sldns_buffer_clear(proxy_buf);
pp2_write_to_buf(proxy_buf, &pp2_addr, !udp);
sldns_buffer_flip(proxy_buf);
return 1;
}
/** send the TCP queries and print answers */
static void
send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
int delay, int num, char** qs)
send_em(const char* svr, const char* pp2_client, int udp, int usessl,
int noanswer, int onarrival, int delay, int num, char** qs)
{
sldns_buffer* buf = sldns_buffer_new(65553);
int fd = open_svr(svr, udp);
int i, wait_results = 0;
sldns_buffer* proxy_buf = sldns_buffer_new(65553);
struct sockaddr_storage svr_addr;
socklen_t svr_addrlen;
int fd = open_svr(svr, udp, &svr_addr, &svr_addrlen);
int i, wait_results = 0, pp2_parsed;
SSL_CTX* ctx = NULL;
SSL* ssl = NULL;
if(!buf) fatal_exit("out of memory");
pp2_parsed = parse_pp2_client(pp2_client, udp, proxy_buf);
if(usessl) {
ctx = connect_sslctx_create(NULL, NULL, NULL, 0);
if(!ctx) fatal_exit("cannot create ssl ctx");
@@ -361,6 +407,28 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
}
}
}
/* Send the PROXYv2 information once per stream */
if(!udp && pp2_parsed) {
if(ssl) {
if(SSL_write(ssl, (void*)sldns_buffer_begin(proxy_buf),
(int)sldns_buffer_limit(proxy_buf)) <= 0) {
log_crypto_err("cannot SSL_write");
exit(1);
}
} else {
if(send(fd, (void*)sldns_buffer_begin(proxy_buf),
sldns_buffer_limit(proxy_buf), 0) <
(ssize_t)sldns_buffer_limit(proxy_buf)) {
#ifndef USE_WINSOCK
perror("send() data failed");
#else
printf("send data: %s\n",
wsa_strerror(WSAGetLastError()));
#endif
exit(1);
}
}
}
for(i=0; i<num; i+=3) {
if (delay != 0) {
#ifdef HAVE_SLEEP
@@ -370,8 +438,9 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
#endif
}
printf("\nNext query is %s %s %s\n", qs[i], qs[i+1], qs[i+2]);
write_q(fd, udp, ssl, buf, (uint16_t)get_random(), qs[i],
qs[i+1], qs[i+2]);
write_q(fd, udp, ssl, buf, (uint16_t)get_random(), proxy_buf,
pp2_parsed,
qs[i], qs[i+1], qs[i+2]);
/* print at least one result */
if(onarrival) {
wait_results += 1; /* one more answer to fetch */
@@ -390,6 +459,7 @@ send_em(const char* svr, int udp, int usessl, int noanswer, int onarrival,
}
sock_close(fd);
sldns_buffer_free(buf);
sldns_buffer_free(proxy_buf);
printf("orderly exit\n");
}
@@ -418,10 +488,11 @@ extern int optind;
extern char* optarg;
/** main program for streamtcp */
int main(int argc, char** argv)
int main(int argc, char** argv)
{
int c;
const char* svr = "127.0.0.1";
const char* pp2_client = "";
int udp = 0;
int noanswer = 0;
int onarrival = 0;
@@ -451,11 +522,14 @@ int main(int argc, char** argv)
if(argc == 1) {
usage(argv);
}
while( (c=getopt(argc, argv, "af:hnsud:")) != -1) {
while( (c=getopt(argc, argv, "af:p:hnsud:")) != -1) {
switch(c) {
case 'f':
svr = optarg;
break;
case 'p':
pp2_client = optarg;
break;
case 'a':
onarrival = 1;
break;
@@ -508,7 +582,7 @@ int main(int argc, char** argv)
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
#endif
}
send_em(svr, udp, usessl, noanswer, onarrival, delay, argc, argv);
send_em(svr, pp2_client, udp, usessl, noanswer, onarrival, delay, argc, argv);
checklock_stop();
#ifdef USE_WINSOCK
WSACleanup();
+243
View File
@@ -25,6 +25,7 @@ struct sockaddr_storage;
#include <errno.h>
#include <stdarg.h>
#include <ctype.h>
#include <time.h>
#include "testcode/testpkts.h"
#include "util/net_help.h"
#include "sldns/sbuffer.h"
@@ -39,6 +40,8 @@ struct sockaddr_storage;
#define MAX_LINE 10240
/** string to show in warnings and errors */
static const char* prog_name = "testpkts";
/** hardcoded EDNS server cookie (RFC7876) */
static const char* hardcoded_server_cookie = "7e8b5fcc6a4bc7bc";
#ifndef UTIL_LOG_H
/** verbosity definition for compat */
@@ -140,6 +143,13 @@ static void matchline(char* line, struct entry* e)
e->match_noedns = 1;
} else if(str_keyword(&parse, "ednsdata")) {
e->match_ednsdata_raw = 1;
} else if(str_keyword(&parse, "random_client_cookie")) {
e->match_random_client_cookie = 1;
} else if (str_keyword(&parse, "random_complete_cookie_renewed")) {
e->match_random_complete_cookie = 1;
e->match_random_complete_cookie_renewed = 1;
} else if(str_keyword(&parse, "random_complete_cookie")) {
e->match_random_complete_cookie = 1;
} else if(str_keyword(&parse, "UDP")) {
e->match_transport = transport_udp;
} else if(str_keyword(&parse, "TCP")) {
@@ -263,6 +273,11 @@ static void adjustline(char* line, struct entry* e,
pkt->packet_sleep = (unsigned int) strtol(parse, (char**)&parse, 10);
while(isspace((unsigned char)*parse))
parse++;
} else if (str_keyword(&parse, "server_cookie_renew")) {
e->server_cookie = 1;
e->server_cookie_renew = 1;
} else if (str_keyword(&parse, "server_cookie")) {
e->server_cookie = 1;
} else {
error("could not parse ADJUST: '%s'", parse);
}
@@ -299,6 +314,8 @@ static struct entry* new_entry(void)
e->copy_ednsdata_assume_clientsubnet = 0;
e->increment_ecs_scope = 0;
e->sleeptime = 0;
e->server_cookie = 0;
e->server_cookie_renew = 0;
e->next = NULL;
return e;
}
@@ -1499,6 +1516,110 @@ match_ednsdata(uint8_t* q, size_t qlen, uint8_t* p, size_t plen)
return (memcmp(walk_p+8, walk_q+8, walk_qlen-8) == 0);
}
/** verify that a client cookie of length 8 is in the EDNS data of the query */
static int
match_random_client_cookie(uint8_t* query, size_t query_len)
{
uint8_t* walk_query = query;
size_t walk_query_len = query_len;
if(!pkt_find_edns_opt(&walk_query, &walk_query_len)) {
walk_query_len = 0;
log_err("no edns found");
}
/* class + ttl + rdlen = 8 */
if (walk_query_len <= 8) {
verbose(3, "No correct EDNS record found, so no cookie");
return 0;
}
/* class + ttl + rdlen + opt_code + opt_len = 12 */
if (walk_query_len < 12) {
verbose(3, "No EDNS opt found, so no cookie");
return 0;
}
if (sldns_read_uint16(walk_query+8) != 10 /* LDNS_EDNS_COOKIE */) {
verbose(3, "EDNS option is not a cookie");
return 0;
}
if (sldns_read_uint16(walk_query+10) != 8) {
verbose(3, "EDNS cookie is not 8 bytes, so not a correct client cookie");
return 0;
}
return 1;
}
/** verify that a complete EDNS cookie (client+server) (RFC9018) of length 24
* is in the EDNS data of the query and the hardcoded cookie is the same */
static int
match_random_complete_cookie(uint8_t* query, size_t query_len, struct entry* p)
{
uint8_t* walk_query = query;
size_t walk_query_len = query_len;
if(!pkt_find_edns_opt(&walk_query, &walk_query_len)) {
walk_query_len = 0;
log_err("no edns found");
}
/* class + ttl + rdlen = 8 */
if(walk_query_len <= 8) {
verbose(3, "No correct EDNS record , so no cookie");
return 0;
}
walk_query += 8;
walk_query_len -= 8;
/* opt_code + opt_len = 4 */
if (walk_query_len < 4) {
verbose(3, "No EDNS opt found, so no cookie");
return 0;
}
if (sldns_read_uint16(walk_query) != 10 /* LDNS_EDNS_COOKIE */) {
verbose(3, "EDNS option is not a cookie");
return 0;
}
if (sldns_read_uint16(walk_query+2) != 24) {
verbose(3, "EDNS cookie is not 24 bytes, so not a correct complete cookie");
return 0;
}
/* opt_code + opt_len + cookie_data = 28 */
if (walk_query_len < 28) {
verbose(3, "No complete cookie found in the packet");
return 0;
}
if (p->match_random_complete_cookie_renewed) {
uint8_t renewed_cookie[16];
/* shuffle the hardcoded cookie like adjust_packet() does */
memcpy(renewed_cookie, hardcoded_server_cookie+8, 8);
memcpy(renewed_cookie+8, hardcoded_server_cookie, 8);
/* client_cookie = 8 */
if (!(memcmp(walk_query+8, renewed_cookie, 16))) {
verbose(3, "EDNS server cookie does not match the renewed"
"cookie, so not a correct complete cookie");
return 0;
}
}
/* client_cookie = 8 */
if (!(memcmp(walk_query+8, hardcoded_server_cookie, 16))) {
verbose(3, "EDNS server cookie does not match the hardcoded cookie, "
"so not a correct complete cookie");
return 0;
}
return 1;
}
/* finds entry in list, or returns NULL */
struct entry*
find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
@@ -1594,6 +1715,16 @@ find_match(struct entry* entries, uint8_t* query_pkt, size_t len,
verbose(3, "bad EDNS data match.\n");
continue;
}
if (p->match_random_client_cookie &&
!match_random_client_cookie(query_pkt, len)) {
verbose(3, "bad client cookie match.\n");
continue;
}
if (p->match_random_complete_cookie &&
!match_random_complete_cookie(query_pkt, len, p)) {
verbose(3, "bad complete cookie match.\n");
continue;
}
if(p->match_transport != transport_any && p->match_transport != transport) {
verbose(3, "bad transport\n");
continue;
@@ -1690,6 +1821,118 @@ adjust_packet(struct entry* match, uint8_t** answer_pkt, size_t *answer_len,
if(match->copy_id && reslen >= 1 && query_len >= 1)
res[0] = query_pkt[0];
if(match->server_cookie) {
/** Find the cookie option and add the server cookie if
* the client cookie is present and not already there */
uint8_t* walk_query = query_pkt;
size_t walk_query_len = query_len;
uint8_t* walk_response;
size_t walk_response_len;
uint8_t* rdlen_ptr_response;
/* create space for the server cookie in the response packet */
res = realloc(res, reslen + 28);
reslen += 28;
walk_response = res;
walk_response_len = reslen;
if (!(walk_response)) {
log_err("testbound: out of memory; send without cookie");
return;
}
/* verify that we have a EDNS record */
if(!pkt_find_edns_opt(&walk_query, &walk_query_len)) {
walk_query_len = 0;
log_err("testbound: no EDNS in the query packet when "
"trying to attach a EDNS cookie");
}
if(!pkt_find_edns_opt(&walk_response, &walk_response_len)) {
walk_response_len = 0;
log_err("testbound: no EDNS in the response packet when"
"trying to attach a EDNS cookie");
}
/* verify that we have a EDNS option */
if (walk_query_len < 12) /* class + ttl + rdlen + opt_code + opt_len */ {
/* invalid or no (OPT) record in the query */
walk_query_len = 0;
log_err("testbound: invalid or no OPT record in the query packet");
}
if (walk_response_len < 8) /* class + ttl + rdlen */ {
walk_response_len = 0;
log_err("testbound: invalid OPT record in the response packet");
}
/* store the location of the rdlen */
rdlen_ptr_response = walk_response + 6;
/* skip past the OPT record to get to the option */
walk_query += 8;
walk_query_len -= 8;
walk_response += 8;
walk_response_len -= 8;
/* verify that the client cookie exists */
if (walk_query_len < 12 /* opt_code + opt_len + client cookie */) {
walk_query_len = 0;
log_err("testbound: no EDNS cookie in the query packet");
}
/* assume one record in the query */
if (sldns_read_uint16(walk_query) != 10 /* LDNS_EDNS_COOKIE */ ||
!(sldns_read_uint16(walk_query+2) == 8 || /* client cookie length */
sldns_read_uint16(walk_query+2) == 24)) { /* client+server cookie */
/* incorrect cookie */
walk_query_len = 0;
log_err("testbound: invalid EDNS cookie in the query packet");
}
if (walk_query_len > 0 && walk_response_len > 0) {
/* create space for the cookie, as the length of the
* rest of the response is 0 */
/* depending on the incoming cookie, add the server cookie
* or copy the complete cookie to the response */
if (sldns_read_uint16(walk_query+2) == 8) {
/* copy the EDNS client cookie from the query
* packet to the response */
memmove(walk_response, walk_query, 12);
/* add the server cookie to the client cookie to make it
* 'complete'. we fake the siphash specified in RFC9018
* by hardcoding the server cookie */
memmove(walk_response+12, hardcoded_server_cookie, 16);
/* update the RDLEN and OPTLEN */
sldns_write_uint16(rdlen_ptr_response, 28);
sldns_write_uint16(walk_response+2, 24);
} else if (sldns_read_uint16(walk_query+2) == 24) {
/* update the RDLEN */
sldns_write_uint16(rdlen_ptr_response, 28);
/* we fake verification of the cookie and send
* it back like it's still valid. We renew the cookie
* if this desired */
if (match->server_cookie_renew) {
/* copy the cookie from the response but add a
* different cookie (by reshuffeling server cookie) */
memmove(walk_response, walk_query, 12);
memmove(walk_response+12, walk_query+12+8, 8);
memmove(walk_response+12+8, walk_query+12, 8);
} else {
memmove(walk_response, walk_query, 28);
}
} else {
log_err("testbound: the incoming EDNS cookie has the wrong length");
}
} else {
log_err("testbound: an error has occured while parsing the EDNS cookie");
}
}
if(match->copy_ednsdata_assume_clientsubnet) {
/** Assume there is only one EDNS option, which is ECS.
* Copy source mask from query to scope mask in reply. Assume
+16
View File
@@ -214,6 +214,14 @@ struct entry {
uint8_t match_noedns;
/** match edns data field given in hex */
uint8_t match_ednsdata_raw;
/** match an EDNS cookie (RFC7873) of length 8*/
uint8_t match_random_client_cookie;
/** match an EDNS cookie (RFC7873) of length 24, we call
* this "complete" (RFC9018) */
uint8_t match_random_complete_cookie;
/** match an EDNS compelete cookie (RFC7873) of length 24, which cannot be
* the same as the hardcoded client cookie */
uint8_t match_random_complete_cookie_renewed;
/** match query serial with this value. */
uint32_t ixfr_soa_serial;
/** match on UDP/TCP */
@@ -237,6 +245,14 @@ struct entry {
/** in seconds */
unsigned int sleeptime;
/** add a server cookie (RFC9018) to the response (provided the query
* contains a client cookie) */
uint8_t server_cookie;
/** renew the server cookie (RFC9018) to the response (provided the query
* contains a client cookie) by shuffling the bytes in the server cookie
* Note that this also sets "server_cookie" to 1*/
uint8_t server_cookie_renew;
/** some number that names this entry, line number in file or so */
int lineno;
+3 -3
View File
@@ -173,7 +173,7 @@ static void consistency_test(void)
for (i = 0; i < 1000; i++) {
l = randomkey(&k, 128);
elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));
addrtree_insert(t, k, l, 64, elem, timenow + 10, timenow);
addrtree_insert(t, k, l, 64, elem, timenow + 10, timenow, 0);
/* This should always hold because no items ever expire. They
* could be overwritten, though. */
unit_assert( count <= t->node_count );
@@ -189,7 +189,7 @@ static void consistency_test(void)
for (i = 0; i < 1000; i++) {
l = randomkey(&k, 128);
elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));
addrtree_insert(t, k, l, 64, elem, i + 10, i);
addrtree_insert(t, k, l, 64, elem, i + 10, i, 0);
free(k);
unit_assert( !addrtree_inconsistent(t) );
}
@@ -201,7 +201,7 @@ static void consistency_test(void)
for (i = 0; i < 1000; i++) {
l = randomkey(&k, 128);
elem = (struct reply_info *) calloc(1, sizeof(struct reply_info));
addrtree_insert(t, k, l, 64, elem, i + 10, i);
addrtree_insert(t, k, l, 64, elem, i + 10, i, 0);
unit_assert( t->node_count <= 27);
free(k);
unit_assert( !addrtree_inconsistent(t) );
+3 -1
View File
@@ -469,11 +469,12 @@ infra_test(void)
struct infra_key* k;
struct infra_data* d;
int init = 376;
struct ub_randstate* rnd = ub_initstate(NULL);
unit_show_feature("infra cache");
unit_assert(ipstrtoaddr("127.0.0.1", 53, &one, &onelen));
slab = infra_create(cfg);
slab = infra_create(cfg, rnd);
unit_assert( infra_host(slab, &one, onelen, zone, zonelen, now,
&vs, &edns_lame, &to) );
unit_assert( vs == 0 && to == init && edns_lame == 0 );
@@ -528,6 +529,7 @@ infra_test(void)
infra_delete(slab);
config_delete(cfg);
ub_randfree(rnd);
}
#include "util/random.h"
+253
View File
@@ -44,6 +44,8 @@
#include "util/random.h"
#include "services/outside_network.h"
#define MAX_TCP_WAITING_NODES 5
/** add number of new IDs to the reuse tree, randomly chosen */
static void tcpid_addmore(struct reuse_tcp* reuse,
struct outside_network* outnet, unsigned int addnum)
@@ -228,9 +230,260 @@ static void tcp_reuse_tree_list_test(void)
free(outnet.tcp_conns);
}
static void check_waiting_tcp_list(struct outside_network* outnet,
struct waiting_tcp* first, struct waiting_tcp* last, size_t total)
{
size_t i, j;
struct waiting_tcp* w = outnet->tcp_wait_first;
struct waiting_tcp* n = NULL;
if(first) unit_assert(outnet->tcp_wait_first == first);
if(last) unit_assert(outnet->tcp_wait_last == last && !last->next_waiting);
for(i=0; w; i++) {
unit_assert(i<total); /* otherwise we are looping */
unit_assert(w->on_tcp_waiting_list);
n = w->next_waiting;
for(j=0; n; j++) {
unit_assert(j<total-i-1); /* otherwise we are looping */
unit_assert(n != w);
n = n->next_waiting;
}
w = w->next_waiting;
}
}
/** clear the tcp waiting list */
static void waiting_tcp_list_clear(struct outside_network* outnet)
{
struct waiting_tcp* w = outnet->tcp_wait_first, *n = NULL;
if(!w) return;
unit_assert(outnet->tcp_wait_first);
unit_assert(outnet->tcp_wait_last);
while(w) {
n = w->next_waiting;
w->on_tcp_waiting_list = 0;
w->next_waiting = (struct waiting_tcp*)1; /* In purpose faux value */
w = n;
}
outnet->tcp_wait_first = NULL;
outnet->tcp_wait_last = NULL;
}
/** check removal of the waiting_tcp element on the given position of total
* elements */
static void check_waiting_tcp_removal(int is_pop,
struct outside_network* outnet, struct waiting_tcp* store,
size_t position, size_t total)
{
size_t i;
struct waiting_tcp* w;
waiting_tcp_list_clear(outnet);
for(i=0; i<total; i++) {
outnet_waiting_tcp_list_add(outnet, &store[i], 0);
}
check_waiting_tcp_list(outnet, &store[0], &store[total-1], total);
if(is_pop) {
w = outnet_waiting_tcp_list_pop(outnet);
unit_assert(w); /* please clang-analyser */
} else {
w = outnet->tcp_wait_first;
for(i=0; i<position; i++) {
unit_assert(w); /* please clang-analyser */
w = w->next_waiting;
}
unit_assert(w); /* please clang-analyser */
outnet_waiting_tcp_list_remove(outnet, w);
}
unit_assert(!(w->on_tcp_waiting_list || w->next_waiting));
if(position == 0 && total == 1) {
/* the list should be empty */
check_waiting_tcp_list(outnet, NULL, NULL, total-1);
} else if(position == 0) {
/* first element should be gone */
check_waiting_tcp_list(outnet, &store[1], &store[total-1], total-1);
} else if(position == total - 1) {
/* last element should be gone */
check_waiting_tcp_list(outnet, &store[0], &store[total-2], total-1);
} else {
/* an element should be gone */
check_waiting_tcp_list(outnet, &store[0], &store[total-1], total-1);
}
}
static void waiting_tcp_list_test(void)
{
size_t i = 0;
struct outside_network outnet;
struct waiting_tcp* w, *t = NULL;
struct waiting_tcp store[MAX_TCP_WAITING_NODES];
memset(&outnet, 0, sizeof(outnet));
memset(&store, 0, sizeof(store));
/* Check add first on empty list */
unit_show_func("services/outside_network.c", "outnet_waiting_tcp_list_add_first");
t = &store[i];
outnet_waiting_tcp_list_add_first(&outnet, t, 0);
check_waiting_tcp_list(&outnet, t, t, 1);
/* Check add */
unit_show_func("services/outside_network.c", "outnet_waiting_tcp_list_add");
for(i=1; i<MAX_TCP_WAITING_NODES-1; i++) {
w = &store[i];
outnet_waiting_tcp_list_add(&outnet, w, 0);
}
check_waiting_tcp_list(&outnet, t, w, MAX_TCP_WAITING_NODES-1);
/* Check add first on populated list */
unit_show_func("services/outside_network.c", "outnet_waiting_tcp_list_add_first");
w = &store[i];
t = outnet.tcp_wait_last;
outnet_waiting_tcp_list_add_first(&outnet, w, 0);
check_waiting_tcp_list(&outnet, w, t, MAX_TCP_WAITING_NODES);
/* Check removal */
unit_show_func("services/outside_network.c", "outnet_waiting_tcp_list_remove");
check_waiting_tcp_removal(0, &outnet, store, 2, 5);
check_waiting_tcp_removal(0, &outnet, store, 1, 3);
check_waiting_tcp_removal(0, &outnet, store, 0, 2);
check_waiting_tcp_removal(0, &outnet, store, 1, 2);
check_waiting_tcp_removal(0, &outnet, store, 0, 1);
/* Check pop */
unit_show_func("services/outside_network.c", "outnet_waiting_tcp_list_pop");
check_waiting_tcp_removal(1, &outnet, store, 0, 3);
check_waiting_tcp_removal(1, &outnet, store, 0, 2);
check_waiting_tcp_removal(1, &outnet, store, 0, 1);
}
static void check_reuse_write_wait(struct reuse_tcp* reuse,
struct waiting_tcp* first, struct waiting_tcp* last, size_t total)
{
size_t i, j;
struct waiting_tcp* w = reuse->write_wait_first;
struct waiting_tcp* n = NULL;
if(first) unit_assert(reuse->write_wait_first == first && !first->write_wait_prev);
if(last) unit_assert(reuse->write_wait_last == last && !last->write_wait_next);
/* check one way */
for(i=0; w; i++) {
unit_assert(i<total); /* otherwise we are looping */
unit_assert(w->write_wait_queued);
n = w->write_wait_next;
for(j=0; n; j++) {
unit_assert(j<total-i-1); /* otherwise we are looping */
unit_assert(n != w);
n = n->write_wait_next;
}
w = w->write_wait_next;
}
/* check the other way */
w = reuse->write_wait_last;
for(i=0; w; i++) {
unit_assert(i<total); /* otherwise we are looping */
unit_assert(w->write_wait_queued);
n = w->write_wait_prev;
for(j=0; n; j++) {
unit_assert(j<total-i-1); /* otherwise we are looping */
unit_assert(n != w);
n = n->write_wait_prev;
}
w = w->write_wait_prev;
}
}
/** clear the tcp waiting list */
static void reuse_write_wait_clear(struct reuse_tcp* reuse)
{
struct waiting_tcp* w = reuse->write_wait_first, *n = NULL;
if(!w) return;
unit_assert(reuse->write_wait_first);
unit_assert(reuse->write_wait_last);
while(w) {
n = w->write_wait_next;
w->write_wait_queued = 0;
w->write_wait_next = (struct waiting_tcp*)1; /* In purpose faux value */
w->write_wait_prev = (struct waiting_tcp*)1; /* In purpose faux value */
w = n;
}
reuse->write_wait_first = NULL;
reuse->write_wait_last = NULL;
}
/** check removal of the reuse_write_wait element on the given position of total
* elements */
static void check_reuse_write_wait_removal(int is_pop,
struct reuse_tcp* reuse, struct waiting_tcp* store,
size_t position, size_t total)
{
size_t i;
struct waiting_tcp* w;
reuse_write_wait_clear(reuse);
for(i=0; i<total; i++) {
reuse_write_wait_push_back(reuse, &store[i]);
}
check_reuse_write_wait(reuse, &store[0], &store[total-1], total);
if(is_pop) {
w = reuse_write_wait_pop(reuse);
} else {
w = reuse->write_wait_first;
for(i=0; i<position; i++) w = w->write_wait_next;
reuse_write_wait_remove(reuse, w);
}
unit_assert(!(w->write_wait_queued || w->write_wait_next || w->write_wait_prev));
if(position == 0 && total == 1) {
/* the list should be empty */
check_reuse_write_wait(reuse, NULL, NULL, total-1);
} else if(position == 0) {
/* first element should be gone */
check_reuse_write_wait(reuse, &store[1], &store[total-1], total-1);
} else if(position == total - 1) {
/* last element should be gone */
check_reuse_write_wait(reuse, &store[0], &store[total-2], total-1);
} else {
/* an element should be gone */
check_reuse_write_wait(reuse, &store[0], &store[total-1], total-1);
}
}
static void reuse_write_wait_test(void)
{
size_t i;
struct reuse_tcp reuse;
struct waiting_tcp store[MAX_TCP_WAITING_NODES];
struct waiting_tcp* w;
memset(&reuse, 0, sizeof(reuse));
memset(&store, 0, sizeof(store));
/* Check adding */
unit_show_func("services/outside_network.c", "reuse_write_wait_push_back");
for(i=0; i<MAX_TCP_WAITING_NODES; i++) {
w = &store[i];
reuse_write_wait_push_back(&reuse, w);
}
check_reuse_write_wait(&reuse, &store[0], w, MAX_TCP_WAITING_NODES);
/* Check removal */
unit_show_func("services/outside_network.c", "reuse_write_wait_remove");
check_reuse_write_wait_removal(0, &reuse, store, 2, 5);
check_reuse_write_wait_removal(0, &reuse, store, 1, 3);
check_reuse_write_wait_removal(0, &reuse, store, 0, 2);
check_reuse_write_wait_removal(0, &reuse, store, 1, 2);
check_reuse_write_wait_removal(0, &reuse, store, 0, 1);
/* Check pop */
unit_show_func("services/outside_network.c", "reuse_write_wait_pop");
check_reuse_write_wait_removal(1, &reuse, store, 0, 3);
check_reuse_write_wait_removal(1, &reuse, store, 0, 2);
check_reuse_write_wait_removal(1, &reuse, store, 0, 1);
}
void tcpreuse_test(void)
{
unit_show_feature("tcp_reuse");
tcpid_test();
tcp_reuse_tree_list_test();
waiting_tcp_list_test();
reuse_write_wait_test();
}
+9
View File
@@ -103,6 +103,15 @@ for input in $PRE/testdata/*.rpl $PRE/testdata/*.crpl; do
fi
fi
# detect if cachedb is needed
if echo $cleaninput | grep cachedb >/dev/null 2>&1; then
if grep "define USE_CACHEDB 1" $PRE/config.h >/dev/null 2>&1; then
: # CACHEDB is supported
else
continue
fi
fi
if test $do_valgrind = "yes"; then
echo
if (valgrind $VALGRIND_FLAGS $PRE/testbound -p $input >tmpout 2>&1;); then
+10
View File
@@ -28,6 +28,12 @@ if grep "define UB_ON_WINDOWS 1" ../../config.h; then
else
onwin=0
fi
# detect dnscrypt
if grep "define USE_DNSCRYPT 1" ../../config.h; then
with_dnscrypt=1
else
with_dnscrypt=0
fi
# test check of config files.
for f in bad.*; do
@@ -37,6 +43,10 @@ for f in bad.*; do
echo "skipped on windows"
continue
fi
if test $f = "bad.proxy-and-dnscrypt" -a $with_dnscrypt -eq 0; then
echo "skipped; no DNSCRYPT support"
continue
fi
$PRE/unbound-checkconf $f
if test $? != 1; then
+6
View File
@@ -0,0 +1,6 @@
server:
interface: 127.0.0.1
proxy-protocol-port: 53
dnscrypt:
dnscrypt-enable: yes
dnscrypt-port: 53
+4
View File
@@ -0,0 +1,4 @@
server:
interface: 127.0.0.1
proxy-protocol-port: 53
https-port: 53
+1 -1
View File
@@ -8,7 +8,7 @@ Component:
CmdDepends:
Depends:
Help:
Pre:
Pre: 07-confroot.pre
Post:
Test: 07-confroot.test
AuxFiles:
+13
View File
@@ -0,0 +1,13 @@
# #-- 07-confroot.pre --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
if uname | grep "MINGW" >/dev/null; then
# no chroot, no need to test.
# (test fails on / and \ comparisons, by the way).
skip_test "no chroot on windows, end test"
fi
-7
View File
@@ -6,13 +6,6 @@
PRE="../.."
if uname | grep "MINGW" >/dev/null; then
# no chroot, no need to test.
# (test fails on / en \ comparisons, by the way).
echo "no chroot on windows, end test"
exit 0
fi
# create config file
cwd=`pwd -P`
subdir=$cwd/subdir
+9
View File
@@ -4,7 +4,16 @@
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
if grep FORK $PRE/config.h | grep "define" >/dev/null 2>&1; then
# nothing
:
else
skip_test "forking is not available; test skipped."
fi
get_random_port 2
FWD_PORT=$(($RND_PORT + 1))
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
-8
View File
@@ -7,14 +7,6 @@
PRE="../.."
. ../common.sh
if grep FORK $PRE/config.h | grep "define" >/dev/null 2>&1; then
# nothing
:
else
echo "forking is not available; test skipped."
exit 0
fi
# test if fwder is up
echo "> dig @127.0.0.1 -p $FWD_PORT www.example.com | tee outfile"
dig @127.0.0.1 -p $FWD_PORT www.example.com | tee outfile
+140
View File
@@ -0,0 +1,140 @@
server:
verbosity: 7
use-syslog: no
directory: ""
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
use-caps-for-id: no
define-tag: "one two refuse"
# Interface configuration for IPv4
interface: @IPV4_ADDR@@@PORT_ALLOW@
interface: @IPV4_ADDR@@@PORT_DENY@
interface: @IPV4_ADDR@@@PORT_REFUSE@
interface: @IPV4_ADDR@@@PORT_TAG_1@
interface: @IPV4_ADDR@@@PORT_TAG_2@
interface: @IPV4_ADDR@@@PORT_TAG_3@
interface: @IPV4_ADDR@@@PORT_VIEW_INT@
interface: @IPV4_ADDR@@@PORT_VIEW_EXT@
interface: @IPV4_ADDR@@@PORT_VIEW_INTEXT@
interface-action: @IPV4_ADDR@@@PORT_ALLOW@ allow
interface-action: @IPV4_ADDR@@@PORT_DENY@ deny
# interface-action: @IPV4_ADDR@@@PORT_REFUSE@ refuse # This is the default action
interface-action: @IPV4_ADDR@@@PORT_TAG_1@ allow
interface-action: @IPV4_ADDR@@@PORT_TAG_2@ allow
interface-action: @IPV4_ADDR@@@PORT_TAG_3@ allow
interface-action: @IPV4_ADDR@@@PORT_VIEW_INT@ allow
interface-action: @IPV4_ADDR@@@PORT_VIEW_EXT@ allow
interface-action: @IPV4_ADDR@@@PORT_VIEW_INTEXT@ allow
interface-tag: @IPV4_ADDR@@@PORT_TAG_1@ "one"
interface-tag: @IPV4_ADDR@@@PORT_TAG_2@ "two"
interface-tag: @IPV4_ADDR@@@PORT_TAG_3@ "refuse"
interface-tag-action: @IPV4_ADDR@@@PORT_TAG_1@ one redirect
interface-tag-data: @IPV4_ADDR@@@PORT_TAG_1@ one "A 1.1.1.1"
interface-tag-action: @IPV4_ADDR@@@PORT_TAG_2@ two redirect
interface-tag-data: @IPV4_ADDR@@@PORT_TAG_2@ two "A 2.2.2.2"
interface-tag-action: @IPV4_ADDR@@@PORT_TAG_3@ refuse always_refuse
interface-view: @IPV4_ADDR@@@PORT_VIEW_INT@ "int"
interface-view: @IPV4_ADDR@@@PORT_VIEW_EXT@ "ext"
interface-view: @IPV4_ADDR@@@PORT_VIEW_INTEXT@ "intext"
# Mirrored interface configuration for IPv6
interface: @IPV6_ADDR@@@PORT_ALLOW@
interface: @IPV6_ADDR@@@PORT_DENY@
interface: @IPV6_ADDR@@@PORT_REFUSE@
interface: @IPV6_ADDR@@@PORT_TAG_1@
interface: @IPV6_ADDR@@@PORT_TAG_2@
interface: @IPV6_ADDR@@@PORT_TAG_3@
interface: @IPV6_ADDR@@@PORT_VIEW_INT@
interface: @IPV6_ADDR@@@PORT_VIEW_EXT@
interface: @IPV6_ADDR@@@PORT_VIEW_INTEXT@
interface-action: @IPV6_ADDR@@@PORT_ALLOW@ allow
interface-action: @IPV6_ADDR@@@PORT_DENY@ deny
# interface-action: @IPV6_ADDR@@@PORT_REFUSE@ refuse # This is the default action
interface-action: @IPV6_ADDR@@@PORT_TAG_1@ allow
interface-action: @IPV6_ADDR@@@PORT_TAG_2@ allow
interface-action: @IPV6_ADDR@@@PORT_TAG_3@ allow
interface-action: @IPV6_ADDR@@@PORT_VIEW_INT@ allow
interface-action: @IPV6_ADDR@@@PORT_VIEW_EXT@ allow
interface-action: @IPV6_ADDR@@@PORT_VIEW_INTEXT@ allow
interface-tag: @IPV6_ADDR@@@PORT_TAG_1@ "one"
interface-tag: @IPV6_ADDR@@@PORT_TAG_2@ "two"
interface-tag: @IPV6_ADDR@@@PORT_TAG_3@ "refuse"
interface-tag-action: @IPV6_ADDR@@@PORT_TAG_1@ one redirect
interface-tag-data: @IPV6_ADDR@@@PORT_TAG_1@ one "A 1.1.1.1"
interface-tag-action: @IPV6_ADDR@@@PORT_TAG_2@ two redirect
interface-tag-data: @IPV6_ADDR@@@PORT_TAG_2@ two "A 2.2.2.2"
interface-tag-action: @IPV6_ADDR@@@PORT_TAG_3@ refuse always_refuse
interface-view: @IPV6_ADDR@@@PORT_VIEW_INT@ "int"
interface-view: @IPV6_ADDR@@@PORT_VIEW_EXT@ "ext"
interface-view: @IPV6_ADDR@@@PORT_VIEW_INTEXT@ "intext"
# Mirrored interface configuration for interface name
interface: @INTERFACE@@@PORT_ALLOW@
interface: @INTERFACE@@@PORT_DENY@
interface: @INTERFACE@@@PORT_REFUSE@
interface: @INTERFACE@@@PORT_TAG_1@
interface: @INTERFACE@@@PORT_TAG_2@
interface: @INTERFACE@@@PORT_TAG_3@
interface: @INTERFACE@@@PORT_VIEW_INT@
interface: @INTERFACE@@@PORT_VIEW_EXT@
interface: @INTERFACE@@@PORT_VIEW_INTEXT@
interface-action: @INTERFACE@@@PORT_ALLOW@ allow
interface-action: @INTERFACE@@@PORT_DENY@ deny
# interface-action: @INTERFACE@@@PORT_REFUSE@ refuse # This is the default action
interface-action: @INTERFACE@@@PORT_TAG_1@ allow
interface-action: @INTERFACE@@@PORT_TAG_2@ allow
interface-action: @INTERFACE@@@PORT_TAG_3@ allow
interface-action: @INTERFACE@@@PORT_VIEW_INT@ allow
interface-action: @INTERFACE@@@PORT_VIEW_EXT@ allow
interface-action: @INTERFACE@@@PORT_VIEW_INTEXT@ allow
interface-tag: @INTERFACE@@@PORT_TAG_1@ "one"
interface-tag: @INTERFACE@@@PORT_TAG_2@ "two"
interface-tag: @INTERFACE@@@PORT_TAG_3@ "refuse"
interface-tag-action: @INTERFACE@@@PORT_TAG_1@ one redirect
interface-tag-data: @INTERFACE@@@PORT_TAG_1@ one "A 1.1.1.1"
interface-tag-action: @INTERFACE@@@PORT_TAG_2@ two redirect
interface-tag-data: @INTERFACE@@@PORT_TAG_2@ two "A 2.2.2.2"
interface-tag-action: @INTERFACE@@@PORT_TAG_3@ refuse always_refuse
interface-view: @INTERFACE@@@PORT_VIEW_INT@ "int"
interface-view: @INTERFACE@@@PORT_VIEW_EXT@ "ext"
interface-view: @INTERFACE@@@PORT_VIEW_INTEXT@ "intext"
# Local zones configuration
local-zone: local. transparent
local-data: "local. A 0.0.0.0"
local-zone-tag: local. "one two refuse"
# Views configuration
view:
name: "int"
view-first: yes
local-zone: "." refuse
local-zone: "internal" transparent
view:
name: "ext"
view-first: yes
local-zone: "internal" refuse
view:
name: "intext"
view-first: yes
# Stubs configuration
forward-zone:
name: "."
forward-addr: @IPV4_ADDR@@@FORWARD_PORT@
stub-zone:
name: "internal"
stub-addr: @IPV4_ADDR@@@STUB_PORT@
+16
View File
@@ -0,0 +1,16 @@
BaseName: acl_interface
Version: 1.0
Description: Check the interface-* settings
CreationDate: Fri 8 Oct 18:14:40 CEST 2021
Maintainer:
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: acl_interface.pre
Post: acl_interface.post
Test: acl_interface.test
AuxFiles:
Passed:
Failure:
+11
View File
@@ -0,0 +1,11 @@
# #-- acl_interface.post --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# source the test var file when it's there
[ -f .tpkg.var.test ] && source .tpkg.var.test
#
# do your teardown here
. ../common.sh
kill_pid $UNBOUND_PID
kill_pid $FWD_PID
kill_pid $STUB_PID
+75
View File
@@ -0,0 +1,75 @@
# #-- acl_interface.pre--#
PRE="../.."
. ../common.sh
# This test uses the unshare utility
if test ! -x "`which unshare 2>&1`"; then
skip_test "no unshare (from util-linux package) available, skip test"
fi
get_random_port 11
PORT_ALLOW=$RND_PORT
PORT_DENY=$(($RND_PORT + 1))
PORT_REFUSE=$(($RND_PORT + 2))
PORT_TAG_1=$(($RND_PORT + 3))
PORT_TAG_2=$(($RND_PORT + 4))
PORT_TAG_3=$(($RND_PORT + 5))
PORT_VIEW_INT=$(($RND_PORT + 6))
PORT_VIEW_EXT=$(($RND_PORT + 7))
PORT_VIEW_INTEXT=$(($RND_PORT + 8))
FORWARD_PORT=$(($RND_PORT + 9))
STUB_PORT=$(($RND_PORT + 10))
IPV4_ADDR=192.168.1.1
IPV6_ADDR=2001:db8::1
INTERFACE=eth24
INTERFACE_ADDR_1=10.0.0.1
INTERFACE_ADDR_2=10.0.0.2
INTERFACE_ADDR_3=10.0.0.3
INTERFACE_ADDR_4=10.0.0.4
# make config file
sed \
-e 's/@PORT_ALLOW\@/'$PORT_ALLOW'/' \
-e 's/@PORT_DENY\@/'$PORT_DENY'/' \
-e 's/@PORT_REFUSE\@/'$PORT_REFUSE'/' \
-e 's/@PORT_TAG_1\@/'$PORT_TAG_1'/' \
-e 's/@PORT_TAG_2\@/'$PORT_TAG_2'/' \
-e 's/@PORT_TAG_3\@/'$PORT_TAG_3'/' \
-e 's/@PORT_VIEW_INT\@/'$PORT_VIEW_INT'/' \
-e 's/@PORT_VIEW_EXT\@/'$PORT_VIEW_EXT'/' \
-e 's/@PORT_VIEW_INTEXT\@/'$PORT_VIEW_INTEXT'/' \
-e 's/@FORWARD_PORT\@/'$FORWARD_PORT'/' \
-e 's/@STUB_PORT\@/'$STUB_PORT'/' \
-e 's/@IPV4_ADDR\@/'$IPV4_ADDR'/' \
-e 's/@IPV6_ADDR\@/'$IPV6_ADDR'/' \
-e 's/@INTERFACE\@/'$INTERFACE'/' \
< acl_interface.conf > ub.conf
if test -x "`which bash`"; then
shell="bash"
else
shell="sh"
fi
echo "PORT_ALLOW=$PORT_ALLOW" >> .tpkg.var.test
echo "PORT_DENY=$PORT_DENY" >> .tpkg.var.test
echo "PORT_REFUSE=$PORT_REFUSE" >> .tpkg.var.test
echo "PORT_TAG_1=$PORT_TAG_1" >> .tpkg.var.test
echo "PORT_TAG_2=$PORT_TAG_2" >> .tpkg.var.test
echo "PORT_TAG_3=$PORT_TAG_3" >> .tpkg.var.test
echo "PORT_VIEW_INT=$PORT_VIEW_INT" >> .tpkg.var.test
echo "PORT_VIEW_EXT=$PORT_VIEW_EXT" >> .tpkg.var.test
echo "PORT_VIEW_INTEXT=$PORT_VIEW_INTEXT" >> .tpkg.var.test
echo "FORWARD_PORT=$FORWARD_PORT" >> .tpkg.var.test
echo "STUB_PORT=$STUB_PORT" >> .tpkg.var.test
echo "IPV4_ADDR=$IPV4_ADDR" >> .tpkg.var.test
echo "IPV6_ADDR=$IPV6_ADDR" >> .tpkg.var.test
echo "INTERFACE=$INTERFACE" >> .tpkg.var.test
echo "INTERFACE_ADDR_1=$INTERFACE_ADDR_1" >> .tpkg.var.test
echo "INTERFACE_ADDR_2=$INTERFACE_ADDR_2" >> .tpkg.var.test
echo "INTERFACE_ADDR_3=$INTERFACE_ADDR_3" >> .tpkg.var.test
echo "INTERFACE_ADDR_4=$INTERFACE_ADDR_4" >> .tpkg.var.test
echo "shell=$shell" >> .tpkg.var.test
+11
View File
@@ -0,0 +1,11 @@
# #-- acl_interface.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
# Run the scenario in an unshared namespace
unshare -rUn $shell acl_interface.test.scenario
exit $?
+205
View File
@@ -0,0 +1,205 @@
# #-- acl_interface.test.scenario --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
ip addr add $IPV4_ADDR dev lo
ip addr add $IPV6_ADDR dev lo
ip link set lo up
ip link add $INTERFACE type dummy
ip addr add $INTERFACE_ADDR_1 dev $INTERFACE
ip addr add $INTERFACE_ADDR_2 dev $INTERFACE
ip addr add $INTERFACE_ADDR_3 dev $INTERFACE
ip addr add $INTERFACE_ADDR_4 dev $INTERFACE
ip link set $INTERFACE up
# start the forwarder in the background
get_ldns_testns
$LDNS_TESTNS -p $FORWARD_PORT acl_interface.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# start the stub in the background
$LDNS_TESTNS -p $STUB_PORT acl_interface.testns2 >fwd2.log 2>&1 &
STUB_PID=$!
echo "STUB_PID=$STUB_PID" >> .tpkg.var.test
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_ldns_testns_up fwd2.log
wait_unbound_up unbound.log
end () {
echo "> cat logfiles"
cat fwd.log
cat fwd2.log
cat unbound.log
exit $1
}
# Query for the given domain to the given port
# $1: address family [4, 6]
# $2: port
# $3: dname
query () {
addr=$IPV4_ADDR
if test "$1" -eq 6; then
addr=$IPV6_ADDR
fi
echo "> dig -p $2 $3"
dig @"$addr" -p $2 $3 | tee outfile
}
# Query for the given domain to the given port
# $1: address
# $2: port
# $3: dname
query_addr () {
echo "> dig @$1 -p $2 $3"
dig @"$1" -p $2 $3 | tee outfile
}
expect_refused () {
echo "> check answer for REFUSED"
if grep "REFUSED" outfile; then
echo "OK"
else
echo "Not OK"
end 1
fi
}
expect_external_answer () {
echo "> check external answer"
if grep "1.2.3.4" outfile; then
echo "OK"
else
echo "Not OK"
end 1
fi
}
expect_internal_answer () {
echo "> check internal answer"
if grep "10.20.30.40" outfile; then
echo "OK"
else
echo "Not OK"
end 1
fi
}
expect_tag_one_answer () {
echo "> check tag 'one' answer"
if grep "1.1.1.1" outfile; then
echo "OK"
else
echo "Not OK"
end 1
fi
}
expect_tag_two_answer () {
echo "> check tag 'two' answer"
if grep "2.2.2.2" outfile; then
echo "OK"
else
echo "Not OK"
end 1
fi
}
# do the test
for i in 4 6; do
query $i $PORT_REFUSE "www.external"
expect_refused
query $i $PORT_REFUSE "www.internal"
expect_refused
query $i $PORT_ALLOW "www.external"
expect_external_answer
query $i $PORT_ALLOW "www.internal"
expect_internal_answer
query $i $PORT_TAG_1 "local"
expect_tag_one_answer
query $i $PORT_TAG_2 "local"
expect_tag_two_answer
query $i $PORT_TAG_3 "local"
expect_refused
query $i $PORT_VIEW_INT "www.internal"
expect_internal_answer
query $i $PORT_VIEW_INT "www.external"
expect_refused
query $i $PORT_VIEW_EXT "www.internal"
expect_refused
query $i $PORT_VIEW_EXT "www.external"
expect_external_answer
query $i $PORT_VIEW_INTEXT "www.internal"
expect_internal_answer
query $i $PORT_VIEW_INTEXT "www.external"
expect_external_answer
done
for addr in $INTERFACE_ADDR_1 $INTERFACE_ADDR_2 $INTERFACE_ADDR_3 $INTERFACE_ADDR_4; do
query_addr $addr $PORT_REFUSE "www.external"
expect_refused
query_addr $addr $PORT_REFUSE "www.internal"
expect_refused
query_addr $addr $PORT_ALLOW "www.external"
expect_external_answer
query_addr $addr $PORT_ALLOW "www.internal"
expect_internal_answer
query_addr $addr $PORT_TAG_1 "local"
expect_tag_one_answer
query_addr $addr $PORT_TAG_2 "local"
expect_tag_two_answer
query_addr $addr $PORT_TAG_3 "local"
expect_refused
query_addr $addr $PORT_VIEW_INT "www.internal"
expect_internal_answer
query_addr $addr $PORT_VIEW_INT "www.external"
expect_refused
query_addr $addr $PORT_VIEW_EXT "www.internal"
expect_refused
query_addr $addr $PORT_VIEW_EXT "www.external"
expect_external_answer
query_addr $addr $PORT_VIEW_INTEXT "www.internal"
expect_internal_answer
query_addr $addr $PORT_VIEW_INTEXT "www.external"
expect_external_answer
done
end 0
+26
View File
@@ -0,0 +1,26 @@
; nameserver test file
$ORIGIN external.
$TTL 3600
ENTRY_BEGIN
MATCH opcode qtype qname
REPLY QR AA NOERROR
ADJUST copy_id
SECTION QUESTION
www IN A
SECTION ANSWER
www IN A 1.2.3.4
ENTRY_END
$ORIGIN local.
$TTL 3600
ENTRY_BEGIN
MATCH opcode qtype qname
REPLY QR AA NOERROR
ADJUST copy_id
SECTION QUESTION
@ IN A
SECTION ANSWER
@ IN A 127.0.0.1
ENTRY_END
+13
View File
@@ -0,0 +1,13 @@
; nameserver test file
$ORIGIN internal.
$TTL 3600
ENTRY_BEGIN
MATCH opcode qtype qname
REPLY QR AA NOERROR
ADJUST copy_id
SECTION QUESTION
www IN A
SECTION ANSWER
www IN A 10.20.30.40
ENTRY_END
+181
View File
@@ -0,0 +1,181 @@
; config options
server:
target-fetch-policy: "0 0 0 0 0"
qname-minimisation: no
minimal-responses: no
;serve-expired: yes
module-config: "cachedb iterator"
cachedb:
backend: "testframe"
secret-seed: "testvalue"
stub-zone:
name: "."
stub-addr: 193.0.14.129
CONFIG_END
SCENARIO_BEGIN Test cachedb store and servfail reply from cname.
; the servfail reply should not overwrite the cache contents.
; K.ROOT-SERVERS.NET.
RANGE_BEGIN 0 100
ADDRESS 193.0.14.129
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR NOERROR
SECTION QUESTION
. IN NS
SECTION ANSWER
. IN NS K.ROOT-SERVERS.NET.
SECTION ADDITIONAL
K.ROOT-SERVERS.NET. IN A 193.0.14.129
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
com. IN NS
SECTION AUTHORITY
com. IN NS a.gtld-servers.net.
SECTION ADDITIONAL
a.gtld-servers.net. IN A 192.5.6.30
ENTRY_END
RANGE_END
; a.gtld-servers.net.
RANGE_BEGIN 0 100
ADDRESS 192.5.6.30
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
example.com. IN NS
SECTION AUTHORITY
example.com. IN NS ns2.example.com.
SECTION ADDITIONAL
ns2.example.com. IN A 1.2.3.5
ENTRY_END
ENTRY_BEGIN
MATCH opcode subdomain
ADJUST copy_id copy_query
REPLY QR NOERROR
SECTION QUESTION
foo.com. IN NS
SECTION AUTHORITY
foo.com. IN NS ns.example.com.
ENTRY_END
RANGE_END
; ns2.example.com.
RANGE_BEGIN 0 20
ADDRESS 1.2.3.5
ENTRY_BEGIN
MATCH opcode qname qtype
REPLY QR AA NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. 10 IN A 1.2.3.4
ENTRY_END
RANGE_END
; ns2.example.com., now failing
RANGE_BEGIN 20 100
ADDRESS 1.2.3.5
ENTRY_BEGIN
MATCH opcode qname qtype
REPLY QR AA NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. 10 IN CNAME foo.example.com.
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
REPLY QR AA SERVFAIL
SECTION QUESTION
foo.example.com. IN A
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
REPLY QR AA SERVFAIL
SECTION QUESTION
ns2.example.com. IN A
SECTION ANSWER
ENTRY_END
ENTRY_BEGIN
MATCH opcode qname qtype
REPLY QR AA SERVFAIL
SECTION QUESTION
ns2.example.com. IN AAAA
SECTION ANSWER
ENTRY_END
RANGE_END
; get and entry in cache, to make it expired.
STEP 1 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
www.example.com. IN A
ENTRY_END
; get the answer for it
STEP 10 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA NOERROR
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. 10 IN A 1.2.3.4
ENTRY_END
; it is now expired
STEP 20 TIME_PASSES ELAPSE 20
; get a servfail in cache for the destination
STEP 30 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
foo.example.com. IN A
ENTRY_END
STEP 40 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA SERVFAIL
SECTION QUESTION
foo.example.com. IN A
ENTRY_END
; the query is now a CNAME to servfail.
; there is a valid, but expired, entry in cache.
STEP 50 QUERY
ENTRY_BEGIN
REPLY RD
SECTION QUESTION
www.example.com. IN A
ENTRY_END
STEP 60 CHECK_ANSWER
ENTRY_BEGIN
MATCH all
REPLY QR RD RA SERVFAIL
SECTION QUESTION
www.example.com. IN A
SECTION ANSWER
www.example.com. 10 IN CNAME foo.example.com.
ENTRY_END
SCENARIO_END
+1 -1
View File
@@ -7,7 +7,7 @@ Category:
Component:
Depends:
Help:
Pre:
Pre: clang-analysis.pre
Post:
Test: clang-analysis.test
AuxFiles:
+21
View File
@@ -0,0 +1,21 @@
# #-- clang-analysis.pre --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
# common functions
. ../common.sh
PRE="../.."
if test ! -x "`which clang 2>&1`"; then
skip_test "No clang in path"
fi
#echo "have clang"
# test if assertions are enabled
if grep "^#define UNBOUND_DEBUG" $PRE/config.h >/dev/null; then
:
else
skip_test "UNBOUND_DEBUG is not enabled, skip test"
# no unbound debug means no assertions, and clang analyzer uses
# the assertions to make inferences.
fi
-14
View File
@@ -7,20 +7,6 @@
. ../common.sh
PRE="../.."
if test ! -x "`which clang 2>&1`"; then
echo "No clang in path"
exit 0
fi
#echo "have clang"
# test if assertions are enabled
if grep "^#define UNBOUND_DEBUG" $PRE/config.h >/dev/null; then
:
else
echo "UNBOUND_DEBUG is not enabled, skip test"
# no unbound debug means no assertions, and clang analyzer uses
# the assertions to make inferences.
exit 0
fi
# read value from Makefile
# $1: result variable name
+8
View File
@@ -27,6 +27,7 @@
# wait_petal_up : wait for petal to come up.
# wait_nsd_up : wait for nsd to come up.
# wait_server_up_or_fail: wait for server to come up or print a failure string
# skip_test x : print message and skip test (must be called in .pre)
# kill_pid : kill a server, make sure and wait for it to go down.
@@ -109,6 +110,13 @@ skip_if_in_list () {
fi
}
# Print a message and skip the test. Must be called in the .pre file.
# $1: message to print.
skip_test () {
echo "$1"
exit 3
}
# function to get a number of random port numbers.
# $1: number of random ports.
# RND_PORT is returned as the starting port number
-3
View File
@@ -8,9 +8,6 @@
PRE="../.."
. ../common.sh
# Check if we can run the test.
. ./precheck.sh
kill_pid $FWD_PID
kill_pid $UNBOUND_PID
+5 -1
View File
@@ -8,7 +8,11 @@ PRE="../.."
. ../common.sh
# Check if we can run the test.
. ./precheck.sh
if grep "define USE_DNSCRYPT 1" $PRE/config.h; then
echo "have dnscrypt"
else
skip_test "no dnscrypt"
fi
get_random_port 3
UNBOUND_PORT=$RND_PORT
-3
View File
@@ -7,9 +7,6 @@
PRE="../.."
. ../common.sh
# Check if we can run the test.
. ./precheck.sh
# do the test
# Query plain request over DNSCrypt channel get closed
-16
View File
@@ -1,16 +0,0 @@
# dnscrypt precheck.sh
# if no dnscrypt; exit
if grep "define USE_DNSCRYPT 1" $PRE/config.h; then
echo "have dnscrypt"
else
echo "no dnscrypt"
exit 0
fi
# if no xchacha20 support in unbound; exit
if grep "define USE_DNSCRYPT_XCHACHA20 1" $PRE/config.h; then
xchacha20=1
else
xchacha20=0
fi

Some files were not shown because too many files have changed in this diff Show More