Compare commits

...
431 Commits
Author SHA1 Message Date
W.C.A. Wijngaards 8ee0bca833 - Fix stat_values.tdir test to have less test failures. 2026-08-11 10:07:38 +02:00
W.C.A. Wijngaards c58e6add2b - Fix #1492 from zacek: Data race in log_init() on
key_created/log_lock when calling ub_ctx_create()
  concurrently from multiple threads.
2026-08-11 09:42:30 +02:00
W.C.A. Wijngaards 93a56205cf - Fix #1489 from jplesnik: Replace removed Python 2 C API
macros for SWIG 4.5.0 compatibility.
2026-08-07 08:57:32 +02:00
W.C.A. Wijngaards 709f622658 Note issue number in Changlog entry. 2026-08-06 17:15:55 +02:00
akhanin-dnsfandGitHub 307fc6f062 - Fix bounds check in packed_rr_to_string, it checked the (#1488)
assembled rr length against the output string length
  dest_len, instead of against the size of the rr buffer it
  writes into. Callers in cachedump.c and remote.c pass a
  dest_len larger than that buffer.
- Unit test for packed_rr_to_string.
2026-08-06 17:04:05 +02:00
W.C.A. Wijngaards 8b33c5d7ff - Fix #1487: regression in 1.26.0, ipsecmod is now always
partly enabled.
2026-08-06 09:46:18 +02:00
W.C.A. Wijngaards 36bd52afb9 Fix typo in Changelog. 2026-08-06 09:08:33 +02:00
W.C.A. Wijngaards b7d13ff12b - Fix ##1485: the list_forwards command omits port numbers.
The list_forwards and list_stubs commands for
  unbound-control print port and tls auth name.
2026-08-06 09:08:17 +02:00
W.C.A. Wijngaards bdfcfb861f - Fix to set makedist.sh to not wget config.sub and
config.guess from git repo. The fetch times out, and the
  version from libtoolize is much more recent now than
  that it was when the wget was added.
2026-08-04 10:04:34 +02:00
W.C.A. Wijngaards b444deffd2 Note 1.26.0 release. 2026-08-04 10:01:59 +02:00
W.C.A. Wijngaards ff28b7e5cf - For #1483: The failure reason when an NSEC NXDOMAIN is
encountered when looking for an insecure delegation, is
  fixed to mention the NSEC records, instead of nonexistent
  NSEC3 records, that it attempted.
2026-07-31 09:53:47 +02:00
W.C.A. Wijngaards 79b84bbc91 - Fix #1482: DNS-over-QUIC doesn't work with simple config.
That fixes interface-automatic for use with doq service.
2026-07-30 08:24:42 +02:00
W.C.A. Wijngaards cbfc3b0342 - Tag for 1.26.0rc1. The repo continues with version 1.26.1. 2026-07-28 09:45:59 +02:00
W.C.A. Wijngaards a45da353d3 - Fix to call OPENSSL_cleanup on exit when that is defined. 2026-07-24 17:04:38 +02:00
W.C.A. Wijngaards c21e3ee929 Changelog note for #1479
- Merge #1479 from psumbera: Fix pthread detection on
  Solaris 11.4.
2026-07-24 15:35:55 +02:00
8a38bed262 Fix pthread detection on Solaris 11.4 (#1479)
AX_PTHREAD requires _REENTRANT to confirm that pthread support is enabled.
Solaris 11.4 headers no longer use the macro, and GCC 16 therefore no
longer defines it for -pthread.

Detect XPG7 support in the target headers and require _REENTRANT only on
older Solaris releases. The existing pthread compile and link test remains
the final capability check.

This follows the canonical Autoconf Archive change:
https://github.com/autoconf-archive/autoconf-archive/pull/341

Regenerate configure with Autoconf 2.71.

Tested on Solaris 11.4 with GCC 15.2 and GCC 16.1. The Autoconf Archive
change was also tested on Solaris 11.3.

Co-authored-by: Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE>
2026-07-24 15:34:18 +02:00
W.C.A. Wijngaards 7cc7a43ff6 Changelog note for #1481.
- Fix #1481: Fix to use tls-port after referral if
  tls-upstream is set.
2026-07-24 15:32:20 +02:00
W.C.A. Wijngaards 9bd8df0149 - Fix to use tls-port after referral if tls-upstream is set. 2026-07-24 15:31:06 +02:00
W.C.A. Wijngaards 8f7411057f - Fix sign of comparison warning in shared ports setup. 2026-07-24 14:44:44 +02:00
W.C.A. Wijngaards ca1fe4f82a - Fix to guard access to shared ports interface array during
set up, for analyzer.
2026-07-24 14:38:46 +02:00
W.C.A. Wijngaards e183c2c506 - Fix unused variable warnings in shared_ports_fetch_random
and shared_ports_return_port when compiled without threads.
2026-07-24 14:37:17 +02:00
W.C.A. Wijngaards 52b18fc6f5 Changelog entry for #1480
- Merge #1480 from petrvaganoff: authzone: fix memory leak in
  xfer_set_masters() error path.
2026-07-24 12:25:34 +02:00
Petr VaganovandGitHub e6d00725c2 authzone: fix memory leak in xfer_set_masters() error path (#1480)
Added memory deallocation for the `file` and `host` fields of the
`auth_master` node in the event of a URL/allocation error, and
unlinked the partially created node from the masters list by
resetting the link that pointed to it.

Signed-off-by: Petr Vaganov <petrvaganoff@gmail.com>
2026-07-24 12:24:49 +02:00
W.C.A. Wijngaards e597711824 - Fix lock test protect for auth zone change.
- Fix to lock shared_ports structure during initialisation.
- Fix to lock anchor structure when file is set for it in
2026-07-24 12:13:09 +02:00
W.C.A. Wijngaards e1e646c6fc - Fix to allow test fake sha1 on systems with possible sha1
support.
- Fix to use sha256 for unbound-anchor unit test.
- Fix unbound-anchor check for return value of
  X509_NAME_get_text_by_NID of the emailaddress.
2026-07-24 11:50:15 +02:00
W.C.A. Wijngaards fc3b5b4f63 - Update generated man pages. 2026-07-24 10:03:41 +02:00
W.C.A. Wijngaards 1e904a3ce5 - set code repository version to 1.26.0. 2026-07-24 09:45:49 +02:00
W.C.A. Wijngaards 79e100a7fb - Fix #1477: respip + dns64: dns64 uses A records modified by
respip instead of original A records. Adds local-zone types
  block_a_wdata and block_aaaa_wdata, that are like block_a
  and block_aaaa, and uses local-data if present.
2026-07-24 09:29:17 +02:00
W.C.A. Wijngaards a65d3d7283 - Unit test for block_a and block_aaaa. 2026-07-24 09:03:45 +02:00
W.C.A. Wijngaards 3b8766aa43 Changelog note for #1433
- Merge #1433 from jisakiel: Add new static zone type
  block_aaaa to suppress AAAA queries.
2026-07-24 08:53:30 +02:00
c8b3c89a39 Add new static zone type block_aaaa to suppress AAAA queries (#1433)
Following d5b9a790f lead for block_a - this would allow suppressing AAAA queries instead for sticking to IPV4.

Co-authored-by: Jisakiel <jisakiel@users.noreply.github.com>
2026-07-24 08:52:20 +02:00
W.C.A. Wijngaards a05d460e66 - Fix mesh cycle detection for configuration with respip CNAME
loop and tagged clients. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-07-23 16:28:45 +02:00
W.C.A. Wijngaards 5eb362a6c0 - Fix that the aggressive negative cache does not insert NSEC
records with overreaching next owner name. Also the result
  is not above the trust anchor's bailiwick. Also RRSIGS are
  not considered valid when an NSEC next owner name is not
  under the signer zone name. Thanks to Qifan Zhang, Palo
  Alto Networks, for the report.
2026-07-23 16:17:59 +02:00
W.C.A. Wijngaards 0735cb28d1 - Fix that for NSEC3 proofs the NSEC3 zone, as the b32.name is
checked to be the same as the signer name. Also RRSIGs are
  not considered valid when an NSEC3 is not b32.signerzone.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-07-23 15:54:59 +02:00
W.C.A. Wijngaards 737c28e836 Changelog entry for #1478
- Merge #1478 from petrvaganoff: pythonmod: add check return
  value after ftell().
2026-07-23 10:22:53 +02:00
Petr VaganovandGitHub 1bab2dfafa pythonmod: add check return value after ftell() (#1478)
Variable 'flen', which might receive a negative value at pythonmod.c:493
by calling function 'ftell', is used without checking at pythonmod.c:508
by calling function 'fread'.

Found by the static analyzer Svace (ISP RAS).

Signed-off-by: Petr Vaganov <petrvaganoff@gmail.com>
2026-07-23 10:22:02 +02:00
W.C.A. Wijngaards 22e2c5b6d1 - Updated credits for Xuanchao Xie in 22 july changelog. 2026-07-23 10:01:10 +02:00
W.C.A. Wijngaards 914dbfea4e - iana portlist update. 2026-07-22 14:12:34 +02:00
W.C.A. Wijngaards cf5e6e89a5 - Fix error in log printout in fix for CVE-2026-50248, when the
primary name is bogus.
2026-07-22 12:16:49 +02:00
W.C.A. Wijngaards 4941edf275 - Unit test for CVE-2026-56416. 2026-07-22 12:06:00 +02:00
W.C.A. Wijngaards b08723ef97 - Unit test for CVE-2026-55973. 2026-07-22 12:04:35 +02:00
W.C.A. Wijngaards c163fbc505 - Unit test for CVE-2026-55717. 2026-07-22 12:03:48 +02:00
W.C.A. Wijngaards eed3f1ab38 - Unit test for CVE-2026-50248. 2026-07-22 12:00:19 +02:00
W.C.A. Wijngaards 63501f51bb - Unit test for CVE-2026-50243. 2026-07-22 11:59:36 +02:00
W.C.A. Wijngaards 1ae2570bda - Unit test for CVE-2026-46582. 2026-07-22 11:58:18 +02:00
W.C.A. Wijngaards 9ad825b267 - Unit test for CVE-2026-50045. 2026-07-22 11:57:13 +02:00
W.C.A. Wijngaards 3d5e6c0692 - Unit test for CVE-2026-44690. 2026-07-22 11:56:08 +02:00
W.C.A. Wijngaards 23e19ca6fc - Unit test for CVE-2026-44687. 2026-07-22 11:55:09 +02:00
W.C.A. Wijngaards 9f757aa9f3 - Unit test for CVE-2026-42955. 2026-07-22 11:54:00 +02:00
W.C.A. Wijngaards 1df6c170ff Changelog entry for 1.25.2.
- Set the repository to 1.25.3, it continues with the previous
  changes.
2026-07-22 11:38:48 +02:00
W.C.A. Wijngaards 7a95bedc26 Fix conflict merge fixup. 2026-07-22 11:36:06 +02:00
W.C.A. Wijngaards ae685bc33d Move repo to version 1.25.3. 2026-07-22 11:34:48 +02:00
W.C.A. Wijngaards 91ac449bcd Merge branch 'branch-1.25.2' 2026-07-22 11:33:54 +02:00
W.C.A. Wijngaards c33ad1b1a2 rerun autoconf. 2026-07-22 10:21:21 +02:00
W.C.A. Wijngaards 84d9682dd0 - Fix CVE-2026-56444, Degradation of resolution service when
'discard-timeout' and 'serve-expired-client-timeout' are combined in
  unusual configuration. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report. In addition, thanks to Xin Wang, Jiapeng Li,
  and Jiajia Liu, Northwestern Polytechnical University, for also
  reporting this issue. In addition, thanks to Haruki Oyama (Waseda
  University), for also reporting this issue.
2026-07-22 10:19:50 +02:00
W.C.A. Wijngaards 4b1635e194 - Fix CVE-2026-56416, Possible heap buffer overflow when validator
canonicalizes RDATA that contains domain name. Thanks to Qifan
  Zhang, Palo Alto Networks, for the report.
2026-07-22 10:19:28 +02:00
W.C.A. Wijngaards aac261cbb3 - Fix CVE-2026-55991, Remote DNS-over-QUIC (DoQ) flow-control
assertion failure in libngtcp2. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report. In addition, thanks to Xuanchao Xie,
  for also reporting this issue.
2026-07-22 10:19:02 +02:00
W.C.A. Wijngaards ae1b3810cc - Fix CVE-2026-55990, Packet of death for a DNSCrypt misconfigured
Unbound. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-07-22 10:18:41 +02:00
W.C.A. Wijngaards 96f8755520 - Fix CVE-2026-55973, 'dns-error-reporting: yes' leads to stack buffer
overflow. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-07-22 10:18:16 +02:00
W.C.A. Wijngaards 2ce2ca3691 - Fix CVE-2026-55717, 'serve-expired-client-timeout' and 'response-ip'
CNAME redirect could lead to a crash. Thanks to Qifan Zhang, Palo
  Alto Networks, for the report. In addition, thanks to Xin Wang,
  Jiapeng Li, and Jiajia Liu, Northwestern Polytechnical University,
  for also reporting this issue.
2026-07-22 10:17:32 +02:00
W.C.A. Wijngaards c29ff70f6a - Fix CVE-2026-55708, Privacy/configuration issue when adding local
data in views through 'unbound-control'. Thanks to Qifan Zhang,
  Palo Alto Networks, for the report.
2026-07-22 10:17:10 +02:00
W.C.A. Wijngaards 8a15ffee62 - Fix CVE-2026-54478, DNS Cookie bypass when combined with
proxy-protocol use. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-07-22 10:16:42 +02:00
W.C.A. Wijngaards 8c702de175 - Fix CVE-2026-52863, Memory corruption could lead to crash and
denial of service. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-07-22 10:16:03 +02:00
W.C.A. Wijngaards 804cff4c15 - Fix CVE-2026-50252, Possible cache poisoning attack by mapping
source port population per thread. Thanks to Inbal Schussheim and
  Amit Klein, Hebrew University, for the report.
2026-07-22 10:15:31 +02:00
W.C.A. Wijngaards e180b06298 - Fix CVE-2026-50251, Attacker supplied 0.0.0.0/:: glue triggers
defensive full-cache flush. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-07-22 10:15:02 +02:00
W.C.A. Wijngaards 3530c81e29 - Fix CVE-2026-50248, BOGUS configured primary hostname accepted for
XFR in auth/rpz zones. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-07-22 10:14:35 +02:00
W.C.A. Wijngaards 02b16de1ae - Fix CVE-2026-50243, 'response-ip'/'rpz' can rewrite BOGUS answers
instead of returning SERVFAIL. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-07-22 10:14:04 +02:00
W.C.A. Wijngaards 1ad8d4c395 - Fix CVE-2026-50046, Possible heap use-after-free in an error path
when a DoT forwarded query is jostled out. Thanks to Qifan Zhang,
  Palo Alto Networks, for the report.
2026-07-22 10:13:36 +02:00
W.C.A. Wijngaards 364ac737f7 - Fix CVE-2026-50045, 'max-global-quota' reset by DNSSEC validation
restarts. Thanks to Kunjie Shang, University of Science and
  Technology of China, for the report.
2026-07-22 10:13:14 +02:00
W.C.A. Wijngaards f7637a4f18 - Fix CVE-2026-44690, Cross-zone wildcard cache poisoning via
RRSIG.labels manipulation. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-07-22 10:12:38 +02:00
W.C.A. Wijngaards 1e1940383a - Fix CVE-2026-44687, Off-by-one error in 'harden-below-nxdomain'
logic can shadow a stub/forward zone by a legitimate parent's
  NXDOMAIN. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-07-22 10:12:03 +02:00
W.C.A. Wijngaards f52a9e864b - Fix CVE-2026-44621, Libunbound applications configured with
'unwanted-reply-threshold' could eventually be abruptly
  terminated. Thanks to Qifan Zhang, Palo Alto Networks, for the
  report.
2026-07-22 10:11:26 +02:00
W.C.A. Wijngaards 13ec8d0f26 - Fix CVE-2026-42955, Extra fix for CVE-2026-40622 to also clamp
the TTL of A/AAAA records disallowing a one-time 'ghost domain'
  delegation renewal via glue records. Thanks to Qifan Zhang, Palo
  Alto Networks, for the report.
2026-07-22 10:11:04 +02:00
W.C.A. Wijngaards 27f22b8808 - Fix CVE-2026-41637, Degradation of resolution service from
improperly accounted client-terminated DNS-over-QUIC queries. Thanks
  to Qifan Zhang, Palo Alto Networks, for the report.
2026-07-22 10:10:24 +02:00
W.C.A. Wijngaards f54e0791ba - Fix CVE-2026-40691, Packet of death for DNSCrypt over TCP. Thanks
to Qifan Zhang, Palo Alto Networks, for the report. In addition,
  thanks to Trung Nguyen (@everping) of CyStack, for also reporting
  this issue.
2026-07-22 10:09:50 +02:00
W.C.A. Wijngaards 01dfd2f466 - Fix CVE-2026-32665, Remote DNS-over-QUIC denial of
service due to `quic-size` budget bypass. Thanks to N0zoM1z0
  (https://github.com/N0zoM1z0) for the report. In addition, thanks to
  Kunta Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University,
  for also reporting this issue. In addition, thanks to Qifan Zhang,
  Palo Alto Networks, for also reporting this issue. In addition,
  thanks to Xuanchao Xie, for also reporting this issue.
2026-07-22 10:09:26 +02:00
W.C.A. Wijngaards f157c691bb - Fix CVE-2026-14586, Assertion in libngtcp2 when under pressure
in high concurrency DNS-over-QUIC environments. Thanks to Kunta
  Chu, Kaihua Wang, and Jianjun Chen from Tsinghua University,
  for the report.
2026-07-22 10:08:48 +02:00
W.C.A. Wijngaards fea0ff550b - Fix CVE-2026-46582, A wildcard replay, as another piece of data,
triggers poisoning in the serve expired reply path. Thanks to
  Qifan Zhang, Palo Alto Networks, for the report.
2026-07-22 10:07:52 +02:00
W.C.A. Wijngaards 87d59bfced Set version to 1.25.2 2026-07-22 10:06:30 +02:00
W.C.A. Wijngaards 25b2543e5e Changelog note for #1476
- Merge #1476 from petrvaganoff: ipsecmod: fix possible deref
  on null after reply_find_answer_rrset().
2026-07-21 11:57:14 +02:00
Petr VaganovandGitHub 7133e0d32a ipsecmod: fix possible deref on null after reply_find_answer_rrset() (#1476)
Return value of a function 'reply_find_answer_rrset' is dereferenced at
ipsecmod.c:438 without checking for NULL, but it is usually checked for
this function (10/12).

Found by the static analyzer Svace (ISP	RAS).

Signed-off-by: Petr Vaganov <petrvaganoff@gmail.com>
2026-07-21 11:56:29 +02:00
W.C.A. Wijngaards fac7584830 - Fix #1474: DoQ responses are never padded - pad-responses
does not apply to comm_doq (RFC 9250 §5.4 MUST).
2026-07-20 10:14:26 +02:00
W.C.A. Wijngaards 87f9258fb4 Changelog entry for #1475
- Merge #1475 from petrvaganoff: ipsecmod: fix deref on null
  in ipsecmod-whitelist after OOM.
2026-07-20 10:05:45 +02:00
Petr VaganovandGitHub a2fe5356b5 ipsecmod: fix deref on null in ipsecmod-whitelist after OOM (#1475)
DEREF_OF_NULL.RET.STAT Return value of a function 'rbtree_create'
is dereferenced at ipsecmod-whitelist.c:105 without checking for
NULL, but it is usually checked for this function (5/6).

In ipsecmod_whitelist_apply_cfg(), the return value of rbtree_create()
is not checked for NULL before being used.

Found by the static analyzer Svace (ISP	RAS).

Signed-off-by: Petr Vaganov <petrvaganoff@gmail.com>
2026-07-20 10:04:47 +02:00
W.C.A. Wijngaards ad9b12a863 - Fix unit test for malformed svcb for test on Windows. 2026-07-09 09:52:09 +02:00
W.C.A. Wijngaards 61ca4111a1 Changelog note and explanation comment for #1383
- Merge #1383 from jdek: Fix randomness generation on
  macOS/iOS under chroot.
2026-07-09 09:21:56 +02:00
J. DekkerandGitHub 71a971d70c - Fix randomness generation on macOS/iOS under chroot (#1383)
SecRandomCopyBytes() has existed since macOS 10.7 (2011) and iOS 2.0 (2008), and is the primary API for cryptographic random numbers.
2026-07-09 09:19:42 +02:00
W.C.A. Wijngaards ba4f8478e6 Add changelog note for #1087, remove copyright line as discussed, and
compile fixes for newer local_zones_lookup, unused variable warnings
fixed, and also manual page description of the feature.
- Merge #1087: Overload `local_data_remove` to support removing
  specific records.
2026-07-02 15:04:51 +02:00
R. Christian McDonaldandGitHub 374a18cc5b Overload local_data_remove to support removing specific records (#1087)
Here we overload the `local_data_remove` control command to support
deleting specific records. Curently, this command deletes all records
for a given zone. The modification works by attempting to parse the
command argument first as a complete record and then as just a domain
name, if the first attempt failed.

This preserves the command's behavior, while also supporting removing
specific records from the zone tree.

Signed-off-by: R. Christian McDonald <rcm@rcm.sh>
2026-07-02 14:55:54 +02:00
W.C.A. Wijngaards f35561287a - iana portlist updated. 2026-06-30 12:38:33 +02:00
W.C.A. Wijngaards 672b9659cf - Fix #1469: dohclient: DoH POST missing content-length → :status
400 from strict resolvers (Cloudflare, Mullvad).
2026-06-30 12:14:00 +02:00
W.C.A. Wijngaards 1978add0cd - Merge #1467: daemon: fix DEREF_AFTER_NULL.EX.COND on
worker_init. This fixes error handling if the worker
  stat_timer allocation has an out of memory error. That
  makes the server not crash later, attempting to use it.
2026-06-26 13:44:27 +02:00
Petr VaganovandGitHub 6cbcea3ac7 daemon: fix DEREF_AFTER_NULL.EX.COND on worker_init (#1467)
Found by the static analyzer Svace (ISP RAS).

After having been compared to a NULL value at worker.c:2216,
pointer 'worker->stat_timer' is passed in call to function
'worker_restart_timer' at worker.c:2319,where it is
dereferenced at worker.c:2029.

Fix that stat_timer creation failure in worker_init does
not continue with a NULL timer that causes a crash later.

Signed-off-by: Petr Vaganov <petrvaganoff@gmail.com>
2026-06-26 13:42:29 +02:00
W.C.A. Wijngaards 65e23d4b6f - Merge #1465 from dag-erling: Add libunbound/remote.h. Add
a shared header containing prototypes for functions that
  both ends of a remote control connection need to implement.
2026-06-25 11:16:01 +02:00
Dag-Erling SmørgravandGitHub fbe41cdef9 Add libunbound/remote.h (#1465)
Add a shared header containing prototypes for functions that both ends
of a remote control connection need to implement.
2026-06-25 11:14:37 +02:00
W.C.A. Wijngaards 01a95108b3 - Fix warning about file_string_matches in unbound-checkconf. 2026-06-19 09:30:46 +02:00
W.C.A. Wijngaards f75d11821f - Fix to update github ci actions/checkout to v7. 2026-06-19 09:25:39 +02:00
W.C.A. Wijngaards 6aa5cfc903 - Fix for #1457: fix thread setname for thread start of
dnstap, and fast_reload.
2026-06-19 08:37:23 +02:00
Yorgos Thessalonikefs f6931c794e - Fix memory leak on DNAME 0TTL records. 2026-06-17 17:30:21 +02:00
W.C.A. Wijngaards 4c5082ad05 - Fix that fast_reload does not terminate the server if
random init for DNS cookies fails. The data is only random
  generated if cookies are enabled, and the random data
  is necessary. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-06-17 16:15:15 +02:00
W.C.A. Wijngaards 5fb892a097 - Fix that fast_reload does not terminate the server
on config read failure after malloc failure. Thanks to
  Qifan Zhang, Palo Alto Networks, for the report.
2026-06-17 16:10:48 +02:00
W.C.A. Wijngaards 55e9532d16 - Fix after malloc failure for stats, then it drains the pipe
so the internal messaging stays correct. Also it does
  not exit the server if stats pipe communication fails.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-17 16:05:45 +02:00
W.C.A. Wijngaards fff6657cea - Fix that fast_reload does not terminate the server
on malloc failure for dnstap, or if gethostname fails.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-17 16:02:21 +02:00
W.C.A. Wijngaards 45d1e75caf - Fix to check for malloc failure in rpz response create,
for nodata and nxdomain, so it does not crash later.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-17 15:59:29 +02:00
W.C.A. Wijngaards b806f16c8b - Fix to check the return value of auth_xfer_create
during fast_reload auth-zone add and change processing.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-17 15:57:30 +02:00
W.C.A. Wijngaards 8d3348c71b - Fix that malloc failure during edns subnet addrtree
insert is checked, so it does not crash later. Thanks to
  Qifan Zhang, Palo Alto Networks, for the report.
2026-06-17 15:55:33 +02:00
W.C.A. Wijngaards e2cc14681e - Fix that malloc failure for rpz_strip_nsdname is
checked and handled, so that it does not crash later.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-17 15:53:28 +02:00
W.C.A. Wijngaards 5ae979bb6e - Fix that on malloc failure during accept of TCP, the
socket is not left to cause a read event loop. It uses
  slow-accept to delay accepting new connections, if
  that fails it drops the new connections. When the tcp
  connection usage is full, it waits for 50msec, to allow
  existing queries to be resolved. Thanks to Qifan Zhang,
  Palo Alto Networks, for the report.
2026-06-17 15:37:04 +02:00
W.C.A. Wijngaards 8f2fbd66fc - Fix that malloc failure for ngtcp2_conn_server_new
cleans up reference that older ngtcp2 versions can leave.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-17 15:33:06 +02:00
W.C.A. Wijngaards b5909d8d22 - Fix that malloc failure in doq connection setup, does
not crash in doq connection delete later. Thanks to Qifan
  Zhang, Palo Alto Networks, for the report.
2026-06-17 15:29:48 +02:00
W.C.A. Wijngaards fa8e94f155 - Fix that malloc failure for new_local_rrset for RPZ qname
trigger RR insert does not crash. It does not link a
  partial RRset, and logs an error on failure, and cleans
  up the dname allocation. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-06-17 15:26:56 +02:00
W.C.A. Wijngaards cb5683aeae - Fix that malloc failure in dns64_inform_super does
not set up a half-built reply for cache store, that could
  lead to a crash. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-06-17 15:23:25 +02:00
W.C.A. Wijngaards c9715724ec - Fix that unbound-control auth_zone_reload stops the
server answering from the zone after a failure to read.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-17 15:20:22 +02:00
W.C.A. Wijngaards 78d9cfffd8 - Fix that malloc failure in auth-zone insert rr does
not create an empty node and does not cause an infinite
  loop. Thanks to Qifan Zhang, Palo Alto Networks, for
  the report.
2026-06-17 15:16:21 +02:00
W.C.A. Wijngaards b47b1d048d - Fix that unbound-checkconf checks if an auth-zone download
can overwrite another file, by filename collision.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-17 15:11:42 +02:00
W.C.A. Wijngaards 740952fb82 - Fix to remove debug from auth_transfer_limit test. 2026-06-17 11:38:24 +02:00
W.C.A. Wijngaards 5c550f4548 - Fix that after fast_reload the disown of the auth zone
transfer task cleans the chunk list. Also fix the
  auth_transfer_limit test to use a forwarder for each type
  of failure, so the one is not blocked by the other waiting.
2026-06-17 11:37:06 +02:00
W.C.A. Wijngaards 3d78cb8d9a - Fix for #1462: Fix that auth primary host name lookup
allows CNAMEs.
2026-06-16 11:13:47 +02:00
W.C.A. Wijngaards 1ab75c0043 - Fix after malloc failure the rrset_insert_rr in
localzone processing, during RPZ qname trigger processing,
  the RRset retains its previous data correcly. Thanks to
  Qifan Zhang, Palo Alto Networks, for the report.
2026-06-16 10:59:37 +02:00
W.C.A. Wijngaards bebc8d516b - Fix incorrect cleanup after an allocation failure for
a delegation point in a region. Thanks to Qifan Zhang,
  Palo Alto Networks, for the report.
2026-06-16 10:56:36 +02:00
W.C.A. Wijngaards a7debe7ff6 - Fix that after shared memory cannot be created, from
`shm-enable`, the server does not crash. Thanks to Qifan
  Zhang, Palo Alto Networks, for the report.
2026-06-16 10:53:40 +02:00
W.C.A. Wijngaards 215e3920ef - Fix that after malloc failure in find_tag_datas, the
local_alias is cleaned up. Thanks to Qifan Zhang, Palo
  Alto Networks, for the report.
2026-06-16 10:51:49 +02:00
W.C.A. Wijngaards aabf28aef5 - Fix incorrect cleanup after an allocation failure for
a delegation point. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-06-16 10:49:50 +02:00
W.C.A. Wijngaards aa09835c90 - Fix for neater solution to clear log thread id after
worker init failure. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-06-16 10:48:17 +02:00
W.C.A. Wijngaards 9b9e13b665 - Fix that libunbound pipe functions fail with error after
an event base is set. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-06-16 10:44:41 +02:00
W.C.A. Wijngaards f72e11ef5b - Fix locking in libunbound ub_ctx_set_event call.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-16 10:42:39 +02:00
W.C.A. Wijngaards a45e54555d - Fix that dnscrypt configuration does not crash, due to
inconsistency between secret and public keys. Also
  duplicate files are skipped. Thanks to Qifan Zhang, Palo
  Alto Networks, for the report.
2026-06-16 10:40:10 +02:00
W.C.A. Wijngaards 4693c00c9f - Fix that after malloc failure in RPZ load a half built
list does not crash later. The newly created RRset is
  linked after creation has succeeded. Thanks to Qifan Zhang,
  Palo Alto Networks, for the report.
2026-06-16 10:35:41 +02:00
W.C.A. Wijngaards 8fe23e0297 - Fix that for a zonefile only zone, if that file does not
exist on server start, the server continues to start with
  a warning log message. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-06-16 10:26:25 +02:00
W.C.A. Wijngaards 8557788699 - Fix that after malloc failure a half-built local_alias does
not crash the server. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-06-16 10:12:19 +02:00
W.C.A. Wijngaards 81a19ebeb3 - Fix that a signed wildcard NSEC, is checked before use,
so it does not allow insecure DS proofs inappropriately.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-16 10:09:00 +02:00
W.C.A. Wijngaards 299df5ec77 - Fix that dns64 does not ignore the forward-no-cache and
`stub-no-cache` options. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-06-16 09:52:46 +02:00
W.C.A. Wijngaards 6f9b6db7be - Fix that auth-zone, and RPZ zones, do not allow out-of-zone
records. These are records that are not under the zone apex.
  The out-of-zone records are dropped from the zone contents.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-16 09:48:10 +02:00
W.C.A. Wijngaards 96f15b9160 - Fix that a half-written trust anchor file does not crash
the server at runtime. It unlinks a wrong file from the list.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-16 09:45:10 +02:00
W.C.A. Wijngaards 159384c2a9 - Fix that when SVCB records cannot be written out, and
are written in unknown format, that the zone read allows
  such unknown format SVCB records. Thanks to Qifan Zhang,
  Palo Alto Networks, for the report.
2026-06-16 09:36:33 +02:00
W.C.A. Wijngaards 621fc91453 - Fix to disallow $INCLUDE for secondary zones. Start up
of server continues if a secondary zone fails to load.
  Failed loads clear the zone data, so there is no partial
  zone. Thanks to Qifan Zhang, Palo Alto Networks, for
  the report.
2026-06-16 09:30:52 +02:00
W.C.A. Wijngaards 543c49f76c - Fix that dns64 bypasses rpz-passthru rule during
synthesis. This restricted more than necessary. Thanks to
  Qifan Zhang, Palo Alto Networks, for the report.
2026-06-15 16:50:42 +02:00
W.C.A. Wijngaards d0a760a587 - Fix misconfigured ipsecmod hook causing path name
similarity with other file. The ipsecmod is changed for
  exec of the hook. The ipsecmod hook, if a script, has to
  start now with a line like `#!/bin/sh`. Thanks to Qifan
  Zhang, Palo Alto Networks, for the report.
2026-06-15 16:45:53 +02:00
W.C.A. Wijngaards f68cca4097 - Fix DNAME synthesis from cache that keeps use of 0TTL
entries in a sliding window. It did not surpass RRSIG
  expiry. Thanks to Qifan Zhang, Palo Alto Networks, for
  the report.
2026-06-15 16:39:34 +02:00
W.C.A. Wijngaards 3129357874 - Fix log of an aliased qname, to not use freed region
memory. Thanks to Qifan Zhang, Palo Alto Networks, for
  the report.
2026-06-15 16:34:17 +02:00
W.C.A. Wijngaards fc09352df6 - Fix that fast_reload does not terminate the server for
errors in config, for key files. Thanks to Qifan Zhang,
  Palo Alto Networks, for the report.
2026-06-15 16:31:37 +02:00
W.C.A. Wijngaards 06da5d45a3 - Fix integer overflow for very high values of
`sock-queue-timeout`. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-06-15 16:28:30 +02:00
W.C.A. Wijngaards 69524cadad - Fix erroneous DNS error report values after bogus AAAA
query caused error information that was not cleared by
  a successful A subquery. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-06-15 16:26:35 +02:00
W.C.A. Wijngaards 98e95d80e6 - Fix integer overflow in infra-cache-max-rtt calculation.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-15 16:22:50 +02:00
W.C.A. Wijngaards 2f8aa8a43a - Fix for fast_reload that removes an auth zone while its
lookups are in progress, for a primary name. Also after the
  change, it no longer picks up the old results. Thanks to
  Qifan Zhang, Palo Alto Networks, for the report.
2026-06-15 16:18:56 +02:00
W.C.A. Wijngaards 56e60e37ae - Fix that fast_reload when a zonemd verification lookup
it in progress with subnet loaded, deregisters the
  callback. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-06-15 16:16:50 +02:00
W.C.A. Wijngaards 8f5348ab47 - Fix that misconfigured iter-scrub-ns: 0 causes request
failures. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-06-15 16:04:24 +02:00
W.C.A. Wijngaards c5d693b21c - Fix buffer overflow when configured with lower than
default size and http transfer. Thanks to Qifan Zhang,
  Palo Alto Networks, for the report.
2026-06-15 16:01:51 +02:00
W.C.A. Wijngaards 27e3ac55b9 - Fix assertion failure for long HTTP header that fills
buffer. Thanks to Qifan Zhang, Palo Alto Networks, for
  the report.
2026-06-15 15:54:37 +02:00
W.C.A. Wijngaards 7879218773 Fix comment. 2026-06-15 15:53:00 +02:00
W.C.A. Wijngaards 1354624ba4 - Fix perform a full transfer every number of incremental
transfers, to stop increasing memory usage, for auth-zone
  and rpz zones. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-06-15 15:51:03 +02:00
W.C.A. Wijngaards 153f8d5353 - Fix to add max-transfer-size and max-transfer-time that
limit auth-zone and rpz transfer amount and time taken.
  Default is disabled. This hardens against unbounded
  transfers. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-06-15 15:45:03 +02:00
W.C.A. Wijngaards a1cecf7462 - Fix that for auth-zone and rpz zones the allow-notify
addresses and netblocks are available from start, and
  fix the probe step skip.
2026-06-12 11:48:14 +02:00
W.C.A. Wijngaards e2dac8a00a - Fix compile for OpenSSL 1.0.2 and before in server cleanup. 2026-06-11 17:31:19 +02:00
W.C.A. Wijngaards ecd41bef27 - Fix #1437: Fix compile with OpenSSL 4.0.1. 2026-06-11 17:31:01 +02:00
W.C.A. Wijngaards fd2131687a - Fix for #1306: configure checks if the ngtcp2_crypto_ossl
header file is available, and prints an error otherwise.
2026-06-11 11:43:46 +02:00
W.C.A. Wijngaards 316b9ab4fc - Fix for #1306: configure detects specifically the call to
SSL_set_quic_tls_early_data_enabled and
  SSL_set_quic_early_data_enabled, so the correct one is used.
2026-06-11 11:04:50 +02:00
W.C.A. Wijngaards d45daaf313 - Fix warnings with gcc in compat/inet_pton.c. 2026-06-10 16:43:41 +02:00
W.C.A. Wijngaards db1c6d6557 - Fix pythonmod script read for numeric overflow. 2026-06-10 11:24:02 +02:00
W.C.A. Wijngaards e7a713a525 - Fix unit test for ecs to check for malloc success. 2026-06-09 16:41:37 +02:00
Alex BandandGitHub 39e67508c9 change mailing list to forum 2026-06-08 21:48:04 +02:00
W.C.A. Wijngaards 3eab974ca2 - Fix that dns64 cleans up the allocated message if the adjust
routines fail, and checks if there is a reply before cache
  store, also unbound checks if A and AAAA are malformed
  for auth-zones. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-06-03 14:56:20 +02:00
W.C.A. Wijngaards b1d1dcb3b6 - Fix that dump_cache has a larger buffer for records,
and it checks that an owner name does not collide with BADRR
  on the input, and changes verbosity on the log of failure in
  rrset to string.  Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-06-03 14:51:16 +02:00
W.C.A. Wijngaards 10cb62aca2 - Fix that validation canonicalization of domain names
in rdata checks for buffer bounds. Thanks to Qifan Zhang,
  Palo Alto Networks, for the report.
2026-06-03 14:48:06 +02:00
W.C.A. Wijngaards 6da73aba38 - Fix fast_reload for when a ZONEMD lookup is in progress.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-06-03 14:42:47 +02:00
W.C.A. Wijngaards 1b1b9626ee - Fix negative cache NSEC3 nodata proof, to use the correct
message size. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-06-03 14:40:17 +02:00
W.C.A. Wijngaards 8bc074043a - Fix PROXYv2 header read and consume, it checks the header
size. Thanks to Qifan Zhang, Palo Alto Networks for
  the report.
2026-06-03 14:37:37 +02:00
W.C.A. Wijngaards 04a6322aa4 - Fix ipset module to use larger domain name buffers, and
check buffer lengths. Thanks to Qifan Zhang, Palo Alto
  Networks for the report.
2026-06-03 14:35:06 +02:00
W.C.A. Wijngaards 5748f518d1 - Fix that quotation and escaping works the same in auth-zone
url content, as in the zonefile read. Thanks to Qifan Zhang,
  Palo Alto Networks for the report.
2026-06-03 14:32:14 +02:00
W.C.A. Wijngaards d05eff4d54 - Fix parse of svcbparam ech, it had incorrect length. Thanks
to Qifan Zhang, Palo Alto Networks for the report.
2026-06-03 14:05:48 +02:00
Yorgos Thessalonikefs 4544eaa4cc - Fix const as reported by newest compiler warnings. 2026-06-03 14:00:04 +02:00
W.C.A. Wijngaards 5d0770d0ad - Fix negative cache to work with NSEC3 records without salt.
Thanks to Xin Wang, Jiapeng Li, and Jiajia Liu, Northwestern
  Polytechnical University, for the report.
2026-06-03 13:56:31 +02:00
W.C.A. Wijngaards 7f4beb846e - Fix that the processing of class responses does not have
a heap use-after-free. That could happen if at least two
  distinct classes are configured for resolution. Thanks
  to Qifan Zhang, Palo Alto Networks for the report.
  In addition, thanks to Xin Wang, Jiapeng Li, and Jiajia
  Liu, Northwestern Polytechnical University, for also
  reporting this.
2026-06-03 12:14:30 +02:00
W.C.A. Wijngaards 8e8c04e1b9 - Fix unit test to check for new icannbundle.pem. 2026-05-29 12:10:40 +02:00
W.C.A. Wijngaards bf0da2ed21 - Update icannbundle.pem certificates in unbound-anchor. It
has the public keys for 2009 to 2029 and for 2025 to 2045.
2026-05-29 12:10:07 +02:00
W.C.A. Wijngaards 670ece06df - iana portlist updated. 2026-05-29 11:54:40 +02:00
W.C.A. Wijngaards 9e41903be8 - Fix header_seen detection for trust anchor files, so that it
detects the id line.
2026-05-29 11:54:03 +02:00
W.C.A. Wijngaards 57f92cc97e - Fix #1457: race condition causes segfault when starting
threads.
2026-05-28 09:34:04 +02:00
W.C.A. Wijngaards c0741ccc68 - Fix analyzer warning in mesh_new_client. 2026-05-27 16:03:15 +02:00
W.C.A. Wijngaards fb2745024a - Fix that validator caps number of ANY RRsets it can
validate, and the wait timer is shortened. Thanks to Qifan
  Zhang, Palo Alto Networks, for the report.
2026-05-27 13:38:10 +02:00
W.C.A. Wijngaards 0c15ddd133 - Fix ipset module for name too long checks, race conditions
on local name buffer, and for socket close race condition.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-05-27 13:34:32 +02:00
W.C.A. Wijngaards b53504049c - Fix that dns64 with subnetcache does not write ECS scoped
answers to global cache. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-05-27 13:31:11 +02:00
W.C.A. Wijngaards a5324e58eb - Fix, in depth, for respip rewrite of dns64 responses. Thanks
to Qifan Zhang, Palo Alto Networks, for the report.
2026-05-27 13:28:41 +02:00
W.C.A. Wijngaards 963cd68535 - Fix manual to document ratelimit, that it is for target
nameservers for a domain, and keeps queries limited. Thanks
  to Qifan Zhang, Palo Alto Networks, for the report.
2026-05-27 13:24:44 +02:00
W.C.A. Wijngaards 047df73887 - Fix to decrement the per-netblock tcp connection limits, so
it keeps usable. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-05-27 13:20:35 +02:00
W.C.A. Wijngaards d2e1ea7d19 - Fix to reset the tcp-timeout before applying a load based
reduction. Thanks to Qifan Zhang, Palo Alto Networks, for the
  report.
2026-05-27 13:17:35 +02:00
W.C.A. Wijngaards fbbe95ba5b - Fix that msgencode insert_query has the correct assertion,
for a local_alias. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-05-27 12:20:04 +02:00
W.C.A. Wijngaards 758c649611 - Fix that the ratelimit is decremented on successful
referrals. Thanks to Qifan Zhang, Palo Alto Networks, for
  the report.
2026-05-27 12:16:23 +02:00
W.C.A. Wijngaards a23f95f620 - Fix to limit the DSNS per-label walk in the iterator. Thanks
to Qifan Zhang, Palo Alto Networks, for the report.
2026-05-27 12:12:39 +02:00
W.C.A. Wijngaards 5363570df0 - Fix for autotrust state-file line overflow, that can give
hold-down bypass. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-05-27 12:09:01 +02:00
W.C.A. Wijngaards 368857a45b - Fix for mesh new client and mesh new callback to rollback the
added address, tcp mesh state and callback when there is a failure
  to initialize. This fixes the mesh accounting of reply addresses.
  Thanks to Xin Wang, Jiapeng Li, and Jiajia Liu, Northwestern
  Polytechnical University, for the report
2026-05-26 16:20:11 +02:00
W.C.A. Wijngaards 40b16d0565 - Fix for signed same-owner CNAME and ordinary RRset responses.
Thanks to Xin Wang and Jiajia Liu, Northwestern Polytechnical
  University, for the report.
2026-05-20 16:30:37 +02:00
W.C.A. Wijngaards 08e901a1ac - Fix cleaning up DoH session. The same query can be on multiple
streams in a session. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-05-20 15:04:12 +02:00
W.C.A. Wijngaards bc703c9129 - Fix lame server detection, for selfpointed glue records.
Thanks to Shuhan Zhang, Dan Li, and Baojun Liu from Tsinghua
  University for the report.
2026-05-20 15:01:42 +02:00
W.C.A. Wijngaards 9ce52de6c1 - Fix in depth for serve-expired responses from cachedb, that it
does not store bogus. Thanks to Qifan Zhang, Palo Alto Networks,
  for the report.
2026-05-20 14:58:26 +02:00
W.C.A. Wijngaards b3aa262477 Remove the debug file. 2026-05-20 12:43:08 +02:00
W.C.A. Wijngaards 25e112c674 - Unit test for CVE-2026-44390. 2026-05-20 12:42:04 +02:00
W.C.A. Wijngaards 0d2282d551 - Unit test for CVE-2026-42960. 2026-05-20 12:40:32 +02:00
W.C.A. Wijngaards b5f21f4165 - Unit test for CVE-2026-40622. 2026-05-20 12:37:17 +02:00
W.C.A. Wijngaards d357935f66 - Unit test for CVE-2026-42959. 2026-05-20 12:35:38 +02:00
W.C.A. Wijngaards 9d2e0f1c02 - Unit test for CVE-2026-42944. 2026-05-20 12:34:16 +02:00
W.C.A. Wijngaards b46ff5c18e - Unit test for CVE-2026-33278. 2026-05-20 12:32:43 +02:00
W.C.A. Wijngaards f597105800 - Tag for 1.25.1 release, it contains the security fixes on 1.25.0.
the code repository continues with in addition the previous fixes,
  for 1.25.2.
2026-05-20 11:31:53 +02:00
W.C.A. Wijngaards 3692517a41 Merge branch 'branch-1.25.1' 2026-05-20 11:19:56 +02:00
W.C.A. Wijngaards 75b6dba593 - Fix CVE-2026-44608, Use after free and crash in RPZ code. Thanks
to Qifan Zhang, Palo Alto Networks, for the report.
2026-05-20 10:22:52 +02:00
W.C.A. Wijngaards 138fb48eac Changelog entry.
- Fix CVE-2026-44390, Unbounded name compression in certain cases
  causes degradation of service. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-05-20 10:22:10 +02:00
W.C.A. Wijngaards dae7a37974 - Fix CVE-2026-44390, Unbounded name compression in certain cases
causes degradation of service. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-05-20 10:21:26 +02:00
W.C.A. Wijngaards 8ae4b4545d - Fix CVE-2026-42960, Possible cache poisoning attack while following
delegation. Thanks to TaoFei Guo from Peking University, Yang Luo
  and JianJun Chen, Tsinghua University, for the report.
2026-05-20 10:20:45 +02:00
W.C.A. Wijngaards c343fff3a4 - Fix CVE-2026-42923, Degradation of service with unbounded NSEC3
hash calculations. Thanks to Qifan Zhang, Palo Alto Networks, for
  the report.
2026-05-20 10:20:02 +02:00
W.C.A. Wijngaards a794c87578 - Fix CVE-2026-42534, Jostle logic bypass degrades resolution
performance. Thanks to Qifan Zhang, Palo Alto Networks, for the
  report.
2026-05-20 10:19:08 +02:00
W.C.A. Wijngaards ef5ca84360 - Fix CVE-2026-41292, Parsing a long list of incoming EDNS options
degrades performance. Thanks to GitHub user 'N0zoM1z0', also Qifan
  Zhang from Palo Alto Networks, for the report.
2026-05-20 10:18:23 +02:00
W.C.A. Wijngaards 8d8fa42266 - Fix CVE-2026-40622, "Ghost domain name" variant. Thanks to Qifan
Zhang, Palo Alto Networks, for the report.
2026-05-20 10:16:18 +02:00
W.C.A. Wijngaards a587535c5d - Fix CVE-2026-32792, Packet of death with DNSCrypt. Thanks to Andrew
Griffiths from 'calif.io' for the report.
2026-05-20 10:15:30 +02:00
W.C.A. Wijngaards 94d5babaee - Fix CVE-2026-42959, Crash during DNSSEC validation of malicious
content. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-05-20 10:14:32 +02:00
W.C.A. Wijngaards fe946ba4e9 - Fix CVE-2026-42944, Heap overflow and crash with multiple nsid,
cookie, padding EDNS options. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-05-20 10:13:55 +02:00
W.C.A. Wijngaards 6a31e470f8 - Fix CVE-2026-33278, Possible remote code execution during DNSSEC
validation. Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-05-20 10:13:08 +02:00
W.C.A. Wijngaards e577695aeb Set version to 1.25.1 for release. 2026-05-20 10:11:15 +02:00
W.C.A. Wijngaards a58bd6cb1e - Fix for mixed class referrals, the resolver uses the query
class. Thanks to Xin Wang and Jiajia Liu, Northwestern
  Polytechnical University, for the report.
2026-05-18 16:42:39 +02:00
W.C.A. Wijngaards 4bad944ae4 - Fix DNSKEY size calculation for noncanonical RSA DNSKEYs
with leading zeroes for n. Thanks to Xin Wang and Jiajia Liu,
  Northwestern Polytechnical University, for the report.
2026-05-15 16:22:59 +02:00
W.C.A. Wijngaards 594182f109 - Fix DNSSEC validation with libnettle for noncanonical RSA
DNSKEYs with leading zeroes for n. Thanks to Xin Wang and
  Jiajia Liu, Northwestern Polytechnical University, for
  the report.
2026-05-15 16:20:52 +02:00
W.C.A. Wijngaards 53c261cb33 - Fix for allocation-failure hardening of rrset cache wildcard
storage and canonical NSEC owner replacement. Thanks to Xin
  Wang and Jiajia Liu, Northwestern Polytechnical University,
  for the report.
2026-05-15 16:00:58 +02:00
W.C.A. Wijngaards 8703d9a5be - Fix that for dns64 answers, the AAAA query is checked to be
DNSSEC validated, when DNSSEC is enabled. This improves
  the RFC6147 conformance of Unbound. Thanks to Xin Wang
  and Jiajia Liu, Northwestern Polytechnical University, for
  the report. In addition, thanks to Qifan Zhang, Palo Alto
  Networks, for reporting it.
2026-05-15 15:43:18 +02:00
W.C.A. Wijngaards aa9f1e68ff - Fix val_find_DS for robustness, to check the result of
packet_rrset_copy_region before using it. Thanks to Xin Wang
  and Jiajia Liu, Northwestern Polytechnical University, for
  the report.
2026-05-15 14:27:18 +02:00
W.C.A. Wijngaards 84a4f556b1 Merge branch 'master' of github.com:NLnetLabs/unbound 2026-05-15 08:42:40 +02:00
W.C.A. Wijngaards 5b166dbf0a - Fix man page entry for so-sndbuf, it is for responses sent out. 2026-05-15 08:42:27 +02:00
Yorgos Thessalonikefs 9e2233b821 - Fix another comment for EDNS fallback buffer size. 2026-05-14 13:11:17 +02:00
Yorgos Thessalonikefs 13716dc8be - Fix comment and verbose logging for EDNS fallback buffer size. 2026-05-11 20:39:38 +02:00
W.C.A. Wijngaards 8ada1bd88d - Fix to relax assertions after the TTL 0 handling change.
This relaxes an assertion in cachedb (it fails instead),
  and for packet_rrset_copy_region.
2026-05-08 10:09:41 +02:00
W.C.A. Wijngaards 9c80bb9fb0 - Fix to clean up log ids after a failure to start a worker thread. 2026-05-07 14:42:29 +02:00
W.C.A. Wijngaards 33e2863862 - Fix for Heap Out-of-Bounds Write via size_t-to-int Truncation
in setup_if() - outside_network_create(). This fixes that
  large values for num_ports do not overflow and create
  invalid references after integer truncation. Thanks
  to Karnakar Reddy (@karnakarreddi) for the report.
2026-05-07 14:40:48 +02:00
W.C.A. Wijngaards 027e23a11d - iana portlist updated. 2026-05-01 11:25:49 +02:00
W.C.A. Wijngaards 62e8db1c6a - Fix windows 64bit build for libssp dependency. 2026-04-29 15:06:09 +02:00
W.C.A. Wijngaards 581b2f31bc - tag for 1.25.0. The code repository continues with 1.25.1 in
development.
2026-04-29 12:10:23 +02:00
W.C.A. Wijngaards 25fe602024 - For #1441: Fix type of ipv6 addr struct. 2026-04-23 09:37:30 +02:00
W.C.A. Wijngaards df0e86de49 Changelog entry for #1441.
- Merge #1441: Fix buffer overrun in
  doq_repinfo_retrieve_localaddr().
2026-04-23 09:35:44 +02:00
FothsidandGitHub e49b550cf3 Fix buffer overrun in doq_repinfo_retrieve_localaddr() (#1441) 2026-04-23 09:35:23 +02:00
W.C.A. Wijngaards 07c96792f2 - Fix doxygen comment syntax. 2026-04-21 13:44:55 +02:00
W.C.A. Wijngaards 84ab430e11 - Set version number to 1.25.0 of code repository. 2026-04-21 13:27:55 +02:00
W.C.A. Wijngaards 53499e4a88 - Fix handling of wildcard CNAMEs in the chain of trust.
An improper wildcard in the chain of trust would send
  the retries to the wrong upstream. Also it could label
  the step in the chain of trust as secure, when it was not.
  Thanks to Qifan Zhang, Palo Alto Networks for the report.
2026-04-21 13:24:40 +02:00
W.C.A. Wijngaards 8a25a97687 - Fix that a DNAME with an unsigned CNAME is checked for
the correct match. This stops that for certain zone
  configurations an unchecked unsigned CNAME could get
  secure status. Thanks to Qifan Zhang, Palo Alto Networks
  for the report.
2026-04-21 13:19:13 +02:00
W.C.A. Wijngaards c112bcf2fd - Fix that signatures are not allowed with revoked dnskeys.
Thanks to Qifan Zhang, Palo Alto Networks for the report.
2026-04-21 13:07:34 +02:00
W.C.A. Wijngaards 9de549c498 - Fix that upstream TLS connections are not reused as TLS
connections for a different name, at the same IP. This
  checks that the tls name is correct when reusing the
  upstream connections. Thanks to TaoFei Guo from Peking
  University and JianJun Chen from Tsinghua University for
  the report.
2026-04-21 11:59:05 +02:00
W.C.A. Wijngaards 84c645e7b3 - Fix for missing bounds check for decompressing dnames
for downloaded authority zones. This fixes that the server
  could end up with malformed zone content after receiving
  truncated packet contents from an AXFR. In addition, the
  domain names in the SOA rdata are checked before the
  authority code picks up the zone serial.
  Thanks to Halil Oktay for the report.
2026-04-21 10:32:37 +02:00
W.C.A. Wijngaards 197a425c7d - Fix for iterator RCODE handling of YXDOMAIN. This fixes
that the server only accepts YXDOMAIN answers that contain
  a DNAME record. This stops bad answers, and checks that
  the authoritative server gives correct replies.
  Thanks to Qifan Zhang, Palo Alto Networks for the report.
2026-04-21 10:09:02 +02:00
W.C.A. Wijngaards 311054728d - Fix EDNS extended RCODE reflection. This fixes that
the server does not echo extended rcode values after class
  chaos queries. Thanks to Qifan Zhang, Palo Alto Networks
  for the report.
2026-04-21 09:58:19 +02:00
W.C.A. Wijngaards 6d74856212 - Fix for the Jiggle Attack. The server is fixed to answer
with errors for error cases, and does not stay silent.
  In addition, the error replies do not contain parts of the
  incoming query. This is more conformant, stops reflection
  and stops it as a covert channel. Thanks to Yuqi Qiu and
  Xiang Li, Nankai University (AOSP Lab) for the report.
  In addition, thanks to Qifan Zhang, Palo Alto Networks, for
  noting the fingerprinting possibility, that is also fixed
  with this.
2026-04-21 09:54:17 +02:00
W.C.A. Wijngaards d489e6027e - Add test case for malformed SVCB records. Thanks to
Qifan Zhang, Palo Alto Networks for the additional test.
2026-04-21 09:41:53 +02:00
W.C.A. Wijngaards e1d146d6b0 - Fix test with https zone for libressl. 2026-04-20 16:10:33 +02:00
W.C.A. Wijngaards eb2fe8df8d - Fix unused variable warning when compiled without ssl. 2026-04-20 12:24:55 +02:00
W.C.A. Wijngaards 86a8be75f0 - Fix compile warnings for thread setname routine, and test compile. 2026-04-20 12:24:28 +02:00
W.C.A. Wijngaards 52fc5ee374 - Fix pthread_setname detection to fail on warnings. 2026-04-17 17:13:14 +02:00
W.C.A. Wijngaards 82359c8fb1 - Update generated configure, with autoconf. 2026-04-17 17:00:09 +02:00
W.C.A. Wijngaards c996671a1f - Update generated man pages. 2026-04-17 16:32:02 +02:00
Yorgos Thessalonikefs e233a1ef65 Changelog entry for #1400:
- Merge #1400: Support pthread_setname_np.
2026-04-17 16:23:53 +02:00
Yorgos Thessalonikefs 06ff9f20d0 Merge branch 'features/pthread-setname' 2026-04-17 16:22:04 +02:00
W.C.A. Wijngaards af209a12ea - Fix subnet store of servfail to not leak memory. 2026-04-17 13:48:38 +02:00
W.C.A. Wijngaards 84ac7e1b58 - Fix ttl comparisons in rdata_copy for 32bit signed or unsigned. 2026-04-17 13:27:41 +02:00
W.C.A. Wijngaards 24d502763c - Fix to increase size of the buffer for the win_svc reportev log
function.
2026-04-17 11:05:31 +02:00
W.C.A. Wijngaards 99c61c19ac - Fix compat/gmtime_r old style definition syntax. 2026-04-17 11:05:15 +02:00
W.C.A. Wijngaards cb05e9d525 - Fix compat/chacha_private sigma and tau definitions to use
nonstring attribute.
2026-04-17 11:04:51 +02:00
W.C.A. Wijngaards abddd4e270 - Update github ci cross platform to use
cross-platform-actions/action@v1.0.0.
- Fix github ci to speed up with parralel build, for windows ci.
2026-04-17 10:41:24 +02:00
W.C.A. Wijngaards 656b412492 - Update github ci to use actions/checkout@v6. 2026-04-17 10:13:06 +02:00
W.C.A. Wijngaards f15a46fcd4 - Fix to compile the shm code when there is no shmget. 2026-04-17 09:42:35 +02:00
W.C.A. Wijngaards 8d434bf744 - Fix setup of ssl context copy, to check for the tls service
pem option for stat calls.
2026-04-17 09:34:06 +02:00
W.C.A. Wijngaards 13b269d398 - Fix setup of ssl context copy of the tls service pem option,
from a clang analyzer warning.
2026-04-17 09:29:10 +02:00
Yorgos Thessalonikefs 7aff88881a - Fix cleaning up DoH session. The same query can be on multiple
streams in a session.
2026-04-16 11:01:07 +02:00
W.C.A. Wijngaards b97bd3a1fc - Fix configure, autoconf for #1406. 2026-04-16 10:55:57 +02:00
Yorgos Thessalonikefs 6aa5ad85f4 Changelog entry for #1406:
- Merge #1406: Introduce new 'tls-protocols' configuration option.
2026-04-16 10:53:01 +02:00
42b19c20c1 Introduce new 'tls-protocols' configuration option (#1406)
- Introduce new 'tls-protocols' configuration option that specifies
  which of the supported TLS protocols will be used.
  This change invalidates some previous changes:
- TLSv1.2 is again enabled by default, but can be selectively turned off if
  desired (related to #1303).
- The biefly introduced (not yet released) 'tls-use-system-versions'
  configuration option, that addressed #1346, is reverted in favor of
  'tls-protocols'.
- The briefly introduced (not yet released) '--enable-system-tls'
  configure option, related to #1401, is no longer needed with the new
  option and the current default.

- Review comment for checking out of memory condition

Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com>
2026-04-16 10:38:24 +02:00
W.C.A. Wijngaards db1fe8b475 - Fix to shorten RRSIG count in scrubber, this protects against
an overly large number of RRSIGs. It can be configured with
  `iter-scrub-rrsig: 8`, it has default 8. Thanks to Yuxiao Wu,
  Tsinghua University for the report.
2026-04-15 11:41:28 +02:00
W.C.A. Wijngaards f4f964f4fb - Fix RFC7766 compliance when client sends EOF over TCP. It stops
pending replies and closes. Thanks to Yuxiao Wu, Tsinghua
  University for the report.
2026-04-15 11:29:07 +02:00
W.C.A. Wijngaards a2272860de - iana portlist updated. 2026-04-14 15:36:33 +02:00
W.C.A. Wijngaards 95083d4377 - Fix clang analyzer warning for subnetmod, when return_msg is
NULL for update cache, like when it stores servfail status.
2026-04-14 15:36:00 +02:00
W.C.A. Wijngaards 5ce0bf5281 - Fix #1017: memory corruption related core dumps.
When alloc_reg_obtain has an empty list, return a new allocation.
2026-04-14 15:34:59 +02:00
Yorgos Thessalonikefs 6a0d5e2cb1 - Update the documentation of 'max-query-restarts' in the man page. 2026-04-13 18:07:01 +02:00
W.C.A. Wijngaards 330d5211c9 - Fix for EDNS client subnet so that it does not store SERVFAIL in
the global cache after a failed lookup, such as timeouts. A failure
  entry is stored in the subnet cache, for the query name, for a
  couple of seconds. Queries can continue to use the subnet cache
  during that time.
2026-04-10 15:45:28 +02:00
Yorgos Thessalonikefs 2dc28a249a - Fix unused variable warning. 2026-04-07 18:03:20 +02:00
W.C.A. Wijngaards c5f14dc880 Changelog comment for #1408
- Merge #1408: Fix shared memory stats with threads.
2026-03-30 16:15:32 +02:00
a2ace114de Fix shared memory stats with threads (#1408)
* - stats-shm-volley, with mesh_time_median the additions add up to the correct
  average that is used.

* - stats-shm-volley, the stat interval is selected with offset.

* - stats-shm-volley, stat totals in separate struct. The first thread zeroes
  it, and the last thread copies it.

* - stats-shm-volley, the array is inited for a new round if one or more

* - stats-shm-volley, the array is inited for a new round if one or more
  threads are not responsive for stat collection.

* - stats-shm-volley review, typos and slightly more detailed text for comments.

---------

Co-authored-by: Yorgos Thessalonikefs <yorgos@nlnetlabs.nl>
2026-03-30 16:13:11 +02:00
W.C.A. Wijngaards 2e9b880718 - Fix defense in depth for service callback with empty packet. 2026-03-27 15:42:45 +01:00
W.C.A. Wijngaards a0ec6cd946 - Fix test code to allow empty hex answer packets from testbound. 2026-03-27 15:39:27 +01:00
W.C.A. Wijngaards ea36979c40 - Fix to allow the control-interface config to use ip@port notation. 2026-03-27 14:29:15 +01:00
W.C.A. Wijngaards 315077b9e6 - Fix to check for invalid http content length and chunk size,
and to check the RR rdata field lengths when decompressing and
  inserting RRs from an authority zone transfer. This stops
  large memory use and heap buffer-overflow read errors. Thanks
  to Haruto Kimura (Stella) for the report.
2026-03-24 08:45:52 +01:00
W.C.A. Wijngaards 535d899bef - Fix for testcode pktview to check buffer size and log errors. 2026-03-20 15:57:46 +01:00
W.C.A. Wijngaards 8656cfd4c8 - Fix to add tls-service-key to memory printout for fast_reload. 2026-03-13 16:49:34 +01:00
W.C.A. Wijngaards 8f44ddb7de - Fix detection of http listening port in fast_reload. 2026-03-13 16:37:41 +01:00
W.C.A. Wijngaards 4484dc3954 - For #278: fast_reload can reload tls-service-key, tls-service-pem
and tls-cert-bundle changes. It checks the modification time of
  the tls-service-key and tls-service-pem files for update.
2026-03-13 16:25:42 +01:00
W.C.A. Wijngaards eb3bba0724 - iana portlist updated. 2026-03-13 12:05:33 +01:00
W.C.A. Wijngaards 2eff1d8ab5 - Fix #278: DoT: complete unbound restart required on certificate
renew. Fix so that a reload checks if the files have changed, and
  if so, reload the contexts. Also for DoH, DoQ and outgoing DoT.
2026-03-13 11:42:34 +01:00
Yorgos Thessalonikefs 4672fa5b53 - Fix to ignore out-of-zone DNAME records for CNAME synthesis. Thanks
to Yuxiao Wu, Yiyi Wang, Zhang Chao, Baojun Liu, and Haixin Duan from
  Tsinghua University.
2026-03-13 11:28:32 +01:00
W.C.A. Wijngaards 18029fc44f Changelog comment for #1418
- Merge #1418: Apply cache TTL policy to DNAME and synthesized
  CNAME on wire path.
2026-03-09 13:54:37 +01:00
Arunabha DasandGitHub 5c6f56f8f1 Apply cache TTL policy to DNAME and synthesized CNAME on wire path (#1418)
When the scrubber synthesizes a CNAME from a DNAME (authority omits CNAME),
apply cache-min-ttl/cache-max-ttl to both DNAME and synthesized CNAME in
msg_parse so they stay equal and respect config (RFC 6672).

- iterator/iter_scrub.c: In synth_cname_rrset(), clamp TTL to [MIN_TTL,
  MAX_TTL] when !SERVE_ORIGINAL_TTL and write back to both synth CNAME
  and DNAME rrset. Removes FIXME.
2026-03-09 13:53:52 +01:00
W.C.A. Wijngaards 9af29c3ed1 - Fix compile failure in unbound-checkconf for older gcc compiler. 2026-03-09 09:18:43 +01:00
Yorgos Thessalonikefs 76ef8c5803 - Constrain the explicit macros for remote.c:fr_atomic_copy_cfg(). 2026-03-06 17:27:21 +01:00
Yorgos Thessalonikefs 94ef1a8fee - Warn for unused 'nodefault' local-zone configuration in
unbound-checkconf (related to #1416).
2026-03-06 17:05:57 +01:00
Yorgos Thessalonikefs 683241a2f5 - Document the suggestion for a higher value for 'outgoing-range';
helps when the request list is full.
2026-03-06 17:01:41 +01:00
W.C.A. Wijngaards 92ab54641e Changelog entry for #1415
- Merge #1415: Add lock unlock for view in memory error handling.
2026-03-06 08:58:33 +01:00
Andy WarnerandGitHub da3812953a Add lock unlock for view in memory error handling (#1415)
view->lock would be skipped during an out of memory error bailout.
2026-03-06 08:57:54 +01:00
W.C.A. Wijngaards 1bd7c8dfee - Update generated man pages. 2026-03-05 12:15:54 +01:00
W.C.A. Wijngaards 8f96ae7acf - Fix for DNS Rebinding Bypass via SVCB/HTTPS Records in Unbound.
Thanks to Kunta Chu, School of Software, Tsinghua University,
  Taofei Guo, Peking University, and Jianjun Chen, Institute for
  Network Sciences and Cyberspace, Tsinghua University for the
  report. The private-address option is fixed to also elide
  SVCB and HTTPS records that match the filter.
2026-03-05 09:47:13 +01:00
Yorgos Thessalonikefs c4f8e60c85 - For #1411: Introduce a failing case in the rpl test so that it only
passes with the fix in place.
2026-03-04 13:22:42 +01:00
W.C.A. Wijngaards a296b248b0 - For #1411: Fix that the lookup for DNAME uses flag. Fix assertion
in expired calc debug routine.
2026-03-03 17:44:31 +01:00
W.C.A. Wijngaards 1ef131299a For #1411, fix up doc/Changelog. 2026-03-03 08:55:56 +01:00
Arunabha DasandGitHub 5b58a872ef Allow synthesized DNAME TTL=0 to be served from cache within grace period (#1411)
* Allow synthesized DNAME TTL=0 to be served from cache within grace period

Addresses doc/TODO: cache TTL=0 packets properly for synthesis.
- rrset_cache_lookup: allow TTL=0 DNAME within 1s grace for synthesis
- synth_dname_msg: support PACKED_RRSET_UPSTREAM_0TTL, return TTL=0 to client

Reduces recursion when authoritative servers return DNAME with TTL=0 (RFC 2308).
Client response still correctly returns TTL=0.

Note: Test with proper TTL=0 DNSSEC RRSIGs omitted - requires ldns-signzone
to generate valid signatures for TTL=0 RRsets.

* Add iter_dname_ttl0.rpl replay test for DNAME TTL=0
Tests signed DNAME with TTL=0 and RRSIG Original TTL=0 (RFC 4034).
Verifies end-to-end handling of TTL=0 DNAME responses.
2026-03-03 08:51:31 +01:00
W.C.A. Wijngaards 94b04d6d46 - Update generated man pages. 2026-02-27 14:33:55 +01:00
W.C.A. Wijngaards f1a65eb4e8 For #1409: Changelog entry and more text. 2026-02-27 13:55:25 +01:00
Daisuke HIGASHIandGitHub 38e1e3eec3 Documentation CNAME in redirect-type local-zone (#1409) 2026-02-27 13:37:56 +01:00
W.C.A. Wijngaards bff3d762ff - Fix validator to set unchecked when validation recursion
requests are passed. The edns subnet module checks if validation
  is needed for a cache response, and set the validator to protect
  the cache with validation for non-subnet lookups.
2026-02-25 10:59:33 +01:00
Yorgos Thessalonikefs fb322f3e87 - Fixed some typos reported in #1395 by rezky_nightky. 2026-02-23 16:17:40 +01:00
Yorgos Thessalonikefs 2feee13735 - Fix to disallow cache lookup/store in external cachedb when a
forwarder/stub forbids it with the no-cache option.
2026-02-23 14:35:50 +01:00
W.C.A. Wijngaards 1d36696462 - Fix to make the cachedb_val_expired.crpl succeed. 2026-02-23 12:52:10 +01:00
W.C.A. Wijngaards aa4e2a9e69 - Fix to have cachedb not return expired bogus data as non-bogus. 2026-02-23 12:45:14 +01:00
W.C.A. Wijngaards 8e04d04949 - For #1405: local-zone always_refuse also blocks queries of type DS. 2026-02-17 15:36:08 +01:00
W.C.A. Wijngaards c5627dbd52 - Fix to remove unused conditional from cookie timestamp at
worker env.
2026-02-17 11:15:15 +01:00
W.C.A. Wijngaards 014ed9c5ff - Fix that cachedb aggressive negative responses have the RA flag set. 2026-02-16 16:35:37 +01:00
Yorgos Thessalonikefs 16e1e6d375 - Fix #1404: Priming the root key fails after loading ipfire.org RPZ
zones. Fixed by including the ZONEMD RRtype in the list of types to
  ignore for RPZ zones. Analysis and patch provided by ummeegge.
2026-02-16 13:37:19 +01:00
W.C.A. Wijngaards 1a9a4e4ca1 - Fix #1403: Inconsistency between do-nat64 and do-not-query-address
during retries.
2026-02-11 16:01:30 +01:00
W.C.A. Wijngaards f7f638e18f - Update generated man pages. 2026-02-09 16:11:17 +01:00
W.C.A. Wijngaards c956aea93d Changelog note and documentation for #1401.
- Merge #1401: Add a new build-time option for system TLS.
  The --enable-system-tls flag enables the
  tls-use-system-policy-versions setting by default.
2026-02-09 16:05:28 +01:00
Petr MenšíkandGitHub 4556a4f490 Add a new build-time option for system TLS (#1401)
We want to use crypto-policy provided configuration always in our
builds. Allow changing the default of tls-use-system-policy-versions at
build time by a simple configure parameter.
2026-02-09 15:57:16 +01:00
Yorgos Thessalonikefs 1cdddf0fe9 - Fix #1389: [FR] replacement with ECC-GOST12 according to RFC9558.
Patch contributed by Igor V. Ruzanov, available in
  contrib/gost12.patch.
2026-02-06 14:39:23 +01:00
Yorgos Thessalonikefs 18fec256b7 - Support pthread_setname_np, and variants, to set the name on spawned
threads for easier debugging/monitoring.
2026-02-06 14:17:04 +01:00
W.C.A. Wijngaards 567c70dada Fix attribution of fix. 2026-02-04 14:17:56 +01:00
W.C.A. Wijngaards 8b4b2a88f7 - Fix local privilege escalation on Windows. Thanks to Hao Huang
for the report. The OpenSSL init calls are set to not load
  the openssl.cnf file when compiled for Windows.
2026-02-04 11:54:11 +01:00
Yorgos Thessalonikefs faf40c97fc - Eagerly remove .skip mark files in between mini_tdir.sh runs in case
there has been a change on the environment.
2026-02-03 15:08:59 +01:00
W.C.A. Wijngaards daa016e3e4 - Add test for allow-notify with a host name. 2026-01-27 13:49:33 +01:00
W.C.A. Wijngaards 039f69e735 - Fix to not skip allow-notify hostname lookups when there are only
urls.
2026-01-26 16:16:38 +01:00
W.C.A. Wijngaards b39009e487 Merge branch 'master' of github.com:NLnetLabs/unbound 2026-01-26 15:17:26 +01:00
W.C.A. Wijngaards 933769ee73 - Fix that allow-notify entries with hostnames are copied after IPv4
and IPv6 lookup.
2026-01-26 15:16:43 +01:00
Yorgos Thessalonikefs 57bff79627 - Update generated man pages. 2026-01-23 18:04:25 +01:00
Yorgos Thessalonikefs 1b5559d534 Changelog entry for #1396:
- Merge #1396: Log Linux thread ID.
- On Linux systems log the system-wide unique thread ID instead of
  Unbound's internal thread counter.
- Introduce the 'log-thread-id' configuration option to manage logging
  the system-wide Linux thread ID for easier debugging with system
  tools.
2026-01-23 17:46:14 +01:00
Yorgos ThessalonikefsandGitHub 9d271c5343 Merge pull request #1396 from NLnetLabs/features/thread-id 2026-01-23 17:42:30 +01:00
Yorgos Thessalonikefs 74cc49e6c4 - Introduce the 'log-thread-id' configuration option to manage logging
the system-wide Linux thread ID for easier debugging with system
  tools.
2026-01-23 17:15:14 +01:00
Yorgos Thessalonikefs d414ebf0c7 - On Linux systems log the system-wide unique thread ID instead of
Unbound's internal thread counter.
2026-01-23 17:08:55 +01:00
W.C.A. Wijngaards 9b123d1b78 - Fix http test tool petal to not print errors when there is no
error.
2026-01-22 14:19:35 +01:00
W.C.A. Wijngaards 37b71261a2 - Fix that fast reload copies the iter_scrub_ns, iter_scrub_cname
and max_global_quota options.
2026-01-22 09:42:56 +01:00
W.C.A. Wijngaards 4426db4d3d - Merge #1388: QNX Porting support for unbound. 2026-01-21 13:13:01 +01:00
nnarayanamurthyandGitHub fe10bc7682 QNX Porting support for unbound branch-1.24.1 (#1388)
* qnx Porting support for version release-1.24.1

* updating __QNXNTO__ with __QNX__
2026-01-21 13:12:13 +01:00
W.C.A. Wijngaards 67d2eae28c - Merge #1392: Include "V" (version) option in synopsis. 2026-01-19 09:09:47 +01:00
David H. GutteridgeandGitHub 9010a7075e Include "V" (version) option in synopsis (#1392) 2026-01-19 09:09:12 +01:00
W.C.A. Wijngaards cc6dbc9f38 - Fix documentation for requestlist.overwritten and
requestlist.exceeded, it explains which query was dropped.
2026-01-15 09:35:04 +01:00
W.C.A. Wijngaards 4198343dbe Compile fixup for #1381. 2026-01-08 14:19:06 +01:00
W.C.A. Wijngaards 08600d68e8 Changelog note for #1381, and man page explanation.
- Merge #1381: Do not initialize quic_table unless it is enabled.
2026-01-08 14:16:54 +01:00
Petr MenšíkandGitHub 18e098285e Do not initialize quic_table unless it is enabled (#1381)
* Do not initialize quic_table unless it is enabled

Fedora in FIPS mode might fail to initialize ngtcp2 library, because
some ciphers desired are not available.

Make it possible to skip initialization by setting explicitly quic_port
to 0. Unless we have some listeners for port 853 configured, skip its
initialization as well.

Related: https://pagure.io/freeipa/issue/9877

* Fix typo in logged function name
2026-01-08 14:12:32 +01:00
Yorgos Thessalonikefs f1b35bab4b Changelog entry for #1391:
- Merge #1391 from Götz Görisch: Fix documentation to adhere to
  RFC5952.
2026-01-06 18:21:34 +01:00
Yorgos ThessalonikefsandGitHub 84ed77238d Merge pull request #1391 from GoetzGoerisch/docs
Fix documentation to adhere to RFC 5952
2026-01-06 18:19:47 +01:00
Goetz Goerisch adb0374a4d Fix documentation to adhere to RFC 5952
Update the text representations of IPv6 addresses.
2026-01-06 16:10:37 +01:00
W.C.A. Wijngaards b0b634558b - Fix edns subnet, that scope zero queries, when there is a
subquery without subnet, and the forward-no-cache or
  stub-no-cache option is set, it is not stored in cache due to
  the forward or stub option.
This has the changelog entry and test.
2026-01-06 09:33:00 +01:00
W.C.A. Wijngaards 8546247292 - Fix edns subnet, that scope zero queries, when there is a
subquery without subnet, and the forward-no-cache or
  stub-no-cache option is set, it is not stored in cache due to
  the forward or stub option.
2026-01-06 09:32:21 +01:00
Yorgos Thessalonikefs 44659cb3bf - Use the same EDE removal logic when encoding errors as when encoding
replies.
2025-12-31 16:22:15 +01:00
Yorgos Thessalonikefs a1ac2d0252 - Update the unbound-anchor man page to note write permissions of the
generated file if it is to be used with Unbound's
  auto-trust-anchor-file option.
2025-12-31 14:05:42 +01:00
Yorgos Thessalonikefs 5c7a26b615 - Mark "THROWAWAY" and "(DNSSEC) LAME" responses clearly as Unbound's
categorization in the log output.
2025-12-30 13:15:37 +01:00
Yorgos Thessalonikefs 09d352b917 - More specific wording in the unbound.conf man page for stub-first
and forward-first options.
2025-12-24 14:57:44 +01:00
W.C.A. Wijngaards c0522043f0 - Fix http2 drop handling to clear the postpone_drop state so that
other streams on the http2 session are not affected by a drop,
  and can clean up properly if also dropped. Fix http2 send reply
  so that when there is a send failure is does not recurse into
  the mesh functions and also does not drop the connection due to
  the condition of one stream.
2025-12-03 14:41:10 +01:00
W.C.A. Wijngaards b858801feb - Fix to remove http2 stream mesh state when mesh new request is
dropping the new request.
2025-12-02 15:31:53 +01:00
W.C.A. Wijngaards 588db09928 - Fix header comment about EDE reference in validator/val_sigcrypt.h. 2025-12-01 16:04:41 +01:00
W.C.A. Wijngaards 5c66c48a1b - Fix to add EDNS CO flag to testbound and debug message log. 2025-12-01 15:29:41 +01:00
Yorgos Thessalonikefs 83336477c6 - For #1375, there is no DNSTAP environment if it wasn't configured. 2025-11-28 15:20:21 +01:00
Yorgos Thessalonikefs e3e5eb66cf - Tag for 1.24.2 release.
The repository continues with version 1.24.3.
2025-11-26 13:54:25 +01:00
Yorgos Thessalonikefs 00d3b97dbb Merge branch 'branch-1.24.2' 2025-11-26 13:50:49 +01:00
W.C.A. Wijngaards 0f43b0ea6c Changelog note for #1375, and lock for lockchecks and ifdef for compile fix.
- Merge #1375: Copy DNSTAP changes from daemon to workers after
  fast_reload.
2025-11-13 15:45:27 +01:00
smeddlepandGitHub e6d92f458f Copy DNSTAP changes from daemon to workers after fast_reload (#1375)
- On fast_reload, the identity and version strings are always freed and
  reallocated as part of dt_apply_cfg(). Add fr_worker_pickup_dnstap_changes()
  to copy any changes from daemon to workers.
2025-11-13 15:42:44 +01:00
W.C.A. Wijngaards a31b9d50e2 Changelog note for #1374
- Merge #1374: Mesh reply counters.
  This adds the statistics num.queries.replyaddr_limit and
  requestlist.current.replies.
2025-11-13 09:34:45 +01:00
Robert EdmondsandGitHub fceb4e8585 Mesh reply counters (#1374)
* Statistics counter for number of queries dropped by limit on reply addresses

Request list entries can be associated with multiple pending "reply
addresses". Basically each request list entry keeps its own list of
clients that should receive the response once the recursion is finished.
This requires keeping allocations around for each client, and there is
a global limit on the number of *additional* reply addresses that can
be allocated. (Each new request list entry seems to get its own initial
reply address which is not counted against the limit.)

This commit adds a statistics counter "num_queries_replyaddr_limit" that
counts the number of incoming client queries that have been dropped due
to the restriction on allocating additional reply addresses. This allows
distinguishing these drops from other kinds of drops.

* Statistics counter for number of mesh reply entries

Request list entries can be associated with multiple pending "reply
addresses". Since there is a limit on the number of additional reply
addresses that can be allocated which can cause incoming queries to be
dropped if exceeded, it would be nice to be able to track this number.

This commit basically exports the mesh_area's internal counter
`num_reply_addrs` as "threadX.requestlist.current.replies" /
"total.requestlist.current.replies".
2025-11-13 09:33:05 +01:00
W.C.A. Wijngaards 98f4257890 - iana portlist updated. 2025-11-12 11:49:21 +01:00
W.C.A. Wijngaards 0a15118aff - Fix that when discard timeout drops packet, they are accounted as
less reply addresses in use in the mesh area.
2025-11-12 11:49:04 +01:00
W.C.A. Wijngaards e887a79a92 - Fix configure test for nonstring attribute so that it does not
accept when the compiler prints a warning about an unknown
  attribute.
2025-11-06 15:03:17 +01:00
W.C.A. Wijngaards f9b9050ab8 - Fix configure test for noreturn attribute so it compiles without
warning.
2025-11-06 15:00:08 +01:00
W.C.A. Wijngaards 94735384fd - Fix add comment to worker_handle_request function that explain it. 2025-11-06 14:32:56 +01:00
W.C.A. Wijngaards 5dab0609e5 - Fix dns64 log output to log the default instead of a null string. 2025-11-04 10:19:03 +01:00
Yorgos Thessalonikefs 024c921dbf - Fix #1366: Infra cache does not work correctly for NAT64, by
moving the NAT64 synthesis from the iterator when selecting a target
  address, to the delegation point itself when adding target
  addresses.
2025-11-01 15:10:27 +01:00
Yorgos Thessalonikefs 1a808e2978 - Fix typo; spotted by T3rm1. 2025-10-28 14:42:20 +01:00
Yorgos Thessalonikefs 56ded934de - Fix #1165, document the possible circular dependency when using
host names instead of IP addresses for name servers in stub/forward
  zones and log a warning when spotted in the configuration.
2025-10-27 14:01:10 +01:00
Yorgos Thessalonikefs 98952f11d1 Changelog entry for #1331:
- Merge #1331 from Jitka Plesníková: Replace deprecated $function by
  new $action, for SWIG.
2025-10-27 09:59:35 +01:00
Yorgos ThessalonikefsandGitHub cb4b3de62f Merge pull request #1331 from jplesnik/master
Replace deprecated $function by new $action
2025-10-27 09:57:59 +01:00
Yorgos Thessalonikefs c8dcfc0853 - For #1364, use OPENSSL_VERSION_TEXT instead of OPENSSL_VERSION_NUMBER
for part of the configure script. OPENSSL_VERSION_TEXT is more
  consistent across versions.
2025-10-24 15:43:22 +02:00
Yorgos Thessalonikefs 2bb28fdf12 - Fix unused attribute warning in redis.c when threads are not
supported.
2025-10-24 14:44:58 +02:00
Yorgos Thessalonikefs 6ad26909dd - Note Havard Eidnes for his suggestions on the mailing list. 2025-10-24 14:26:08 +02:00
Yorgos Thessalonikefs 9602973c86 - unbound.conf man page updates to include a preview of the section
clauses and some reformatting around the use of "clause", "option"
  and "attributes".
2025-10-24 14:23:53 +02:00
Yorgos Thessalonikefs 713b1783d4 - Tag for 1.24.1 release.
The repository continues with version 1.24.2.
2025-10-22 12:49:29 +02:00
Yorgos Thessalonikefs e06b7eb3f1 Merge branch 'branch-1.24.1' 2025-10-22 12:44:59 +02:00
Yorgos Thessalonikefs 1cb9595a42 - Update the unbound.conf online man page link and some text
reformatting in README.md.
2025-10-20 14:34:40 +02:00
Wouter WijngaardsandGitHub aa21e38b3a Fix for analysis and ports workflows iOS, Windows (#1361)
* - Remove SDK_VERSION and only run failed jobs, echo windows config.log

* Use commented out to fix syntax of ci.

* - Turn off succeeded tests, only link libssp for cross compile, use
no-shared for openssl ios.

* - Remove iPhone armv7s, and iPhoneSimulator i386 from ios ci.
  The lib system does not provide symbols for it on the new macos
  runner.
- Fix to exclude libssp for windows compiles.
2025-10-15 16:12:39 +02:00
W.C.A. Wijngaards 964848b94a - Fix unbound.conf man page entry for root-hints to say it can
be used without strongly recommending it.
2025-10-15 15:40:47 +02:00
Yorgos Thessalonikefs a4dd321fd8 - Remove extra gpg instructions from makedist.sh output. 2025-10-15 14:59:48 +02:00
Yorgos Thessalonikefs d23a28a693 - ci: don't fail fast for the analysis_port workflow. 2025-10-15 14:10:20 +02:00
W.C.A. Wijngaards 5423c0a8e9 Update ios ci with older sdk version to use. 2025-10-15 13:41:36 +02:00
W.C.A. Wijngaards 6a5385f291 - Fix to update openssl version in ios ci. 2025-10-15 12:25:44 +02:00
W.C.A. Wijngaards 16f3478048 - Add extended dns error code for invalid query type to definition
list.
2025-10-15 11:39:58 +02:00
W.C.A. Wijngaards c8860a5fb6 - Fix to reply with SERVFAIL when the wait-limit is exceeded. 2025-10-15 11:36:29 +02:00
W.C.A. Wijngaards 735c96aac7 - Fix to drop UDP for discard-timeout, but not stream connections. 2025-10-15 11:04:22 +02:00
W.C.A. Wijngaards a75ea01a15 - Fix #1358 Enabling FIPS in OpenSSL causes unit test to fail. 2025-10-10 09:17:08 +02:00
Yorgos Thessalonikefs 21f02a0865 - Note clearly that 'wait-limit: 0' disables all wait limits.
- 'wait-limit-cookie: 0' can now disable cookie validated wait
  limits.
2025-10-03 16:44:44 +02:00
Yorgos Thessalonikefs e017d66fc1 - Note 'respip' and 'dns64' module order in the unbound.conf
man page.
2025-10-03 11:27:26 +02:00
W.C.A. Wijngaards adaf5dab49 - Fix that https is set up as enabled when the port is listed in
interface-automatic-ports. Also for the set up of quic it is
  enabled when listed there.
2025-10-02 10:16:06 +02:00
W.C.A. Wijngaards feeebc95f8 - Fix for #1344: Fix that respip and dns64 can be enabled at the
same time, the client info is copied for attach_sub and add_sub
  calls. That makes respip work on dns64 synthesized answers, and
  also makes RPZ work with DNS64. The order for the modules is
  module-config: "respip dns64 validator iterator".
2025-09-30 11:28:15 +02:00
W.C.A. Wijngaards 187aa52859 - Fix #1344: module conf 'respip dns64 validator cachedb iterator'
is not known to work.
2025-09-29 16:11:50 +02:00
W.C.A. Wijngaards f1fea8dc46 - Fix #1353: auth-zone can not use empty label for $ORIGIN when
http download.
2025-09-29 14:24:31 +02:00
Yorgos Thessalonikefs 0c01257d1d Changelog entry for #1351:
- Merge #1351: ac_cv_func_malloc_0_nonnull for malloc(0) check.
2025-09-29 13:14:07 +02:00
W.C.A. Wijngaards 50a11ebcc8 - Rebuild configure script from its sources. 2025-09-29 13:13:15 +02:00
Yorgos ThessalonikefsandGitHub 1e2dc657a1 ac_cv_func_malloc_0_nonnull for malloc(0) check (#1351)
- For #1339, use the standard variable ac_cv_func_malloc_0_nonnull for
  the malloc(0) check during configure; patch from Helmut Grohne.
2025-09-29 13:12:27 +02:00
Yorgos Thessalonikefs 843124852f Changelog entry for #1349:
- Merge #1349: Fix #1346: [FR] Please allow back TLS 1.2.
2025-09-29 12:10:34 +02:00
W.C.A. Wijngaards 5e2fdff8e5 - Fix fr_atomic_copy_cfg. 2025-09-29 12:08:30 +02:00
499a3a7a61 Fix #1346: [FR] Please allow back TLS 1.2. (#1349)
* 'tls-use-system-policy-versions' is introduced to allow Unbound to use
  any system available TLS version when serving TLS.

* Apply suggestions from code review

---------

Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com>
2025-09-29 12:03:56 +02:00
W.C.A. Wijngaards 2024c1d050 - Neaten up the change in acx_nlnetlabs.m4 to version 49. 2025-09-29 11:40:14 +02:00
W.C.A. Wijngaards 6cd595a816 - Fix modstack_call_init to use the original string when it has
changed, to call modstack_config with. And skip the changed name
  in the string correctly. Thanks to Jan Komissar.
2025-09-29 11:31:50 +02:00
W.C.A. Wijngaards 74cf81e9a7 - Rebuild configure script from its sources. 2025-09-29 10:02:54 +02:00
Yorgos Thessalonikefs 35f6fd47fb - Test for nonstring attribute in configure and add
nonstring attribute annotations.
2025-09-26 16:23:55 +02:00
Alex BandandGitHub 270e099aab Update Mastodon shield 2025-09-25 21:39:39 +02:00
Yorgos Thessalonikefs 64645e1401 - Avoid calling mesh_detect_cycle_found() when there is no mesh state
to begin with.
2025-09-24 14:30:24 +02:00
Yorgos Thessalonikefs 421d317a64 - For #1350, same CAP_NET_ADMIN change for unbound_portable.service.in
as well.
2025-09-23 17:42:41 +02:00
Yorgos Thessalonikefs 0b8ed987de Changelog entry for #1350:
- Merge #1350 from Maryse47: unbound.service.in: allow CAP_NET_ADMIN.
2025-09-23 17:37:59 +02:00
Yorgos ThessalonikefsandGitHub 9511797487 Merge pull request #1350 from Maryse47/patch-1
unbound.service.in: allow CAP_NET_ADMIN and drop CAP_NET_RAW (redundant now).
2025-09-23 17:37:09 +02:00
Yorgos Thessalonikefs 0b7bb75152 - For #1352, align with the current Python<3 code. 2025-09-23 17:31:55 +02:00
Yorgos Thessalonikefs 88c688ec10 Changelog entry for #1352:
- Merge #1352 from Petr Vaganov: pythonmod: fix HANDLE_LEAK on
  pythonmod_init.
2025-09-23 17:15:16 +02:00
Maryse47andGitHub 81fd1dc71c unbound.service.in: drop CAP_NET_RAW
CAP_NET_RAW is unnecessary after CAP_NET_ADMIN was added
2025-09-23 17:13:31 +02:00
Yorgos ThessalonikefsandGitHub 69217cf675 Merge pull request #1352 from petrvaganoff/dev-52227
pythonmod: fix HANDLE_LEAK on pythonmod_init
2025-09-23 17:13:30 +02:00
Petr Vaganov 7c28f1b99c pythonmod: fix HANDLE_LEAK on pythonmod_init
Found by the static analyzer Svace (ISP RAS).

Handle 'script_py' is created at pythonmod.c:436
by calling function 'fopen' and lost at pythonmod.c:457,465.

Signed-off-by: Petr Vaganov <petrvaganoff@gmail.com>
2025-09-23 19:51:46 +05:00
Maryse47andGitHub fa6340cfa5 unbound.service.in: allow CAP_NET_ADMIN
Allowing CAP_NET_ADMIN is necessary for SO_SNDBUFFORCE and SO_RCVBUFFORCE calls.
2025-09-23 13:00:50 +02:00
Yorgos Thessalonikefs e471e15774 - unbound.conf manpage: explicitly mention RFC6891. 2025-09-19 15:49:07 +02:00
Yorgos Thessalonikefs ec3db03121 Changelog entry for #1337:
- Merge #1337: 0 TTL cached replies and some TTL behavior changes.
2025-09-19 15:01:30 +02:00
Yorgos Thessalonikefs e2bf773089 Merge branch 'features/no-ttl-zero-cacherep' 2025-09-19 14:56:04 +02:00
Yorgos Thessalonikefs 3017a0aa52 - Update README.man with clearer text. 2025-09-19 10:03:10 +02:00
W.C.A. Wijngaards 8419e9780e - Fix to remove configure~ from release tarballs. 2025-09-19 09:46:34 +02:00
W.C.A. Wijngaards c429c4ab96 - Tag for 1.24.0 release. Includes the fixes below after rc1.
The repository continues with version 1.24.1.
2025-09-18 10:57:37 +02:00
bc61034f60 code review: use proper roundrobin index
Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com>
2025-09-17 12:19:20 +02:00
Yorgos Thessalonikefs 73e408f1d0 A few changes for TTL processing:
- Cached messages that reach 0 TTL are considered expired. This prevents
  Unbound itself from issuing replies with TTL 0 and possibly causing a
  thundering herd at the last second. Upstream replies of TTL 0 still
  get the usual pass-through but they are not considered for caching
  from Unbound or any of its caching modules.
- 'serve-expired-reply-ttl' is changed and is now capped by the original
  TTL value of the record to try and make some sense when replying
  with expired records.
- TTL decoding was updated to adhere to RFC8767 section 4 where a set
  high-order bit means the value is positive instead of 0.
2025-09-15 10:03:35 +02:00
Yorgos Thessalonikefs d521135f66 Merge branch 'master' into features/no-ttl-zero-cacherep 2025-09-12 15:24:06 +02:00
Jitka Plesnikova 1d3d78dff5 Replace deprecated $function by new $action
The long-deprecated $function was removed from future SWIG 4.4.0.
It can be safely replaced by $action.
2025-09-08 10:11:49 +02:00
W.C.A. Wijngaards c88eed83d9 - ttl-zero-cacherep, unit test for ttl zero for a cache response. 2024-11-11 17:08:38 +01:00
W.C.A. Wijngaards 50fcf71f04 - ttl-zero-cacherep, Responses in the last second of their cache TTL,
get an extra second. That makes the TTL not 0, since they are from
  cache and can be cached by the client.
2024-11-11 15:43:10 +01:00
322 changed files with 27838 additions and 3104 deletions
+9 -24
View File
@@ -12,6 +12,7 @@ jobs:
build:
runs-on: ${{ matrix.os }}
strategy:
fail-fast: false
matrix:
include:
- name: GCC on Linux
@@ -48,15 +49,6 @@ jobs:
os: ubuntu-latest
config: 'CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=address" --disable-flto --disable-static'
make_test: "yes"
- name: Apple iPhone on iOS, armv7
os: macos-latest
AUTOTOOLS_HOST: armv7-apple-ios
OPENSSL_HOST: ios-cross
IOS_SDK: iPhoneOS
IOS_CPU: armv7s
test_ios: "yes"
config: "no"
make: "no"
- name: Apple iPhone on iOS, arm64
os: macos-latest
AUTOTOOLS_HOST: aarch64-apple-ios
@@ -84,15 +76,6 @@ jobs:
test_ios: "yes"
config: "no"
make: "no"
- name: iPhoneSimulator on OS X, i386
os: macos-latest
AUTOTOOLS_HOST: i386-apple-ios
OPENSSL_HOST: iphoneos-cross
IOS_SDK: iPhoneSimulator
IOS_CPU: i386
test_ios: "yes"
config: "no"
make: "no"
- name: iPhoneSimulator on OS X, x86_64
os: macos-latest
AUTOTOOLS_HOST: x86_64-apple-ios
@@ -190,7 +173,7 @@ jobs:
cross_platform_config: "--enable-debug --disable-flto --with-libevent --disable-static"
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
submodules: false
persist-credentials: false
@@ -206,6 +189,8 @@ jobs:
cd ..
export prepath=`pwd`
echo prepath=${prepath}
# parralel build option
export MINJ="-j4"
echo "choco install winflexbison3"
choco install winflexbison3
echo 'LEX="win_flex"'
@@ -228,8 +213,8 @@ jobs:
C:/msys64/usr/bin/perl ./Configure no-shared no-asm -DOPENSSL_NO_CAPIENG mingw64 --prefix="$prepath/openssl" PERL="C:/msys64/usr/bin/perl"
# make the libs only, build faster
echo "make build_libs"
#make
make build_libs
#make $MINJ
make $MINJ build_libs
mv Makefile Makefile.orig
# fixup \\ in the installtop to /.
echo "fixup INSTALLTOP"
@@ -261,7 +246,7 @@ jobs:
mv xmlwf/Makefile xmlwf/Makefile.orig
sed -e 's/SHELL/SHELLZZ/g' < xmlwf/Makefile.orig > xmlwf/Makefile
echo "make"
make
make $MINJ
echo "make install"
make install
cd ..
@@ -269,7 +254,7 @@ jobs:
cd unbound
echo "./configure --enable-debug --enable-static-exe --disable-flto \"--with-ssl=$prepath/openssl\" --with-libexpat=\"$prepath/expat\" --disable-shared"
./configure --enable-debug --enable-static-exe --disable-flto "--with-ssl=$prepath/openssl" --with-libexpat="$prepath/expat" --disable-shared
make
make $MINJ
# specific test output
#make testbound.exe; ./testbound.exe -s
#make testbound; ./testbound.exe -p testdata/acl.rpl -o -vvvv
@@ -364,7 +349,7 @@ jobs:
echo "::endgroup::"
- name: cross-platform-action on ${{ matrix.cross_platform_os }} ${{ matrix.cross_platform_version }}
if: ${{ matrix.with_cross_platform_action == 'yes' }}
uses: cross-platform-actions/action@v0.25.0
uses: cross-platform-actions/action@v1.0.0
env:
CROSS_PLATFORM_OS: ${{ matrix.cross_platform_os }}
with:
+1 -1
View File
@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v7
with:
persist-credentials: false
- name: configure
+13 -10
View File
@@ -4,13 +4,13 @@
[![Packaging status](https://repology.org/badge/tiny-repos/unbound.svg)](https://repology.org/project/unbound/versions)
[![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/unbound.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:unbound)
[![Documentation Status](https://readthedocs.org/projects/unbound/badge/?version=latest)](https://unbound.readthedocs.io/en/latest/?badge=latest)
[![Mastodon Follow](https://img.shields.io/mastodon/follow/109262826617293067?domain=https%3A%2F%2Ffosstodon.org&style=social)](https://fosstodon.org/@nlnetlabs)
[![Mastodon Follow](https://img.shields.io/mastodon/follow/114692612288811644?domain=social.nlnetlabs.nl&style=social)](https://social.nlnetlabs.nl/@nlnetlabs)
Unbound is a validating, recursive, caching DNS resolver. It is designed to be
fast and lean and incorporates modern features based on open standards. If you
have any feedback, we would love to hear from you. Dont hesitate to
[create an issue on Github](https://github.com/NLnetLabs/unbound/issues/new)
or post a message on the [Unbound mailing list](https://lists.nlnetlabs.nl/mailman/listinfo/unbound-users).
or post a message on our [community forum](https://community.nlnetlabs.nl/).
You can learn more about Unbound by reading our
[documentation](https://unbound.docs.nlnetlabs.nl/).
@@ -25,18 +25,21 @@ Unbound can be compiled and installed using:
./configure && make && make install
```
You can use libevent if you want. libevent is useful when using many (10000)
outgoing ports. By default max 256 ports are opened at the same time and the
builtin alternative is equally capable and a little faster.
You can use libevent if you want. libevent is useful when using many (e.g.,
10000) outgoing ports.
Use the `--with-libevent` configure option to compile Unbound with libevent
support.
If not, the default builtin alternative opens max 256 ports at the same time
and is equally capable and a little faster.
## Unbound configuration
All of Unbound's configuration options are described in the man pages, which
will be installed and are available on the Unbound
[documentation page](https://unbound.docs.nlnetlabs.nl/).
All of Unbound's configuration options are described in the `unbound.conf(5)`
man page, which will be installed and is also available on the Unbound
[documentation page](https://unbound.docs.nlnetlabs.nl/en/latest/manpages/unbound.conf.html)
for the latest version.
An example configuration file is located in
An example configuration file, with minimal documentation, is located in
[doc/example.conf](https://github.com/NLnetLabs/unbound/blob/master/doc/example.conf.in).
+65 -12
View File
@@ -2,7 +2,12 @@
# Copyright 2009, Wouter Wijngaards, NLnet Labs.
# BSD licensed.
#
# Version 48
# Version 51
# 2025-11-06 Fix ACX_CHECK_NONSTRING_ATTRIBUTE to reject clang, that prints
# a warning for 'unknown attribute' when nonstring is used.
# 2025-09-29 add ac_cv_func_malloc_0_nonnull as a cache value for the malloc(0)
# check by ACX_FUNC_MALLOC.
# 2025-09-29 add ACX_CHECK_NONSTRING_ATTRIBUTE, AHX_CONFIG_NONSTRING_ATTRIBUTE.
# 2024-01-16 fix to add -l:libssp.a to -lcrypto link check.
# and check for getaddrinfo with only header.
# 2024-01-15 fix to add crypt32 to -lcrypto link check when checking for gdi32.
@@ -71,6 +76,7 @@
# ACX_DEPFLAG - find cc dependency flags.
# ACX_DETERMINE_EXT_FLAGS_UNBOUND - find out which flags enable BSD and POSIX.
# ACX_CHECK_FORMAT_ATTRIBUTE - find cc printf format syntax.
# ACX_CHECK_NONSTRING_ATTRIBUTE - find cc nonstring attribute syntax.
# ACX_CHECK_UNUSED_ATTRIBUTE - find cc variable unused syntax.
# ACX_CHECK_FLTO - see if cc supports -flto and use it if so.
# ACX_LIBTOOL_C_ONLY - create libtool for C only, improved.
@@ -92,6 +98,7 @@
# ACX_FUNC_IOCTLSOCKET - find ioctlsocket, portably.
# ACX_FUNC_MALLOC - check malloc, define replacement .
# AHX_CONFIG_FORMAT_ATTRIBUTE - config.h text for format.
# AHX_CONFIG_NONSTRING_ATTRIBUTE - config.h text for nonstring.
# AHX_CONFIG_UNUSED_ATTRIBUTE - config.h text for unused.
# AHX_CONFIG_FSEEKO - define fseeko, ftello fallback.
# AHX_CONFIG_RAND_MAX - define RAND_MAX if needed.
@@ -490,7 +497,7 @@ AC_DEFUN([AHX_CONFIG_FORMAT_ATTRIBUTE],
])
dnl Check how to mark function arguments as unused.
dnl result in HAVE_ATTR_UNUSED.
dnl result in HAVE_ATTR_UNUSED.
dnl Make sure you include AHX_CONFIG_UNUSED_ATTRIBUTE also.
AC_DEFUN([ACX_CHECK_UNUSED_ATTRIBUTE],
[AC_REQUIRE([AC_PROG_CC])
@@ -525,6 +532,49 @@ if test $ac_cv_c_unused_attribute = yes; then
fi
])dnl
dnl Check how to mark function arguments as nonstring.
dnl result in HAVE_ATTR_NONSTRING.
dnl Make sure you include AHX_CONFIG_NONSTRING_ATTRIBUTE also.
AC_DEFUN([ACX_CHECK_NONSTRING_ATTRIBUTE],
[AC_REQUIRE([AC_PROG_CC])
AC_REQUIRE([ACX_CHECK_ERROR_FLAGS])
BAKCFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $ERRFLAG"
AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "nonstring" attribute)
AC_CACHE_VAL(ac_cv_c_nonstring_attribute,
[ac_cv_c_nonstring_attribute=no
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[#include <stdio.h>
struct test {
char __attribute__((nonstring)) s[1];
};
]], [[
struct test t = { "1" };
(void) t;
]])],[ac_cv_c_nonstring_attribute="yes"],[ac_cv_c_nonstring_attribute="no"])
CFLAGS="$BAKCFLAGS"
])
dnl Setup ATTR_NONSTRING config.h parts.
dnl make sure you call ACX_CHECK_NONSTRING_ATTRIBUTE also.
AC_DEFUN([AHX_CONFIG_NONSTRING_ATTRIBUTE],
[
#if defined(DOXYGEN)
# define ATTR_NONSTRING(x) x
#elif defined(__cplusplus)
# define ATTR_NONSTRING(x) __attribute__((nonstring)) x
#elif defined(HAVE_ATTR_NONSTRING)
# define ATTR_NONSTRING(x) __attribute__((nonstring)) x
#else /* !HAVE_ATTR_NONSTRING */
# define ATTR_NONSTRING(x) x
#endif /* !HAVE_ATTR_NONSTRING */
])
AC_MSG_RESULT($ac_cv_c_nonstring_attribute)
if test $ac_cv_c_nonstring_attribute = yes; then
AC_DEFINE(HAVE_ATTR_NONSTRING, 1, [Whether the C compiler accepts the "nonstring" attribute])
fi
])dnl
dnl Pre-fun for ACX_LIBTOOL_C_ONLY
AC_DEFUN([ACX_LIBTOOL_C_PRE], [
# skip these tests, we do not need them.
@@ -1190,8 +1240,9 @@ dnl detect malloc and provide malloc compat prototype.
dnl $1: unique name for compat code
AC_DEFUN([ACX_FUNC_MALLOC],
[
AC_MSG_CHECKING([for GNU libc compatible malloc])
AC_RUN_IFELSE([AC_LANG_PROGRAM(
AC_CACHE_CHECK([for GNU libc compatible malloc],[ac_cv_func_malloc_0_nonnull],
[
AC_RUN_IFELSE([AC_LANG_PROGRAM(
[[#if defined STDC_HEADERS || defined HAVE_STDLIB_H
#include <stdlib.h>
#else
@@ -1199,14 +1250,16 @@ char *malloc ();
#endif
]], [ if(malloc(0) != 0) return 1;])
],
[AC_MSG_RESULT([no])
AC_LIBOBJ(malloc)
AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])] ,
[AC_MSG_RESULT([yes])
AC_DEFINE([HAVE_MALLOC], 1, [If have GNU libc compatible malloc])],
[AC_MSG_RESULT([no (crosscompile)])
AC_LIBOBJ(malloc)
AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])] )
[ac_cv_func_malloc_0_nonnull=no],
[ac_cv_func_malloc_0_nonnull=yes],
[ac_cv_func_malloc_0_nonnull="no (crosscompile)"])
])
AS_IF([test "$ac_cv_func_malloc_0_nonnull" = yes],
[AC_DEFINE([HAVE_MALLOC], 1, [If have GNU libc compatible malloc])],
[
AC_LIBOBJ(malloc)
AC_DEFINE_UNQUOTED([malloc], [rpl_malloc_$1], [Define if replacement function should be used.])
])
])
dnl Define fallback for fseeko and ftello if needed.
+17 -2
View File
@@ -87,7 +87,7 @@
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 31
#serial 32
AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
AC_DEFUN([AX_PTHREAD], [
@@ -249,7 +249,22 @@ AS_IF([test "x$ax_pthread_clang" = "xyes"],
# correctly enabled
case $host_os in
darwin* | hpux* | linux* | osf* | solaris*)
solaris*)
# Solaris 11.4 introduced XPG7 support and did away with the need for
# _REENTRANT.
AC_EGREP_CPP([AX_PTHREAD_SOLARIS__REENTRANT],
[
# undef _XOPEN_SOURCE
# include <sys/feature_tests.h>
# if _XOPEN_VERSION < 700
AX_PTHREAD_SOLARIS__REENTRANT
# endif
],
[ax_pthread_check_macro="_REENTRANT"],
[ax_pthread_check_macro="--"])
;;
darwin* | hpux* | linux* | osf*)
ax_pthread_check_macro="_REENTRANT"
;;
+73 -46
View File
@@ -401,12 +401,15 @@ prep_data(struct module_qstate* qstate, struct sldns_buffer* buf)
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
* dns_cache_store_msg(). */
if(qstate->return_msg->rep->ttl == 0 &&
!qstate->env->cfg->serve_expired)
/* Do not persist data the validator has not yet seen, or has rejected.
* Otherwise an expired blob could maybe reach clients via
* serve-expired. */
if(qstate->env->need_to_validate &&
qstate->return_msg->rep->security == sec_status_bogus)
return 0;
/* We don't store the reply if its TTL is 0. This is probably coming
* from upstream and it is not meant to be stored. */
if(qstate->return_msg->rep->ttl == 0)
return 0;
/* The EDE is added to the out-list so it is encoded in the cached message */
@@ -460,7 +463,7 @@ good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf)
* - serve_expired needs to be set
* - if SERVE_EXPIRED_TTL is set make sure that the record is not older
* than that. */
if((time_t)expiry < *qstate->env->now &&
if(TTL_IS_EXPIRED((time_t)expiry, *qstate->env->now) &&
(!qstate->env->cfg->serve_expired ||
(SERVE_EXPIRED_TTL &&
*qstate->env->now - (time_t)expiry > SERVE_EXPIRED_TTL)))
@@ -472,7 +475,8 @@ good_expiry_and_qinfo(struct module_qstate* qstate, struct sldns_buffer* buf)
/* Adjust the TTL of the given RRset by 'subtract'. If 'subtract' is
* negative, set the TTL to 0. */
static void
packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract)
packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract,
time_t timestamp)
{
size_t i;
size_t total = data->count + data->rrsig_count;
@@ -484,13 +488,13 @@ packed_rrset_ttl_subtract(struct packed_rrset_data* data, time_t subtract)
data->rr_ttl[i] -= subtract;
else data->rr_ttl[i] = 0;
}
data->ttl_add = (subtract < data->ttl_add) ? (data->ttl_add - subtract) : 0;
data->ttl_add = timestamp;
}
/* Adjust the TTL of a DNS message and its RRs by 'adjust'. If 'adjust' is
* negative, set the TTLs to 0. */
static void
adjust_msg_ttl(struct dns_msg* msg, time_t adjust)
adjust_msg_ttl(struct dns_msg* msg, time_t adjust, time_t timestamp)
{
size_t i;
if(adjust >= 0 && msg->rep->ttl > adjust)
@@ -502,13 +506,13 @@ adjust_msg_ttl(struct dns_msg* msg, time_t adjust)
for(i=0; i<msg->rep->rrset_count; i++) {
packed_rrset_ttl_subtract((struct packed_rrset_data*)msg->
rep->rrsets[i]->entry.data, adjust);
rep->rrsets[i]->entry.data, adjust, timestamp);
}
}
/* Set the TTL of the given RRset to fixed value. */
static void
packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl)
packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl, time_t timestamp)
{
size_t i;
size_t total = data->count + data->rrsig_count;
@@ -516,12 +520,12 @@ packed_rrset_ttl_set(struct packed_rrset_data* data, time_t ttl)
for(i=0; i<total; i++) {
data->rr_ttl[i] = ttl;
}
data->ttl_add = 0;
data->ttl_add = timestamp;
}
/* Set the TTL of a DNS message and its RRs by to a fixed value. */
static void
set_msg_ttl(struct dns_msg* msg, time_t ttl)
set_msg_ttl(struct dns_msg* msg, time_t ttl, time_t timestamp)
{
size_t i;
msg->rep->ttl = ttl;
@@ -530,14 +534,14 @@ set_msg_ttl(struct dns_msg* msg, time_t ttl)
for(i=0; i<msg->rep->rrset_count; i++) {
packed_rrset_ttl_set((struct packed_rrset_data*)msg->
rep->rrsets[i]->entry.data, ttl);
rep->rrsets[i]->entry.data, ttl, timestamp);
}
}
/** convert dns message in buffer to return_msg */
static int
parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
int* msg_expired)
int* msg_expired, time_t* msg_timestamp, time_t* msg_expiry)
{
struct msg_parse* prs;
struct edns_data edns;
@@ -554,6 +558,9 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
&timestamp, sizeof(timestamp));
expiry = be64toh(expiry);
timestamp = be64toh(timestamp);
log_assert(timestamp <= expiry);
*msg_expiry = (time_t)expiry;
*msg_timestamp = (time_t)timestamp;
/* parse DNS packet */
regional_free_all(qstate->env->scratch);
@@ -605,11 +612,9 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
return 1; /* message from the future (clock skew?) */
}
adjust = *qstate->env->now - (time_t)timestamp;
if(qstate->return_msg->rep->ttl < adjust) {
if(TTL_IS_EXPIRED((time_t)expiry, *qstate->env->now)) {
verbose(VERB_ALGO, "cachedb msg expired");
*msg_expired = 1;
/* If serve-expired is enabled, we still use an expired message
* setting the TTL to 0. */
if(!qstate->env->cfg->serve_expired ||
(FLAGS_GET_RCODE(qstate->return_msg->rep->flags)
!= LDNS_RCODE_NOERROR &&
@@ -618,23 +623,21 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
FLAGS_GET_RCODE(qstate->return_msg->rep->flags)
!= LDNS_RCODE_YXDOMAIN))
return 0; /* message expired */
else
adjust = -1;
/* If serve-expired is enabled, we still use an expired message.
* Set the TTL to 0 now and it will be handled specially later
* when we need to store it internally. */
adjust = -1;
}
adjust_msg_ttl(qstate->return_msg, adjust, timestamp);
verbose(VERB_ALGO, "cachedb msg adjusted down by %d", (int)adjust);
adjust_msg_ttl(qstate->return_msg, adjust);
if(qstate->env->cfg->aggressive_nsec) {
limit_nsec_ttl(qstate->return_msg);
}
/* Similar to the unbound worker, if serve-expired is enabled and
* the msg would be considered to be expired, mark the state so a
* refetch will be scheduled. The comparison between 'expiry' and
* 'now' should be redundant given how these values were calculated,
* but we check it just in case as does good_expiry_and_qinfo(). */
if(qstate->env->cfg->serve_expired &&
!qstate->env->cfg->serve_expired_client_timeout &&
(adjust == -1 || (time_t)expiry < *qstate->env->now)) {
* refetch will be scheduled. */
if(*msg_expired && !qstate->env->cfg->serve_expired_client_timeout) {
qstate->need_refetch = 1;
}
@@ -647,7 +650,7 @@ parse_data(struct module_qstate* qstate, struct sldns_buffer* buf,
*/
static int
cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie,
int* msg_expired)
int* msg_expired, time_t* msg_timestamp, time_t* msg_expiry)
{
char key[(CACHEDB_HASHSIZE/8)*2+1];
calc_hash(&qstate->qinfo, qstate->env, key, sizeof(key));
@@ -664,7 +667,8 @@ cachedb_extcache_lookup(struct module_qstate* qstate, struct cachedb_env* ie,
}
/* parse dns message into return_msg */
if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired) ) {
if( !parse_data(qstate, qstate->env->scratch_buffer, msg_expired,
msg_timestamp, msg_expiry) ) {
return 0;
}
return 1;
@@ -736,24 +740,30 @@ cachedb_intcache_lookup(struct module_qstate* qstate, struct cachedb_env* cde)
* Store query into the internal cache of unbound.
*/
static void
cachedb_intcache_store(struct module_qstate* qstate, int msg_expired)
cachedb_intcache_store(struct module_qstate* qstate, int msg_expired,
time_t msg_timestamp, time_t msg_expiry)
{
uint32_t store_flags = qstate->query_flags;
int serve_expired = qstate->env->cfg->serve_expired;
if(qstate->env->cfg->serve_expired)
store_flags |= DNSCACHE_STORE_ZEROTTL;
if(!qstate->return_msg)
return;
if(serve_expired && msg_expired) {
/* Set TTLs to a value such that value + *env->now is
* going to be now-3 seconds. Making it expired
* in the cache. */
set_msg_ttl(qstate->return_msg, (time_t)-3);
time_t original_ttl = msg_expiry - msg_timestamp;
store_flags |= DNSCACHE_STORE_EXPIRED_MSG_CACHEDB;
/* Pass the original TTL of the expired message and signal with
* the DNSCACHE_STORE_EXPIRED_MSG_CACHEDB flag that
* dns_cache_store_msg() needs to set absolute expired TTLs
* based on the original message TTL.
* Results as expired message in the cache */
set_msg_ttl(qstate->return_msg, original_ttl, 0);
verbose(VERB_ALGO, "cachedb expired msg set to be expired now "
"(original ttl: %d)", (int)original_ttl);
/* The expired entry does not get checked by the validator
* and we need a validation value for it. */
/* By setting this to unchecked, bogus data is not returned
* as non-bogus. */
if(qstate->env->cfg->cachedb_check_when_serve_expired)
qstate->return_msg->rep->security = sec_status_insecure;
qstate->return_msg->rep->security = sec_status_unchecked;
}
(void)dns_cache_store(qstate->env, &qstate->qinfo,
qstate->return_msg->rep, 0, qstate->prefetch_leeway, 0,
@@ -767,12 +777,14 @@ cachedb_intcache_store(struct module_qstate* qstate, int msg_expired)
* of cache. */
return;
}
/* set TTLs to zero again */
adjust_msg_ttl(qstate->return_msg, -1);
/* Send serve expired responses based on the cachedb
* returned message, that was just stored in the cache.
* It can then continue to work on this query. */
mesh_respond_serve_expired(qstate->mesh_info);
/* set TTLs as expired for this return_msg in case it is used
* later on */
set_msg_ttl(qstate->return_msg,
EXPIRED_REPLY_TTL_CALC(msg_expiry, msg_timestamp), 0);
}
}
@@ -790,6 +802,7 @@ cachedb_handle_query(struct module_qstate* qstate,
struct cachedb_env* ie, int id)
{
int msg_expired = 0;
time_t msg_timestamp, msg_expiry;
qstate->is_cachedb_answer = 0;
/* check if we are enabled, and skip if so */
if(!ie->enabled) {
@@ -798,8 +811,11 @@ cachedb_handle_query(struct module_qstate* qstate,
return;
}
if(qstate->blacklist || qstate->no_cache_lookup) {
/* cache is blacklisted or we are instructed from edns to not look */
if(qstate->blacklist || qstate->no_cache_lookup
|| iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL,
NULL, 0)) {
/* cache is blacklisted or we are instructed from edns to not
* look or a forwarder/stub forbids it */
/* pass request to next module */
qstate->ext_state[id] = module_wait_module;
return;
@@ -824,13 +840,15 @@ cachedb_handle_query(struct module_qstate* qstate,
}
/* ask backend cache to see if we have data */
if(cachedb_extcache_lookup(qstate, ie, &msg_expired)) {
if(cachedb_extcache_lookup(qstate, ie, &msg_expired, &msg_timestamp,
&msg_expiry)) {
if(verbosity >= VERB_ALGO)
log_dns_msg(ie->backend->name,
&qstate->return_msg->qinfo,
qstate->return_msg->rep);
/* store this result in internal cache */
cachedb_intcache_store(qstate, msg_expired);
cachedb_intcache_store(qstate,
msg_expired, msg_timestamp, msg_expiry);
/* In case we have expired data but there is a client timer for expired
* answers, pass execution to next module in order to try updating the
* data first.
@@ -850,6 +868,13 @@ cachedb_handle_query(struct module_qstate* qstate,
qstate->ext_state[id] = module_wait_module;
return;
}
/* No 0TTL answers escaping from external cache. */
if(qstate->return_msg->rep->ttl == 0) {
qstate->return_msg = NULL;
qstate->ext_state[id] = module_wait_module;
return;
}
log_assert(qstate->return_msg->rep->ttl > 0);
qstate->is_cachedb_answer = 1;
/* we are done with the query */
qstate->ext_state[id] = module_finished;
@@ -883,7 +908,9 @@ cachedb_handle_response(struct module_qstate* qstate,
{
qstate->is_cachedb_answer = 0;
/* check if we are not enabled or instructed to not cache, and skip */
if(!ie->enabled || qstate->no_cache_store) {
if(!ie->enabled || qstate->no_cache_store
|| iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL,
NULL, 0)) {
/* we are done with the query */
qstate->ext_state[id] = module_finished;
return;
+6
View File
@@ -143,6 +143,12 @@ redis_connect(const char* host, int port, const char* path,
{
struct timeval now_val;
redisContext* ctx;
#ifdef THREADS_DISABLED
/* Fix attribute unused warning.
* wait_lock is only used with lock_basic_* functions that are nop'ed
* when compiled without thread support. */
(void)wait_lock;
#endif /* THREADS_DISABLED */
/* See if the redis server is down, and reconnect has to wait. */
if(*reconnect_attempts > REDIS_RECONNECT_ATTEMPT_LIMIT) {
+7
View File
@@ -38,6 +38,9 @@
#ifndef UB_ON_WINDOWS
#include <sys/mman.h>
#endif
#ifdef __QNX__
#include "util/log.h"
#endif /* __QNX__ */
#define KEYSTREAM_ONLY
#include "chacha_private.h"
@@ -187,7 +190,11 @@ _rs_stir(void)
if(errno != ENOSYS ||
fallback_getentropy_urandom(rnd, sizeof rnd) == -1) {
#ifdef SIGKILL
#ifndef __QNX__
raise(SIGKILL);
#else /* !__QNX__ */
fatal_exit("failed to getentropy");
#endif /* __QNX__ */
#else
exit(9); /* windows */
#endif
+2 -2
View File
@@ -48,8 +48,8 @@ typedef struct
a = PLUS(a,b); d = ROTATE(XOR(d,a), 8); \
c = PLUS(c,d); b = ROTATE(XOR(b,c), 7);
static const char sigma[16] = "expand 32-byte k";
static const char tau[16] = "expand 16-byte k";
static const char ATTR_NONSTRING(sigma[16]) = "expand 32-byte k";
static const char ATTR_NONSTRING(tau[16]) = "expand 16-byte k";
static void
chacha_keysetup(chacha_ctx *x,const u8 *k,u32 kbits,u32 ATTR_UNUSED(ivbits))
+20
View File
@@ -29,7 +29,9 @@
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#ifndef __QNX__
#include <sys/syscall.h>
#endif /* !__QNX__ */
#ifdef SYS__sysctl
#include <linux/sysctl.h>
#endif
@@ -42,7 +44,9 @@
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#ifndef __QNX__
#include <link.h>
#endif /* __QNX__ */
#include <termios.h>
#include <fcntl.h>
#include <signal.h>
@@ -60,12 +64,14 @@
#define SHA512_Final(r, c) sha512_digest(c, SHA512_DIGEST_SIZE, r)
#endif
#ifndef __QNX__
#include <linux/types.h>
#include <linux/random.h>
#ifdef HAVE_GETAUXVAL
#include <sys/auxv.h>
#endif
#include <sys/vfs.h>
#endif /* !__QNX__ */
#ifndef MAP_ANON
#define MAP_ANON MAP_ANONYMOUS
#endif
@@ -94,8 +100,10 @@ static int getentropy_urandom(void *buf, size_t len);
#ifdef SYS__sysctl
static int getentropy_sysctl(void *buf, size_t len);
#endif
#ifndef __QNX__
static int getentropy_fallback(void *buf, size_t len);
static int getentropy_phdr(struct dl_phdr_info *info, size_t size, void *data);
#endif /* !__QNX__ */
int
getentropy(void *buf, size_t len)
@@ -178,6 +186,7 @@ getentropy(void *buf, size_t len)
* sysctl ABI, or consider providing a new failsafe API which
* works in a chroot or when file descriptors are exhausted.
*/
#ifndef __QNX__
#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
raise(SIGKILL);
@@ -185,6 +194,9 @@ getentropy(void *buf, size_t len)
ret = getentropy_fallback(buf, len);
if (ret != -1)
return (ret);
#else /* !__QNX__ */
fatal_exit("failed to read from /dev/urandom");
#endif /* __QNX__ */
errno = EIO;
return (ret);
@@ -214,7 +226,11 @@ getentropy_urandom(void *buf, size_t len)
{
struct stat st;
size_t i;
#ifndef __QNX__
int fd, cnt, flags;
#else /* !__QNX__ */
int fd, flags;
#endif /* __QNX__ */
int save_errno = errno;
start:
@@ -241,10 +257,12 @@ start:
close(fd);
goto nodevrandom;
}
#ifndef __QNX__
if (ioctl(fd, RNDGETENTCNT, &cnt) == -1) {
close(fd);
goto nodevrandom;
}
#endif /* !__QNX__ */
for (i = 0; i < len; ) {
size_t wanted = len - i;
ssize_t ret = read(fd, (char *)buf + i, wanted);
@@ -265,6 +283,7 @@ nodevrandom:
return (-1);
}
#ifndef __QNX__
#ifdef SYS__sysctl
static int
getentropy_sysctl(void *buf, size_t len)
@@ -537,3 +556,4 @@ getentropy_fallback(void *buf, size_t len)
errno = save_errno;
return (0); /* satisfied */
}
#endif /* !__QNX__ */
+9 -382
View File
@@ -20,398 +20,25 @@
* http://man.openbsd.org/getentropy.2
*/
#include <TargetConditionals.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/ioctl.h>
#include <sys/resource.h>
#include <sys/syscall.h>
#include <sys/sysctl.h>
#include <sys/statvfs.h>
#include <sys/socket.h>
#include <sys/mount.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <termios.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
/* Modified to use SecRandomCopyBytes. It is from macOS 10.7 (2011) and
* iOS 2.0 (2008), and is the primary API for cryptographic random numbers. */
#include <errno.h>
#include <unistd.h>
#include <time.h>
#include <mach/mach_time.h>
#include <mach/mach_host.h>
#include <mach/host_info.h>
#if TARGET_OS_OSX
#include <sys/socketvar.h>
#include <sys/vmmeter.h>
#endif
#include <netinet/in.h>
#include <netinet/tcp.h>
#if TARGET_OS_OSX
#include <netinet/udp.h>
#include <netinet/ip_var.h>
#include <netinet/tcp_var.h>
#include <netinet/udp_var.h>
#endif
#include <CommonCrypto/CommonDigest.h>
#define SHA512_Update(a, b, c) (CC_SHA512_Update((a), (b), (c)))
#define SHA512_Init(xxx) (CC_SHA512_Init((xxx)))
#define SHA512_Final(xxx, yyy) (CC_SHA512_Final((xxx), (yyy)))
#define SHA512_CTX CC_SHA512_CTX
#define SHA512_DIGEST_LENGTH CC_SHA512_DIGEST_LENGTH
#define REPEAT 5
#define min(a, b) (((a) < (b)) ? (a) : (b))
#define HX(a, b) \
do { \
if ((a)) \
HD(errno); \
else \
HD(b); \
} while (0)
#define HR(x, l) (SHA512_Update(&ctx, (char *)(x), (l)))
#define HD(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (x)))
#define HF(x) (SHA512_Update(&ctx, (char *)&(x), sizeof (void*)))
#include <Security/SecRandom.h>
int getentropy(void *buf, size_t len);
static int getentropy_urandom(void *buf, size_t len);
static int getentropy_fallback(void *buf, size_t len);
int
getentropy(void *buf, size_t len)
{
int ret = -1;
if (len > 256) {
errno = EIO;
return (-1);
goto error;
}
/*
* Try to get entropy with /dev/urandom
*
* This can fail if the process is inside a chroot or if file
* descriptors are exhausted.
*/
ret = getentropy_urandom(buf, len);
if (ret != -1)
return (ret);
/*
* Entropy collection via /dev/urandom and sysctl have failed.
*
* No other API exists for collecting entropy, and we have
* no failsafe way to get it on OSX that is not sensitive
* to resource exhaustion.
*
* We have very few options:
* - Even syslog_r is unsafe to call at this low level, so
* there is no way to alert the user or program.
* - Cannot call abort() because some systems have unsafe
* corefiles.
* - Could raise(SIGKILL) resulting in silent program termination.
* - Return EIO, to hint that arc4random's stir function
* should raise(SIGKILL)
* - Do the best under the circumstances....
*
* This code path exists to bring light to the issue that OSX
* does not provide a failsafe API for entropy collection.
*
* We hope this demonstrates that OSX should consider
* providing a new failsafe API which works in a chroot or
* when file descriptors are exhausted.
*/
#undef FAIL_INSTEAD_OF_TRYING_FALLBACK
#ifdef FAIL_INSTEAD_OF_TRYING_FALLBACK
raise(SIGKILL);
#endif
ret = getentropy_fallback(buf, len);
if (ret != -1)
return (ret);
if (SecRandomCopyBytes(kSecRandomDefault, len, buf) == errSecSuccess) {
return 0;
}
error:
errno = EIO;
return (ret);
}
static int
getentropy_urandom(void *buf, size_t len)
{
struct stat st;
size_t i;
int fd, flags;
int save_errno = errno;
start:
flags = O_RDONLY;
#ifdef O_NOFOLLOW
flags |= O_NOFOLLOW;
#endif
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif
fd = open("/dev/urandom", flags, 0);
if (fd == -1) {
if (errno == EINTR)
goto start;
goto nodevrandom;
}
#ifndef O_CLOEXEC
fcntl(fd, F_SETFD, fcntl(fd, F_GETFD) | FD_CLOEXEC);
#endif
/* Lightly verify that the device node looks sane */
if (fstat(fd, &st) == -1 || !S_ISCHR(st.st_mode)) {
close(fd);
goto nodevrandom;
}
for (i = 0; i < len; ) {
size_t wanted = len - i;
ssize_t ret = read(fd, (char *)buf + i, wanted);
if (ret == -1) {
if (errno == EAGAIN || errno == EINTR)
continue;
close(fd);
goto nodevrandom;
}
i += ret;
}
close(fd);
errno = save_errno;
return (0); /* satisfied */
nodevrandom:
errno = EIO;
return (-1);
}
#if TARGET_OS_OSX
static int tcpmib[] = { CTL_NET, AF_INET, IPPROTO_TCP, TCPCTL_STATS };
static int udpmib[] = { CTL_NET, AF_INET, IPPROTO_UDP, UDPCTL_STATS };
static int ipmib[] = { CTL_NET, AF_INET, IPPROTO_IP, IPCTL_STATS };
#endif
static int kmib[] = { CTL_KERN, KERN_USRSTACK };
static int hwmib[] = { CTL_HW, HW_USERMEM };
static int
getentropy_fallback(void *buf, size_t len)
{
uint8_t results[SHA512_DIGEST_LENGTH];
int save_errno = errno, e, pgs = getpagesize(), faster = 0, repeat;
static int cnt;
struct timespec ts;
struct timeval tv;
struct rusage ru;
sigset_t sigset;
struct stat st;
SHA512_CTX ctx;
static pid_t lastpid;
pid_t pid;
size_t i, ii, m;
char *p;
#if TARGET_OS_OSX
struct tcpstat tcpstat;
struct udpstat udpstat;
struct ipstat ipstat;
#endif
u_int64_t mach_time;
unsigned int idata;
void *addr;
pid = getpid();
if (lastpid == pid) {
faster = 1;
repeat = 2;
} else {
faster = 0;
lastpid = pid;
repeat = REPEAT;
}
for (i = 0; i < len; ) {
int j;
SHA512_Init(&ctx);
for (j = 0; j < repeat; j++) {
HX((e = gettimeofday(&tv, NULL)) == -1, tv);
if (e != -1) {
cnt += (int)tv.tv_sec;
cnt += (int)tv.tv_usec;
}
mach_time = mach_absolute_time();
HD(mach_time);
ii = sizeof(addr);
HX(sysctl(kmib, sizeof(kmib) / sizeof(kmib[0]),
&addr, &ii, NULL, 0) == -1, addr);
ii = sizeof(idata);
HX(sysctl(hwmib, sizeof(hwmib) / sizeof(hwmib[0]),
&idata, &ii, NULL, 0) == -1, idata);
#if TARGET_OS_OSX
ii = sizeof(tcpstat);
HX(sysctl(tcpmib, sizeof(tcpmib) / sizeof(tcpmib[0]),
&tcpstat, &ii, NULL, 0) == -1, tcpstat);
ii = sizeof(udpstat);
HX(sysctl(udpmib, sizeof(udpmib) / sizeof(udpmib[0]),
&udpstat, &ii, NULL, 0) == -1, udpstat);
ii = sizeof(ipstat);
HX(sysctl(ipmib, sizeof(ipmib) / sizeof(ipmib[0]),
&ipstat, &ii, NULL, 0) == -1, ipstat);
#endif
HX((pid = getpid()) == -1, pid);
HX((pid = getsid(pid)) == -1, pid);
HX((pid = getppid()) == -1, pid);
HX((pid = getpgid(0)) == -1, pid);
HX((e = getpriority(0, 0)) == -1, e);
if (!faster) {
ts.tv_sec = 0;
ts.tv_nsec = 1;
(void) nanosleep(&ts, NULL);
}
HX(sigpending(&sigset) == -1, sigset);
HX(sigprocmask(SIG_BLOCK, NULL, &sigset) == -1,
sigset);
HF(getentropy); /* an addr in this library */
HF(printf); /* an addr in libc */
p = (char *)&p;
HD(p); /* an addr on stack */
p = (char *)&errno;
HD(p); /* the addr of errno */
if (i == 0) {
struct sockaddr_storage ss;
struct statvfs stvfs;
struct termios tios;
struct statfs stfs;
socklen_t ssl;
off_t off;
/*
* Prime-sized mappings encourage fragmentation;
* thus exposing some address entropy.
*/
struct mm {
size_t npg;
void *p;
} mm[] = {
{ 17, MAP_FAILED }, { 3, MAP_FAILED },
{ 11, MAP_FAILED }, { 2, MAP_FAILED },
{ 5, MAP_FAILED }, { 3, MAP_FAILED },
{ 7, MAP_FAILED }, { 1, MAP_FAILED },
{ 57, MAP_FAILED }, { 3, MAP_FAILED },
{ 131, MAP_FAILED }, { 1, MAP_FAILED },
};
for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
HX(mm[m].p = mmap(NULL,
mm[m].npg * pgs,
PROT_READ|PROT_WRITE,
MAP_PRIVATE|MAP_ANON, -1,
(off_t)0), mm[m].p);
if (mm[m].p != MAP_FAILED) {
size_t mo;
/* Touch some memory... */
p = mm[m].p;
mo = cnt %
(mm[m].npg * pgs - 1);
p[mo] = 1;
cnt += (int)((long)(mm[m].p)
/ pgs);
}
/* Check cnts and times... */
mach_time = mach_absolute_time();
HD(mach_time);
cnt += (int)mach_time;
HX((e = getrusage(RUSAGE_SELF,
&ru)) == -1, ru);
if (e != -1) {
cnt += (int)ru.ru_utime.tv_sec;
cnt += (int)ru.ru_utime.tv_usec;
}
}
for (m = 0; m < sizeof mm/sizeof(mm[0]); m++) {
if (mm[m].p != MAP_FAILED)
munmap(mm[m].p, mm[m].npg * pgs);
mm[m].p = MAP_FAILED;
}
HX(stat(".", &st) == -1, st);
HX(statvfs(".", &stvfs) == -1, stvfs);
HX(statfs(".", &stfs) == -1, stfs);
HX(stat("/", &st) == -1, st);
HX(statvfs("/", &stvfs) == -1, stvfs);
HX(statfs("/", &stfs) == -1, stfs);
HX((e = fstat(0, &st)) == -1, st);
if (e == -1) {
if (S_ISREG(st.st_mode) ||
S_ISFIFO(st.st_mode) ||
S_ISSOCK(st.st_mode)) {
HX(fstatvfs(0, &stvfs) == -1,
stvfs);
HX(fstatfs(0, &stfs) == -1,
stfs);
HX((off = lseek(0, (off_t)0,
SEEK_CUR)) < 0, off);
}
if (S_ISCHR(st.st_mode)) {
HX(tcgetattr(0, &tios) == -1,
tios);
} else if (S_ISSOCK(st.st_mode)) {
memset(&ss, 0, sizeof ss);
ssl = sizeof(ss);
HX(getpeername(0,
(void *)&ss, &ssl) == -1,
ss);
}
}
HX((e = getrusage(RUSAGE_CHILDREN,
&ru)) == -1, ru);
if (e != -1) {
cnt += (int)ru.ru_utime.tv_sec;
cnt += (int)ru.ru_utime.tv_usec;
}
} else {
/* Subsequent hashes absorb previous result */
HD(results);
}
HX((e = gettimeofday(&tv, NULL)) == -1, tv);
if (e != -1) {
cnt += (int)tv.tv_sec;
cnt += (int)tv.tv_usec;
}
HD(cnt);
}
SHA512_Final(results, &ctx);
memcpy((char *)buf + i, results, min(sizeof(results), len - i));
i += min(sizeof(results), len - i);
}
explicit_bzero(&ctx, sizeof ctx);
explicit_bzero(results, sizeof results);
errno = save_errno;
return (0); /* satisfied */
return -1;
}
+1 -4
View File
@@ -42,10 +42,7 @@ static const int year_lengths[2] = {
};
static void
timesub(timep, offset, tmp)
const time_t * const timep;
const long offset;
struct tm * const tmp;
timesub(const time_t * const timep, const long offset, struct tm * const tmp)
{
long days;
long rem;
+3 -10
View File
@@ -59,10 +59,7 @@ static int inet_pton6 (const char *src, uint8_t *dst);
* Paul Vixie, 1996.
*/
int
inet_pton(af, src, dst)
int af;
const char *src;
void *dst;
inet_pton(int af, const char *src, void *dst)
{
switch (af) {
case AF_INET:
@@ -91,9 +88,7 @@ inet_pton(af, src, dst)
* Paul Vixie, 1996.
*/
static int
inet_pton4(src, dst)
const char *src;
uint8_t *dst;
inet_pton4(const char *src, uint8_t *dst)
{
static const char digits[] = "0123456789";
int saw_digit, octets, ch;
@@ -145,9 +140,7 @@ inet_pton4(src, dst)
* Paul Vixie, 1996.
*/
static int
inet_pton6(src, dst)
const char *src;
uint8_t *dst;
inet_pton6(const char *src, uint8_t *dst)
{
static const char xdigits_l[] = "0123456789abcdef",
xdigits_u[] = "0123456789ABCDEF";
+67
View File
@@ -31,6 +31,9 @@
/* Whether daemon is deprecated */
#undef DEPRECATED_DAEMON
/* Whether X509_NAME_get_text_by_NID is deprecated */
#undef DEPRECATED_X509_NAME_GET_TEXT_BY_NID
/* Deprecate RSA 1024 bit length, makes that an unsupported key */
#undef DEPRECATE_RSA_1024
@@ -60,12 +63,18 @@
/* Define to 1 if you have the <arpa/inet.h> header file. */
#undef HAVE_ARPA_INET_H
/* Define to 1 if you have the `ASN1_STRING_get0_data' function. */
#undef HAVE_ASN1_STRING_GET0_DATA
/* Whether the C compiler accepts the "fallthrough" attribute */
#undef HAVE_ATTR_FALLTHROUGH
/* Whether the C compiler accepts the "format" attribute */
#undef HAVE_ATTR_FORMAT
/* Whether the C compiler accepts the "nonstring" attribute */
#undef HAVE_ATTR_NONSTRING
/* Whether the C compiler accepts the "noreturn" attribute */
#undef HAVE_ATTR_NORETURN
@@ -137,6 +146,10 @@
to 0 if you don't. */
#undef HAVE_DECL_NGTCP2_CRYPTO_ENCRYPT_CB
/* Define to 1 if you have the declaration of `ngtcp2_crypto_ossl_ctx_new',
and to 0 if you don't. */
#undef HAVE_DECL_NGTCP2_CRYPTO_OSSL_CTX_NEW
/* Define to 1 if you have the declaration of `NID_ED25519', and to 0 if you
don't. */
#undef HAVE_DECL_NID_ED25519
@@ -286,6 +299,12 @@
/* Define to 1 if you have the `FIPS_mode' function. */
#undef HAVE_FIPS_MODE
/* Define to 1 if you have the `fnmatch' function. */
#undef HAVE_FNMATCH
/* Define to 1 if you have the <fnmatch.h> header file. */
#undef HAVE_FNMATCH_H
/* Define to 1 if you have the `fork' function. */
#undef HAVE_FORK
@@ -510,6 +529,9 @@
/* Define to 1 if you have the <openssl/bn.h> header file. */
#undef HAVE_OPENSSL_BN_H
/* Define to 1 if you have the `OPENSSL_cleanup' function. */
#undef HAVE_OPENSSL_CLEANUP
/* Define to 1 if you have the `OPENSSL_config' function. */
#undef HAVE_OPENSSL_CONFIG
@@ -561,12 +583,27 @@
/* Define if you have POSIX threads libraries and header files. */
#undef HAVE_PTHREAD
/* Define to 1 if you have the <pthread_np.h> header file. */
#undef HAVE_PTHREAD_NP_H
/* Have PTHREAD_PRIO_INHERIT. */
#undef HAVE_PTHREAD_PRIO_INHERIT
/* Define to 1 if the system has the type `pthread_rwlock_t'. */
#undef HAVE_PTHREAD_RWLOCK_T
/* Define if pthread_setname_np has the common 2 arguments. */
#undef HAVE_PTHREAD_SETNAME_NP
/* Define if pthread_setname_np has only 1 argument. */
#undef HAVE_PTHREAD_SETNAME_NP1
/* Define if pthread_setname_np has 3 arguments. */
#undef HAVE_PTHREAD_SETNAME_NP3
/* Define if pthread_setname_np exists as pthread_set_name_np instead. */
#undef HAVE_PTHREAD_SET_NAME_NP
/* Define to 1 if the system has the type `pthread_spinlock_t'. */
#undef HAVE_PTHREAD_SPINLOCK_T
@@ -667,9 +704,16 @@
/* Define to 1 if you have the `SSL_is_quic' function. */
#undef HAVE_SSL_IS_QUIC
/* Define to 1 if you have the `SSL_set1_dnsname' function. */
#undef HAVE_SSL_SET1_DNSNAME
/* Define to 1 if you have the `SSL_set1_host' function. */
#undef HAVE_SSL_SET1_HOST
/* Define to 1 if you have the `SSL_set_quic_tls_early_data_enabled' function.
*/
#undef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED
/* Define to 1 if you have the <stdarg.h> header file. */
#undef HAVE_STDARG_H
@@ -732,6 +776,12 @@
/* Define to 1 if `sun_len' is a member of `struct sockaddr_un'. */
#undef HAVE_STRUCT_SOCKADDR_UN_SUN_LEN
/* Define to 1 if `st_mtimensec' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIMENSEC
/* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */
#undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC
/* Define if you have Swig libraries and header files. */
#undef HAVE_SWIG
@@ -828,6 +878,12 @@
/* Define to 1 if you have the <ws2tcpip.h> header file. */
#undef HAVE_WS2TCPIP_H
/* Define to 1 if you have the `X509_get_key_usage' function. */
#undef HAVE_X509_GET_KEY_USAGE
/* Define to 1 if you have the `X509_NAME_get_text_by_NID' function. */
#undef HAVE_X509_NAME_GET_TEXT_BY_NID
/* Define to 1 if you have the `X509_VERIFY_PARAM_set1_host' function. */
#undef HAVE_X509_VERIFY_PARAM_SET1_HOST
@@ -1381,6 +1437,17 @@
#endif /* !HAVE_ATTR_UNUSED */
#if defined(DOXYGEN)
# define ATTR_NONSTRING(x) x
#elif defined(__cplusplus)
# define ATTR_NONSTRING(x) __attribute__((nonstring)) x
#elif defined(HAVE_ATTR_NONSTRING)
# define ATTR_NONSTRING(x) __attribute__((nonstring)) x
#else /* !HAVE_ATTR_NONSTRING */
# define ATTR_NONSTRING(x) x
#endif /* !HAVE_ATTR_NONSTRING */
#ifndef HAVE_FSEEKO
#define fseeko fseek
#define ftello ftell
Vendored
+470 -51
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for unbound 1.24.2.
# Generated by GNU Autoconf 2.71 for unbound 1.26.1.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>.
#
@@ -622,8 +622,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
PACKAGE_VERSION='1.24.2'
PACKAGE_STRING='unbound 1.24.2'
PACKAGE_VERSION='1.26.1'
PACKAGE_STRING='unbound 1.26.1'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
PACKAGE_URL=''
@@ -1513,7 +1513,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures unbound 1.24.2 to adapt to many kinds of systems.
\`configure' configures unbound 1.26.1 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1579,7 +1579,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of unbound 1.24.2:";;
short | recursive ) echo "Configuration of unbound 1.26.1:";;
esac
cat <<\_ACEOF
@@ -1832,7 +1832,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
unbound configure 1.24.2
unbound configure 1.26.1
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2489,7 +2489,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by unbound $as_me 1.24.2, which was
It was created by unbound $as_me 1.26.1, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -3251,13 +3251,13 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
UNBOUND_VERSION_MAJOR=1
UNBOUND_VERSION_MINOR=24
UNBOUND_VERSION_MINOR=26
UNBOUND_VERSION_MICRO=2
UNBOUND_VERSION_MICRO=1
LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=34
LIBUNBOUND_REVISION=40
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -3360,6 +3360,11 @@ LIBUNBOUND_AGE=1
# 1.24.0 had 9:33:1
# 1.24.1 had 9:34:1
# 1.24.2 had 9:35:1
# 1.25.0 had 9:36:1
# 1.25.1 had 9:37:1
# 1.25.2 had 9:38:1
# 1.26.0 had 9:39:1
# 1.26.1 had 9:40:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -6950,6 +6955,57 @@ fi
BAKCFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $ERRFLAG"
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"nonstring\" attribute" >&5
printf %s "checking whether the C compiler (${CC-cc}) accepts the \"nonstring\" attribute... " >&6; }
if test ${ac_cv_c_nonstring_attribute+y}
then :
printf %s "(cached) " >&6
else $as_nop
ac_cv_c_nonstring_attribute=no
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
struct test {
char __attribute__((nonstring)) s[1];
};
int
main (void)
{
struct test t = { "1" };
(void) t;
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
ac_cv_c_nonstring_attribute="yes"
else $as_nop
ac_cv_c_nonstring_attribute="no"
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
CFLAGS="$BAKCFLAGS"
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_nonstring_attribute" >&5
printf "%s\n" "$ac_cv_c_nonstring_attribute" >&6; }
if test $ac_cv_c_nonstring_attribute = yes; then
printf "%s\n" "#define HAVE_ATTR_NONSTRING 1" >>confdefs.h
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether the C compiler (${CC-cc}) accepts the \"weak\" attribute" >&5
printf %s "checking whether the C compiler (${CC-cc}) accepts the \"weak\" attribute... " >&6; }
@@ -7012,7 +7068,14 @@ else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
#include <stdio.h>
__attribute__((noreturn)) void f(int x) { printf("%d", x); }
#ifdef STDC_HEADERS
# include <stdlib.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
__attribute__((noreturn)) void f(int x) { printf("%d", x); exit(1); }
int
main (void)
@@ -15944,6 +16007,13 @@ if test "x$ac_cv_header_glob_h" = xyes
then :
printf "%s\n" "#define HAVE_GLOB_H 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "fnmatch.h" "ac_cv_header_fnmatch_h" "$ac_includes_default
"
if test "x$ac_cv_header_fnmatch_h" = xyes
then :
printf "%s\n" "#define HAVE_FNMATCH_H 1" >>confdefs.h
fi
ac_fn_c_check_header_compile "$LINENO" "grp.h" "ac_cv_header_grp_h" "$ac_includes_default
"
@@ -17974,7 +18044,9 @@ if test x_$enable_alloc_nonregional = x_yes; then
printf "%s\n" "#define UNBOUND_ALLOC_NONREGIONAL 1" >>confdefs.h
fi
if test x_$enable_alloc_checks = x_yes; then
if test x_$enable_alloc_checks = x_yes
then :
printf "%s\n" "#define UNBOUND_ALLOC_STATS 1" >>confdefs.h
@@ -17982,28 +18054,29 @@ printf "%s\n" "#define UNBOUND_ALLOC_STATS 1" >>confdefs.h
ASYNCLOOK_ALLOCCHECK_EXTRA_OBJ="alloc.lo"
else
if test x_$enable_alloc_lite = x_yes; then
else $as_nop
if test x_$enable_alloc_lite = x_yes
then :
printf "%s\n" "#define UNBOUND_ALLOC_LITE 1" >>confdefs.h
else
else $as_nop
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for GNU libc compatible malloc" >&5
printf %s "checking for GNU libc compatible malloc... " >&6; }
if test "$cross_compiling" = yes
if test ${ac_cv_func_malloc_0_nonnull+y}
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no (crosscompile)" >&5
printf "%s\n" "no (crosscompile)" >&6; }
case " $LIBOBJS " in
*" malloc.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS malloc.$ac_objext"
;;
esac
printf "%s\n" "#define malloc rpl_malloc_unbound" >>confdefs.h
printf %s "(cached) " >&6
else $as_nop
if test "$cross_compiling" = yes
then :
ac_cv_func_malloc_0_nonnull="no (crosscompile)"
else $as_nop
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
@@ -18024,9 +18097,26 @@ main (void)
_ACEOF
if ac_fn_c_try_run "$LINENO"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
case " $LIBOBJS " in
ac_cv_func_malloc_0_nonnull=no
else $as_nop
ac_cv_func_malloc_0_nonnull=yes
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: $ac_cv_func_malloc_0_nonnull" >&5
printf "%s\n" "$ac_cv_func_malloc_0_nonnull" >&6; }
if test "$ac_cv_func_malloc_0_nonnull" = yes
then :
printf "%s\n" "#define HAVE_MALLOC 1" >>confdefs.h
else $as_nop
case " $LIBOBJS " in
*" malloc.$ac_objext "* ) ;;
*) LIBOBJS="$LIBOBJS malloc.$ac_objext"
;;
@@ -18035,19 +18125,12 @@ esac
printf "%s\n" "#define malloc rpl_malloc_unbound" >>confdefs.h
else $as_nop
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
printf "%s\n" "#define HAVE_MALLOC 1" >>confdefs.h
fi
rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
conftest.$ac_objext conftest.beam conftest.$ac_ext
fi
fi
fi
# check windows threads (we use them, not pthreads, on windows).
@@ -18333,7 +18416,31 @@ fi
# correctly enabled
case $host_os in
darwin* | hpux* | linux* | osf* | solaris*)
solaris*)
# Solaris 11.4 introduced XPG7 support and did away with the need for
# _REENTRANT.
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
# undef _XOPEN_SOURCE
# include <sys/feature_tests.h>
# if _XOPEN_VERSION < 700
AX_PTHREAD_SOLARIS__REENTRANT
# endif
_ACEOF
if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
$EGREP "AX_PTHREAD_SOLARIS__REENTRANT" >/dev/null 2>&1
then :
ax_pthread_check_macro="_REENTRANT"
else $as_nop
ax_pthread_check_macro="--"
fi
rm -rf conftest*
;;
darwin* | hpux* | linux* | osf*)
ax_pthread_check_macro="_REENTRANT"
;;
@@ -19008,6 +19115,171 @@ ac_compiler_gnu=$ac_cv_c_compiler_gnu
fi
if test x_$ub_have_pthreads != x_no; then
# Long checks to support pthread_setname_np().
# Some OSes have the extra non-portable functions in a specific
# header file.
ac_fn_c_check_header_compile "$LINENO" "pthread_np.h" "ac_cv_header_pthread_np_h" "$ac_includes_default
"
if test "x$ac_cv_header_pthread_np_h" = xyes
then :
printf "%s\n" "#define HAVE_PTHREAD_NP_H 1" >>confdefs.h
fi
BAKCFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Werror"
# MacOS only has 1 argument, the name.
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np has only 1 argument" >&5
printf %s "checking whether pthread_setname_np has only 1 argument... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_includes_default
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
int
main (void)
{
(void)pthread_setname_np("");
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP1 1" >>confdefs.h
else $as_nop
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
# NetBSD has 3 arguments to allow for formatting of the name.
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np has 3 arguments" >&5
printf %s "checking whether pthread_setname_np has 3 arguments... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_includes_default
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
int
main (void)
{
(void)pthread_setname_np(0, "", NULL);
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP3 1" >>confdefs.h
else $as_nop
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
# Most OSes have the common 2 arguments, thread and name.
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np has the common 2 arguments" >&5
printf %s "checking whether pthread_setname_np has the common 2 arguments... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_includes_default
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
int
main (void)
{
(void)pthread_setname_np(0, "");
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
printf "%s\n" "#define HAVE_PTHREAD_SETNAME_NP 1" >>confdefs.h
else $as_nop
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
# FreeBSD/OpenBSD use a slightly different function name.
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking whether pthread_setname_np exists as pthread_set_name_np instead" >&5
printf %s "checking whether pthread_setname_np exists as pthread_set_name_np instead... " >&6; }
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
/* end confdefs.h. */
$ac_includes_default
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
int
main (void)
{
(void)pthread_set_name_np(0, "");
;
return 0;
}
_ACEOF
if ac_fn_c_try_compile "$LINENO"
then :
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
printf "%s\n" "#define HAVE_PTHREAD_SET_NAME_NP 1" >>confdefs.h
else $as_nop
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
CFLAGS="$BAKCFLAGS"
fi
# check solaris thread library
# Check whether --with-solaris-threads was given.
@@ -20822,6 +21094,12 @@ then :
printf "%s\n" "#define HAVE_BIO_SET_CALLBACK_EX 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "OPENSSL_cleanup" "ac_cv_func_OPENSSL_cleanup"
if test "x$ac_cv_func_OPENSSL_cleanup" = xyes
then :
printf "%s\n" "#define HAVE_OPENSSL_CLEANUP 1" >>confdefs.h
fi
# these check_funcs need -lssl
@@ -20850,6 +21128,24 @@ if test "x$ac_cv_func_SSL_get0_peername" = xyes
then :
printf "%s\n" "#define HAVE_SSL_GET0_PEERNAME 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "SSL_set1_dnsname" "ac_cv_func_SSL_set1_dnsname"
if test "x$ac_cv_func_SSL_set1_dnsname" = xyes
then :
printf "%s\n" "#define HAVE_SSL_SET1_DNSNAME 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "X509_get_key_usage" "ac_cv_func_X509_get_key_usage"
if test "x$ac_cv_func_X509_get_key_usage" = xyes
then :
printf "%s\n" "#define HAVE_X509_GET_KEY_USAGE 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "ASN1_STRING_get0_data" "ac_cv_func_ASN1_STRING_get0_data"
if test "x$ac_cv_func_ASN1_STRING_get0_data" = xyes
then :
printf "%s\n" "#define HAVE_ASN1_STRING_GET0_DATA 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "X509_VERIFY_PARAM_set1_host" "ac_cv_func_X509_VERIFY_PARAM_set1_host"
if test "x$ac_cv_func_X509_VERIFY_PARAM_set1_host" = xyes
@@ -20894,6 +21190,54 @@ then :
fi
ac_fn_c_check_func "$LINENO" "X509_NAME_get_text_by_NID" "ac_cv_func_X509_NAME_get_text_by_NID"
if test "x$ac_cv_func_X509_NAME_get_text_by_NID" = xyes
then :
printf "%s\n" "#define HAVE_X509_NAME_GET_TEXT_BY_NID 1" >>confdefs.h
fi
if test $ac_cv_func_X509_NAME_get_text_by_NID = yes; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if X509_NAME_get_text_by_NID is deprecated" >&5
printf %s "checking if X509_NAME_get_text_by_NID is deprecated... " >&6; }
cache=`echo X509_NAME_get_text_by_NID | sed 'y%.=/+-%___p_%'`
if eval test \${cv_cc_deprecated_$cache+y}
then :
printf %s "(cached) " >&6
else $as_nop
echo '
#include "openssl/x509.h"
' >conftest.c
echo 'void f(void){
(void)X509_NAME_get_text_by_NID(NULL, 0, NULL, 0); }' >>conftest.c
if test -z "`$CC $CPPFLAGS $CFLAGS -c conftest.c 2>&1 | grep -e deprecated -e unavailable`"; then
eval "cv_cc_deprecated_$cache=no"
else
eval "cv_cc_deprecated_$cache=yes"
fi
rm -f conftest conftest.o conftest.c
fi
if eval "test \"`echo '$cv_cc_deprecated_'$cache`\" = yes"; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: yes" >&5
printf "%s\n" "yes" >&6; }
printf "%s\n" "#define DEPRECATED_X509_NAME_GET_TEXT_BY_NID 1" >>confdefs.h
:
else
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
:
fi
fi
LIBS="$BAKLIBS"
ac_fn_check_decl "$LINENO" "SSL_COMP_get_compression_methods" "ac_cv_have_decl_SSL_COMP_get_compression_methods" "
@@ -21460,7 +21804,7 @@ fi
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking if openssl supports SHA2 and ECDSA with EVP" >&5
printf %s "checking if openssl supports SHA2 and ECDSA with EVP... " >&6; }
if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then
if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL 0\." >/dev/null; then
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result: no" >&5
printf "%s\n" "no" >&6; }
@@ -22400,6 +22744,24 @@ then :
printf "%s\n" "#define USE_NGTCP2_CRYPTO_OSSL 1" >>confdefs.h
ac_fn_check_decl "$LINENO" "ngtcp2_crypto_ossl_ctx_new" "ac_cv_have_decl_ngtcp2_crypto_ossl_ctx_new" "$ac_includes_default
#include <ngtcp2/ngtcp2_crypto_ossl.h>
" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_ngtcp2_crypto_ossl_ctx_new" = xyes
then :
ac_have_decl=1
else $as_nop
ac_have_decl=0
fi
printf "%s\n" "#define HAVE_DECL_NGTCP2_CRYPTO_OSSL_CTX_NEW $ac_have_decl" >>confdefs.h
if test $ac_have_decl = 1
then :
else $as_nop
as_fn_error $? "No declaration of ngtcp2_crypto_ossl_ctx_new in the ngtcp2_crypto_ossl header file. Perhaps the ngtcp2_crypto_ossl devel header files need to be installed." "$LINENO" 5
fi
else $as_nop
@@ -22579,6 +22941,13 @@ else $as_nop
fi
done
ac_fn_c_check_func "$LINENO" "SSL_set_quic_tls_early_data_enabled" "ac_cv_func_SSL_set_quic_tls_early_data_enabled"
if test "x$ac_cv_func_SSL_set_quic_tls_early_data_enabled" = xyes
then :
printf "%s\n" "#define HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED 1" >>confdefs.h
fi
LIBS="$BAKLIBS"
ac_fn_c_check_type "$LINENO" "struct ngtcp2_version_cid" "ac_cv_type_struct_ngtcp2_version_cid" "$ac_includes_default
@@ -22684,6 +23053,29 @@ printf "%s\n" "no" >&6; }
fi
rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
ac_fn_check_decl "$LINENO" "CLOCK_MONOTONIC
" "ac_cv_have_decl_CLOCK_MONOTONIC_________" "$ac_includes_default
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
" "$ac_c_undeclared_builtin_options" "CFLAGS"
if test "x$ac_cv_have_decl_CLOCK_MONOTONIC_________" = xyes
then :
else $as_nop
as_fn_error $? "ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system" "$LINENO" 5
fi
fi
# set static linking for uninstalled libraries if requested
@@ -22745,10 +23137,12 @@ then :
LIBS="$LIBS -lz"
fi
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
:
else
LIBS="$LIBS -l:libssp.a"
if echo "$host" | $GREP -i -e linux >/dev/null; then
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
:
else
LIBS="$LIBS -l:libssp.a"
fi
fi
fi
fi
@@ -22809,10 +23203,12 @@ then :
LIBS="$LIBS -lz"
fi
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
:
else
LIBS="$LIBS -l:libssp.a"
if echo "$host" | $GREP -i -e linux >/dev/null; then
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
:
else
LIBS="$LIBS -l:libssp.a"
fi
fi
fi
fi
@@ -23188,6 +23584,23 @@ printf "%s\n" "no" >&6; }
fi
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtimensec" "ac_cv_member_struct_stat_st_mtimensec" "$ac_includes_default"
if test "x$ac_cv_member_struct_stat_st_mtimensec" = xyes
then :
printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIMENSEC 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct stat" "st_mtim.tv_nsec" "ac_cv_member_struct_stat_st_mtim_tv_nsec" "$ac_includes_default"
if test "x$ac_cv_member_struct_stat_st_mtim_tv_nsec" = xyes
then :
printf "%s\n" "#define HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC 1" >>confdefs.h
fi
ac_fn_c_check_member "$LINENO" "struct sockaddr_un" "sun_len" "ac_cv_member_struct_sockaddr_un_sun_len" "
@@ -23497,6 +23910,12 @@ if test "x$ac_cv_func_glob" = xyes
then :
printf "%s\n" "#define HAVE_GLOB 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "fnmatch" "ac_cv_func_fnmatch"
if test "x$ac_cv_func_fnmatch" = xyes
then :
printf "%s\n" "#define HAVE_FNMATCH 1" >>confdefs.h
fi
ac_fn_c_check_func "$LINENO" "initgroups" "ac_cv_func_initgroups"
if test "x$ac_cv_func_initgroups" = xyes
@@ -25293,7 +25712,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h
version=1.24.2
version=1.26.1
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5
printf %s "checking for build time... " >&6; }
@@ -25823,7 +26242,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by unbound $as_me 1.24.2, which was
This file was extended by unbound $as_me 1.26.1, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -25891,7 +26310,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
unbound config.status 1.24.2
unbound config.status 1.26.1
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
+139 -23
View File
@@ -11,15 +11,15 @@ sinclude(dnscrypt/dnscrypt.m4)
# must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1])
m4_define([VERSION_MINOR],[24])
m4_define([VERSION_MICRO],[2])
m4_define([VERSION_MINOR],[26])
m4_define([VERSION_MICRO],[1])
AC_INIT([unbound],m4_defn([VERSION_MAJOR]).m4_defn([VERSION_MINOR]).m4_defn([VERSION_MICRO]),[unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues],[unbound])
AC_SUBST(UNBOUND_VERSION_MAJOR, [VERSION_MAJOR])
AC_SUBST(UNBOUND_VERSION_MINOR, [VERSION_MINOR])
AC_SUBST(UNBOUND_VERSION_MICRO, [VERSION_MICRO])
LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=34
LIBUNBOUND_REVISION=40
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -122,6 +122,11 @@ LIBUNBOUND_AGE=1
# 1.24.0 had 9:33:1
# 1.24.1 had 9:34:1
# 1.24.2 had 9:35:1
# 1.25.0 had 9:36:1
# 1.25.1 had 9:37:1
# 1.25.2 had 9:38:1
# 1.26.0 had 9:39:1
# 1.26.1 had 9:40:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -330,6 +335,7 @@ fi
AC_C_INLINE
ACX_CHECK_FORMAT_ATTRIBUTE
ACX_CHECK_UNUSED_ATTRIBUTE
ACX_CHECK_NONSTRING_ATTRIBUTE
AC_DEFUN([CHECK_WEAK_ATTRIBUTE],
[AC_REQUIRE([AC_PROG_CC])
@@ -360,7 +366,14 @@ AC_MSG_CHECKING(whether the C compiler (${CC-cc}) accepts the "noreturn" attribu
AC_CACHE_VAL(ac_cv_c_noreturn_attribute,
[ac_cv_c_noreturn_attribute=no
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[ #include <stdio.h>
__attribute__((noreturn)) void f(int x) { printf("%d", x); }
#ifdef STDC_HEADERS
# include <stdlib.h>
#else
# ifdef HAVE_STDLIB_H
# include <stdlib.h>
# endif
#endif
__attribute__((noreturn)) void f(int x) { printf("%d", x); exit(1); }
]], [[
f(1);
]])],[ac_cv_c_noreturn_attribute="yes"],[ac_cv_c_noreturn_attribute="no"])
@@ -472,7 +485,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 poll.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 fnmatch.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],,, [
@@ -635,19 +648,19 @@ AC_ARG_ENABLE(alloc-nonregional, AS_HELP_STRING([--enable-alloc-nonregional],[ e
if test x_$enable_alloc_nonregional = x_yes; then
AC_DEFINE(UNBOUND_ALLOC_NONREGIONAL, 1, [use malloc not regions, for debug use])
fi
if test x_$enable_alloc_checks = x_yes; then
AS_IF([test x_$enable_alloc_checks = x_yes],[
AC_DEFINE(UNBOUND_ALLOC_STATS, 1, [use statistics for allocs and frees, for debug use])
SLDNS_ALLOCCHECK_EXTRA_OBJ="alloc.lo log.lo"
AC_SUBST(SLDNS_ALLOCCHECK_EXTRA_OBJ)
ASYNCLOOK_ALLOCCHECK_EXTRA_OBJ="alloc.lo"
AC_SUBST(ASYNCLOOK_ALLOCCHECK_EXTRA_OBJ)
else
if test x_$enable_alloc_lite = x_yes; then
],[
AS_IF([test x_$enable_alloc_lite = x_yes],[
AC_DEFINE(UNBOUND_ALLOC_LITE, 1, [use to enable lightweight alloc assertions, for debug use])
else
],[
ACX_FUNC_MALLOC([unbound])
fi
fi
])
])
# check windows threads (we use them, not pthreads, on windows).
if test "$on_mingw" = "yes"; then
@@ -722,6 +735,76 @@ int main(void) {return 0;}
])
fi
if test x_$ub_have_pthreads != x_no; then
# Long checks to support pthread_setname_np().
# Some OSes have the extra non-portable functions in a specific
# header file.
AC_CHECK_HEADERS([pthread_np.h],,, [AC_INCLUDES_DEFAULT])
BAKCFLAGS="$CFLAGS"
CFLAGS="$CFLAGS -Werror"
# MacOS only has 1 argument, the name.
AC_MSG_CHECKING([whether pthread_setname_np has only 1 argument])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
],[
(void)pthread_setname_np("");
])],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP1, 1, [Define if pthread_setname_np has only 1 argument.])
],[
AC_MSG_RESULT(no)
])
# NetBSD has 3 arguments to allow for formatting of the name.
AC_MSG_CHECKING([whether pthread_setname_np has 3 arguments])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
],[
(void)pthread_setname_np(0, "", NULL);
])],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP3, 1, [Define if pthread_setname_np has 3 arguments.])
],[
AC_MSG_RESULT(no)
])
# Most OSes have the common 2 arguments, thread and name.
AC_MSG_CHECKING([whether pthread_setname_np has the common 2 arguments])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
],[
(void)pthread_setname_np(0, "");
])],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_PTHREAD_SETNAME_NP, 1, [Define if pthread_setname_np has the common 2 arguments.])
],[
AC_MSG_RESULT(no)
])
# FreeBSD/OpenBSD use a slightly different function name.
AC_MSG_CHECKING([whether pthread_setname_np exists as pthread_set_name_np instead])
AC_COMPILE_IFELSE([AC_LANG_PROGRAM([AC_INCLUDES_DEFAULT
#include <pthread.h>
#ifdef HAVE_PTHREAD_NP_H
#include <pthread_np.h>
#endif
],[
(void)pthread_set_name_np(0, "");
])],[
AC_MSG_RESULT(yes)
AC_DEFINE(HAVE_PTHREAD_SET_NAME_NP, 1, [Define if pthread_setname_np exists as pthread_set_name_np instead.])
],[
AC_MSG_RESULT(no)
])
CFLAGS="$BAKCFLAGS"
fi
# check solaris thread library
AC_ARG_WITH(solaris-threads, AS_HELP_STRING([--with-solaris-threads],[use solaris native thread library.]), [ ],[ withval="no" ])
ub_have_sol_threads=no
@@ -999,12 +1082,19 @@ else
AC_MSG_RESULT([no])
fi
AC_CHECK_HEADERS([openssl/conf.h openssl/engine.h openssl/bn.h openssl/dh.h openssl/dsa.h openssl/rsa.h openssl/core_names.h openssl/param_build.h],,, [AC_INCLUDES_DEFAULT])
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex])
AC_CHECK_FUNCS([OPENSSL_config EVP_sha1 EVP_sha256 EVP_sha512 FIPS_mode EVP_default_properties_is_fips_enabled EVP_MD_CTX_new OpenSSL_add_all_digests OPENSSL_init_crypto EVP_cleanup ENGINE_cleanup ERR_load_crypto_strings CRYPTO_cleanup_all_ex_data ERR_free_strings RAND_cleanup DSA_SIG_set0 EVP_dss1 EVP_DigestVerify EVP_aes_256_cbc EVP_EncryptInit_ex HMAC_Init_ex CRYPTO_THREADID_set_callback EVP_MAC_CTX_set_params OSSL_PARAM_BLD_new BIO_set_callback_ex OPENSSL_cleanup])
# these check_funcs need -lssl
BAKLIBS="$LIBS"
LIBS="-lssl $LIBS"
AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level SSL_set1_host SSL_get0_peername X509_VERIFY_PARAM_set1_host SSL_CTX_set_ciphersuites SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_alpn_select_cb SSL_get0_alpn_selected SSL_CTX_set_alpn_protos SSL_get1_peer_certificate])
AC_CHECK_FUNCS([OPENSSL_init_ssl SSL_CTX_set_security_level SSL_set1_host SSL_get0_peername SSL_set1_dnsname X509_get_key_usage ASN1_STRING_get0_data X509_VERIFY_PARAM_set1_host SSL_CTX_set_ciphersuites SSL_CTX_set_tlsext_ticket_key_evp_cb SSL_CTX_set_alpn_select_cb SSL_get0_alpn_selected SSL_CTX_set_alpn_protos SSL_get1_peer_certificate])
AC_CHECK_FUNCS([X509_NAME_get_text_by_NID])
if test $ac_cv_func_X509_NAME_get_text_by_NID = yes; then
ACX_FUNC_DEPRECATED([X509_NAME_get_text_by_NID], [
(void)X509_NAME_get_text_by_NID(NULL, 0, NULL, 0);], [
#include "openssl/x509.h"
])
fi
LIBS="$BAKLIBS"
AC_CHECK_DECLS([SSL_COMP_get_compression_methods,sk_SSL_COMP_pop_free,SSL_CTX_set_ecdh_auto,SSL_CTX_set_tmp_ecdh], [], [], [
@@ -1253,7 +1343,7 @@ case "$enable_ecdsa" in
# see if OPENSSL 1.0.0 or later (has EVP MD and Verify independency)
AC_MSG_CHECKING([if openssl supports SHA2 and ECDSA with EVP])
if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL" >/dev/null; then
if grep OPENSSL_VERSION_NUMBER $ssldir_include/openssl/opensslv.h | grep 0x0 >/dev/null; then
if grep OPENSSL_VERSION_TEXT $ssldir_include/openssl/opensslv.h | grep "OpenSSL 0\." >/dev/null; then
AC_MSG_RESULT([no])
AC_DEFINE_UNQUOTED([USE_ECDSA_EVP_WORKAROUND], [1], [Define this to enable an EVP workaround for older openssl])
else
@@ -1623,6 +1713,9 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
AC_CHECK_LIB([ngtcp2_crypto_ossl], [ngtcp2_crypto_encrypt_cb], [
LIBS="$LIBS -lngtcp2_crypto_ossl"
AC_DEFINE(USE_NGTCP2_CRYPTO_OSSL, 1, [Define this to use ngtcp2_crypto_ossl.])
AC_CHECK_DECLS([ngtcp2_crypto_ossl_ctx_new], [], [AC_MSG_ERROR([No declaration of ngtcp2_crypto_ossl_ctx_new in the ngtcp2_crypto_ossl header file. Perhaps the ngtcp2_crypto_ossl devel header files need to be installed.])], [AC_INCLUDES_DEFAULT
#include <ngtcp2/ngtcp2_crypto_ossl.h>
])
], [
AC_CHECK_LIB([ngtcp2_crypto_openssl], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_openssl" ], [
AC_CHECK_LIB([ngtcp2_crypto_quictls], [ngtcp2_crypto_encrypt_cb], [ LIBS="$LIBS -lngtcp2_crypto_quictls" ])
@@ -1634,6 +1727,7 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
BAKLIBS="$LIBS"
LIBS="-lssl $LIBS"
AC_CHECK_FUNCS([SSL_is_quic], [], [AC_MSG_ERROR([No QUIC support detected in OpenSSL. Need OpenSSL version with QUIC support to enable DNS over QUIC with libngtcp2.])])
AC_CHECK_FUNCS([SSL_set_quic_tls_early_data_enabled])
LIBS="$BAKLIBS"
AC_CHECK_TYPES([struct ngtcp2_version_cid, ngtcp2_encryption_level],,,[AC_INCLUDES_DEFAULT
@@ -1655,6 +1749,22 @@ if test x_$withval = x_yes -o x_$withval != x_no; then
AC_MSG_RESULT(no)
])
AC_CHECK_DECL([CLOCK_MONOTONIC]
, []
, [AC_MSG_ERROR([ngtcp2 for QUIC needs at least CLOCK_MONOTONIC on the system])]
, [AC_INCLUDES_DEFAULT
#ifdef TIME_WITH_SYS_TIME
# include <sys/time.h>
# include <time.h>
#else
# ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
# else
# include <time.h>
# endif
#endif
])
fi
# set static linking for uninstalled libraries if requested
@@ -1673,10 +1783,12 @@ if test x_$enable_static_exe = x_yes; then
LIBS="$LIBS -lgdi32"
fi
AC_CHECK_LIB([z], [compress], [ LIBS="$LIBS -lz" ])
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
:
else
LIBS="$LIBS -l:libssp.a"
if echo "$host" | $GREP -i -e linux >/dev/null; then
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
:
else
LIBS="$LIBS -l:libssp.a"
fi
fi
fi
fi
@@ -1694,10 +1806,12 @@ if test x_$enable_fully_static = x_yes; then
LIBS="$LIBS -lgdi32"
fi
AC_CHECK_LIB([z], [compress], [ LIBS="$LIBS -lz" ])
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
:
else
LIBS="$LIBS -l:libssp.a"
if echo "$host" | $GREP -i -e linux >/dev/null; then
if echo "$LIBS" | grep -e "libssp.a" -e "lssp" >/dev/null; then
:
else
LIBS="$LIBS -l:libssp.a"
fi
fi
fi
fi
@@ -1756,6 +1870,7 @@ if test $ac_cv_func_daemon = yes; then
])
fi
AC_CHECK_MEMBERS([struct stat.st_mtimensec, struct stat.st_mtim.tv_nsec])
AC_CHECK_MEMBERS([struct sockaddr_un.sun_len],,,[
AC_INCLUDES_DEFAULT
#ifdef HAVE_SYS_UN_H
@@ -1826,7 +1941,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 poll gettid])
AC_CHECK_FUNCS([tzset sigprocmask fcntl getpwnam endpwent getrlimit setrlimit setsid chroot kill chown sleep usleep random srandom recvmsg sendmsg writev socketpair glob fnmatch 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])])
@@ -2293,6 +2408,7 @@ dnl includes
AHX_CONFIG_FORMAT_ATTRIBUTE
AHX_CONFIG_UNUSED_ATTRIBUTE
AHX_CONFIG_NONSTRING_ATTRIBUTE
AHX_CONFIG_FSEEKO
AHX_CONFIG_MAXHOSTNAMELEN
#if !defined(HAVE_SNPRINTF) || defined(SNPRINTF_RET_BROKEN)
+2
View File
@@ -58,3 +58,5 @@ distribution but may be helpful.
* unbound.init_yocto: An init script to start and stop the server. Put it
in /etc/init.d/unbound to use it. It is for the Yocto Project, in
embedded systems, contributed by beni-sandu.
* gost12.patch: adds ECC-GOST12 support for the informational RFC9558.
Contributed by Igor V. Ruzanov.
+325
View File
@@ -0,0 +1,325 @@
diff --git a/sldns/keyraw.c b/sldns/keyraw.c
index 42a9262a3..cc6406a56 100644
--- a/sldns/keyraw.c
+++ b/sldns/keyraw.c
@@ -85,7 +85,7 @@ sldns_rr_dnskey_key_size_raw(const unsigned char* keydata,
}
break;
#ifdef USE_GOST
- case LDNS_ECC_GOST:
+ case LDNS_ECC_GOST12:
return 512;
#endif
#ifdef USE_ECDSA
@@ -146,7 +146,7 @@ sldns_key_EVP_load_gost_id(void)
if(gost_id) return gost_id;
/* see if configuration loaded gost implementation from other engine*/
- meth = EVP_PKEY_asn1_find_str(NULL, "gost2001", -1);
+ meth = EVP_PKEY_asn1_find_str(NULL, "gost2012_256", -1);
if(meth) {
EVP_PKEY_asn1_get0_info(&gost_id, NULL, NULL, NULL, NULL, meth);
return gost_id;
@@ -170,7 +170,7 @@ sldns_key_EVP_load_gost_id(void)
return 0;
}
- meth = EVP_PKEY_asn1_find_str(&e, "gost2001", -1);
+ meth = EVP_PKEY_asn1_find_str(&e, "gost2012_256", -1);
if(!meth) {
/* algo not found */
ENGINE_finish(e);
@@ -536,12 +536,17 @@ EVP_PKEY* sldns_key_rsa2pkey_raw(unsigned char* key, size_t len)
EVP_PKEY*
sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
{
- /* prefix header for X509 encoding */
- uint8_t asn[37] = { 0x30, 0x63, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85,
- 0x03, 0x02, 0x02, 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85,
- 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07, 0x2a, 0x85, 0x03,
- 0x02, 0x02, 0x1e, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40};
- unsigned char encoded[37+64];
+ /* prefix header for X509 encoding
+ *
+ * note: based on draft-makarenko-gost2012-dnssec-01 (pre-RFC9558 and it DOES work!)
+ * ASN1 header described in RFC9558 is not suitable due to d2i_PUBKEY() works with
+ * non-compressed public keys (two additional bytes 0x04, 0x40 at the end of header)
+ */
+ uint8_t asn[32] = { 0x30, 0x5e, 0x30, 0x17, 0x06, 0x08, 0x2a, 0x85,
+ 0x03, 0x07, 0x01, 0x01, 0x01, 0x01, 0x30, 0x0b,
+ 0x06, 0x09, 0x2a, 0x85, 0x03, 0x07, 0x01, 0x02,
+ 0x01, 0x01, 0x01, 0x03, 0x43, 0x00, 0x04, 0x40 };
+ unsigned char encoded[32+64];
const unsigned char* pp;
if(keylen != 64) {
/* key wrong size */
@@ -549,8 +554,8 @@ sldns_gost2pkey_raw(unsigned char* key, size_t keylen)
}
/* create evp_key */
- memmove(encoded, asn, 37);
- memmove(encoded+37, key, 64);
+ memmove(encoded, asn, 32);
+ memmove(encoded+32, key, 64);
pp = (unsigned char*)&encoded[0];
return d2i_PUBKEY(NULL, &pp, (int)sizeof(encoded));
diff --git a/sldns/rrdef.h b/sldns/rrdef.h
index bbc3d5b86..7d5f3c057 100644
--- a/sldns/rrdef.h
+++ b/sldns/rrdef.h
@@ -384,11 +384,12 @@ enum sldns_enum_algorithm
LDNS_RSASHA1_NSEC3 = 7,
LDNS_RSASHA256 = 8, /* RFC 5702 */
LDNS_RSASHA512 = 10, /* RFC 5702 */
- LDNS_ECC_GOST = 12, /* RFC 5933 */
+ LDNS_ECC_GOST = 12, /* RFC 5933, deprecated */
LDNS_ECDSAP256SHA256 = 13, /* RFC 6605 */
LDNS_ECDSAP384SHA384 = 14, /* RFC 6605 */
LDNS_ED25519 = 15, /* RFC 8080 */
LDNS_ED448 = 16, /* RFC 8080 */
+ LDNS_ECC_GOST12 = 23, /* RFC 9558 */
LDNS_INDIRECT = 252,
LDNS_PRIVATEDNS = 253,
LDNS_PRIVATEOID = 254
@@ -402,8 +403,9 @@ enum sldns_enum_hash
{
LDNS_SHA1 = 1, /* RFC 4034 */
LDNS_SHA256 = 2, /* RFC 4509 */
- LDNS_HASH_GOST = 3, /* RFC 5933 */
- LDNS_SHA384 = 4 /* RFC 6605 */
+ LDNS_HASH_GOST = 3, /* RFC 5933, deprecated */
+ LDNS_SHA384 = 4, /* RFC 6605 */
+ LDNS_HASH_GOST12 = 5 /* RFC 9558 */
};
typedef enum sldns_enum_hash sldns_hash;
diff --git a/sldns/wire2str.c b/sldns/wire2str.c
index 75b8f37b0..b4c4755e6 100644
--- a/sldns/wire2str.c
+++ b/sldns/wire2str.c
@@ -45,11 +45,12 @@ static sldns_lookup_table sldns_algorithms_data[] = {
{ LDNS_RSASHA1_NSEC3, "RSASHA1-NSEC3-SHA1" },
{ LDNS_RSASHA256, "RSASHA256"},
{ LDNS_RSASHA512, "RSASHA512"},
- { LDNS_ECC_GOST, "ECC-GOST"},
+ { LDNS_ECC_GOST, "ECC-GOST"}, /* deprecated */
{ LDNS_ECDSAP256SHA256, "ECDSAP256SHA256"},
{ LDNS_ECDSAP384SHA384, "ECDSAP384SHA384"},
{ LDNS_ED25519, "ED25519"},
{ LDNS_ED448, "ED448"},
+ { LDNS_ECC_GOST12, "ECC-GOST12"},
{ LDNS_INDIRECT, "INDIRECT" },
{ LDNS_PRIVATEDNS, "PRIVATEDNS" },
{ LDNS_PRIVATEOID, "PRIVATEOID" },
@@ -61,8 +62,9 @@ sldns_lookup_table* sldns_algorithms = sldns_algorithms_data;
static sldns_lookup_table sldns_hashes_data[] = {
{ LDNS_SHA1, "SHA1" },
{ LDNS_SHA256, "SHA256" },
- { LDNS_HASH_GOST, "HASH-GOST" },
+ { LDNS_HASH_GOST, "HASH-GOST" }, /* deprecated */
{ LDNS_SHA384, "SHA384" },
+ { LDNS_HASH_GOST12, "HASH-GOST12" },
{ 0, NULL }
};
sldns_lookup_table* sldns_hashes = sldns_hashes_data;
diff --git a/testcode/unitverify.c b/testcode/unitverify.c
index fcf2e2ffe..4a33e9f6a 100644
--- a/testcode/unitverify.c
+++ b/testcode/unitverify.c
@@ -696,7 +696,7 @@ verify_test(void)
#endif
#ifdef USE_GOST
if(sldns_key_EVP_load_gost_id())
- verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost", "20090807060504");
+ verifytest_file(SRCDIRSTR "/testdata/test_sigs.gost12", "20251226060504");
else printf("Warning: skipped GOST, openssl does not provide gost.\n");
#endif
#ifdef USE_ECDSA
diff --git a/testdata/test_sigs.gost12 b/testdata/test_sigs.gost12
new file mode 100644
index 000000000..72a250cff
--- /dev/null
+++ b/testdata/test_sigs.gost12
@@ -0,0 +1,39 @@
+; Signature test file
+
+; first entry is a DNSKEY answer, with the DNSKEY rrset used for verification.
+; later entries are verified with it.
+
+; Test GOST signatures using algo number 23.
+
+ENTRY_BEGIN
+SECTION QUESTION
+nlnetlabs.nl. IN DNSKEY
+SECTION ANSWER
+nlnetlabs.nl. 3600 IN DNSKEY 256 3 23 cdOtkEcb6NhcdOpIbPYtWyWxdlUiKgtKQbYg3lIjtG7i3fYjUID9zyOgoQEiV9wuGCfrw5cNsnvNw+8HiVFK4g== ;{id = 12301 (zsk), size = 512b}
+ENTRY_END
+
+; entry to test
+ENTRY_BEGIN
+SECTION QUESTION
+open.nlnetlabs.nl. IN A
+SECTION ANSWER
+open.nlnetlabs.nl. 600 IN A 213.154.224.1
+open.nlnetlabs.nl. 600 IN RRSIG A 23 3 600 20260122084903 20251225084903 12301 nlnetlabs.nl. I12wYNs96DxMy26CWx296/sWMJAFg4nNXBo0sw7PnuMbJW5NFAmZYtFWhUdOWn4umaiodYOAmKG8Zg/OKvEtAQ==
+ENTRY_END
+
+ENTRY_BEGIN
+SECTION QUESTION
+open.nlnetlabs.nl. IN AAAA
+SECTION ANSWER
+open.nlnetlabs.nl. 600 IN AAAA 2001:7b8:206:1::1
+open.nlnetlabs.nl. 600 IN AAAA 2001:7b8:206:1::53
+open.nlnetlabs.nl. 600 IN RRSIG AAAA 23 3 600 20260122084903 20251225084903 12301 nlnetlabs.nl. J0jHa+CP8HM6UDa2+uYgaze2mfpJTh2hkZ2KwMTYb5sfL6iBmxxql0c/403Itk4fMfYBMGn7zfzDQ+CxnCgSWw==
+ENTRY_END
+
+ENTRY_BEGIN
+SECTION QUESTION
+open.nlnetlabs.nl. IN NSEC
+SECTION ANSWER
+open.nlnetlabs.nl. 86400 IN NSEC nlnetlabs.nl. A AAAA RRSIG NSEC
+open.nlnetlabs.nl. 86400 IN RRSIG NSEC 23 3 86400 20260122084903 20251225084903 12301 nlnetlabs.nl. INCLYe9vAaNYaYx5Ay3Q6QdX+wPW9sMRvVlGt/jUEGgCi+88QlV80CT1oHrhRI66I14Wk6NRAGZRNx1tUPSHSg==
+ENTRY_END
diff --git a/validator/val_secalgo.c b/validator/val_secalgo.c
index be8347b1b..4f621a309 100644
--- a/validator/val_secalgo.c
+++ b/validator/val_secalgo.c
@@ -246,10 +246,10 @@ ds_digest_size_supported(int algo)
return SHA256_DIGEST_LENGTH;
#endif
#ifdef USE_GOST
- case LDNS_HASH_GOST:
+ case LDNS_HASH_GOST12:
/* we support GOST if it can be loaded */
(void)sldns_key_EVP_load_gost_id();
- if(EVP_get_digestbyname("md_gost94"))
+ if(EVP_get_digestbyname("md_gost12_256"))
return 32;
else return 0;
#endif
@@ -265,9 +265,9 @@ ds_digest_size_supported(int algo)
#ifdef USE_GOST
/** Perform GOST hash */
static int
-do_gost94(unsigned char* data, size_t len, unsigned char* dest)
+do_gost12(unsigned char* data, size_t len, unsigned char* dest)
{
- const EVP_MD* md = EVP_get_digestbyname("md_gost94");
+ const EVP_MD* md = EVP_get_digestbyname("md_gost12_256");
if(!md)
return 0;
return sldns_digest_evp(data, (unsigned int)len, dest, md);
@@ -302,8 +302,8 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
return 1;
#endif
#ifdef USE_GOST
- case LDNS_HASH_GOST:
- if(do_gost94(buf, len, res))
+ case LDNS_HASH_GOST12:
+ if(do_gost12(buf, len, res))
return 1;
break;
#endif
@@ -384,7 +384,7 @@ dnskey_algo_id_is_supported(int id)
#endif
#ifdef USE_GOST
- case LDNS_ECC_GOST:
+ case LDNS_ECC_GOST12:
/* we support GOST if it can be loaded */
return sldns_key_EVP_load_gost_id();
#endif
@@ -612,17 +612,17 @@ setup_key_digest(int algo, EVP_PKEY** evp_key, const EVP_MD** digest_type,
break;
#ifdef USE_GOST
- case LDNS_ECC_GOST:
+ case LDNS_ECC_GOST12:
*evp_key = sldns_gost2pkey_raw(key, keylen);
if(!*evp_key) {
verbose(VERB_QUERY, "verify: "
"sldns_gost2pkey_raw failed");
return 0;
}
- *digest_type = EVP_get_digestbyname("md_gost94");
+ *digest_type = EVP_get_digestbyname("md_gost12_256");
if(!*digest_type) {
verbose(VERB_QUERY, "verify: "
- "EVP_getdigest md_gost94 failed");
+ "EVP_getdigest md_gost12_256 failed");
return 0;
}
break;
@@ -964,7 +964,7 @@ ds_digest_size_supported(int algo)
return SHA384_LENGTH;
#endif
/* GOST not supported in NSS */
- case LDNS_HASH_GOST:
+ case LDNS_HASH_GOST12:
default: break;
}
return 0;
@@ -991,7 +991,7 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
return HASH_HashBuf(HASH_AlgSHA384, res, buf, len)
== SECSuccess;
#endif
- case LDNS_HASH_GOST:
+ case LDNS_HASH_GOST12:
default:
verbose(VERB_QUERY, "unknown DS digest algorithm %d",
algo);
@@ -1031,7 +1031,7 @@ dnskey_algo_id_is_supported(int id)
case LDNS_ECDSAP384SHA384:
return PK11_TokenExists(CKM_ECDSA);
#endif
- case LDNS_ECC_GOST:
+ case LDNS_ECC_GOST12:
default:
return 0;
}
@@ -1352,7 +1352,7 @@ nss_setup_key_digest(int algo, SECKEYPublicKey** pubkey, HASH_HashType* htype,
/* no prefix for DSA verification */
break;
#endif /* USE_ECDSA */
- case LDNS_ECC_GOST:
+ case LDNS_ECC_GOST12:
default:
verbose(VERB_QUERY, "verify: unknown algorithm %d",
algo);
@@ -1675,7 +1675,7 @@ ds_digest_size_supported(int algo)
return SHA384_DIGEST_SIZE;
#endif
/* GOST not supported */
- case LDNS_HASH_GOST:
+ case LDNS_ECC_GOST12:
default:
break;
}
@@ -1700,7 +1700,7 @@ secalgo_ds_digest(int algo, unsigned char* buf, size_t len,
return _digest_nettle(SHA384_DIGEST_SIZE, buf, len, res);
#endif
- case LDNS_HASH_GOST:
+ case LDNS_ECC_GOST12:
default:
verbose(VERB_QUERY, "unknown DS digest algorithm %d",
algo);
@@ -1744,7 +1744,7 @@ dnskey_algo_id_is_supported(int id)
return 1;
#endif
case LDNS_RSAMD5: /* RFC 6725 deprecates RSAMD5 */
- case LDNS_ECC_GOST:
+ case LDNS_ECC_GOST12:
default:
return 0;
}
@@ -2103,7 +2103,7 @@ verify_canonrrset(sldns_buffer* buf, int algo, unsigned char* sigblock,
return sec_status_secure;
#endif
case LDNS_RSAMD5:
- case LDNS_ECC_GOST:
+ case LDNS_ECC_GOST12:
default:
*reason = "unable to verify signature, unknown algorithm";
return sec_status_bogus;
+7 -5
View File
@@ -1,21 +1,22 @@
#!/usr/bin/env bash
OPENSSL_VERSION=1.1.1d
echo "Downloading OpenSSL"
if ! curl -L -k -s -o openssl-1.1.1d.tar.gz https://www.openssl.org/source/openssl-1.1.1d.tar.gz;
if ! curl -L -k -s -o openssl-$OPENSSL_VERSION.tar.gz https://www.openssl.org/source/openssl-$OPENSSL_VERSION.tar.gz;
then
echo "Failed to download OpenSSL"
exit 1
fi
echo "Unpacking OpenSSL"
rm -rf ./openssl-1.1.1d
if ! tar -xf openssl-1.1.1d.tar.gz;
rm -rf ./openssl-$OPENSSL_VERSION
if ! tar -xf openssl-$OPENSSL_VERSION.tar.gz;
then
echo "Failed to unpack OpenSSL"
exit 1
fi
cd openssl-1.1.1d || exit 1
cd openssl-$OPENSSL_VERSION || exit 1
if ! cp ../contrib/ios/15-ios.conf Configurations/; then
echo "Failed to copy OpenSSL ios config"
@@ -27,7 +28,8 @@ fi
# Also see https://github.com/openssl/openssl/issues/7607.
if ! patch -u -p0 < ../contrib/ios/openssl.patch; then
echo "Failed to patch OpenSSL"
exit 1
# the partial patch may be useful.
#exit 1
fi
echo "Configuring OpenSSL"
+5
View File
@@ -175,6 +175,7 @@ fi
# For example, remove 4.3, 6.2, and 6.1 if they are not installed. We go back to
# the 1.0 SDKs because Apple WatchOS uses low numbers, like 2.0 and 2.1.
XCODE_SDK=
if test -z "$SDK_VERSION"; then
for i in $(seq -f "%.1f" 30.0 -0.1 1.0)
do
if [ -d "$XCODE_DEVELOPER_SDK/Developer/SDKs/$IOS_SDK$i.sdk" ]; then
@@ -182,6 +183,10 @@ do
break
fi
done
else
i="$SDK_VERSION"
XCODE_SDK="$IOS_SDK$i.sdk"
fi
# Error checking
if [ -z "$XCODE_SDK" ]; then
+1 -1
View File
@@ -59,7 +59,7 @@ ExecReload=+/bin/kill -HUP $MAINPID
ExecStart=@UNBOUND_SBIN_DIR@/unbound -d -p
NotifyAccess=main
Type=notify
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_ADMIN
MemoryDenyWriteExecute=true
NoNewPrivileges=true
PrivateDevices=true
+1 -1
View File
@@ -26,7 +26,7 @@ ExecReload=+/bin/kill -HUP $MAINPID
ExecStart=@UNBOUND_SBIN_DIR@/unbound -d -p
NotifyAccess=main
Type=notify
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_RAW
CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_SYS_CHROOT CAP_SYS_RESOURCE CAP_NET_ADMIN
MemoryDenyWriteExecute=true
NoNewPrivileges=true
PrivateDevices=true
+2 -2
View File
@@ -99,7 +99,7 @@ static void
dump_rrset_line(struct config_strlist_head* txt, struct ub_packed_rrset_key* k,
time_t now, size_t i)
{
char s[65535];
char s[65535*4+2048];
if(!packed_rr_to_string(k, i, now, s, sizeof(s))) {
spool_txt_string(txt, "BADRR\n");
return;
@@ -455,7 +455,7 @@ load_rr(RES* ssl, sldns_buffer* buf, struct regional* region,
/* read the line */
if(!ssl_read_buf(ssl, buf))
return 0;
if(strncmp((char*)sldns_buffer_begin(buf), "BADRR\n", 6) == 0) {
if(strcmp((char*)sldns_buffer_begin(buf), "BADRR") == 0) {
*go_on = 0;
return 1;
}
+339 -27
View File
@@ -79,6 +79,7 @@
#include "util/tcp_conn_limit.h"
#include "util/edns.h"
#include "services/listen_dnsport.h"
#include "services/outside_network.h"
#include "services/cache/rrset.h"
#include "services/cache/infra.h"
#include "services/localzone.h"
@@ -199,6 +200,267 @@ signal_handling_playback(struct worker* wrk)
sig_record_reload = 0;
}
#ifdef HAVE_SSL
/* setup a listening ssl context, fatal_exit() on any failure */
static void
setup_listen_sslctx(void** ctx, int is_dot, int is_doh,
struct config_file* cfg, char* chroot)
{
char* key = cfg->ssl_service_key;
char* pem = cfg->ssl_service_pem;
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
key += strlen(chroot);
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
pem += strlen(chroot);
if(!(*ctx = listen_sslctx_create(key, pem, NULL,
cfg->tls_ciphers, cfg->tls_ciphersuites,
(cfg->tls_session_ticket_keys.first &&
cfg->tls_session_ticket_keys.first->str[0] != 0),
is_dot, is_doh, cfg->tls_protocols))) {
log_err("could not set up listen SSL_CTX");
*ctx = NULL;
}
}
#endif /* HAVE_SSL */
#ifdef HAVE_SSL
void* daemon_setup_listen_dot_sslctx(struct daemon* daemon,
struct config_file* cfg)
{
void* ctx;
(void)setup_listen_sslctx(&ctx, 1, 0, cfg, daemon->chroot);
return ctx;
}
#endif /* HAVE_SSL */
#ifdef HAVE_SSL
#ifdef HAVE_NGHTTP2_NGHTTP2_H
void* daemon_setup_listen_doh_sslctx(struct daemon* daemon,
struct config_file* cfg)
{
void* ctx;
(void)setup_listen_sslctx(&ctx, 0, 1, cfg, daemon->chroot);
return ctx;
}
#endif /* HAVE_NGHTTP2_NGHTTP2_H */
#endif /* HAVE_SSL */
#ifdef HAVE_SSL
#ifdef HAVE_NGTCP2
void* daemon_setup_listen_quic_sslctx(struct daemon* daemon,
struct config_file* cfg)
{
void* ctx;
char* chroot = daemon->chroot;
char* key = cfg->ssl_service_key;
char* pem = cfg->ssl_service_pem;
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
key += strlen(chroot);
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
pem += strlen(chroot);
if(!(ctx = quic_sslctx_create(key, pem, NULL))) {
log_err("could not set up quic SSL_CTX");
return NULL;
}
return ctx;
}
#endif /* HAVE_NGTCP2 */
#endif /* HAVE_SSL */
#ifdef HAVE_SSL
void* daemon_setup_connect_dot_sslctx(struct daemon* daemon,
struct config_file* cfg)
{
void* ctx;
char* bundle, *chroot = daemon->chroot;
bundle = cfg->tls_cert_bundle;
if(chroot && bundle && strncmp(bundle, chroot, strlen(chroot)) == 0)
bundle += strlen(chroot);
if(!(ctx = connect_sslctx_create(NULL, NULL, bundle,
cfg->tls_win_cert))) {
log_err("could not set up connect SSL_CTX");
return NULL;
}
return ctx;
}
#endif /* HAVE_SSL */
/* setups the needed ssl contexts, fatal_exit() on any failure */
void
daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
{
#ifdef HAVE_SSL
char* chroot = daemon->chroot;
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
char* key = cfg->ssl_service_key;
char* pem = cfg->ssl_service_pem;
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
key += strlen(chroot);
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
pem += strlen(chroot);
/* setup the session keys; the callback to use them will be
* attached to each sslctx separately */
if(cfg->tls_session_ticket_keys.first &&
cfg->tls_session_ticket_keys.first->str[0] != 0) {
if(!listen_sslctx_setup_ticket_keys(
cfg->tls_session_ticket_keys.first, chroot)) {
fatal_exit("could not set session ticket SSL_CTX");
}
}
daemon->listen_dot_sslctx = daemon_setup_listen_dot_sslctx(
daemon, cfg);
if(!daemon->listen_dot_sslctx)
fatal_exit("Could not set up listen dot sslctx");
#ifdef HAVE_NGHTTP2_NGHTTP2_H
if(cfg_has_https(cfg)) {
daemon->listen_doh_sslctx =
daemon_setup_listen_doh_sslctx(daemon, cfg);
if(!daemon->listen_doh_sslctx)
fatal_exit("Could not set up listen doh sslctx");
}
#endif
#ifdef HAVE_NGTCP2
if(cfg_has_quic(cfg)) {
daemon->listen_quic_sslctx =
daemon_setup_listen_quic_sslctx(daemon, cfg);
if(!daemon->listen_quic_sslctx)
fatal_exit("Could not set up listen quic sslctx");
}
#endif /* HAVE_NGTCP2 */
/* Store the file name and mtime to detect changes later. */
daemon->ssl_service_key = strdup(cfg->ssl_service_key);
if(!daemon->ssl_service_key)
fatal_exit("could not setup ssl ctx: out of memory");
if(cfg->ssl_service_pem) {
daemon->ssl_service_pem = strdup(cfg->ssl_service_pem);
if(!daemon->ssl_service_pem)
fatal_exit("could not setup ssl ctx: out of memory");
} else {
daemon->ssl_service_pem = NULL;
}
if(!file_get_mtime(key,
&daemon->mtime_ssl_service_key,
&daemon->mtime_ns_ssl_service_key, NULL))
log_err("Could not stat(%s): %s",
key, strerror(errno));
if(pem) {
if(!file_get_mtime(pem,
&daemon->mtime_ssl_service_pem,
&daemon->mtime_ns_ssl_service_pem, NULL))
log_err("Could not stat(%s): %s",
pem, strerror(errno));
} else {
daemon->mtime_ssl_service_pem = 0;
daemon->mtime_ns_ssl_service_pem = 0;
}
}
daemon->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(
daemon, cfg);
if(!daemon->connect_dot_sslctx)
fatal_exit("could not setup connect dot sslctx");
#else /* HAVE_SSL */
(void)daemon;(void)cfg;
#endif /* HAVE_SSL */
}
/** Delete the ssl ctxs */
static void
daemon_delete_sslctxs(struct daemon* daemon)
{
#ifdef HAVE_SSL
listen_sslctx_delete_ticket_keys();
SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx);
daemon->listen_dot_sslctx = NULL;
SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx);
daemon->listen_doh_sslctx = NULL;
SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx);
daemon->connect_dot_sslctx = NULL;
free(daemon->ssl_service_key);
daemon->ssl_service_key = NULL;
free(daemon->ssl_service_pem);
daemon->ssl_service_pem = NULL;
#else
(void)daemon;
#endif
#ifdef HAVE_NGTCP2
SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx);
daemon->listen_quic_sslctx = NULL;
#endif
}
int
ssl_cert_changed(struct daemon* daemon, struct config_file* cfg)
{
time_t mtime = 0;
long ns = 0;
char* chroot = daemon->chroot;
char* key = cfg->ssl_service_key;
char* pem = cfg->ssl_service_pem;
log_assert(daemon->ssl_service_key && cfg->ssl_service_key);
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
key += strlen(chroot);
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
pem += strlen(chroot);
if(strcmp(daemon->ssl_service_key, cfg->ssl_service_key) != 0)
return 1;
if(daemon->ssl_service_pem && cfg->ssl_service_pem &&
strcmp(daemon->ssl_service_pem, cfg->ssl_service_pem) != 0)
return 1;
if(!file_get_mtime(key, &mtime, &ns, NULL)) {
log_err("Could not stat(%s): %s",
key, strerror(errno));
/* It has probably changed, but file read is likely going to
* fail. */
return 0;
}
if(mtime != daemon->mtime_ssl_service_key ||
ns != daemon->mtime_ns_ssl_service_key)
return 1;
if(pem) {
if(!file_get_mtime(pem, &mtime, &ns, NULL)) {
log_err("Could not stat(%s): %s",
pem, strerror(errno));
/* It has probably changed, but file read is likely going to
* fail. */
return 0;
}
if(mtime != daemon->mtime_ssl_service_pem ||
ns != daemon->mtime_ns_ssl_service_pem)
return 1;
}
return 0;
}
/** Reload the sslctxs if they have changed */
static void
daemon_reload_sslctxs(struct daemon* daemon)
{
#ifdef HAVE_SSL
if(daemon->cfg->ssl_service_key && daemon->cfg->ssl_service_key[0]) {
/* See if changed */
if(!daemon->ssl_service_key ||
ssl_cert_changed(daemon,daemon->cfg)) {
verbose(VERB_ALGO, "Reloading certificates");
daemon_delete_sslctxs(daemon);
daemon_setup_sslctxs(daemon, daemon->cfg);
}
} else {
/* See if sslctxs are removed from config. */
if(daemon->ssl_service_key) {
verbose(VERB_ALGO, "Removing certificates");
daemon_delete_sslctxs(daemon);
}
}
#else
(void)daemon;
#endif
}
struct daemon*
daemon_init(void)
{
@@ -235,7 +497,11 @@ daemon_init(void)
# else
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
| OPENSSL_INIT_ADD_ALL_DIGESTS
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
| OPENSSL_INIT_NO_LOAD_CONFIG
# endif
, NULL);
# endif
# if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS
/* grab the COMP method ptr because openssl leaks it */
@@ -244,7 +510,11 @@ daemon_init(void)
# if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
(void)SSL_library_init();
# else
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
| OPENSSL_INIT_NO_LOAD_CONFIG
# endif
, NULL);
# endif
# if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
if(!ub_openssl_lock_init())
@@ -556,11 +826,17 @@ daemon_create_workers(struct daemon* daemon)
fatal_exit("out of memory during daemon init");
numport = daemon_get_shufport(daemon, shufport);
verbose(VERB_ALGO, "total of %d outgoing ports available", numport);
if(!(daemon->shared_ports = shared_ports_create(daemon->cfg->out_ifs,
daemon->cfg->num_out_ifs, daemon->cfg->do_ip4,
daemon->cfg->do_ip6, shufport, numport)))
fatal_exit("could not setup shared ports: out of memory");
#ifdef HAVE_NGTCP2
daemon->doq_table = doq_table_create(daemon->cfg, daemon->rand);
if(!daemon->doq_table)
fatal_exit("could not create doq_table: out of memory");
if (cfg_has_quic(daemon->cfg)) {
daemon->doq_table = doq_table_create(daemon->cfg, daemon->rand);
if(!daemon->doq_table)
fatal_exit("could not create doq_table: out of memory");
}
#endif
daemon->num = (daemon->cfg->num_threads?daemon->cfg->num_threads:1);
@@ -584,10 +860,7 @@ daemon_create_workers(struct daemon* daemon)
#endif
}
for(i=0; i<daemon->num; i++) {
if(!(daemon->workers[i] = worker_create(daemon, i,
shufport+numport*i/daemon->num,
numport*(i+1)/daemon->num - numport*i/daemon->num)))
/* the above is not ports/numthr, due to rounding */
if(!(daemon->workers[i] = worker_create(daemon, i)))
fatal_exit("could not create worker");
}
/* create per-worker alloc caches if not reusing existing ones. */
@@ -631,6 +904,25 @@ static void close_other_pipes(struct daemon* daemon, int thr)
}
#endif /* THREADS_DISABLED */
/**
* Function to set the thread local log ID.
* Either the internal thread number, or the LWP ID on Linux based on
* configuration.
*/
static void
set_log_thread_id(struct worker* worker, struct config_file* cfg)
{
(void)cfg;
log_assert(worker);
#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED)
worker->thread_tid = gettid();
if(cfg->log_thread_id)
log_thread_set(&worker->thread_tid);
else
#endif
log_thread_set(&worker->thread_num);
}
/**
* Function to start one thread.
* @param arg: user argument.
@@ -641,7 +933,15 @@ thread_start(void* arg)
{
struct worker* worker = (struct worker*)arg;
int port_num = 0;
log_thread_set(&worker->thread_num);
set_log_thread_id(worker, worker->daemon->cfg);
{
char name[16]; /* seems to be the safest size between
different OSes */
snprintf(name, sizeof(name), "unbound/%u", worker->thread_num);
/* worker->thr_id can be written to after the thread was made
* by the creating thread, so this uses pthread_self. */
ub_thread_setname(ub_thread_self(), name);
}
ub_thread_blocksigs();
#ifdef THREADS_DISABLED
/* close pipe ends used by main */
@@ -655,8 +955,9 @@ thread_start(void* arg)
port_num = 0;
#endif
if(!worker_init(worker, worker->daemon->cfg,
worker->daemon->ports[port_num], 0))
worker->daemon->ports[port_num], 0)) {
fatal_exit("Could not initialize thread");
}
worker_work(worker);
return NULL;
@@ -716,6 +1017,7 @@ daemon_fork(struct daemon* daemon)
#endif
log_assert(daemon);
daemon_reload_sslctxs(daemon);
if(!(daemon->env->views = views_create()))
fatal_exit("Could not create views: out of memory");
/* create individual views and their localzone/data trees */
@@ -801,14 +1103,25 @@ daemon_fork(struct daemon* daemon)
fatal_exit("RPZ requires the respip module");
/* first create all the worker structures, so we can pass
* them to the newly created threads.
* them to the newly created threads.
*/
daemon_create_workers(daemon);
/* Set it for the first (main) worker since it does not take part in
* the thread_start() procedure.
*/
set_log_thread_id(daemon->workers[0], daemon->cfg);
/* If shm stats need an offset, calculate it */
if(daemon->cfg->shm_enable && daemon->cfg->stat_interval > 0) {
daemon->stat_time_specific = 1;
daemon->stat_time_offset =
((int)time(NULL))%daemon->cfg->stat_interval;
}
#if defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP)
/* in libev the first inited base gets signals */
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1))
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) {
fatal_exit("Could not initialize main thread");
}
#endif
/* Now create the threads and init the workers.
@@ -821,8 +1134,9 @@ daemon_fork(struct daemon* daemon)
*/
#if !(defined(HAVE_EV_LOOP) || defined(HAVE_EV_DEFAULT_LOOP))
/* libevent has the last inited base get signals (or any base) */
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1))
if(!worker_init(daemon->workers[0], daemon->cfg, daemon->ports[0], 1)) {
fatal_exit("Could not initialize main thread");
}
#endif
signal_handling_playback(daemon->workers[0]);
@@ -866,7 +1180,6 @@ daemon_cleanup(struct daemon* daemon)
/* before stopping main worker, handle signals ourselves, so we
don't die on multiple reload signals for example. */
signal_handling_record();
log_thread_set(NULL);
/* clean up caches because
* a) RRset IDs will be recycled after a reload, causing collisions
* b) validation config can change, thus rrset, msg, keycache clear
@@ -908,6 +1221,8 @@ daemon_cleanup(struct daemon* daemon)
if(!daemon->reuse_cache || daemon->need_to_exit)
daemon_clear_allocs(daemon);
daemon->num = 0;
shared_ports_delete(daemon->shared_ports);
daemon->shared_ports = NULL;
#ifdef USE_DNSTAP
dt_delete(daemon->dtenv);
daemon->dtenv = NULL;
@@ -917,8 +1232,10 @@ daemon_cleanup(struct daemon* daemon)
daemon->dnscenv = NULL;
#endif
#ifdef HAVE_NGTCP2
doq_table_delete(daemon->doq_table);
daemon->doq_table = NULL;
if (daemon->doq_table) {
doq_table_delete(daemon->doq_table);
daemon->doq_table = NULL;
}
#endif
daemon->cfg = NULL;
}
@@ -956,15 +1273,7 @@ daemon_delete(struct daemon* daemon)
free(daemon->pidfile);
free(daemon->cfgfile);
free(daemon->env);
#ifdef HAVE_SSL
listen_sslctx_delete_ticket_keys();
SSL_CTX_free((SSL_CTX*)daemon->listen_dot_sslctx);
SSL_CTX_free((SSL_CTX*)daemon->listen_doh_sslctx);
SSL_CTX_free((SSL_CTX*)daemon->connect_dot_sslctx);
#endif
#ifdef HAVE_NGTCP2
SSL_CTX_free((SSL_CTX*)daemon->listen_quic_sslctx);
#endif
daemon_delete_sslctxs(daemon);
free(daemon);
/* lex cleanup */
ub_c_lex_destroy();
@@ -976,7 +1285,7 @@ daemon_delete(struct daemon* daemon)
# if HAVE_DECL_SSL_COMP_GET_COMPRESSION_METHODS && HAVE_DECL_SK_SSL_COMP_POP_FREE
# ifndef S_SPLINT_S
# if OPENSSL_VERSION_NUMBER < 0x10100000
sk_SSL_COMP_pop_free(comp_meth, (void(*)())CRYPTO_free);
sk_SSL_COMP_pop_free(comp_meth, (void(*)(SSL_COMP*))CRYPTO_free);
# endif
# endif
# endif
@@ -999,6 +1308,9 @@ daemon_delete(struct daemon* daemon)
# if defined(HAVE_SSL) && defined(OPENSSL_THREADS) && !defined(THREADS_DISABLED)
ub_openssl_lock_delete();
# endif
#ifdef HAVE_OPENSSL_CLEANUP
OPENSSL_cleanup();
#endif
#ifndef HAVE_ARC4RANDOM
_ARC4_LOCK_DESTROY();
#endif
+44
View File
@@ -62,6 +62,7 @@ struct doq_table;
struct cookie_secrets;
struct fast_reload_thread;
struct fast_reload_printq;
struct shared_ports;
#include "dnstap/dnstap_config.h"
#ifdef USE_DNSTAP
@@ -97,6 +98,8 @@ struct daemon {
int rc_port;
/** listening ports for remote control */
struct listen_port* rc_ports;
/** the shared ports structure, with random ports numbers. */
struct shared_ports* shared_ports;
/** remote control connections management (for first worker) */
struct daemon_remote* rc;
/** ssl context for listening to dnstcp over ssl */
@@ -107,6 +110,18 @@ struct daemon {
void* listen_doh_sslctx;
/** ssl context for listening to quic */
void* listen_quic_sslctx;
/** the file name that the ssl context is made with, private key. */
char* ssl_service_key;
/** the file name that the ssl context is made with, certificate. */
char* ssl_service_pem;
/** modification time for ssl_service_key, in sec and ns. Like
* in a struct timespec, but without that for portability. */
time_t mtime_ssl_service_key;
long mtime_ns_ssl_service_key;
/** modification time for ssl_service_pem, in sec and ns. Like
* in a struct timespec, but without that for portability. */
time_t mtime_ssl_service_pem;
long mtime_ns_ssl_service_pem;
/** num threads allocated */
int num;
/** num threads allocated in the previous config or 0 at first */
@@ -143,7 +158,14 @@ struct daemon {
/** the dnstap environment master value, copied and changed by threads*/
struct dt_env* dtenv;
#endif
/** The SHM info for shared memory stats. */
struct shm_main_info* shm_info;
/** if the timeout for statistics is attempted at specific offset.
* If it is true, the stat timeout is the interval+offset, and that
* picks (roughly) the same time offset every time period. */
int stat_time_specific;
/** if the timeout is specific, what offset in the period. */
int stat_time_offset;
/** some response-ip tags or actions are configured if true */
int use_response_ip;
/** some RPZ policies are configured */
@@ -229,4 +251,26 @@ void daemon_apply_cfg(struct daemon* daemon, struct config_file* cfg);
*/
int setup_acl_for_ports(struct acl_list* list, struct listen_port* port_list);
/* setups the needed ssl contexts, fatal_exit() on any failure */
void daemon_setup_sslctxs(struct daemon* daemon, struct config_file* cfg);
/** See if the SSL cert files have changed */
int ssl_cert_changed(struct daemon* daemon, struct config_file* cfg);
/** Setup the listening DoT SSL_CTX, returns the ssl ctx. */
void* daemon_setup_listen_dot_sslctx(struct daemon* daemon,
struct config_file* cfg);
/** Setup the listening DoH SSL_CTX, returns the ssl ctx. */
void* daemon_setup_listen_doh_sslctx(struct daemon* daemon,
struct config_file* cfg);
/** Setup the listening Quic SSL_CTX, returns the ssl ctx */
void* daemon_setup_listen_quic_sslctx(struct daemon* daemon,
struct config_file* cfg);
/** Setup the connect DoT SSL_CTX, returns the ssl ctx */
void* daemon_setup_connect_dot_sslctx(struct daemon* daemon,
struct config_file* cfg);
#endif /* DAEMON_H */
+595 -20
View File
@@ -153,7 +153,7 @@ remote_setup_ctx(struct daemon_remote* rc, struct config_file* cfg)
log_crypto_err("could not SSL_CTX_new");
return 0;
}
if(!listen_sslctx_setup(rc->ctx)) {
if(!listen_sslctx_setup(rc->ctx, cfg->tls_protocols)) {
return 0;
}
@@ -307,6 +307,26 @@ add_open(const char* ip, int nr, struct listen_port** list, int noproto_is_err,
#endif
}
} else {
const char* s = strchr(ip, '@');
char newif[128];
if(s) {
/* override port with ifspec@port */
int portnr;
if((size_t)(s-ip) >= sizeof(newif)) {
log_err("ifname too long: %s", ip);
return -1;
}
portnr = atoi(s+1);
if(portnr < 0 || 0 == portnr || portnr > 65535) {
log_err("invalid portnumber in control-interface: %s", ip);
return -1;
}
(void)strlcpy(newif, ip, sizeof(newif));
newif[s-ip] = 0;
ip = newif;
snprintf(port, sizeof(port), "%d", portnr);
port[sizeof(port)-1]=0;
}
hints.ai_socktype = SOCK_STREAM;
hints.ai_flags = AI_PASSIVE | AI_NUMERICHOST;
if((r = getaddrinfo(ip, port, &hints, &res)) != 0 || !res) {
@@ -801,6 +821,8 @@ print_stats(RES* ssl, const char* nm, struct ub_stats_info* s)
(unsigned long)s->svr.num_queries_cookie_invalid)) return 0;
if(!ssl_printf(ssl, "%s.num.queries_discard_timeout"SQ"%lu\n", nm,
(unsigned long)s->svr.num_queries_discard_timeout)) return 0;
if(!ssl_printf(ssl, "%s.num.queries_replyaddr_limit"SQ"%lu\n", nm,
(unsigned long)s->svr.num_queries_replyaddr_limit)) return 0;
if(!ssl_printf(ssl, "%s.num.queries_wait_limit"SQ"%lu\n", nm,
(unsigned long)s->svr.num_queries_wait_limit)) return 0;
if(!ssl_printf(ssl, "%s.num.cachehits"SQ"%lu\n", nm,
@@ -845,6 +867,8 @@ print_stats(RES* ssl, const char* nm, struct ub_stats_info* s)
(unsigned long)s->mesh_num_states)) return 0;
if(!ssl_printf(ssl, "%s.requestlist.current.user"SQ"%lu\n", nm,
(unsigned long)s->mesh_num_reply_states)) return 0;
if(!ssl_printf(ssl, "%s.requestlist.current.replies"SQ"%lu\n", nm,
(unsigned long)s->mesh_num_reply_addrs)) return 0;
#ifndef S_SPLINT_S
sumwait.tv_sec = s->mesh_replies_sum_wait_sec;
sumwait.tv_usec = s->mesh_replies_sum_wait_usec;
@@ -1509,18 +1533,95 @@ do_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker)
(void)ssl_printf(ssl, "added %d datas\n", num);
}
static int
perform_data_remove_rr(RES* ssl, struct local_zones* local_zones,
uint8_t* rr, size_t len, size_t dname_len, char *arg)
{
uint16_t rr_class, rr_type;
int labs;
struct local_zone* z;
struct local_data* ld;
uint8_t *rdata;
size_t rdata_len, index;
struct packed_rrset_data* d;
struct local_rrset* p;
rdata = sldns_wirerr_get_rdatawl(rr, len, dname_len);
rdata_len = ((size_t)sldns_wirerr_get_rdatalen(rr, len, dname_len))+2;
labs = dname_count_labels(rr);
rr_class = sldns_wirerr_get_class(rr, len, dname_len);
rr_type = sldns_wirerr_get_type(rr, len, dname_len);
z = local_zones_lookup(local_zones, rr, dname_len,
labs, rr_class, rr_type, 1);
if (!z) {
ssl_printf(ssl, "error no zone for rr %s\n", arg);
return 0;
}
ld = local_zone_find_data(z, rr, dname_len, labs);
if (!ld) {
ssl_printf(ssl, "error no local data for rr %s\n", arg);
return 0;
}
p = ld->rrsets;
while (p && ntohs(p->rrset->rk.type) != rr_type) {
p = p->next;
}
if (!p) {
ssl_printf(ssl, "error no rrset for rr %s\n", arg);
return 0;
}
d = (struct packed_rrset_data*)p->rrset->entry.data;
if (!packed_rrset_find_rr(d, rdata, rdata_len, &index)) {
ssl_printf(ssl, "error rr %s not found in rrset\n", arg);
return 0;
}
if (!local_rrset_remove_rr(d, index)) {
ssl_printf(ssl, "error unable to delete rr %s\n", arg);
return 0;
}
return 1;
}
/** Remove RR data */
static int
perform_data_remove(RES* ssl, struct local_zones* zones, char* arg)
{
uint8_t* nm;
int nmlabs;
size_t nmlen;
if(!parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs))
uint8_t rr[LDNS_RR_BUF_SIZE], *nm;
size_t len = sizeof(rr);
int status, nmlabs;
size_t nmlen, dname_len;
/* try to parse as a rr first */
status = sldns_str2wire_rr_buf(arg, rr, &len, &dname_len, 3600,
NULL, 0, NULL, 0);
/* try to parse as a domain name second */
if (status != 0) {
if (parse_arg_name(ssl, arg, &nm, &nmlen, &nmlabs)) {
local_zones_del_data(zones, nm,
nmlen, nmlabs, LDNS_RR_CLASS_IN);
free(nm);
return 1;
}
ssl_printf(ssl, "error cannot parse rr %s at %d: %s\n", arg,
LDNS_WIREPARSE_OFFSET(status),
sldns_get_errorstr_parse(status));
return 0;
local_zones_del_data(zones, nm,
nmlen, nmlabs, LDNS_RR_CLASS_IN);
free(nm);
}
/* handle the rr case */
if (!perform_data_remove_rr(ssl, zones, rr, len, dname_len, arg))
return 0;
return 1;
}
@@ -1634,6 +1735,14 @@ do_view_data_add(RES* ssl, struct worker* worker, char* arg)
ssl_printf(ssl,"error out of memory\n");
return;
}
if(!v->isfirst) {
/* Global local-zone is not used for this view,
* therefore add defaults to this view-specific
* local-zone. */
struct config_file lz_cfg;
memset(&lz_cfg, 0, sizeof(lz_cfg));
local_zone_enter_defaults(v->local_zones, &lz_cfg);
}
}
do_data_add(ssl, v->local_zones, arg2);
lock_rw_unlock(&v->lock);
@@ -1659,6 +1768,14 @@ do_view_datas_add(struct daemon_remote* rc, RES* ssl, struct worker* worker,
ssl_printf(ssl,"error out of memory\n");
return;
}
if(!v->isfirst) {
/* Global local-zone is not used for this view,
* therefore add defaults to this view-specific
* local-zone. */
struct config_file lz_cfg;
memset(&lz_cfg, 0, sizeof(lz_cfg));
local_zone_enter_defaults(v->local_zones, &lz_cfg);
}
}
/* put the view name in the command buf */
(void)snprintf(buf+strlen(buf), sizeof(buf)-strlen(buf), "%s ", arg);
@@ -2275,6 +2392,9 @@ zone_del_rrset(struct lruhash_entry* e, void* arg)
(struct packed_rrset_data*)e->data;
if(d->ttl > inf->expired) {
d->ttl = inf->expired;
if(d->ttl_add > inf->expired)
d->ttl_add = inf->expired; /* for 0TTL rrsets,
means that d->ttl_add <= d->ttl */
inf->num_rrsets++;
}
}
@@ -2561,7 +2681,7 @@ static int
ssl_print_name_dp(RES* ssl, const char* str, uint8_t* nm, uint16_t dclass,
struct delegpt* dp)
{
char buf[LDNS_MAX_DOMAINLEN];
char buf[LDNS_MAX_DOMAINLEN], portstr[128], tls_auth_name[256];
struct delegpt_ns* ns;
struct delegpt_addr* a;
int f = 0;
@@ -2576,13 +2696,32 @@ ssl_print_name_dp(RES* ssl, const char* str, uint8_t* nm, uint16_t dclass,
}
for(ns = dp->nslist; ns; ns = ns->next) {
dname_str(ns->name, buf);
if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf))
if(ns->port != UNBOUND_DNS_PORT)
snprintf(portstr, sizeof(portstr), "@%d", ns->port);
else portstr[0]=0;
if(ns->tls_auth_name)
snprintf(tls_auth_name, sizeof(tls_auth_name), "#%s",
ns->tls_auth_name);
else tls_auth_name[0]=0;
if(!ssl_printf(ssl, "%s%s%s%s", (f?" ":""), buf, portstr,
tls_auth_name))
return 0;
f = 1;
}
for(a = dp->target_list; a; a = a->next_target) {
int port = (unsigned)((a->addr.ss_family == AF_INET) ?
ntohs(((struct sockaddr_in*)&a->addr)->sin_port) :
ntohs(((struct sockaddr_in6*)&a->addr)->sin6_port));
addr_to_str(&a->addr, a->addrlen, buf, sizeof(buf));
if(!ssl_printf(ssl, "%s%s", (f?" ":""), buf))
if(port != UNBOUND_DNS_PORT)
snprintf(portstr, sizeof(portstr), "@%d", port);
else portstr[0]=0;
if(a->tls_auth_name)
snprintf(tls_auth_name, sizeof(tls_auth_name), "#%s",
a->tls_auth_name);
else tls_auth_name[0]=0;
if(!ssl_printf(ssl, "%s%s%s%s", (f?" ":""), buf, portstr,
tls_auth_name))
return 0;
f = 1;
}
@@ -3198,6 +3337,10 @@ do_auth_zone_reload(RES* ssl, struct worker* worker, char* arg)
return;
}
if(!auth_zone_read_zonefile(z, worker->env.cfg)) {
/* The old tree was already cleared. Do not answer from the
* failed load. */
z->zone_expired = 1;
auth_zone_clear_data(z);
lock_rw_unlock(&z->lock);
if(xfr) {
lock_basic_unlock(&xfr->lock);
@@ -3209,6 +3352,7 @@ do_auth_zone_reload(RES* ssl, struct worker* worker, char* arg)
z->zone_expired = 0;
if(xfr) {
xfr->zone_expired = 0;
xfr->num_ixfrs = 0;
if(!xfr_find_soa(z, xfr)) {
if(z->data.count == 0) {
lock_rw_unlock(&z->lock);
@@ -4629,6 +4773,26 @@ fr_init_time(struct timeval* time_start, struct timeval* time_read,
* are kept in here. They can then be deleted.
*/
struct fast_reload_construct {
/** ssl context for listening to dnstcp over ssl */
void* listen_dot_sslctx;
/** ssl context for connecting to dnstcp over ssl */
void* connect_dot_sslctx;
/** ssl context for listening to DoH */
void* listen_doh_sslctx;
/** ssl context for listening to quic */
void* listen_quic_sslctx;
/** the file name that the ssl context is made with, private key. */
char* ssl_service_key;
/** the file name that the ssl context is made with, certificate. */
char* ssl_service_pem;
/** modification time for ssl_service_key, in sec and ns. Like
* in a struct timespec, but without that for portability. */
time_t mtime_ssl_service_key;
long mtime_ns_ssl_service_key;
/** modification time for ssl_service_pem, in sec and ns. Like
* in a struct timespec, but without that for portability. */
time_t mtime_ssl_service_pem;
long mtime_ns_ssl_service_pem;
/** construct for views */
struct views* views;
/** construct for auth zones */
@@ -4881,6 +5045,74 @@ fr_check_changed_cfg_str2list(struct config_str2list* cmp1,
}
}
/** fast reload thread, check if config str3list has changed. */
#define FR_CHECK_CHANGED_CFG_STR3LIST(desc, var, buff) do { \
fr_check_changed_cfg_str3list(cfg->var, newcfg->var, desc, buff,\
sizeof(buff)); \
} while(0);
static void
fr_check_changed_cfg_str3list(struct config_str3list* cmp1,
struct config_str3list* cmp2, const char* desc, char* str, size_t len)
{
struct config_str3list* p1 = cmp1, *p2 = cmp2;
while(p1 && p2) {
if((!p1->str && p2->str) ||
(p1->str && !p2->str) ||
(p1->str && p2->str && strcmp(p1->str, p2->str) != 0)) {
/* The str3list is different. */
fr_add_incompatible_option(desc, str, len);
return;
}
if((!p1->str2 && p2->str2) ||
(p1->str2 && !p2->str2) ||
(p1->str2 && p2->str2 &&
strcmp(p1->str2, p2->str2) != 0)) {
/* The str3list is different. */
fr_add_incompatible_option(desc, str, len);
return;
}
if((!p1->str3 && p2->str3) ||
(p1->str3 && !p2->str3) ||
(p1->str3 && p2->str3 &&
strcmp(p1->str3, p2->str3) != 0)) {
/* The str3list is different. */
fr_add_incompatible_option(desc, str, len);
return;
}
p1 = p1->next;
p2 = p2->next;
}
if((!p1 && p2) || (p1 && !p2)) {
fr_add_incompatible_option(desc, str, len);
}
}
/** fast reload thread, check tag datas. */
static int
fr_check_tag_datas(struct fast_reload_thread* fr, struct config_file* newcfg)
{
char changed_str[1024];
struct config_file* cfg = fr->worker->env.cfg;
changed_str[0]=0;
/* Check for tag_datas in acl_addr. */
FR_CHECK_CHANGED_CFG_STR3LIST("interface-tag-data", interface_tag_datas, changed_str);
FR_CHECK_CHANGED_CFG_STR3LIST("access-control-tag-data", acl_tag_datas, changed_str);
if(changed_str[0] != 0) {
if(fr->fr_drop_mesh)
return 1; /* already dropping queries */
fr->fr_drop_mesh = 1;
fr->worker->daemon->fast_reload_drop_mesh = fr->fr_drop_mesh;
if(!fr_output_printf(fr, "recursion referenced data has changed, with: '%s"
"', and the queries have to be dropped"
", setting '+d'\n", changed_str))
return 0;
fr_send_notification(fr, fast_reload_notification_printout);
}
return 1;
}
/** fast reload thread, check compatible config items */
static int
fr_check_compat_cfg(struct fast_reload_thread* fr, struct config_file* newcfg)
@@ -4932,9 +5164,7 @@ fr_check_compat_cfg(struct fast_reload_thread* fr, struct config_file* newcfg)
FR_CHECK_CHANGED_CFG("http_notls_downstream", http_notls_downstream, changed_str);
FR_CHECK_CHANGED_CFG("https-port", https_port, changed_str);
FR_CHECK_CHANGED_CFG("tls-port", ssl_port, changed_str);
FR_CHECK_CHANGED_CFG_STR("tls-service-key", ssl_service_key, changed_str);
FR_CHECK_CHANGED_CFG_STR("tls-service-pem", ssl_service_pem, changed_str);
FR_CHECK_CHANGED_CFG_STR("tls-cert-bundle", tls_cert_bundle, changed_str);
FR_CHECK_CHANGED_CFG_STR("tls-protocols", tls_protocols, changed_str);
FR_CHECK_CHANGED_CFG_STRLIST("proxy-protocol-port", proxy_protocol_port, changed_str);
FR_CHECK_CHANGED_CFG_STRLIST("tls-additional-port", tls_additional_port, changed_str);
FR_CHECK_CHANGED_CFG_STR("interface-automatic-ports", if_automatic_ports, changed_str);
@@ -5043,6 +5273,19 @@ fr_construct_clear(struct fast_reload_construct* ct)
wait_limits_free(&ct->wait_limits_netblock);
wait_limits_free(&ct->wait_limits_cookie_netblock);
domain_limits_free(&ct->domain_limits);
#ifdef HAVE_SSL
/* The SSL contexts can be SSL_CTX_free here. It is reference
* counted. So ongoing transfers with can continue.
* Once they are done, the context is freed. */
SSL_CTX_free((SSL_CTX*)ct->listen_dot_sslctx);
SSL_CTX_free((SSL_CTX*)ct->connect_dot_sslctx);
SSL_CTX_free((SSL_CTX*)ct->listen_doh_sslctx);
#endif /* HAVE_SSL */
#ifdef HAVE_NGTCP2
SSL_CTX_free((SSL_CTX*)ct->listen_quic_sslctx);
#endif
free(ct->ssl_service_key);
free(ct->ssl_service_pem);
/* Delete the log identity here so that the global value is not
* reset by config_delete. */
if(ct->oldcfg && ct->oldcfg->log_identity) {
@@ -5175,6 +5418,7 @@ config_file_getmem(struct config_file* cfg)
m += getmem_config_strlist(cfg->tls_session_ticket_keys.first);
m += getmem_str(cfg->tls_ciphers);
m += getmem_str(cfg->tls_ciphersuites);
m += getmem_str(cfg->tls_protocols);
m += getmem_str(cfg->http_endpoint);
m += (cfg->outgoing_avail_ports?65536*sizeof(int):0);
m += getmem_str(cfg->target_fetch_policy);
@@ -5291,6 +5535,8 @@ fr_printmem(struct fast_reload_thread* fr,
size_t mem = 0;
if(fr_poll_for_quit(fr))
return 1;
mem += getmem_str(ct->ssl_service_key);
mem += getmem_str(ct->ssl_service_pem);
mem += views_get_mem(ct->views);
mem += respip_set_get_mem(ct->respip_set);
mem += auth_zones_get_mem(ct->auth_zones);
@@ -5403,6 +5649,23 @@ xfr_masterlist_equal(struct auth_master* list1, struct auth_master* list2)
return 0;
}
/** See if configuration has changed. */
static int
xfr_config_equal(struct auth_xfer* xfr1, struct auth_xfer* xfr2)
{
if(xfr1 == NULL && xfr2 == NULL)
return 1;
if(xfr1 == NULL && xfr2 != NULL)
return 0;
if(xfr1 != NULL && xfr2 == NULL)
return 0;
if(xfr1->max_transfer_size != xfr2->max_transfer_size)
return 0;
if(xfr1->max_transfer_time != xfr2->max_transfer_time)
return 0;
return 1;
}
/** See if the list of masters has changed. */
static int
xfr_masters_equal(struct auth_xfer* xfr1, struct auth_xfer* xfr2)
@@ -5491,8 +5754,31 @@ auth_zones_check_changes(struct fast_reload_thread* fr,
&old_serial)!=0);
have_new = (auth_zone_get_serial(new_z,
&new_serial)!=0);
/* A change in primaries, also means it is different
* and the change makes it fire new transfers, from
* the new primaries. */
/* Treat as changed when the old zone has an
* outstanding ZONEMD DS/DNSKEY mesh callback.
* This will make the worker pickup change code
* remove the mesh callback, before the old zone is
* deleted. Also it makes a new zonemd lookup.
* The new lookup is needed, because the new zone
* entry needs to have a valid zonemd result,
* and if that is bad, needs to be invalidated.
* Also if there is a race event where the
* outstanding callback makes the zone invalid,
* before fast-reload completes, the change makes
* the new zone entry have a new zonemd lookup,
* to then invalidate that new zone.
* There is also a brief operational window at
* program start when a zonemd has to be looked
* up on-line, where the zone is operational.
* And this copies that for such a race event.
*/
if(have_old != have_new || old_serial != new_serial
|| !xfr_masters_equal(old_xfr, new_xfr)) {
|| !xfr_masters_equal(old_xfr, new_xfr)
|| !xfr_config_equal(old_xfr, new_xfr)
|| old_z->zonemd_callback_env != NULL) {
/* The zone has been changed. */
if(!fr_add_auth_zone_change(fr, old_z, new_z,
0, 0, 1)) {
@@ -5524,6 +5810,106 @@ auth_zones_check_changes(struct fast_reload_thread* fr,
return 1;
}
/** Check if the sslctxs have changed. */
static int
fr_check_sslctx_change(struct fast_reload_thread* fr,
struct config_file* newcfg)
{
#ifdef HAVE_SSL
struct daemon* daemon = fr->worker->daemon;
if(newcfg->ssl_service_key && newcfg->ssl_service_key[0]) {
if(!daemon->ssl_service_key ||
ssl_cert_changed(daemon, newcfg))
return 1;
} else {
if(daemon->ssl_service_key)
return 1; /* it is removed */
}
if((daemon->cfg->tls_cert_bundle && !newcfg->tls_cert_bundle) ||
(!daemon->cfg->tls_cert_bundle && newcfg->tls_cert_bundle) ||
(daemon->cfg->tls_cert_bundle && newcfg->tls_cert_bundle &&
strcmp(daemon->cfg->tls_cert_bundle, newcfg->tls_cert_bundle)!=0))
return 1; /* The tls-cert-bundle has changed and return
true here makes it reload the connect_dot_sslctx. */
#else
(void)fr; (void)newcfg;
#endif /* HAVE_SSL */
return 0;
}
/** Create the SSL CTXs when they have changed. */
static int
ct_create_sslctxs(struct fast_reload_construct* ct,
struct config_file* newcfg, struct daemon* daemon)
{
#ifdef HAVE_SSL
char* chroot = daemon->chroot;
char* key = newcfg->ssl_service_key;
char* pem = newcfg->ssl_service_pem;
if(!(newcfg->ssl_service_key && newcfg->ssl_service_key[0])) {
/* Leave listen ctxs and file str at NULL */
ct->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(
daemon, newcfg);
if(!ct->connect_dot_sslctx)
return 0;
return 1;
}
if(chroot && strncmp(key, chroot, strlen(chroot)) == 0)
key += strlen(chroot);
if(chroot && pem && strncmp(pem, chroot, strlen(chroot)) == 0)
pem += strlen(chroot);
ct->listen_dot_sslctx = daemon_setup_listen_dot_sslctx(daemon, newcfg);
if(!ct->listen_dot_sslctx)
return 0;
#ifdef HAVE_NGHTTP2_NGHTTP2_H
if(cfg_has_https(newcfg)) {
ct->listen_doh_sslctx = daemon_setup_listen_doh_sslctx(
daemon, newcfg);
if(!ct->listen_doh_sslctx)
return 0;
}
#endif
#ifdef HAVE_NGTCP2
if(cfg_has_quic(newcfg)) {
ct->listen_quic_sslctx = daemon_setup_listen_quic_sslctx(
daemon, newcfg);
if(!ct->listen_quic_sslctx)
return 0;
}
#endif /* HAVE_NGTCP2 */
ct->connect_dot_sslctx = daemon_setup_connect_dot_sslctx(daemon,
newcfg);
if(!ct->connect_dot_sslctx)
return 0;
/* Store mtime and names */
ct->ssl_service_key = strdup(newcfg->ssl_service_key);
if(!ct->ssl_service_key) {
log_err("ct_create_sslctxs: out of memory");
return 0;
}
ct->ssl_service_pem = strdup(newcfg->ssl_service_pem);
if(!ct->ssl_service_pem) {
log_err("ct_create_sslctxs: out of memory");
return 0;
}
if(!file_get_mtime(key, &ct->mtime_ssl_service_key,
&ct->mtime_ns_ssl_service_key, NULL))
log_err("Could not stat(%s): %s",
key, strerror(errno));
if(!file_get_mtime(pem, &ct->mtime_ssl_service_pem,
&ct->mtime_ns_ssl_service_pem, NULL))
log_err("Could not stat(%s): %s",
pem, strerror(errno));
#else
(void)ct; (void)newcfg; (void)daemon;
#endif /* HAVE_SSL */
return 1;
}
/** fast reload thread, construct from config the new items */
static int
fr_construct_from_config(struct fast_reload_thread* fr,
@@ -5531,6 +5917,13 @@ fr_construct_from_config(struct fast_reload_thread* fr,
{
int have_view_respip_cfg = 0;
fr->sslctxs_changed = fr_check_sslctx_change(fr, newcfg);
if(fr->sslctxs_changed) {
if(!ct_create_sslctxs(ct, newcfg, fr->worker->daemon)) {
fr_construct_clear(ct);
return 0;
}
}
if(!(ct->views = views_create())) {
fr_construct_clear(ct);
return 0;
@@ -5808,6 +6201,44 @@ auth_zones_swap(struct auth_zones* az, struct auth_zones* data)
* the xfer elements can continue to be their callbacks. */
}
/** Swap two void* */
static void
void_ptr_swap(void** a, void **b)
{
void* tmp = *a;
*a = *b;
*b = tmp;
}
/** Swap two char* */
static void
char_ptr_swap(char** a, char **b)
{
char* tmp = *a;
*a = *b;
*b = tmp;
}
/** Swap and set ssl ctx information */
static void
sslctxs_swap(struct daemon* daemon, struct fast_reload_construct* ct)
{
void_ptr_swap(&daemon->listen_dot_sslctx, &ct->listen_dot_sslctx);
void_ptr_swap(&daemon->connect_dot_sslctx, &ct->connect_dot_sslctx);
#ifdef HAVE_NGHTTP2_NGHTTP2_H
void_ptr_swap(&daemon->listen_doh_sslctx, &ct->listen_doh_sslctx);
#endif
#ifdef HAVE_NGTCP2
void_ptr_swap(&daemon->listen_quic_sslctx, &ct->listen_quic_sslctx);
#endif /* HAVE_NGTCP2 */
char_ptr_swap(&daemon->ssl_service_key, &ct->ssl_service_key);
char_ptr_swap(&daemon->ssl_service_pem, &ct->ssl_service_pem);
daemon->mtime_ssl_service_key = ct->mtime_ssl_service_key;
daemon->mtime_ns_ssl_service_key = ct->mtime_ns_ssl_service_key;
daemon->mtime_ssl_service_pem = ct->mtime_ssl_service_pem;
daemon->mtime_ns_ssl_service_pem = ct->mtime_ns_ssl_service_pem;
}
#if defined(ATOMIC_POINTER_LOCK_FREE) && defined(HAVE_LINK_ATOMIC_STORE)
/** Fast reload thread, if atomics are available, copy the config items
* one by one with atomic store operations. */
@@ -5869,6 +6300,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
COPY_VAR_ptr(tls_session_ticket_keys.last);
COPY_VAR_ptr(tls_ciphers);
COPY_VAR_ptr(tls_ciphersuites);
COPY_VAR_ptr(tls_protocols);
COPY_VAR_int(tls_use_sni);
COPY_VAR_int(https_port);
COPY_VAR_ptr(http_endpoint);
@@ -5967,6 +6399,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
COPY_VAR_int(log_servfail);
COPY_VAR_ptr(log_identity);
COPY_VAR_int(log_destaddr);
COPY_VAR_int(log_thread_id);
COPY_VAR_int(hide_identity);
COPY_VAR_int(hide_version);
COPY_VAR_int(hide_trustanchor);
@@ -6176,7 +6609,20 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
COPY_VAR_ptr(ipset_name_v6);
#endif
COPY_VAR_int(ede);
COPY_VAR_int(iter_scrub_ns);
COPY_VAR_int(iter_scrub_cname);
COPY_VAR_int(iter_scrub_rrsig);
COPY_VAR_int(max_global_quota);
COPY_VAR_int(iter_scrub_promiscuous);
#undef COPY_VAR_int
#undef COPY_VAR_ptr
#undef COPY_VAR_unsigned_int
#undef COPY_VAR_size_t
#undef COPY_VAR_uint8_t
#undef COPY_VAR_uint16_t
#undef COPY_VAR_uint32_t
#undef COPY_VAR_int32_t
}
#endif /* ATOMIC_POINTER_LOCK_FREE && HAVE_LINK_ATOMIC_STORE */
@@ -6402,11 +6848,17 @@ fr_reload_config(struct fast_reload_thread* fr, struct config_file* newcfg,
daemon->env->cachedb_enabled = cachedb_is_enabled(&daemon->mods,
daemon->env);
#endif
if(fr->sslctxs_changed) {
sslctxs_swap(daemon, ct);
}
#ifdef USE_DNSTAP
if(env->cfg->dnstap) {
if(!fr->fr_nopause)
dt_apply_cfg(daemon->dtenv, env->cfg);
else dt_apply_logcfg(daemon->dtenv, env->cfg);
if(!fr->fr_nopause) {
if(!dt_apply_cfg(daemon->dtenv, env->cfg))
log_warn("fast_reload: dnstap identity/version metadata not updated due to allocation failure");
} else {
dt_apply_logcfg(daemon->dtenv, env->cfg);
}
}
#endif
fr_adjust_cache(env, ct->oldcfg);
@@ -6546,6 +6998,10 @@ fr_load_config(struct fast_reload_thread* fr, struct timeval* time_read,
config_delete(newcfg);
return 0;
}
if(!fr_check_tag_datas(fr, newcfg)) {
config_delete(newcfg);
return 0;
}
if(!fr_check_compat_cfg(fr, newcfg)) {
config_delete(newcfg);
return 0;
@@ -6626,7 +7082,19 @@ static void* fast_reload_thread_main(void* arg)
struct fast_reload_thread* fast_reload_thread = (struct fast_reload_thread*)arg;
struct timeval time_start, time_read, time_construct, time_reload,
time_end;
log_thread_set(&fast_reload_thread->threadnum);
const char name[16] = "unbound/freload"; /* seems to be the safest size
between different OSes */
#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED)
fast_reload_thread->thread_tid = gettid();
if(fast_reload_thread->thread_tid_log)
log_thread_set(&fast_reload_thread->thread_tid);
else
#endif
log_thread_set(&fast_reload_thread->threadnum);
ub_thread_setname(ub_thread_self(), name);
(void)name; /* When setname is not defined, ignore the name variable. */
verbose(VERB_ALGO, "start fast reload thread");
if(fast_reload_thread->fr_verb >= 1) {
@@ -7014,6 +7482,9 @@ fast_reload_thread_setup(struct worker* worker, int fr_verb, int fr_nopause,
lock_basic_init(&fr->fr_output_lock);
lock_protect(&fr->fr_output_lock, fr->fr_output,
sizeof(*fr->fr_output));
#ifdef HAVE_GETTID
fr->thread_tid_log = worker->env.cfg->log_thread_id;
#endif
return 1;
}
@@ -7345,7 +7816,8 @@ auth_zone_zonemd_stop_lookup(struct auth_zone* z, struct mesh_area* mesh)
qinfo.local_alias = NULL;
mesh_remove_callback(mesh, &qinfo, qflags,
&auth_zonemd_dnskey_lookup_callback, z);
&auth_zonemd_dnskey_lookup_callback, z,
z->zonemd_callback_unique_info);
}
/** Pick up the auth zone locks. */
@@ -7454,6 +7926,9 @@ auth_xfr_pickup_config(struct auth_xfer* loadxfr, struct auth_xfer* xfr)
log_assert(loadxfr->namelabs == xfr->namelabs);
log_assert(loadxfr->dclass == xfr->dclass);
xfr->max_transfer_size = loadxfr->max_transfer_size;
xfr->max_transfer_time = loadxfr->max_transfer_time;
/* The lists can be swapped in, the other xfr struct will be deleted
* afterwards. */
probe_masters = xfr->task_probe->masters;
@@ -7478,6 +7953,16 @@ fr_worker_auth_add(struct worker* worker, struct fast_reload_auth_change* item,
/* The xfr item needs to be created. The auth zones lock
* is held to make this possible. */
xfr = auth_xfer_create(worker->env.auth_zones, item->new_z);
if(!xfr) {
log_err("out of memory in fr_worker_auth_add");
lock_rw_unlock(&item->new_z->lock);
lock_rw_unlock(&worker->env.auth_zones->lock);
lock_rw_unlock(&worker->daemon->fast_reload_thread->old_auth_zones->lock);
if(loadxfr) {
lock_basic_unlock(&loadxfr->lock);
}
return;
}
auth_xfr_pickup_config(loadxfr, xfr);
/* Serial information is copied into the xfr struct. */
if(!xfr_find_soa(item->new_z, xfr)) {
@@ -7547,6 +8032,17 @@ fr_worker_auth_cha(struct worker* worker, struct fast_reload_auth_change* item)
} else if(loadxfr && !xfr) {
/* Create the xfr. */
xfr = auth_xfer_create(worker->env.auth_zones, item->new_z);
if(!xfr) {
log_err("out of memory in fr_worker_auth_cha");
lock_rw_unlock(&item->new_z->lock);
lock_rw_unlock(&item->old_z->lock);
lock_rw_unlock(&worker->daemon->fast_reload_thread->old_auth_zones->lock);
lock_rw_unlock(&worker->env.auth_zones->lock);
if(loadxfr) {
lock_basic_unlock(&loadxfr->lock);
}
return;
}
auth_xfr_pickup_config(loadxfr, xfr);
item->new_z->zone_is_slave = 1;
}
@@ -7588,6 +8084,44 @@ fr_worker_pickup_auth_changes(struct worker* worker,
}
}
/** Fast reload, the worker picks up changes in listen_dnsport. */
static void
fr_worker_pickup_listen_dnsport(struct worker* worker)
{
struct listen_dnsport* front = worker->front;
struct daemon* daemon = worker->daemon;
if(worker->daemon->fast_reload_thread->sslctxs_changed) {
struct listen_list* ll;
void* dot_sslctx = daemon->listen_dot_sslctx;
void* doh_sslctx = daemon->listen_doh_sslctx;
#ifdef HAVE_NGTCP2
void* quic_sslctx = daemon->listen_quic_sslctx;
#endif /* HAVE_NGTCP2 */
for(ll = front->cps; ll; ll = ll->next) {
struct comm_point* cp = ll->com;
if(cp->type == comm_tcp_accept &&
cp->tcp_handlers &&
cp->max_tcp_count > 0 &&
cp->tcp_handlers[0]->type == comm_http) {
if(cp->ssl)
cp->ssl = doh_sslctx;
} else if(cp->type == comm_tcp_accept) {
if(cp->ssl)
cp->ssl = dot_sslctx;
#ifdef HAVE_NGTCP2
} else if(cp->type == comm_doq) {
if(cp->ssl) {
cp->ssl = quic_sslctx;
if(cp->doq_socket)
cp->doq_socket->ctx =
(SSL_CTX*)quic_sslctx;
}
#endif /* HAVE_NGTCP2 */
}
}
}
}
/** Fast reload, the worker picks up changes in outside_network. */
static void
fr_worker_pickup_outside_network(struct worker* worker)
@@ -7603,6 +8137,8 @@ fr_worker_pickup_outside_network(struct worker* worker)
outnet->tcp_reuse_timeout = cfg->tcp_reuse_timeout;
outnet->tcp_auth_query_timeout = cfg->tcp_auth_query_timeout;
outnet->delayclose = cfg->delay_close;
if(worker->daemon->fast_reload_thread->sslctxs_changed)
outnet->sslctx = worker->daemon->connect_dot_sslctx;
if(outnet->delayclose) {
#ifndef S_SPLINT_S
outnet->delay_tv.tv_sec = cfg->delay_close/1000;
@@ -7611,6 +8147,41 @@ fr_worker_pickup_outside_network(struct worker* worker)
}
}
#ifdef USE_DNSTAP
/** Fast reload, the worker picks up changes to DNSTAP configuration. */
static void
fr_worker_pickup_dnstap_changes(struct worker* worker)
{
struct dt_env* w_dtenv = &worker->dtenv;
struct dt_env* d_dtenv = worker->daemon->dtenv;
log_assert(d_dtenv != NULL || !worker->daemon->cfg->dnstap);
if(d_dtenv == NULL) {
/* There is no environment when DNSTAP was not enabled
* in the configuration. */
return;
}
w_dtenv->identity = d_dtenv->identity;
w_dtenv->len_identity = d_dtenv->len_identity;
w_dtenv->version = d_dtenv->version;
w_dtenv->len_version = d_dtenv->len_version;
w_dtenv->log_resolver_query_messages =
d_dtenv->log_resolver_query_messages;
w_dtenv->log_resolver_response_messages =
d_dtenv->log_resolver_response_messages;
w_dtenv->log_client_query_messages =
d_dtenv->log_client_query_messages;
w_dtenv->log_client_response_messages =
d_dtenv->log_client_response_messages;
w_dtenv->log_forwarder_query_messages =
d_dtenv->log_forwarder_query_messages;
w_dtenv->log_forwarder_response_messages =
d_dtenv->log_forwarder_response_messages;
lock_basic_lock(&d_dtenv->sample_lock);
w_dtenv->sample_rate = d_dtenv->sample_rate;
lock_basic_unlock(&d_dtenv->sample_lock);
}
#endif /* USE_DNSTAP */
void
fast_reload_worker_pickup_changes(struct worker* worker)
{
@@ -7638,7 +8209,11 @@ fast_reload_worker_pickup_changes(struct worker* worker)
#ifdef USE_CACHEDB
worker->env.cachedb_enabled = worker->daemon->env->cachedb_enabled;
#endif
fr_worker_pickup_listen_dnsport(worker);
fr_worker_pickup_outside_network(worker);
#ifdef USE_DNSTAP
fr_worker_pickup_dnstap_changes(worker);
#endif
}
/** fast reload thread, handle reload_stop notification, send reload stop
+9 -7
View File
@@ -49,6 +49,7 @@
#include <openssl/ssl.h>
#endif
#include "util/locks.h"
#include "libunbound/remote.h"
struct config_file;
struct listen_list;
struct listen_port;
@@ -206,6 +207,12 @@ struct fast_reload_thread {
int commpair[2];
/** thread id, of the io thread */
ub_thread_type tid;
#ifdef HAVE_GETTID
/** thread tid, the LWP id */
pid_t thread_tid;
/** if logging should include the LWP id */
int thread_tid_log;
#endif
/** if the io processing has started */
int started;
/** if the thread has to quit */
@@ -249,6 +256,8 @@ struct fast_reload_thread {
struct fast_reload_auth_change* auth_zone_change_list;
/** the old tree of auth zones, to lookup. */
struct auth_zones* old_auth_zones;
/** If the ssl ctxs have changed. */
int sslctxs_changed;
};
/**
@@ -357,13 +366,6 @@ void fast_reload_thread_start(RES* ssl, struct worker* worker,
*/
void fast_reload_thread_stop(struct fast_reload_thread* fast_reload_thread);
/** fast reload thread commands to remote service thread event callback */
void fast_reload_service_cb(int fd, short bits, void* arg);
/** fast reload callback for the remote control client connection */
int fast_reload_client_callback(struct comm_point* c, void* arg, int err,
struct comm_reply* rep);
/** fast reload printq delete list */
void fast_reload_printq_list_delete(struct fast_reload_printq* list);
+28 -6
View File
@@ -262,6 +262,7 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
s->svr = worker->stats;
s->mesh_num_states = (long long)worker->env.mesh->all.count;
s->mesh_num_reply_states = (long long)worker->env.mesh->num_reply_states;
s->mesh_num_reply_addrs = (long long)worker->env.mesh->num_reply_addrs;
s->mesh_jostled = (long long)worker->env.mesh->stats_jostled;
s->mesh_dropped = (long long)worker->env.mesh->stats_dropped;
s->mesh_replies_sent = (long long)worker->env.mesh->replies_sent;
@@ -284,6 +285,8 @@ server_stats_compile(struct worker* worker, struct ub_stats_info* s, int reset)
NUM_BUCKETS_HIST);
s->svr.num_queries_discard_timeout +=
(long long)worker->env.mesh->num_queries_discard_timeout;
s->svr.num_queries_replyaddr_limit +=
(long long)worker->env.mesh->num_queries_replyaddr_limit;
s->svr.num_queries_wait_limit +=
(long long)worker->env.mesh->num_queries_wait_limit;
s->svr.num_dns_error_reports +=
@@ -419,12 +422,28 @@ void server_stats_obtain(struct worker* worker, struct worker* who,
# endif
#endif
);
log_err("server_stats_obtain: no response from worker %d "
"(stats timeout); returning zero stats for this worker",
who->thread_num);
/* A later reply from the worker, would be sizeof stats reply,
* and the worker_handle_control_cmd routine discards if
* it is not a 4byte command, when that is received here. */
memset(s, 0, sizeof(*s));
return;
}
if(!tube_read_msg(worker->cmd, &reply, &len, 0)) {
log_err("server_stats_obtain: failed to read stats from worker "
"(tube read error); returning zero stats for this worker");
memset(s, 0, sizeof(*s));
return;
}
if(len != (uint32_t)sizeof(*s)) {
log_err("server_stats_obtain: wrong stats length %d (expected %d); "
"discarding", (int)len, (int)sizeof(*s));
free(reply);
memset(s, 0, sizeof(*s));
return;
}
if(!tube_read_msg(worker->cmd, &reply, &len, 0))
fatal_exit("failed to read stats over cmd channel");
if(len != (uint32_t)sizeof(*s))
fatal_exit("stats on cmd channel wrong length %d %d",
(int)len, (int)sizeof(*s));
memcpy(s, reply, (size_t)len);
free(reply);
}
@@ -436,7 +455,7 @@ void server_stats_reply(struct worker* worker, int reset)
verbose(VERB_ALGO, "write stats replymsg");
if(!tube_write_msg(worker->daemon->workers[0]->cmd,
(uint8_t*)&s, sizeof(s), 0))
fatal_exit("could not write stat values over cmd channel");
log_err("could not write stat values over cmd channel");
}
void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
@@ -448,6 +467,8 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
total->svr.num_queries_cookie_invalid += a->svr.num_queries_cookie_invalid;
total->svr.num_queries_discard_timeout +=
a->svr.num_queries_discard_timeout;
total->svr.num_queries_replyaddr_limit +=
a->svr.num_queries_replyaddr_limit;
total->svr.num_queries_wait_limit += a->svr.num_queries_wait_limit;
total->svr.num_dns_error_reports += a->svr.num_dns_error_reports;
total->svr.num_queries_missed_cache += a->svr.num_queries_missed_cache;
@@ -519,6 +540,7 @@ void server_stats_add(struct ub_stats_info* total, struct ub_stats_info* a)
total->mesh_num_states += a->mesh_num_states;
total->mesh_num_reply_states += a->mesh_num_reply_states;
total->mesh_num_reply_addrs += a->mesh_num_reply_addrs;
total->mesh_jostled += a->mesh_jostled;
total->mesh_dropped += a->mesh_dropped;
total->mesh_replies_sent += a->mesh_replies_sent;
+4 -47
View File
@@ -463,57 +463,13 @@ detach(void)
#endif /* HAVE_DAEMON */
}
#ifdef HAVE_SSL
/* setup a listening ssl context, fatal_exit() on any failure */
/** setup the remote and ticket keys */
static void
setup_listen_sslctx(void** ctx, int is_dot, int is_doh, struct config_file* cfg)
{
if(!(*ctx = listen_sslctx_create(
cfg->ssl_service_key, cfg->ssl_service_pem, NULL,
cfg->tls_ciphers, cfg->tls_ciphersuites,
(cfg->tls_session_ticket_keys.first &&
cfg->tls_session_ticket_keys.first->str[0] != 0),
is_dot, is_doh))) {
fatal_exit("could not set up listen SSL_CTX");
}
}
#endif /* HAVE_SSL */
/* setups the needed ssl contexts, fatal_exit() on any failure */
static void
setup_sslctxs(struct daemon* daemon, struct config_file* cfg)
setup_sslctx_remote(struct daemon* daemon, struct config_file* cfg)
{
#ifdef HAVE_SSL
if(!(daemon->rc = daemon_remote_create(cfg)))
fatal_exit("could not set up remote-control");
if(cfg->ssl_service_key && cfg->ssl_service_key[0]) {
/* setup the session keys; the callback to use them will be
* attached to each sslctx separately */
if(cfg->tls_session_ticket_keys.first &&
cfg->tls_session_ticket_keys.first->str[0] != 0) {
if(!listen_sslctx_setup_ticket_keys(
cfg->tls_session_ticket_keys.first)) {
fatal_exit("could not set session ticket SSL_CTX");
}
}
(void)setup_listen_sslctx(&daemon->listen_dot_sslctx, 1, 0, cfg);
#ifdef HAVE_NGHTTP2_NGHTTP2_H
if(cfg_has_https(cfg)) {
(void)setup_listen_sslctx(&daemon->listen_doh_sslctx, 0, 1, cfg);
}
#endif
#ifdef HAVE_NGTCP2
if(cfg_has_quic(cfg)) {
if(!(daemon->listen_quic_sslctx = quic_sslctx_create(
cfg->ssl_service_key, cfg->ssl_service_pem, NULL))) {
fatal_exit("could not set up quic SSL_CTX");
}
}
#endif /* HAVE_NGTCP2 */
}
if(!(daemon->connect_dot_sslctx = connect_sslctx_create(NULL, NULL,
cfg->tls_cert_bundle, cfg->tls_win_cert)))
fatal_exit("could not set up connect SSL_CTX");
#else /* HAVE_SSL */
(void)daemon;(void)cfg;
#endif /* HAVE_SSL */
@@ -545,7 +501,8 @@ perform_setup(struct daemon* daemon, struct config_file* cfg, int debug_mode,
#endif
/* read ssl keys while superuser and outside chroot */
(void)setup_sslctxs(daemon, cfg);
setup_sslctx_remote(daemon, cfg);
daemon_setup_sslctxs(daemon, cfg);
/* init syslog (as root) if needed, before daemonize, otherwise
* a fork error could not be printed since daemonize closed stderr.*/
+213 -116
View File
@@ -255,7 +255,8 @@ worker_handle_service_reply(struct comm_point* c, void* arg, int error,
return 0;
}
/* sanity check. */
if(!LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
if(sldns_buffer_limit(c->buffer) < LDNS_HEADER_SIZE
|| !LDNS_QR_WIRE(sldns_buffer_begin(c->buffer))
|| LDNS_OPCODE_WIRE(sldns_buffer_begin(c->buffer)) !=
LDNS_PACKET_QUERY
|| LDNS_QDCOUNT(sldns_buffer_begin(c->buffer)) > 1) {
@@ -292,6 +293,44 @@ worker_err_ratelimit(struct worker* worker, int err)
return err;
}
/**
* Reply with an error.
* This reply includes the qname if it has been parsed.
* For error ratelimiting, the err ratelimit routine should be checked
* beforehand. The reply is without EDNS, and copies RD and sets QR flag.
* @param pkt: the packet buffer from the comm point.
* @param err: the error code that would be wanted.
* @param qname_len: 0 if not parsed, and the qname length in packet.
*/
static void
query_error(sldns_buffer* pkt, int err, size_t qname_len)
{
/* Preserve the RD flag.
* The CD flag must be cleared in authoritative answers,
* also the AD flag need not be copied into answers.
* The other flags need not be copied into the answer. */
sldns_buffer_write_u16_at(pkt, 2,
sldns_buffer_read_u16_at(pkt, 2)&0x0100U);
LDNS_QR_SET(sldns_buffer_begin(pkt)); /* Set QR flag. */
LDNS_RCODE_SET(sldns_buffer_begin(pkt), err); /* Set rcode */
if(qname_len && LDNS_QDCOUNT(sldns_buffer_begin(pkt))>=1 &&
qname_len <= LDNS_MAX_DOMAINLEN) {
/* Copy query into the answer. */
LDNS_QDCOUNT_SET(sldns_buffer_begin(pkt), 1);
sldns_buffer_set_position(pkt, LDNS_HEADER_SIZE +
qname_len + 2 /* type */ + 2 /* class */ );
} else {
/* No query section in answer. */
LDNS_QDCOUNT_SET(sldns_buffer_begin(pkt), 0);
sldns_buffer_set_position(pkt, LDNS_HEADER_SIZE);
}
LDNS_ANCOUNT_SET(sldns_buffer_begin(pkt), 0);
LDNS_NSCOUNT_SET(sldns_buffer_begin(pkt), 0);
LDNS_ARCOUNT_SET(sldns_buffer_begin(pkt), 0);
sldns_buffer_flip(pkt);
}
/**
* Structure holding the result of the worker_check_request function.
* Based on configuration it could be called up to four times; ideally should
@@ -329,7 +368,6 @@ worker_check_request(sldns_buffer* pkt, struct worker* worker,
return;
}
if(LDNS_TC_WIRE(sldns_buffer_begin(pkt))) {
LDNS_TC_CLR(sldns_buffer_begin(pkt));
verbose(VERB_QUERY, "request bad, has TC bit on");
out->value = worker_err_ratelimit(worker, LDNS_RCODE_FORMERR);
return;
@@ -463,7 +501,9 @@ worker_handle_control_cmd(struct tube* ATTR_UNUSED(tube), uint8_t* msg,
return;
}
if(len != sizeof(uint32_t)) {
fatal_exit("bad control msg length %d", (int)len);
verbose(VERB_ALGO, "bad control msg length %d", (int)len);
free(msg);
return;
}
cmd = sldns_read_uint32(msg);
free(msg);
@@ -676,7 +716,8 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
struct respip_client_info* cinfo, struct reply_info* rep,
struct sockaddr_storage* addr, socklen_t addrlen,
struct ub_packed_rrset_key** alias_rrset,
struct reply_info** encode_repp, struct auth_zones* az)
struct reply_info** encode_repp, struct auth_zones* az,
int* rpz_passthru)
{
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
actinfo.action = respip_none;
@@ -687,7 +728,7 @@ apply_respip_action(struct worker* worker, const struct query_info* qinfo,
return 1;
if(!respip_rewrite_reply(qinfo, cinfo, rep, encode_repp, &actinfo,
alias_rrset, 0, worker->scratchpad, az, NULL,
alias_rrset, 0, worker->scratchpad, az, rpz_passthru,
worker->env.views, worker->env.respip_set))
return 0;
@@ -734,7 +775,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
int* is_secure_answer, struct ub_packed_rrset_key** alias_rrset,
struct reply_info** partial_repp,
struct reply_info* rep, uint16_t id, uint16_t flags,
struct comm_reply* repinfo, struct edns_data* edns)
struct comm_reply* repinfo, struct edns_data* edns, int* rpz_passthru)
{
time_t timenow = *worker->env.now;
uint16_t udpsize = edns->udp_size;
@@ -746,7 +787,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
*partial_repp = NULL; /* avoid accidental further pass */
/* Check TTL */
if(rep->ttl < timenow) {
if(TTL_IS_EXPIRED(rep->ttl, timenow)) {
/* Check if we need to serve expired now */
if(worker->env.cfg->serve_expired &&
/* if serve-expired-client-timeout is set, serve
@@ -844,7 +885,7 @@ answer_from_cache(struct worker* worker, struct query_info* qinfo,
if((worker->daemon->use_response_ip || worker->daemon->use_rpz) &&
!partial_rep && !apply_respip_action(worker, qinfo, cinfo, rep,
&repinfo->client_addr, repinfo->client_addrlen, alias_rrset,
&encode_rep, worker->env.auth_zones)) {
&encode_rep, worker->env.auth_zones, rpz_passthru)) {
goto bail_out;
} else if(partial_rep &&
!respip_merge_cname(partial_rep, qinfo, rep, cinfo,
@@ -971,6 +1012,7 @@ chaos_replystr(sldns_buffer* pkt, char** str, int num, struct edns_data* edns,
size_t udpsize = edns->udp_size;
edns->edns_version = EDNS_ADVERTISED_VERSION;
edns->udp_size = EDNS_ADVERTISED_SIZE;
edns->ext_rcode = 0;
edns->bits &= EDNS_DO;
if(!inplace_cb_reply_local_call(&worker->env, NULL, NULL, NULL,
LDNS_RCODE_NOERROR, edns, repinfo, worker->scratchpad,
@@ -1229,9 +1271,7 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
worker_check_request(c->buffer, worker, check_result);
if(check_result->value != 0) {
if(check_result->value != -1) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
check_result->value);
query_error(c->buffer, check_result->value, 0);
return 1;
}
comm_point_drop_reply(repinfo);
@@ -1248,41 +1288,17 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
/* check additional section is present and that we respond with EDEs */
if(LDNS_ARCOUNT(sldns_buffer_begin(c->buffer)) != 1
|| !ede) {
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_REFUSED);
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
sldns_buffer_flip(c->buffer);
query_error(c->buffer, LDNS_RCODE_REFUSED, 0);
return 1;
}
if (!query_dname_len(c->buffer)) {
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
sldns_buffer_flip(c->buffer);
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
return 1;
}
/* space available for query type and class? */
if (sldns_buffer_remaining(c->buffer) < 2 * sizeof(uint16_t)) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
LDNS_QDCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
sldns_buffer_flip(c->buffer);
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
return 1;
}
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
@@ -1304,35 +1320,27 @@ deny_refuse(struct comm_point* c, enum acl_access acl,
if(!skip_pkt_rrs(c->buffer,
((int)LDNS_ANCOUNT(sldns_buffer_begin(c->buffer)))+
((int)LDNS_NSCOUNT(sldns_buffer_begin(c->buffer))))) {
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
sldns_buffer_set_position(c->buffer, opt_rr_mark);
sldns_buffer_flip(c->buffer);
query_error(c->buffer, LDNS_RCODE_FORMERR,
opt_rr_mark - LDNS_HEADER_SIZE
- 2 /* qtype */ - 2 /* qclass */);
return 1;
}
}
/* Do we have a valid OPT RR here? If not return REFUSED (could be a valid TSIG or something so no FORMERR) */
/* domain name must be the root of length 1. */
if(sldns_buffer_remaining(c->buffer) < 1 || *sldns_buffer_current(c->buffer) != 0) {
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
sldns_buffer_set_position(c->buffer, opt_rr_mark);
sldns_buffer_flip(c->buffer);
query_error(c->buffer, LDNS_RCODE_REFUSED,
opt_rr_mark - LDNS_HEADER_SIZE
- 2 /* qtype */ - 2 /* qclass */);
return 1;
} else {
sldns_buffer_skip(c->buffer, 1); /* skip root label */
}
if(sldns_buffer_remaining(c->buffer) < 2 ||
sldns_buffer_read_u16(c->buffer) != LDNS_RR_TYPE_OPT) {
LDNS_ANCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_NSCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
LDNS_ARCOUNT_SET(sldns_buffer_begin(c->buffer), 0);
sldns_buffer_set_position(c->buffer, opt_rr_mark);
sldns_buffer_flip(c->buffer);
query_error(c->buffer, LDNS_RCODE_REFUSED,
opt_rr_mark - LDNS_HEADER_SIZE
- 2 /* qtype */ - 2 /* qclass */);
return 1;
}
/* Write OPT RR directly after the query,
@@ -1444,6 +1452,24 @@ check_ip_ratelimit(struct worker* worker, struct sockaddr_storage* addr,
return 1;
}
/*
* This is the callback function when a request arrives. It is passed
* the packet and user argument. Return true to send a reply.
* This is of type comm_point_callback_type. The struct comm_point contains
* more comments on the comm_point.callback member about the function.
* @param c: the comm_point where the request arrives on.
* @param arg: the user argument for the callback, the worker.
* @param error: This can be NETEVENT_NOERROR, NETEVENT_TIMEOUT,
* NETEVENT_CLOSED or other comm point callback error values.
* @param repinfo: The reply info, use it to send a reply. If the reply
* is immediate, return 1. If the reply is later on return 0 and save
* the repinfo, to call comm_point_send_reply on.
* @return 1 to sent a reply straight away, for like cache response so that
* no allocation needs to be done. And only internal preallocated buffers
* are used. Return 0 and save the repinfo to reply later, for responses
* that need to be looked up. Return 0 and call comm_point_drop_reply on
* the repinfo to drop the response.
*/
int
worker_handle_request(struct comm_point* c, void* arg, int error,
struct comm_reply* repinfo)
@@ -1471,6 +1497,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
struct reply_info* partial_rep = NULL;
struct query_info* lookup_qinfo = &qinfo;
struct query_info qinfo_tmp; /* placeholder for lookup_qinfo */
uint8_t* alias_orig_qname = NULL; /* original qname for logs, if
a local_alias is used to change the qname. */
struct respip_client_info* cinfo = NULL, cinfo_tmp;
struct timeval wait_time;
struct check_request_result check_result = {0,0};
@@ -1488,7 +1516,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
if (worker->stats.max_query_time_us < wait_queue_time)
worker->stats.max_query_time_us = wait_queue_time;
if(wait_queue_time >
(long long)(worker->env.cfg->sock_queue_timeout * 1000000)) {
(long long)worker->env.cfg->sock_queue_timeout * 1000000) {
/* count and drop queries that were sitting in the socket queue too long */
worker->stats.num_queries_timed_out++;
return 0;
@@ -1510,6 +1538,10 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
"dnscrypt: worker check request: bad query.");
log_addr(VERB_CLIENT,"from",&repinfo->client_addr,
repinfo->client_addrlen);
if(check_result.value != -1) {
query_error(c->buffer, check_result.value, 0);
return 1;
}
comm_point_drop_reply(repinfo);
return 0;
}
@@ -1518,8 +1550,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
"dnscrypt: worker parse request: formerror.");
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
comm_point_drop_reply(repinfo);
return 0;
if(worker_err_ratelimit(worker, LDNS_RCODE_FORMERR) == -1) {
comm_point_drop_reply(repinfo);
return 0;
}
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
return 1;
}
dname_str(qinfo.qname, buf);
if(!(qinfo.qtype == LDNS_RR_TYPE_TXT &&
@@ -1530,9 +1567,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
worker->daemon->dnscenv->provider_name,
sldns_rr_descript(qinfo.qtype)->_name,
buf);
comm_point_drop_reply(repinfo);
if(worker_err_ratelimit(worker, LDNS_RCODE_SERVFAIL) == -1) {
comm_point_drop_reply(repinfo);
return 0;
}
query_error(c->buffer, LDNS_RCODE_SERVFAIL,
qinfo.qname_len);
worker->stats.num_query_dnscrypt_cleartext++;
return 0;
sldns_buffer_copy(c->dnscrypt_buffer, c->buffer);
return 1;
}
worker->stats.num_query_dnscrypt_cert++;
sldns_buffer_rewind(c->buffer);
@@ -1572,9 +1615,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
verbose(VERB_ALGO, "worker check request: bad query.");
log_addr(VERB_CLIENT,"from",&repinfo->client_addr, repinfo->client_addrlen);
if(check_result.value != -1) {
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
check_result.value);
query_error(c->buffer, check_result.value, 0);
return 1;
}
comm_point_drop_reply(repinfo);
@@ -1608,10 +1649,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
comm_point_drop_reply(repinfo);
return 0;
}
sldns_buffer_rewind(c->buffer);
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
query_error(c->buffer, LDNS_RCODE_FORMERR, 0);
goto send_reply;
}
if(worker->env.cfg->log_queries) {
@@ -1624,10 +1662,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
verbose(VERB_ALGO, "worker request: refused zone transfer.");
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
sldns_buffer_rewind(c->buffer);
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_REFUSED);
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
comm_point_drop_reply(repinfo);
return 0;
}
query_error(c->buffer, LDNS_RCODE_REFUSED, qinfo.qname_len);
if(worker->stats.extended) {
worker->stats.qtype[qinfo.qtype]++;
}
@@ -1646,10 +1685,7 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
comm_point_drop_reply(repinfo);
return 0;
}
sldns_buffer_rewind(c->buffer);
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_FORMERR);
query_error(c->buffer, LDNS_RCODE_FORMERR, qinfo.qname_len);
if(worker->stats.extended) {
worker->stats.qtype[qinfo.qtype]++;
}
@@ -1657,13 +1693,17 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}
if((ret=parse_edns_from_query_pkt(
c->buffer, &edns, worker->env.cfg, c, repinfo,
(worker->env.now ? *worker->env.now : time(NULL)),
worker->scratchpad,
*worker->env.now, worker->scratchpad,
worker->daemon->cookie_secrets)) != 0) {
struct edns_data reply_edns;
verbose(VERB_ALGO, "worker parse edns: formerror.");
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
if(worker_err_ratelimit(worker, ret) == -1) {
comm_point_drop_reply(repinfo);
regional_free_all(worker->scratchpad);
return 0;
}
memset(&reply_edns, 0, sizeof(reply_edns));
reply_edns.edns_present = 1;
error_encode(c->buffer, ret, &qinfo,
@@ -1680,6 +1720,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
verbose(VERB_ALGO, "query with bad edns version.");
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
if(worker_err_ratelimit(worker, EDNS_RCODE_BADVERS) == -1) {
comm_point_drop_reply(repinfo);
regional_free_all(worker->scratchpad);
return 0;
}
extended_error_encode(c->buffer, EDNS_RCODE_BADVERS, &qinfo,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), 0, &edns);
@@ -1725,6 +1770,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
else if(edns.cookie_present) {
/* Cookie present, but not valid: Cookie was bad! */
if(worker_err_ratelimit(worker, LDNS_EXT_RCODE_BADCOOKIE) == -1) {
comm_point_drop_reply(repinfo);
regional_free_all(worker->scratchpad);
return 0;
}
extended_error_encode(c->buffer,
LDNS_EXT_RCODE_BADCOOKIE, &qinfo,
*(uint16_t*)(void *)
@@ -1739,6 +1789,11 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
"need cookie or stateful transport");
log_addr(VERB_ALGO, "from",&repinfo->remote_addr
, repinfo->remote_addrlen);
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
comm_point_drop_reply(repinfo);
regional_free_all(worker->scratchpad);
return 0;
}
EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
worker->scratchpad, LDNS_EDE_OTHER,
"DNS Cookie needed for UDP replies");
@@ -1765,14 +1820,14 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
verbose(VERB_ALGO, "worker request: edns is too small.");
log_addr(VERB_CLIENT, "from", &repinfo->client_addr,
repinfo->client_addrlen);
LDNS_QR_SET(sldns_buffer_begin(c->buffer));
if(worker_err_ratelimit(worker, LDNS_RCODE_SERVFAIL) == -1) {
comm_point_drop_reply(repinfo);
regional_free_all(worker->scratchpad);
return 0;
}
/* A small error without qname, and TC flag on. */
query_error(c->buffer, LDNS_RCODE_SERVFAIL, 0);
LDNS_TC_SET(sldns_buffer_begin(c->buffer));
LDNS_RCODE_SET(sldns_buffer_begin(c->buffer),
LDNS_RCODE_SERVFAIL);
sldns_buffer_set_position(c->buffer, LDNS_HEADER_SIZE);
sldns_buffer_write_at(c->buffer, 4,
(uint8_t*)"\0\0\0\0\0\0\0\0", 8);
sldns_buffer_flip(c->buffer);
regional_free_all(worker->scratchpad);
goto send_reply;
}
@@ -1780,7 +1835,13 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
server_stats_insquery(&worker->stats, c, qinfo.qtype,
qinfo.qclass, &edns, repinfo);
if(c->type != comm_udp)
#ifdef USE_DNSCRYPT
edns.udp_size = (c->dnscrypt && repinfo->is_dnscrypted)
? sldns_buffer_capacity(c->buffer) - DNSCRYPT_REPLY_HEADER_SIZE
: 65535;
#else
edns.udp_size = 65535; /* max size for TCP replies */
#endif
if(qinfo.qclass == LDNS_RR_CLASS_CH && answer_chaos(worker, &qinfo,
&edns, repinfo, c->buffer)) {
regional_free_all(worker->scratchpad);
@@ -1857,6 +1918,15 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
* ACLs allow the snooping. */
if(!(LDNS_RD_WIRE(sldns_buffer_begin(c->buffer))) &&
acl != acl_allow_snoop ) {
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
&repinfo->client_addr, repinfo->client_addrlen);
/* This ratelimited error query is accounted in the stats,
* as an incoming query. */
if(worker_err_ratelimit(worker, LDNS_RCODE_REFUSED) == -1) {
comm_point_drop_reply(repinfo);
regional_free_all(worker->scratchpad);
return 0;
}
if(worker->env.cfg->ede) {
EDNS_OPT_LIST_APPEND_EDE(&edns.opt_list_out,
worker->scratchpad, LDNS_EDE_NOT_AUTHORITATIVE, "");
@@ -1865,15 +1935,17 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), &edns);
regional_free_all(worker->scratchpad);
log_addr(VERB_ALGO, "refused nonrec (cache snoop) query from",
&repinfo->client_addr, repinfo->client_addrlen);
goto send_reply;
}
/* If we've found a local alias, replace the qname with the alias
* target before resolving it. */
if(qinfo.local_alias) {
if(qinfo.local_alias->rrset &&
qinfo.local_alias->rrset->rk.dname)
/* Store the original qname, used for logs, since
* local_alias can be removed by region_free_all. */
alias_orig_qname = qinfo.local_alias->rrset->rk.dname;
if(!local_alias_shallow_copy_qname(qinfo.local_alias, &qinfo.qname,
&qinfo.qname_len)) {
regional_free_all(worker->scratchpad);
@@ -1921,7 +1993,7 @@ lookup_cache:
&alias_rrset, &partial_rep, rep,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), repinfo,
&edns)) {
&edns, &rpz_passthru)) {
/* prefetch it if the prefetch TTL expired.
* Note that if there is more than one pass
* its qname must be that used for cache
@@ -1929,11 +2001,11 @@ lookup_cache:
if((worker->env.cfg->prefetch &&
rep->prefetch_ttl <= *worker->env.now) ||
(worker->env.cfg->serve_expired &&
rep->ttl < *worker->env.now &&
TTL_IS_EXPIRED(rep->ttl, *worker->env.now) &&
!(*worker->env.now < rep->serve_expired_norec_ttl))) {
time_t leeway = rep->ttl - *worker->env.now;
if(rep->ttl < *worker->env.now)
leeway = 0;
time_t leeway =
TTL_IS_EXPIRED(rep->ttl, *worker->env.now)
? 0 : rep->ttl - *worker->env.now;
lock_rw_unlock(&e->lock);
reply_and_prefetch(worker, lookup_qinfo,
@@ -2039,11 +2111,10 @@ send_reply_rc:
{
struct timeval tv;
memset(&tv, 0, sizeof(tv));
if(qinfo.local_alias && qinfo.local_alias->rrset &&
qinfo.local_alias->rrset->rk.dname) {
if(alias_orig_qname) {
/* log original qname, before the local alias was
* used to resolve that CNAME to something else */
qinfo.qname = qinfo.local_alias->rrset->rk.dname;
qinfo.qname = alias_orig_qname;
log_reply_info(NO_VERBOSE, &qinfo,
&repinfo->client_addr, repinfo->client_addrlen,
tv, 1, c->buffer,
@@ -2058,7 +2129,7 @@ send_reply_rc:
}
}
#ifdef USE_DNSCRYPT
if(!dnsc_handle_uncurved_request(repinfo)) {
if(!dnsc_handle_uncurved_request(repinfo, c->buffer)) {
return 0;
}
#endif
@@ -2106,10 +2177,37 @@ worker_restart_timer(struct worker* worker)
{
if(worker->env.cfg->stat_interval > 0) {
struct timeval tv;
if(worker->daemon->stat_time_specific) {
struct timeval dest, now;
int interval = worker->env.cfg->stat_interval;
int offset = worker->daemon->stat_time_offset;
int nows, spec;
if(gettimeofday(&now, NULL) < 0)
log_err("gettimeofday: %s", strerror(errno));
#ifndef S_SPLINT_S
tv.tv_sec = worker->env.cfg->stat_interval;
tv.tv_usec = 0;
nows = (int)now.tv_sec;
/* The next time is on the timer interval, at the
* specific offset, time value % interval = offset. */
/* It relies on the integer division below to drop the
* remainder in order to calculate the expected
* result. */
spec = ((nows-offset)/interval+1)*interval+offset;
/* This is instead of an assertion, and should not
* be needed. So assert(spec > nows), tv is going to
* be positive. */
if(spec<=nows) spec += interval;
dest.tv_sec = spec;
dest.tv_usec = 0;
#endif
/* Subtract in timeval, so the fractions of a second
* are rounded to the whole specific time. */
timeval_subtract(&tv, &dest, &now);
} else {
#ifndef S_SPLINT_S
tv.tv_sec = worker->env.cfg->stat_interval;
tv.tv_usec = 0;
#endif
}
comm_timer_set(worker->stat_timer, &tv);
}
}
@@ -2144,23 +2242,16 @@ void worker_probe_timer_cb(void* arg)
}
struct worker*
worker_create(struct daemon* daemon, int id, int* ports, int n)
worker_create(struct daemon* daemon, int id)
{
unsigned int seed;
struct worker* worker = (struct worker*)calloc(1,
sizeof(struct worker));
if(!worker)
return NULL;
worker->numports = n;
worker->ports = (int*)memdup(ports, sizeof(int)*n);
if(!worker->ports) {
free(worker);
return NULL;
}
worker->daemon = daemon;
worker->thread_num = id;
if(!(worker->cmd = tube_create())) {
free(worker->ports);
free(worker);
return NULL;
}
@@ -2168,7 +2259,6 @@ worker_create(struct daemon* daemon, int id, int* ports, int n)
if(!(worker->rndstate = ub_initstate(daemon->rand))) {
log_err("could not init random numbers.");
tube_delete(worker->cmd);
free(worker->ports);
free(worker);
return NULL;
}
@@ -2184,9 +2274,6 @@ worker_init(struct worker* worker, struct config_file *cfg,
struct dt_env* dtenv = &worker->dtenv;
#else
void* dtenv = NULL;
#endif
#ifdef HAVE_GETTID
worker->thread_tid = gettid();
#endif
worker->need_to_exit = 0;
worker->base = comm_base_create(do_sigs);
@@ -2270,14 +2357,14 @@ worker_init(struct worker* worker, struct config_file *cfg,
cfg->out_ifs, cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
worker->daemon->env->infra_cache, worker->rndstate,
cfg->use_caps_bits_for_id, worker->ports, worker->numports,
cfg->use_caps_bits_for_id,
cfg->unwanted_threshold, cfg->outgoing_tcp_mss,
&worker_alloc_cleanup, worker,
cfg->do_udp || cfg->udp_upstream_without_downstream,
worker->daemon->connect_dot_sslctx, cfg->delay_close,
cfg->tls_use_sni, dtenv, cfg->udp_connect,
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
cfg->tcp_auth_query_timeout);
cfg->tcp_auth_query_timeout, worker->daemon->shared_ports);
if(!worker->back) {
log_err("could not create outgoing sockets");
worker_delete(worker);
@@ -2296,6 +2383,8 @@ worker_init(struct worker* worker, struct config_file *cfg,
worker_stat_timer_cb, worker);
if(!worker->stat_timer) {
log_err("could not create statistics timer");
worker_delete(worker);
return 0;
}
/* we use the msg_buffer_size as a good estimate for what the
@@ -2428,7 +2517,6 @@ worker_delete(struct worker* worker)
tube_delete(worker->cmd);
comm_timer_delete(worker->stat_timer);
comm_timer_delete(worker->env.probe_timer);
free(worker->ports);
if(worker->thread_num == 0) {
#ifdef UB_ON_WINDOWS
wsvc_desetup_worker(worker);
@@ -2449,6 +2537,8 @@ worker_delete(struct worker* worker)
/* don't touch worker->alloc, as it's maintained in daemon */
regional_destroy(worker->env.scratch);
regional_destroy(worker->scratchpad);
/* The thread id can reference this worker's id value, so clear it. */
log_thread_set(NULL);
free(worker);
}
@@ -2457,7 +2547,8 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
int want_dnssec, int nocaps, int check_ratelimit,
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
struct module_qstate* q, int* was_ratelimited)
struct module_qstate* q, int* was_ratelimited,
int* ratelimit_incremented)
{
struct worker* worker = q->env->worker;
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@@ -2469,7 +2560,7 @@ worker_send_query(struct query_info* qinfo, uint16_t flags, int dnssec,
want_dnssec, nocaps, check_ratelimit, tcp_upstream,
ssl_upstream, tls_auth_name, addr, addrlen, zone, zonelen, q,
worker_handle_service_reply, e, worker->back->udp_buff, q->env,
was_ratelimited);
was_ratelimited, ratelimit_incremented);
if(!e->qsent) {
return NULL;
}
@@ -2518,7 +2609,8 @@ struct outbound_entry* libworker_send_query(
struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
int* ATTR_UNUSED(ratelimit_incremented))
{
log_assert(0);
return 0;
@@ -2560,6 +2652,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
log_assert(0);
}
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
{
log_assert(0);
}
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
{
log_assert(0);
+1 -7
View File
@@ -104,10 +104,6 @@ struct worker {
struct listen_dnsport* front;
/** the backside outside network interface to the auth servers */
struct outside_network* back;
/** ports to be used by this worker. */
int* ports;
/** number of ports for this worker */
int numports;
/** the signal handler */
struct comm_signal* comsig;
/** commpoint to listen to commands. */
@@ -146,11 +142,9 @@ struct worker {
* with backpointers only. Use worker_init on it later.
* @param daemon: the daemon that this worker thread is part of.
* @param id: the thread number from 0.. numthreads-1.
* @param ports: the ports it is allowed to use, array.
* @param n: the number of ports.
* @return: the new worker or NULL on alloc failure.
*/
struct worker* worker_create(struct daemon* daemon, int id, int* ports, int n);
struct worker* worker_create(struct daemon* daemon, int id);
/**
* Initialize worker.
+71 -19
View File
@@ -366,22 +366,23 @@ static int
dns64_apply_cfg(struct dns64_env* dns64_env, struct config_file* cfg)
{
struct config_strlist* s;
verbose(VERB_ALGO, "dns64-prefix: %s", cfg->dns64_prefix);
if (!netblockstrtoaddr(cfg->dns64_prefix ? cfg->dns64_prefix :
DEFAULT_DNS64_PREFIX, 0, &dns64_env->prefix_addr,
const char* dns64_prefix = cfg->dns64_prefix ?
cfg->dns64_prefix : DEFAULT_DNS64_PREFIX;
verbose(VERB_ALGO, "dns64-prefix: %s", dns64_prefix);
if (!netblockstrtoaddr(dns64_prefix, 0, &dns64_env->prefix_addr,
&dns64_env->prefix_addrlen, &dns64_env->prefix_net)) {
log_err("cannot parse dns64-prefix netblock: %s", cfg->dns64_prefix);
log_err("cannot parse dns64-prefix netblock: %s", dns64_prefix);
return 0;
}
if (!addr_is_ip6(&dns64_env->prefix_addr, dns64_env->prefix_addrlen)) {
log_err("dns64_prefix is not IPv6: %s", cfg->dns64_prefix);
log_err("dns64_prefix is not IPv6: %s", dns64_prefix);
return 0;
}
if (dns64_env->prefix_net != 32 && dns64_env->prefix_net != 40 &&
dns64_env->prefix_net != 48 && dns64_env->prefix_net != 56 &&
dns64_env->prefix_net != 64 && dns64_env->prefix_net != 96 ) {
log_err("dns64-prefix length it not 32, 40, 48, 56, 64 or 96: %s",
cfg->dns64_prefix);
log_err("dns64-prefix length is not 32, 40, 48, 56, 64 or 96: %s",
dns64_prefix);
return 0;
}
for(s = cfg->dns64_ignore_aaaa; s; s = s->next) {
@@ -496,8 +497,8 @@ handle_ipv6_ptr(struct module_qstate* qstate, int id)
/* Create the new sub-query. */
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0, 0,
&subq))
if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->client_info,
qstate->query_flags, 0, 0, &subq))
return module_error;
if (subq) {
subq->curmod = id;
@@ -522,8 +523,8 @@ generate_type_A_query(struct module_qstate* qstate, int id)
/* Start the sub-query. */
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->query_flags, 0,
0, &subq))
if(!(*qstate->env->attach_sub)(qstate, &qinfo, qstate->client_info,
qstate->query_flags, 0, 0, &subq))
{
verbose(VERB_ALGO, "dns64: sub-query creation failed");
return module_error;
@@ -642,6 +643,12 @@ handle_event_moddone(struct module_qstate* qstate, int id)
qstate->return_msg->rep &&
reply_find_answer_rrset(&qstate->qinfo, qstate->return_msg->rep);
int synth_qname = 0;
if(could_synth && !has_data && qstate->env->need_to_validate &&
qstate->return_msg && qstate->return_msg->rep &&
qstate->return_msg->rep->security == sec_status_bogus) {
verbose(VERB_ALGO, "dns64: bogus AAAA reply not synthesized");
could_synth = 0;
}
if(could_synth &&
(!has_data ||
@@ -653,8 +660,11 @@ handle_event_moddone(struct module_qstate* qstate, int id)
/* Store the response in cache. */
if( (!iq || !iq->started_no_cache_store) &&
!qstate->rpz_applied && !qstate->rpz_passthru &&
!qstate->is_subnet_answer &&
qstate->return_msg &&
qstate->return_msg->rep &&
!qstate->fwd_stub_no_cache &&
!dns_cache_store(
qstate->env, &qstate->qinfo, qstate->return_msg->rep,
0, qstate->prefetch_leeway, 0, NULL,
@@ -716,8 +726,15 @@ dns64_operate(struct module_qstate* qstate, enum module_ev event, int id,
}
if(qstate->ext_state[id] == module_finished) {
iq = (struct dns64_qstate*)qstate->minfo[id];
if(iq && iq->state != DNS64_INTERNAL_QUERY)
qstate->no_cache_store = iq->started_no_cache_store;
if(iq && iq->state != DNS64_INTERNAL_QUERY) {
if(qstate->fwd_stub_no_cache) {
/* If the forward/stub has no cache, then
* continue with the query with no cache. */
qstate->no_cache_store = qstate->fwd_stub_no_cache;
} else {
qstate->no_cache_store = iq->started_no_cache_store;
}
}
}
}
@@ -824,6 +841,7 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
size_t i, s;
struct packed_rrset_data* fd, *dd;
struct ub_packed_rrset_key* fk, *dk;
int allocated_return_msg = 0;
verbose(VERB_ALGO, "converting A answers to AAAA answers");
@@ -839,6 +857,7 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
return;
memset(super->return_msg, 0, sizeof(*super->return_msg));
super->return_msg->qinfo = super->qinfo;
allocated_return_msg = 1;
}
rep = qstate->return_msg->rep;
@@ -851,11 +870,14 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
rep->serve_expired_norec_ttl,
rep->an_numrrsets, rep->ns_numrrsets, rep->ar_numrrsets,
rep->rrset_count, rep->security, LDNS_EDE_NONE);
if(!cp)
if(!cp) {
if(allocated_return_msg) super->return_msg = NULL;
return;
}
/* allocate ub_key structures special or not */
if(!reply_info_alloc_rrset_keys(cp, NULL, super->region)) {
if(allocated_return_msg) super->return_msg = NULL;
return;
}
@@ -870,8 +892,10 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
if(i<rep->an_numrrsets && fk->rk.type == htons(LDNS_RR_TYPE_A)) {
/* also sets dk->entry.hash */
dns64_synth_aaaa_data(fk, fd, dk, &dd, super->region, dns64_env);
if(!dd)
if(!dd) {
if(allocated_return_msg) super->return_msg = NULL;
return;
}
/* Delete negative AAAA record from cache stored by
* the iterator module */
rrset_cache_remove(super->env->rrset_cache, dk->rk.dname,
@@ -888,15 +912,19 @@ dns64_adjust_a(int id, struct module_qstate* super, struct module_qstate* qstate
dk->rk.dname = (uint8_t*)regional_alloc_init(super->region,
fk->rk.dname, fk->rk.dname_len);
if(!dk->rk.dname)
if(!dk->rk.dname) {
if(allocated_return_msg) super->return_msg = NULL;
return;
}
s = packed_rrset_sizeof(fd);
dd = (struct packed_rrset_data*)regional_alloc_init(
super->region, fd, s);
if(!dd)
if(!dd) {
if(allocated_return_msg) super->return_msg = NULL;
return;
}
}
packed_rrset_ptr_fixup(dd);
@@ -927,8 +955,10 @@ dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super)
return;
super->return_msg->qinfo = super->qinfo;
if (!(super->return_msg->rep = reply_info_copy(qstate->return_msg->rep,
NULL, super->region)))
NULL, super->region))) {
super->return_msg = NULL;
return;
}
/*
* Adjust the domain name of the answer RR set so that it matches the
@@ -997,6 +1027,21 @@ dns64_inform_super(struct module_qstate* qstate, int id,
/* Use return code from A query in response to client. */
if (super->return_rcode != LDNS_RCODE_NOERROR)
super->return_rcode = qstate->return_rcode;
/* RPZ applied to the subquery need to then change (not cache)
* the super query. With the super query not cached, it is
* going to run the state machine modules on incoming queries,
* that fetch the subquery (cache) response, and modify it
* according to the rpz policy. That makes the synthesized
* super query also adjusted by rpz policies. But loses cache
* hits. Even though the subquery likely is answered from cache,
* internally in its state machine process. */
if(qstate->rpz_applied)
super->rpz_applied = 1;
if(qstate->rpz_passthru)
super->rpz_passthru = 1;
/* Since the super qstate has a new response, its errinf is removed. */
super->errinf = NULL;
/* Generate a response suitable for the original query. */
if (qstate->qinfo.qtype == LDNS_RR_TYPE_A) {
@@ -1005,9 +1050,16 @@ dns64_inform_super(struct module_qstate* qstate, int id,
log_assert(qstate->qinfo.qtype == LDNS_RR_TYPE_PTR);
dns64_adjust_ptr(qstate, super);
}
/* If the sub-query has no cache store, then also the super query. */
if(qstate->fwd_stub_no_cache)
super->fwd_stub_no_cache = 1;
/* Store the generated response in cache. */
if ( (!super_dq || !super_dq->started_no_cache_store) &&
if ( super->return_msg && super->return_msg->rep &&
(!super_dq || !super_dq->started_no_cache_store) &&
!qstate->fwd_stub_no_cache &&
!super->rpz_applied && !super->rpz_passthru &&
!super->is_subnet_answer &&
!dns_cache_store(super->env, &super->qinfo, super->return_msg->rep,
0, super->prefetch_leeway, 0, NULL, super->query_flags,
qstate->qstarttime, qstate->is_valrec))
+32 -5
View File
@@ -361,7 +361,7 @@ dnscrypt_server_uncurve(struct dnsc_env* env,
len -= DNSCRYPT_QUERY_HEADER_SIZE;
while (*sldns_buffer_at(buffer, --len) == 0)
while (len>0 && *sldns_buffer_at(buffer, --len) == 0)
;
if (*sldns_buffer_at(buffer, len) != 0x80) {
@@ -474,10 +474,18 @@ dnscrypt_server_curve(const dnsccert *cert,
uint8_t *const buf = sldns_buffer_begin(buffer);
size_t len = sldns_buffer_limit(buffer);
if(len + DNSCRYPT_REPLY_HEADER_SIZE > sldns_buffer_capacity(buffer))
return -1;
sldns_buffer_clear(buffer);
if(udp){
if (max_len > max_reply_size)
max_len = max_reply_size;
}
if(max_len > sldns_buffer_capacity(buffer))
max_len = sldns_buffer_capacity(buffer);
if(max_len > 65535)
max_len = 65535;
memcpy(nonce, client_nonce, crypto_box_HALF_NONCEBYTES);
@@ -520,6 +528,7 @@ dnscrypt_server_curve(const dnsccert *cert,
DNSCRYPT_MAGIC_HEADER_LEN,
nonce,
crypto_box_NONCEBYTES);
sldns_buffer_flip(buffer);
sldns_buffer_set_limit(buffer, len + DNSCRYPT_REPLY_HEADER_SIZE);
return 0;
}
@@ -663,6 +672,8 @@ dnsc_find_cert(struct dnsc_env* dnscenv, struct sldns_buffer* buffer)
}
dnscrypt_header = (struct dnscrypt_query_header *)sldns_buffer_begin(buffer);
for (i = 0U; i < dnscenv->signed_certs_count; i++) {
if(!certs[i].keypair)
continue;
if (memcmp(certs[i].magic_query, dnscrypt_header->magic_query,
DNSCRYPT_MAGIC_HEADER_LEN) == 0) {
return &certs[i];
@@ -804,6 +815,7 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg)
sizeof *env->keypairs);
env->certs = sodium_allocarray(env->signed_certs_count,
sizeof *env->certs);
memset(env->certs, 0, env->signed_certs_count * sizeof(*env->certs));
cert_id = 0U;
keypair_id = 0U;
@@ -830,7 +842,14 @@ dnsc_parse_keys(struct dnsc_env *env, struct config_file *cfg)
if(memcmp(current_keypair->crypt_publickey,
env->signed_certs[c].server_publickey,
crypto_box_PUBLICKEYBYTES) == 0) {
dnsccert *current_cert = &env->certs[cert_id++];
dnsccert* current_cert;
if(cert_id >= env->signed_certs_count) {
log_err("dnscrypt: secret key %s matches a cert that "
"is already bound to another key (duplicate "
"dnscrypt-secret-key?)", head->str);
return -1;
}
current_cert = &env->certs[cert_id++];
found_cert = 1;
current_cert->keypair = current_keypair;
memcpy(current_cert->magic_query,
@@ -912,12 +931,13 @@ dnsc_handle_curved_request(struct dnsc_env* dnscenv,
}
int
dnsc_handle_uncurved_request(struct comm_reply *repinfo)
dnsc_handle_uncurved_request(struct comm_reply *repinfo,
struct sldns_buffer* buffer)
{
if(!repinfo->c->dnscrypt) {
return 1;
}
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, repinfo->c->buffer);
sldns_buffer_copy(repinfo->c->dnscrypt_buffer, buffer);
if(!repinfo->is_dnscrypted) {
return 1;
}
@@ -963,12 +983,19 @@ dnsc_create(void)
int
dnsc_apply_cfg(struct dnsc_env *env, struct config_file *cfg)
{
int nkeys;
if(dnsc_parse_certs(env, cfg) <= 0) {
fatal_exit("dnsc_apply_cfg: no cert file loaded");
}
if(dnsc_parse_keys(env, cfg) <= 0) {
nkeys = dnsc_parse_keys(env, cfg);
if(nkeys <= 0) {
fatal_exit("dnsc_apply_cfg: no key file loaded");
}
if((size_t)nkeys < env->signed_certs_count) {
fatal_exit("dnsc_apply_cfg: %u dnscrypt-provider-cert file(s) have no "
"matching dnscrypt-secret-key",
(unsigned)(env->signed_certs_count - (size_t)nkeys));
}
randombytes_buf(env->hash_key, sizeof env->hash_key);
env->provider_name = cfg->dnscrypt_provider;
+2 -1
View File
@@ -128,7 +128,8 @@ int dnsc_handle_curved_request(struct dnsc_env* dnscenv,
* \return 0 in case of failure.
*/
int dnsc_handle_uncurved_request(struct comm_reply *repinfo);
int dnsc_handle_uncurved_request(struct comm_reply *repinfo,
struct sldns_buffer* buffer);
/**
* Computes the size of the shared secret cache entry.
+36 -17
View File
@@ -176,26 +176,29 @@ dt_create(struct config_file* cfg)
env->dtio = dt_io_thread_create();
if(!env->dtio) {
log_err("malloc failure");
free(env);
dt_delete(env);
return NULL;
}
if(!dt_io_thread_apply_cfg(env->dtio, cfg)) {
dt_io_thread_delete(env->dtio);
free(env);
dt_delete(env);
return NULL;
}
if(!dt_apply_cfg(env, cfg)) {
dt_delete(env);
return NULL;
}
dt_apply_cfg(env, cfg);
return env;
}
static void
static int
dt_apply_identity(struct dt_env *env, struct config_file *cfg)
{
char buf[MAXHOSTNAMELEN+1];
if (!cfg->dnstap_send_identity) {
free(env->identity);
env->identity = NULL;
return;
env->len_identity = 0;
return 1;
}
free(env->identity);
if (cfg->dnstap_identity == NULL || cfg->dnstap_identity[0] == 0) {
@@ -203,36 +206,49 @@ dt_apply_identity(struct dt_env *env, struct config_file *cfg)
buf[MAXHOSTNAMELEN] = 0;
env->identity = strdup(buf);
} else {
fatal_exit("dt_apply_identity: gethostname() failed");
log_err("dt_apply_identity: gethostname() failed: %s",
strerror(errno));
env->identity = NULL;
env->len_identity = 0;
return 0;
}
} else {
env->identity = strdup(cfg->dnstap_identity);
}
if (env->identity == NULL)
fatal_exit("dt_apply_identity: strdup() failed");
if (env->identity == NULL) {
log_err("dt_apply_identity: strdup() failed");
env->len_identity = 0;
return 0;
}
env->len_identity = (unsigned int)strlen(env->identity);
verbose(VERB_OPS, "dnstap identity field set to \"%s\"",
env->identity);
return 1;
}
static void
static int
dt_apply_version(struct dt_env *env, struct config_file *cfg)
{
if (!cfg->dnstap_send_version) {
free(env->version);
env->version = NULL;
return;
env->len_version = 0;
return 1;
}
free(env->version);
if (cfg->dnstap_version == NULL || cfg->dnstap_version[0] == 0)
env->version = strdup(PACKAGE_STRING);
else
env->version = strdup(cfg->dnstap_version);
if (env->version == NULL)
fatal_exit("dt_apply_version: strdup() failed");
if (env->version == NULL) {
log_err("dt_apply_version: strdup() failed");
env->len_version = 0;
return 0;
}
env->len_version = (unsigned int)strlen(env->version);
verbose(VERB_OPS, "dnstap version field set to \"%s\"",
env->version);
return 1;
}
void
@@ -276,15 +292,18 @@ dt_apply_logcfg(struct dt_env *env, struct config_file *cfg)
lock_basic_unlock(&env->sample_lock);
}
void
int
dt_apply_cfg(struct dt_env *env, struct config_file *cfg)
{
if (!cfg->dnstap)
return;
return 1;
dt_apply_identity(env, cfg);
dt_apply_version(env, cfg);
dt_apply_logcfg(env, cfg);
if(!dt_apply_identity(env, cfg))
return 0;
if(!dt_apply_version(env, cfg))
return 0;
return 1;
}
int
+2 -2
View File
@@ -102,9 +102,9 @@ dt_create(struct config_file* cfg);
* Apply config settings.
* @param env: dnstap environment object.
* @param cfg: new config settings.
* @return false on failure.
*/
void
dt_apply_cfg(struct dt_env *env, struct config_file *cfg);
int dt_apply_cfg(struct dt_env *env, struct config_file *cfg);
/**
* Apply config settings for log enable for message types.
+15 -1
View File
@@ -448,6 +448,9 @@ int dt_io_thread_apply_cfg(struct dt_io_thread* dtio, struct config_file *cfg)
dtio->tls_use_sni = cfg->tls_use_sni;
#endif /* HAVE_SSL */
}
#ifdef HAVE_GETTID
dtio->thread_tid_log = cfg->log_thread_id;
#endif
return 1;
}
@@ -2130,7 +2133,18 @@ static void* dnstap_io(void* arg)
struct dt_io_thread* dtio = (struct dt_io_thread*)arg;
time_t secs = 0;
struct timeval now;
log_thread_set(&dtio->threadnum);
const char name[16] = "unbound/dnstap"; /* seems to be the safest size
between different OSes */
#if defined(HAVE_GETTID) && !defined(THREADS_DISABLED)
dtio->thread_tid = gettid();
if(dtio->thread_tid_log)
log_thread_set(&dtio->thread_tid);
else
#endif
log_thread_set(&dtio->threadnum);
ub_thread_setname(ub_thread_self(), name);
/* setup */
verbose(VERB_ALGO, "start dnstap io thread");
+6
View File
@@ -131,6 +131,12 @@ struct dt_io_thread {
struct dt_io_list_item* io_list_iter;
/** thread id, of the io thread */
ub_thread_type tid;
#ifdef HAVE_GETTID
/** thread tid, the LWP id */
pid_t thread_tid;
/** if logging should include the LWP id */
int thread_tid_log;
#endif
/** if the io processing has started */
int started;
/** ssl context for the io thread, for tls connections. type SSL_CTX* */
+28 -11
View File
@@ -330,7 +330,7 @@ static struct tap_socket* tap_socket_new_tcpaccept(char* ip,
/** create new socket (unconnected, not base-added), or NULL malloc fail */
static struct tap_socket* tap_socket_new_tlsaccept(char* ip,
void (*ev_cb)(int, short, void*), void* data, char* server_key,
char* server_cert, char* verifypem)
char* server_cert, char* verifypem, char* tls_protocols)
{
struct tap_socket* s = calloc(1, sizeof(*s));
if(!s) {
@@ -347,7 +347,7 @@ static struct tap_socket* tap_socket_new_tlsaccept(char* ip,
s->ev_cb = ev_cb;
s->data = data;
s->sslctx = listen_sslctx_create(server_key, server_cert, verifypem,
NULL, NULL, 0, 0, 0);
NULL, NULL, 0, 0, 0, tls_protocols);
if(!s->sslctx) {
log_err("could not create ssl context");
free(s->ip);
@@ -1261,13 +1261,13 @@ static void setup_tcp_list(struct main_tap_data* maindata,
/** setup tls accept sockets */
static void setup_tls_list(struct main_tap_data* maindata,
struct config_strlist_head* tls_list, char* server_key,
char* server_cert, char* verifypem)
char* server_cert, char* verifypem, char* tls_protocols)
{
struct config_strlist* item;
for(item = tls_list->first; item; item = item->next) {
struct tap_socket* s;
s = tap_socket_new_tlsaccept(item->str, &dtio_mainfdcallback,
maindata, server_key, server_cert, verifypem);
maindata, server_key, server_cert, verifypem, tls_protocols);
if(!s) fatal_exit("out of memory");
if(!tap_socket_list_insert(&maindata->acceptlist, s))
fatal_exit("out of memory");
@@ -1300,7 +1300,7 @@ static void
setup_and_run(struct config_strlist_head* local_list,
struct config_strlist_head* tcp_list,
struct config_strlist_head* tls_list, char* server_key,
char* server_cert, char* verifypem)
char* server_cert, char* verifypem, char* tls_protocols)
{
time_t secs = 0;
struct timeval now;
@@ -1326,7 +1326,7 @@ setup_and_run(struct config_strlist_head* local_list,
setup_local_list(maindata, local_list);
setup_tcp_list(maindata, tcp_list);
setup_tls_list(maindata, tls_list, server_key, server_cert,
verifypem);
verifypem, tls_protocols);
if(!tap_socket_list_addevs(maindata->acceptlist, base))
fatal_exit("could not setup accept events");
if(verbosity) log_info("start of service");
@@ -1462,6 +1462,8 @@ int main(int argc, char** argv)
struct config_strlist_head tcp_list;
struct config_strlist_head tls_list;
char* server_key = NULL, *server_cert = NULL, *verifypem = NULL;
char* tls_protocols = "TLSv1.2 TLSv1.3";
#ifdef USE_WINSOCK
WSADATA wsa_data;
if(WSAStartup(MAKEWORD(2,2), &wsa_data) != 0) {
@@ -1561,17 +1563,25 @@ int main(int argc, char** argv)
#else
OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS
| OPENSSL_INIT_ADD_ALL_DIGESTS
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS, NULL);
| OPENSSL_INIT_LOAD_CRYPTO_STRINGS
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
| OPENSSL_INIT_NO_LOAD_CONFIG
# endif
, NULL);
#endif
#if OPENSSL_VERSION_NUMBER < 0x10100000 || !defined(HAVE_OPENSSL_INIT_SSL)
(void)SSL_library_init();
#else
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS, NULL);
(void)OPENSSL_init_ssl(OPENSSL_INIT_LOAD_SSL_STRINGS
# if defined(OPENSSL_INIT_NO_LOAD_CONFIG) && defined(UB_ON_WINDOWS)
| OPENSSL_INIT_NO_LOAD_CONFIG
# endif
, NULL);
#endif
#endif /* HAVE_SSL */
}
setup_and_run(&local_list, &tcp_list, &tls_list, server_key,
server_cert, verifypem);
server_cert, verifypem, tls_protocols);
config_delstrlist(local_list.first);
config_delstrlist(tcp_list.first);
config_delstrlist(tls_list.first);
@@ -1649,7 +1659,8 @@ struct outbound_entry* worker_send_query(
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
int* ATTR_UNUSED(ratelimit_incremented))
{
log_assert(0);
return 0;
@@ -1683,7 +1694,8 @@ struct outbound_entry* libworker_send_query(
socklen_t ATTR_UNUSED(addrlen), uint8_t* ATTR_UNUSED(zone),
size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
int* ATTR_UNUSED(ratelimit_incremented))
{
log_assert(0);
return 0;
@@ -1725,6 +1737,11 @@ void libworker_event_done_cb(void* ATTR_UNUSED(arg), int ATTR_UNUSED(rcode),
log_assert(0);
}
void libworker_alloc_cleanup(void* ATTR_UNUSED(arg))
{
log_assert(0);
}
int context_query_cmp(const void* ATTR_UNUSED(a), const void* ATTR_UNUSED(b))
{
log_assert(0);
+1136
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -13,7 +13,7 @@ If you're not using DNSSEC then you may remove "validator".
2. The "dns64-prefix" directive indicates your DNS64 prefix. For example:
dns64-prefix: 64:FF9B::/96
dns64-prefix: 64:ff9b::/96
The prefix must be a /96 or shorter.
@@ -42,9 +42,9 @@ To enable NAT64 in Unbound, add to unbound.conf's "server" section:
do-nat64: yes
The NAT64 prefix defaults to the DNS64 prefix, which in turn defaults to the
standard 64:FF9B::/96 prefix. You can reconfigure it with:
standard 64:ff9b::/96 prefix. You can reconfigure it with:
nat64-prefix: 64:FF9B::/96
nat64-prefix: 64:ff9b::/96
To test NAT64 operation, pick a domain that only has IPv4 reachability for its
nameservers and try resolving any names in that domain.
+8 -3
View File
@@ -6,11 +6,16 @@ and makes it easier to maintain and contribute to the documentation.
The templated man pages (*.in) are still part of the code repository as to not
alter current procedures that could be in place by users/packagers.
These man pages (*.in) are still the ones being used when
configuring/installing Unbound.
Packagers/users do not have to generate any man pages themselves, this is done
by the core developers during development and upon releasing new versions.
The templated man pages (*.in) are generated by Sphinx (used for the online
documentation).
The online documentation has its own repository at
https://github.com/NLnetLabs/unbound-manual.
In the README.md there (branch test-auto for now), there are further simple
instructions on how to generate the templated man pages there and update them
in this repository.
In that README.md (https://github.com/NLnetLabs/unbound-manual/README.md)
there are further simple instructions on how to generate the templated man
pages there and update them in this repository.
+61 -21
View File
@@ -54,7 +54,7 @@ server:
# interface: 192.0.2.153
# interface: 192.0.2.154
# interface: 192.0.2.154@5003
# interface: 2001:DB8::5
# interface: 2001:db8::5
# interface: eth0@5003
# enable this feature to copy the source address of queries to reply.
@@ -72,12 +72,12 @@ server:
# server from by ip-address. If none, the default (all) interface
# is used. Specify every interface on a 'outgoing-interface:' line.
# outgoing-interface: 192.0.2.153
# outgoing-interface: 2001:DB8::5
# outgoing-interface: 2001:DB8::6
# outgoing-interface: 2001:db8::5
# outgoing-interface: 2001:db8::6
# Specify a netblock to use remainder 64 bits as random bits for
# upstream queries. Uses freebind option (Linux).
# outgoing-interface: 2001:DB8::/64
# outgoing-interface: 2001:db8::/64
# Also (Linux:) ip -6 addr add 2001:db8::/64 dev lo
# And: ip -6 route add local 2001:db8::/64 dev lo
# And set prefer-ip6: yes to use the ip6 randomness from a netblock.
@@ -193,6 +193,9 @@ server:
# Limit on number of CNAME, DNAME records for incoming packets.
# iter-scrub-cname: 11
# Limit on number of RRSIGs for an RRset for incoming packets.
# iter-scrub-rrsig: 8
# Limit on upstream queries for an incoming query and its recursion.
# max-global-quota: 200
@@ -379,7 +382,7 @@ server:
# interface-action: 192.0.2.153 allow
# interface-action: 192.0.2.154 allow
# interface-action: 192.0.2.154@5003 allow
# interface-action: 2001:DB8::5 allow
# interface-action: 2001:db8::5 allow
# interface-action: eth0@5003 allow
# Similar to 'access-control-tag:' but for interfaces.
@@ -496,6 +499,10 @@ server:
# print log lines that say why queries return SERVFAIL to clients.
# log-servfail: no
# log system-wide Linux thread ID, insted of Unbound's internal thread
# counter. Only on Linux and only when threads are available.
# log-thread-id: no
# the pid file. Can be an absolute path outside of chroot/work dir.
# pidfile: "@UNBOUND_PIDFILE@"
@@ -658,7 +665,7 @@ server:
# or, just before the iterator).
# module-config: "validator iterator"
# File with trusted keys, kept uptodate using RFC5011 probes,
# File with trusted keys, kept up-to-date using RFC5011 probes,
# initial file like trust-anchor-file, then it stores metadata.
# Use several entries, one per domain name, to track multiple zones.
#
@@ -718,7 +725,7 @@ server:
# val-max-restart: 5
# Should additional section of secure message also be kept clean of
# unsecure data. Useful to shield the users of this validator from
# non-secure data. Useful to shield the users of this validator from
# potential bogus data in the additional section. All unsigned data
# in the additional section is removed from secure messages.
# val-clean-additional: yes
@@ -756,6 +763,7 @@ server:
# serve-expired-ttl-reset: no
#
# TTL value to use when replying with expired data.
# Capped by the original TTL of the record.
# serve-expired-reply-ttl: 30
#
# Time in milliseconds before replying to the client with expired data.
@@ -891,6 +899,10 @@ server:
# that name
# o block_a resolves all records normally but returns
# NODATA for A queries and ignores local data for that name
# o block_aaaa similarly to block_a, resolves all records normally but
# returns NODATA for AAAA queries and ignores local data for that name
# o block_a_wdata like block_a but uses local data if present.
# o block_aaaa_wdata like block_aaaa but uses local data if present.
# o always_null returns 0.0.0.0 or ::0 for any name in the zone.
# o noview breaks out of that view towards global local-zones.
#
@@ -925,6 +937,22 @@ server:
# add a netblock specific override to a localzone, with zone type
# local-zone-override: "example.com" 192.0.2.0/24 refuse
# Action to apply when the IP address in an AAAA or A RR in the answer
# section of a response matches the specified IP netblock.
# Requires use of the respip module.
# response-ip: 192.0.2.0/24 redirect
# Redirect as specified by the "resource record string" when the IP
# address in an AAAA or A RR in the answer section of a response
# matches the specified IP netblock.
# Requires use of the respip module.
# response-ip-data: 192.0.2.0/24 "example. A 192.0.2.1"
# Apply tag(s) when the IP address in an AAAA or A RR in the answer
# section of a response matches the specified IP netblock.
# Requires use of the respip module.
# response-ip-tag: 192.0.2.0/24 "tag1 tag2"
# service clients over TLS (on the TCP sockets) with plain DNS inside
# the TLS stream, and over HTTPS using HTTP/2 as specified in RFC8484.
# Give the certificate to use and private key.
@@ -935,21 +963,22 @@ server:
# https-port: 443
# quic-port: 853
# Also serve tls on these port numbers (eg. 443, ...), by listing
# tls-additional-port: portno for each of the port numbers.
# cipher setting for TLSv1.2
# tls-ciphers: "DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256"
# cipher setting for TLSv1.3
# tls-ciphersuites: "TLS_AES_128_GCM_SHA256:TLS_AES_128_CCM_8_SHA256:TLS_AES_128_CCM_SHA256:TLS_AES_256_GCM_SHA384:TLS_CHACHA20_POLY1305_SHA256"
# Pad responses to padded queries received over TLS
# pad-responses: yes
# Padded responses will be padded to the closest multiple of this size.
# pad-responses-block-size: 468
# Use the SNI extension for TLS connections. Default is yes.
# Changing the value requires a reload.
# Changing the value requires a restart.
# tls-use-sni: yes
# TLS protocols.
# Changing the value requires a restart.
# tls-protocols: "TLSv1.2 TLSv1.3"
# Add the secret file for TLS Session Ticket.
# Secret file must be 80 bytes of random data.
# First key use to encrypt and decrypt TLS session tickets.
@@ -970,15 +999,18 @@ server:
# and on other systems, the default openssl certificates
# tls-system-cert: no
# Pad responses to padded queries received over TLS
# pad-responses: yes
# Padded responses will be padded to the closest multiple of this size.
# pad-responses-block-size: 468
# Pad queries over TLS upstreams
# pad-queries: yes
# Padded queries will be padded to the closest multiple of this size.
# pad-queries-block-size: 128
# Also serve tls on these port numbers (eg. 443, ...), by listing
# tls-additional-port: portno for each of the port numbers.
# HTTP endpoint to provide DNS-over-HTTPS service on.
# http-endpoint: "/dns-query"
@@ -1259,12 +1291,16 @@ remote-control:
# zonemd-check: no
# zonemd-reject-absence: no
# zonefile: "example.org.zone"
# max-transfer-size: 0
# max-transfer-time: 0
# Views
# Create named views. Name must be unique. Map views to requests using
# the access-control-view option. Views can contain zero or more local-zone
# and local-data options. Options from matching views will override global
# options. Global options will be used if no matching view is found.
# Create named views. Name must be unique.
# Map views to requests using the access-control-view/interface-view options.
# Views can contain zero or more local-zone and local-data options.
# Options from matching views will override global options.
# Global options will be used if no matching view is found.
# With view-first yes, it will try to answer using the global local-zone and
# local-data elements if there is no view specific match.
# view:
@@ -1272,6 +1308,8 @@ remote-control:
# local-zone: "example.com" redirect
# local-data: "example.com A 192.0.2.3"
# local-data-ptr: "192.0.2.3 www.example.com"
# response-ip: 192.0.2.0/24 redirect
# response-ip-data: 192.0.2.0/24 "example. A 192.0.2.1"
# view-first: no
# view:
# name: "anotherview"
@@ -1422,3 +1460,5 @@ remote-control:
# rpz-signal-nxdomain-ra: no
# for-downstream: no
# tags: "example"
# max-transfer-size: 0
# max-transfer-time: 0
+1 -1
View File
@@ -416,6 +416,6 @@ on a function return with file read failure.
.SH AUTHOR
Unbound developers are mentioned in the CREDITS file in the distribution.
.SH COPYRIGHT
1999-2025, NLnet Labs
1999-2026, NLnet Labs
.\" Generated by docutils manpage writer.
.
+13 -4
View File
@@ -39,9 +39,17 @@ unbound-anchor \- Unbound @version@ anchor utility.
validation.
The program fetches the trust anchor with the method from \fI\%RFC 7958\fP when
regular \fI\%RFC 5011\fP update fails to bring it up to date.
It can be run (as root) from the commandline, or run as part of startup
scripts.
Before you start the \fI\%unbound(8)\fP DNS server.
It can be run from the commandline, or run as part of startup scripts before
you start the \fI\%unbound(8)\fP DNS server.
.sp
Note that if you want to use \fI\%RFC 5011\fP with Unbound (i.e., the
\fI\%auto\-trust\-anchor\-file\fP option) so
that trust anchor information is automatically tracked by Unbound during
operation, the user that Unbound runs under (by default \(aqunbound\(aq) must have
write permissions to the file and the directory the file lives in (for creating
temporary files).
In this case you would probably want to run this program as the designated
Unbound user.
.sp
Suggested usage:
.INDENT 0.0
@@ -52,6 +60,7 @@ Suggested usage:
# in the init scripts.
# provide or update the root anchor (if necessary)
unbound\-anchor \-a \(dq@UNBOUND_ROOTKEY_FILE@\(dq
# Please note usage of this root anchor is at your own risk
# and under the terms of our LICENSE (see source).
#
@@ -295,6 +304,6 @@ Signature on the root key information.
.SH AUTHOR
Unbound developers are mentioned in the CREDITS file in the distribution.
.SH COPYRIGHT
1999-2025, NLnet Labs
1999-2026, NLnet Labs
.\" Generated by docutils manpage writer.
.
+12 -3
View File
@@ -51,9 +51,17 @@ Description
validation.
The program fetches the trust anchor with the method from :rfc:`7958` when
regular :rfc:`5011` update fails to bring it up to date.
It can be run (as root) from the commandline, or run as part of startup
scripts.
Before you start the :doc:`unbound(8)</manpages/unbound>` DNS server.
It can be run from the commandline, or run as part of startup scripts before
you start the :doc:`unbound(8)</manpages/unbound>` DNS server.
Note that if you want to use :rfc:`5011` with Unbound (i.e., the
:ref:`auto-trust-anchor-file<unbound.conf.auto-trust-anchor-file>` option) so
that trust anchor information is automatically tracked by Unbound during
operation, the user that Unbound runs under (by default 'unbound') must have
write permissions to the file and the directory the file lives in (for creating
temporary files).
In this case you would probably want to run this program as the designated
Unbound user.
Suggested usage:
@@ -62,6 +70,7 @@ Suggested usage:
# in the init scripts.
# provide or update the root anchor (if necessary)
unbound-anchor -a "@UNBOUND_ROOTKEY_FILE@"
# Please note usage of this root anchor is at your own risk
# and under the terms of our LICENSE (see source).
#
+1 -1
View File
@@ -88,6 +88,6 @@ Unbound configuration file.
.SH AUTHOR
Unbound developers are mentioned in the CREDITS file in the distribution.
.SH COPYRIGHT
1999-2025, NLnet Labs
1999-2026, NLnet Labs
.\" Generated by docutils manpage writer.
.
+42 -1
View File
@@ -168,6 +168,8 @@ ipset,
\fI\%tcp\-auth\-query\-timeout\fP,
\fI\%delay\-close\fP\&.
\fI\%iter\-scrub\-promiscuous\fP\&.
\fI\%tls\-service\-key\fP\&.
\fI\%tls\-service\-pem\fP\&.
.sp
It does not work with
\fI\%interface\fP and
@@ -352,6 +354,8 @@ If the name already has no items, nothing happens.
Often results in NXDOMAIN for the name (in a static zone), but if the name
has become an empty nonterminal (there is still data in domain names below
the removed name), NOERROR nodata answers are the result for that name.
With a specific RR instead of a domain name, that specific record is
removed from the local data, and not all the RR data.
.UNINDENT
.INDENT 0.0
.TP
@@ -880,6 +884,11 @@ number of queries removed due to discard\-timeout by thread
.UNINDENT
.INDENT 0.0
.TP
.B threadX.num.queries_replyaddr_limit
number of queries removed due to replyaddr limits by thread
.UNINDENT
.INDENT 0.0
.TP
.B threadX.num.queries_wait_limit
number of queries removed due to wait\-limit by thread
.UNINDENT
@@ -973,6 +982,10 @@ Number of requests in the request list that were overwritten by newer
entries.
This happens if there is a flood of queries that recursive processing and
the server has a hard time.
The counter is increased when during the flood the
\fI\%jostle\-timeout\fP
allows a query to be removed in favor of a new incoming query.
The older query is then dropped to make space.
.UNINDENT
.INDENT 0.0
.TP
@@ -980,6 +993,12 @@ the server has a hard time.
Queries that were dropped because the request list was full.
This happens if a flood of queries need recursive processing, and the
server can not keep up.
The counter is increased when during the flood there is no space
to be made with the jostle out of an older query, and the new query
is dropped.
Since no older queries are removed, see
\fI\%jostle\-timeout\fP setting, there
is no space for the new query.
.UNINDENT
.INDENT 0.0
.TP
@@ -994,6 +1013,13 @@ Current size of the request list, only the requests from client queries.
.UNINDENT
.INDENT 0.0
.TP
.B threadX.requestlist.current.replies
Current count of the number of reply entries waiting on request list
entries. Because a request list entry can send results to multiple reply
addresses, this number may be larger than the size of the request list.
.UNINDENT
.INDENT 0.0
.TP
.B threadX.recursion.time.avg
Average time it took to answer queries that needed recursive processing.
Note that queries that were answered from the cache are not in this average.
@@ -1048,6 +1074,11 @@ summed over threads.
.UNINDENT
.INDENT 0.0
.TP
.B total.num.queries_replyaddr_limit
summed over threads.
.UNINDENT
.INDENT 0.0
.TP
.B total.num.queries_wait_limit
summed over threads.
.UNINDENT
@@ -1138,6 +1169,16 @@ summed over threads.
.UNINDENT
.INDENT 0.0
.TP
.B total.requestlist.current.user
summed over threads.
.UNINDENT
.INDENT 0.0
.TP
.B total.requestlist.current.replies
summed over threads.
.UNINDENT
.INDENT 0.0
.TP
.B total.recursion.time.median
averaged over threads.
.UNINDENT
@@ -1543,6 +1584,6 @@ directory with private keys (\fBunbound_server.key\fP and
.SH AUTHOR
Unbound developers are mentioned in the CREDITS file in the distribution.
.SH COPYRIGHT
1999-2025, NLnet Labs
1999-2026, NLnet Labs
.\" Generated by docutils manpage writer.
.
+36
View File
@@ -170,6 +170,8 @@ There are several commands that the server understands.
:ref:`tcp-auth-query-timeout<unbound.conf.tcp-auth-query-timeout>`,
:ref:`delay-close<unbound.conf.delay-close>`.
:ref:`iter-scrub-promiscuous<unbound.conf.iter-scrub-promiscuous>`.
:ref:`tls-service-key<unbound.conf.tls-service-key>`.
:ref:`tls-service-pem<unbound.conf.tls-service-pem>`.
It does not work with
:ref:`interface<unbound.conf.interface>` and
@@ -345,6 +347,8 @@ There are several commands that the server understands.
Often results in NXDOMAIN for the name (in a static zone), but if the name
has become an empty nonterminal (there is still data in domain names below
the removed name), NOERROR nodata answers are the result for that name.
With a specific RR instead of a domain name, that specific record is
removed from the local data, and not all the RR data.
@@UAHL@unbound-control.commands@local_zones@@
@@ -815,6 +819,10 @@ number of statistic counters:
number of queries removed due to discard-timeout by thread
@@UAHL@unbound-control.stats@threadX.num.queries_replyaddr_limit@@
number of queries removed due to replyaddr limits by thread
@@UAHL@unbound-control.stats@threadX.num.queries_wait_limit@@
number of queries removed due to wait-limit by thread
@@ -893,12 +901,22 @@ number of statistic counters:
entries.
This happens if there is a flood of queries that recursive processing and
the server has a hard time.
The counter is increased when during the flood the
:ref:`jostle-timeout<unbound.conf.jostle-timeout>`
allows a query to be removed in favor of a new incoming query.
The older query is then dropped to make space.
@@UAHL@unbound-control.stats@threadX.requestlist.exceeded@@
Queries that were dropped because the request list was full.
This happens if a flood of queries need recursive processing, and the
server can not keep up.
The counter is increased when during the flood there is no space
to be made with the jostle out of an older query, and the new query
is dropped.
Since no older queries are removed, see
:ref:`jostle-timeout<unbound.conf.jostle-timeout>` setting, there
is no space for the new query.
@@UAHL@unbound-control.stats@threadX.requestlist.current.all@@
@@ -910,6 +928,12 @@ number of statistic counters:
Current size of the request list, only the requests from client queries.
@@UAHL@unbound-control.stats@threadX.requestlist.current.replies@@
Current count of the number of reply entries waiting on request list
entries. Because a request list entry can send results to multiple reply
addresses, this number may be larger than the size of the request list.
@@UAHL@unbound-control.stats@threadX.recursion.time.avg@@
Average time it took to answer queries that needed recursive processing.
Note that queries that were answered from the cache are not in this average.
@@ -955,6 +979,10 @@ number of statistic counters:
summed over threads.
@@UAHL@unbound-control.stats@total.num.queries_replyaddr_limit@@
summed over threads.
@@UAHL@unbound-control.stats@total.num.queries_wait_limit@@
summed over threads.
@@ -1027,6 +1055,14 @@ number of statistic counters:
summed over threads.
@@UAHL@unbound-control.stats@total.requestlist.current.user@@
summed over threads.
@@UAHL@unbound-control.stats@total.requestlist.current.replies@@
summed over threads.
@@UAHL@unbound-control.stats@total.recursion.time.median@@
averaged over threads.
+1 -1
View File
@@ -185,6 +185,6 @@ encountered a fatal error.
.SH AUTHOR
Unbound developers are mentioned in the CREDITS file in the distribution.
.SH COPYRIGHT
1999-2025, NLnet Labs
1999-2026, NLnet Labs
.\" Generated by docutils manpage writer.
.
+2 -2
View File
@@ -32,7 +32,7 @@ level margin: \\n[rst2man-indent\\n[rst2man-indent-level]]
unbound \- Unbound DNS validating resolver @version@.
.SH SYNOPSIS
.sp
\fBunbound\fP [\fB\-hdpv\fP] [\fB\-c <cfgfile>\fP]
\fBunbound\fP [\fB\-hdpVv\fP] [\fB\-c <cfgfile>\fP]
.SH DESCRIPTION
.sp
\fBunbound\fP is a caching DNS resolver.
@@ -118,6 +118,6 @@ Show the version number and build options, and exit.
.SH AUTHOR
Unbound developers are mentioned in the CREDITS file in the distribution.
.SH COPYRIGHT
1999-2025, NLnet Labs
1999-2026, NLnet Labs
.\" Generated by docutils manpage writer.
.
+516 -146
View File
File diff suppressed because it is too large Load Diff
+487 -141
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -42,7 +42,7 @@ unbound(8)
Synopsis
--------
**unbound** [``-hdpv``] [``-c <cfgfile>``]
**unbound** [``-hdpVv``] [``-c <cfgfile>``]
Description
-----------
+1
View File
@@ -459,6 +459,7 @@ addrtree_insert(struct addrtree *tree, const addrkey_t *addr,
/* Data is stored in other leafnode */
node = newnode;
newnode = node_create(tree, elem, scope, ttl);
if (!newnode) return;
if (!edge_create(newnode, addr, sourcemask, node,
index^1)) {
clean_node(tree, newnode);
+104 -7
View File
@@ -70,6 +70,7 @@ subnet_data_delete(void *d, void *ATTR_UNUSED(arg))
r = (struct subnet_msg_cache_data*)d;
addrtree_delete(r->tree4);
addrtree_delete(r->tree6);
free(r->reason_fail);
free(r);
}
@@ -84,6 +85,8 @@ msg_cache_sizefunc(void *k, void *d)
+ q->key.qname_len + lock_get_mem(&q->entry.lock);
s += addrtree_size(r->tree4);
s += addrtree_size(r->tree6);
if(r->reason_fail)
s += strlen(r->reason_fail)+1;
return s;
}
@@ -162,8 +165,15 @@ int ecs_whitelist_check(struct query_info* qinfo,
if(!ecs_is_whitelisted(sn_env->whitelist,
addr, addrlen, qinfo->qname, qinfo->qname_len,
qinfo->qclass)) {
verbose(VERB_ALGO, "subnet store subquery global, name and addr have no subnet treatment.");
qstate->no_cache_store = 0;
/* The stub or forward can have no_cache set.*/
if(iter_stub_fwd_no_cache(qstate, &qstate->qinfo, NULL, NULL, NULL, 0)) {
verbose(VERB_ALGO, "subnet subquery is not stored globally, stuborfwd is no_cache");
} else {
verbose(VERB_ALGO, "subnet store subquery global, name and addr have no subnet treatment.%s",
(sq->started_no_cache_store?
" But the subnet module was started with no_cache_store for the super query, and that is still applied to this query":""));
qstate->no_cache_store = sq->started_no_cache_store;
}
}
}
return 1;
@@ -193,12 +203,18 @@ int ecs_whitelist_check(struct query_info* qinfo,
if(sq->ecs_server_out.subnet_source_mask == 0) {
sq->subnet_sent_no_subnet = 1;
sq->subnet_sent = 0;
/* The result should end up in subnet cache,
* not in global cache. */
qstate->no_cache_store = 1;
return 1;
}
subnet_ecs_opt_list_append(&sq->ecs_server_out,
&qstate->edns_opts_back_out, qstate, region);
}
sq->subnet_sent = 1;
/* Do not store servfails in global cache, since the subnet
* option is sent out. */
qstate->no_cache_store = 1;
}
else {
/* Outgoing ECS option is set, but we don't want to sent it to
@@ -420,6 +436,35 @@ update_cache(struct module_qstate *qstate, int id)
}
/* lru_entry->lock is locked regardless of how we got here,
* either from the slabhash_lookup, or above in the new allocated */
if(!qstate->return_msg && qstate->error_response_cache) {
struct subnet_msg_cache_data *data =
(struct subnet_msg_cache_data*)lru_entry->data;
data->ttl_servfail = *qstate->env->now + NORR_TTL;
data->ede_fail = errinf_to_reason_bogus(qstate);
diff_size = (data->reason_fail?strlen(data->reason_fail)+1:0);
if(qstate->errinf) {
char* str = errinf_to_str_misc(qstate);
free(data->reason_fail);
data->reason_fail = NULL;
if(str)
data->reason_fail = strdup(str);
}
diff_size = (data->reason_fail?strlen(data->reason_fail)+1:0)
- diff_size;
lock_rw_unlock(&lru_entry->lock);
if (need_to_insert) {
slabhash_insert(subnet_msg_cache, h, lru_entry,
lru_entry->data, NULL);
} else {
slabhash_update_space_used(subnet_msg_cache, h, NULL,
diff_size);
}
return;
}
if(!qstate->return_msg) {
lock_rw_unlock(&lru_entry->lock);
return;
}
/* Step 2, find the correct tree */
if (!(tree = get_tree(lru_entry->data, edns, sne, qstate->env->cfg))) {
lock_rw_unlock(&lru_entry->lock);
@@ -463,6 +508,21 @@ update_cache(struct module_qstate *qstate, int id)
}
}
/** See if there is a stored servfail, returns true if so, and sets reply. */
static int
lookup_check_servfail(struct module_qstate *qstate,
struct subnet_msg_cache_data *data)
{
struct module_env *env = qstate->env;
if(!data)
return 0;
if(!data->ttl_servfail || TTL_IS_EXPIRED(data->ttl_servfail, *env->now))
return 0;
qstate->return_rcode = LDNS_RCODE_SERVFAIL;
errinf_ede(qstate, data->reason_fail, data->ede_fail);
return 1;
}
/** Lookup in cache and reply true iff reply is sent. */
static int
lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq, int prefetch)
@@ -476,6 +536,8 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
struct addrtree *tree;
struct addrnode *node;
uint8_t scope;
int must_validate = (!(qstate->query_flags&BIT_CD)
|| qstate->env->cfg->ignore_cd) && qstate->env->need_to_validate;
memset(&sq->ecs_client_out, 0, sizeof(sq->ecs_client_out));
@@ -489,12 +551,20 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
tree = (ecs->subnet_addr_fam == EDNSSUBNET_ADDRFAM_IP4)?
data->tree4 : data->tree6;
if (!tree) { /* qinfo in cache but not for this family */
if(lookup_check_servfail(qstate, data)) {
lock_rw_unlock(&e->lock);
return 1;
}
lock_rw_unlock(&e->lock);
return 0;
}
node = addrtree_find(tree, (addrkey_t*)ecs->subnet_addr,
ecs->subnet_source_mask, *env->now);
if (!node) { /* plain old cache miss */
if(lookup_check_servfail(qstate, data)) {
lock_rw_unlock(&e->lock);
return 1;
}
lock_rw_unlock(&e->lock);
return 0;
}
@@ -503,12 +573,24 @@ lookup_and_reply(struct module_qstate *qstate, int id, struct subnet_qstate *sq,
(struct reply_info *)node->elem, qstate->region, *env->now, 0,
env->scratch);
scope = (uint8_t)node->scope;
lock_rw_unlock(&e->lock);
if (!qstate->return_msg) { /* Failed allocation or expired TTL */
if(lookup_check_servfail(qstate, data)) {
lock_rw_unlock(&e->lock);
return 1;
}
lock_rw_unlock(&e->lock);
return 0;
}
lock_rw_unlock(&e->lock);
if(qstate->return_msg->rep->security == sec_status_unchecked
&& must_validate) {
/* The message has to be validated first. */
verbose(VERB_ALGO, "subnet: unchecked cache entry needs "
"validation");
return 0;
}
if (sq->subnet_downstream) { /* relay to interested client */
sq->ecs_client_out.subnet_scope_mask = scope;
sq->ecs_client_out.subnet_addr_fam = ecs->subnet_addr_fam;
@@ -563,12 +645,15 @@ generate_sub_request(struct module_qstate *qstate, int id, struct subnet_qstate*
qflags |= BIT_RD;
if((qstate->query_flags & BIT_CD)!=0) {
qflags |= BIT_CD;
valrec = 1;
/* The valrec is left off. Leave out: valrec = 1;
* So that the cache is protected with DNSSEC validation.
* Just like the global cache. DNSSEC validation is performed
* regardless of the setting of the querier's CD flag. */
}
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime, valrec,
&subq)) {
if(!(*qstate->env->attach_sub)(qstate, &qinf, qstate->client_info,
qflags, prime, valrec, &subq)) {
return 0;
}
if(subq) {
@@ -580,6 +665,7 @@ generate_sub_request(struct module_qstate *qstate, int id, struct subnet_qstate*
}
subsq = (struct subnet_qstate*)subq->minfo[id];
subsq->is_subquery_nonsubnet = 1;
subsq->started_no_cache_store = sq->started_no_cache_store;
/* When the client asks 0.0.0.0/0 and the name is not treated
* as subnet, it is to be stored in the global cache.
@@ -632,6 +718,12 @@ eval_response(struct module_qstate *qstate, int id, struct subnet_qstate *sq)
/* already an answer and its not a message, but retain
* the actual rcode, instead of module_error, so send
* module_finished */
if(qstate->error_response_cache) {
verbose(VERB_ALGO, "subnet: store error response");
lock_rw_wrlock(&sne->biglock);
update_cache(qstate, id);
lock_rw_unlock(&sne->biglock);
}
return module_finished;
}
@@ -881,9 +973,11 @@ ecs_edns_back_parsed(struct module_qstate* qstate, int id,
sq->max_scope = sq->ecs_server_in.subnet_scope_mask;
} else if(sq->subnet_sent_no_subnet) {
/* The answer can be stored as scope 0, not in global cache. */
/* This was already set in ecs_whitelist_check */
qstate->no_cache_store = 1;
} else if(sq->subnet_sent) {
/* Need another query to be able to store in global cache. */
/* This was already set in ecs_whitelist_check */
qstate->no_cache_store = 1;
}
@@ -921,6 +1015,7 @@ 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);
qstate->is_subnet_answer = 1;
}
sq->wait_subquery_done = 0;
qstate->ext_state[id] = module_finished;
@@ -1000,6 +1095,7 @@ subnetmod_operate(struct module_qstate *qstate, enum module_ev event,
qstate->env->cfg->prefetch)) {
sne->num_msg_cache++;
lock_rw_unlock(&sne->biglock);
qstate->is_subnet_answer = 1;
verbose(VERB_QUERY, "subnetcache: answered from cache");
qstate->ext_state[id] = module_finished;
@@ -1071,6 +1167,7 @@ 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);
qstate->is_subnet_answer = 1;
if(verbosity >= VERB_ALGO) {
subnet_log_print("reply has edns subnet",
edns_opt_list_find(
+10
View File
@@ -69,8 +69,18 @@ struct subnet_env {
};
struct subnet_msg_cache_data {
/** Tree for nodes with IPv4 subnets. */
struct addrtree* tree4;
/** Tree for nodes with IPv6 subnets. */
struct addrtree* tree6;
/** If servfail is stored, for how long. Abs time in seconds.
* This protects against too much recusion on the item when
* resolution fails, for a couple of seconds. */
time_t ttl_servfail;
/** servfail ede */
sldns_ede_code ede_fail;
/** servfail reason */
char* reason_fail;
};
struct subnet_qstate {
+2
View File
@@ -100,6 +100,8 @@ ipsecmod_whitelist_apply_cfg(struct ipsecmod_env* ie,
struct config_file* cfg)
{
ie->whitelist = rbtree_create(name_tree_compare);
if (!ie->whitelist)
return 0;
if(!read_whitelist(ie->whitelist, cfg))
return 0;
name_tree_init_parents(ie->whitelist);
+92 -38
View File
@@ -51,18 +51,28 @@
#include "util/config_file.h"
#include "services/cache/dns.h"
#include "sldns/wire2str.h"
#ifdef HAVE_SYS_WAIT_H
#include <sys/wait.h>
#endif
/** Apply configuration to ipsecmod module 'global' state. */
static int
ipsecmod_apply_cfg(struct ipsecmod_env* ipsecmod_env, struct config_file* cfg)
{
if(cfg->ipsecmod_whitelist &&
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
return 0;
if(!cfg->ipsecmod_enabled)
return 1;
if(!cfg->ipsecmod_hook || (cfg->ipsecmod_hook && !cfg->ipsecmod_hook[0])) {
log_err("ipsecmod: missing ipsecmod-hook.");
return 0;
}
if(cfg->ipsecmod_whitelist &&
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
if(access(cfg->ipsecmod_hook, X_OK) != 0) {
log_err("ipsecmod: ipsecmod-hook '%s' is not an executable file: %s",
cfg->ipsecmod_hook, strerror(errno));
return 0;
}
return 1;
}
@@ -163,7 +173,7 @@ generate_request(struct module_qstate* qstate, int id, uint8_t* name,
}
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
if(!(*qstate->env->attach_sub)(qstate, &ask,
if(!(*qstate->env->attach_sub)(qstate, &ask, NULL,
(uint16_t)(BIT_RD|flags), 0, 0, &newq)){
log_err("Could not generate request: out of memory");
return 0;
@@ -250,27 +260,16 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
struct ipsecmod_env* ATTR_UNUSED(ie))
{
size_t slen, tempdata_len, tempstring_len, i;
char str[65535], *s, *tempstring;
char qname_s[LDNS_MAX_DOMAINLEN*5+16], ttl_s[32], a_s[32768], k_s[32768];
char *s, *tempstring;
int w = 0, w_temp, qtype;
struct ub_packed_rrset_key* rrset_key;
struct packed_rrset_data* rrset_data;
uint8_t *tempdata;
pid_t pid;
int st;
char* argv[6];
/* Check if a shell is available */
if(system(NULL) == 0) {
log_err("ipsecmod: no shell available for ipsecmod-hook");
return 0;
}
/* Zero the buffer. */
s = str;
slen = sizeof(str);
memset(s, 0, slen);
/* Copy the hook into the buffer. */
w += sldns_str_print(&s, &slen, "%s", qstate->env->cfg->ipsecmod_hook);
/* Put space into the buffer. */
w += sldns_str_print(&s, &slen, " ");
/* Copy the qname into the buffer. */
tempstring = sldns_wire2str_dname(qstate->qinfo.qname,
qstate->qinfo.qname_len);
@@ -283,17 +282,24 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
free(tempstring);
return 0;
}
w += sldns_str_print(&s, &slen, "\"%s\"", tempstring);
if(strlen(tempstring)+1 > sizeof(qname_s)) {
log_err("ipsecmod: string too long");
free(tempstring);
return 0;
}
snprintf(qname_s, sizeof(qname_s), "%s", tempstring);
free(tempstring);
/* Put space into the buffer. */
w += sldns_str_print(&s, &slen, " ");
/* Copy the IPSECKEY TTL into the buffer. */
rrset_data = (struct packed_rrset_data*)iq->ipseckey_rrset->entry.data;
w += sldns_str_print(&s, &slen, "\"%ld\"", (long)rrset_data->ttl);
/* Put space into the buffer. */
w += sldns_str_print(&s, &slen, " ");
snprintf(ttl_s, sizeof(ttl_s), "%ld", (long)rrset_data->ttl);
rrset_key = reply_find_answer_rrset(&qstate->return_msg->qinfo,
qstate->return_msg->rep);
if(!rrset_key) {
log_err("ipsecmod: could not find answer rrset for A/AAAA");
return 0;
}
/* Double check that the records are indeed A/AAAA.
* This should never happen as this function is only executed for A/AAAA
* queries but make sure we don't pass anything other than A/AAAA to the
@@ -304,9 +310,15 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
return 0;
}
rrset_data = (struct packed_rrset_data*)rrset_key->entry.data;
/* Copy the A/AAAA record(s) into the buffer. Start and end this section
* with a double quote. */
w += sldns_str_print(&s, &slen, "\"");
if(!rrset_data) {
log_err("ipsecmod: Answer has no data");
return 0;
}
/* Copy the A/AAAA record(s) into the buffer. */
w = 0;
s = a_s;
slen = sizeof(a_s);
memset(s, 0, slen);
for(i=0; i<rrset_data->count; i++) {
if(i > 0) {
/* Put space into the buffer. */
@@ -322,7 +334,7 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
} else if((size_t)w_temp >= slen) {
s = NULL; /* We do not want str to point outside of buffer. */
slen = 0;
log_err("ipsecmod: shell command too long");
log_err("ipsecmod: command addr argument too long");
return 0;
} else {
s += w_temp;
@@ -330,12 +342,17 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
w += w_temp;
}
}
w += sldns_str_print(&s, &slen, "\"");
/* Put space into the buffer. */
w += sldns_str_print(&s, &slen, " ");
if(w >= (int)sizeof(a_s)) {
log_err("ipsecmod: command addr argument too long");
return 0;
}
/* Copy the IPSECKEY record(s) into the buffer. Start and end this section
* with a double quote. */
w += sldns_str_print(&s, &slen, "\"");
w = 0;
s = k_s;
slen = sizeof(k_s);
memset(s, 0, slen);
rrset_data = (struct packed_rrset_data*)iq->ipseckey_rrset->entry.data;
for(i=0; i<rrset_data->count; i++) {
if(i > 0) {
@@ -362,15 +379,44 @@ call_hook(struct module_qstate* qstate, struct ipsecmod_qstate* iq,
w += w_temp;
}
}
w += sldns_str_print(&s, &slen, "\"");
if(w >= (int)sizeof(str)) {
log_err("ipsecmod: shell command too long");
if(w >= (int)sizeof(k_s)) {
log_err("ipsecmod: command ipseckey argument too long");
return 0;
}
verbose(VERB_ALGO, "ipsecmod: shell command: '%s'", str);
/* ipsecmod-hook should return 0 on success. */
if(system(str) != 0)
/* exec the ipsecmod-hook */
argv[0] = qstate->env->cfg->ipsecmod_hook;
argv[1] = qname_s;
argv[2] = ttl_s;
argv[3] = a_s;
argv[4] = k_s;
argv[5] = NULL;
verbose(VERB_ALGO, "ipsecmod: exec %s \"%s\" %s \"%s\" \"%s\"",
argv[0], argv[1], argv[2], argv[3], argv[4]);
if((pid = fork()) < 0) {
log_err("ipsecmod: for exec, can not fork: %s",
strerror(errno));
return 0;
}
if(pid == 0) {
if(execv(argv[0], argv) < 0)
fprintf(stderr, "ipsecmod: execv: %s\n",
strerror(errno));
_exit(127);
}
while(1) {
if(waitpid(pid, &st, 0) < 0) {
if(errno == EINTR)
continue;
log_err("ipsecmod: wait_pid: %s", strerror(errno));
}
break;
}
if(!(WIFEXITED(st) && WEXITSTATUS(st) == 0)) {
/* the command failed */
return 0;
}
return 1;
}
@@ -435,6 +481,12 @@ ipsecmod_handle_query(struct module_qstate* qstate,
* ipsecmod_max_ttl. */
rrset_key = reply_find_answer_rrset(&qstate->return_msg->qinfo,
qstate->return_msg->rep);
if(!rrset_key) {
log_err("ipsecmod: reply-find-answer failed");
errinf(qstate, "ipsecmod: reply-find-answer failed");
ipsecmod_error(qstate, id);
return;
}
rrset_data = (struct packed_rrset_data*)rrset_key->entry.data;
if(rrset_data->ttl > (time_t)qstate->env->cfg->ipsecmod_max_ttl) {
/* Update TTL for rrset to fixed value. */
@@ -576,6 +628,8 @@ ipsecmod_inform_super(struct module_qstate* qstate, int id,
verbose(VERB_ALGO, "super has no ipsecmod state");
return;
}
if(!siq->enabled)
return;
if(qstate->return_msg) {
struct ub_packed_rrset_key* rrset_key = reply_find_answer_rrset(
+17 -14
View File
@@ -143,7 +143,7 @@ static int add_to_ipset(filter_dev dev, const char *setname, const void *ipaddr,
struct nlmsghdr *nlh;
struct nfgenmsg *nfg;
struct nlattr *nested[2];
static char buffer[BUFF_LEN];
char buffer[BUFF_LEN];
if (strlen(setname) >= IPSET_MAXNAMELEN) {
errno = ENAMETOOLONG;
@@ -208,13 +208,6 @@ ipset_add_rrset_data(struct ipset_env *ie,
ret = add_to_ipset((filter_dev)ie->dev, setname, rr_data + 2, af);
if (ret < 0) {
log_err("ipset: could not add %s into %s", dname, setname);
#if HAVE_NET_PFVAR_H
/* don't close as we might not be able to open again due to dropped privs */
#else
mnl_socket_close((filter_dev)ie->dev);
ie->dev = NULL;
#endif
break;
}
}
@@ -226,15 +219,15 @@ ipset_check_zones_for_rrset(struct module_env *env, struct ipset_env *ie,
struct ub_packed_rrset_key *rrset, const char *qname, int qlen,
const char *setname, int af)
{
static char dname[BUFF_LEN];
char dname[LDNS_MAX_DOMAINLEN*4+16];
const char *ds, *qs;
int dlen, plen;
struct config_strlist *p;
struct packed_rrset_data *d;
dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, BUFF_LEN);
if (dlen == 0) {
dlen = sldns_wire2str_dname_buf(rrset->rk.dname, rrset->rk.dname_len, dname, sizeof(dname));
if (dlen == 0 || dlen >= (int)sizeof(dname)) {
log_err("bad domain name");
return -1;
}
@@ -276,7 +269,7 @@ static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
const char *setname;
struct ub_packed_rrset_key *rrset;
int af;
static char qname[BUFF_LEN];
char qname[LDNS_MAX_DOMAINLEN*4+16];
int qlen;
#ifdef HAVE_NET_PFVAR_H
@@ -292,8 +285,8 @@ static int ipset_update(struct module_env *env, struct dns_msg *return_msg,
#endif
qlen = sldns_wire2str_dname_buf(qinfo.qname, qinfo.qname_len,
qname, BUFF_LEN);
if(qlen == 0) {
qname, sizeof(qname));
if(qlen == 0 || qlen >= (int)sizeof(qname)) {
log_err("bad domain name");
return -1;
}
@@ -372,6 +365,16 @@ int ipset_init(struct module_env* env, int id) {
ipset_env->name_v4 = env->cfg->ipset_name_v4;
ipset_env->name_v6 = env->cfg->ipset_name_v6;
#ifndef HAVE_NET_PFVAR_H
if (ipset_env->name_v4 && strlen(ipset_env->name_v4) >= IPSET_MAXNAMELEN) {
log_err("ipset: name-v4 exceeds IPSET_MAXNAMELEN (%d)", IPSET_MAXNAMELEN);
return 0;
}
if (ipset_env->name_v6 && strlen(ipset_env->name_v6) >= IPSET_MAXNAMELEN) {
log_err("ipset: name-v6 exceeds IPSET_MAXNAMELEN (%d)", IPSET_MAXNAMELEN);
return 0;
}
#endif
ipset_env->v4_enabled = !ipset_env->name_v4 || (strlen(ipset_env->name_v4) == 0) ? 0 : 1;
ipset_env->v6_enabled = !ipset_env->name_v6 || (strlen(ipset_env->name_v6) == 0) ? 0 : 1;
+31 -24
View File
@@ -118,10 +118,10 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
sizeof(struct delegpt_ns));
if(!ns)
return 0;
ns->next = dp->nslist;
ns->namelen = len;
dp->nslist = ns;
ns->name = regional_alloc_init(region, name, ns->namelen);
if(!ns->name)
return 0;
ns->cache_lookup_count = 0;
ns->resolved = 0;
ns->got4 = 0;
@@ -137,7 +137,9 @@ delegpt_add_ns(struct delegpt* dp, struct regional* region, uint8_t* name,
} else {
ns->tls_auth_name = NULL;
}
return ns->name != 0;
ns->next = dp->nslist;
dp->nslist = ns;
return 1;
}
struct delegpt_ns*
@@ -223,11 +225,7 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region,
sizeof(struct delegpt_addr));
if(!a)
return 0;
a->next_target = dp->target_list;
dp->target_list = a;
a->next_result = 0;
a->next_usable = dp->usable_list;
dp->usable_list = a;
memcpy(&a->addr, addr, addrlen);
a->addrlen = addrlen;
a->attempts = 0;
@@ -241,6 +239,10 @@ delegpt_add_addr(struct delegpt* dp, struct regional* region,
} else {
a->tls_auth_name = NULL;
}
a->next_target = dp->target_list;
dp->target_list = a;
a->next_usable = dp->usable_list;
dp->usable_list = a;
return 1;
}
@@ -398,30 +400,33 @@ delegpt_count_missing_targets(struct delegpt* dp, int* alllame)
/** find NS rrset in given list */
static struct ub_packed_rrset_key*
find_NS(struct reply_info* rep, size_t from, size_t to)
find_NS(struct reply_info* rep, size_t from, size_t to, uint16_t qclass)
{
size_t i;
for(i=from; i<to; i++) {
if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS)
if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_NS &&
ntohs(rep->rrsets[i]->rk.rrset_class) == qclass)
return rep->rrsets[i];
}
return NULL;
}
struct delegpt*
delegpt_from_message(struct dns_msg* msg, struct regional* region)
delegpt_from_message(struct dns_msg* msg, struct regional* region, int port)
{
struct ub_packed_rrset_key* ns_rrset = NULL;
struct delegpt* dp;
size_t i;
/* look for NS records in the authority section... */
ns_rrset = find_NS(msg->rep, msg->rep->an_numrrsets,
msg->rep->an_numrrsets+msg->rep->ns_numrrsets);
msg->rep->an_numrrsets+msg->rep->ns_numrrsets,
msg->qinfo.qclass);
/* In some cases (even legitimate, perfectly legal cases), the
* NS set for the "referral" might be in the answer section. */
if(!ns_rrset)
ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets);
ns_rrset = find_NS(msg->rep, 0, msg->rep->an_numrrsets,
msg->qinfo.qclass);
/* If there was no NS rrset in the authority section, then this
* wasn't a referral message. (It might not actually be a
@@ -436,7 +441,7 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
dp->has_parent_side_NS = 1; /* created from message */
if(!delegpt_set_name(dp, region, ns_rrset->rk.dname))
return NULL;
if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0))
if(!delegpt_rrset_add_ns(dp, region, ns_rrset, 0, port))
return NULL;
/* add glue, A and AAAA in answer and additional section */
@@ -447,10 +452,12 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
i < (msg->rep->an_numrrsets+msg->rep->ns_numrrsets))
continue;
if(ntohs(s->rk.type) == LDNS_RR_TYPE_A) {
if(ntohs(s->rk.type) == LDNS_RR_TYPE_A &&
ntohs(s->rk.rrset_class) == msg->qinfo.qclass) {
if(!delegpt_add_rrset_A(dp, region, s, 0, NULL))
return NULL;
} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA) {
} else if(ntohs(s->rk.type) == LDNS_RR_TYPE_AAAA &&
ntohs(s->rk.rrset_class) == msg->qinfo.qclass) {
if(!delegpt_add_rrset_AAAA(dp, region, s, 0, NULL))
return NULL;
}
@@ -460,7 +467,7 @@ delegpt_from_message(struct dns_msg* msg, struct regional* region)
int
delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
struct ub_packed_rrset_key* ns_rrset, uint8_t lame)
struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port)
{
struct packed_rrset_data* nsdata = (struct packed_rrset_data*)
ns_rrset->entry.data;
@@ -475,7 +482,7 @@ delegpt_rrset_add_ns(struct delegpt* dp, struct regional* region,
continue; /* bad format */
/* add rdata of NS (= wirefmt dname), skip rdatalen bytes */
if(!delegpt_add_ns(dp, region, nsdata->rr_data[i]+2, lame,
NULL, UNBOUND_DNS_PORT))
NULL, (port==-1?UNBOUND_DNS_PORT:port)))
return 0;
}
return 1;
@@ -534,7 +541,7 @@ delegpt_add_rrset(struct delegpt* dp, struct regional* region,
if(!rrset)
return 1;
if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_NS)
return delegpt_rrset_add_ns(dp, region, rrset, lame);
return delegpt_rrset_add_ns(dp, region, rrset, lame, -1);
else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_A)
return delegpt_add_rrset_A(dp, region, rrset, lame, additions);
else if(ntohs(rrset->rk.type) == LDNS_RR_TYPE_AAAA)
@@ -659,8 +666,6 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
free(ns);
return 0;
}
ns->next = dp->nslist;
dp->nslist = ns;
ns->cache_lookup_count = 0;
ns->resolved = 0;
ns->got4 = 0;
@@ -679,6 +684,8 @@ int delegpt_add_ns_mlc(struct delegpt* dp, uint8_t* name, uint8_t lame,
} else {
ns->tls_auth_name = NULL;
}
ns->next = dp->nslist;
dp->nslist = ns;
return 1;
}
@@ -704,11 +711,7 @@ int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
a = (struct delegpt_addr*)malloc(sizeof(struct delegpt_addr));
if(!a)
return 0;
a->next_target = dp->target_list;
dp->target_list = a;
a->next_result = 0;
a->next_usable = dp->usable_list;
dp->usable_list = a;
memcpy(&a->addr, addr, addrlen);
a->addrlen = addrlen;
a->attempts = 0;
@@ -724,6 +727,10 @@ int delegpt_add_addr_mlc(struct delegpt* dp, struct sockaddr_storage* addr,
} else {
a->tls_auth_name = NULL;
}
a->next_target = dp->target_list;
dp->target_list = a;
a->next_usable = dp->usable_list;
dp->usable_list = a;
return 1;
}
+4 -2
View File
@@ -221,10 +221,11 @@ int delegpt_add_ns(struct delegpt* dp, struct regional* regional,
* @param regional: where to allocate the info.
* @param ns_rrset: NS rrset.
* @param lame: rrset is lame, disprefer it.
* @param port: port or -1 if not set.
* @return 0 on alloc error.
*/
int delegpt_rrset_add_ns(struct delegpt* dp, struct regional* regional,
struct ub_packed_rrset_key* ns_rrset, uint8_t lame);
struct ub_packed_rrset_key* ns_rrset, uint8_t lame, int port);
/**
* Add target address to the delegation point.
@@ -365,11 +366,12 @@ size_t delegpt_count_targets(struct delegpt* dp);
*
* @param msg: the dns message, referral.
* @param regional: where to allocate delegation point.
* @param port: if not -1 specifies a port number.
* @return new delegation point or NULL on alloc error, or if the
* message was not appropriate.
*/
struct delegpt* delegpt_from_message(struct dns_msg* msg,
struct regional* regional);
struct regional* regional, int port);
/**
* Mark negative return in delegation point for specific nameserver.
+12
View File
@@ -132,6 +132,18 @@ donotq_apply_cfg(struct iter_donotq* dq, struct config_file* cfg)
if(cfg->do_ip6) {
if(!donotq_str_cfg(dq, "::1"))
return 0;
if(!donotq_str_cfg(dq, "::ffff:127.0.0.0/104"))
return 0;
}
/* RFC 1122 3.2.1.3 / RFC 6890 / RFC 4291 2.5.2: not valid as
* destination; on Linux these route to the local host. */
if(!donotq_str_cfg(dq, "0.0.0.0/8"))
return 0;
if(cfg->do_ip6) {
if(!donotq_str_cfg(dq, "::"))
return 0;
if(!donotq_str_cfg(dq, "::ffff:0:0/96"))
return 0;
}
}
addr_tree_init_parents(&dq->tree);
+5
View File
@@ -228,6 +228,11 @@ read_fwds_host(struct config_stub* s, struct delegpt* dp)
s->name, p->str);
return 0;
}
if(dname_subdomain_c(dname, dp->name)) {
log_warn("forward-host '%s' may have a circular "
"dependency on forward-zone '%s'",
p->str, s->name);
}
#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
if(tls_auth_name)
log_err("no name verification functionality in "
+5
View File
@@ -231,6 +231,11 @@ read_stubs_host(struct config_stub* s, struct delegpt* dp)
s->name, p->str);
return 0;
}
if(dname_subdomain_c(dname, dp->name)) {
log_warn("stub-host '%s' may have a circular "
"dependency on stub-zone '%s'",
p->str, s->name);
}
#if ! defined(HAVE_SSL_SET1_HOST) && ! defined(HAVE_X509_VERIFY_PARAM_SET1_HOST)
if(tls_auth_name)
log_err("no name verification functionality in "
+167 -1
View File
@@ -207,6 +207,168 @@ size_t priv_get_mem(struct iter_priv* priv)
return sizeof(*priv) + regional_get_mem(priv->region);
}
/**
* Check if svcparam ipv4hint contains a private address.
* @param priv: private address lookup struct.
* @param d: the data bytes.
* @param data_len: number of data bytes in the svcparam.
* @param addr: address to return the private address to log in to.
* It has space for IPv4 and IPv6 addresses.
* @param addrlen: length of the addr. Returns the correct size for the addr.
* @return true if the rdata contains a private address.
*/
static int svcb_ipv4hint_contains_priv_addr(struct iter_priv* priv,
uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr,
socklen_t* addrlen)
{
struct sockaddr_in sa;
*addrlen = (socklen_t)sizeof(struct sockaddr_in);
memset(&sa, 0, sizeof(struct sockaddr_in));
sa.sin_family = AF_INET;
sa.sin_port = (in_port_t)htons(UNBOUND_DNS_PORT);
while(data_len >= LDNS_IP4ADDRLEN) {
memmove(&sa.sin_addr, d, LDNS_IP4ADDRLEN);
memmove(addr, &sa, *addrlen);
if(priv_lookup_addr(priv, addr, *addrlen))
return 1;
d += LDNS_IP4ADDRLEN;
data_len -= LDNS_IP4ADDRLEN;
}
/* if data_len != 0 here, then the svcparam is malformed. */
return 0;
}
/**
* Check if svcparam ipv6hint contains a private address.
* @param priv: private address lookup struct.
* @param d: the data bytes.
* @param data_len: number of data bytes in the svcparam.
* @param addr: address to return the private address to log in to.
* It has space for IPv4 and IPv6 addresses.
* @param addrlen: length of the addr. Returns the correct size for the addr.
* @return true if the rdata contains a private address.
*/
static int svcb_ipv6hint_contains_priv_addr(struct iter_priv* priv,
uint8_t* d, uint16_t data_len, struct sockaddr_storage* addr,
socklen_t* addrlen)
{
struct sockaddr_in6 sa;
*addrlen = (socklen_t)sizeof(struct sockaddr_in6);
memset(&sa, 0, sizeof(struct sockaddr_in6));
sa.sin6_family = AF_INET6;
sa.sin6_port = (in_port_t)htons(UNBOUND_DNS_PORT);
while(data_len >= LDNS_IP6ADDRLEN) {
memmove(&sa.sin6_addr, d, LDNS_IP6ADDRLEN);
memmove(addr, &sa, *addrlen);
if(priv_lookup_addr(priv, addr, *addrlen))
return 1;
d += LDNS_IP6ADDRLEN;
data_len -= LDNS_IP6ADDRLEN;
}
/* if data_len != 0 here, then the svcparam is malformed. */
return 0;
}
/**
* Check if type SVCB and HTTPS rdata contains a private address.
* @param priv: private address lookup struct.
* @param pkt: the packet.
* @param rr: the rr with rdata to check.
* @param addr: address to return the private address to log in to.
* @param addrlen: length of the addr. Initially the total size, on
* return the correct size for the addr.
* @return true if the rdata contains a private address.
*/
static int svcb_rr_contains_priv_addr(struct iter_priv* priv,
sldns_buffer* pkt, struct rr_parse* rr, struct sockaddr_storage* addr,
socklen_t* addrlen)
{
uint8_t* d = rr->ttl_data;
uint16_t svcparamkey, data_len, rdatalen;
size_t oldpos, dname_len, dname_start, dname_compr_len;
d += 4; /* skip TTL */
rdatalen = sldns_read_uint16(d); /* read rdata length */
d += 2;
if(rdatalen < 2 /* priority */ + 1 /* 1 length target */)
return 0; /* malformed, too short */
d += 2; /* skip priority */
rdatalen -= 2;
oldpos = sldns_buffer_position(pkt);
sldns_buffer_set_position(pkt, (size_t)(d - sldns_buffer_begin(pkt)));
dname_start = sldns_buffer_position(pkt);
dname_len = pkt_dname_len(pkt);
dname_compr_len = sldns_buffer_position(pkt) - dname_start;
sldns_buffer_set_position(pkt, oldpos);
if(dname_len == 0)
return 0; /* dname malformed */
if(dname_compr_len > rdatalen)
return 0; /* malformed */
d += dname_compr_len; /* skip target */
rdatalen -= dname_compr_len;
while(rdatalen >= 4) {
svcparamkey = sldns_read_uint16(d);
data_len = sldns_read_uint16(d+2);
d += 4;
rdatalen -= 4;
/* verify that we have data_len data */
if(data_len > rdatalen) {
/* It is malformed, but if there are addresses
* in there it can be rejected. */
data_len = rdatalen;
}
if(!data_len)
continue; /* no data for the svcparamkey */
if(svcparamkey == SVCB_KEY_IPV4HINT) {
if(svcb_ipv4hint_contains_priv_addr(priv, d, data_len,
addr, addrlen))
return 1;
} else if(svcparamkey == SVCB_KEY_IPV6HINT) {
if(svcb_ipv6hint_contains_priv_addr(priv, d, data_len,
addr, addrlen))
return 1;
}
d += data_len;
rdatalen -= data_len;
}
/* If rdatalen != 0 here, then the svcb rdata is malformed. */
return 0;
}
/**
* Check if the SVCB and HTTPS rrset is bad.
* @param priv: private address lookup struct.
* @param pkt: the packet.
* @param rrset: the rrset to check.
* @return 1 if the entire rrset has to be removed. 0 if not.
* It removes RRs if they have private addresses, and log that.
*/
static int priv_svcb_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
struct rrset_parse* rrset)
{
struct rr_parse* rr, *prev = NULL;
struct sockaddr_storage addr;
socklen_t addrlen = (socklen_t)sizeof(addr);
for(rr = rrset->rr_first; rr; rr = rr->next) {
if(svcb_rr_contains_priv_addr(priv, pkt, rr, &addr,
&addrlen)) {
if(msgparse_rrset_remove_rr("sanitize: removing public name with private address", pkt, rrset, prev, rr, &addr, addrlen))
return 1;
continue;
}
prev = rr;
}
return 0;
}
int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
struct rrset_parse* rrset)
{
@@ -268,7 +430,11 @@ int priv_rrset_bad(struct iter_priv* priv, sldns_buffer* pkt,
}
prev = rr;
}
}
} else if(rrset->type == LDNS_RR_TYPE_SVCB ||
rrset->type == LDNS_RR_TYPE_HTTPS) {
if(priv_svcb_rrset_bad(priv, pkt, rrset))
return 1;
}
}
return 0;
}
+18 -7
View File
@@ -107,7 +107,7 @@ response_type_from_cache(struct dns_msg* msg,
enum response_type
response_type_from_server(int rdset,
struct dns_msg* msg, struct query_info* request, struct delegpt* dp,
int* empty_nodata_found)
int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral)
{
uint8_t* origzone = (uint8_t*)"\000"; /* the default */
struct ub_packed_rrset_key* s;
@@ -122,6 +122,10 @@ response_type_from_server(int rdset,
/* If the message is NXDOMAIN, then it answers the question. */
if(FLAGS_GET_RCODE(msg->rep->flags) == LDNS_RCODE_NXDOMAIN) {
if(msg->rep->an_numrrsets == 0 &&
msg->rep->ns_numrrsets == 0 &&
msg_lame_empty)
return RESPONSE_TYPE_LAME;
/* make sure its not recursive when we don't want it to */
if( (msg->rep->flags&BIT_RA) &&
!(msg->rep->flags&BIT_AA) && !rdset)
@@ -143,6 +147,10 @@ response_type_from_server(int rdset,
if(FLAGS_GET_RCODE(msg->rep->flags) != LDNS_RCODE_NOERROR)
return RESPONSE_TYPE_THROWAWAY;
if(msg->rep->an_numrrsets == 0 && msg->rep->ns_numrrsets == 0 &&
msg_lame_empty)
return RESPONSE_TYPE_LAME;
/* Note: TC bit has already been handled */
if(dp) {
@@ -249,13 +257,16 @@ response_type_from_server(int rdset,
* which gives ns==zone delegation from cache
* without AA bit as well, with nodata nosoa*/
/* real answer must be +AA and SOA RFC(2308),
* so this is wrong, and we SERVFAIL it if
* this is the only possible reply, if it
* is misdeployed the THROWAWAY makes us pick
* the next server from the selection */
if(msg->rep->an_numrrsets==0 &&
* this is picked up as lame_referral by the
* sanitize step, so it can spot if there
* was data in the answer section before
* removal. If such data is then removed we
* do not want to turn that answer into lame.
* But if it was not there, it can be lame. */
if(msg_lame_referral &&
msg->rep->an_numrrsets==0 &&
!(msg->rep->flags&BIT_AA) && !rdset)
return RESPONSE_TYPE_THROWAWAY;
return RESPONSE_TYPE_LAME;
return RESPONSE_TYPE_ANSWER;
}
/* If we are getting a referral upwards (or to
+5 -1
View File
@@ -120,10 +120,14 @@ enum response_type response_type_from_cache(struct dns_msg* msg,
* @param dp: The delegation point that was being queried
* when the response was returned.
* @param empty_nodata_found: flag to keep track of empty nodata detection.
* @param msg_lame_empty: The scrubber indicates that this empty message
* is lame, before it became empty.
* @param msg_lame_referral: returned true if the reply has a referral before
* scrub.
* @return the response type (CNAME or ANSWER).
*/
enum response_type response_type_from_server(int rdset,
struct dns_msg* msg, struct query_info* request, struct delegpt* dp,
int* empty_nodata_found);
int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral);
#endif /* ITERATOR_ITER_RESPTYPE_H */
+143 -11
View File
@@ -285,6 +285,17 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
return NULL;
memmove(cn->rr_first->ttl_data, rrset->rr_first->ttl_data,
sizeof(uint32_t)); /* RFC6672: synth CNAME TTL == DNAME TTL */
/* Apply cache TTL policy so DNAME and synthesized CNAME stay equal
* and respect cache-min-ttl/cache-max-ttl (same as rdata_copy path). */
if(!SERVE_ORIGINAL_TTL) {
uint32_t ttl = sldns_read_uint32(cn->rr_first->ttl_data);
time_t ttl_t = (time_t)ttl;
if(ttl_t < MIN_TTL) ttl_t = MIN_TTL;
if(ttl_t > MAX_TTL) ttl_t = MAX_TTL;
ttl = (uint32_t)ttl_t;
sldns_write_uint32(cn->rr_first->ttl_data, ttl);
sldns_write_uint32(rrset->rr_first->ttl_data, ttl);
}
sldns_write_uint16(cn->rr_first->ttl_data+4, aliaslen);
memmove(cn->rr_first->ttl_data+6, alias, aliaslen);
cn->rr_first->size = sizeof(uint16_t)+aliaslen;
@@ -305,6 +316,20 @@ synth_cname_rrset(uint8_t** sname, size_t* snamelen, uint8_t* alias,
return cn;
}
/** Check if the packet has type NS in answer or authority section */
static int
pkt_contains_ns(struct msg_parse* msg)
{
struct rrset_parse* rrset;
for(rrset = msg->rrset_first; rrset; rrset = rrset->rrset_all_next) {
if(rrset->type == LDNS_RR_TYPE_NS &&
(rrset->section == LDNS_SECTION_ANSWER ||
rrset->section == LDNS_SECTION_AUTHORITY))
return 1;
}
return 0;
}
/** check if DNAME applies to a name */
static int
pkt_strict_sub(sldns_buffer* pkt, uint8_t* sname, uint8_t* dr)
@@ -383,6 +408,8 @@ shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
struct rr_parse* rr = rrset->rr_first, *prev = NULL;
if(!rr)
return;
if(count < 1)
return; /* cannot leave a still-linked rrset_parse with rr_count == 0 */
for(i=0; i<count; i++) {
prev = rr;
rr = rr->next;
@@ -408,6 +435,43 @@ shorten_rrset(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
else rrset->rr_first = NULL;
}
/** Shorten RRSIGs list */
static void
shorten_rrsig(sldns_buffer* pkt, struct rrset_parse* rrset, int count)
{
/* The too large list of RRSIGs on the RRset is shortened.
* This is so that too large content does not overwhelm the cache.
* The validator does not validate more than a max number of
* RRSIGs as well. */
int i;
struct rr_parse* rr = rrset->rrsig_first, *prev = NULL;
if(!rr)
return;
for(i=0; i<count; i++) {
prev = rr;
rr = rr->next;
if(!rr)
return; /* The RRSIG list is already short. */
}
if(verbosity >= VERB_QUERY
&& rrset->dname_len <= LDNS_MAX_DOMAINLEN) {
uint8_t buf[LDNS_MAX_DOMAINLEN+1];
dname_pkt_copy(pkt, buf, rrset->dname);
log_nametypeclass(VERB_QUERY, "normalize: shorten RRSIGs:",
buf, rrset->type, ntohs(rrset->rrset_class));
}
/* remove further rrsigs */
rrset->rrsig_last = prev;
rrset->rrsig_count = count;
while(rr) {
rrset->size -= rr->size;
rr = rr->next;
}
if(rrset->rrsig_last)
rrset->rrsig_last->next = NULL;
else rrset->rrsig_first = NULL;
}
/**
* This routine normalizes a response. This includes removing "irrelevant"
* records from the answer and additional sections and (re)synthesizing
@@ -430,6 +494,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
size_t snamelen = qinfo->qname_len;
struct rrset_parse* rrset, *prev, *nsset=NULL;
int cname_length = 0; /* number of CNAMEs, or DNAMEs */
int has_answer = 0; /* if answer section contains nonCNAME,nonDNAME */
if(FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NOERROR &&
FLAGS_GET_RCODE(msg->flags) != LDNS_RCODE_NXDOMAIN &&
@@ -445,6 +510,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
prev = NULL;
rrset = msg->rrset_first;
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
if(cname_length > env->cfg->iter_scrub_cname) {
/* Too many CNAMEs, or DNAMEs, from the authority
* server, scrub down the length to something
@@ -455,8 +522,9 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
pkt, msg, prev, &rrset);
continue;
}
if(rrset->type == LDNS_RR_TYPE_DNAME &&
pkt_strict_sub(pkt, sname, rrset->dname)) {
if(rrset->type == LDNS_RR_TYPE_DNAME &&
pkt_strict_sub(pkt, sname, rrset->dname) &&
pkt_sub(pkt, rrset->dname, zonename)) {
/* check if next rrset is correct CNAME. else,
* synthesize a CNAME */
struct rrset_parse* nx = rrset->rrset_all_next;
@@ -468,6 +536,11 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
(unsigned)rrset->rr_count);
return 0;
}
if(has_answer) {
remove_rrset("normalize: removing DNAME redirection after answer:",
pkt, msg, prev, &rrset);
continue;
}
if(!synth_cname(sname, snamelen, rrset, alias,
&aliaslen, pkt)) {
verbose(VERB_ALGO, "synthesized CNAME "
@@ -502,8 +575,6 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
log_err("out of memory synthesizing CNAME");
return 0;
}
/* FIXME: resolve the conflict between synthesized
* CNAME ttls and the cache. */
rrset = nx;
continue;
@@ -520,12 +591,18 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
if(rrset->type == LDNS_RR_TYPE_CNAME) {
struct rrset_parse* nx = rrset->rrset_all_next;
uint8_t* oldsname = sname;
if(has_answer) {
remove_rrset("normalize: removing redirection after answer:",
pkt, msg, prev, &rrset);
continue;
}
cname_length++;
/* see if the next one is a DNAME, if so, swap them */
if(nx && nx->section == LDNS_SECTION_ANSWER &&
nx->type == LDNS_RR_TYPE_DNAME &&
nx->rr_count == 1 &&
pkt_strict_sub(pkt, sname, nx->dname)) {
pkt_strict_sub(pkt, sname, nx->dname) &&
pkt_sub(pkt, nx->dname, zonename)) {
/* there is a DNAME after this CNAME, it
* is in the ANSWER section, and the DNAME
* applies to the name we cover */
@@ -597,6 +674,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
* will be removed by sanitize, so no additional for them */
if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) == 0)
mark_additional_rrset(pkt, msg, rrset);
has_answer = 1;
prev = rrset;
rrset = rrset->rrset_all_next;
@@ -620,6 +698,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
"RRset:", pkt, msg, prev, &rrset);
continue;
}
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
/* only one NS set allowed in authority section */
if(rrset->type==LDNS_RR_TYPE_NS) {
/* NS set must be pertinent to the query */
@@ -680,6 +760,11 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
"RRset:", pkt, msg, prev, &rrset);
continue;
}
if(ntohs(rrset->rrset_class) != qinfo->qclass) {
remove_rrset("normalize: removing other class "
"RRset:", pkt, msg, prev, &rrset);
continue;
}
if(nsset == NULL) {
nsset = rrset;
} else {
@@ -725,7 +810,13 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
rrset->rrset_all_next = NULL;
return 1;
}
mark_additional_rrset(pkt, msg, rrset);
/* Only mark glue as allowed for type NS in the authority
* section. Other RR types do not get glue for them, it
* is allowed from the answer section, but not authority
* so that a message can not have address records cached
* as a side effect to the query. */
if(rrset->type==LDNS_RR_TYPE_NS)
mark_additional_rrset(pkt, msg, rrset);
prev = rrset;
rrset = rrset->rrset_all_next;
}
@@ -762,6 +853,8 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
"RRset:", pkt, msg, prev, &rrset);
continue;
}
if((int)rrset->rrsig_count > env->cfg->iter_scrub_rrsig)
shorten_rrsig(pkt, rrset, env->cfg->iter_scrub_rrsig);
prev = rrset;
rrset = rrset->rrset_all_next;
}
@@ -908,12 +1001,20 @@ scrub_sanitize_rr_length(sldns_buffer* pkt, struct msg_parse* msg,
* @param env: module environment with config and cache.
* @param ie: iterator environment with private address data.
* @param qstate: for setting errinf for EDE error messages.
* @param pkt_before_NS: if the packet had type NS before scrub. If that
* is removed now, that indicates this may have been lame.
* @param msg_lame_empty: returned true if the empty packet is lame.
* @param msg_lame_referral: returned true if the reply has a referral before
* scrub.
* @param rdset: if RD bit was sent in query sent by unbound.
* @return 0 on error.
*/
static int
scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
struct query_info* qinfo, uint8_t* zonename, struct module_env* env,
struct iter_env* ie, struct module_qstate* qstate)
struct iter_env* ie, struct module_qstate* qstate,
int pkt_before_NS, int* msg_lame_empty, int* msg_lame_referral,
int rdset)
{
int del_addi = 0; /* if additional-holding rrsets are deleted, we
do not trust the normalized additional-A-AAAA any more */
@@ -972,8 +1073,10 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
}
/* remove private addresses */
if( (rrset->type == LDNS_RR_TYPE_A ||
rrset->type == LDNS_RR_TYPE_AAAA)) {
if(rrset->type == LDNS_RR_TYPE_A ||
rrset->type == LDNS_RR_TYPE_AAAA ||
rrset->type == LDNS_RR_TYPE_SVCB ||
rrset->type == LDNS_RR_TYPE_HTTPS) {
/* do not set servfail since this leads to too
* many drops of other people using rfc1918 space */
@@ -1068,6 +1171,21 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
prev = rrset;
rrset = rrset->rrset_all_next;
}
/* If the packet is empty now, but it was not before. And there
* was type NS in authority, then that indicates the answer is lame. */
if(msg->rrset_first == NULL && pkt_before_NS) {
*msg_lame_empty = 1;
verbose(VERB_ALGO, "sanitize: empty message had referral to NS before, marked as lame");
} else if(pkt_before_NS && msg->an_rrsets==0 &&
!(msg->flags&BIT_AA) && !rdset) {
/* If the packet is now a referral, not really a nodata,
* then if it was also with an empty answer section before,
* it is also lame. */
*msg_lame_referral = 1;
verbose(VERB_ALGO, "sanitize: message has referral not answer, marked as lame");
}
return 1;
}
@@ -1075,11 +1193,15 @@ int
scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
struct query_info* qinfo, uint8_t* zonename, struct regional* region,
struct module_env* env, struct module_qstate* qstate,
struct iter_env* ie)
struct iter_env* ie, int* msg_lame_empty, int* msg_lame_referral,
int rdset)
{
int pkt_before_NS;
/* basic sanity checks */
log_nametypeclass(VERB_ALGO, "scrub for", zonename, LDNS_RR_TYPE_NS,
qinfo->qclass);
*msg_lame_empty = 0;
*msg_lame_referral = 0;
if(msg->qdcount > 1)
return 0;
if( !(msg->flags&BIT_QR) )
@@ -1104,11 +1226,21 @@ scrub_message(sldns_buffer* pkt, struct msg_parse* msg,
return 0;
}
/* If the packet contains type NS in authority before scrub,
* like a self referral. With the answer section empty, it
* was not AA, the query was not sent with RD, with NS in auth,
* and no SOA in auth. For a negative answer, type SOA is present.
* This detects certain lameness if after has removed that. */
pkt_before_NS = msg->an_rrsets == 0 &&
!(msg->flags&BIT_AA) && !rdset &&
pkt_contains_ns(msg) && !soa_in_auth(msg);
/* normalize the response, this cleans up the additional. */
if(!scrub_normalize(pkt, msg, qinfo, region, env, zonename))
return 0;
/* delete all out-of-zone information */
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate))
if(!scrub_sanitize(pkt, msg, qinfo, zonename, env, ie, qstate,
pkt_before_NS, msg_lame_empty, msg_lame_referral, rdset))
return 0;
return 1;
}
+6 -1
View File
@@ -62,11 +62,16 @@ struct module_qstate;
* @param env: module environment with config settings and cache.
* @param qstate: for setting errinf for EDE error messages.
* @param ie: iterator module environment data.
* @param msg_lame_empty: returned true if the empty packet is lame.
* @param msg_lame_referral: returned true if the reply has a referral before
* scrub.
* @param rdset: if RD bit was sent in query sent by unbound.
* @return: false if the message is total waste. true if scrubbed with success.
*/
int scrub_message(struct sldns_buffer* pkt, struct msg_parse* msg,
struct query_info* qinfo, uint8_t* zonename, struct regional* regional,
struct module_env* env, struct module_qstate* qstate,
struct iter_env* ie);
struct iter_env* ie, int* msg_lame_empty, int* msg_lame_referral,
int rdset);
#endif /* ITERATOR_ITER_SCRUB_H */
+56 -5
View File
@@ -253,7 +253,9 @@ iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg)
return 1;
}
/** filter out unsuitable targets
/** filter out unsuitable targets.
* Applies NAT64 if needed as well by replacing the IPv4 with the synthesized
* IPv6 address.
* @param iter_env: iterator environment with ipv6-support flag.
* @param env: module environment with infra cache.
* @param name: zone name
@@ -306,9 +308,30 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
if(a->bogus)
return -1; /* address of server is bogus */
if(donotq_lookup(iter_env->donotq, &a->addr, a->addrlen)) {
log_addr(VERB_ALGO, "skip addr on the donotquery list",
&a->addr, a->addrlen);
return -1; /* server is on the donotquery list */
if(iter_env->nat64.use_nat64 &&
addr_is_ip6(&a->addr, a->addrlen) &&
a->addrlen == iter_env->nat64.nat64_prefix_addrlen &&
addr_in_common(&a->addr, 128,
&iter_env->nat64.nat64_prefix_addr,
iter_env->nat64.nat64_prefix_net,
iter_env->nat64.nat64_prefix_addrlen) ==
iter_env->nat64.nat64_prefix_net) {
/* The NAT64 is enabled, and address is IPv6, it is
* in the NAT64 prefix. It is allowed.
* So that in an IPv6-only cluster without internet
* access, that makes the NAT64 translation continue
* to work. The NAT64 prefix is allowed. */
/* Otherwise, after a timeout, the already NAT64
* translated address would be treated differently,
* and that causes confusion. */
log_addr(VERB_ALGO, "the addr is on the donotquery "
"list, but allowed because it is NAT64",
&a->addr, a->addrlen);
} else {
log_addr(VERB_ALGO, "skip addr on the donotquery list",
&a->addr, a->addrlen);
return -1; /* server is on the donotquery list */
}
}
if(!iter_env->supports_ipv6 && addr_is_ip6(&a->addr, a->addrlen)) {
return -1; /* there is no ip6 available */
@@ -317,6 +340,20 @@ iter_filter_unsuitable(struct iter_env* iter_env, struct module_env* env,
!addr_is_ip6(&a->addr, a->addrlen)) {
return -1; /* there is no ip4 available */
}
if(iter_env->nat64.use_nat64 && !addr_is_ip6(&a->addr, a->addrlen)) {
struct sockaddr_storage real_addr;
socklen_t real_addrlen;
addr_to_nat64(&a->addr, &iter_env->nat64.nat64_prefix_addr,
iter_env->nat64.nat64_prefix_addrlen,
iter_env->nat64.nat64_prefix_net,
&real_addr, &real_addrlen);
log_name_addr(VERB_QUERY, "NAT64 apply: from: ",
name, &a->addr, a->addrlen);
log_name_addr(VERB_QUERY, "NAT64 apply: to: ",
name, &real_addr, real_addrlen);
a->addr = real_addr;
a->addrlen = real_addrlen;
}
/* check lameness - need zone , class info */
if(infra_get_lame_rtt(env->infra_cache, &a->addr, a->addrlen,
name, namelen, qtype, &lame, &dnsseclame, &reclame,
@@ -1276,7 +1313,8 @@ iter_lookup_parent_NS_from_cache(struct module_env* env, struct delegpt* dp,
log_rrset_key(VERB_ALGO, "found parent-side NS in cache", akey);
dp->has_parent_side_NS = 1;
/* and mark the new names as lame */
if(!delegpt_rrset_add_ns(dp, region, akey, 1)) {
if(!delegpt_rrset_add_ns(dp, region, akey, 1,
deleg_port_number(env))) {
lock_rw_unlock(&akey->entry.lock);
return 0;
}
@@ -1511,6 +1549,11 @@ iter_stub_fwd_no_cache(struct module_qstate *qstate, struct query_info *qinf,
struct delegpt *dp;
int nolock = 1;
log_assert((retdpname && retdpnamelen
&& dpname_storage && dpname_storage_len > 0) ||
(retdpname == NULL && retdpnamelen == NULL
&& dpname_storage == NULL && dpname_storage_len == 0));
/* Check for stub. */
/* Lock both forwards and hints for atomic read. */
lock_rw_rdlock(&qstate->env->fwds->lock);
@@ -1661,3 +1704,11 @@ iter_make_minimal(struct reply_info* rep)
rep->ar_numrrsets = 0;
rep->rrset_count -= rem;
}
int
deleg_port_number(struct module_env* env)
{
if(env->cfg->ssl_upstream)
return env->cfg->ssl_port;
return -1;
}
+4
View File
@@ -84,6 +84,7 @@ int iter_apply_cfg(struct iter_env* iter_env, struct config_file* cfg);
/**
* Select a valid, nice target to send query to.
* Sorting and removing unsuitable targets is combined.
* Adds records to the infra cache if not already there.
*
* @param iter_env: iterator module global state, with ip6 enabled and
* do-not-query-addresses.
@@ -482,4 +483,7 @@ void limit_nsec_ttl(struct dns_msg* msg);
*/
void iter_make_minimal(struct reply_info* rep);
/** See if we need a different port number */
int deleg_port_number(struct module_env* env);
#endif /* ITERATOR_ITER_UTILS_H */
+134 -60
View File
@@ -81,7 +81,8 @@ int BLACKLIST_PENALTY = (120000*4);
/** Timeout when only a single probe query per IP is allowed. */
int PROBE_MAXRTO = PROBE_MAXRTO_DEFAULT; /* in msec */
static void target_count_increase_nx(struct iter_qstate* iq, int num);
static void target_count_increase_nx(struct module_qstate* qstate,
struct iter_qstate* iq, int num);
int
iter_init(struct module_env* env, int id)
@@ -250,7 +251,7 @@ error_supers(struct module_qstate* qstate, int id, struct module_qstate* super)
if((dpns->got4 == 2 || (!ie->supports_ipv4 && !ie->nat64.use_nat64)) &&
(dpns->got6 == 2 || !ie->supports_ipv6)) {
dpns->resolved = 1; /* mark as failed */
target_count_increase_nx(super_iq, 1);
target_count_increase_nx(super, super_iq, 1);
}
}
if(qstate->qinfo.qtype == LDNS_RR_TYPE_NS) {
@@ -297,6 +298,7 @@ error_response_cache(struct module_qstate* qstate, int id, int rcode)
struct reply_info err;
struct msgreply_entry* msg;
if(qstate->no_cache_store) {
qstate->error_response_cache = 1;
return error_response(qstate, id, rcode);
}
if(qstate->prefetch_leeway > NORR_TTL) {
@@ -733,7 +735,7 @@ is_caps_whitelisted(struct iter_env* ie, struct iter_qstate* iq)
* created for the parent query.
*/
static void
target_count_create(struct iter_qstate* iq)
target_count_create(struct module_qstate* qstate, struct iter_qstate* iq)
{
if(!iq->target_count) {
iq->target_count = (int*)calloc(TARGET_COUNT_MAX, sizeof(int));
@@ -741,33 +743,57 @@ target_count_create(struct iter_qstate* iq)
if(iq->target_count) {
iq->target_count[TARGET_COUNT_REF] = 1;
iq->nxns_dp = (uint8_t**)calloc(1, sizeof(uint8_t*));
/* continue global quota from where it was. */
if(qstate->global_quota_reached >
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA])
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] =
qstate->global_quota_reached;
}
}
}
static void
target_count_increase(struct iter_qstate* iq, int num)
target_count_store(struct module_qstate* qstate, struct iter_qstate* iq)
{
target_count_create(iq);
if(iq->target_count) {
/* By storing the global quota counter, it stays
* there to be picked up if the module is restarted,
* eg. due to a validator retry, and then the
* target_count_create routine picks it up. */
if(iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] >
qstate->global_quota_reached)
qstate->global_quota_reached =
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA];
}
}
static void
target_count_increase(struct module_qstate* qstate,
struct iter_qstate* iq, int num)
{
target_count_create(qstate, iq);
if(iq->target_count)
iq->target_count[TARGET_COUNT_QUERIES] += num;
iq->dp_target_count++;
}
static void
target_count_increase_nx(struct iter_qstate* iq, int num)
target_count_increase_nx(struct module_qstate* qstate,
struct iter_qstate* iq, int num)
{
target_count_create(iq);
target_count_create(qstate, iq);
if(iq->target_count)
iq->target_count[TARGET_COUNT_NX] += num;
}
static void
target_count_increase_global_quota(struct iter_qstate* iq, int num)
target_count_increase_global_quota(struct module_qstate* qstate,
struct iter_qstate* iq, int num)
{
target_count_create(iq);
target_count_create(qstate, iq);
if(iq->target_count)
iq->target_count[TARGET_COUNT_GLOBAL_QUOTA] += num;
target_count_store(qstate, iq);
}
/**
@@ -829,7 +855,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
struct mesh_state* sub = NULL;
fptr_ok(fptr_whitelist_modenv_add_sub(
qstate->env->add_sub));
if(!(*qstate->env->add_sub)(qstate, &qinf,
if(!(*qstate->env->add_sub)(qstate, &qinf, NULL,
qflags, prime, valrec, &subq, &sub)){
return 0;
}
@@ -838,8 +864,8 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
/* attach subquery, lookup existing or make a new one */
fptr_ok(fptr_whitelist_modenv_attach_sub(
qstate->env->attach_sub));
if(!(*qstate->env->attach_sub)(qstate, &qinf, qflags, prime,
valrec, &subq)) {
if(!(*qstate->env->attach_sub)(qstate, &qinf, NULL, qflags,
prime, valrec, &subq)) {
return 0;
}
}
@@ -860,7 +886,7 @@ generate_sub_request(uint8_t* qname, size_t qnamelen, uint16_t qtype,
subiq = (struct iter_qstate*)subq->minfo[id];
memset(subiq, 0, sizeof(*subiq));
subiq->num_target_queries = 0;
target_count_create(iq);
target_count_create(qstate, iq);
subiq->target_count = iq->target_count;
if(iq->target_count) {
iq->target_count[TARGET_COUNT_REF] ++; /* extra reference */
@@ -1485,6 +1511,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
verbose(VERB_ALGO, "no-cache set, going to the network");
qstate->no_cache_lookup = 1;
qstate->no_cache_store = 1;
qstate->fwd_stub_no_cache = 1;
msg = NULL;
} else if(qstate->blacklist) {
/* if cache, or anything else, was blacklisted then
@@ -1504,7 +1531,7 @@ processInitRequest(struct module_qstate* qstate, struct iter_qstate* iq,
msg = val_neg_getmsg(qstate->env->neg_cache, &iq->qchase,
qstate->region, qstate->env->rrset_cache,
qstate->env->scratch_buffer,
*qstate->env->now, 1/*add SOA*/, NULL,
*qstate->env->now, 1/*add SOA*/, dpname,
qstate->env->cfg);
}
/* item taken from cache does not match our query name, thus
@@ -2233,7 +2260,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += qs;
target_count_increase(iq, qs);
target_count_increase(qstate, iq, qs);
if(qs != 0) {
qstate->ext_state[id] = module_wait_subquery;
return 0; /* and wait for them */
@@ -2289,7 +2316,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
* lookups at a time. */
verbose(VERB_ALGO, "try parent-side glue lookup");
iq->num_target_queries += query_count;
target_count_increase(iq, query_count);
target_count_increase(qstate, iq, query_count);
qstate->ext_state[id] = module_wait_subquery;
return 0;
}
@@ -2309,7 +2336,7 @@ processLastResort(struct module_qstate* qstate, struct iter_qstate* iq,
if(query_count != 0) { /* suspend to await results */
verbose(VERB_ALGO, "try parent-side glue lookup");
iq->num_target_queries += query_count;
target_count_increase(iq, query_count);
target_count_increase(qstate, iq, query_count);
qstate->ext_state[id] = module_wait_subquery;
return 0;
}
@@ -2365,6 +2392,12 @@ processDSNSFind(struct module_qstate* qstate, struct iter_qstate* iq, int id)
/* go up one (more) step, until we hit the dp, if so, end */
dname_remove_label(&iq->dsns_point, &iq->dsns_point_len);
if(++iq->dsns_count > MAX_DSNS_FIND_COUNT) {
verbose(VERB_QUERY, "DS NS search exceeded %d labels",
MAX_DSNS_FIND_COUNT);
errinf(qstate, "DS NS search exceeded label limit");
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
if(query_dname_compare(iq->dsns_point, iq->dp->name) == 0) {
/* there was no inbetween nameserver, use the old delegation
* point again. And this time, because dsns_point is nonNULL
@@ -2436,8 +2469,6 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
int tf_policy;
struct delegpt_addr* target;
struct outbound_entry* outq;
struct sockaddr_storage real_addr;
socklen_t real_addrlen;
int auth_fallback = 0;
uint8_t* qout_orig = NULL;
size_t qout_orig_len = 0;
@@ -2789,7 +2820,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += extra;
target_count_increase(iq, extra);
target_count_increase(qstate, iq, extra);
if(iq->num_target_queries > 0) {
/* wait to get all targets, we want to try em */
verbose(VERB_ALGO, "wait for all targets for fallback");
@@ -2840,7 +2871,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
/* errors ignored, these targets are not strictly necessary for
* this result, we do not have to reply with SERVFAIL */
iq->num_target_queries += extra;
target_count_increase(iq, extra);
target_count_increase(qstate, iq, extra);
}
/* Add the current set of unused targets to our queue. */
@@ -2963,7 +2994,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
LDNS_RCODE_SERVFAIL);
}
iq->num_target_queries += qs;
target_count_increase(iq, qs);
target_count_increase(qstate, iq, qs);
}
/* Since a target query might have been made, we
* need to check again. */
@@ -3023,7 +3054,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
* this result, we do not have to reply with SERVFAIL */
if(extra > 0) {
iq->num_target_queries += extra;
target_count_increase(iq, extra);
target_count_increase(qstate, iq, extra);
check_waiting_queries(iq, qstate, id);
/* undo qname minimise step because we'll get back here
* to do it again */
@@ -3036,7 +3067,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
}
}
target_count_increase_global_quota(iq, 1);
target_count_increase_global_quota(qstate, iq, 1);
if(iq->target_count && iq->target_count[TARGET_COUNT_GLOBAL_QUOTA]
> MAX_GLOBAL_QUOTA) {
char s[LDNS_MAX_DOMAINLEN];
@@ -3049,7 +3080,9 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
/* 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);
sq_check_ratelimit = ((!(iq->chase_flags & BIT_RD) &&
!iq->ratelimit_ok));
iq->ratelimit_incremented = 0;
/* We have a valid target. */
if(verbosity >= VERB_QUERY) {
log_query_info(VERB_QUERY, "sending query:", &iq->qinfo_out);
@@ -3060,17 +3093,6 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
iq->dnssec_lame_query?" but lame_query anyway": "");
}
real_addr = target->addr;
real_addrlen = target->addrlen;
if(ie->nat64.use_nat64 && target->addr.ss_family == AF_INET) {
addr_to_nat64(&target->addr, &ie->nat64.nat64_prefix_addr,
ie->nat64.nat64_prefix_addrlen, ie->nat64.nat64_prefix_net,
&real_addr, &real_addrlen);
log_name_addr(VERB_QUERY, "applied NAT64:",
iq->dp->name, &real_addr, real_addrlen);
}
fptr_ok(fptr_whitelist_modenv_send_query(qstate->env->send_query));
outq = (*qstate->env->send_query)(&iq->qinfo_out,
iq->chase_flags | (iq->chase_to_rd?BIT_RD:0),
@@ -3082,11 +3104,12 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
!qstate->blacklist&&(!iter_qname_indicates_dnssec(qstate->env,
&iq->qinfo_out)||target->attempts==1)?0:BIT_CD),
iq->dnssec_expected, iq->caps_fallback || is_caps_whitelisted(
ie, iq), sq_check_ratelimit, &real_addr, real_addrlen,
ie, iq), sq_check_ratelimit, &target->addr, target->addrlen,
iq->dp->name, iq->dp->namelen,
(iq->dp->tcp_upstream || qstate->env->cfg->tcp_upstream),
(iq->dp->ssl_upstream || qstate->env->cfg->ssl_upstream),
target->tls_auth_name, qstate, &sq_was_ratelimited);
target->tls_auth_name, qstate, &sq_was_ratelimited,
&iq->ratelimit_incremented);
if(!outq) {
if(sq_was_ratelimited) {
lock_basic_lock(&ie->queries_ratelimit_lock);
@@ -3099,7 +3122,7 @@ processQueryTargets(struct module_qstate* qstate, struct iter_qstate* iq,
return error_response_cache(qstate, id, LDNS_RCODE_SERVFAIL);
}
log_addr(VERB_QUERY, "error sending query to auth server",
&real_addr, real_addrlen);
&target->addr, target->addrlen);
if(qstate->env->cfg->qname_minimisation)
iq->minimisation_state = SKIP_MINIMISE_STATE;
return next_state(iq, QUERYTARGETS_STATE);
@@ -3124,7 +3147,6 @@ find_NS(struct reply_info* rep, size_t from, size_t to)
return NULL;
}
/**
* Process the query response. All queries end up at this state first. This
* process generally consists of analyzing the response and routing the
@@ -3166,7 +3188,8 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
orig_empty_nodata_found = iq->empty_nodata_found;
type = response_type_from_server(
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found);
iq->response, &iq->qinfo_out, iq->dp, &iq->empty_nodata_found,
iq->msg_lame_empty, iq->msg_lame_referral);
iq->chase_to_rd = 0;
/* remove TC flag, if this is erroneously set by TCP upstream */
iq->response->rep->flags &= ~BIT_TC;
@@ -3236,8 +3259,19 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
} else iter_scrub_ds(iq->response, NULL, NULL);
if(type == RESPONSE_TYPE_THROWAWAY &&
FLAGS_GET_RCODE(iq->response->rep->flags) == LDNS_RCODE_YXDOMAIN) {
/* YXDOMAIN is a permanent error, no need to retry */
type = RESPONSE_TYPE_ANSWER;
/* YXDOMAIN is a permanent error for DNAME expansion overflow
* (RFC 6672 Section 2.2). Only accept if the response
* contains a DNAME record in the answer section; otherwise
* treat as invalid, to make sure the authoritative answer
* make sense. */
size_t i;
for(i=0; i<iq->response->rep->an_numrrsets; i++) {
if(ntohs(iq->response->rep->rrsets[i]->rk.type)
== LDNS_RR_TYPE_DNAME) {
type = RESPONSE_TYPE_ANSWER;
break;
}
}
}
if(type == RESPONSE_TYPE_CNAME)
origtypecname = 1;
@@ -3433,7 +3467,14 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
iq->deleg_msg = iq->response;
/* Keep current delegation point for label comparison */
old_dp = iq->dp;
iq->dp = delegpt_from_message(iq->response, qstate->region);
/* A referral reply is "pleasant", refund the
* parent dp's rate charge before descending to the child. */
if(iq->ratelimit_incremented)
infra_ratelimit_dec(qstate->env->infra_cache,
old_dp->name, old_dp->namelen,
*qstate->env->now);
iq->dp = delegpt_from_message(iq->response, qstate->region,
deleg_port_number(qstate->env));
if (qstate->env->cfg->qname_minimisation)
iq->minimisation_state = INIT_MINIMISE_STATE;
if(!iq->dp) {
@@ -3616,7 +3657,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
return next_state(iq, INIT_REQUEST_STATE);
} else if(type == RESPONSE_TYPE_LAME) {
/* Cache the LAMEness. */
verbose(VERB_DETAIL, "query response was %sLAME",
verbose(VERB_DETAIL, "query response was categorized as %sLAME",
dnsseclame?"DNSSEC ":"");
if(!dname_subdomain_c(iq->qchase.qname, iq->dp->name)) {
log_err("mark lame: mismatch in qname and dpname");
@@ -3655,7 +3696,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
* In this case, the event is just sent directly back to
* the QUERYTARGETS_STATE without resetting anything,
* because, clearly, the next target must be tried. */
verbose(VERB_DETAIL, "query response was THROWAWAY");
verbose(VERB_DETAIL, "query response was categorized as THROWAWAY");
} else {
log_warn("A query response came back with an unknown type: %d",
(int)type);
@@ -3710,7 +3751,8 @@ prime_supers(struct module_qstate* qstate, int id, struct module_qstate* forq)
log_assert(qstate->is_priming || foriq->wait_priming_stub);
log_assert(qstate->return_rcode == LDNS_RCODE_NOERROR);
/* Convert our response to a delegation point */
dp = delegpt_from_message(qstate->return_msg, forq->region);
dp = delegpt_from_message(qstate->return_msg, forq->region,
deleg_port_number(forq->env));
if(!dp) {
/* if there is no convertible delegation point, then
* the ANSWER type was (presumably) a negative answer. */
@@ -3761,7 +3803,8 @@ processPrimeResponse(struct module_qstate* qstate, int id)
iq->response->rep->flags &= ~(BIT_RD|BIT_RA); /* ignore rec-lame */
type = response_type_from_server(
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
iq->response, &iq->qchase, iq->dp, NULL);
iq->response, &iq->qchase, iq->dp, NULL, iq->msg_lame_empty,
iq->msg_lame_referral);
if(type == RESPONSE_TYPE_ANSWER) {
qstate->return_rcode = LDNS_RCODE_NOERROR;
qstate->return_msg = iq->response;
@@ -3880,7 +3923,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
/* no new addresses, increase the nxns counter, like
* this could be a list of wildcards with no new
* addresses */
target_count_increase_nx(foriq, 1);
target_count_increase_nx(qstate, foriq, 1);
}
verbose(VERB_ALGO, "added target response");
delegpt_log(VERB_ALGO, foriq->dp);
@@ -3892,7 +3935,7 @@ processTargetResponse(struct module_qstate* qstate, int id,
dpns->resolved = 1; /* fail the target */
/* do not count cached answers */
if(qstate->reply_origin && qstate->reply_origin->len != 0) {
target_count_increase_nx(foriq, 1);
target_count_increase_nx(qstate, foriq, 1);
}
}
}
@@ -3925,7 +3968,8 @@ processDSNSResponse(struct module_qstate* qstate, int id,
/* else, store as DP and continue at querytargets */
foriq->state = QUERYTARGETS_STATE;
foriq->dp = delegpt_from_message(qstate->return_msg, forq->region);
foriq->dp = delegpt_from_message(qstate->return_msg, forq->region,
deleg_port_number(forq->env));
if(!foriq->dp) {
log_err("out of memory in dsns dp alloc");
errinf(qstate, "malloc failure, in DS search");
@@ -3974,7 +4018,7 @@ processClassResponse(struct module_qstate* qstate, int id,
/* if there are records, copy RCODE */
/* lower sec_state if this message is lower */
if(from->rep->rrset_count != 0) {
size_t n = from->rep->rrset_count+to->rep->rrset_count;
size_t i, n = from->rep->rrset_count+to->rep->rrset_count;
struct ub_packed_rrset_key** dest, **d;
/* copy appropriate rcode */
to->rep->flags = from->rep->flags;
@@ -3996,24 +4040,49 @@ processClassResponse(struct module_qstate* qstate, int id,
memcpy(dest, to->rep->rrsets, to->rep->an_numrrsets
* sizeof(dest[0]));
dest += to->rep->an_numrrsets;
memcpy(dest, from->rep->rrsets, from->rep->an_numrrsets
* sizeof(dest[0]));
for(i=0; i<from->rep->an_numrrsets; i++) {
dest[i] = packed_rrset_copy_region(
from->rep->rrsets[i], forq->region, 0);
if(!dest[i]) {
log_err("malloc failed in collect ANY");
foriq->state = FINISHED_STATE;
return;
}
}
dest += from->rep->an_numrrsets;
/* copy NS */
memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets,
to->rep->ns_numrrsets * sizeof(dest[0]));
dest += to->rep->ns_numrrsets;
memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets,
from->rep->ns_numrrsets * sizeof(dest[0]));
for(i=0; i<from->rep->ns_numrrsets; i++) {
dest[i] = packed_rrset_copy_region(
from->rep->rrsets[
from->rep->an_numrrsets+i],
forq->region, 0);
if(!dest[i]) {
log_err("malloc failed in collect ANY");
foriq->state = FINISHED_STATE;
return;
}
}
dest += from->rep->ns_numrrsets;
/* copy AR */
memcpy(dest, to->rep->rrsets+to->rep->an_numrrsets+
to->rep->ns_numrrsets,
to->rep->ar_numrrsets * sizeof(dest[0]));
dest += to->rep->ar_numrrsets;
memcpy(dest, from->rep->rrsets+from->rep->an_numrrsets+
from->rep->ns_numrrsets,
from->rep->ar_numrrsets * sizeof(dest[0]));
for(i=0; i<from->rep->ar_numrrsets; i++) {
dest[i] = packed_rrset_copy_region(
from->rep->rrsets[
from->rep->an_numrrsets+
from->rep->ns_numrrsets+i],
forq->region, 0);
if(!dest[i]) {
log_err("malloc failed in collect ANY");
foriq->state = FINISHED_STATE;
return;
}
}
/* update counts */
to->rep->rrsets = d;
to->rep->an_numrrsets += from->rep->an_numrrsets;
@@ -4117,6 +4186,7 @@ processFinished(struct module_qstate* qstate, struct iter_qstate* iq,
iter_store_parentside_neg(qstate->env, &qstate->qinfo,
iq->deleg_msg?iq->deleg_msg->rep:
(iq->response?iq->response->rep:NULL));
target_count_store(qstate, iq);
if(!iq->response) {
verbose(VERB_ALGO, "No response is set, servfail");
errinf(qstate, "(no response found at query finish)");
@@ -4370,7 +4440,10 @@ process_response(struct module_qstate* qstate, struct iter_qstate* iq,
/* normalize and sanitize: easy to delete items from linked lists */
if(!scrub_message(pkt, prs, &iq->qinfo_out, iq->dp->name,
qstate->env->scratch, qstate->env, qstate, ie)) {
qstate->env->scratch, qstate->env, qstate, ie,
&iq->msg_lame_empty, &iq->msg_lame_referral,
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd)
)) {
/* if 0x20 enabled, start fallback, but we have no message */
if(event == module_event_capsfail && !iq->caps_fallback) {
iq->caps_fallback = 1;
@@ -4532,6 +4605,7 @@ iter_clear(struct module_qstate* qstate, int id)
iq = (struct iter_qstate*)qstate->minfo[id];
if(iq) {
outbound_list_clear(&iq->outlist);
target_count_store(qstate, iq);
if(iq->target_count && --iq->target_count[TARGET_COUNT_REF] == 0) {
free(iq->target_count);
if(*iq->nxns_dp) free(*iq->nxns_dp);
+18
View File
@@ -104,6 +104,11 @@ extern int BLACKLIST_PENALTY;
#define RTT_BAND 400
/** Number of retries for empty nodata packets before it is accepted. */
#define EMPTY_NODATA_RETRY_COUNT 2
/** max label-strip iterations in DSNS_FIND_STATE (RFC 4035 4.2 parent-NS
* search) before giving up; bounds upstream NS sends per client DS.
* Means the max number of labels in grandchild to the grandparent zone that
* are co-hosted. */
#define MAX_DSNS_FIND_COUNT 20
/**
* Iterator global state for nat64.
@@ -375,6 +380,10 @@ struct iter_qstate {
/** if true, already tested for ratelimiting and passed the test */
int ratelimit_ok;
/** If the last query, that may be a referral, incremented the
* ratelimit counter. */
int ratelimit_incremented;
/**
* The query must store NS records from referrals as parentside RRs
* Enabled once it hits resolution problems, to throttle retries.
@@ -399,6 +408,8 @@ struct iter_qstate {
uint8_t* dsns_point;
/** length of the dname in dsns_point */
size_t dsns_point_len;
/** number of label-strip iterations performed in DSNS_FIND_STATE */
int dsns_count;
/**
* expected dnssec information for this iteration step.
@@ -434,6 +445,13 @@ struct iter_qstate {
* already so that it is accepted later. */
int empty_nodata_found;
/** Store if the answer was empty, but lame, before it became empty.*/
int msg_lame_empty;
/** Store if the answer was a referral, to self, before scrub. So the
* it is not some sort of answer. */
int msg_lame_referral;
/** list of pending queries to authoritative servers. */
struct outbound_list outlist;
+2
View File
@@ -167,6 +167,8 @@ struct ctx_query {
ub_event_callback_type cb_event;
/** for async query, the callback user arg */
void* cb_arg;
/** for async query the unique info */
void* unique_info;
/** answer message, result from resolver lookup. */
uint8_t* msg;
+17
View File
@@ -571,6 +571,8 @@ ub_ctx_async(struct ub_ctx* ctx, int dothread)
int
ub_poll(struct ub_ctx* ctx)
{
if(!ctx || ctx->event_base)
return UB_INITFAIL;
/* no need to hold lock while testing for readability. */
return tube_poll(ctx->rr_pipe);
}
@@ -578,6 +580,8 @@ ub_poll(struct ub_ctx* ctx)
int
ub_fd(struct ub_ctx* ctx)
{
if(!ctx || ctx->event_base)
return -1;
return tube_read_fd(ctx->rr_pipe);
}
@@ -672,6 +676,8 @@ ub_process(struct ub_ctx* ctx)
int r;
uint8_t* msg;
uint32_t len;
if(!ctx || ctx->event_base)
return UB_INITFAIL;
while(1) {
msg = NULL;
lock_basic_lock(&ctx->rrpipe_lock);
@@ -700,6 +706,8 @@ ub_wait(struct ub_ctx* ctx)
int r;
uint8_t* msg;
uint32_t len;
if(!ctx || ctx->event_base)
return UB_INITFAIL;
/* this is basically the same loop as _process(), but with changes.
* holds the rrpipe lock and waits with tube_wait */
while(1) {
@@ -837,6 +845,8 @@ ub_resolve_async(struct ub_ctx* ctx, const char* name, int rrtype,
struct ctx_query* q;
uint8_t* msg = NULL;
uint32_t len = 0;
if(!ctx || ctx->event_base)
return UB_INITFAIL;
if(async_id)
*async_id = 0;
@@ -1467,8 +1477,15 @@ ub_ctx_set_event(struct ub_ctx* ctx, struct event_base* base) {
lock_basic_lock(&ctx->cfglock);
/* destroy the current worker - safe to pass in NULL */
/* Unlock the cfglock during libworker_delete_event, since it
* calls context_release_alloc, that wants to lock cfglock again.
* Since the event base is used from one thread, the one that
* called this function, it is safe to do so. */
lock_basic_unlock(&ctx->cfglock);
libworker_delete_event(ctx->event_worker);
ctx->event_worker = NULL;
lock_basic_lock(&ctx->cfglock);
new_base = ub_libevent_event_base(base);
if (new_base)
ctx->event_base = new_base;
+22 -8
View File
@@ -105,6 +105,7 @@ libworker_delete_env(struct libworker* w)
SSL_CTX_free(w->sslctx);
#endif
outside_network_delete(w->back);
shared_ports_delete(w->shared_ports);
}
/** delete libworker struct */
@@ -219,17 +220,25 @@ libworker_setup(struct ub_ctx* ctx, int is_bg, struct ub_event_base* eb)
libworker_delete(w);
return NULL;
}
if(!(w->shared_ports = shared_ports_create(cfg->out_ifs,
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6, ports, numports))) {
if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock);
}
libworker_delete(w);
return NULL;
}
w->back = outside_network_create(w->base, cfg->msg_buffer_size,
(size_t)cfg->outgoing_num_ports, cfg->out_ifs,
cfg->num_out_ifs, cfg->do_ip4, cfg->do_ip6,
cfg->do_tcp?cfg->outgoing_num_tcp:0, cfg->ip_dscp,
w->env->infra_cache, w->env->rnd, cfg->use_caps_bits_for_id,
ports, numports, cfg->unwanted_threshold,
cfg->unwanted_threshold,
cfg->outgoing_tcp_mss, &libworker_alloc_cleanup, w,
cfg->do_udp || cfg->udp_upstream_without_downstream, w->sslctx,
cfg->delay_close, cfg->tls_use_sni, NULL, cfg->udp_connect,
cfg->max_reuse_tcp_queries, cfg->tcp_reuse_timeout,
cfg->tcp_auth_query_timeout);
cfg->tcp_auth_query_timeout, w->shared_ports);
w->env->outnet = w->back;
if(!w->is_bg || w->is_bg_thread) {
lock_basic_unlock(&ctx->cfglock);
@@ -642,7 +651,8 @@ int libworker_fg(struct ub_ctx* ctx, struct ctx_query* q)
}
/* process new query */
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
w->back->udp_buff, qid, libworker_fg_done_cb, q, 0)) {
w->back->udp_buff, qid, libworker_fg_done_cb, q, 0,
&q->unique_info)) {
free(qinfo.qname);
return UB_NOMEM;
}
@@ -723,7 +733,8 @@ int libworker_attach_mesh(struct ub_ctx* ctx, struct ctx_query* q,
if(async_id)
*async_id = q->querynum;
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
w->back->udp_buff, qid, libworker_event_done_cb, q, 0)) {
w->back->udp_buff, qid, libworker_event_done_cb, q, 0,
&q->unique_info)) {
free(qinfo.qname);
return UB_NOMEM;
}
@@ -861,7 +872,8 @@ handle_newq(struct libworker* w, uint8_t* buf, uint32_t len)
q->w = w;
/* process new query */
if(!mesh_new_callback(w->env->mesh, &qinfo, qflags, &edns,
w->back->udp_buff, qid, libworker_bg_done_cb, q, 0)) {
w->back->udp_buff, qid, libworker_bg_done_cb, q, 0,
&q->unique_info)) {
add_bg_result(w, q, NULL, UB_NOMEM, NULL, 0);
}
free(qinfo.qname);
@@ -879,7 +891,8 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
int check_ratelimit,
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
struct module_qstate* q, int* was_ratelimited)
struct module_qstate* q, int* was_ratelimited,
int* ratelimit_incremented)
{
struct libworker* w = (struct libworker*)q->env->worker;
struct outbound_entry* e = (struct outbound_entry*)regional_alloc(
@@ -891,7 +904,7 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
want_dnssec, nocaps, check_ratelimit, tcp_upstream, ssl_upstream,
tls_auth_name, addr, addrlen, zone, zonelen, q,
libworker_handle_service_reply, e, w->back->udp_buff, q->env,
was_ratelimited);
was_ratelimited, ratelimit_incremented);
if(!e->qsent) {
return NULL;
}
@@ -976,7 +989,8 @@ struct outbound_entry* worker_send_query(struct query_info* ATTR_UNUSED(qinfo),
struct sockaddr_storage* ATTR_UNUSED(addr), socklen_t ATTR_UNUSED(addrlen),
uint8_t* ATTR_UNUSED(zone), size_t ATTR_UNUSED(zonelen), int ATTR_UNUSED(tcp_upstream),
int ATTR_UNUSED(ssl_upstream), char* ATTR_UNUSED(tls_auth_name),
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited))
struct module_qstate* ATTR_UNUSED(q), int* ATTR_UNUSED(was_ratelimited),
int* ATTR_UNUSED(ratelimit_incremented))
{
log_assert(0);
return 0;
+3
View File
@@ -60,6 +60,7 @@ struct tube;
struct sldns_buffer;
struct ub_event_base;
struct query_info;
struct shared_ports;
/**
* The library-worker status structure
@@ -84,6 +85,8 @@ struct libworker {
struct comm_base* base;
/** the backside outside network interface to the auth servers */
struct outside_network* back;
/** shared ports structure */
struct shared_ports* shared_ports;
/** random() table for this worker. */
struct ub_randstate* rndstate;
/** sslcontext for SSL wrapped DNS over TCP queries */
+1 -1
View File
@@ -853,7 +853,7 @@ Result: ['74.125.43.147', '74.125.43.99', '74.125.43.103', '74.125.43.104']
%{
//printf("resolve_start(%lX)\n",(long unsigned int)arg1);
Py_BEGIN_ALLOW_THREADS
$function
$action
Py_END_ALLOW_THREADS
//printf("resolve_stop()\n");
%}
+65
View File
@@ -0,0 +1,65 @@
/*
* libunbound/remote.h - prototypes for remote control methods.
*
* Copyright (c) 2026, NLnet Labs. All rights reserved.
*
* This software is open source.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the NLNET LABS nor the names of its contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/**
* \file
*
* This file declares the methods that must be implemented to use the
* remote control service.
*/
#ifndef LIBUNBOUND_REMOTE_H
#define LIBUNBOUND_REMOTE_H
struct comm_reply;
struct comm_point;
/** fast reload thread commands to remote service thread event callback */
void fast_reload_service_cb(int fd, short bits, void* arg);
/** fast reload callback for the remote control client connection */
int fast_reload_client_callback(struct comm_point* c, void* arg, int err,
struct comm_reply* rep);
/** handle remote control accept callbacks */
int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*);
/** handle remote control data callbacks */
int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*);
/** routine to printout option values over SSL */
void remote_get_opt_ssl(char* line, void* arg);
#endif /* LIBUNBOUND_REMOTE_H */
+4
View File
@@ -853,6 +853,8 @@ struct ub_server_stats {
long long qquic;
/** number of queries removed due to discard-timeout */
long long num_queries_discard_timeout;
/** number of queries removed due to replyaddr limit */
long long num_queries_replyaddr_limit;
/** number of queries removed due to wait-limit */
long long num_queries_wait_limit;
/** number of dns error reports generated */
@@ -872,6 +874,8 @@ struct ub_stats_info {
long long mesh_num_states;
/** mesh stats: current number of reply (user) states */
long long mesh_num_reply_states;
/** mesh stats: current number of reply entries */
long long mesh_num_reply_addrs;
/** mesh stats: number of reply states overwritten with a new one */
long long mesh_jostled;
/** mesh stats: number of incoming queries dropped */
+8 -11
View File
@@ -70,6 +70,8 @@ struct query_info;
* @param q: which query state to reactivate upon return.
* @param was_ratelimited: it will signal back if the query failed to pass the
* ratelimit check.
* @param ratelimit_incremented: set to true if the ratelimit counter
* was increased.
* @return: false on failure (memory or socket related). no query was
* sent.
*/
@@ -78,7 +80,8 @@ struct outbound_entry* libworker_send_query(struct query_info* qinfo,
int check_ratelimit,
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
struct module_qstate* q, int* was_ratelimited);
struct module_qstate* q, int* was_ratelimited,
int* ratelimit_incremented);
/** process incoming serviced query replies from the network */
int libworker_handle_service_reply(struct comm_point* c, void* arg, int error,
@@ -126,6 +129,8 @@ void worker_sighandler(int sig, void* arg);
* @param q: which query state to reactivate upon return.
* @param was_ratelimited: it will signal back if the query failed to pass the
* ratelimit check.
* @param ratelimit_incremented: set to true if the ratelimit counter
* was increased.
* @return: false on failure (memory or socket related). no query was
* sent.
*/
@@ -134,7 +139,8 @@ struct outbound_entry* worker_send_query(struct query_info* qinfo,
int check_ratelimit,
struct sockaddr_storage* addr, socklen_t addrlen, uint8_t* zone,
size_t zonelen, int tcp_upstream, int ssl_upstream, char* tls_auth_name,
struct module_qstate* q, int* was_ratelimited);
struct module_qstate* q, int* was_ratelimited,
int* ratelimit_incremented);
/**
* process control messages from the main thread. Frees the control
@@ -171,13 +177,4 @@ void worker_start_accept(void* arg);
/** stop accept callback handler */
void worker_stop_accept(void* arg);
/** handle remote control accept callbacks */
int remote_accept_callback(struct comm_point*, void*, int, struct comm_reply*);
/** handle remote control data callbacks */
int remote_control_callback(struct comm_point*, void*, int, struct comm_reply*);
/** routine to printout option values over SSL */
void remote_get_opt_ssl(char* line, void* arg);
#endif /* LIBUNBOUND_WORKER_H */
+11 -2
View File
@@ -440,6 +440,7 @@ if [ "$DOWIN" = "yes" ]; then
autoheader -f || error_cleanup "Autoheader failed."
rm -r autom4te* || echo "ignored"
rm -f config.h.in~ || echo "ignore absence of config.h.in~ file."
rm -f configure~ || echo "ignore absence of configure~ file."
fi
if test "`uname`" = "Linux"; then
@@ -465,9 +466,13 @@ if [ "$DOWIN" = "yes" ]; then
|| error_cleanup "Could not configure"
set +x
else
# Add -l:libssp:a to statically link libssp if possible.
# Put it at the end of LIBS, to satisfy also linked in
# dependencies.
set -x
$configure --enable-debug --enable-static-exe --disable-flto --disable-gost $* $cross_flag \
|| error_cleanup "Could not configure"
sed -i Makefile -e 's/^\(LIBS=.*\)$/\1 -l:libssp.a/'
set +x
fi
info "Calling make"
@@ -484,6 +489,7 @@ if [ "$DOWIN" = "yes" ]; then
|| error_cleanup "Could not configure"
set +x
else
# Do not add -l:libssp:a statically because it is a shared build.
set -x
$configure --enable-debug --disable-flto --disable-gost $* $shared_cross_flag \
|| error_cleanup "Could not configure"
@@ -602,6 +608,8 @@ rm -rf .git .travis.yml .gitattributes .github .gitignore || error_cleanup "Fail
info "Adding libtool utils (libtoolize)."
libtoolize -c --install || libtoolize -c || error_cleanup "Libtoolize failed."
# Turn this off, if the git repo times out for lookups.
if test "updateconfigsub" = "false"; then
# https://www.gnu.org/software/gettext/manual/html_node/config_002eguess.html
info "Updating config.guess and config.sub"
wget -O config.guess 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD'
@@ -615,12 +623,14 @@ if [ `uname -s | grep -i -c darwin` -ne 0 ]; then
xattr -d com.apple.quarantine config.sub
fi
fi
fi
info "Building configure script (autoreconf)."
autoreconf -f || error_cleanup "Autoconf failed."
rm -r autom4te* || error_cleanup "Failed to remove autoconf cache directory."
rm -f config.h.in~ || echo "ignore absence of config.h.in~ file."
rm -f configure~ || echo "ignore absence of configure~ file."
info "Building lexer and parser."
echo "#include \"config.h\"" > util/configlexer.c || error_cleanup "Failed to create configlexer"
@@ -666,6 +676,7 @@ if [ "$RECONFIGURE" = "yes" ]; then
autoreconf -f || error_cleanup "Autoconf failed."
rm -r autom4te* || error_cleanup "Failed to remove autoconf cache directory."
rm -f config.h.in~ || echo "ignore absence of config.h.in~ file."
rm -f configure~ || echo "ignore absence of configure~ file."
fi
replace_all doc/README
@@ -697,7 +708,5 @@ cleanup
storehash unbound-$version.tar.gz
echo "create unbound-$version.tar.gz.asc with:"
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound-$version.tar.gz"
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound-$version.zip"
echo " gpg --armor --detach-sign --digest-algo SHA256 unbound_setup_$version.exe"
info "Unbound distribution created successfully."
+18 -17
View File
@@ -79,7 +79,7 @@
i+(int)((unsigned int)name[i]) < len) {
memmove(buf, name + i + 1, (unsigned int)name[i]);
buf[(unsigned int)name[i]] = 0;
PyList_SetItem(list, cnt, PyString_FromString(buf));
PyList_SetItem(list, cnt, PyUnicode_FromString(buf));
}
i += ((unsigned int)name[i]) + 1;
cnt++;
@@ -96,7 +96,7 @@
list = PyList_New(len);
for (i=0; i < len; i++) {
PyList_SET_ITEM(list, i, PyString_FromString(array[i]));
PyList_SET_ITEM(list, i, PyUnicode_FromString(array[i]));
}
return list;
}
@@ -207,7 +207,7 @@ struct query_info {
char buf[LDNS_MAX_DOMAINLEN];
buf[0] = '\0';
dname_str((uint8_t*)PyBytes_AsString(dname), buf);
return PyString_FromString(buf);
return PyUnicode_FromString(buf);
}
%}
@@ -345,7 +345,7 @@ struct packed_rrset_data {
PyObject* _get_data_rr_len(struct packed_rrset_data* d, int idx) {
if ((d != NULL) && (idx >= 0) &&
((size_t)idx < (d->count+d->rrsig_count)))
return PyInt_FromLong(d->rr_len[idx]);
return PyLong_FromLong(d->rr_len[idx]);
return Py_None;
}
void _set_data_rr_ttl(struct packed_rrset_data* d, int idx, uint32_t ttl)
@@ -357,7 +357,7 @@ struct packed_rrset_data {
PyObject* _get_data_rr_ttl(struct packed_rrset_data* d, int idx) {
if ((d != NULL) && (idx >= 0) &&
((size_t)idx < (d->count+d->rrsig_count)))
return PyInt_FromLong(d->rr_ttl[idx]);
return PyLong_FromLong(d->rr_ttl[idx]);
return Py_None;
}
PyObject* _get_data_rr_data(struct packed_rrset_data* d, int idx) {
@@ -555,12 +555,12 @@ struct sockaddr_storage {};
if (ss->ss_family == AF_INET) {
const struct sockaddr_in *sa4 = (struct sockaddr_in *)ss;
return PyInt_FromLong(ntohs(sa4->sin_port));
return PyLong_FromLong(ntohs(sa4->sin_port));
}
if (ss->ss_family == AF_INET6) {
const struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ss;
return PyInt_FromLong(ntohs(sa6->sin6_port));
return PyLong_FromLong(ntohs(sa6->sin6_port));
}
return Py_None;
@@ -574,7 +574,7 @@ struct sockaddr_storage {};
}
sa6 = (struct sockaddr_in6 *)ss;
return PyInt_FromLong(ntohl(sa6->sin6_flowinfo));
return PyLong_FromLong(ntohl(sa6->sin6_flowinfo));
}
PyObject *_sockaddr_storage_scope_id(const struct sockaddr_storage *ss) {
@@ -585,7 +585,7 @@ struct sockaddr_storage {};
}
sa6 = (struct sockaddr_in6 *)ss;
return PyInt_FromLong(ntohl(sa6->sin6_scope_id));
return PyLong_FromLong(ntohl(sa6->sin6_scope_id));
}
%}
@@ -661,7 +661,7 @@ struct edns_option {
%inline %{
PyObject* _edns_option_opt_code_get(struct edns_option* option) {
uint16_t opt_code = option->opt_code;
return PyInt_FromLong(opt_code);
return PyLong_FromLong(opt_code);
}
PyObject* _edns_option_opt_data_get(struct edns_option* option) {
@@ -729,11 +729,12 @@ struct module_env {
int check_ratelimit,
struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* zone, size_t zonelen, int tcp_upstream, int ssl_upstream,
char* tls_auth_name, struct module_qstate* q, int* was_ratelimited);
char* tls_auth_name, struct module_qstate* q, int* was_ratelimited,
int* ratelimit_incremented);
void (*detach_subs)(struct module_qstate* qstate);
int (*attach_sub)(struct module_qstate* qstate,
struct query_info* qinfo, uint16_t qflags, int prime,
int valrec, struct module_qstate** newq);
struct query_info* qinfo, struct respip_client_info* cinfo,
uint16_t qflags, int prime, int valrec, struct module_qstate** newq);
void (*kill_sub)(struct module_qstate* newq);
int (*detect_cycle)(struct module_qstate* qstate,
struct query_info* qinfo, uint16_t flags, int prime,
@@ -1626,7 +1627,7 @@ int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_edns);
@@ -1710,7 +1711,7 @@ out:
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_qinfo);
@@ -1764,7 +1765,7 @@ out:
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_qstate);
@@ -1813,7 +1814,7 @@ out:
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_qstate);
+33 -37
View File
@@ -246,14 +246,14 @@ log_py_err(void)
}
/* And it should be a string all ready to go - duplicate it. */
if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) {
if (!PyBytes_Check(obResult) && !PyUnicode_Check(obResult)) {
log_err("pythonmod: cannot print exception, "
"StringIO.getvalue() result did not String_Check"
" or Unicode_Check");
goto cleanup;
}
if(PyString_Check(obResult)) {
result = PyString_AsString(obResult);
if(PyBytes_Check(obResult)) {
result = PyBytes_AsString(obResult);
} else {
ascstr = PyUnicode_AsASCIIString(obResult);
result = PyBytes_AsString(ascstr);
@@ -450,11 +450,11 @@ int pythonmod_init(struct module_env* env, int id)
pe->data = PyDict_New();
/* add the script filename to the global "mod_env" for trivial access */
fname = PyString_FromString(pe->fname);
fname = PyUnicode_FromString(pe->fname);
if(PyDict_SetItemString(pe->data, "script", fname) < 0) {
log_err("pythonmod: could not add item to dictionary");
Py_XDECREF(fname);
goto python_init_fail;
goto fail_close_file;
}
Py_XDECREF(fname);
Py_XINCREF(pe->data); /* reference will be stolen below */
@@ -462,7 +462,7 @@ int pythonmod_init(struct module_env* env, int id)
log_err("pythonmod: could not add mod_env object");
Py_XDECREF(pe->data); /* 2 times, here and on python_init_fail; */
/* on failure the reference is not stolen */
goto python_init_fail;
goto fail_close_file;
}
if (PyRun_SimpleFile(script_py, pe->fname) < 0) {
@@ -487,37 +487,34 @@ int pythonmod_init(struct module_env* env, int id)
/* for python 3.9 and newer */
char* fstr = NULL;
size_t flen = 0;
long pos = 0;
log_err("pythonmod: can't parse Python script %s", pe->fname);
/* print the error to logs too, run it again */
fseek(script_py, 0, SEEK_END);
flen = (size_t)ftell(script_py);
pos = ftell(script_py);
if (pos == -1L) {
log_err("ftell failed to print parse error: %s: %s",
pe->fname, strerror(errno));
goto fail_close_file;
}
flen = (size_t)pos;
#ifdef SIZE_MAX
if(flen > SIZE_MAX-2) {
log_err("script file too large");
goto fail_close_file;
}
#endif
fstr = malloc(flen+1);
if(!fstr) {
log_err("malloc failure to print parse error");
/* close the file */
#if PY_MAJOR_VERSION < 3
Py_XDECREF(PyFileObject);
#else
fclose(script_py);
#endif
goto python_init_fail;
log_err("malloc failure to print parse error");
goto fail_close_file;
}
fseek(script_py, 0, SEEK_SET);
if(fread(fstr, flen, 1, script_py) < 1) {
log_err("file read failed to print parse error: %s: %s",
log_err("file read failed to print parse error: %s: %s",
pe->fname, strerror(errno));
free(fstr);
/* close the file */
#if PY_MAJOR_VERSION < 3
Py_XDECREF(PyFileObject);
#else
fclose(script_py);
#endif
goto python_init_fail;
free(fstr);
goto fail_close_file;
}
fstr[flen] = 0;
/* we compile the string, but do not run it, to stop side-effects */
@@ -527,21 +524,13 @@ int pythonmod_init(struct module_env* env, int id)
#endif
log_py_err();
/* close the file */
#if PY_MAJOR_VERSION < 3
Py_XDECREF(PyFileObject);
#else
fclose(script_py);
#endif
#if PY_MAJOR_VERSION <= 2 || (PY_MAJOR_VERSION == 3 && PY_MINOR_VERSION < 9)
/* no cleanup needed for python before 3.9 */
#else
/* cleanup for python 3.9 and newer */
free(fstr);
#endif
goto python_init_fail;
goto fail_close_file;
}
/* close the file */
@@ -602,6 +591,13 @@ int pythonmod_init(struct module_env* env, int id)
PyGILState_Release(gil);
return 1;
fail_close_file:
#if PY_MAJOR_VERSION < 3
Py_XDECREF(PyFileObject);
#else
fclose(script_py);
#endif
python_init_fail:
Py_XDECREF(pe->module);
Py_XDECREF(pe->dict);
+46 -24
View File
@@ -899,27 +899,34 @@ respip_rewrite_reply(const struct query_info* qinfo,
int rpz_cname_override = 0;
char* log_name = NULL;
if(!cinfo)
goto done;
ctaglist = cinfo->taglist;
ctaglen = cinfo->taglen;
tag_actions = cinfo->tag_actions;
tag_actions_size = cinfo->tag_actions_size;
tag_datas = cinfo->tag_datas;
tag_datas_size = cinfo->tag_datas_size;
if(cinfo->view) {
view = cinfo->view;
lock_rw_rdlock(&view->lock);
} else if(cinfo->view_name) {
view = views_find_view(views, cinfo->view_name, 0);
if(!view) {
/* If the view no longer exists, the rewrite can not
* be processed further. */
verbose(VERB_ALGO, "respip: failed because view %s no "
"longer exists", cinfo->view_name);
return 0;
if(!cinfo) {
/* Internal mesh sub-query (e.g. dns64 A lookup): no
* per-client view/tags, but global response-ip and RPZ
* rpz-ip must still apply. */
ctaglist = NULL; ctaglen = 0;
tag_actions = NULL; tag_actions_size = 0;
tag_datas = NULL; tag_datas_size = 0;
} else {
ctaglist = cinfo->taglist;
ctaglen = cinfo->taglen;
tag_actions = cinfo->tag_actions;
tag_actions_size = cinfo->tag_actions_size;
tag_datas = cinfo->tag_datas;
tag_datas_size = cinfo->tag_datas_size;
if(cinfo->view) {
view = cinfo->view;
lock_rw_rdlock(&view->lock);
} else if(cinfo->view_name) {
view = views_find_view(views, cinfo->view_name, 0);
if(!view) {
/* If the view no longer exists, the rewrite can not
* be processed further. */
verbose(VERB_ALGO, "respip: failed because view %s no "
"longer exists", cinfo->view_name);
return 0;
}
/* The view is rdlocked by views_find_view. */
}
/* The view is rdlocked by views_find_view. */
}
log_assert(ipset);
@@ -973,6 +980,9 @@ respip_rewrite_reply(const struct query_info* qinfo,
lock_rw_unlock(&raddr->lock);
lock_rw_unlock(&a->lock);
lock_rw_unlock(&az->rpz_lock);
if(view) {
lock_rw_unlock(&view->lock);
}
return 0;
}
if(rpz_used) {
@@ -1074,7 +1084,8 @@ generate_cname_request(struct module_qstate* qstate,
subqi.qtype = qstate->qinfo.qtype;
subqi.qclass = qstate->qinfo.qclass;
fptr_ok(fptr_whitelist_modenv_attach_sub(qstate->env->attach_sub));
return (*qstate->env->attach_sub)(qstate, &subqi, BIT_RD, 0, 0, &subq);
return (*qstate->env->attach_sub)(qstate, &subqi,
qstate->client_info, BIT_RD, 0, 0, &subq);
}
void
@@ -1110,7 +1121,13 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
if((qstate->qinfo.qtype == LDNS_RR_TYPE_A ||
qstate->qinfo.qtype == LDNS_RR_TYPE_AAAA ||
qstate->qinfo.qtype == LDNS_RR_TYPE_ANY) &&
qstate->return_msg && qstate->return_msg->rep) {
qstate->return_msg && qstate->return_msg->rep &&
!(qstate->env->need_to_validate &&
(!(qstate->query_flags & BIT_CD)
|| qstate->env->cfg->ignore_cd) &&
(qstate->return_msg->rep->security <= sec_status_bogus
|| qstate->return_msg->rep->security ==
sec_status_secure_sentinel_fail))) {
struct reply_info* new_rep = qstate->return_msg->rep;
struct ub_packed_rrset_key* alias_rrset = NULL;
struct respip_action_info actinfo = {0, 0, 0, 0, NULL, 0, NULL};
@@ -1147,8 +1164,10 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
* clients. */
qstate->is_drop = 1;
} else if(alias_rrset) {
if(!generate_cname_request(qstate, alias_rrset))
if(!generate_cname_request(qstate, alias_rrset)) {
errinf(qstate, "Could not generate CNAME request");
goto servfail;
}
next_state = module_wait_subquery;
}
qstate->return_msg->rep = new_rep;
@@ -1162,6 +1181,7 @@ respip_operate(struct module_qstate* qstate, enum module_ev event, int id,
servfail:
qstate->return_rcode = LDNS_RCODE_SERVFAIL;
qstate->return_msg = NULL;
qstate->ext_state[id] = module_finished;
}
int
@@ -1233,7 +1253,8 @@ respip_inform_super(struct module_qstate* qstate, int id,
struct respip_qstate* rq = (struct respip_qstate*)super->minfo[id];
struct reply_info* new_rep = NULL;
rq->state = RESPIP_SUBQUERY_FINISHED;
if(rq)
rq->state = RESPIP_SUBQUERY_FINISHED;
/* respip subquery should have always been created with a valid reply
* in super. */
@@ -1257,6 +1278,7 @@ respip_inform_super(struct module_qstate* qstate, int id,
return;
fail:
errinf(super, "CNAME lookup failed");
super->return_rcode = LDNS_RCODE_SERVFAIL;
super->return_msg = NULL;
return;
+418 -107
View File
File diff suppressed because it is too large Load Diff
+29
View File
@@ -144,6 +144,8 @@ struct auth_zone {
struct module_env* zonemd_callback_env;
/** for the zonemd callback, the type of data looked up */
uint16_t zonemd_callback_qtype;
/** for the zonemd callback, the unique info */
void* zonemd_callback_unique_info;
/** zone has been deleted */
int zone_deleted;
/** deletelist pointer, unused normally except during delete */
@@ -153,6 +155,10 @@ struct auth_zone {
struct auth_zone* rpz_az_next;
/** previous auth zone containing RPZ data, or NULL */
struct auth_zone* rpz_az_prev;
/** The maximum auth zone transfer size, in bytes. */
size_t max_transfer_size;
/** The maximum auth zone transfer time taken, in msec. */
int max_transfer_time;
};
/**
@@ -283,6 +289,15 @@ struct auth_xfer {
* this is renewed every SOA probe and transfer. On zone load
* from zonefile it is also set (with probe set soon to check) */
time_t lease_time;
/** The maximum auth zone transfer size, in bytes. */
size_t max_transfer_size;
/** The maximum auth zone transfer time taken, in msec. */
int max_transfer_time;
/** the zone is an rpz zone */
int is_rpz;
/** the number of IXFRs since the last full transfer. */
int num_ixfrs;
};
/**
@@ -331,6 +346,8 @@ struct auth_probe {
/** for the hostname lookups, which master is current */
struct auth_master* lookup_target;
/** for the lookup, the callback unique info */
void* lookup_unique_info;
/** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */
int lookup_aaaa;
/** we only want to do lookups for making config work (for notify),
@@ -379,12 +396,18 @@ struct auth_transfer {
struct auth_chunk* chunks_first;
/** last element in chunks list (to append new data at the end) */
struct auth_chunk* chunks_last;
/** running total of bytes held in chunks_first..chunks_last */
size_t chunks_total;
/** start time of the transfer */
struct timeval start_time;
/** list of upstream masters for this zone, from config */
struct auth_master* masters;
/** for the hostname lookups, which master is current */
struct auth_master* lookup_target;
/** for the lookup, the callback unique info */
void* lookup_unique_info;
/** are we looking up A or AAAA, first A, then AAAA (if ip6 enabled) */
int lookup_aaaa;
@@ -828,4 +851,10 @@ void auth_xfer_delete(struct auth_xfer* xfr);
*/
void xfr_disown_tasks(struct auth_xfer* xfr, struct worker* worker);
/** count number of open and closed parenthesis in a chunkline */
int chunkline_count_parens(struct sldns_buffer* buf, size_t start);
/** Clear data in auth zone */
void auth_zone_clear_data(struct auth_zone* z);
#endif /* SERVICES_AUTHZONE_H */
+101 -35
View File
@@ -43,6 +43,7 @@
#include "iterator/iter_utils.h"
#include "validator/val_nsec.h"
#include "validator/val_utils.h"
#include "iterator/iter_utils.h"
#include "services/cache/dns.h"
#include "services/cache/rrset.h"
#include "util/data/msgparse.h"
@@ -60,10 +61,10 @@
* @param rep: contains list of rrsets to store.
* @param now: current time.
* @param leeway: during prefetch how much leeway to update TTLs.
* This makes rrsets (other than type NS) timeout sooner so they get
* updated with a new full TTL.
* Type NS does not get this, because it must not be refreshed from the
* child domain, but keep counting down properly.
* This makes rrsets expire sooner so they get updated with a new full
* TTL.
* Child side type NS does get this but TTL checks are done using the time
* the query was created rather than the time the answer was received.
* @param pside: if from parentside discovered NS, so that its NS is okay
* in a prefetch situation to be updated (without becoming sticky).
* @param qrep: update rrsets here if cache is better
@@ -100,11 +101,20 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
rep->ref[i].id != rep->ref[i].key->id)
ck = NULL;
else ck = packed_rrset_copy_region(
rep->ref[i].key, region, now);
rep->ref[i].key, region,
((ntohs(rep->ref[i].key->rk.type)==
LDNS_RR_TYPE_NS && !pside)?qstarttime:now));
lock_rw_unlock(&rep->ref[i].key->entry.lock);
if(ck) {
/* use cached copy if memory allows */
qrep->rrsets[i] = ck;
ttl = ((struct packed_rrset_data*)
ck->entry.data)->ttl;
if(ttl < qrep->ttl) {
qrep->ttl = ttl;
qrep->prefetch_ttl = PREFETCH_TTL_CALC(qrep->ttl);
qrep->serve_expired_ttl = qrep->ttl + SERVE_EXPIRED_TTL;
}
}
}
/* no break: also copy key item */
@@ -169,10 +179,12 @@ 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);
if((flags & DNSCACHE_STORE_EXPIRED_MSG_CACHEDB)) {
reply_info_absolute_ttls(rep, *env->now, *env->now - ttl);
} else reply_info_set_ttls(rep, *env->now);
store_rrsets(env, rep, *env->now, leeway, pside, qrep, region,
qstarttime);
if(ttl == 0 && !(flags & DNSCACHE_STORE_ZEROTTL)) {
if(ttl == 0) {
/* we do not store the message, but we did store the RRs,
* which could be useful for delegation information */
verbose(VERB_ALGO, "TTL 0: dropped msg from cache");
@@ -221,8 +233,15 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
/* snip off front part of qname until the type is found */
while(qnamelen > 0) {
if((rrset = rrset_cache_lookup(env->rrset_cache, qname,
qnamelen, searchtype, qclass, 0, now, 0))) {
rrset = rrset_cache_lookup(env->rrset_cache, qname,
qnamelen, searchtype, qclass, 0, now, 0);
if(!rrset && searchtype == LDNS_RR_TYPE_DNAME)
/* If not found, for type DNAME, try 0TTL stored,
* for its grace period. */
rrset = rrset_cache_lookup(env->rrset_cache, qname,
qnamelen, searchtype, qclass,
PACKED_RRSET_UPSTREAM_0TTL, now, 0);
if(rrset) {
uint8_t* origqname = qname;
size_t origqnamelen = qnamelen;
if(!noexpiredabove)
@@ -259,6 +278,8 @@ find_closest_of_type(struct module_env* env, uint8_t* qname, size_t qnamelen,
/* snip off front label */
lablen = *qname;
if(lablen == 0)
break;
qname += lablen + 1;
qnamelen -= lablen + 1;
}
@@ -272,8 +293,10 @@ addr_to_additional(struct ub_packed_rrset_key* rrset, struct regional* region,
{
if((msg->rep->rrsets[msg->rep->rrset_count] =
packed_rrset_copy_region(rrset, region, now))) {
struct packed_rrset_data* d = rrset->entry.data;
msg->rep->ar_numrrsets++;
msg->rep->rrset_count++;
UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
}
}
@@ -456,8 +479,10 @@ find_add_ds(struct module_env* env, struct regional* region,
/* add it to auth section. This is the second rrset. */
if((msg->rep->rrsets[msg->rep->rrset_count] =
packed_rrset_copy_region(rrset, region, now))) {
struct packed_rrset_data* d = rrset->entry.data;
msg->rep->ns_numrrsets++;
msg->rep->rrset_count++;
UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
}
lock_rw_unlock(&rrset->entry.lock);
}
@@ -487,6 +512,8 @@ dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype,
return NULL; /* integer overflow protection */
msg->rep->flags = BIT_QR; /* with QR, no AA */
msg->rep->qdcount = 1;
msg->rep->ttl = MAX_TTL; /* will be updated (brought down) while we add
* rrsets to the message */
msg->rep->reason_bogus = LDNS_EDE_NONE;
msg->rep->rrsets = (struct ub_packed_rrset_key**)
regional_alloc(region,
@@ -497,24 +524,28 @@ dns_msg_create(uint8_t* qname, size_t qnamelen, uint16_t qtype,
}
int
dns_msg_authadd(struct dns_msg* msg, struct regional* region,
dns_msg_authadd(struct dns_msg* msg, struct regional* region,
struct ub_packed_rrset_key* rrset, time_t now)
{
if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
struct packed_rrset_data* d = rrset->entry.data;
if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
packed_rrset_copy_region(rrset, region, now)))
return 0;
msg->rep->ns_numrrsets++;
UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
return 1;
}
int
dns_msg_ansadd(struct dns_msg* msg, struct regional* region,
dns_msg_ansadd(struct dns_msg* msg, struct regional* region,
struct ub_packed_rrset_key* rrset, time_t now)
{
if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
struct packed_rrset_data* d = rrset->entry.data;
if(!(msg->rep->rrsets[msg->rep->rrset_count++] =
packed_rrset_copy_region(rrset, region, now)))
return 0;
msg->rep->an_numrrsets++;
UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
return 1;
}
@@ -556,8 +587,12 @@ dns_cache_find_delegation(struct module_env* env, uint8_t* qname,
return NULL;
}
}
if(!delegpt_rrset_add_ns(dp, region, nskey, 0))
if(!delegpt_rrset_add_ns(dp, region, nskey, 0,
deleg_port_number(env))) {
lock_rw_unlock(&nskey->entry.lock);
log_err("find_delegation: addns out of memory");
return NULL;
}
lock_rw_unlock(&nskey->entry.lock); /* first unlock before next lookup*/
/* find and add DS/NSEC (if any) */
if(msg)
@@ -585,6 +620,7 @@ gen_dns_msg(struct regional* region, struct query_info* q, size_t num)
sizeof(struct reply_info) - sizeof(struct rrset_ref));
if(!msg->rep)
return NULL;
msg->rep->ttl = MAX_TTL;
msg->rep->reason_bogus = LDNS_EDE_NONE;
msg->rep->reason_bogus_str = NULL;
if(num > RR_COUNT_MAX)
@@ -606,13 +642,13 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
size_t i;
int is_expired = 0;
time_t now_control = now;
if(now > r->ttl) {
if(TTL_IS_EXPIRED(r->ttl, now)) {
/* Check if we are allowed to serve expired */
if(!allow_expired || !reply_info_can_answer_expired(r, now))
return NULL;
/* Change the current time so we can pass the below TTL checks when
* serving expired data. */
now_control = r->ttl - env->cfg->serve_expired_reply_ttl;
/* Change the current time so we can pass the below TTL checks
* when serving expired data. */
now_control = 0;
is_expired = 1;
}
@@ -620,15 +656,6 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
if(!msg) return NULL;
msg->rep->flags = r->flags;
msg->rep->qdcount = r->qdcount;
msg->rep->ttl = is_expired
?SERVE_EXPIRED_REPLY_TTL
:r->ttl - now;
if(r->prefetch_ttl > now)
msg->rep->prefetch_ttl = r->prefetch_ttl - now;
else
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
msg->rep->serve_expired_norec_ttl = 0;
msg->rep->security = r->security;
msg->rep->an_numrrsets = r->an_numrrsets;
msg->rep->ns_numrrsets = r->ns_numrrsets;
@@ -656,13 +683,30 @@ tomsg(struct module_env* env, struct query_info* q, struct reply_info* r,
return NULL;
}
for(i=0; i<msg->rep->rrset_count; i++) {
struct packed_rrset_data* d;
msg->rep->rrsets[i] = packed_rrset_copy_region(r->rrsets[i],
region, now);
if(!msg->rep->rrsets[i]) {
rrset_array_unlock(r->ref, r->rrset_count);
return NULL;
}
d = msg->rep->rrsets[i]->entry.data;
UPDATE_TTL_FROM_RRSET(msg->rep->ttl, d->ttl);
}
if(msg->rep->rrset_count < 1) {
msg->rep->ttl = is_expired
?SERVE_EXPIRED_REPLY_TTL
:r->ttl - now;
if(r->prefetch_ttl > now)
msg->rep->prefetch_ttl = r->prefetch_ttl - now;
else
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
} else {
/* msg->rep->ttl has been updated through the RRSets above */
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
}
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
msg->rep->serve_expired_norec_ttl = 0;
if(env)
rrset_array_unlock_touch(env->rrset_cache, scratch, r->ref,
r->rrset_count);
@@ -675,10 +719,16 @@ struct dns_msg*
dns_msg_deepcopy_region(struct dns_msg* origin, struct regional* region)
{
size_t i;
struct ub_packed_rrset_key** saved_rrsets;
struct dns_msg* res = NULL;
size_t rep_alloc_size = sizeof(struct reply_info)
- sizeof(struct rrset_ref); /* this is the size of res->rep
allocated in gen_dns_msg() */
res = gen_dns_msg(region, &origin->qinfo, origin->rep->rrset_count);
if(!res) return NULL;
*res->rep = *origin->rep;
saved_rrsets = res->rep->rrsets; /* save rrsets alloc by gen_dns_msg */
memcpy(res->rep, origin->rep, rep_alloc_size);
res->rep->rrsets = saved_rrsets;
if(origin->rep->reason_bogus_str) {
res->rep->reason_bogus_str = regional_strdup(region,
origin->rep->reason_bogus_str);
@@ -701,7 +751,7 @@ rrset_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
struct dns_msg* msg;
struct packed_rrset_data* d = (struct packed_rrset_data*)
rrset->entry.data;
if(now > d->ttl)
if(TTL_IS_EXPIRED(d->ttl, now))
return NULL;
msg = gen_dns_msg(region, q, 1); /* only the CNAME (or other) RRset */
if(!msg)
@@ -736,8 +786,20 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
rrset->entry.data;
uint8_t* newname, *dtarg = NULL;
size_t newlen, dtarglen;
if(now > d->ttl)
return NULL;
time_t rr_ttl;
int graceperiod = 0;
if(TTL_IS_EXPIRED(d->ttl, now)) {
/* Allow TTL=0 DNAME from upstream within grace period */
if(!(rrset->rk.flags & PACKED_RRSET_UPSTREAM_0TTL))
return NULL;
rr_ttl = 0;
/* Since PACKED_RRSET_UPSTREAM_0TTL set the flag that
* the grace period has been applied, this stops the rrset
* from getting stored back into the cache with a bigger TTL.*/
graceperiod = 1;
} else {
rr_ttl = d->ttl - now;
}
/* only allow validated (with DNSSEC) DNAMEs used from cache
* for insecure DNAMEs, query again. */
*sec_status = d->security;
@@ -749,7 +811,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
msg->rep->flags = BIT_QR; /* reply, no AA, no error */
msg->rep->authoritative = 0; /* reply stored in cache can't be authoritative */
msg->rep->qdcount = 1;
msg->rep->ttl = d->ttl - now;
msg->rep->ttl = rr_ttl;
msg->rep->prefetch_ttl = PREFETCH_TTL_CALC(msg->rep->ttl);
msg->rep->serve_expired_ttl = msg->rep->ttl + SERVE_EXPIRED_TTL;
msg->rep->serve_expired_norec_ttl = 0;
@@ -762,6 +824,8 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
msg->rep->rrsets[0] = packed_rrset_copy_region(rrset, region, now);
if(!msg->rep->rrsets[0]) /* copy DNAME */
return NULL;
if(graceperiod)
msg->rep->rrsets[0]->rk.flags |= PACKED_RRSET_0TTL_GRACE;
/* synth CNAME rrset */
get_cname_target(rrset, &dtarg, &dtarglen);
if(!dtarg)
@@ -801,7 +865,7 @@ synth_dname_msg(struct ub_packed_rrset_key* rrset, struct regional* region,
if(!newd)
return NULL;
ck->entry.data = newd;
newd->ttl = d->ttl - now; /* RFC6672: synth CNAME TTL == DNAME TTL */
newd->ttl = rr_ttl; /* RFC6672: synth CNAME TTL == DNAME TTL */
newd->count = 1;
newd->rrsig_count = 0;
newd->trust = rrset_trust_ans_noAA;
@@ -844,6 +908,8 @@ fill_any(struct module_env* env,
/* set NOTIMPL for RFC 8482 */
msg->rep->flags |= LDNS_RCODE_NOTIMPL;
msg->rep->security = sec_status_indeterminate;
msg->rep->ttl = 1; /* empty NOTIMPL response will never be
* updated with rrsets, set TTL to 1 */
return msg;
}
@@ -1013,7 +1079,7 @@ dns_cache_lookup(struct module_env* env,
if(env->cfg->harden_below_nxdomain) {
while(!dname_is_root(k.qname)) {
if(dpname && dpnamelen
&& !dname_subdomain_c(k.qname, dpname))
&& !dname_strict_subdomain_c(k.qname, dpname))
break; /* no synth nxdomain above the stub */
dname_remove_label(&k.qname, &k.qname_len);
h = query_info_hash(&k, flags);
@@ -1069,7 +1135,7 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
msgqinf->qclass, flags, 0, 1);
if(e) {
struct reply_info* cached = e->entry.data;
if(cached->ttl < *env->now
if(TTL_IS_EXPIRED(cached->ttl, *env->now)
&& reply_info_could_use_expired(cached, *env->now)
/* If we are validating make sure only
* validating modules can update such messages.
+1 -1
View File
@@ -53,7 +53,7 @@ struct delegpt;
* Must be an unsigned 32-bit value larger than 0xffff */
/** Allow caching a DNS message with a zero TTL. */
#define DNSCACHE_STORE_ZEROTTL 0x100000
#define DNSCACHE_STORE_EXPIRED_MSG_CACHEDB 0x100000
/**
* Region allocated message reply
+2 -1
View File
@@ -1269,7 +1269,8 @@ int infra_wait_limit_allowed(struct infra_cache* infra, struct comm_reply* rep,
int cookie_valid, struct config_file* cfg)
{
struct lruhash_entry* entry;
if(cfg->wait_limit == 0)
if(cfg->wait_limit == 0 ||
(cookie_valid && cfg->wait_limit_cookie == 0))
return 1;
entry = infra_find_ip_ratedata(infra, &rep->client_addr,
+91 -19
View File
@@ -50,6 +50,7 @@
#include "util/regional.h"
#include "util/alloc.h"
#include "util/net_help.h"
#include "validator/val_utils.h"
void
rrset_markdel(void* key)
@@ -126,12 +127,13 @@ rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key,
/** see if rrset needs to be updated in the cache */
static int
need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns,
int a_aaaa)
{
struct packed_rrset_data* newd = (struct packed_rrset_data*)nd;
struct packed_rrset_data* cached = (struct packed_rrset_data*)cd;
/* o if new data is expired, cached data is better */
if( newd->ttl < timenow && timenow <= cached->ttl)
if( TTL_IS_EXPIRED(newd->ttl, timenow) && !TTL_IS_EXPIRED(cached->ttl, timenow))
return 0;
/* o store if rrset has been validated
* everything better than bogus data
@@ -146,13 +148,27 @@ need_to_update_rrset(void* nd, void* cd, time_t timenow, int equal, int ns)
if( newd->trust > cached->trust ) {
/* if the cached rrset is bogus, and new is equal,
* do not update the TTL - let it expire. */
if(equal && cached->ttl >= timenow &&
if(equal && !TTL_IS_EXPIRED(cached->ttl, timenow) &&
cached->security == sec_status_bogus)
return 0;
/* ghost-domain: never let an NS overwrite extend lifetime
* past the entry it replaces, regardless of trust. */
/* Also for A/AAAA and it is glue. */
if((ns ||
(a_aaaa && cached->trust==rrset_trust_add_noAA))
&& !TTL_IS_EXPIRED(cached->ttl, timenow) &&
newd->ttl > cached->ttl) {
size_t i;
if(a_aaaa) newd->trust=rrset_trust_add_noAA;
newd->ttl = cached->ttl;
for(i=0; i<(newd->count+newd->rrsig_count); i++)
if(newd->rr_ttl[i] > newd->ttl)
newd->rr_ttl[i] = newd->ttl;
}
return 1;
}
/* o item in cache has expired */
if( cached->ttl < timenow )
if( TTL_IS_EXPIRED(cached->ttl, timenow) )
return 1;
/* o same trust, but different in data - insert it */
if( newd->trust == cached->trust && !equal ) {
@@ -199,6 +215,13 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
int equal = 0;
log_assert(ref->id != 0 && k->id != 0);
log_assert(k->rk.dname != NULL);
if((k->rk.flags&PACKED_RRSET_0TTL_GRACE) !=0) {
log_nametypeclass(VERB_ALGO, "rrset store of PACKED_RRSET_0TTL_GRACE rrset skipped", k->rk.dname, rrset_type, ntohs(k->rk.rrset_class));
ub_packed_rrset_parsedelete(k, alloc);
return 0; /* Do not store 0TTL items after apply of
the grace ttl amount.
This means the ref was not changed by the call. */
}
/* looks up item with a readlock - no editing! */
if((e=slabhash_lookup(&r->table, h, k, 0)) != 0) {
/* return id and key as they will be used in the cache
@@ -213,7 +236,8 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
equal = rrsetdata_equal((struct packed_rrset_data*)k->entry.
data, (struct packed_rrset_data*)e->data);
if(!need_to_update_rrset(k->entry.data, e->data, timenow,
equal, (rrset_type==LDNS_RR_TYPE_NS))) {
equal, (rrset_type==LDNS_RR_TYPE_NS),
(rrset_type==LDNS_RR_TYPE_A || rrset_type==LDNS_RR_TYPE_AAAA))) {
/* cache is superior, return that value */
lock_rw_unlock(&e->lock);
ub_packed_rrset_parsedelete(k, alloc);
@@ -245,12 +269,45 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
return 0;
}
/** See if the name is a within signer authority */
static int
dname_subdomain_rrsig_signers(uint8_t* dname,
struct ub_packed_rrset_key* rrset)
{
struct packed_rrset_data* d = (struct packed_rrset_data*)
rrset->entry.data;
size_t i;
if(!d || !d->rrsig_count)
return 0;
for(i=0; i<d->rrsig_count; i++) {
uint8_t* sname = NULL;
size_t slen = 0;
rrsig_get_signer(d->rr_data[d->count+i], d->rr_len[d->count+i],
&sname, &slen);
if(!sname || !slen)
return 0; /* malformed */
if(!dname_subdomain_c(dname, sname))
return 0; /* not a subdomain */
}
return 1;
}
void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
struct ub_packed_rrset_key* rrset, uint8_t* ce, size_t ce_len,
struct alloc_cache* alloc, time_t timenow)
{
struct rrset_ref ref;
uint8_t wc_dname[LDNS_MAX_DOMAINLEN+3];
uint8_t* new_dname;
size_t new_dname_len;
/* See if the RRSIG signer name allows this wildcard,
* the new rrset should fall within the zone of the RRSIG signer(s). */
if(!dname_subdomain_rrsig_signers(ce, rrset)) {
verbose(VERB_ALGO, "wildcard canonical parent outside signer authority");
return;
}
rrset = packed_rrset_copy_alloc(rrset, alloc, timenow);
if(!rrset) {
log_err("malloc failure in rrset_cache_update_wildcard");
@@ -262,14 +319,16 @@ void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
wc_dname[1] = (uint8_t)'*';
memmove(wc_dname+2, ce, ce_len);
free(rrset->rk.dname);
rrset->rk.dname_len = ce_len + 2;
rrset->rk.dname = (uint8_t*)memdup(wc_dname, rrset->rk.dname_len);
if(!rrset->rk.dname) {
alloc_special_release(alloc, rrset);
new_dname_len = ce_len + 2;
new_dname = (uint8_t*)memdup(wc_dname, new_dname_len);
if(!new_dname) {
ub_packed_rrset_parsedelete(rrset, alloc);
log_err("memdup failure in rrset_cache_update_wildcard");
return;
}
free(rrset->rk.dname);
rrset->rk.dname = new_dname;
rrset->rk.dname_len = new_dname_len;
rrset->entry.hash = rrset_key_hash(&rrset->rk);
ref.key = rrset;
@@ -278,6 +337,10 @@ void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
(void)rrset_cache_update(rrset_cache, &ref, alloc, timenow);
}
/** Grace period in seconds for TTL=0 DNAME rrsets (RFC 2308: do not cache).
* Allows synthesis from cache within this window to reduce recursion load. */
#define DNAME_TTL0_GRACE_SECONDS 1
struct ub_packed_rrset_key*
rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen,
uint16_t qtype, uint16_t qclass, uint32_t flags, time_t timenow,
@@ -300,27 +363,36 @@ rrset_cache_lookup(struct rrset_cache* r, uint8_t* qname, size_t qnamelen,
/* check TTL */
struct packed_rrset_data* data =
(struct packed_rrset_data*)e->data;
if(timenow > data->ttl) {
lock_rw_unlock(&e->lock);
return NULL;
struct ub_packed_rrset_key* k = (struct ub_packed_rrset_key*)e->key;
if(TTL_IS_EXPIRED(data->ttl, timenow)) {
/* Allow TTL=0 DNAME within grace period for synthesis */
if(qtype == LDNS_RR_TYPE_DNAME &&
(k->rk.flags & PACKED_RRSET_UPSTREAM_0TTL) &&
(timenow - data->ttl_add) <= DNAME_TTL0_GRACE_SECONDS) {
/* within grace: allow for synthesis */
} else {
lock_rw_unlock(&e->lock);
return NULL;
}
}
/* we're done */
return (struct ub_packed_rrset_key*)e->key;
return k;
}
return NULL;
}
int
int
rrset_array_lock(struct rrset_ref* ref, size_t count, time_t timenow)
{
size_t i;
struct packed_rrset_data* d;
for(i=0; i<count; i++) {
if(i>0 && ref[i].key == ref[i-1].key)
continue; /* only lock items once */
lock_rw_rdlock(&ref[i].key->entry.lock);
if(ref[i].id != ref[i].key->id || timenow >
((struct packed_rrset_data*)(ref[i].key->entry.data))
->ttl) {
d = ref[i].key->entry.data;
if(ref[i].id != ref[i].key->id ||
TTL_IS_EXPIRED(d->ttl, timenow)) {
/* failure! rollback our readlocks */
rrset_array_unlock(ref, i+1);
return 0;
@@ -511,7 +583,7 @@ rrset_cache_expired_above(struct rrset_cache* r, uint8_t** qname, size_t*
*qnamelen, searchtype, qclass, 0, 0, 0))) {
struct packed_rrset_data* data =
(struct packed_rrset_data*)rrset->entry.data;
if(now > data->ttl) {
if(TTL_IS_EXPIRED(data->ttl, now)) {
/* it is expired, this is not wanted */
lock_rw_unlock(&rrset->entry.lock);
log_nametypeclass(VERB_ALGO, "this rrset is expired", *qname, searchtype, qclass);
+203 -105
View File
@@ -42,7 +42,6 @@
#ifdef HAVE_SYS_TYPES_H
# include <sys/types.h>
#endif
#include <sys/time.h>
#include <limits.h>
#ifdef USE_TCP_FASTOPEN
#include <netinet/tcp.h>
@@ -1126,7 +1125,7 @@ make_sock_port(int stype, const char* ifname, int port,
int use_systemd, int dscp, struct unbound_socket* ub_sock,
const char* additional)
{
char* s = strchr(ifname, '@');
const char* s = strchr(ifname, '@');
if(s) {
/* override port with ifspec@port */
int port;
@@ -1342,13 +1341,33 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if((is_doq) && !(is_https || is_ssl)) do_tcp = 0;
if(do_auto) {
enum listen_type auto_port_type;
ub_sock = calloc(1, sizeof(struct unbound_socket));
if(!ub_sock)
return 0;
if(is_dnscrypt) {
auto_port_type = listen_type_udpancil_dnscrypt;
add = "udpancil_dnscrypt";
} else if(is_doq) {
auto_port_type = listen_type_doq;
add = "doq";
if(if_listens_on(ifname, port, 53, NULL)) {
log_err("DNS over QUIC is strictly not "
"allowed on port 53 as per RFC 9250. "
"Port 53 is for DNS datagrams. Error "
"for interface '%s'.", ifname);
free(ub_sock->addr);
free(ub_sock);
return 0;
}
} else {
auto_port_type = listen_type_udpancil;
add = "udpancil";
}
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
&noip6, rcv, snd, reuseport, transparent,
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock,
(is_dnscrypt?"udpancil_dnscrypt":"udpancil"))) == -1) {
add)) == -1) {
free(ub_sock->addr);
free(ub_sock);
if(noip6) {
@@ -1367,9 +1386,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if (sock_queue_timeout && !set_recvtimestamp(s)) {
log_warn("socket timestamping is not available");
}
if(!port_insert(list, s, is_dnscrypt
?listen_type_udpancil_dnscrypt:listen_type_udpancil,
is_pp2, ub_sock)) {
if(!port_insert(list, s, auto_port_type, is_pp2, ub_sock)) {
sock_close(s);
free(ub_sock->addr);
free(ub_sock);
@@ -1564,7 +1581,7 @@ listen_create(struct comm_base* base, struct listen_port* ports,
cp = comm_point_create_udp(base, ports->fd,
front->udp_buff, ports->pp2_enabled, cb,
cb_arg, ports->socket);
} else if(ports->ftype == listen_type_doq) {
} else if(ports->ftype == listen_type_doq && doq_table) {
#ifndef HAVE_NGTCP2
log_warn("Unbound is not compiled with "
"ngtcp2. This is required to use DNS "
@@ -2167,7 +2184,8 @@ void tcp_req_info_clear(struct tcp_req_info* req)
open = req->open_req_list;
while(open) {
nopen = open->next;
mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp);
mesh_state_remove_reply(open->mesh, open->mesh_state, req->cp,
NULL, NULL);
free(open);
open = nopen;
}
@@ -2300,21 +2318,8 @@ int
tcp_req_info_handle_read_close(struct tcp_req_info* req)
{
verbose(VERB_ALGO, "tcp channel read side closed %d", req->cp->fd);
/* reset byte count for (potential) partial read */
req->cp->tcp_byte_count = 0;
/* if we still have results to write, pick up next and write it */
if(req->num_done_req != 0) {
tcp_req_pickup_next_result(req);
tcp_req_info_setup_listen(req);
return 1;
}
/* if nothing to do, this closes the connection */
if(req->num_open_req == 0 && req->num_done_req == 0)
return 0;
/* otherwise, we must be waiting for dns resolve, wait with timeout */
req->read_is_closed = 1;
tcp_req_info_setup_listen(req);
return 1;
/* RFC 7766 6.2.4 says to drop pending replies when client closes. */
return 0; /* drop connection */
}
void
@@ -2884,6 +2889,7 @@ submit_http_error:
sldns_buffer_flip(h2_stream->qbuffer);
h2_session->postpone_drop = 1;
query_read_done = http2_query_read_done(h2_session, h2_stream);
h2_session->postpone_drop = 0;
if(query_read_done < 0)
return NGHTTP2_ERR_CALLBACK_FAILURE;
else if(!query_read_done) {
@@ -2893,11 +2899,9 @@ submit_http_error:
* failure will result in reclaiming (and closing)
* of comm point. */
verbose(VERB_QUERY, "http2 query dropped in worker cb");
h2_session->postpone_drop = 0;
return NGHTTP2_ERR_CALLBACK_FAILURE;
}
/* nothing to submit right now, query added to mesh. */
h2_session->postpone_drop = 0;
return 0;
}
if(!http2_submit_dns_response(h2_session)) {
@@ -3275,14 +3279,18 @@ nghttp2_session_callbacks* http2_req_callbacks_create(void)
struct doq_table*
doq_table_create(struct config_file* cfg, struct ub_randstate* rnd)
{
struct doq_table* table = calloc(1, sizeof(*table));
struct doq_table* table;
if (!cfg->quic_port)
return NULL;
table = calloc(1, sizeof(*table));
if(!table)
return NULL;
#ifdef USE_NGTCP2_CRYPTO_OSSL
/* Initialize the ossl crypto, it is harmless to call twice,
* and this is before use of doq connections. */
if(ngtcp2_crypto_ossl_init() != 0) {
log_err("ngtcp2_crypto_oss_init failed");
log_err("ngtcp2_crypto_ossl_init failed");
free(table);
return NULL;
}
@@ -3354,7 +3362,7 @@ conn_tree_del(rbnode_type* node, void* arg)
{
struct doq_table* table = (struct doq_table*)arg;
struct doq_conn* conn;
if(!node)
if(!node || !table)
return;
conn = (struct doq_conn*)node->key;
if(conn->timer.timer_in_list) {
@@ -3409,13 +3417,13 @@ doq_table_delete(struct doq_table* table)
}
struct doq_timer*
doq_timer_find_time(struct doq_table* table, struct timeval* tv)
doq_timer_find_time(struct doq_table* table, ngtcp2_tstamp ts)
{
struct doq_timer key;
struct rbnode_type* node;
log_assert(table != NULL);
memset(&key, 0, sizeof(key));
key.time.tv_sec = tv->tv_sec;
key.time.tv_usec = tv->tv_usec;
key.time_mono = ts;
node = rbtree_search(table->timer_tree, &key);
if(node)
return (struct doq_timer*)node->key;
@@ -3463,7 +3471,7 @@ doq_timer_list_remove(struct doq_table* table, struct doq_timer* timer)
if(!timer->timer_in_list)
return;
/* The item in the rbtree has the list start and end. */
rb_timer = doq_timer_find_time(table, &timer->time);
rb_timer = doq_timer_find_time(table, timer->time_mono);
if(rb_timer) {
if(timer->setlist_prev)
timer->setlist_prev->setlist_next = timer->setlist_next;
@@ -3509,7 +3517,8 @@ doq_timer_unset(struct doq_table* table, struct doq_timer* timer)
}
void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
struct doq_server_socket* worker_doq_socket, struct timeval* tv)
struct doq_server_socket* worker_doq_socket, struct timeval* tv,
ngtcp2_tstamp ts)
{
struct doq_timer* rb_timer;
if(verbosity >= VERB_ALGO && timer->conn) {
@@ -3523,14 +3532,14 @@ void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
(int)rel.tv_sec, (int)rel.tv_usec);
}
if(timer->timer_in_tree || timer->timer_in_list) {
if(timer->time.tv_sec == tv->tv_sec &&
timer->time.tv_usec == tv->tv_usec)
if(timer->time_mono == ts)
return; /* already set on that time */
doq_timer_unset(table, timer);
}
timer->time.tv_sec = tv->tv_sec;
timer->time.tv_usec = tv->tv_usec;
rb_timer = doq_timer_find_time(table, tv);
timer->time_real.tv_sec = tv->tv_sec;
timer->time_real.tv_usec = tv->tv_usec;
timer->time_mono = ts;
rb_timer = doq_timer_find_time(table, ts);
if(rb_timer) {
/* There is a timeout already with this value. Timer is
* added to the setlist. */
@@ -3606,15 +3615,29 @@ doq_conn_create(struct comm_point* c, struct doq_pkt_addr* paddr,
return conn;
}
/** The arguments for doq stream tree del. */
struct doq_stream_tree_del_args {
/** The doq table. */
struct doq_table* table;
/** The doq connection for the stream. */
struct doq_conn* conn;
};
/** delete stream tree node */
static void
stream_tree_del(rbnode_type* node, void* arg)
{
struct doq_table* table = (struct doq_table*)arg;
struct doq_stream_tree_del_args* args = (struct doq_stream_tree_del_args*)arg;
struct doq_table* table = args->table;
struct doq_stream* stream;
if(!node)
return;
stream = (struct doq_stream*)node;
if(stream->mesh_state) {
mesh_state_remove_reply(stream->mesh, stream->mesh_state,
args->conn->doq_socket->cp, NULL, stream);
stream->mesh_state = NULL;
}
if(stream->in)
doq_table_quic_size_subtract(table, stream->inlen);
if(stream->out)
@@ -3634,9 +3657,14 @@ doq_conn_delete(struct doq_conn* conn, struct doq_table* table)
lock_rw_unlock(&conn->table->conid_lock);
/* Remove the app data from ngtcp2 before SSL_free of conn->ssl,
* because the ngtcp2 conn is deleted. */
SSL_set_app_data(conn->ssl, NULL);
if(conn->ssl)
SSL_set_app_data(conn->ssl, NULL);
if(conn->stream_tree.count != 0) {
traverse_postorder(&conn->stream_tree, stream_tree_del, table);
struct doq_stream_tree_del_args args;
memset(&args, 0, sizeof(args));
args.table = table;
args.conn = conn;
traverse_postorder(&conn->stream_tree, stream_tree_del, &args);
}
free(conn->key.dcid);
SSL_free(conn->ssl);
@@ -3709,13 +3737,9 @@ int doq_timer_cmp(const void* key1, const void* key2)
{
struct doq_timer* e = (struct doq_timer*)key1;
struct doq_timer* f = (struct doq_timer*)key2;
if(e->time.tv_sec < f->time.tv_sec)
if(e->time_mono < f->time_mono)
return -1;
if(e->time.tv_sec > f->time.tv_sec)
return 1;
if(e->time.tv_usec < f->time.tv_usec)
return -1;
if(e->time.tv_usec > f->time.tv_usec)
if(e->time_mono > f->time_mono)
return 1;
return 0;
}
@@ -3776,7 +3800,7 @@ doq_repinfo_retrieve_localaddr(struct comm_reply* repinfo,
memset(sa6, 0, *localaddrlen);
sa6->sin6_family = AF_INET6;
memmove(&sa6->sin6_addr, &repinfo->pktinfo.v6info.ipi6_addr,
*localaddrlen);
sizeof(struct in6_addr));
sa6->sin6_port = repinfo->doq_srcport;
#endif
} else {
@@ -3786,7 +3810,7 @@ doq_repinfo_retrieve_localaddr(struct comm_reply* repinfo,
memset(sa, 0, *localaddrlen);
sa->sin_family = AF_INET;
memmove(&sa->sin_addr, &repinfo->pktinfo.v4info.ipi_addr,
*localaddrlen);
sizeof(struct in_addr));
sa->sin_port = repinfo->doq_srcport;
#elif defined(IP_RECVDSTADDR)
struct sockaddr_in* sa = (struct sockaddr_in*)localaddr;
@@ -3949,6 +3973,11 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
if(stream->is_closed)
return 1;
stream->is_closed = 1;
if(stream->mesh_state) {
mesh_state_remove_reply(stream->mesh, stream->mesh_state,
conn->doq_socket->cp, NULL, stream);
stream->mesh_state = NULL;
}
doq_stream_off_write_list(conn, stream);
if(send_shutdown) {
verbose(VERB_ALGO, "doq: shutdown stream_id %d with app_error_code %d",
@@ -3978,7 +4007,8 @@ doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
/** doq stream pick up answer data from buffer */
static int
doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf)
doq_stream_pickup_answer(struct doq_conn* conn, struct doq_stream* stream,
struct sldns_buffer* buf)
{
stream->is_answer_available = 1;
if(stream->out) {
@@ -3988,6 +4018,11 @@ doq_stream_pickup_answer(struct doq_stream* stream, struct sldns_buffer* buf)
}
stream->nwrite = 0;
stream->outlen = sldns_buffer_limit(buf);
if(!doq_table_quic_size_available(conn->doq_socket->table,
conn->doq_socket->cfg, stream->outlen)) {
verbose(VERB_ALGO, "doq stream: no space for reply length");
return 0;
}
/* For quic the output bytes have to stay allocated and available,
* for potential resends, until the remote end has acknowledged them.
* This includes the tcplen start uint16_t, in outlen_wire. */
@@ -4014,24 +4049,56 @@ doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
if(stream->out)
doq_table_quic_size_subtract(conn->doq_socket->table,
stream->outlen);
if(!doq_stream_pickup_answer(stream, buf))
if(!doq_stream_pickup_answer(conn, stream, buf))
return 0;
doq_table_quic_size_add(conn->doq_socket->table, stream->outlen);
doq_stream_on_write_list(conn, stream);
doq_conn_write_enable(conn);
return 1;
}
#endif /* HAVE_NGTCP2 */
void
doq_stream_add_meshstate(struct doq_stream* stream,
struct mesh_area* mesh, struct mesh_state* m)
{
#ifdef HAVE_NGTCP2
stream->mesh = mesh;
stream->mesh_state = m;
#else
(void)stream; (void)mesh; (void)m;
#endif
}
void
doq_stream_remove_mesh_state(struct doq_stream* stream)
{
#ifdef HAVE_NGTCP2
if(!stream)
return;
stream->mesh_state = NULL;
#else
(void)stream;
#endif
}
#ifdef HAVE_NGTCP2
/** doq stream data length has completed, allocations can be done. False on
* allocation failure. */
static int
doq_stream_datalen_complete(struct doq_stream* stream, struct doq_table* table)
doq_stream_datalen_complete(struct doq_conn* conn, struct doq_stream* stream,
struct doq_table* table)
{
if(stream->inlen > 1024*1024) {
log_err("doq stream in length too large %d",
(int)stream->inlen);
return 0;
}
if(!doq_table_quic_size_available(table, conn->doq_socket->cfg,
stream->inlen)) {
verbose(VERB_ALGO, "doq stream: no space for query length");
return 0;
}
stream->in = calloc(1, stream->inlen);
if(!stream->in) {
log_err("doq could not read stream, calloc failed: "
@@ -4076,6 +4143,7 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream)
return 0;
}
c->repinfo.doq_streamid = stream->stream_id;
c->repinfo.doq_stream = stream;
conn->doq_socket->current_conn = conn;
fptr_ok(fptr_whitelist_comm_point(c->callback));
if( (*c->callback)(c, c->cb_arg, NETEVENT_NOERROR, &c->repinfo)) {
@@ -4092,8 +4160,9 @@ doq_stream_data_complete(struct doq_conn* conn, struct doq_stream* stream)
/** doq receive data for a stream, more bytes of the incoming data */
static int
doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data,
size_t datalen, int* recv_done, struct doq_table* table)
doq_stream_recv_data(struct doq_conn* conn, struct doq_stream* stream,
const uint8_t* data, size_t datalen, int* recv_done,
struct doq_table* table)
{
int got_data = 0;
/* read the tcplength uint16_t at the start */
@@ -4114,7 +4183,7 @@ doq_stream_recv_data(struct doq_stream* stream, const uint8_t* data,
if(stream->nread == 2) {
/* the initial length value is completed */
stream->inlen = ntohs(tcplen);
if(!doq_stream_datalen_complete(stream, table))
if(!doq_stream_datalen_complete(conn, stream, table))
return 0;
} else {
/* store for later */
@@ -4263,12 +4332,11 @@ doq_submit_new_token(struct doq_conn* conn)
ngtcp2_ssize tokenlen;
int ret;
const ngtcp2_path* path = ngtcp2_conn_get_path(conn->conn);
ngtcp2_tstamp ts = doq_get_timestamp_nanosec();
tokenlen = ngtcp2_crypto_generate_regular_token(token,
conn->doq_socket->static_secret,
conn->doq_socket->static_secret_len, path->remote.addr,
path->remote.addrlen, ts);
path->remote.addrlen, doq_get_timestamp_nanosec());
if(tokenlen < 0) {
log_err("doq ngtcp2_crypto_generate_regular_token failed");
return 1;
@@ -4331,8 +4399,7 @@ doq_stream_open_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
verbose(VERB_ALGO, "doq: stream with this id already exists");
return 0;
}
if(stream_id != 0 && stream_id != 4 && /* allow one stream on a new connection */
!doq_table_quic_size_available(doq_conn->doq_socket->table,
if(!doq_table_quic_size_available(doq_conn->doq_socket->table,
doq_conn->doq_socket->cfg, sizeof(*stream)
+ 100 /* estimated query in */
+ 512 /* estimated response out */
@@ -4390,8 +4457,8 @@ doq_recv_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn), uint32_t flags,
return 0;
}
if(datalen != 0) {
if(!doq_stream_recv_data(stream, data, datalen, &recv_done,
doq_conn->doq_socket->table))
if(!doq_stream_recv_data(doq_conn, stream, data, datalen,
&recv_done, doq_conn->doq_socket->table))
return NGTCP2_ERR_CALLBACK_FAILURE;
}
if((flags&NGTCP2_STREAM_DATA_FLAG_FIN)!=0) {
@@ -4460,6 +4527,29 @@ doq_stream_reset_cb(ngtcp2_conn* ATTR_UNUSED(conn), int64_t stream_id,
return 0;
}
/** ngtcp2 extend_max_stream_data function */
int doq_extend_max_stream_data_cb(ngtcp2_conn* ATTR_UNUSED(conn),
int64_t stream_id, uint64_t max_data, void* user_data,
void* ATTR_UNUSED(stream_user_data))
{
struct doq_conn* doq_conn = (struct doq_conn*)user_data;
struct doq_stream* stream;
verbose(VERB_ALGO, "doq extend_max_stream_data stream id %d "
"max_data %d ", (int)stream_id, (int)max_data);
if(max_data == 0)
return 0;
stream = doq_stream_find(doq_conn, stream_id);
if(!stream) {
verbose(VERB_ALGO, "doq: unknown stream %d", (int)stream_id);
return 0;
}
if(!stream->is_answer_available)
return 0;
doq_stream_on_write_list(doq_conn, stream);
doq_conn_write_enable(doq_conn);
return 0;
}
/** ngtcp2 acked_stream_data_offset callback function */
static int
doq_acked_stream_data_offset_cb(ngtcp2_conn* ATTR_UNUSED(conn),
@@ -4780,7 +4870,7 @@ doq_ssl_server_setup(SSL_CTX* ctx, struct doq_conn* conn)
SSL_set_app_data(ssl, conn);
#endif
SSL_set_accept_state(ssl);
#ifdef USE_NGTCP2_CRYPTO_OSSL
#ifdef HAVE_SSL_SET_QUIC_TLS_EARLY_DATA_ENABLED
SSL_set_quic_tls_early_data_enabled(ssl, 1);
#else
SSL_set_quic_early_data_enabled(ssl, 1);
@@ -4834,6 +4924,7 @@ doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen,
callbacks.stream_open = doq_stream_open_cb;
callbacks.stream_close = doq_stream_close_cb;
callbacks.stream_reset = doq_stream_reset_cb;
callbacks.extend_max_stream_data = doq_extend_max_stream_data_cb;
callbacks.acked_stream_data_offset = doq_acked_stream_data_offset_cb;
callbacks.recv_stream_data = doq_recv_stream_data_cb;
@@ -4888,6 +4979,7 @@ doq_conn_setup(struct doq_conn* conn, uint8_t* scid, size_t scidlen,
rv = ngtcp2_conn_server_new(&conn->conn, &scid_cid, &sv_scid, &path,
conn->version, &callbacks, &settings, &params, NULL, conn);
if(rv != 0) {
conn->conn = NULL;
lock_rw_unlock(&conn->table->conid_lock);
log_err("ngtcp2_conn_server_new failed: %s",
ngtcp2_strerror(rv));
@@ -4922,6 +5014,7 @@ doq_conid_find(struct doq_table* table, const uint8_t* data, size_t datalen)
key.node.key = &key;
key.cid = (void*)data;
key.cidlen = datalen;
log_assert(table != NULL);
node = rbtree_search(table->conid_tree, &key);
if(node)
return (struct doq_conid*)node->key;
@@ -5109,23 +5202,30 @@ doq_conn_clear_conids(struct doq_conn* conn)
ngtcp2_tstamp doq_get_timestamp_nanosec(void)
{
#ifdef CLOCK_REALTIME
struct timespec tp;
memset(&tp, 0, sizeof(tp));
/* Get a nanosecond time, that can be compared with the event base. */
if(clock_gettime(CLOCK_REALTIME, &tp) == -1) {
log_err("clock_gettime failed: %s", strerror(errno));
#ifdef CLOCK_BOOTTIME
if(clock_gettime(CLOCK_BOOTTIME, &tp) == -1) {
#endif
if(clock_gettime(CLOCK_MONOTONIC, &tp) == -1) {
log_err("clock_gettime failed: %s", strerror(errno));
}
#ifdef CLOCK_BOOTTIME
}
#endif
return ((uint64_t)tp.tv_sec)*((uint64_t)1000000000) +
((uint64_t)tp.tv_nsec);
#else
}
static struct timeval doq_get_timevalue(void)
{
struct timeval tv;
memset(&tv, 0, sizeof(tv));
if(gettimeofday(&tv, NULL) < 0) {
log_err("gettimeofday failed: %s", strerror(errno));
memset(&tv, 0, sizeof(tv));
}
return ((uint64_t)tv.tv_sec)*((uint64_t)1000000000) +
((uint64_t)tv.tv_usec)*((uint64_t)1000);
#endif /* CLOCK_REALTIME */
return tv;
}
/** doq start the closing period for the connection. */
@@ -5248,18 +5348,17 @@ doq_conn_recv(struct comm_point* c, struct doq_pkt_addr* paddr,
int* err_drop)
{
int ret;
ngtcp2_tstamp ts;
struct ngtcp2_path path;
memset(&path, 0, sizeof(path));
path.remote.addr = (struct sockaddr*)&paddr->addr;
path.remote.addrlen = paddr->addrlen;
path.local.addr = (struct sockaddr*)&paddr->localaddr;
path.local.addrlen = paddr->localaddrlen;
ts = doq_get_timestamp_nanosec();
ret = ngtcp2_conn_read_pkt(conn->conn, &path, pi,
sldns_buffer_begin(c->doq_socket->pkt_buf),
sldns_buffer_limit(c->doq_socket->pkt_buf), ts);
sldns_buffer_limit(c->doq_socket->pkt_buf),
doq_get_timestamp_nanosec());
if(ret != 0) {
if(err_retry)
*err_retry = 0;
@@ -5347,7 +5446,6 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
{
struct doq_stream* stream = conn->stream_write_first;
ngtcp2_path_storage ps;
ngtcp2_tstamp ts = doq_get_timestamp_nanosec();
size_t num_packets = 0, max_packets = 65535;
ngtcp2_path_storage_zero(&ps);
@@ -5400,7 +5498,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
ret = ngtcp2_conn_writev_stream(conn->conn, &ps.path, &pi,
sldns_buffer_begin(c->doq_socket->pkt_buf),
sldns_buffer_remaining(c->doq_socket->pkt_buf),
&ndatalen, flags, stream_id, datav, datav_count, ts);
&ndatalen, flags, stream_id, datav, datav_count,
doq_get_timestamp_nanosec());
if(ret < 0) {
if(ret == NGTCP2_ERR_WRITE_MORE) {
verbose(VERB_ALGO, "doq: write more, ndatalen %d", (int)ndatalen);
@@ -5415,26 +5514,20 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
continue;
} else if(ret == NGTCP2_ERR_STREAM_DATA_BLOCKED) {
verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_DATA_BLOCKED");
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
ngtcp2_ccerr_set_application_error(
&conn->ccerr, -1, NULL, 0);
#else
ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0);
#endif
if(err_drop)
*err_drop = 0;
if(!doq_conn_close_error(c, conn)) {
if(err_drop)
*err_drop = 1;
if(stream) {
doq_stream_off_write_list(conn, stream);
stream = stream->write_next;
continue;
} else {
break;
}
return 0;
} else if(ret == NGTCP2_ERR_STREAM_SHUT_WR) {
verbose(VERB_ALGO, "doq: ngtcp2_conn_writev_stream returned NGTCP2_ERR_STREAM_SHUT_WR");
#ifdef HAVE_NGTCP2_CCERR_DEFAULT
ngtcp2_ccerr_set_application_error(
&conn->ccerr, -1, NULL, 0);
&conn->ccerr, DOQ_APP_ERROR_CODE, NULL, 0);
#else
ngtcp2_connection_close_error_set_application_error(&conn->last_error, -1, NULL, 0);
ngtcp2_connection_close_error_set_application_error(&conn->last_error, DOQ_APP_ERROR_CODE, NULL, 0);
#endif
if(err_drop)
*err_drop = 0;
@@ -5472,7 +5565,8 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
if(ret == 0) {
/* congestion limited */
doq_conn_write_disable(conn);
ngtcp2_conn_update_pkt_tx_time(conn->conn, ts);
ngtcp2_conn_update_pkt_tx_time(conn->conn,
doq_get_timestamp_nanosec());
return 1;
}
sldns_buffer_set_position(c->doq_socket->pkt_buf, ret);
@@ -5486,7 +5580,7 @@ doq_conn_write_streams(struct comm_point* c, struct doq_conn* conn,
if(stream)
stream = stream->write_next;
}
ngtcp2_conn_update_pkt_tx_time(conn->conn, ts);
ngtcp2_conn_update_pkt_tx_time(conn->conn, doq_get_timestamp_nanosec());
return 1;
}
@@ -5563,32 +5657,35 @@ doq_table_pop_first(struct doq_table* table)
}
int
doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv)
doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv, ngtcp2_tstamp* ts)
{
ngtcp2_tstamp expiry = ngtcp2_conn_get_expiry(conn->conn);
ngtcp2_tstamp now = doq_get_timestamp_nanosec();
ngtcp2_tstamp doq_expiry = ngtcp2_conn_get_expiry(conn->conn);
ngtcp2_tstamp doq_now = doq_get_timestamp_nanosec();
ngtcp2_tstamp t;
struct timeval now = doq_get_timevalue();
if(expiry <= now) {
if(doq_expiry <= doq_now || doq_expiry == UINT64_MAX) {
/* UINT64_MAX means there is no next expiry. */
/* The timer has already expired, add with zero timeout.
* This should call the callback straight away. Calling it
* from the event callbacks is cleaner than calling it here,
* because then it is always called with the same locks and
* so on. This routine only has the conn.lock. */
t = now;
t = doq_now;
memcpy(tv, &now, sizeof(*tv));
} else {
t = expiry;
t = doq_expiry;
memset(tv, 0, sizeof(*tv));
tv->tv_sec = (doq_expiry - doq_now) / NGTCP2_SECONDS;
tv->tv_usec = ((doq_expiry - doq_now) / NGTCP2_MICROSECONDS)%1000000;
timeval_add(tv, &now);
}
/* convert to timeval */
memset(tv, 0, sizeof(*tv));
tv->tv_sec = t / NGTCP2_SECONDS;
tv->tv_usec = (t / NGTCP2_MICROSECONDS)%1000000;
*ts = t;
/* If we already have a timer, is it the right value? */
if(conn->timer.timer_in_tree || conn->timer.timer_in_list) {
if(conn->timer.time.tv_sec == tv->tv_sec &&
conn->timer.time.tv_usec == tv->tv_usec)
if(conn->timer.time_mono == *ts)
return 0;
}
return 1;
@@ -5609,13 +5706,12 @@ doq_conn_log_line(struct doq_conn* conn, char* s)
int
doq_conn_handle_timeout(struct doq_conn* conn)
{
ngtcp2_tstamp now = doq_get_timestamp_nanosec();
int rv;
if(verbosity >= VERB_ALGO)
doq_conn_log_line(conn, "timeout");
rv = ngtcp2_conn_handle_expiry(conn->conn, now);
rv = ngtcp2_conn_handle_expiry(conn->conn, doq_get_timestamp_nanosec());
if(rv != 0) {
verbose(VERB_ALGO, "ngtcp2_conn_handle_expiry failed: %s",
ngtcp2_strerror(rv));
@@ -5662,6 +5758,8 @@ doq_table_quic_size_available(struct doq_table* table,
struct config_file* cfg, size_t mem)
{
size_t cur;
if (!table)
return 0;
lock_basic_lock(&table->size_lock);
cur = table->current_size;
lock_basic_unlock(&table->size_lock);
+29 -8
View File
@@ -61,6 +61,8 @@ struct config_file;
struct addrinfo;
struct sldns_buffer;
struct tcl_list;
struct mesh_area;
struct mesh_state;
/**
* Listening for queries structure.
@@ -538,8 +540,11 @@ void doq_table_delete(struct doq_table* table);
struct doq_timer {
/** The rbnode in the tree sorted by timeout value. Key this struct. */
struct rbnode_type node;
/** The timeout value. Monotonic value used with ngtcp2.
* This time value is used for the tree operations. */
ngtcp2_tstamp time_mono;
/** The timeout value. Absolute time value. */
struct timeval time;
struct timeval time_real;
/** If the timer is in the time tree, with the node. */
int timer_in_tree;
/** If there are more timers with the exact same timeout value,
@@ -689,6 +694,11 @@ struct doq_stream {
uint8_t* out;
/** if the stream is on the write list */
uint8_t on_write_list;
/** The mesh area and mesh state, set when this stream's query was
* dispatched into the mesh; used to detach the reply on stream close */
struct mesh_area* mesh;
/** the mesh state for the query, is nonNULL when there is one. */
struct mesh_state* mesh_state;
/** the prev and next on the write list, if on the list */
struct doq_stream* write_prev, *write_next;
};
@@ -791,7 +801,16 @@ int doq_stream_close(struct doq_conn* conn, struct doq_stream* stream,
/** send reply for a connection */
int doq_stream_send_reply(struct doq_conn* conn, struct doq_stream* stream,
struct sldns_buffer* buf);
#endif /* HAVE_NGTCP2 */
/** add mesh state to doq stream */
void doq_stream_add_meshstate(struct doq_stream* stream,
struct mesh_area* mesh, struct mesh_state* m);
/** remove mesh state from doq stream */
void doq_stream_remove_mesh_state(struct doq_stream* stream);
#ifdef HAVE_NGTCP2
/** the connection has write interest, wants to write packets */
void doq_conn_write_enable(struct doq_conn* conn);
@@ -813,10 +832,12 @@ struct doq_conn* doq_table_pop_first(struct doq_table* table);
* doq check if the timer for the conn needs to be changed.
* @param conn: connection, caller must hold lock on it.
* @param tv: time value, absolute time, returned.
* @param ts: time stamp, absolute time, returned.
* @return true if timer needs to be set to tv, false if no change is needed
* to the timer. The timer is already set to the right time in that case.
*/
int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv);
int doq_conn_check_timer(struct doq_conn* conn, struct timeval* tv,
ngtcp2_tstamp* ts);
/** doq remove timer from tree */
void doq_timer_tree_remove(struct doq_table* table, struct doq_timer* timer);
@@ -829,11 +850,12 @@ void doq_timer_unset(struct doq_table* table, struct doq_timer* timer);
/** doq set the timer and add it. */
void doq_timer_set(struct doq_table* table, struct doq_timer* timer,
struct doq_server_socket* worker_doq_socket, struct timeval* tv);
struct doq_server_socket* worker_doq_socket, struct timeval* tv,
ngtcp2_tstamp ts);
/** doq find a timeout in the timer tree */
struct doq_timer* doq_timer_find_time(struct doq_table* table,
struct timeval* tv);
ngtcp2_tstamp ts);
/** doq handle timeout for a connection. Pass conn locked. Returns false for
* deletion. */
@@ -851,6 +873,9 @@ int doq_table_quic_size_available(struct doq_table* table,
/** doq get the quic size value */
size_t doq_table_quic_size_get(struct doq_table* table);
/** get a timestamp in nanoseconds */
ngtcp2_tstamp doq_get_timestamp_nanosec(void);
#endif /* HAVE_NGTCP2 */
char* set_ip_dscp(int socket, int addrfamily, int ds);
@@ -866,8 +891,4 @@ void doq_client_event_cb(int fd, short event, void* arg);
/** timer event callback for testcode/doqclient */
void doq_client_timer_cb(int fd, short event, void* arg);
#ifdef HAVE_NGTCP2
/** get a timestamp in nanoseconds */
ngtcp2_tstamp doq_get_timestamp_nanosec(void);
#endif
#endif /* LISTEN_DNSPORT_H */
+162 -86
View File
@@ -56,6 +56,24 @@
* with 16 bytes for an A record, a 64K packet has about 4000 max */
#define LOCALZONE_RRSET_COUNT_MAX 4096
static const char* default_zones_reverse_array[] = {
"127.in-addr.arpa.", /* reverse ip4 zone */
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", /* reverse ip6 zone */
0
};
const char** local_zones_default_reverse = default_zones_reverse_array;
static const char* default_zones_special_array[] = {
"test.", /* RFC 6761 */
"invalid.", /* RFC 6761 */
"onion.", /* RFC 7686 */
"home.arpa.", /* RFC 8375 */
"resolver.arpa.", /* RFC 9462 */
"service.arpa.", /* RFC 9665 */
0
};
const char** local_zones_default_special = default_zones_special_array;
/** print all RRsets in local zone */
static void
local_zone_out(struct local_zone* z)
@@ -368,8 +386,6 @@ new_local_rrset(struct regional* region, struct local_data* node,
log_err("out of memory");
return NULL;
}
rrset->next = node->rrsets;
node->rrsets = rrset;
rrset->rrset = (struct ub_packed_rrset_key*)
regional_alloc_zero(region, sizeof(*rrset->rrset));
if(!rrset->rrset) {
@@ -390,6 +406,8 @@ new_local_rrset(struct regional* region, struct local_data* node,
rrset->rrset->rk.dname_len = node->namelen;
rrset->rrset->rk.type = htons(rrtype);
rrset->rrset->rk.rrset_class = htons(rrclass);
rrset->next = node->rrsets;
node->rrsets = rrset;
return rrset;
}
@@ -413,6 +431,10 @@ rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
pd->rr_ttl = regional_alloc(region, sizeof(*pd->rr_ttl)*pd->count);
pd->rr_data = regional_alloc(region, sizeof(*pd->rr_data)*pd->count);
if(!pd->rr_len || !pd->rr_ttl || !pd->rr_data) {
pd->count--;
pd->rr_len = oldlen;
pd->rr_ttl = oldttl;
pd->rr_data = olddata;
log_err("out of memory");
return 0;
}
@@ -428,6 +450,10 @@ rrset_insert_rr(struct regional* region, struct packed_rrset_data* pd,
pd->rr_ttl[0] = ttl;
pd->rr_data[0] = regional_alloc_init(region, rdata, rdata_len);
if(!pd->rr_data[0]) {
pd->count--;
pd->rr_len = oldlen;
pd->rr_ttl = oldttl;
pd->rr_data = olddata;
log_err("out of memory");
return 0;
}
@@ -650,10 +676,12 @@ lz_enter_rr_str(struct local_zones* zones, const char* rr)
}
labs = dname_count_size_labels(rr_name, &len);
lock_rw_rdlock(&zones->lock);
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type, 1);
if(!z) {
lock_rw_unlock(&zones->lock);
fatal_exit("internal error: no zone for rr %s", rr);
log_err("internal error: no zone for rr %s", rr);
free(rr_name);
return 0;
}
lock_rw_wrlock(&z->lock);
lock_rw_unlock(&zones->lock);
@@ -834,7 +862,7 @@ lz_nodefault(struct config_file* cfg, const char* name)
for(p = cfg->local_zones_nodefault; p; p = p->next) {
/* compare zone name, lowercase, compare without ending . */
if(strncasecmp(p->str, name, len) == 0 &&
if(strncasecmp(p->str, name, len) == 0 &&
(strlen(p->str) == len || (strlen(p->str)==len+1 &&
p->str[len] == '.')))
return 1;
@@ -842,6 +870,45 @@ lz_nodefault(struct config_file* cfg, const char* name)
return 0;
}
/** enter reverse default zone */
static int
add_reverse_default(struct local_zones* zones, struct config_file* cfg,
const char* name)
{
struct local_zone* z;
char str[1024]; /* known long enough */
if(lz_exists(zones, name) || lz_nodefault(cfg, name))
return 1; /* do not enter default content */
if(!(z=lz_enter_zone(zones, name, "static", LDNS_RR_CLASS_IN)))
return 0;
snprintf(str, sizeof(str), "%s 10800 IN SOA localhost. "
"nobody.invalid. 1 3600 1200 604800 10800", name);
if(!lz_enter_rr_into_zone(z, str)) {
lock_rw_unlock(&z->lock);
return 0;
}
snprintf(str, sizeof(str), "%s 10800 IN NS localhost. ", name);
if(!lz_enter_rr_into_zone(z, str)) {
lock_rw_unlock(&z->lock);
return 0;
}
if(strncasecmp("127.in-addr.arpa.", name, 17) == 0) {
if(!lz_enter_rr_into_zone(z,
"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
lock_rw_unlock(&z->lock);
return 0;
}
} else if(strncasecmp("1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", name, 73) == 0) {
snprintf(str, sizeof(str), "%s 10800 IN PTR localhost.", name);
if(!lz_enter_rr_into_zone(z, str)) {
lock_rw_unlock(&z->lock);
return 0;
}
}
lock_rw_unlock(&z->lock);
return 1;
}
/** enter (AS112) empty default zone */
static int
add_empty_default(struct local_zones* zones, struct config_file* cfg,
@@ -902,72 +969,23 @@ int local_zone_enter_defaults(struct local_zones* zones, struct config_file* cfg
}
lock_rw_unlock(&z->lock);
}
/* reverse ip4 zone */
if(!lz_exists(zones, "127.in-addr.arpa.") &&
!lz_nodefault(cfg, "127.in-addr.arpa.")) {
if(!(z=lz_enter_zone(zones, "127.in-addr.arpa.", "static",
LDNS_RR_CLASS_IN)) ||
!lz_enter_rr_into_zone(z,
"127.in-addr.arpa. 10800 IN NS localhost.") ||
!lz_enter_rr_into_zone(z,
"127.in-addr.arpa. 10800 IN SOA localhost. "
"nobody.invalid. 1 3600 1200 604800 10800") ||
!lz_enter_rr_into_zone(z,
"1.0.0.127.in-addr.arpa. 10800 IN PTR localhost.")) {
/* ip4 and ip6 reverse */
for(zstr = local_zones_default_reverse; *zstr; zstr++) {
if(!add_reverse_default(zones, cfg, *zstr)) {
log_err("out of memory adding default zone");
if(z) { lock_rw_unlock(&z->lock); }
return 0;
}
lock_rw_unlock(&z->lock);
}
/* reverse ip6 zone */
if(!lz_exists(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.") &&
!lz_nodefault(cfg, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.")) {
if(!(z=lz_enter_zone(zones, "1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa.", "static",
LDNS_RR_CLASS_IN)) ||
!lz_enter_rr_into_zone(z,
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN NS localhost.") ||
!lz_enter_rr_into_zone(z,
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN SOA localhost. "
"nobody.invalid. 1 3600 1200 604800 10800") ||
!lz_enter_rr_into_zone(z,
"1.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.0.ip6.arpa. 10800 IN PTR localhost.")) {
/* special-use zones */
for(zstr = local_zones_default_special; *zstr; zstr++) {
if(!add_empty_default(zones, cfg, *zstr)) {
log_err("out of memory adding default zone");
if(z) { lock_rw_unlock(&z->lock); }
return 0;
}
lock_rw_unlock(&z->lock);
}
/* home.arpa. zone (RFC 8375) */
if(!add_empty_default(zones, cfg, "home.arpa.")) {
log_err("out of memory adding default zone");
return 0;
}
/* resolver.arpa. zone (RFC 9462) */
if(!add_empty_default(zones, cfg, "resolver.arpa.")) {
log_err("out of memory adding default zone");
return 0;
}
/* service.arpa. zone (draft-ietf-dnssd-srp-25) */
if(!add_empty_default(zones, cfg, "service.arpa.")) {
log_err("out of memory adding default zone");
return 0;
}
/* onion. zone (RFC 7686) */
if(!add_empty_default(zones, cfg, "onion.")) {
log_err("out of memory adding default zone");
return 0;
}
/* test. zone (RFC 6761) */
if(!add_empty_default(zones, cfg, "test.")) {
log_err("out of memory adding default zone");
return 0;
}
/* invalid. zone (RFC 6761) */
if(!add_empty_default(zones, cfg, "invalid.")) {
log_err("out of memory adding default zone");
return 0;
}
/* block AS112 zones, unless asked not to */
if(!cfg->unblock_lan_zones) {
for(zstr = as112_zones; *zstr; zstr++) {
@@ -1062,14 +1080,15 @@ lz_setup_implicit(struct local_zones* zones, struct config_file* cfg)
labs = dname_count_size_labels(rr_name, &len);
lock_rw_rdlock(&zones->lock);
if(!local_zones_lookup(zones, rr_name, len, labs, rr_class,
rr_type)) {
rr_type, 1)) {
/* Check if there is a zone that this could go
* under but for different class; created zones are
* always for LDNS_RR_CLASS_IN. Create the zone with
* a different class but the same configured
* local_zone_type. */
struct local_zone* z = local_zones_lookup(zones,
rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type);
rr_name, len, labs, LDNS_RR_CLASS_IN, rr_type,
1);
if(z) {
uint8_t* name = memdup(z->name, z->namelen);
size_t znamelen = z->namelen;
@@ -1231,28 +1250,48 @@ local_zones_apply_cfg(struct local_zones* zones, struct config_file* cfg)
struct local_zone*
local_zones_lookup(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype)
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
int foradd)
{
return local_zones_tags_lookup(zones, name, len, labs,
dclass, dtype, NULL, 0, 1);
dclass, dtype, NULL, 0, 1, foradd);
}
struct local_zone*
local_zones_tags_lookup(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
uint8_t* taglist, size_t taglen, int ignoretags)
uint8_t* taglist, size_t taglen, int ignoretags, int foradd)
{
rbnode_type* res = NULL;
struct local_zone *result;
struct local_zone key;
int m;
/* for type DS use a zone higher when on a zonecut */
if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) {
dname_remove_label(&name, &len);
labs--;
}
key.node.key = &key;
key.dclass = dclass;
/* for type DS use a zone higher when on a zonecut */
if(dtype == LDNS_RR_TYPE_DS && !dname_is_root(name)) {
/* If this is at a zone cut, of a local-zone, and it is
* of type always_refuse. Then also refuse the type DS
* for it. That could make it DNSSEC bogus, but it is
* REFUSED anyway. It stops CNAME type answers in the
* type DS lookup. */
key.name = name;
key.namelen = len;
key.namelabs = labs;
/* For additions and removals, use the ordinary rule,
* to remove a label for type DS to locate the parent zone.
* That is where the DS RR needs to be put. */
if(!foradd &&
(result=(struct local_zone*)rbtree_search(
&zones->ztree, &key)) != NULL &&
result->type == local_zone_always_refuse) {
/* The type DS does not go up one label. */
return result;
} else {
dname_remove_label(&name, &len);
labs--;
}
}
key.name = name;
key.namelen = len;
key.namelabs = labs;
@@ -1471,8 +1510,10 @@ find_tag_datas(struct query_info* qinfo, struct config_strlist* list,
return 0; /* out of memory */
qinfo->local_alias->rrset =
regional_alloc_init(temp, r, sizeof(*r));
if(!qinfo->local_alias->rrset)
if(!qinfo->local_alias->rrset) {
qinfo->local_alias = NULL;
return 0; /* out of memory */
}
}
return result;
}
@@ -1538,13 +1579,17 @@ local_data_answer(struct local_zone* z, struct module_env* env,
return 0; /* out of memory */
qinfo->local_alias->rrset = regional_alloc_init(
temp, lr->rrset, sizeof(*lr->rrset));
if(!qinfo->local_alias->rrset)
if(!qinfo->local_alias->rrset) {
qinfo->local_alias = NULL;
return 0; /* out of memory */
}
qinfo->local_alias->rrset->rk.dname = qinfo->qname;
qinfo->local_alias->rrset->rk.dname_len = qinfo->qname_len;
get_cname_target(lr->rrset, &ctarget, &ctargetlen);
if(!ctargetlen)
if(!ctargetlen) {
qinfo->local_alias = NULL;
return 0; /* invalid cname */
}
if(dname_is_wild(ctarget)) {
/* synthesize cname target */
struct packed_rrset_data* d, *lr_d;
@@ -1573,8 +1618,10 @@ local_data_answer(struct local_zone* z, struct module_env* env,
sizeof(struct packed_rrset_data) + sizeof(size_t) +
sizeof(uint8_t*) + sizeof(time_t) + sizeof(uint16_t)
+ newtargetlen);
if(!d)
if(!d) {
qinfo->local_alias = NULL;
return 0; /* out of memory */
}
lr_d = (struct packed_rrset_data*)lr->rrset->entry.data;
qinfo->local_alias->rrset->entry.data = d;
d->ttl = lr_d->rr_ttl[0]; /* RFC6672-like behavior:
@@ -1621,7 +1668,7 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
struct local_data key;
struct local_data* ld = NULL;
struct local_rrset* lr = NULL;
if(z->type == local_zone_always_transparent || z->type == local_zone_block_a)
if(z->type == local_zone_always_transparent || z->type == local_zone_block_a || z->type == local_zone_block_aaaa)
return 1;
if(z->type != local_zone_transparent
&& z->type != local_zone_typetransparent
@@ -1632,7 +1679,9 @@ local_zone_does_not_cover(struct local_zone* z, struct query_info* qinfo,
key.namelen = qinfo->qname_len;
key.namelabs = labs;
ld = (struct local_data*)rbtree_search(&z->data, &key.node);
if(z->type == local_zone_transparent || z->type == local_zone_inform)
if(z->type == local_zone_transparent || z->type == local_zone_inform
|| z->type == local_zone_block_a_wdata
|| z->type == local_zone_block_aaaa_wdata)
return (ld == NULL);
if(ld)
lr = local_data_find_type(ld, qinfo->qtype, 1);
@@ -1698,7 +1747,8 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
|| lz_type == local_zone_always_transparent) {
/* no NODATA or NXDOMAINS for this zone type */
return 0;
} else if(lz_type == local_zone_block_a) {
} else if(lz_type == local_zone_block_a ||
lz_type == local_zone_block_a_wdata) {
/* Return NODATA for all A queries */
if(qinfo->qtype == LDNS_RR_TYPE_A) {
local_error_encode(qinfo, env, edns, repinfo, buf, temp,
@@ -1707,6 +1757,17 @@ local_zones_zone_answer(struct local_zone* z, struct module_env* env,
return 1;
}
return 0;
} else if(lz_type == local_zone_block_aaaa ||
lz_type == local_zone_block_aaaa_wdata) {
/* Return NODATA for all AAAA queries */
if(qinfo->qtype == LDNS_RR_TYPE_AAAA) {
local_error_encode(qinfo, env, edns, repinfo, buf, temp,
LDNS_RCODE_NOERROR, (LDNS_RCODE_NOERROR|BIT_AA),
LDNS_EDE_NONE, NULL);
return 1;
}
return 0;
} else if(lz_type == local_zone_always_null) {
/* 0.0.0.0 or ::0 or noerror/nodata for this zone type,
@@ -1863,7 +1924,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
if(view->local_zones &&
(z = local_zones_lookup(view->local_zones,
qinfo->qname, qinfo->qname_len, labs,
qinfo->qclass, qinfo->qtype))) {
qinfo->qclass, qinfo->qtype, 0))) {
lock_rw_rdlock(&z->lock);
lzt = z->type;
}
@@ -1875,7 +1936,10 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
lzt == local_zone_typetransparent ||
lzt == local_zone_inform ||
lzt == local_zone_always_transparent ||
lzt == local_zone_block_a) &&
lzt == local_zone_block_a ||
lzt == local_zone_block_aaaa ||
lzt == local_zone_block_a_wdata ||
lzt == local_zone_block_aaaa_wdata) &&
local_zone_does_not_cover(z, qinfo, labs)) {
lock_rw_unlock(&z->lock);
z = NULL;
@@ -1897,7 +1961,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
lock_rw_rdlock(&zones->lock);
if(!(z = local_zones_tags_lookup(zones, qinfo->qname,
qinfo->qname_len, labs, qinfo->qclass, qinfo->qtype,
taglist, taglen, 0))) {
taglist, taglen, 0, 0))) {
lock_rw_unlock(&zones->lock);
return 0;
}
@@ -1924,6 +1988,7 @@ local_zones_answer(struct local_zones* zones, struct module_env* env,
if(lzt != local_zone_always_refuse
&& lzt != local_zone_always_transparent
&& lzt != local_zone_block_a
&& lzt != local_zone_block_aaaa
&& lzt != local_zone_always_nxdomain
&& lzt != local_zone_always_nodata
&& lzt != local_zone_always_deny
@@ -1955,6 +2020,9 @@ const char* local_zone_type2str(enum localzone_type t)
case local_zone_inform_redirect: return "inform_redirect";
case local_zone_always_transparent: return "always_transparent";
case local_zone_block_a: return "block_a";
case local_zone_block_aaaa: return "block_aaaa";
case local_zone_block_a_wdata: return "block_a_wdata";
case local_zone_block_aaaa_wdata: return "block_aaaa_wdata";
case local_zone_always_refuse: return "always_refuse";
case local_zone_always_nxdomain: return "always_nxdomain";
case local_zone_always_nodata: return "always_nodata";
@@ -1991,6 +2059,12 @@ int local_zone_str2type(const char* type, enum localzone_type* t)
*t = local_zone_always_transparent;
else if(strcmp(type, "block_a") == 0)
*t = local_zone_block_a;
else if(strcmp(type, "block_aaaa") == 0)
*t = local_zone_block_aaaa;
else if(strcmp(type, "block_a_wdata") == 0)
*t = local_zone_block_a_wdata;
else if(strcmp(type, "block_aaaa_wdata") == 0)
*t = local_zone_block_aaaa_wdata;
else if(strcmp(type, "always_refuse") == 0)
*t = local_zone_always_refuse;
else if(strcmp(type, "always_nxdomain") == 0)
@@ -2102,7 +2176,8 @@ local_zones_add_RR(struct local_zones* zones, const char* rr)
/* could first try readlock then get writelock if zone does not exist,
* but we do not add enough RRs (from multiple threads) to optimize */
lock_rw_wrlock(&zones->lock);
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type);
z = local_zones_lookup(zones, rr_name, len, labs, rr_class, rr_type,
1);
if(!z) {
z = local_zones_add_zone(zones, rr_name, len, labs, rr_class,
local_zone_transparent);
@@ -2180,7 +2255,8 @@ void local_zones_del_data(struct local_zones* zones,
/* remove DS */
lock_rw_rdlock(&zones->lock);
z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS);
z = local_zones_lookup(zones, name, len, labs, dclass, LDNS_RR_TYPE_DS,
1);
if(z) {
lock_rw_wrlock(&z->lock);
d = local_zone_find_data(z, name, len, labs);
@@ -2194,7 +2270,7 @@ void local_zones_del_data(struct local_zones* zones,
/* remove other types */
lock_rw_rdlock(&zones->lock);
z = local_zones_lookup(zones, name, len, labs, dclass, 0);
z = local_zones_lookup(zones, name, len, labs, dclass, 0, 1);
if(!z) {
/* no such zone, we're done */
lock_rw_unlock(&zones->lock);
+17 -3
View File
@@ -57,6 +57,9 @@ struct sldns_buffer;
struct comm_reply;
struct config_strlist;
extern const char** local_zones_default_special;
extern const char** local_zones_default_reverse;
/**
* Local zone type
* This type determines processing for queries that did not match
@@ -90,6 +93,12 @@ enum localzone_type {
local_zone_always_transparent,
/** resolve normally, even when there is local data but return NODATA for A queries */
local_zone_block_a,
/** resolve normally, even when there is local data, but return NODATA for AAAA queries */
local_zone_block_aaaa,
/** resolve normally, use local data, else return NODATA for A queries */
local_zone_block_a_wdata,
/** resolve normally, use local data, else return NODATA for AAAA queries */
local_zone_block_aaaa_wdata,
/** answer with error, even when there is local data */
local_zone_always_refuse,
/** answer with nxdomain, even when there is local data */
@@ -262,11 +271,13 @@ void local_zone_delete(struct local_zone* z);
* @param taglen: length of taglist.
* @param ignoretags: lookup zone by name and class, regardless the
* local-zone's tags.
* @param foradd: if the lookup is for addition or removal of the type.
* Used for type DS. The lookup for answers turns this off.
* @return closest local_zone or NULL if no covering zone is found.
*/
struct local_zone* local_zones_tags_lookup(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
uint8_t* taglist, size_t taglen, int ignoretags);
uint8_t* taglist, size_t taglen, int ignoretags, int foradd);
/**
* Lookup zone that contains the given name, class.
@@ -278,10 +289,13 @@ struct local_zone* local_zones_tags_lookup(struct local_zones* zones,
* @param dclass: class to lookup.
* @param dtype: type of the record, if type DS then a zone higher up is found
* pass 0 to just plain find a zone for a name.
* @param foradd: if the lookup is for addition or removal of the type.
* Used for type DS. The lookup for answers turns this off.
* @return closest local_zone or NULL if no covering zone is found.
*/
struct local_zone* local_zones_lookup(struct local_zones* zones,
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype);
uint8_t* name, size_t len, int labs, uint16_t dclass, uint16_t dtype,
int foradd);
/**
* Debug helper. Print all zones
@@ -565,7 +579,7 @@ enum respip_action {
respip_always_nxdomain = local_zone_always_nxdomain,
/** answer with nodata response */
respip_always_nodata = local_zone_always_nodata,
/** answer with nodata response */
/** drop query */
respip_always_deny = local_zone_always_deny,
/** RPZ: truncate answer in order to force switch to tcp */
respip_truncate = local_zone_truncate,
+275 -110
View File
@@ -231,6 +231,7 @@ mesh_create(struct module_stack* stack, struct module_env* env)
mesh->ans_expired = 0;
mesh->ans_cachedb = 0;
mesh->num_queries_discard_timeout = 0;
mesh->num_queries_replyaddr_limit = 0;
mesh->num_queries_wait_limit = 0;
mesh->num_dns_error_reports = 0;
mesh->max_reply_states = env->cfg->num_queries_per_thread;
@@ -296,12 +297,14 @@ int mesh_make_new_space(struct mesh_area* mesh, sldns_buffer* qbuf)
if(mesh->num_reply_states < mesh->max_reply_states)
return 1;
/* try to kick out a jostle-list item */
if(m && m->reply_list && m->list_select == mesh_jostle_list) {
if(m && m->list_select == mesh_jostle_list) {
/* how old is it? */
struct timeval age;
timeval_subtract(&age, mesh->env->now_tv,
&m->reply_list->start_time);
if(timeval_smaller(&mesh->jostle_max, &age)) {
if(m->has_first_reply_time)
timeval_subtract(&age, mesh->env->now_tv,
&m->first_reply_time);
if(!m->has_first_reply_time ||
timeval_smaller(&mesh->jostle_max, &age)) {
/* its a goner */
log_nametypeclass(VERB_ALGO, "query jostled out to "
"make space for a new one",
@@ -348,7 +351,7 @@ mesh_serve_expired_lookup(struct module_qstate* qstate,
key = (struct msgreply_entry*)e->key;
data = (struct reply_info*)e->data;
if(data->ttl < timenow) *is_expired = 1;
if(TTL_IS_EXPIRED(data->ttl, timenow)) *is_expired = 1;
msg = tomsg(qstate->env, &key->key, data, qstate->region, timenow,
qstate->env->cfg->serve_expired, qstate->env->scratch);
if(!msg)
@@ -421,6 +424,44 @@ mesh_serve_expired_init(struct mesh_state* mstate, int timeout)
return 1;
}
/** remove a reply without accounting, rollback the add reply. */
static void
mesh_remove_reply_without_accounting(struct mesh_state* s,
struct mesh_reply* todel)
{
struct mesh_reply* r, *prev = NULL;
for(r = s->reply_list; r; r = r->next) {
if(r == todel) {
if(prev)
prev->next = r->next;
else s->reply_list = r->next;
r->next = NULL;
/* todel is allocated in region */
return;
}
prev = r;
}
}
/** remove a callback without accounting, rollback the add reply. */
static void
mesh_remove_callback_without_accounting(struct mesh_state* s,
struct mesh_cb* todel)
{
struct mesh_cb* r, *prev = NULL;
for(r = s->cb_list; r; r = r->next) {
if(r == todel) {
if(prev)
prev->next = r->next;
else s->cb_list = r->next;
r->next = NULL;
/* todel is allocated in region */
return;
}
prev = r;
}
}
void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
struct respip_client_info* cinfo, uint16_t qflags,
struct edns_data* edns, struct comm_reply* rep, uint16_t qid,
@@ -430,7 +471,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
int was_detached = 0;
int was_noreply = 0;
int added = 0;
int added = 0, added_reply_without_accounting = 0, added_tcp = 0;
struct mesh_reply* repadded = NULL;
int timeout = mesh->env->cfg->serve_expired?
mesh->env->cfg->serve_expired_client_timeout:0;
struct sldns_buffer* r_buffer = rep->c->buffer;
@@ -441,9 +483,18 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
if(!infra_wait_limit_allowed(mesh->env->infra_cache, rep,
edns->cookie_valid, mesh->env->cfg)) {
verbose(VERB_ALGO, "Too many queries waiting from the IP. "
"dropping incoming query.");
comm_point_drop_reply(rep);
"servfail incoming query.");
mesh->num_queries_wait_limit++;
edns_opt_list_append_ede(&edns->opt_list_out,
mesh->env->scratch, LDNS_EDE_OTHER,
"Too many queries queued up and waiting from the IP");
if(!inplace_cb_reply_servfail_call(mesh->env, qinfo, NULL, NULL,
LDNS_RCODE_SERVFAIL, edns, rep, mesh->env->scratch, mesh->env->now_tv))
edns->opt_list_inplace_cb_out = NULL;
error_encode(r_buffer, LDNS_RCODE_SERVFAIL,
qinfo, qid, qflags, edns);
regional_free_all(mesh->env->scratch);
comm_point_send_reply(rep);
return;
}
if(!unique)
@@ -453,6 +504,10 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
if(!mesh_make_new_space(mesh, rep->c->buffer)) {
verbose(VERB_ALGO, "Too many queries. dropping "
"incoming query.");
if(rep->c->use_h2)
http2_stream_remove_mesh_state(rep->c->h2_stream);
else if(rep->c->type == comm_doq && rep->doq_stream)
doq_stream_remove_mesh_state(rep->doq_stream);
comm_point_drop_reply(rep);
mesh->stats_dropped++;
return;
@@ -464,8 +519,12 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
if(mesh->num_reply_addrs > mesh->max_reply_states*16) {
verbose(VERB_ALGO, "Too many requests queued. "
"dropping incoming query.");
if(rep->c->use_h2)
http2_stream_remove_mesh_state(rep->c->h2_stream);
else if(rep->c->type == comm_doq && rep->doq_stream)
doq_stream_remove_mesh_state(rep->doq_stream);
comm_point_drop_reply(rep);
mesh->stats_dropped++;
mesh->num_queries_replyaddr_limit++;
return;
}
}
@@ -524,18 +583,22 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
}
}
/* add reply to s */
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo)) {
if(!mesh_state_add_reply(s, edns, rep, qid, qflags, qinfo, &repadded)) {
log_err("mesh_new_client: out of memory; SERVFAIL");
goto servfail_mem;
}
added_reply_without_accounting = 1;
if(rep->c->tcp_req_info) {
if(!tcp_req_info_add_meshstate(rep->c->tcp_req_info, mesh, s)) {
log_err("mesh_new_client: out of memory add tcpreqinfo");
goto servfail_mem;
}
}
added_tcp = 1;
if(rep->c->use_h2) {
http2_stream_add_meshstate(rep->c->h2_stream, mesh, s);
} else if(rep->c->type == comm_doq && rep->doq_stream) {
doq_stream_add_meshstate(rep->doq_stream, mesh, s);
}
/* add serve expired timer if required and not already there */
if(timeout && !mesh_serve_expired_init(s, timeout)) {
@@ -553,6 +616,8 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
}
}
#endif
/* Since the acccounting now happens,
* added_reply_without_accounting = 0; but that is not used. */
infra_wait_limit_inc(mesh->env->infra_cache, rep, *mesh->env->now,
mesh->env->cfg);
/* update statistics */
@@ -589,7 +654,14 @@ servfail_mem:
qinfo, qid, qflags, edns);
if(rep->c->use_h2)
http2_stream_remove_mesh_state(rep->c->h2_stream);
else if(rep->c->type == comm_doq && rep->doq_stream)
doq_stream_remove_mesh_state(rep->doq_stream);
comm_point_send_reply(rep);
if(added_reply_without_accounting) {
mesh_remove_reply_without_accounting(s, repadded);
if(added_tcp && rep->c->tcp_req_info)
tcp_req_info_remove_mesh_state(rep->c->tcp_req_info, s);
}
if(added)
mesh_state_delete(&s->s);
return;
@@ -598,7 +670,8 @@ servfail_mem:
int
mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, struct edns_data* edns, sldns_buffer* buf,
uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru)
uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru,
void** unique_info)
{
struct mesh_state* s = NULL;
int unique = unique_mesh_state(edns->opt_list_in, mesh->env);
@@ -607,6 +680,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
int was_detached = 0;
int was_noreply = 0;
int added = 0;
struct mesh_cb* add_cb = NULL;
uint16_t mesh_flags = qflags&(BIT_RD|BIT_CD);
if(!unique)
s = mesh_area_find(mesh, NULL, qinfo, mesh_flags, 0, 0);
@@ -652,13 +726,14 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
}
}
/* add reply to s */
if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags)) {
if(!mesh_state_add_cb(s, edns, buf, cb, cb_arg, qid, qflags, &add_cb)) {
if(added)
mesh_state_delete(&s->s);
return 0;
}
/* add serve expired timer if not already there */
if(timeout && !mesh_serve_expired_init(s, timeout)) {
mesh_remove_callback_without_accounting(s, add_cb);
if(added)
mesh_state_delete(&s->s);
return 0;
@@ -669,6 +744,7 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
(mesh->env->cachedb_enabled &&
mesh->env->cfg->cachedb_check_when_serve_expired)) {
if(!mesh_serve_expired_init(s, -1)) {
mesh_remove_callback_without_accounting(s, add_cb);
if(added)
mesh_state_delete(&s->s);
return 0;
@@ -684,6 +760,8 @@ mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
mesh->num_reply_states ++;
}
mesh->num_reply_addrs++;
if(unique_info)
*unique_info = s->unique;
if(added)
mesh_run(mesh, s, module_event_new, NULL);
return 1;
@@ -887,33 +965,9 @@ void mesh_report_reply(struct mesh_area* mesh, struct outbound_entry* e,
mesh_run(mesh, e->qstate->mesh_info, event, e);
}
/** copy strlist to region */
static struct config_strlist*
cfg_region_strlist_copy(struct regional* region, struct config_strlist* list)
{
struct config_strlist* result = NULL, *last = NULL, *s = list;
while(s) {
struct config_strlist* n = regional_alloc_zero(region,
sizeof(*n));
if(!n)
return NULL;
n->str = regional_strdup(region, s->str);
if(!n->str)
return NULL;
if(last)
last->next = n;
else result = n;
last = n;
s = s->next;
}
return result;
}
/** Copy the client info to the query region. */
static struct respip_client_info*
struct respip_client_info*
mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
{
size_t i;
struct respip_client_info* client_info;
client_info = regional_alloc_init(region, cinfo, sizeof(*cinfo));
if(!client_info)
@@ -932,20 +986,13 @@ mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
if(!client_info->tag_actions)
return NULL;
}
if(cinfo->tag_datas) {
client_info->tag_datas = regional_alloc_zero(region,
sizeof(struct config_strlist*)*cinfo->tag_datas_size);
if(!client_info->tag_datas)
return NULL;
for(i=0; i<cinfo->tag_datas_size; i++) {
if(cinfo->tag_datas[i]) {
client_info->tag_datas[i] = cfg_region_strlist_copy(
region, cinfo->tag_datas[i]);
if(!client_info->tag_datas[i])
return NULL;
}
}
}
/* tag_datas is owned by the matched acl_addr in config_file; its
* lifetime is until config reload, which tears down all mesh states
* first. Keep the original pointer so client_info_compare()
* can recognise two states from the same ACL entry. */
/* fast reload insists on dropping the queries when interface-tag-data
* or access-control-tag-data are changed. */
/* client_info->tag_datas already copied by regional_alloc_init above */
if(cinfo->view) {
/* Do not copy the view pointer but store a name instead.
* The name is looked up later when done, this means that
@@ -955,6 +1002,11 @@ mesh_copy_client_info(struct regional* region, struct respip_client_info* cinfo)
cinfo->view->name);
if(!client_info->view_name)
return NULL;
} else if(cinfo->view_name) {
client_info->view_name = regional_strdup(region,
cinfo->view_name);
if(!client_info->view_name)
return NULL;
}
return client_info;
}
@@ -1022,6 +1074,7 @@ mesh_state_create(struct module_env* env, struct query_info* qinfo,
mstate->s.no_cache_store = 0;
mstate->s.need_refetch = 0;
mstate->s.was_ratelimited = 0;
mstate->s.error_response_cache = 0;
mstate->s.qstarttime = *env->now;
/* init modules */
@@ -1068,8 +1121,6 @@ mesh_state_cleanup(struct mesh_state* mstate)
for(; rep; rep=rep->next) {
infra_wait_limit_dec(mesh->env->infra_cache,
&rep->query_reply, mesh->env->cfg);
if(rep->query_reply.c->use_h2)
http2_stream_remove_mesh_state(rep->h2_stream);
comm_point_drop_reply(&rep->query_reply);
log_assert(mesh->num_reply_addrs > 0);
mesh->num_reply_addrs--;
@@ -1152,8 +1203,7 @@ mesh_detect_cycle_found(struct module_qstate* qstate, struct mesh_state* dep_m)
{
struct mesh_state* cyc_m = qstate->mesh_info;
size_t counter = 0;
if(!dep_m)
return 0;
log_assert(dep_m);
if(dep_m == cyc_m || find_in_subsub(dep_m, cyc_m, &counter)) {
if(counter > MESH_MAX_SUBSUB)
return 2;
@@ -1190,28 +1240,26 @@ void mesh_detach_subs(struct module_qstate* qstate)
}
int mesh_add_sub(struct module_qstate* qstate, struct query_info* qinfo,
uint16_t qflags, int prime, int valrec, struct module_qstate** newq,
struct mesh_state** sub)
struct respip_client_info* cinfo, uint16_t qflags, int prime,
int valrec, struct module_qstate** newq, struct mesh_state** sub)
{
/* find it, if not, create it */
struct mesh_area* mesh = qstate->env->mesh;
*sub = mesh_area_find(mesh, NULL, qinfo, qflags,
prime, valrec);
if(mesh_detect_cycle_found(qstate, *sub)) {
verbose(VERB_ALGO, "attach failed, cycle detected");
return 0;
}
*sub = mesh_area_find(mesh, cinfo, qinfo, qflags, prime, valrec);
if(!*sub) {
#ifdef UNBOUND_DEBUG
struct rbnode_type* n;
#endif
/* create a new one */
*sub = mesh_state_create(qstate->env, qinfo, NULL, qflags, prime,
valrec);
*sub = mesh_state_create(qstate->env, qinfo, cinfo, qflags,
prime, valrec);
if(!*sub) {
log_err("mesh_attach_sub: out of memory");
return 0;
}
/* inherit RPZ passthru from the parent so respip on the sub
* sees the same client-IP/qname PASSTHRU decision */
(*sub)->s.rpz_passthru = qstate->rpz_passthru;
#ifdef UNBOUND_DEBUG
n =
#else
@@ -1230,18 +1278,25 @@ int mesh_add_sub(struct module_qstate* qstate, struct query_info* qinfo,
rbtree_insert(&mesh->run, &(*sub)->run_node);
log_assert(n != NULL);
*newq = &(*sub)->s;
} else
} else {
*newq = NULL;
if(mesh_detect_cycle_found(qstate, *sub)) {
verbose(VERB_ALGO, "attach failed, cycle detected");
return 0;
}
}
return 1;
}
int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
uint16_t qflags, int prime, int valrec, struct module_qstate** newq)
struct respip_client_info* cinfo, uint16_t qflags, int prime,
int valrec, struct module_qstate** newq)
{
struct mesh_area* mesh = qstate->env->mesh;
struct mesh_state* sub = NULL;
int was_detached;
if(!mesh_add_sub(qstate, qinfo, qflags, prime, valrec, newq, &sub))
if(!mesh_add_sub(qstate, qinfo, cinfo, qflags, prime, valrec, newq,
&sub))
return 0;
was_detached = (sub->super_set.count == 0);
if(!mesh_state_attachment(qstate->mesh_info, sub))
@@ -1460,6 +1515,10 @@ mesh_send_reply(struct mesh_state* m, int rcode, struct reply_info* rep,
* for HTTP/2 stream to refer to mesh state, in case
* connection gets cleanup before HTTP/2 stream close. */
r->h2_stream->mesh_state = NULL;
#ifdef HAVE_NGTCP2
} else if(r->query_reply.doq_stream) {
r->query_reply.doq_stream->mesh_state = NULL;
#endif
}
/* send the reply */
/* We don't reuse the encoded answer if:
@@ -1614,9 +1673,9 @@ static void dns_error_reporting(struct module_qstate* qstate,
opt = edns_opt_list_find(qstate->edns_opts_back_in,
LDNS_EDNS_REPORT_CHANNEL);
if(!opt) return;
agent_domain_len = opt->opt_len;
agent_domain = opt->opt_data;
if(dname_valid(agent_domain, agent_domain_len) < 3) {
agent_domain_len = dname_valid(agent_domain, opt->opt_len);
if(agent_domain_len < 3) {
/* The agent domain needs to be a valid dname that is not the
* root; from RFC9567. */
return;
@@ -1684,7 +1743,7 @@ static void dns_error_reporting(struct module_qstate* qstate,
log_query_info(VERB_ALGO, "DNS Error Reporting: generating report "
"query for", &qinfo);
if(mesh_add_sub(qstate, &qinfo, BIT_RD, 0, 0, &newq, &sub)) {
if(mesh_add_sub(qstate, &qinfo, NULL, BIT_RD, 0, 0, &newq, &sub)) {
qstate->env->mesh->num_dns_error_reports++;
}
return;
@@ -1723,32 +1782,46 @@ void mesh_query_done(struct mesh_state* mstate)
}
}
if(mstate->reply_list && mstate->s.env->cfg->dns_error_reporting)
if(mstate->reply_list && mstate->s.env->cfg->dns_error_reporting
&& (!rep || rep->security != sec_status_secure))
dns_error_reporting(&mstate->s, rep);
for(r = mstate->reply_list; r; r = r->next) {
struct timeval old;
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
if(mstate->s.env->cfg->discard_timeout != 0 &&
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
mstate->s.env->cfg->discard_timeout) {
/* Drop the reply, it is too old */
/* briefly set the reply_list to NULL, so that the
* tcp req info cleanup routine that calls the mesh
* to deregister the meshstate for it is not done
* because the list is NULL and also accounting is not
* done there, but instead we do that here. */
struct mesh_reply* reply_list = mstate->reply_list;
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
infra_wait_limit_dec(mstate->s.env->infra_cache,
&r->query_reply, mstate->s.env->cfg);
mstate->reply_list = NULL;
if(r->query_reply.c->use_h2)
http2_stream_remove_mesh_state(r->h2_stream);
comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list;
mstate->s.env->mesh->num_queries_discard_timeout++;
continue;
if(mesh_is_udp(r)) {
/* For UDP queries, the old replies are discarded.
* This stops a large volume of old replies from
* building up.
* The stream replies, are not discarded. The
* stream is open, the other side is waiting.
* Some answer is needed, even if servfail, but the
* real reply is ready to go, so that is given. */
struct timeval old;
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
if(mstate->s.env->cfg->discard_timeout != 0 &&
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
mstate->s.env->cfg->discard_timeout) {
/* Drop the reply, it is too old */
/* briefly set the reply_list to NULL, so that the
* tcp req info cleanup routine that calls the mesh
* to deregister the meshstate for it is not done
* because the list is NULL and also accounting is not
* done there, but instead we do that here. */
struct mesh_reply* reply_list = mstate->reply_list;
verbose(VERB_ALGO, "drop reply, it is older than discard-timeout");
infra_wait_limit_dec(mstate->s.env->infra_cache,
&r->query_reply, mstate->s.env->cfg);
mstate->reply_list = NULL;
if(r->query_reply.c->use_h2)
http2_stream_remove_mesh_state(r->h2_stream);
else if(r->query_reply.doq_stream)
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list;
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
mstate->s.env->mesh->num_reply_addrs--;
mstate->s.env->mesh->num_queries_discard_timeout++;
continue;
}
}
i++;
@@ -1779,9 +1852,13 @@ void mesh_query_done(struct mesh_state* mstate)
mstate->reply_list = NULL;
if(r->query_reply.c->use_h2) {
http2_stream_remove_mesh_state(r->h2_stream);
} else if(r->query_reply.doq_stream) {
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
}
comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list;
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
mstate->s.env->mesh->num_reply_addrs--;
} else {
struct sldns_buffer* r_buffer = r->query_reply.c->buffer;
if(r->query_reply.c->tcp_req_info) {
@@ -1889,6 +1966,25 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
return result;
}
struct mesh_state* mesh_area_find_unique(struct mesh_area* mesh,
struct respip_client_info* cinfo, struct query_info* qinfo,
uint16_t qflags, int prime, int valrec, void* unique_info)
{
struct mesh_state key;
struct mesh_state* result;
key.node.key = &key;
key.s.is_priming = prime;
key.s.is_valrec = valrec;
key.s.qinfo = *qinfo;
key.s.query_flags = qflags;
key.unique = (struct mesh_state*)unique_info;
key.s.client_info = cinfo;
result = (struct mesh_state*)rbtree_search(&mesh->all, &key);
return result;
}
/** remove mesh state callback */
int mesh_state_del_cb(struct mesh_state* s, mesh_cb_func_type cb, void* cb_arg)
{
@@ -1910,7 +2006,7 @@ int mesh_state_del_cb(struct mesh_state* s, mesh_cb_func_type cb, void* cb_arg)
int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg,
uint16_t qid, uint16_t qflags)
uint16_t qid, uint16_t qflags, struct mesh_cb** result)
{
struct mesh_cb* r = regional_alloc(s->s.region,
sizeof(struct mesh_cb));
@@ -1934,13 +2030,14 @@ int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
r->qflags = qflags;
r->next = s->cb_list;
s->cb_list = r;
*result = r;
return 1;
}
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
struct comm_reply* rep, uint16_t qid, uint16_t qflags,
const struct query_info* qinfo)
const struct query_info* qinfo, struct mesh_reply** result)
{
struct mesh_reply* r = regional_alloc(s->s.region,
sizeof(struct mesh_reply));
@@ -1960,6 +2057,10 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
r->qid = qid;
r->qflags = qflags;
r->start_time = *s->s.env->now_tv;
if(s->reply_list == NULL && !s->has_first_reply_time) {
s->first_reply_time = r->start_time;
s->has_first_reply_time = 1;
}
r->next = s->reply_list;
r->qname = regional_alloc_init(s->s.region, qinfo->qname,
s->s.qinfo.qname_len);
@@ -1968,6 +2069,8 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
if(rep->c->use_h2)
r->h2_stream = rep->c->h2_stream;
else r->h2_stream = NULL;
if(rep->c->type != comm_doq)
r->query_reply.doq_stream = NULL;
/* Data related to local alias stored in 'qinfo' (if any) is ephemeral
* and can be different for different original queries (even if the
@@ -2015,6 +2118,7 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
r->local_alias = NULL;
s->reply_list = r;
*result = r;
return 1;
}
@@ -2172,8 +2276,29 @@ void mesh_run(struct mesh_area* mesh, struct mesh_state* mstate,
enum module_ev ev, struct outbound_entry* e)
{
enum module_ext_state s;
int numrun = 0;
verbose(VERB_ALGO, "mesh_run: start");
while(mstate) {
if(numrun++ > MESH_MAX_RUN_ITER) {
/* These modules are too much to activate, stop them.*/
log_err("Too many module run iterations, deleting");
while(mstate) {
/* notify supers */
if(mstate->super_set.count > 0) {
verbose(VERB_ALGO, "notify supers of failure");
mstate->s.return_msg = NULL;
mstate->s.return_rcode = LDNS_RCODE_SERVFAIL;
mesh_walk_supers(mesh, mstate);
}
mesh_state_delete(&mstate->s);
if(mesh->run.count > 0) {
/* pop random element off the runnable tree */
mstate = (struct mesh_state*)mesh->run.root->key;
(void)rbtree_delete(&mesh->run, mstate);
} else mstate = NULL;
}
break;
}
/* run the module */
fptr_ok(fptr_whitelist_mod_operate(
mesh->mods.mod[mstate->s.curmod]->operate));
@@ -2272,6 +2397,7 @@ mesh_stats_clear(struct mesh_area* mesh)
memset(&mesh->rpz_action[0], 0, sizeof(size_t)*UB_STATS_RPZ_ACTION_NUM);
mesh->ans_nodata = 0;
mesh->num_queries_discard_timeout = 0;
mesh->num_queries_replyaddr_limit = 0;
mesh->num_queries_wait_limit = 0;
mesh->num_dns_error_reports = 0;
}
@@ -2297,7 +2423,7 @@ mesh_detect_cycle(struct module_qstate* qstate, struct query_info* qinfo,
struct mesh_area* mesh = qstate->env->mesh;
struct mesh_state* dep_m = NULL;
dep_m = mesh_area_find(mesh, NULL, qinfo, flags, prime, valrec);
return mesh_detect_cycle_found(qstate, dep_m);
return dep_m?mesh_detect_cycle_found(qstate, dep_m):0;
}
void mesh_list_insert(struct mesh_state* m, struct mesh_state** fp,
@@ -2324,7 +2450,8 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
}
void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
struct comm_point* cp)
struct comm_point* cp, struct http2_stream* h2_stream,
struct doq_stream* doq_stream)
{
struct mesh_reply* n, *prev = NULL;
n = m->reply_list;
@@ -2332,7 +2459,9 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
* there is no accounting twice */
if(!n) return; /* nothing to remove, also no accounting needed */
while(n) {
if(n->query_reply.c == cp) {
if(n->query_reply.c == cp
&& (!h2_stream || n->h2_stream == h2_stream)
&& (!doq_stream || n->query_reply.doq_stream == doq_stream)) {
/* unlink it */
if(prev) prev->next = n->next;
else m->reply_list = n->next;
@@ -2341,6 +2470,14 @@ void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
mesh->num_reply_addrs--;
infra_wait_limit_dec(mesh->env->infra_cache,
&n->query_reply, mesh->env->cfg);
/* We may be removing more than one http2 stream (they
* share the same comm_point); make sure the streams
* don't point back. */
if(n->h2_stream) n->h2_stream->mesh_state = NULL;
#ifdef HAVE_NGTCP2
if(n->query_reply.doq_stream)
n->query_reply.doq_stream->mesh_state = NULL;
#endif
/* prev = prev; */
n = n->next;
@@ -2381,9 +2518,10 @@ apply_respip_action(struct module_qstate* qstate,
/* xxx_deny actions mean dropping the reply, unless the original reply
* was redirected to response-ip data. */
if((actinfo->action == respip_deny ||
if(actinfo->action == respip_always_deny ||
((actinfo->action == respip_deny ||
actinfo->action == respip_inform_deny) &&
*encode_repp == rep)
*encode_repp == rep))
*encode_repp = NULL;
return 1;
@@ -2448,12 +2586,15 @@ mesh_serve_expired_callback(void* arg)
qstate->client_info, &actinfo, msg->rep, &alias_rrset, &encode_rep,
qstate->env->auth_zones)) {
return;
} else if(partial_rep &&
!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
} else if(partial_rep) {
if(!respip_merge_cname(partial_rep, &qstate->qinfo, msg->rep,
qstate->client_info, must_validate, &encode_rep, qstate->region,
qstate->env->auth_zones, qstate->env->views,
qstate->env->respip_set)) {
return;
return;
}
/* merge succeeded; final reply, no further alias pass */
partial_rep = NULL;
}
if(!encode_rep || alias_rrset) {
if(!encode_rep) {
@@ -2464,6 +2605,7 @@ mesh_serve_expired_callback(void* arg)
partial_rep = encode_rep;
}
}
msg->rep = encode_rep;
/* We've found a partial reply ending with an
* alias. Replace the lookup qinfo for the
* alias target and lookup the cache again to
@@ -2490,9 +2632,10 @@ mesh_serve_expired_callback(void* arg)
log_dns_msg("Serve expired lookup", &qstate->qinfo, msg->rep);
for(r = mstate->reply_list; r; r = r->next) {
struct timeval old;
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
if(mstate->s.env->cfg->discard_timeout != 0 &&
if(mesh_is_udp(r)) {
struct timeval old;
timeval_subtract(&old, mstate->s.env->now_tv, &r->start_time);
if(mstate->s.env->cfg->discard_timeout != 0 &&
((int)old.tv_sec)*1000+((int)old.tv_usec)/1000 >
mstate->s.env->cfg->discard_timeout) {
/* Drop the reply, it is too old */
@@ -2508,10 +2651,15 @@ mesh_serve_expired_callback(void* arg)
mstate->reply_list = NULL;
if(r->query_reply.c->use_h2)
http2_stream_remove_mesh_state(r->h2_stream);
else if(r->query_reply.doq_stream)
doq_stream_remove_mesh_state(r->query_reply.doq_stream);
comm_point_drop_reply(&r->query_reply);
mstate->reply_list = reply_list;
log_assert(mstate->s.env->mesh->num_reply_addrs > 0);
mstate->s.env->mesh->num_reply_addrs--;
mstate->s.env->mesh->num_queries_discard_timeout++;
continue;
}
}
i++;
@@ -2608,13 +2756,30 @@ int mesh_jostle_exceeded(struct mesh_area* mesh)
}
void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg)
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info)
{
struct mesh_state* s = NULL;
s = mesh_area_find(mesh, NULL, qinfo, qflags&(BIT_RD|BIT_CD), 0, 0);
if(!s) return;
if(!mesh_state_del_cb(s, cb, cb_arg)) return;
if(s && mesh_state_del_cb(s, cb, cb_arg))
goto removed;
if(unique_info) {
s = mesh_area_find_unique(mesh, NULL, qinfo,
qflags&(BIT_RD|BIT_CD), 0, 0, unique_info);
if(s && mesh_state_del_cb(s, cb, cb_arg))
goto removed;
}
/* mesh_area_find builds key.unique=NULL and cannot match a state
* created with mesh_state_make_unique (e.g. subnetcache sets
* env->unique_mesh). Fall back to a linear scan; cb+cb_arg is an
* exact key (mesh_state_del_cb compares both).
* This works for both lookups for zonemd and for hostname authzone. */
RBTREE_FOR(s, struct mesh_state*, &mesh->all) {
if(s->cb_list && mesh_state_del_cb(s, cb, cb_arg))
goto removed;
}
return;
removed:
/* It was in the list and removed. */
log_assert(mesh->num_reply_addrs > 0);
mesh->num_reply_addrs--;
+60 -8
View File
@@ -69,6 +69,13 @@ struct respip_client_info;
*/
#define MESH_MAX_ACTIVATION 10000
/**
* Maximum number of mesh state run items. These are different modules
* activated during a mesh run. Any more is likely an infinite loop
* in the module. It is then terminated, and states are deleted.
*/
#define MESH_MAX_RUN_ITER 10000
/**
* Max number of references-to-references-to-references.. search size.
* Any more is treated like 'too large', and the creation of a new
@@ -141,6 +148,8 @@ struct mesh_area {
size_t rpz_action[UB_STATS_RPZ_ACTION_NUM];
/** stats, number of queries removed due to discard-timeout */
size_t num_queries_discard_timeout;
/** stats, number of queries removed due to replyaddr limit */
size_t num_queries_replyaddr_limit;
/** stats, number of queries removed due to wait-limit */
size_t num_queries_wait_limit;
/** stats, number of dns error reports generated */
@@ -189,6 +198,12 @@ struct mesh_state {
struct module_qstate s;
/** the list of replies to clients for the results */
struct mesh_reply* reply_list;
/** if it has a first reply time */
int has_first_reply_time;
/** wall-clock time the first client reply was attached;
* used by mesh_make_new_space() so duplicate retransmits
* cannot reset jostle aging. */
struct timeval first_reply_time;
/** the list of callbacks for the results */
struct mesh_cb* cb_list;
/** set of superstates (that want this state's result)
@@ -334,11 +349,14 @@ void mesh_new_client(struct mesh_area* mesh, struct query_info* qinfo,
* @param cb_arg: callback user arg.
* @param rpz_passthru: if true, the rpz passthru was previously found and
* further rpz processing is stopped.
* @param unique_info: if nonnull, unique info is passed back to be used
* for the callback remove call. It does not need to be deallocated.
* @return 0 on error.
*/
int mesh_new_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, struct edns_data* edns, struct sldns_buffer* buf,
uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru);
uint16_t qid, mesh_cb_func_type cb, void* cb_arg, int rpz_passthru,
void** unique_info);
/**
* New prefetch message. Create new query state if needed.
@@ -399,6 +417,8 @@ void mesh_detach_subs(struct module_qstate* qstate);
* @param qstate: the state to find mesh state, and that wants to receive
* the results from the new subquery.
* @param qinfo: what to query for (copied).
* @param cinfo: if non-NULL client specific info that may affect IP-based
* actions that apply to the query result. It is copied.
* @param qflags: what flags to use (RD / CD flag or not).
* @param prime: if it is a (stub) priming query.
* @param valrec: if it is a validation recursion query (lookup of key, DS).
@@ -407,7 +427,8 @@ void mesh_detach_subs(struct module_qstate* qstate);
* @return: false on error, true if success (and init may be needed).
*/
int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
uint16_t qflags, int prime, int valrec, struct module_qstate** newq);
struct respip_client_info* cinfo, uint16_t qflags, int prime,
int valrec, struct module_qstate** newq);
/**
* Add detached query.
@@ -426,6 +447,8 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
* @param qstate: the state to find mesh state, and that wants to receive
* the results from the new subquery.
* @param qinfo: what to query for (copied).
* @param cinfo: if non-NULL client specific info that may affect IP-based
* actions that apply to the query result. It is copied.
* @param qflags: what flags to use (RD / CD flag or not).
* @param prime: if it is a (stub) priming query.
* @param valrec: if it is a validation recursion query (lookup of key, DS).
@@ -435,8 +458,8 @@ int mesh_attach_sub(struct module_qstate* qstate, struct query_info* qinfo,
* @return: false on error, true if success (and init may be needed).
*/
int mesh_add_sub(struct module_qstate* qstate, struct query_info* qinfo,
uint16_t qflags, int prime, int valrec, struct module_qstate** newq,
struct mesh_state** sub);
struct respip_client_info* cinfo, uint16_t qflags, int prime,
int valrec, struct module_qstate** newq, struct mesh_state** sub);
/**
* Query state is done, send messages to reply entries.
@@ -530,6 +553,23 @@ struct mesh_state* mesh_area_find(struct mesh_area* mesh,
struct respip_client_info* cinfo, struct query_info* qinfo,
uint16_t qflags, int prime, int valrec);
/**
* Find a unique mesh state in the mesh area. Pass relevant flags.
*
* @param mesh: the mesh area to look in.
* @param cinfo: if non-NULL client specific info that may affect IP-based
* actions that apply to the query result.
* @param qinfo: what query
* @param qflags: if RD / CD bit is set or not.
* @param prime: if it is a priming query.
* @param valrec: if it is a validation-recursion query.
* @param unique_info: the unique info for the state. NULL can be passed.
* @return: mesh state or NULL if not found.
*/
struct mesh_state* mesh_area_find_unique(struct mesh_area* mesh,
struct respip_client_info* cinfo, struct query_info* qinfo,
uint16_t qflags, int prime, int valrec, void* unique_info);
/**
* Setup attachment super/sub relation between super and sub mesh state.
* The relation must not be present when calling the function.
@@ -549,11 +589,12 @@ int mesh_state_attachment(struct mesh_state* super, struct mesh_state* sub);
* @param qid: ID of reply.
* @param qflags: original query flags.
* @param qinfo: original query info.
* @param result: the allocated reply structure, for rollback.
* @return: 0 on alloc error.
*/
int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
struct comm_reply* rep, uint16_t qid, uint16_t qflags,
const struct query_info* qinfo);
const struct query_info* qinfo, struct mesh_reply** result);
/**
* Create new callback structure and attach it to a mesh state.
@@ -565,11 +606,12 @@ int mesh_state_add_reply(struct mesh_state* s, struct edns_data* edns,
* @param cb_arg: callback user arg.
* @param qid: ID of reply.
* @param qflags: original query flags.
* @param result: the allocated callback structure, for rollback.
* @return: 0 on alloc error.
*/
int mesh_state_add_cb(struct mesh_state* s, struct edns_data* edns,
struct sldns_buffer* buf, mesh_cb_func_type cb, void* cb_arg,
uint16_t qid, uint16_t qflags);
uint16_t qid, uint16_t qflags, struct mesh_cb** result);
/**
* Run the mesh. Run all runnable mesh states. Which can create new
@@ -670,9 +712,14 @@ void mesh_list_remove(struct mesh_state* m, struct mesh_state** fp,
* @param mesh: to update the counters.
* @param m: the mesh state.
* @param cp: the comm_point to remove from the list.
* @param h2_stream: if not NULL, it specifies the h2_stream to match
* for the delete.
* @param doq_stream: if not NULL, it specifies the doq_stream to match
* for the delete.
*/
void mesh_state_remove_reply(struct mesh_area* mesh, struct mesh_state* m,
struct comm_point* cp);
struct comm_point* cp, struct http2_stream* h2_stream,
struct doq_stream* doq_stream);
/** Callback for when the serve expired client timer has run out. Tries to
* find an expired answer in the cache and reply that to the client.
@@ -719,8 +766,13 @@ void mesh_respond_serve_expired(struct mesh_state* mstate);
* @param qflags: flags from client query.
* @param cb: callback function.
* @param cb_arg: callback user arg.
* @param unique_info: if not NULL, used to find a unique state for removal.
*/
void mesh_remove_callback(struct mesh_area* mesh, struct query_info* qinfo,
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg);
uint16_t qflags, mesh_cb_func_type cb, void* cb_arg, void* unique_info);
/** Copy the client info to the query region. */
struct respip_client_info* mesh_copy_client_info(struct regional* region,
struct respip_client_info* cinfo);
#endif /* SERVICES_MESH_H */
+5 -2
View File
@@ -262,6 +262,7 @@ int
modstack_call_init(struct module_stack* stack, const char* module_conf,
struct module_env* env)
{
const char* orig_module_conf = module_conf;
int i, changed = 0;
env->need_to_validate = 0; /* set by module init below */
for(i=0; i<stack->num; i++) {
@@ -276,11 +277,13 @@ modstack_call_init(struct module_stack* stack, const char* module_conf,
changed = 1;
}
}
module_conf += strlen(stack->mod[i]->name);
/* Skip this module name in module_conf. */
while(*module_conf && !isspace((unsigned char)*module_conf))
module_conf++;
}
if(changed) {
modstack_free(stack);
if(!modstack_config(stack, module_conf)) {
if(!modstack_config(stack, orig_module_conf)) {
return 0;
}
}
+439 -79
View File
@@ -160,6 +160,19 @@ reuse_cmp_addrportssl(const void* key1, const void* key2)
return 1;
if(!r1->is_ssl && r2->is_ssl)
return -1;
/* compare tls_auth_name if SSL-enabled */
if(r1->is_ssl) {
if(r1->tls_auth_name && !r2->tls_auth_name)
return 1;
if(!r1->tls_auth_name && r2->tls_auth_name)
return -1;
if(r1->tls_auth_name && r2->tls_auth_name) {
r = strcmp(r1->tls_auth_name, r2->tls_auth_name);
if(r != 0)
return r;
}
}
return 0;
}
@@ -195,6 +208,7 @@ static void
waiting_tcp_delete(struct waiting_tcp* w)
{
if(!w) return;
free(w->tls_auth_name);
if(w->timer)
comm_timer_delete(w->timer);
free(w);
@@ -531,7 +545,7 @@ reuse_tcp_insert(struct outside_network* outnet, struct pending_tcp* pend_tcp)
/** find reuse tcp stream to destination for query, or NULL if none */
static struct reuse_tcp*
reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
socklen_t addrlen, int use_ssl)
socklen_t addrlen, int use_ssl, char* tls_auth_name)
{
struct waiting_tcp key_w;
struct pending_tcp key_p;
@@ -545,8 +559,10 @@ reuse_tcp_find(struct outside_network* outnet, struct sockaddr_storage* addr,
key_p.c = &c;
key_p.reuse.pending = &key_p;
key_p.reuse.node.key = &key_p.reuse;
if(use_ssl)
if(use_ssl) {
key_p.reuse.is_ssl = 1;
key_p.reuse.tls_auth_name = tls_auth_name;
}
if(addrlen > (socklen_t)sizeof(key_p.reuse.addr))
return NULL;
memmove(&key_p.reuse.addr, addr, addrlen);
@@ -646,6 +662,7 @@ static int
outnet_tcp_take_into_use(struct waiting_tcp* w)
{
struct pending_tcp* pend = w->outnet->tcp_free;
char* tls_auth_name = NULL;
int s;
log_assert(pend);
log_assert(w->pkt);
@@ -746,7 +763,22 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
comm_point_tcp_win_bio_cb(pend->c, pend->c->ssl);
#endif
pend->c->ssl_shake_state = comm_ssl_shake_write;
if(!set_auth_name_on_ssl(pend->c->ssl, w->tls_auth_name,
if(w->tls_auth_name) {
/* strdup the auth name, while not linked the list yet,
* in case of failure, easy cleanup. */
tls_auth_name = strdup(w->tls_auth_name);
if(!tls_auth_name) {
log_err("out of memory: alloc tls auth name");
pend->c->fd = s;
#ifdef HAVE_SSL
SSL_free(pend->c->ssl);
#endif
pend->c->ssl = NULL;
comm_point_close(pend->c);
return 0;
}
}
if(!set_auth_name_on_ssl(pend->c->ssl, tls_auth_name,
w->outnet->tls_use_sni)) {
pend->c->fd = s;
#ifdef HAVE_SSL
@@ -754,6 +786,7 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
#endif
pend->c->ssl = NULL;
comm_point_close(pend->c);
free(tls_auth_name);
return 0;
}
}
@@ -778,9 +811,20 @@ outnet_tcp_take_into_use(struct waiting_tcp* w)
if(pend->reuse.node.key)
reuse_tcp_remove_tree_list(w->outnet, &pend->reuse);
if(pend->c->ssl)
if(pend->c->ssl) {
pend->reuse.is_ssl = 1;
else pend->reuse.is_ssl = 0;
if(pend->reuse.tls_auth_name)
free(pend->reuse.tls_auth_name);
pend->reuse.tls_auth_name = tls_auth_name;
tls_auth_name = NULL;
} else {
pend->reuse.is_ssl = 0;
if(pend->reuse.tls_auth_name)
free(pend->reuse.tls_auth_name);
pend->reuse.tls_auth_name = NULL;
}
/* free tls auth name if nonNULL */
free(tls_auth_name);
/* insert in reuse by address tree if not already inserted there */
(void)reuse_tcp_insert(w->outnet, pend);
reuse_tree_by_id_insert(&pend->reuse, w);
@@ -969,7 +1013,7 @@ use_free_buffer(struct outside_network* outnet)
(!outnet->tcp_reuse_first && !outnet->tcp_reuse_last) ||
(outnet->tcp_reuse_first && outnet->tcp_reuse_last));
reuse = reuse_tcp_find(outnet, &w->addr, w->addrlen,
w->ssl_upstream);
w->ssl_upstream, w->tls_auth_name);
/* re-select an ID when moving to a new TCP buffer */
w->id = tcp_select_id(outnet, reuse);
LDNS_ID_SET(w->pkt, w->id);
@@ -1198,6 +1242,10 @@ decommission_pending_tcp(struct outside_network* outnet,
/* needs unlink from the reuse tree to get deleted */
reuse_tcp_remove_tree_list(outnet, &pend->reuse);
}
if(pend->reuse.tls_auth_name) {
free(pend->reuse.tls_auth_name);
pend->reuse.tls_auth_name = NULL;
}
/* free SSL structure after remove from outnet tcp reuse tree,
* because the c->ssl null or not is used for sorting in the tree */
if(pend->c->ssl) {
@@ -1433,7 +1481,7 @@ portcomm_loweruse(struct outside_network* outnet, struct port_comm* pc)
pif = pc->pif;
log_assert(pif->inuse > 0);
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
pif->avail_ports[pif->avail_total - pif->inuse] = pc->number;
shared_ports_return_port(outnet->shared_ports, pif->shpif, pc->number);
#endif
pif->inuse--;
pif->out[pc->index] = pif->out[pif->inuse];
@@ -1647,19 +1695,25 @@ create_pending_tcp(struct outside_network* outnet, size_t bufsize)
}
/** setup an outgoing interface, ready address */
static int setup_if(struct port_if* pif, const char* addrstr,
int* avail, int numavail, size_t numfd)
static int setup_if(struct port_if* pif, const char* addrstr, size_t numfd,
struct shared_ports* shp)
{
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
pif->avail_total = numavail;
pif->avail_ports = (int*)memdup(avail, (size_t)numavail*sizeof(int));
if(!pif->avail_ports)
return 0;
#endif
if(!ipstrtoaddr(addrstr, UNBOUND_DNS_PORT, &pif->addr, &pif->addrlen) &&
!netblockstrtoaddr(addrstr, UNBOUND_DNS_PORT,
&pif->addr, &pif->addrlen, &pif->pfxlen))
return 0;
#ifdef INT_MAX
if(numfd > (size_t)INT_MAX) {
log_err("num_ports exceeds INT_MAX");
return 0;
}
#endif
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
pif->shpif = shared_ports_find_if(shp, &pif->addr, pif->addrlen,
pif->pfxlen);
#else
(void)shp;
#endif
pif->maxout = (int)numfd;
pif->inuse = 0;
pif->out = (struct port_comm**)calloc(numfd,
@@ -1673,12 +1727,12 @@ struct outside_network*
outside_network_create(struct comm_base *base, size_t bufsize,
size_t num_ports, char** ifs, int num_ifs, int do_ip4,
int do_ip6, size_t num_tcp, int dscp, struct infra_cache* infra,
struct ub_randstate* rnd, int use_caps_for_id, int* availports,
int numavailports, size_t unwanted_threshold, int tcp_mss,
struct ub_randstate* rnd, int use_caps_for_id,
size_t unwanted_threshold, int tcp_mss,
void (*unwanted_action)(void*), void* unwanted_param, int do_udp,
void* sslctx, int delayclose, int tls_use_sni, struct dt_env* dtenv,
int udp_connect, int max_reuse_tcp_queries, int tcp_reuse_timeout,
int tcp_auth_query_timeout)
int tcp_auth_query_timeout, struct shared_ports* shared_ports)
{
struct outside_network* outnet = (struct outside_network*)
calloc(1, sizeof(struct outside_network));
@@ -1713,6 +1767,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
outnet->do_udp = do_udp;
outnet->tcp_mss = tcp_mss;
outnet->ip_dscp = dscp;
outnet->shared_ports = shared_ports;
#ifndef S_SPLINT_S
if(delayclose) {
outnet->delayclose = 1;
@@ -1723,11 +1778,18 @@ outside_network_create(struct comm_base *base, size_t bufsize,
if(udp_connect) {
outnet->udp_connect = 1;
}
if(numavailports == 0 || num_ports == 0) {
if(num_ports == 0) {
log_err("no outgoing ports available");
outside_network_delete(outnet);
return NULL;
}
#ifdef INT_MAX
if(num_ports > (size_t)INT_MAX) {
log_err("outgoing num_ports exceeds INT_MAX");
outside_network_delete(outnet);
return NULL;
}
#endif
#ifndef INET6
do_ip6 = 0;
#endif
@@ -1784,13 +1846,13 @@ outside_network_create(struct comm_base *base, size_t bufsize,
/* allocate interfaces */
if(num_ifs == 0) {
if(do_ip4 && !setup_if(&outnet->ip4_ifs[0], "0.0.0.0",
availports, numavailports, num_ports)) {
num_ports, outnet->shared_ports)) {
log_err("malloc failed");
outside_network_delete(outnet);
return NULL;
}
if(do_ip6 && !setup_if(&outnet->ip6_ifs[0], "::",
availports, numavailports, num_ports)) {
num_ports, outnet->shared_ports)) {
log_err("malloc failed");
outside_network_delete(outnet);
return NULL;
@@ -1801,7 +1863,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
for(i=0; i<num_ifs; i++) {
if(str_is_ip6(ifs[i]) && do_ip6) {
if(!setup_if(&outnet->ip6_ifs[done_6], ifs[i],
availports, numavailports, num_ports)){
num_ports, outnet->shared_ports)){
log_err("malloc failed");
outside_network_delete(outnet);
return NULL;
@@ -1810,7 +1872,7 @@ outside_network_create(struct comm_base *base, size_t bufsize,
}
if(!str_is_ip6(ifs[i]) && do_ip4) {
if(!setup_if(&outnet->ip4_ifs[done_4], ifs[i],
availports, numavailports, num_ports)){
num_ports, outnet->shared_ports)){
log_err("malloc failed");
outside_network_delete(outnet);
return NULL;
@@ -1888,9 +1950,6 @@ outside_network_delete(struct outside_network* outnet)
comm_point_delete(pc->cp);
free(pc);
}
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
free(outnet->ip4_ifs[i].avail_ports);
#endif
free(outnet->ip4_ifs[i].out);
}
free(outnet->ip4_ifs);
@@ -1904,9 +1963,6 @@ outside_network_delete(struct outside_network* outnet)
comm_point_delete(pc->cp);
free(pc);
}
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
free(outnet->ip6_ifs[i].avail_ports);
#endif
free(outnet->ip6_ifs[i].out);
}
free(outnet->ip6_ifs);
@@ -1922,6 +1978,10 @@ outside_network_delete(struct outside_network* outnet)
* the tcp conn is working on */
decommission_pending_tcp(outnet, pend);
}
if(pend->reuse.tls_auth_name) {
free(pend->reuse.tls_auth_name);
pend->reuse.tls_auth_name = NULL;
}
comm_point_delete(outnet->tcp_conns[i]->c);
free(outnet->tcp_conns[i]);
outnet->tcp_conns[i] = NULL;
@@ -2112,7 +2172,10 @@ static int
select_ifport(struct outside_network* outnet, struct pending* pend,
int num_if, struct port_if* ifs)
{
int my_if, my_port, fd, portno, inuse, tries=0;
int my_if, fd, portno, inuse, tries=0;
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
int reused;
#endif
struct port_if* pif;
/* randomly select interface and port */
if(num_if == 0) {
@@ -2126,37 +2189,35 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
my_if = ub_random_max(outnet->rnd, num_if);
pif = &ifs[my_if];
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(outnet->udp_connect) {
/* if we connect() we cannot reuse fds for a port */
if(pif->inuse >= pif->avail_total) {
tries++;
if(tries < MAX_PORT_RETRY)
continue;
log_err("failed to find an open port, drop msg");
return 0;
}
my_port = pif->inuse + ub_random_max(outnet->rnd,
pif->avail_total - pif->inuse);
} else {
my_port = ub_random_max(outnet->rnd, pif->avail_total);
if(my_port < pif->inuse) {
/* port already open */
pend->pc = pif->out[my_port];
verbose(VERB_ALGO, "using UDP if=%d port=%d",
my_if, pend->pc->number);
break;
}
if(!shared_ports_fetch_random(outnet->shared_ports,
pif->shpif, outnet->rnd, outnet->udp_connect,
pif->inuse, &portno, &reused)) {
tries++;
if(tries < MAX_PORT_RETRY)
continue;
log_err("failed to find an open port, drop msg");
return 0;
}
if(reused) {
/* port already open */
log_assert(portno < pif->inuse);
pend->pc = pif->out[portno];
verbose(VERB_ALGO, "using UDP if=%d port=%d",
my_if, pend->pc->number);
break;
}
/* try to open new port, if fails, loop to try again */
log_assert(pif->inuse < pif->maxout);
portno = pif->avail_ports[my_port - pif->inuse];
#else
my_port = portno = 0;
portno = 0;
#endif
/* try to open new port, if fails, loop to try again */
fd = udp_sockport(&pif->addr, pif->addrlen, pif->pfxlen,
portno, &inuse, outnet->rnd, outnet->ip_dscp);
if(fd == -1 && !inuse) {
/* nonrecoverable error making socket */
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
shared_ports_return_port(outnet->shared_ports,
pif->shpif, portno);
#endif
return 0;
}
if(fd != -1) {
@@ -2173,6 +2234,11 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
pend->addrlen);
}
sock_close(fd);
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
shared_ports_return_port(
outnet->shared_ports,
pif->shpif, portno);
#endif
return 0;
}
}
@@ -2190,14 +2256,14 @@ select_ifport(struct outside_network* outnet, struct pending* pend,
/* grab port in interface */
pif->out[pif->inuse] = pend->pc;
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
pif->avail_ports[my_port - pif->inuse] =
pif->avail_ports[pif->avail_total-pif->inuse-1];
#endif
pif->inuse++;
break;
}
/* failed, already in use */
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
shared_ports_return_port(outnet->shared_ports, pif->shpif,
portno);
#endif
verbose(VERB_QUERY, "port %d in use, trying another", portno);
tries++;
if(tries == MAX_PORT_RETRY) {
@@ -2447,7 +2513,7 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
/* find out if a reused stream to the target exists */
/* if so, take it into use */
reuse = reuse_tcp_find(sq->outnet, &sq->addr, sq->addrlen,
sq->ssl_upstream);
sq->ssl_upstream, sq->tls_auth_name);
if(reuse) {
log_reuse_tcp(VERB_CLIENT, "pending_tcp_query: found reuse", reuse);
log_assert(reuse->pending);
@@ -2489,7 +2555,16 @@ pending_tcp_query(struct serviced_query* sq, sldns_buffer* packet,
w->cb = callback;
w->cb_arg = callback_arg;
w->ssl_upstream = sq->ssl_upstream;
w->tls_auth_name = sq->tls_auth_name;
if(sq->tls_auth_name) {
w->tls_auth_name = strdup(sq->tls_auth_name);
if(!w->tls_auth_name) {
comm_timer_delete(w->timer);
free(w);
return NULL;
}
} else {
w->tls_auth_name = NULL;
}
w->timeout = timeout;
w->id_node.key = NULL;
w->write_wait_prev = NULL;
@@ -3287,9 +3362,9 @@ serviced_udp_callback(struct comm_point* c, void* arg, int error,
if(error == NETEVENT_TIMEOUT) {
if(sq->status == serviced_query_UDP_EDNS && sq->last_rtt < 5000 &&
(serviced_query_udp_size(sq, serviced_query_UDP_EDNS_FRAG) < serviced_query_udp_size(sq, serviced_query_UDP_EDNS))) {
/* fallback to 1480/1280 */
/* fallback to 1472/1232 */
sq->status = serviced_query_UDP_EDNS_FRAG;
log_name_addr(VERB_ALGO, "try edns1xx0", sq->qbuf+10,
log_name_addr(VERB_ALGO, "try edns1xx2", sq->qbuf+10,
&sq->addr, sq->addrlen);
if(!serviced_udp_send(sq, c->buffer)) {
serviced_callbacks(sq, NETEVENT_CLOSED, c, rep);
@@ -3426,7 +3501,8 @@ outnet_serviced_query(struct outside_network* outnet,
char* tls_auth_name, struct sockaddr_storage* addr, socklen_t addrlen,
uint8_t* zone, size_t zonelen, struct module_qstate* qstate,
comm_point_callback_type* callback, void* callback_arg,
sldns_buffer* buff, struct module_env* env, int* was_ratelimited)
sldns_buffer* buff, struct module_env* env, int* was_ratelimited,
int* ratelimit_incremented)
{
struct serviced_query* sq;
struct service_callback* cb;
@@ -3498,6 +3574,7 @@ outnet_serviced_query(struct outside_network* outnet,
"delegation point", zone,
LDNS_RR_TYPE_NS, LDNS_RR_CLASS_IN);
}
*ratelimit_incremented = 1;
}
/* make new serviced query entry */
sq = serviced_create(outnet, buff, dnssec, want_dnssec, nocaps,
@@ -3579,13 +3656,16 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
{
struct sockaddr_storage* addr;
socklen_t addrlen;
int i, try, pnum, dscp;
int i, try, dscp;
struct port_if* pif;
/* create fd */
dscp = outnet->ip_dscp;
for(try = 0; try<1000; try++) {
int port = 0;
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
int reused = 0;
#endif
int freebind = 0;
int noproto = 0;
int inuse = 0;
@@ -3614,16 +3694,18 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
addr = &pif->addr;
addrlen = pif->addrlen;
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
pnum = ub_random_max(outnet->rnd, pif->avail_total);
if(pnum < pif->inuse) {
/* port already open */
port = pif->out[pnum]->number;
} else {
/* unused ports in start part of array */
port = pif->avail_ports[pnum - pif->inuse];
if(!shared_ports_fetch_random(outnet->shared_ports,
pif->shpif, outnet->rnd, 0, pif->inuse,
&port, &reused)) {
/* try again, perhaps another interface. */
continue;
}
if(reused) {
log_assert(port < pif->inuse);
port = pif->out[port]->number;
}
#else
pnum = port = 0;
port = 0;
#endif
if(addr_is_ip6(to_addr, to_addrlen)) {
struct sockaddr_in6 sa = *(struct sockaddr_in6*)addr;
@@ -3638,6 +3720,14 @@ fd_for_dest(struct outside_network* outnet, struct sockaddr_storage* to_addr,
(struct sockaddr*)addr, addrlen, 1, &inuse, &noproto,
0, 0, 0, NULL, 0, freebind, 0, dscp);
}
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(!reused) {
/* Return the port to the pool, since the caller does
* not keep track of it, also have done fd, and bind. */
shared_ports_return_port(outnet->shared_ports,
pif->shpif, port);
}
#endif
if(fd != -1) {
return fd;
}
@@ -3690,7 +3780,33 @@ setup_comm_ssl(struct comm_point* cp, struct outside_network* outnet,
(void)SSL_set_tlsext_host_name(cp->ssl, host);
}
#endif
#ifdef HAVE_SSL_SET1_HOST
#ifdef HAVE_SSL_SET1_DNSNAME
if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
/* because we set SSL_VERIFY_PEER, in netevent in
* ssl_handshake, it'll check if the certificate
* verification has succeeded */
/* SSL_VERIFY_PEER is set on the sslctx */
/* and the certificates to verify with are loaded into
* it with SSL_load_verify_locations or
* SSL_CTX_set_default_verify_paths */
/* setting the hostname makes openssl verify the
* host name in the x509 certificate in the
* SSL connection*/
struct sockaddr_storage tmpaddr;
socklen_t tmpaddrlen = (socklen_t)sizeof(tmpaddr);
if(ipstrtoaddr(host, UNBOUND_DNS_PORT, &tmpaddr, &tmpaddrlen)) {
if(!SSL_set1_ipaddr(cp->ssl, host)) {
log_err("SSL_set1_ipaddr failed");
return 0;
}
} else {
if(!SSL_set1_dnsname(cp->ssl, host)) {
log_err("SSL_set1_dnsname failed");
return 0;
}
}
}
#elif defined(HAVE_SSL_SET1_HOST)
if((SSL_CTX_get_verify_mode(outnet->sslctx)&SSL_VERIFY_PEER)) {
/* because we set SSL_VERIFY_PEER, in netevent in
* ssl_handshake, it'll check if the certificate
@@ -3819,7 +3935,8 @@ outnet_comm_point_for_http(struct outside_network* outnet,
/* outnet_tcp_connect has closed fd on error for us */
return 0;
}
cp = comm_point_create_http_out(outnet->base, 65552, cb, cb_arg,
cp = comm_point_create_http_out(outnet->base,
sldns_buffer_capacity(outnet->udp_buff), cb, cb_arg,
outnet->udp_buff);
if(!cp) {
log_err("malloc failure");
@@ -3868,11 +3985,7 @@ if_get_mem(struct port_if* pif)
{
size_t s;
int i;
s = sizeof(*pif) +
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
sizeof(int)*pif->avail_total +
#endif
sizeof(struct port_comm*)*pif->maxout;
s = sizeof(*pif) + sizeof(struct port_comm*)*pif->maxout;
for(i=0; i<pif->inuse; i++)
s += sizeof(*pif->out[i]) +
comm_point_get_mem(pif->out[i]->cp);
@@ -3960,3 +4073,250 @@ serviced_get_mem(struct serviced_query* sq)
return s;
}
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** Setup shared port interface */
static int shared_ports_setup_if(struct shared_ports_if* shpif, char* str,
int* availports, int numavailports)
{
shpif->avail_ports = (int*)memdup(availports,
(size_t)numavailports*sizeof(int));
if(!shpif->avail_ports)
return 0;
shpif->avail_total = numavailports;
shpif->inuse = 0;
shpif->pfxlen = 0;
if(!ipstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr, &shpif->addrlen) &&
!netblockstrtoaddr(str, UNBOUND_DNS_PORT, &shpif->addr,
&shpif->addrlen, &shpif->pfxlen))
return 0;
return 1;
}
#endif
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** Allocate shared ports interfaces */
static int shared_ports_alloc_ifs(struct shared_ports* shp, char** ifs,
int num_ifs, int do_ip4, int do_ip6, int* availports,
int numavailports)
{
#ifndef INET6
do_ip6 = 0;
#endif
calc_num46(ifs, num_ifs, do_ip4, do_ip6,
&shp->num_ip4, &shp->num_ip6);
if(shp->num_ip4 != 0) {
if(!(shp->ip4_ifs = (struct shared_ports_if*)calloc(
(size_t)shp->num_ip4,
sizeof(struct shared_ports_if))))
return 0;
}
if(shp->num_ip6 != 0) {
if(!(shp->ip6_ifs = (struct shared_ports_if*)calloc(
(size_t)shp->num_ip6,
sizeof(struct shared_ports_if))))
return 0;
}
if(num_ifs == 0) {
if(do_ip4 && !shared_ports_setup_if(&shp->ip4_ifs[0],
"0.0.0.0", availports, numavailports))
return 0;
if(do_ip6 && !shared_ports_setup_if(&shp->ip6_ifs[0],
"::", availports, numavailports))
return 0;
} else {
size_t done_4 = 0, done_6 = 0;
int i;
for(i=0; i<num_ifs; i++) {
if(str_is_ip6(ifs[i]) && do_ip6 &&
(int)done_6 < shp->num_ip6) {
if(!shared_ports_setup_if(&shp->ip6_ifs[done_6],
ifs[i], availports, numavailports))
return 0;
done_6++;
}
if(!str_is_ip6(ifs[i]) && do_ip4 &&
(int)done_4 < shp->num_ip4) {
if(!shared_ports_setup_if(&shp->ip4_ifs[done_4],
ifs[i], availports, numavailports))
return 0;
done_4++;
}
}
}
return 1;
}
#endif
struct shared_ports* shared_ports_create(char** ifs, int num_ifs, int do_ip4,
int do_ip6, int* availports, int numavailports)
{
struct shared_ports* shp = calloc(1, sizeof(*shp));
if(!shp) {
log_err("malloc failed");
return NULL;
}
lock_basic_init(&shp->lock);
lock_protect(&shp->lock, &shp->ip4_ifs, sizeof(shp->ip4_ifs));
lock_protect(&shp->lock, &shp->num_ip4, sizeof(shp->num_ip4));
lock_protect(&shp->lock, &shp->ip6_ifs, sizeof(shp->ip6_ifs));
lock_protect(&shp->lock, &shp->num_ip6, sizeof(shp->num_ip6));
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/* Allocate interfaces */
lock_basic_lock(&shp->lock);
if(!shared_ports_alloc_ifs(shp, ifs, num_ifs, do_ip4, do_ip6,
availports, numavailports)) {
log_err("malloc failed");
shared_ports_delete(shp);
return NULL;
}
lock_basic_unlock(&shp->lock);
#else
(void)ifs; (void)num_ifs; (void)do_ip4; (void)do_ip6;
(void)availports; (void)numavailports;
#endif
return shp;
}
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
/** Delete shared ports interface structure */
static void shared_ports_if_delete(struct shared_ports_if* shpif)
{
if(!shpif)
return;
free(shpif->avail_ports);
}
#endif
void shared_ports_delete(struct shared_ports* shp)
{
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
int i;
#endif
if(!shp)
return;
lock_basic_destroy(&shp->lock);
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
for(i=0; i<shp->num_ip4; i++) {
shared_ports_if_delete(&shp->ip4_ifs[i]);
}
free(shp->ip4_ifs);
for(i=0; i<shp->num_ip6; i++) {
shared_ports_if_delete(&shp->ip6_ifs[i]);
}
free(shp->ip6_ifs);
#endif
free(shp);
}
struct shared_ports_if* shared_ports_find_if(struct shared_ports* shp,
struct sockaddr_storage* addr, socklen_t addrlen, int pfxlen)
{
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
struct shared_ports_if* ret, *ifs = NULL;
int i, num_ifs = 0;
lock_basic_lock(&shp->lock);
if(addr_is_ip6(addr, addrlen)) {
ifs = shp->ip6_ifs;
num_ifs = shp->num_ip6;
} else {
ifs = shp->ip4_ifs;
num_ifs = shp->num_ip4;
}
for(i=0; i<num_ifs; i++) {
if(sockaddr_cmp(addr, addrlen, &ifs[i].addr,
ifs[i].addrlen) == 0
&& pfxlen == ifs[i].pfxlen) {
ret = &ifs[i];
lock_basic_unlock(&shp->lock);
return ret;
}
}
lock_basic_unlock(&shp->lock);
return NULL;
#else
(void)shp; (void)addr; (void)addrlen; (void)pfxlen;
return NULL;
#endif
}
int shared_ports_fetch_random(struct shared_ports* shp,
struct shared_ports_if* shpif, struct ub_randstate* rnd,
int udp_connect, int reusenum, int* port, int* reused)
{
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
int portno = 0, my_port = 0;
if(!shpif)
return 0;
# ifdef THREADS_DISABLED
(void)shp;
# endif
lock_basic_lock(&shp->lock);
if(udp_connect) {
/* if we connect() we cannot reuse fds for a port. */
if(shpif->inuse >= shpif->avail_total) {
lock_basic_unlock(&shp->lock);
return 0;
}
my_port = ub_random_max(rnd,
shpif->avail_total - shpif->inuse);
} else {
/* select from free ports and open ports on this thread. */
if(shpif->inuse >= shpif->avail_total) {
lock_basic_unlock(&shp->lock);
if(reusenum == 0) {
return 0;
}
my_port = ub_random_max(rnd, reusenum);
*port = my_port;
*reused = 1;
return 1;
}
my_port = ub_random_max(rnd, shpif->avail_total - shpif->inuse
+ reusenum);
if(my_port < reusenum) {
/* port already open */
lock_basic_unlock(&shp->lock);
*port = my_port;
*reused = 1;
return 1;
}
my_port -= reusenum;
}
log_assert(shpif->inuse < shpif->avail_total);
log_assert(my_port >= 0 && my_port < shpif->avail_total);
portno = shpif->avail_ports[my_port];
shpif->avail_ports[my_port] =
shpif->avail_ports[shpif->avail_total-shpif->inuse-1];
shpif->inuse++;
lock_basic_unlock(&shp->lock);
*port = portno;
*reused = 0;
return 1;
#else
(void)shp; (void)shpif; (void)rnd; (void)udp_connect;
(void)reusenum;
*port = 0;
*reused = 0;
return 1;
#endif
}
void shared_ports_return_port(struct shared_ports* shp,
struct shared_ports_if* shpif, int port)
{
#ifndef DISABLE_EXPLICIT_PORT_RANDOMISATION
if(!shpif)
return;
# ifdef THREADS_DISABLED
(void)shp;
# endif
lock_basic_lock(&shp->lock);
log_assert(shpif->inuse > 0);
shpif->avail_ports[shpif->avail_total - shpif->inuse] = port;
shpif->inuse--;
lock_basic_unlock(&shp->lock);
#else
(void)shp; (void)shpif; (void)port;
#endif
}

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