Compare commits

...
Author SHA1 Message Date
W.C.A. Wijngaards 22a36aa530 Merge branch 'master' into auth-load-thread 2026-10-21 11:56:30 +02:00
W.C.A. Wijngaards 1ca8678523 - Fix dynlibmod test for inplace callback termination. 2026-10-21 11:49:48 +02:00
W.C.A. Wijngaards 2478ca4c44 - auth-load-thread, fix to pass etag. 2026-10-21 11:40:07 +02:00
W.C.A. Wijngaards 81d192387d Merge branch 'master' into auth-load-thread 2026-10-21 11:24:14 +02:00
W.C.A. Wijngaards 37776636b6 - Unit test for CVE-2026-35501. 2026-10-21 11:07:51 +02:00
W.C.A. Wijngaards 1d0d27513a - Unit test for CVE-2026-50106. 2026-10-21 11:04:39 +02:00
W.C.A. Wijngaards 254492739d - The code repository continues with 1.26.3 under development,
that includes the changes from before the 1.26.2 commits.
2026-10-21 10:59:04 +02:00
W.C.A. Wijngaards 6f2f265616 Merge branch 'branch-1.26.2' 2026-10-21 10:56:27 +02:00
W.C.A. Wijngaards 0bb522715e - Fix testbound to free reference pending packet. 2026-10-20 18:27:32 +02:00
W.C.A. Wijngaards 2bd5309d20 - Fix to remove debug print from unit test. 2026-10-20 17:29:52 +02:00
W.C.A. Wijngaards d1dd5aa905 Merge branch 'master' of github.com:NLnetLabs/unbound 2026-10-20 17:29:25 +02:00
W.C.A. Wijngaards 1f05433d54 - Fix testbound so that it does not reference an already
deleted pending packet, but its packet contents, when
  removing from the pending list.
2026-10-20 17:28:28 +02:00
Yorgos Thessalonikefs 7d91d6345f - Terminate inplace callback progression if one of them errors out;
suggestion by Rio Fujita.
2026-10-20 16:51:37 +02:00
Willem Toorop 3fce3be652 Changelog entry for #1539:
- Merge #1539: Send along ETag with auth zone xfrs over http(s),
  so unbound will not fetch the whole zone every refresh time,
  but only when it has changed.
2026-10-20 16:45:13 +02:00
Willem TooropandGitHub f981776b07 Merge pull request #1539 from NLnetLabs/hackathon/get-root-zone-with-etag
Send along ETag with auth zone xfrs over http(s) - #1422
2026-10-20 16:44:47 +02:00
a5cd943877 Apply batched suggestions from code review
Review feedback from @wcawijngaards and @gthess

Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com>
Co-authored-by: Yorgos Thessalonikefs <yorgos@nlnetlabs.nl>
2026-10-20 16:26:37 +02:00
efad833e28 Apply batched suggestions from code review
Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com>
2026-10-20 15:41:12 +02:00
Willem Toorop 29bd80e53c Make test compile work 2026-10-20 15:25:58 +02:00
Willem TooropandGitHub 2f2d9229e7 Merge branch 'master' into hackathon/get-root-zone-with-etag 2026-10-20 14:39:58 +02:00
Yorgos Thessalonikefs 3d429e7fed Changelog entry for #1536:
- Merge #1536: Better documentation and warning message for no
  configured trust anchors.
2026-10-20 14:16:13 +02:00
Yorgos Thessalonikefs ed5b3b23b3 Merge branch 'validator-warn-no-trust' 2026-10-20 14:13:49 +02:00
Yorgos Thessalonikefs 970e7db1a0 - Better wording. 2026-10-20 12:41:46 +02:00
Yorgos Thessalonikefs ed954b6c18 - Add CONTRIBUTING.md, similar to other NLnet Labs projects. 2026-10-20 12:04:49 +02:00
W.C.A. Wijngaards 024730aca7 - Merge #1534: unbound-checkconf reads config, but zonefiles
are read with an option, '-a'. This speeds up the checkconf
  before server start in the presence of large zone files.
  And it is similar to how nsd-checkconf behaves.
2026-10-20 09:11:09 +02:00
Wouter WijngaardsandGitHub 660bfddeba unbound-checkconf reads config, but zonefiles are read with an option (#1534)
* - checkconf-zone-check, unbound-checkonf only reads config, -a option to read
  zone files of auth-zones and RPZ.

* - checkconf-zone-check, documentation in the man page.
2026-10-20 09:09:29 +02:00
Yorgos Thessalonikefs 3ed72c7681 - Fix #1535: [FR] refuse validator configuration without any trust anchor.
Better documentation and warning message.
2026-10-19 17:44:19 +02:00
W.C.A. Wijngaards 440d58045e Changelog note for #1532
- Merge #1532 from Ar-maan05: Fix packet position after a
  short RRSIG in pkt_rrsig_covered.
2026-10-19 10:54:56 +02:00
Armaan SandhuandGitHub e3a0ce98c4 Fix packet position after a short RRSIG in pkt_rrsig_covered (#1532)
pkt_rrsig_covered() moves the buffer position to the RRSIG's TTL and restores it before returning, except on the first early return, when fewer than 25 bytes are left. When it is called from rrset_has_sigover() on an earlier RRSIG while a later RR is being parsed, the parser then continues from the old RRSIG instead of the current RR, and that RR gets the RRSIG's TTL and rdata. Restore the position on that return too.
2026-10-19 10:54:13 +02:00
W.C.A. Wijngaards d498d8279f - auth-load-thread, copy the respip data RRset only if present for auth
load thread IXFR work.
2026-10-19 10:05:14 +02:00
W.C.A. Wijngaards c5de558e04 - Merge #1531 from nshopik: Fix dnstap queue registration race
between worker threads.
2026-10-19 09:39:13 +02:00
Nikolay ShopikandGitHub be5d1e967a - Fix dnstap queue registration race between worker threads. (#1531)
Workers push their message queue onto dtio->io_list from their own
threads at startup, with no lock, while the io thread may already walk
the list. Two concurrent pushes can lose a queue: the io thread never
drains it, and once its 1 MiB fills, every dnstap message from that
worker is dropped silently until restart.
2026-10-19 09:38:24 +02:00
W.C.A. Wijngaards 6cd9955385 Changelog note for #1528.
- Merge #1528 from Ar-maan05: Fix NSEC at apex detection for
  short type bitmaps.
2026-10-19 09:22:47 +02:00
Armaan SandhuandGitHub aa7634afeb Fix NSEC at apex detection for short type bitmaps (#1528)
nsec_at_apex() starts at the TTL, so the rdata ends at pos + 6 +
rdatalen (4 bytes TTL, 2 bytes rdlength), but both bounds checks use
pos + 4 + rdatalen.  An NSEC whose type bitmap is 3 or 4 bytes long
is then treated as malformed and not flagged as being at the apex,
even when the SOA bit is set.  Use the correct end of the rdata.
2026-10-19 09:21:51 +02:00
pettaiandGitHub 854ef1c2a4 log_nametypeclass -> VERB_DETAIL (#1529)
Don't log this at NO_VERBOSE/VERB_OPS level, it clutters the log especially then big zone updates happens.
This fits better at VERB_DETAIL level
2026-10-19 08:23:25 +02:00
W.C.A. Wijngaards ea96dcf166 Merge branch 'master' into auth-load-thread 2026-10-16 11:29:58 +02:00
W.C.A. Wijngaards d648eac68d - Fix unit test for root_zonemd with updated root key. 2026-10-16 11:29:30 +02:00
W.C.A. Wijngaards 0c4b782c8e - auth-load-thread, implement RPZ IXFR copy for auth load thread. Add unit
test for IXFR with auth load thread.
2026-10-15 15:55:33 +02:00
W.C.A. Wijngaards 8f022e1aa5 - auth-load-thread, release thread count when auth load thread is stopped
during fast_reload.
2026-10-15 11:49:57 +02:00
W.C.A. Wijngaards 7380fd7107 - auth-load-thread, unit test that exercises the reload and exit auth load
thread administration.
2026-10-15 11:16:23 +02:00
W.C.A. Wijngaards 456c85544b - auth-load-thread, fix to not log write error when auth load thread receives
a quit signal.
2026-10-15 11:03:45 +02:00
W.C.A. Wijngaards 276a2db8af - auth-load-thread, fix double delete on auth load thread create failure. 2026-10-15 11:00:48 +02:00
W.C.A. Wijngaards 6180f1b6d0 - auth-load-thread, close file when auth load thread receives quit signal. 2026-10-15 10:58:33 +02:00
W.C.A. Wijngaards 0acb0ab631 - auth-load-thread, release thread count when auth load thread is stopped
during reload and exit. Delete resume timer on cleanup for reload and exit.
2026-10-15 10:19:56 +02:00
W.C.A. Wijngaards cd0a585fbe Merge branch 'master' into auth-load-thread 2026-10-13 15:56:17 +02:00
Yorgos Thessalonikefs d1ea227e94 - Fix #1526: Root Server h.root-servers.net has been included for Zone
Transfer Service by including it in the example configuration.
2026-10-13 14:49:39 +02:00
W.C.A. Wijngaards 18d8676e9c - Fix dns64 synthesis and cache with subnet module enabled.
The subnet module stopped a cache store, that caused later
  dns64 replies to have a nodata answer for the AAAA.
2026-10-13 09:51:19 +02:00
W.C.A. Wijngaards 7c624d1dcd - auth-load-thread, fix pick up of active transfer after full list.
Add unit test for list of auth transfers.
2026-10-09 15:55:21 +02:00
W.C.A. Wijngaards e23010c18e - auth-load-thread, more generic result handling of the thread. 2026-10-09 09:47:13 +02:00
W.C.A. Wijngaards ddcbc291fe - auth-load-thread, delete threads postorder. 2026-10-07 11:48:21 +02:00
W.C.A. Wijngaards a119b1abc6 - auth-load-thread, init tree after stopping authloadthreads for worker. 2026-10-07 11:26:17 +02:00
W.C.A. Wijngaards f62214e714 - auth-load-thread, account write threads, unit test for zonefile write. 2026-10-07 11:10:16 +02:00
W.C.A. Wijngaards 3d1aaae57a - auth-load-thread, track thread in worker tree insertion. Remove unused
lines from compare function.
2026-10-07 10:30:57 +02:00
W.C.A. Wijngaards 614dcbf675 - auth-load-thread, quit auth load threads on exit and reload, and also
when fast_reload changes or deletes a zone.
2026-10-06 16:51:23 +02:00
W.C.A. Wijngaards add0065c43 - auth-load-thread, write to zonefile polls for thread quit. 2026-10-06 15:07:54 +02:00
W.C.A. Wijngaards 3d53f08bd8 - auth-load-thread, write to zonefile with thread. 2026-10-06 14:39:41 +02:00
W.C.A. Wijngaards 0dcd4cd2e8 - auth-load-thread, fix unit test for auth load rpz threads check. 2026-10-06 11:45:57 +02:00
W.C.A. Wijngaards b449d6f713 - auth-load-thread, documentation for auth-task-threads and tests disable
when there is no threading.
2026-10-06 11:44:29 +02:00
W.C.A. Wijngaards 6932ae18f5 - auth-load-thread, swap rpz contents, not config. Test for auth load rpz. 2026-10-06 11:29:54 +02:00
W.C.A. Wijngaards e2537840ba - auth-load-thread, setup RPZ after IXFR and AXFR processing. 2026-10-06 10:38:32 +02:00
W.C.A. Wijngaards b425be8e10 - auth-load-thread, resume waiting transfers. 2026-10-06 09:54:03 +02:00
W.C.A. Wijngaards bb408e503c - auth-load-thread, add num auth transfers and wait_transfer list. 2026-10-05 16:44:10 +02:00
W.C.A. Wijngaards 8942d11bb3 - auth-load-thread, fix for merge and http chunk list delete. 2026-10-05 09:19:59 +02:00
W.C.A. Wijngaards cb027ae649 Merge branch 'master' into auth-load-thread 2026-10-05 09:02:28 +02:00
Yorgos Thessalonikefs eafb027166 - Document libunbound's context lifetime during an async callback.
Thanks to Omar Mousa for the suggestion.
2026-10-02 16:01:19 +02:00
W.C.A. Wijngaards 40d36cda61 - Fix to allow for large (64Kb) packets with testbound. 2026-09-28 14:47:00 +02:00
W.C.A. Wijngaards 8cf2202c52 Changelog note and remove hash call assertion.
- Merge #1518 from nshopik: rrset: rehash copies after
  changing the key.
2026-09-28 11:56:09 +02:00
Nikolay ShopikandGitHub f6fff9efcb rrset: rehash copies after changing the key (#1518)
Copied rrsets that got a new owner name or flags kept the hash of
the source, so the rrset cache filed all of them in one hash bin.
Recompute the hash at each such site and assert it on cache update.
2026-09-28 11:53:24 +02:00
W.C.A. Wijngaards 97c001f9dd - Fix to log the errno for trust anchor write close fail. 2026-09-28 09:40:44 +02:00
Yorgos Thessalonikefs 1e12bef540 - Update generated man pages. 2026-09-22 12:17:02 +02:00
Yorgos Thessalonikefs b49f452f0a - Clarify man page text for harden-short-bufsize. 2026-09-22 12:14:14 +02:00
Yorgos Thessalonikefs 8820254637 - Move NORMAL_UDP_SIZE around. 2026-09-22 12:01:42 +02:00
Yorgos Thessalonikefs 5483a73856 - Fix #1513: [FR] Size of harden-large-queries in the man page. 2026-09-22 11:59:45 +02:00
Yorgos Thessalonikefs 0e2470450c - Fix #1514: [FR] do-not-query-localhost is not including
0.0.0.0/8 and ‘::’ in the manpage.
2026-09-22 10:43:25 +02:00
Yorgos Thessalonikefs 65814ad6f3 Changelog entry for #1510:
- Merge #1510 from Andy Warner: Move unlink of temp file to before
  fatal exit.
2026-09-21 14:13:00 +02:00
Yorgos ThessalonikefsandGitHub 97d6cc3643 Merge pull request #1510 from aww-aww/patch-1
Move unlink of temp file to before fatal exit
2026-09-21 14:08:55 +02:00
Andy WarnerandGitHub e79365ec61 Move unlink of temp file to before fatal exit
Ensure temporary file is deleted only on failure. As written this would never be executed.
2026-09-21 03:51:24 -06:00
W.C.A. Wijngaards a7fc80d8c5 - Unit test for CVE-2026-85501. 2026-09-16 10:47:44 +02:00
W.C.A. Wijngaards 5d89e0c2a7 - Unit test for CVE-2026-82717. 2026-09-16 10:44:49 +02:00
W.C.A. Wijngaards b45c8b4b53 - The code repository continues with 1.26.2 under development,
that includes the changes from before the 1.26.1 commits.
2026-09-16 10:34:06 +02:00
W.C.A. Wijngaards a6586ced92 Merge branch 'branch-1.26.1' 2026-09-16 10:26:54 +02:00
W.C.A. Wijngaards 3ad9b6aade - For #1507: TOCTOU race in store_rrsets() can return a
CNAME chain whose target owns no address.
2026-09-15 13:03:24 +02:00
W.C.A. Wijngaards 5ccee67af2 - Fix to error on missing close parenthesis for zone file
read and for url content read. Thanks to Qifan Zhang, Palo
  Alto Networks, for the report.
2026-09-10 16:12:49 +02:00
W.C.A. Wijngaards b8577a9c04 - Fix to construct the delegation point during DS NS find
as a child side delegation point if that was the response.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-09-10 11:09:39 +02:00
W.C.A. Wijngaards 18d9a5519e - Fix to elevate the diagnostic for no matches for a wildcard
trusted-keys-file, make it more descriptive, and more man
  page content for it. Thanks to Qifan Zhang, Palo Alto
  Networks, for the report.
2026-09-08 16:01:08 +02:00
W.C.A. Wijngaards 2df646e05f - Fix to not change the action override in rpz_config, before
the cname override has succeeded.
2026-09-04 17:20:15 +02:00
W.C.A. Wijngaards bdfa4d4c5d - Fix to make rpz_config leave the rpz with correct set up
on failure. The struct is not half configured on exit.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-09-04 17:06:34 +02:00
W.C.A. Wijngaards bd210d124b - Fix that when a partial EDNS option is in a query, the
response is a more RFC conformant FORMERR, since the EDNS
  option is malformed. Also fix to have an EDNS size for
  the reply error encoding for failed EDNS parse of the query.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-09-03 17:20:35 +02:00
W.C.A. Wijngaards 11900cc2b0 - Fix that when extended EDNS RCODE does not fit, at short
udpsize, the reply is truncated with TC and fix for the
  rcode in that short reply to be a sensible rcode.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-09-03 15:27:10 +02:00
W.C.A. Wijngaards c04a5efb07 - Fix to reorder SVCB and HTTPS svcparams for unknown RR form
zonefile input. If it can not be parsed it is leniently
  accepted, much like as a secondary it leniently accepts it.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-09-03 10:59:08 +02:00
W.C.A. Wijngaards 1060760650 - Remove unused .travis.yml for ci integration. 2026-09-03 10:25:31 +02:00
W.C.A. Wijngaards f251a1157b - Remove unused .travis.yml for ci integration. 2026-09-03 10:24:51 +02:00
W.C.A. Wijngaards 292cf6526b - Fix to match NSEC3 hash length to the NSEC3 algorithm,
this stops negative cache overdeletion. It also contrains
  the hash label length and checks if the NSEC nextowner
  is valid. Thanks to Yuqi Qiu & Xiang Li (Nankai University,
  AOSP Lab).
2026-09-03 08:38:46 +02:00
W.C.A. Wijngaards ac935b9144 - Fix to not commit to have_zone at apply AXFR time for auth
zone transfers, so that later failure rolls back to not.
  The have_zone value is set later when the SOA is retrieved.
  Also fix to clear the zone data when a transfer does not
  have a valid SOA record in the zone for it.
  Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-09-02 11:42:31 +02:00
W.C.A. Wijngaards 9dd370ba04 - Fix LOC RR parse to avoid double to uint32 cast overflow.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2026-09-01 17:21:45 +02:00
W.C.A. Wijngaards a6ccb2f74d - Fix to allow block_a and other local-zone types in a view. 2026-09-01 08:48:27 +02:00
W.C.A. Wijngaards 32ff948a5b - Fix notify for auth-zone during initial start up. It
performs the transfer and not only lookup.
2026-08-26 16:50:33 +02:00
W.C.A. Wijngaards 2ec2afd6b0 - Fix #132: Add harden-cname-follow: yes config option, that
can be used to disable cname scrubbing. That can be useful
  for when the traffic is on localhost only.
2026-08-24 16:06:17 +02:00
W.C.A. Wijngaards 7fb79b0677 - Fix to defend against double event deletion, that could cause
event corruption and use after free, for comm_timer_disable.
2026-08-21 10:29:58 +02:00
W.C.A. Wijngaards 48d0aea60a - auth-load-thread, unit test for auth_load_http. 2026-08-11 16:50:24 +02:00
W.C.A. Wijngaards 17bbcac979 - auth-load-thread, fix buffer free in http processing. 2026-08-11 16:50:00 +02:00
W.C.A. Wijngaards fd8ebbb19c Merge branch 'master' into auth-load-thread 2026-08-11 16:23:20 +02:00
W.C.A. Wijngaards 2adbbea365 - auth-load-thread, print thread details in log at high verbosity, 8. 2026-08-11 16:23:03 +02:00
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 156c00a727 Merge branch 'master' into auth-load-thread 2026-08-10 16:42:59 +02:00
W.C.A. Wijngaards d753f95956 - auth-load-thread, print time taken during auth load processing. 2026-08-10 16:42:04 +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 61d6c0e766 - auth-load-thread, implement active thread counter for auth load threads. 2026-07-07 17:21:16 +02:00
W.C.A. Wijngaards b4daa2d0fa - auth-load-thread, use define for constant for number of records before poll. 2026-07-07 16:26:42 +02:00
W.C.A. Wijngaards 425b701fb9 - auth-load-thread, fix memory leak on alloc failure when appending rrset
copy for ixfr main zone data copy.
2026-07-03 16:39:28 +02:00
W.C.A. Wijngaards 0a5cde80f1 - auth-load-thread, auth-task-threads: num config option that enables and
disables the auth load thread.
2026-07-03 14:03:15 +02:00
W.C.A. Wijngaards 58ede90fdb Merge branch 'master' into auth-load-thread 2026-07-02 15:28:24 +02:00
W.C.A. Wijngaards 55ae8da032 - auth-load-thread, basic test and fixes so it works. 2026-07-02 11:10:06 +02:00
W.C.A. Wijngaards 6bd86df72e - auth-load-thread, simplify cleanup in end transfer load process. 2026-07-02 08:55:13 +02:00
W.C.A. Wijngaards 0efd3605cc Merge branch 'master' into auth-load-thread 2026-07-01 16:54:55 +02:00
W.C.A. Wijngaards a2f2f53ef9 - auth-load-thread, process end of successful transfer. 2026-07-01 16:54:36 +02:00
W.C.A. Wijngaards b5a03093f6 - auth-load-thread, check for quit during the processing. 2026-07-01 14:41:40 +02:00
W.C.A. Wijngaards 8eba898135 - auth-load-thread, process AXFR, by loading, swap in, delete of old. 2026-07-01 14:27:31 +02:00
W.C.A. Wijngaards 56f66de89f - auth-load-thread, process IXFR, by making a copy, adjust changes, swap in. 2026-07-01 13:05:19 +02:00
W.C.A. Wijngaards 2fbaee2255 - auth-load-thread, process transfer content and swap result back in. 2026-06-30 16:53:27 +02:00
W.C.A. Wijngaards a122490461 - auth-load-thread, poll for quit and process load transfer end. 2026-06-29 16:52:20 +02:00
W.C.A. Wijngaards 7826b4f306 Merge branch 'master' into auth-load-thread 2026-06-29 16:00:01 +02:00
W.C.A. Wijngaards 380994219f - auth-load-thread, make and run auth load thread. 2026-06-26 17:11:12 +02:00
W.C.A. Wijngaards 153accb8de - auth-load-thread, put create_socketpair and sock_poll_timeout into
util/net_help.h
2026-06-26 15:22:08 +02:00
W.C.A. Wijngaards 7bb1c62263 - auth-load-thread, add authload.c to Makefile.in. 2026-06-26 14:27:12 +02:00
W.C.A. Wijngaards 1578b6e180 - auth-load-thread, add services/authload.c and services/authload.h 2026-06-26 14:00:04 +02:00
d4999d418c Apply suggestions from code review
Co-authored-by: Wouter Wijngaards <wcawijngaards@users.noreply.github.com>
2026-03-27 16:03:40 +01:00
Willem Toorop 7994365385 Send along ETag with auth zone xfrs over http
When fetching an authoritative zone over http(s), store the ETag if it
was send along in the response, and subsequentally send that along in
subsequent http(s) requests as a "If-None-Match: <ETag>| header.

This will prevent Unbound from fetching the full root zone every 30 minutes
when configured for local root wiht an url, but will instead only fetch
it when there is a different version.
2026-03-14 16:28:31 +08:00
144 changed files with 9977 additions and 1164 deletions
-380
View File
@@ -1,380 +0,0 @@
language: c
git:
depth: 5
addons:
apt:
packages:
- libssl-dev
- libevent-dev
- libexpat-dev
- clang
homebrew:
packages:
- openssl
- libevent
- expat
# homebrew update takes 20min or hangs, so disable update
#update: true
jobs:
include:
- os: linux
name: GCC on Linux, Amd64
compiler: gcc
arch: amd64
env:
- CONFIG_OPTS="--enable-debug --disable-flto"
- os: linux
name: Clang on Linux, Amd64, clang-analysis
compiler: clang
arch: amd64
env:
- CONFIG_OPTS="--enable-debug --disable-flto"
- TEST_ANALYZER=yes
- os: osx
osx_image: xcode12.2
name: Clang on OS X, Amd64, clang-analysis
compiler: clang
arch: amd64
env:
- TEST_OSX=yes
- CONFIG_OPTS="--enable-debug --disable-flto --with-ssl=/usr/local/opt/openssl --with-libexpat=/usr/local/opt/expat"
- TEST_ANALYZER=yes
- HOMEBREW_NO_AUTO_UPDATE=1
- os: linux
name: Libevent, GCC on Linux, Amd64
compiler: gcc
arch: amd64
env:
- TEST_LIBEVENT=yes
- CONFIG_OPTS="--with-libevent"
- os: linux
name: Libevent, Clang on Linux, Amd64
compiler: clang
arch: amd64
env:
- TEST_LIBEVENT=yes
- CONFIG_OPTS="--with-libevent"
- os: osx
osx_image: xcode12.2
name: Libevent, Clang on OS X, Amd64
compiler: clang
arch: amd64
env:
- TEST_OSX=yes
- TEST_LIBEVENT=yes
- CONFIG_OPTS="--disable-flto --with-ssl=/usr/local/opt/openssl --with-libevent=/usr/local/opt/libevent --with-libexpat=/usr/local/opt/expat"
- HOMEBREW_NO_AUTO_UPDATE=1
- os: linux
name: UBsan, GCC on Linux, Amd64
compiler: gcc
arch: amd64
dist: bionic
env:
- TEST_UBSAN=yes
- os: linux
name: UBsan, Clang on Linux, Amd64
compiler: clang
arch: amd64
dist: bionic
env:
- TEST_UBSAN=yes
- os: linux
name: Asan, GCC on Linux, Amd64
compiler: gcc
arch: amd64
dist: bionic
env:
- TEST_ASAN=yes
- os: linux
name: Asan, Clang on Linux, Amd64
compiler: clang
arch: amd64
dist: bionic
env:
- TEST_ASAN=yes
- os: linux
name: GCC on Linux, Aarch64
compiler: gcc
arch: arm64
dist: bionic
env:
- CONFIG_OPTS="--enable-debug --disable-flto"
- os: linux
name: Clang on Linux, Aarch64
compiler: clang
arch: arm64
dist: bionic
env:
- CONFIG_OPTS="--enable-debug --disable-flto"
- os: linux
name: GCC on Linux, PowerPC64
compiler: gcc
arch: ppc64le
dist: bionic
env:
- CONFIG_OPTS="--enable-debug --disable-flto"
- os: linux
name: Clang on Linux, PowerPC64
compiler: clang
arch: ppc64le
dist: bionic
env:
- CONFIG_OPTS="--enable-debug --disable-flto"
- os: linux
name: GCC on Linux, s390x
compiler: gcc
arch: s390x
dist: bionic
env:
- CONFIG_OPTS="--enable-debug --disable-flto"
- os: linux
name: Clang on Linux, s390x
compiler: clang
arch: s390x
dist: bionic
env:
- CONFIG_OPTS="--enable-debug --disable-flto"
- os: osx
osx_image: xcode12.2
name: Apple iPhone on iOS, armv7
compiler: clang
env:
- TEST_IOS=yes
- AUTOTOOLS_HOST=armv7-apple-ios
- OPENSSL_HOST=ios-cross
- IOS_SDK=iPhoneOS
- IOS_CPU=armv7s
- IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- HOMEBREW_NO_AUTO_UPDATE=1
- os: osx
osx_image: xcode12.2
name: Apple iPhone on iOS, arm64
compiler: clang
env:
- TEST_IOS=yes
- AUTOTOOLS_HOST=aarch64-apple-ios
- OPENSSL_HOST=ios64-cross
- IOS_SDK=iPhoneOS
- IOS_CPU=arm64
- IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- HOMEBREW_NO_AUTO_UPDATE=1
- os: osx
osx_image: xcode12.2
name: Apple TV on iOS, arm64
compiler: clang
env:
- TEST_IOS=yes
- AUTOTOOLS_HOST=aarch64-apple-ios
- OPENSSL_HOST=ios64-cross
- IOS_SDK=AppleTVOS
- IOS_CPU=arm64
- IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- HOMEBREW_NO_AUTO_UPDATE=1
- os: osx
osx_image: xcode12.2
name: Apple Watch on iOS, armv7
compiler: clang
env:
- TEST_IOS=yes
- AUTOTOOLS_HOST=armv7-apple-ios
- OPENSSL_HOST=ios-cross
- IOS_SDK=WatchOS
- IOS_CPU=armv7k
- IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- HOMEBREW_NO_AUTO_UPDATE=1
- os: osx
osx_image: xcode12.2
name: iPhoneSimulator on OS X, i386
env:
- TEST_IOS=yes
- AUTOTOOLS_HOST=i386-apple-ios
- OPENSSL_HOST=iphoneos-cross
- IOS_CPU=i386
- IOS_SDK=iPhoneSimulator
- IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- HOMEBREW_NO_AUTO_UPDATE=1
- os: osx
osx_image: xcode12.2
name: iPhoneSimulator on OS X, x86_64
env:
- TEST_IOS=yes
- AUTOTOOLS_HOST=x86_64-apple-ios
- OPENSSL_HOST=iphoneos-cross
- IOS_CPU=x86_64
- IOS_SDK=iPhoneSimulator
- IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- HOMEBREW_NO_AUTO_UPDATE=1
- os: osx
osx_image: xcode12.2
name: AppleTVSimulator on OS X, x86_64
env:
- TEST_IOS=yes
- AUTOTOOLS_HOST=x86_64-apple-ios
- OPENSSL_HOST=iphoneos-cross
- IOS_CPU=x86_64
- IOS_SDK=AppleTVSimulator
- IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- HOMEBREW_NO_AUTO_UPDATE=1
- os: osx
osx_image: xcode12.2
name: WatchSimulator on OS X, i386
env:
- TEST_IOS=yes
- AUTOTOOLS_HOST=i386-apple-ios
- OPENSSL_HOST=iphoneos-cross
- IOS_CPU=i386
- IOS_SDK=WatchSimulator
- IOS_PREFIX="$HOME/$IOS_SDK-$IOS_CPU"
- HOMEBREW_NO_AUTO_UPDATE=1
- os: linux
name: Android armv7a, Linux, Amd64
compiler: clang
arch: amd64
dist: bionic
env:
- TEST_ANDROID=yes
- AUTOTOOLS_HOST=armv7a-linux-androideabi
- OPENSSL_HOST=android-arm
- ANDROID_CPU=armv7a
- ANDROID_API=23
- ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU"
- ANDROID_SDK_ROOT="$HOME/android-sdk"
- ANDROID_NDK_ROOT="$HOME/android-ndk"
- os: linux
name: Android aarch64, Linux, Amd64
compiler: clang
arch: amd64
dist: bionic
env:
- TEST_ANDROID=yes
- AUTOTOOLS_HOST=aarch64-linux-android
- OPENSSL_HOST=android-arm64
- ANDROID_CPU=aarch64
- ANDROID_API=23
- ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU"
- ANDROID_SDK_ROOT="$HOME/android-sdk"
- ANDROID_NDK_ROOT="$HOME/android-ndk"
- os: linux
name: Android x86, Linux, Amd64
compiler: clang
arch: amd64
dist: bionic
env:
- TEST_ANDROID=yes
- AUTOTOOLS_HOST=i686-linux-android
- OPENSSL_HOST=android-x86
- ANDROID_CPU=x86
- ANDROID_API=23
- ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU"
- ANDROID_SDK_ROOT="$HOME/android-sdk"
- ANDROID_NDK_ROOT="$HOME/android-ndk"
- os: linux
name: Android x86_64, Linux, Amd64
compiler: clang
arch: amd64
dist: bionic
env:
- TEST_ANDROID=yes
- AUTOTOOLS_HOST=x86_64-linux-android
- OPENSSL_HOST=android-x86_64
- ANDROID_CPU=x86_64
- ANDROID_API=23
- ANDROID_PREFIX="$HOME/android$ANDROID_API-$ANDROID_CPU"
- ANDROID_SDK_ROOT="$HOME/android-sdk"
- ANDROID_NDK_ROOT="$HOME/android-ndk"
allow_failures:
- os: osx
name: Apple iPhone on iOS, armv7
- os: osx
name: Apple iPhone on iOS, arm64
- os: osx
name: Apple TV on iOS, arm64
- os: osx
name: Apple Watch on iOS, armv7
- os: osx
name: iPhoneSimulator on OS X, i386
- os: osx
name: iPhoneSimulator on OS X, x86_64
- os: osx
name: AppleTVSimulator on OS X, x86_64
- os: osx
name: WatchSimulator on OS X, i386
- os: linux
name: Android armv7a, Linux, Amd64
- os: linux
name: Android aarch64, Linux, Amd64
- os: linux
name: Android x86, Linux, Amd64
- os: linux
name: Android x86_64, Linux, Amd64
before_script:
- |
if [ "$TEST_ANDROID" = "yes" ]; then
./contrib/android/install_tools.sh
elif [ "$TEST_IOS" = "yes" ]; then
./contrib/ios/install_tools.sh
fi
# The Travis docs say to avoid calling exit in the script. It leads to
# some code duplication to avoid failures in cross-compiles. Also see
# https://docs.travis-ci.com/user/job-lifecycle/ in the Travis docs.
script:
- |
export MAKE_TEST="yes"
if [ "$TEST_UBSAN" = "yes" ]; then
export CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=undefined -fno-sanitize-recover=all"
elif [ "$TEST_ASAN" = "yes" ]; then
export CFLAGS="-DNDEBUG -g2 -O3 -fsanitize=address"
fi
- |
if [ "$TEST_IOS" = "yes" ]; then
export AUTOTOOLS_BUILD="$(./config.guess)"
export PKG_CONFIG_PATH="$IOS_PREFIX/lib/pkgconfig"
source ./contrib/ios/setenv_ios.sh
./contrib/ios/install_openssl.sh
./contrib/ios/install_expat.sh
export CONFIG_OPTS="\
--build=$AUTOTOOLS_BUILD --host=$AUTOTOOLS_HOST \
--prefix=$IOS_PREFIX \
--with-ssl=$IOS_PREFIX --disable-gost \
--with-libexpat=$IOS_PREFIX "
echo CONFIG_OPTS ${CONFIG_OPTS}
export MAKE_TEST=no
export TEST_INSTALL=yes
fi
- |
if [ "$TEST_ANDROID" = "yes" ]; then
export AUTOTOOLS_BUILD="$(./config.guess)"
export PKG_CONFIG_PATH="$ANDROID_PREFIX/lib/pkgconfig"
./contrib/android/install_ndk.sh
source ./contrib/android/setenv_android.sh
./contrib/android/install_openssl.sh
./contrib/android/install_expat.sh
export CONFIG_OPTS="\
--build=$AUTOTOOLS_BUILD --host=$AUTOTOOLS_HOST \
--prefix=$ANDROID_PREFIX \
--with-ssl=$ANDROID_PREFIX --disable-gost \
--with-libexpat=$ANDROID_PREFIX "
echo CONFIG_OPTS ${CONFIG_OPTS}
export MAKE_TEST=no
export TEST_INSTALL=yes
fi
- ./configure ${CONFIG_OPTS}
- make -j 2
- |
if [ "$MAKE_TEST" = "yes" ]; then
make test
fi
- |
if [ "$TEST_INSTALL" = "yes" ]; then
make install
fi
- |
if [ "$TEST_ANALYZER" = "yes" ]; then
(cd testdata/clang-analysis.tdir; bash clang-analysis.test)
fi
+54
View File
@@ -0,0 +1,54 @@
# Contributing to Unbound
This document offers guidelines on how to best contribute to Unbound, whether
it being new features or correcting flaws or bugs.
## Code of Conduct
This project and everyone participating in it is governed by the [NLnet Labs
Code of Conduct](https://www.nlnetlabs.nl/conduct/).
By participating, you are expected to uphold this code.
## LLM Policy
Before contributing to this project, please be aware of the [NLnet Labs LLM Policy](https://www.nlnetlabs.nl/llm-policy).
In a nutshell: we do not accept any LLM-generated contributions to
code or documentation.
## Join the Community
We invite you to join the [NLnet Labs Commununity
Forum](https://community.nlnetlabs.nl/) where Unbound has its own category.
Please don't open a GitHub issue for a question.
Instead, follow the discussion on the forum and ask questions there before you
start sending patches.
We prefer public discussions over private ones, so everyone in the community
can participate and learn.
## License and copyright
When contributing with code, you agree to put your changes and new code under
the same license Unbound is already using.
When changing existing source code, do not alter the copyright of the original
file(s).
The copyright will still be owned by the original creator(s) or those who have
been assigned copyright by the original author(s).
By submitting a patch to Unbound, you are assumed to have the right to the code
and to be allowed by your employer or whatever to hand over that patch/code
to us.
We will credit you for your changes as far as possible, to give credit but also
to keep a trace back to who made what changes.
## Sharing Your Changes
We would like you to submit a [pull request on
GitHub](https://github.com/NLnetLabs/Unbound/pulls).
Please note that you can create a draft pull request to indicate that you're
still working on something but still share it with the maintainers to get some
early feedback.
Once final, your change will be reviewed and discussed on GitHub.
You will be expected to correct flaws pointed out and update accordingly.
As a submitter of a change, you are the owner of that change until it has been
merged.
+4 -2
View File
@@ -125,7 +125,7 @@ services/localzone.c services/mesh.c services/modstack.c services/view.c \
services/rpz.c util/rfc_1982.c \
services/outbound_list.c services/outside_network.c util/alloc.c \
util/config_file.c util/configlexer.c util/configparser.c \
util/shm_side/shm_main.c services/authzone.c \
util/shm_side/shm_main.c services/authzone.c services/authload.c \
util/fptr_wlist.c util/locks.c util/log.c util/mini_event.c util/module.c \
util/netevent.c util/net_help.c util/random.c util/rbtree.c util/regional.c \
util/rtt.c util/siphash.c util/edns.c util/storage/dnstree.c util/storage/lookup3.c \
@@ -152,7 +152,8 @@ autotrust.lo val_anchor.lo rpz.lo rfc_1982.lo proxy_protocol.lo \
validator.lo val_kcache.lo val_kentry.lo val_neg.lo val_nsec3.lo val_nsec.lo \
val_secalgo.lo val_sigcrypt.lo val_utils.lo dns64.lo $(CACHEDB_OBJ) authzone.lo \
$(SUBNET_OBJ) $(PYTHONMOD_OBJ) $(CHECKLOCK_OBJ) $(DNSTAP_OBJ) $(DNSCRYPT_OBJ) \
$(IPSECMOD_OBJ) $(IPSET_OBJ) $(DYNLIBMOD_OBJ) respip.lo timeval_func.lo
$(IPSECMOD_OBJ) $(IPSET_OBJ) $(DYNLIBMOD_OBJ) respip.lo timeval_func.lo \
authload.lo
COMMON_OBJ_WITHOUT_UB_EVENT=$(COMMON_OBJ_WITHOUT_NETCALL) netevent.lo listen_dnsport.lo \
outside_network.lo
COMMON_OBJ=$(COMMON_OBJ_WITHOUT_UB_EVENT) ub_event.lo
@@ -721,6 +722,7 @@ depend:
ipset.lo ipset.o: $(srcdir)/ipset/ipset.c
doqclient.lo doqclient.o: $(srcdir)/testcode/doqclient.c
unitdoq.lo unitdoq.o: $(srcdir)/testcode/unitdoq.c
authload.lo authload.o: $(srcdir)/services/authload.c
# Dependencies
dns.lo dns.o: $(srcdir)/services/cache/dns.c config.h $(srcdir)/iterator/iter_delegpt.h $(srcdir)/util/log.h \
Vendored
+13 -12
View File
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.71 for unbound 1.26.2.
# Generated by GNU Autoconf 2.71 for unbound 1.26.3.
#
# Report bugs to <unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues>.
#
@@ -622,8 +622,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='unbound'
PACKAGE_TARNAME='unbound'
PACKAGE_VERSION='1.26.2'
PACKAGE_STRING='unbound 1.26.2'
PACKAGE_VERSION='1.26.3'
PACKAGE_STRING='unbound 1.26.3'
PACKAGE_BUGREPORT='unbound-bugs@nlnetlabs.nl or https://github.com/NLnetLabs/unbound/issues'
PACKAGE_URL=''
@@ -1513,7 +1513,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
\`configure' configures unbound 1.26.2 to adapt to many kinds of systems.
\`configure' configures unbound 1.26.3 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1579,7 +1579,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
short | recursive ) echo "Configuration of unbound 1.26.2:";;
short | recursive ) echo "Configuration of unbound 1.26.3:";;
esac
cat <<\_ACEOF
@@ -1832,7 +1832,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
unbound configure 1.26.2
unbound configure 1.26.3
generated by GNU Autoconf 2.71
Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2489,7 +2489,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
It was created by unbound $as_me 1.26.2, which was
It was created by unbound $as_me 1.26.3, which was
generated by GNU Autoconf 2.71. Invocation command line was
$ $0$ac_configure_args_raw
@@ -3253,11 +3253,11 @@ UNBOUND_VERSION_MAJOR=1
UNBOUND_VERSION_MINOR=26
UNBOUND_VERSION_MICRO=2
UNBOUND_VERSION_MICRO=3
LIBUNBOUND_CURRENT=9
LIBUNBOUND_REVISION=41
LIBUNBOUND_REVISION=42
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -3366,6 +3366,7 @@ LIBUNBOUND_AGE=1
# 1.26.0 had 9:39:1
# 1.26.1 had 9:40:1
# 1.26.2 had 9:41:1
# 1.26.3 had 9:42:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
@@ -25713,7 +25714,7 @@ printf "%s\n" "#define MAXSYSLOGMSGLEN 10240" >>confdefs.h
version=1.26.2
version=1.26.3
{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for build time" >&5
printf %s "checking for build time... " >&6; }
@@ -26243,7 +26244,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
This file was extended by unbound $as_me 1.26.2, which was
This file was extended by unbound $as_me 1.26.3, which was
generated by GNU Autoconf 2.71. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -26311,7 +26312,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config='$ac_cs_config_escaped'
ac_cs_version="\\
unbound config.status 1.26.2
unbound config.status 1.26.3
configured by $0, generated by GNU Autoconf 2.71,
with options \\"\$ac_cs_config\\"
+3 -2
View File
@@ -12,14 +12,14 @@ sinclude(dnscrypt/dnscrypt.m4)
# must be numbers. ac_defun because of later processing
m4_define([VERSION_MAJOR],[1])
m4_define([VERSION_MINOR],[26])
m4_define([VERSION_MICRO],[2])
m4_define([VERSION_MICRO],[3])
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=41
LIBUNBOUND_REVISION=42
LIBUNBOUND_AGE=1
# 1.0.0 had 0:12:0
# 1.0.1 had 0:13:0
@@ -128,6 +128,7 @@ LIBUNBOUND_AGE=1
# 1.26.0 had 9:39:1
# 1.26.1 had 9:40:1
# 1.26.2 had 9:41:1
# 1.26.3 had 9:42:1
# Current -- the number of the binary API that we're implementing
# Revision -- which iteration of the implementation of the binary
+1 -1
View File
@@ -554,7 +554,7 @@ move_into_cache(struct ub_packed_rrset_key* k,
ref.key = ak;
ref.id = ak->id;
(void)rrset_cache_update(worker->env.rrset_cache, &ref,
rrset_cache_update_unlock(worker->env.rrset_cache, &ref,
worker->alloc, *worker->env.now);
return 1;
+16 -1
View File
@@ -86,6 +86,7 @@
#include "services/view.h"
#include "services/modstack.h"
#include "services/authzone.h"
#include "services/authload.h"
#include "util/module.h"
#include "util/random.h"
#include "util/tube.h"
@@ -590,6 +591,17 @@ daemon_init(void)
free(daemon);
return NULL;
}
if(!(daemon->auth_load_info = auth_load_info_create())) {
edns_strings_delete(daemon->env->edns_strings);
auth_zones_delete(daemon->env->auth_zones);
acl_list_delete(daemon->acl_interface);
acl_list_delete(daemon->acl);
tcl_list_delete(daemon->tcl);
edns_known_options_delete(daemon->env);
free(daemon->env);
free(daemon);
return NULL;
}
return daemon;
}
@@ -1077,7 +1089,7 @@ daemon_fork(struct daemon* daemon)
daemon_setup_modules(daemon);
/* read auth zonefiles */
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1,
if(!auth_zones_apply_cfg(daemon->env->auth_zones, daemon->cfg, 1, 1,
&daemon->use_rpz, daemon->env, &daemon->mods))
fatal_exit("auth_zones could not be setup");
@@ -1164,6 +1176,7 @@ daemon_fork(struct daemon* daemon)
/* we exited! a signal happened! Stop other threads */
daemon_stop_others(daemon);
auth_load_stop_threads(daemon);
/* Shutdown SHM */
shm_main_shutdown(daemon);
@@ -1204,6 +1217,7 @@ daemon_cleanup(struct daemon* daemon)
daemon->env->views = NULL;
if(daemon->env->auth_zones)
auth_zones_cleanup(daemon->env->auth_zones);
auth_load_info_cleanup(daemon->auth_load_info);
/* key cache is cleared by module deinit during next daemon_fork() */
daemon_remote_clear(daemon->rc);
if(daemon->fast_reload_thread)
@@ -1262,6 +1276,7 @@ daemon_delete(struct daemon* daemon)
edns_strings_delete(daemon->env->edns_strings);
auth_zones_delete(daemon->env->auth_zones);
}
auth_load_info_delete(daemon->auth_load_info);
ub_randfree(daemon->rand);
alloc_clear(&daemon->superalloc);
acl_list_delete(daemon->acl);
+3
View File
@@ -62,6 +62,7 @@ struct doq_table;
struct cookie_secrets;
struct fast_reload_thread;
struct fast_reload_printq;
struct auth_load_general_info;
struct shared_ports;
#include "dnstap/dnstap_config.h"
@@ -191,6 +192,8 @@ struct daemon {
int fast_reload_tcl_has_changes;
/** config file name */
char* cfgfile;
/** Auth load threads, the number of active threads. */
struct auth_load_general_info* auth_load_info;
};
/**
+35 -373
View File
@@ -73,6 +73,7 @@
#include "services/mesh.h"
#include "services/localzone.h"
#include "services/authzone.h"
#include "services/authload.h"
#include "services/rpz.h"
#include "util/storage/slabhash.h"
#include "util/fptr_wlist.h"
@@ -115,9 +116,6 @@
#ifdef HAVE_NETDB_H
#include <netdb.h>
#endif
#ifdef HAVE_POLL_H
#include <poll.h>
#endif
/* just for portability */
#ifdef SQ
@@ -2681,7 +2679,7 @@ static int
ssl_print_name_dp(RES* ssl, const char* str, uint8_t* nm, uint16_t dclass,
struct delegpt* dp)
{
char buf[LDNS_MAX_DOMAINLEN];
char buf[LDNS_MAX_DOMAINLEN], portstr[128], tls_auth_name[256];
struct delegpt_ns* ns;
struct delegpt_addr* a;
int f = 0;
@@ -2696,13 +2694,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;
}
@@ -4447,92 +4464,6 @@ int remote_control_callback(struct comm_point* c, void* arg, int err,
return 0;
}
/**
* This routine polls a socket for readiness.
* @param fd: file descriptor, -1 uses no fd for a timer only.
* @param timeout: time in msec to wait. 0 means nonblocking test,
* -1 waits blocking for events.
* @param pollin: check for input event.
* @param pollout: check for output event.
* @param event: output variable, set to true if the event happens.
* It is false if there was an error or timeout.
* @return false is system call failure, also logged.
*/
static int
sock_poll_timeout(int fd, int timeout, int pollin, int pollout, int* event)
{
int loopcount = 0;
/* Loop if the system call returns an errno to do so, like EINTR. */
log_assert(pollin || pollout);
while(1) {
struct pollfd p, *fds;
int nfds, ret;
if(++loopcount > IPC_LOOP_MAX) {
log_err("sock_poll_timeout: loop");
if(event)
*event = 0;
return 0;
}
if(fd == -1) {
fds = NULL;
nfds = 0;
} else {
fds = &p;
nfds = 1;
memset(&p, 0, sizeof(p));
p.fd = fd;
#ifndef USE_WINSOCK
p.events = POLLERR
| POLLHUP
;
#endif
if(pollin)
p.events |= POLLIN;
if(pollout)
p.events |= POLLOUT;
}
#ifndef USE_WINSOCK
ret = poll(fds, nfds, timeout);
#else
if(fds == NULL) {
Sleep(timeout);
ret = 0;
} else {
ret = WSAPoll(fds, nfds, timeout);
}
#endif
if(ret == -1) {
#ifndef USE_WINSOCK
if(
errno == EINTR || errno == EAGAIN
# ifdef EWOULDBLOCK
|| errno == EWOULDBLOCK
# endif
) continue; /* Try again. */
#endif
/* For WSAPoll we only get errors here:
* o WSAENETDOWN
* o WSAEFAULT
* o WSAEINVAL
* o WSAENOBUFS
*/
log_err("poll: %s", sock_strerror(errno));
if(event)
*event = 0;
return 0;
} else if(ret == 0) {
/* Timeout */
if(event)
*event = 0;
return 1;
}
break;
}
if(event)
*event = 1;
return 1;
}
/** fast reload convert fast reload notification status to string */
static const char*
fr_notification_to_string(enum fast_reload_notification status)
@@ -5961,7 +5892,7 @@ fr_construct_from_config(struct fast_reload_thread* fr,
fr_construct_clear(ct);
return 0;
}
if(!auth_zones_apply_cfg(ct->auth_zones, newcfg, 1, &ct->use_rpz,
if(!auth_zones_apply_cfg(ct->auth_zones, newcfg, 1, 1, &ct->use_rpz,
fr->worker->daemon->env, &fr->worker->daemon->mods)) {
fr_construct_clear(ct);
return 0;
@@ -6346,6 +6277,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
COPY_VAR_ptr(acls);
COPY_VAR_int(donotquery_localhost);
COPY_VAR_ptr(tcp_connection_limits);
COPY_VAR_int(auth_task_threads);
COPY_VAR_int(harden_short_bufsize);
COPY_VAR_int(harden_large_queries);
COPY_VAR_int(harden_glue);
@@ -6354,6 +6286,7 @@ fr_atomic_copy_cfg(struct config_file* oldcfg, struct config_file* cfg,
COPY_VAR_int(harden_referral_path);
COPY_VAR_int(harden_algo_downgrade);
COPY_VAR_int(harden_unknown_additional);
COPY_VAR_int(harden_cname_follow);
COPY_VAR_int(use_caps_bits_for_id);
COPY_VAR_ptr(caps_whitelist);
COPY_VAR_ptr(private_address);
@@ -7136,286 +7069,6 @@ done_error:
}
#endif /* !THREADS_DISABLED */
/** create a socketpair for bidirectional communication, false on failure */
static int
create_socketpair(int* pair, struct ub_randstate* rand)
{
#ifndef USE_WINSOCK
if(socketpair(AF_UNIX, SOCK_STREAM, 0, pair) == -1) {
log_err("socketpair: %s", strerror(errno));
return 0;
}
(void)rand;
#else
struct sockaddr_in addr, baddr, accaddr, connaddr;
socklen_t baddrlen, accaddrlen, connaddrlen;
uint8_t localhost[] = {127, 0, 0, 1};
uint8_t nonce[16], recvnonce[16];
size_t i;
int lst, pollin_event, bcount, loopcount;
int connect_poll_timeout = 200; /* msec to wait for connection */
ssize_t ret;
pair[0] = -1;
pair[1] = -1;
for(i=0; i<sizeof(nonce); i++) {
nonce[i] = ub_random_max(rand, 256);
}
lst = socket(AF_INET, SOCK_STREAM, 0);
if(lst == -1) {
log_err("create_socketpair: socket: %s", sock_strerror(errno));
return 0;
}
memset(&addr, 0, sizeof(addr));
addr.sin_family = AF_INET;
addr.sin_port = 0;
memcpy(&addr.sin_addr, localhost, 4);
if(bind(lst, (struct sockaddr*)&addr, (socklen_t)sizeof(addr))
== -1) {
log_err("create socketpair: bind: %s", sock_strerror(errno));
sock_close(lst);
return 0;
}
if(listen(lst, 12) == -1) {
log_err("create socketpair: listen: %s", sock_strerror(errno));
sock_close(lst);
return 0;
}
pair[1] = socket(AF_INET, SOCK_STREAM, 0);
if(pair[1] == -1) {
log_err("create socketpair: socket: %s", sock_strerror(errno));
sock_close(lst);
return 0;
}
baddrlen = (socklen_t)sizeof(baddr);
if(getsockname(lst, (struct sockaddr*)&baddr, &baddrlen) == -1) {
log_err("create socketpair: getsockname: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(baddrlen > (socklen_t)sizeof(baddr)) {
log_err("create socketpair: getsockname returned addr too big");
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
/* the socket is blocking */
if(connect(pair[1], (struct sockaddr*)&baddr, baddrlen) == -1) {
log_err("create socketpair: connect: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(!sock_poll_timeout(lst, connect_poll_timeout, 1, 0, &pollin_event)) {
log_err("create socketpair: poll for accept failed: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(!pollin_event) {
log_err("create socketpair: poll timeout for accept");
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
accaddrlen = (socklen_t)sizeof(accaddr);
pair[0] = accept(lst, (struct sockaddr*)&accaddr, &accaddrlen);
if(pair[0] == -1) {
log_err("create socketpair: accept: %s", sock_strerror(errno));
sock_close(lst);
sock_close(pair[1]);
pair[1] = -1;
return 0;
}
if(accaddrlen > (socklen_t)sizeof(accaddr)) {
log_err("create socketpair: accept returned addr too big");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(accaddr.sin_family != AF_INET ||
memcmp(localhost, &accaddr.sin_addr, 4) != 0) {
log_err("create socketpair: accept from wrong address");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
connaddrlen = (socklen_t)sizeof(connaddr);
if(getsockname(pair[1], (struct sockaddr*)&connaddr, &connaddrlen)
== -1) {
log_err("create socketpair: getsockname connectedaddr: %s",
sock_strerror(errno));
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(connaddrlen > (socklen_t)sizeof(connaddr)) {
log_err("create socketpair: getsockname connectedaddr returned addr too big");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(connaddr.sin_family != AF_INET ||
memcmp(localhost, &connaddr.sin_addr, 4) != 0) {
log_err("create socketpair: getsockname connectedaddr returned wrong address");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(accaddr.sin_port != connaddr.sin_port) {
log_err("create socketpair: accept from wrong port");
sock_close(lst);
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
sock_close(lst);
loopcount = 0;
bcount = 0;
while(1) {
if(++loopcount > IPC_LOOP_MAX) {
log_err("create socketpair: send failed due to loop");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
ret = send(pair[1], (void*)(nonce+bcount),
sizeof(nonce)-bcount, 0);
if(ret == -1) {
if(
#ifndef USE_WINSOCK
errno == EINTR || errno == EAGAIN
# ifdef EWOULDBLOCK
|| errno == EWOULDBLOCK
# endif
#else
WSAGetLastError() == WSAEINTR ||
WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEWOULDBLOCK
#endif
)
continue; /* Try again. */
log_err("create socketpair: send: %s", sock_strerror(errno));
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
} else if(ret+(ssize_t)bcount != sizeof(nonce)) {
bcount += ret;
if((size_t)bcount < sizeof(nonce))
continue;
}
break;
}
if(!sock_poll_timeout(pair[0], connect_poll_timeout, 1, 0, &pollin_event)) {
log_err("create socketpair: poll failed: %s",
sock_strerror(errno));
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
if(!pollin_event) {
log_err("create socketpair: poll timeout for recv");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
loopcount = 0;
bcount = 0;
while(1) {
if(++loopcount > IPC_LOOP_MAX) {
log_err("create socketpair: recv failed due to loop");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
ret = recv(pair[0], (void*)(recvnonce+bcount),
sizeof(nonce)-bcount, 0);
if(ret == -1) {
if(
#ifndef USE_WINSOCK
errno == EINTR || errno == EAGAIN
# ifdef EWOULDBLOCK
|| errno == EWOULDBLOCK
# endif
#else
WSAGetLastError() == WSAEINTR ||
WSAGetLastError() == WSAEINPROGRESS ||
WSAGetLastError() == WSAEWOULDBLOCK
#endif
)
continue; /* Try again. */
log_err("create socketpair: recv: %s", sock_strerror(errno));
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
} else if(ret == 0) {
log_err("create socketpair: stream closed");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
} else if(ret+(ssize_t)bcount != sizeof(nonce)) {
bcount += ret;
if((size_t)bcount < sizeof(nonce))
continue;
}
break;
}
if(memcmp(nonce, recvnonce, sizeof(nonce)) != 0) {
log_err("create socketpair: recv wrong nonce");
sock_close(pair[0]);
sock_close(pair[1]);
pair[0] = -1;
pair[1] = -1;
return 0;
}
#endif
return 1;
}
/** fast reload thread. setup the thread info */
static int
fast_reload_thread_setup(struct worker* worker, int fr_verb, int fr_nopause,
@@ -7792,6 +7445,13 @@ auth_zone_zonemd_stop_lookup(struct auth_zone* z, struct mesh_area* mesh)
{
struct query_info qinfo;
uint16_t qflags = BIT_RD;
if(z->zonemd_transfer_active) {
auth_load_info_release_transfer_in_progress(
z->zonemd_callback_env);
auth_load_schedule_waiting_pickup(z->zonemd_callback_env);
z->zonemd_transfer_active = 0;
}
qinfo.qname_len = z->namelen;
qinfo.qname = z->name;
qinfo.qclass = z->dclass;
@@ -7873,6 +7533,8 @@ fr_worker_auth_del(struct worker* worker, struct fast_reload_auth_change* item,
released = 1;
xfr_disown_tasks(xfr, worker);
}
auth_load_del_zone_tasks(worker, xfr->name, xfr->namelen,
xfr->dclass);
lock_basic_unlock(&xfr->lock);
}
+4 -2
View File
@@ -59,6 +59,7 @@
#include "services/cache/infra.h"
#include "services/cache/dns.h"
#include "services/authzone.h"
#include "services/authload.h"
#include "services/mesh.h"
#include "services/localzone.h"
#include "services/rpz.h"
@@ -95,8 +96,6 @@
#include "winrc/win_svc.h"
#endif
/** Size of an UDP datagram */
#define NORMAL_UDP_SIZE 512 /* bytes */
/** ratelimit for error responses */
#define ERROR_RATELIMIT 100 /* qps */
@@ -1706,6 +1705,8 @@ worker_handle_request(struct comm_point* c, void* arg, int error,
}
memset(&reply_edns, 0, sizeof(reply_edns));
reply_edns.edns_present = 1;
reply_edns.edns_version = EDNS_ADVERTISED_VERSION;
reply_edns.udp_size = EDNS_ADVERTISED_SIZE;
error_encode(c->buffer, ret, &qinfo,
*(uint16_t*)(void *)sldns_buffer_begin(c->buffer),
sldns_buffer_read_u16_at(c->buffer, 2), &reply_edns);
@@ -2262,6 +2263,7 @@ worker_create(struct daemon* daemon, int id)
free(worker);
return NULL;
}
rbtree_init(&worker->auth_load_tree, auth_load_tree_cmp);
explicit_bzero(&seed, sizeof(seed));
return worker;
}
+3
View File
@@ -47,6 +47,7 @@
#include "util/netevent.h"
#include "util/locks.h"
#include "util/alloc.h"
#include "util/rbtree.h"
#include "util/data/msgreply.h"
#include "util/data/msgparse.h"
#include "daemon/stats.h"
@@ -135,6 +136,8 @@ struct worker {
#endif
/** reuse existing cache on reload if other conditions allow it. */
int reuse_cache;
/** tree of auth load threads, attached to this worker. */
rbtree_type auth_load_tree;
};
/**
+1
View File
@@ -968,6 +968,7 @@ dns64_adjust_ptr(struct module_qstate* qstate, struct module_qstate* super)
if(answer) {
answer->rk.dname = super->qinfo.qname;
answer->rk.dname_len = super->qinfo.qname_len;
answer->entry.hash = rrset_key_hash(&answer->rk);
}
}
+19 -2
View File
@@ -307,6 +307,11 @@ struct dt_io_thread* dt_io_thread_create(void)
lock_basic_init(&dtio->wakeup_timer_lock);
lock_protect(&dtio->wakeup_timer_lock, &dtio->wakeup_timer_enabled,
sizeof(dtio->wakeup_timer_enabled));
lock_basic_init(&dtio->io_list_lock);
lock_protect(&dtio->io_list_lock, &dtio->io_list,
sizeof(dtio->io_list));
lock_protect(&dtio->io_list_lock, &dtio->io_list_iter,
sizeof(dtio->io_list_iter));
return dtio;
}
@@ -315,6 +320,7 @@ void dt_io_thread_delete(struct dt_io_thread* dtio)
struct dt_io_list_item* item, *nextitem;
if(!dtio) return;
lock_basic_destroy(&dtio->wakeup_timer_lock);
lock_basic_destroy(&dtio->io_list_lock);
item=dtio->io_list;
while(item) {
nextitem = item->next;
@@ -463,9 +469,11 @@ int dt_io_thread_register_queue(struct dt_io_thread* dtio,
mq->dtio = dtio;
lock_basic_unlock(&mq->lock);
item->queue = mq;
lock_basic_lock(&dtio->io_list_lock);
item->next = dtio->io_list;
dtio->io_list = item;
dtio->io_list_iter = NULL;
lock_basic_unlock(&dtio->io_list_lock);
return 1;
}
@@ -474,6 +482,7 @@ void dt_io_thread_unregister_queue(struct dt_io_thread* dtio,
{
struct dt_io_list_item* item, *prev=NULL;
if(!dtio) return;
lock_basic_lock(&dtio->io_list_lock);
item = dtio->io_list;
while(item) {
if(item->queue == mq) {
@@ -486,11 +495,13 @@ void dt_io_thread_unregister_queue(struct dt_io_thread* dtio,
lock_basic_unlock(&item->queue->lock);
free(item);
dtio->io_list_iter = NULL;
lock_basic_unlock(&dtio->io_list_lock);
return;
}
prev = item;
item = item->next;
}
lock_basic_unlock(&dtio->io_list_lock);
}
/** pick a message from the queue, the routine locks and unlocks,
@@ -537,6 +548,7 @@ static int dtio_find_msg(struct dt_io_thread* dtio)
{
struct dt_io_list_item *spot, *item;
lock_basic_lock(&dtio->io_list_lock);
spot = dtio->io_list_iter;
/* use the next queue for the next message lookup,
* if we hit the end(NULL) the NULL restarts the iter at start. */
@@ -548,17 +560,22 @@ static int dtio_find_msg(struct dt_io_thread* dtio)
/* scan from spot to end-of-io_list */
item = spot;
while(item) {
if(dtio_find_in_queue(dtio, item->queue))
if(dtio_find_in_queue(dtio, item->queue)) {
lock_basic_unlock(&dtio->io_list_lock);
return 1;
}
item = item->next;
}
/* scan starting at the start-of-list (to wrap around the end) */
item = dtio->io_list;
while(item) {
if(dtio_find_in_queue(dtio, item->queue))
if(dtio_find_in_queue(dtio, item->queue)) {
lock_basic_unlock(&dtio->io_list_lock);
return 1;
}
item = item->next;
}
lock_basic_unlock(&dtio->io_list_lock);
return 0;
}
+2
View File
@@ -123,6 +123,8 @@ struct dt_io_thread {
int threadnum;
/** event base, for event handling */
void* event_base;
/** lock on io_list and io_list_iter */
lock_basic_type io_list_lock;
/** list of queues that is registered to get written */
struct dt_io_list_item* io_list;
/** iterator point in the io_list, to pick from them in a
+248
View File
@@ -1,3 +1,251 @@
21 October 2026: Wouter
- Release of 1.26.2 with the following security fixes.
- Fix CVE-2026-97206, DoQ path-migration can lead to use-after-free on
multi-threaded deployments. Thanks to Kunta Chu and Jianjun Chen
from Tsinghua University for the report.
- Fix CVE-2026-50106, Possible insecure NXDOMAIN for non-existing
records under a configured island trust anchor underneath an
insecure parent. Thanks to Qifan Zhang from Palo Alto Networks
for the report.
- Fix CVE-2026-96405, Aggregate DNS name chained pointer decompression
work leads to degradation of service. Thanks to Yuheng Zhang
(Tsinghua University and Jingxian Technology Co., Ltd.), Jianjun
Chen (Tsinghua University), Zihan Wang (Z.AI Co., Ltd.) and Kaiwen
Shen (CloudItera) for the report.
- Fix CVE-2026-109125, Possible cache poisoning vulnerability via
a cache side-channel exposed by 'unwanted-reply-threshold'. Thanks
to TaoFei Guo (Peking University), and Yang Luo and JianJun Chen
(Tsinghua University) for the report.
- Fix CVE-2026-35501, Bypass of a configured island trust anchor
underneath an insecure parent from an attacker-controlled NSEC
record. Thanks to Qifan Zhang from Palo Alto Networks for the
report.
- The code repository continues with 1.26.3 under development,
that includes the changes from before the 1.26.2 commits.
- Unit test for CVE-2026-50106.
- Unit test for CVE-2026-35501.
- Fix dynlibmod test for inplace callback termination.
20 October 2026: Willem
- Merge #1539: Send along ETag with auth zone xfrs over http(s),
so Unbound will not fetch the whole zone every refresh time,
but only when it has changed.
20 October 2026: Wouter
- Merge #1534: unbound-checkconf reads config, but zonefiles
are read with an option, '-a'. This speeds up the checkconf
before server start in the presence of large zone files.
And it is similar to how nsd-checkconf behaves.
- Fix testbound so that it does not reference an already
deleted pending packet, but its packet contents, when
removing from the pending list.
- Fix to remove debug print from unit test.
- Fix testbound to free reference pending packet.
20 October 2026: Yorgos
- Add CONTRIBUTING.md, similar to other NLnet Labs projects.
- Merge #1536: Better documentation and warning message for no
configured trust anchors.
- Terminate inplace callback progression if one of them errors out;
suggestion by Rio Fujita.
19 October 2026: Wouter
- Merge #1528 from Ar-maan05: Fix NSEC at apex detection for
short type bitmaps.
- Merge #1531 from nshopik: Fix dnstap queue registration race
between worker threads.
- Merge #1532 from Ar-maan05: Fix packet position after a
short RRSIG in pkt_rrsig_covered.
16 October 2026: Wouter
- Fix unit test for root_zonemd with updated root key.
13 October 2026: Wouter
- Fix dns64 synthesis and cache with subnet module enabled.
The subnet module stopped a cache store, that caused later
dns64 replies to have a nodata answer for the AAAA.
13 October 2026: Yorgos
- Fix #1526: Root Server h.root-servers.net has been included for Zone
Transfer Service by including it in the example configuration.
2 October 2026: Yorgos
- Document libunbound's context lifetime during an async callback.
Thanks to Omar Mousa for the suggestion.
28 September 2026: Wouter
- Fix to log the errno for trust anchor write close fail.
- Merge #1518 from nshopik: rrset: rehash copies after
changing the key.
- Fix to allow for large (64Kb) packets with testbound.
22 September 2026: Yorgos
- Fix #1514: [FR] do-not-query-localhost is not including
0.0.0.0/8 and ‘::’ in the man page.
- Fix #1513: [FR] Size of harden-large-queries in the man page.
- Move NORMAL_UDP_SIZE around.
- Clarify man page text for harden-short-bufsize.
- Update generated man pages.
21 September 2026: Yorgos
- Merge #1510 from Andy Warner: Move unlink of temp file to before
fatal exit.
16 September 2026: Wouter
- Release of 1.26.1 with the following security fixes.
- Fix CVE-2026-81642, Heap buffer overflow and possible Remote Code
Execution when digesting DNSKEY. Thanks to Yuqi Qiu and Xiang Li
from Nankai University, AOSP Lab for the report.
- Fix CVE-2026-81634, Possible heap buffer overflow during DNSSEC
canonicalization. Thanks to Vlatko Kosturjak with Marlink Cyber,
for the report.
- Fix CVE-2026-82717, CNAME synthesis could lead to heap corruption.
Thanks to Ben Morris from Anthropic for the report.
- Fix CVE-2026-77955, Possible ZONEMD verification bypass window.
Thanks to Yuqi Qiu and Xiang Li from Nankai University, AOSP Lab,
for the report. In addition, thanks to Qifan Zhang from Palo Alto
Networks for also reporting this issue.
- Fix CVE-2026-78227, Use-after-free in DoQ stream output buffer on
reset re-transmission. Thanks to Yuqi Qiu and Xiang Li from Nankai
University, AOSP Lab for the report.
- Fix CVE-2026-80225, Possible degradation of service from continuous
queries on the same TCP/DoT connection. Thanks to Qifan Zhang from
Palo Alto Networks for the report.
- Fix CVE-2026-82720, Use-after-free in DoH stream cleanup code path.
Thanks to Yuqi Qiu and Xiang Li from Nankai University, AOSP Lab,
for the report.
- Fix CVE-2026-85501, Retrap: Novel Vulnerabilities to launch
Algorithmic Complexity Attacks on DNSSEC. Thanks to Zuyao Xu and
Xiang Li from Nankai University, AOSP Lab for the report. In
addition, thanks to Qifan Zhang from Palo Alto Networks for a
complimentary report.
- Fix CVE-2026-77860, 'serve-expired' can bypass Unbound 'wait-limit'.
Thanks to Xuanchao Xie, Lutong Chen, and Kaiping Xue from the
University of Science and Technology of China (USTC) for the
report.
- The code repository continues with 1.26.2 under development,
that includes the changes from before the 1.26.1 commits.
- Unit test for CVE-2026-81642.
- Unit test for CVE-2026-82717.
- Unit test for CVE-2026-85501.
15 September 2026: Wouter
- For #1507: TOCTOU race in store_rrsets() can return a
CNAME chain whose target owns no address.
10 September 2026: Wouter
- Fix to construct the delegation point during DS NS find
as a child side delegation point if that was the response.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix to error on missing close parenthesis for zone file
read and for url content read. Thanks to Qifan Zhang, Palo
Alto Networks, for the report.
8 September 2026: Wouter
- Fix to elevate the diagnostic for no matches for a wildcard
trusted-keys-file, make it more descriptive, and more man
page content for it. Thanks to Qifan Zhang, Palo Alto
Networks, for the report.
4 September 2026: Wouter
- Fix to make rpz_config leave the rpz with correct set up
on failure. The struct is not half configured on exit.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix to not change the action override in rpz_config, before
the cname override has succeeded.
3 September 2026: Wouter
- Fix to match NSEC3 hash length to the NSEC3 algorithm,
this stops negative cache overdeletion. It also contrains
the hash label length and checks if the NSEC nextowner
is valid. Thanks to Yuqi Qiu & Xiang Li (Nankai University,
AOSP Lab).
- Remove unused .travis.yml for ci integration.
- Fix to reorder SVCB and HTTPS svcparams for unknown RR form
zonefile input. If it can not be parsed it is leniently
accepted, much like as a secondary it leniently accepts it.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that when extended EDNS RCODE does not fit, at short
udpsize, the reply is truncated with TC and fix for the
rcode in that short reply to be a sensible rcode.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
- Fix that when a partial EDNS option is in a query, the
response is a more RFC conformant FORMERR, since the EDNS
option is malformed. Also fix to have an EDNS size for
the reply error encoding for failed EDNS parse of the query.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
2 September 2026: Wouter
- Fix to not commit to have_zone at apply AXFR time for auth
zone transfers, so that later failure rolls back to not.
The have_zone value is set later when the SOA is retrieved.
Also fix to clear the zone data when a transfer does not
have a valid SOA record in the zone for it.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
1 September 2026: Wouter
- Fix to allow block_a and other local-zone types in a view.
- Fix LOC RR parse to avoid double to uint32 cast overflow.
Thanks to Qifan Zhang, Palo Alto Networks, for the report.
26 August 2026: Wouter
- Fix notify for auth-zone during initial start up. It
performs the transfer and not only lookup.
24 August 2026: Wouter
- Fix #132: Add `harden-cname-follow: yes` config option, that
can be used to disable cname scrubbing. That can be useful
for when the traffic is on localhost only.
21 August 2026: Wouter
- Fix to defend against double event deletion, that could cause
event corruption and use after free, for comm_timer_disable.
11 August 2026: Wouter
- Fix #1492 from zacek: Data race in log_init() on
key_created/log_lock when calling ub_ctx_create()
concurrently from multiple threads.
- Fix stat_values.tdir test to have less test failures.
7 August 2026: Wouter
- Fix #1489 from jplesnik: Replace removed Python 2 C API
macros for SWIG 4.5.0 compatibility.
6 August 2026: Alex Khanin
- Fix #1488: bounds check in packed_rr_to_string, it checked
the assembled rr length against the output string length
dest_len, instead of against the size of the rr buffer it
writes into. Callers in cachedump.c and remote.c pass a
dest_len larger than that buffer.
- Unit test for packed_rr_to_string.
6 August 2026: Wouter
- Fix #1485: the list_forwards command omits port numbers.
The list_forwards and list_stubs commands for
unbound-control print port and tls auth name.
- Fix #1487: regression in 1.26.0, ipsecmod is now always
partly enabled.
4 August 2026: Wouter
- Fix to set makedist.sh to not wget config.sub and
config.guess from git repo. The fetch times out, and the
version from libtoolize is much more recent now than
that it was when the wget was added.
31 July 2026: Wouter
- For #1483: The failure reason when an NSEC NXDOMAIN is
encountered when looking for an insecure delegation, is
fixed to mention the NSEC records, instead of nonexistent
NSEC3 records, that it attempted.
30 July 2026: Wouter
- Fix #1482: DNS-over-QUIC doesn't work with simple config.
That fixes interface-automatic for use with doq service.
28 July 2026: Wouter
- Tag for 1.26.0rc1. The repo continues with version 1.26.1.
This became 1.26.0 on 4 aug 2026.
24 July 2026: Wouter
- Merge #1433 from jisakiel: Add new static zone type
block_aaaa to suppress AAAA queries.
+8
View File
@@ -588,6 +588,9 @@ server:
# additional section.
# harden-unknown-additional: no
# Harden CNAME redirections by following them.
# harden-cname-follow: yes
# Sent minimum amount of information to upstream servers to enhance
# privacy. Only sent minimum required labels of the QNAME and set QTYPE
# to A when possible.
@@ -669,6 +672,7 @@ server:
# most modules have to be listed at the beginning of the line,
# except cachedb(just before iterator), and python (at the beginning,
# or, just before the iterator).
# Note that validator needs configured trust-anchors to be of any use.
# module-config: "validator iterator"
# File with trusted keys, kept up-to-date using RFC5011 probes,
@@ -1168,6 +1172,8 @@ server:
# Timeout in milliseconds for TCP queries to auth servers.
# tcp-auth-query-timeout: 3000
# Number of threads to use to load auth-zones (and RPZ). 0 disables.
# auth-task-threads: 0
# Python config section. To enable:
# o use --with-pythonmodule to configure before compiling.
@@ -1276,6 +1282,7 @@ remote-control:
# primary: 199.7.91.13 # d.root-servers.net
# primary: 192.5.5.241 # f.root-servers.net
# primary: 192.112.36.4 # g.root-servers.net
# primary: 198.97.190.53 # h.root-servers.net
# primary: 193.0.14.129 # k.root-servers.net
# primary: 192.0.47.132 # xfr.cjr.dns.icann.org
# primary: 192.0.32.132 # xfr.lax.dns.icann.org
@@ -1284,6 +1291,7 @@ remote-control:
# primary: 2001:500:2d::d # d.root-servers.net
# primary: 2001:500:2f::f # f.root-servers.net
# primary: 2001:500:12::d0d # g.root-servers.net
# primary: 2001:500:1::53 # h.root-servers.net
# primary: 2001:7fd::1 # k.root-servers.net
# primary: 2620:0:2830:202::132 # xfr.cjr.dns.icann.org
# primary: 2620:0:2d0:202::132 # xfr.lax.dns.icann.org
+2
View File
@@ -331,6 +331,8 @@ void my_callback_function(void* my_arg, int err,
The \fBasync_id\fP is returned so you can (at your option) decide to
track it and cancel the request if needed.
If you pass a NULL pointer the \fBasync_id\fP is not returned.
The context, created via \fBub_ctx_create\fP, is in use during but also
after the callback and it cannot be deleted during a callback.
.TP
.B ub_cancel
Cancel an async query in progress.
+2
View File
@@ -408,6 +408,8 @@ Functions
The **async_id** is returned so you can (at your option) decide to
track it and cancel the request if needed.
If you pass a NULL pointer the **async_id** is not returned.
The context, created via **ub_ctx_create**, is in use during but also
after the callback and it cannot be deleted during a callback.
ub_cancel
Cancel an async query in progress.
+6 -1
View File
@@ -42,7 +42,7 @@ unbound-checkconf(8)
Synopsis
--------
**unbound-checkconf** [``-hf``] [``-o option``] [cfgfile]
**unbound-checkconf** [``-ahf``] [``-o option``] [cfgfile]
Description
-----------
@@ -54,6 +54,11 @@ The config file syntax is described in
The available options are:
.. option:: -a
Also read the zonefiles for auth-zones and RPZ.
It checks if the syntax is okay of the zonefiles.
.. option:: -h
Show the version and commandline option help.
+45 -3
View File
@@ -2070,7 +2070,8 @@ Default: \(dq3 2 1 0 0\(dq
.INDENT 0.0
.TP
.B harden\-short\-bufsize: \fI<yes or no>\fP
Very small EDNS buffer sizes from queries are ignored.
Very small EDNS buffer sizes from queries are ignored and are instead
set to the normal UDP packet size (512 bytes).
.sp
Default: yes (per \fI\%RFC 6891\fP)
.UNINDENT
@@ -2078,6 +2079,7 @@ Default: yes (per \fI\%RFC 6891\fP)
.TP
.B harden\-large\-queries: \fI<yes or no>\fP
Very large queries are ignored.
The cutoff value is chosen to be the normal UDP packet size (512 bytes).
Default is no, since it is legal protocol wise to send these, and could be
necessary for operation if TSIG or EDNS payload is very large.
.sp
@@ -2201,6 +2203,18 @@ Default: no
.UNINDENT
.INDENT 0.0
.TP
.B harden\-cname\-follow: \fI<yes or no>\fP
Harden CNAME redirections by following them.
If no, then upstream CNAME and DNAME redirections are allowed in a
response without checking with further messages if those are valid.
It can only really be disabled safely on localhost net or encrypted
connectivity.
Default is on to protect the cache integrity.
.sp
Default: yes
.UNINDENT
.INDENT 0.0
.TP
.B use\-caps\-for\-id: \fI<yes or no>\fP
Use 0x20\-encoded random bits in the query to foil spoof attempts.
This perturbs the lowercase and uppercase of query names sent to authority
@@ -2336,7 +2350,10 @@ Default: (none)
.B do\-not\-query\-localhost: \fI<yes or no>\fP
If yes, localhost is added to the
\fI\%do\-not\-query\-address\fP entries,
both IPv6 \fB::1\fP and IPv4 \fB127.0.0.1/8\fP\&.
both IPv4 \fB127.0.0.1/8\fP (also \fB::ffff:127.0.0.0/104\fP) and IPv6 \fB::1\fP\&.
Additionally, the zero subnets \fB0.0.0.0/8\fP (also \fB::ffff:0:0/96\fP) and
\fB::\fP are added to the list since on some systems they route to
localhost as well.
If no, then localhost can be used to send queries to.
.sp
Default: yes
@@ -2504,6 +2521,9 @@ Format is BIND\-9 style format, the \fBtrusted\-keys { name flag proto algo
It is possible to use wildcards with this statement, the wildcard is
expanded on start and on reload.
.sp
A wildcard that matches no files is not an error: the entry loads no
trust anchors, and the condition is logged at operational verbosity.
.sp
Default: \(dq\(dq (no trusted keys file)
.UNINDENT
.INDENT 0.0
@@ -2613,7 +2633,7 @@ affected.
Use this setting to protect the users that rely on this validator for
authentication from potentially bad data in the additional section.
.sp
Default: yes
Default: no
.UNINDENT
.INDENT 0.0
.TP
@@ -3879,6 +3899,28 @@ Default: yes
.UNINDENT
.INDENT 0.0
.TP
.B val\-validation\-attempts: \fI<number>\fP
Limit on the number of DNSSEC validation attempts for a query.
This protects against too large numbers of cryptographic operations,
like for a deep delegation chain.
This counts attempts to validate RRSIGs.
When it is exceeded, the query fails.
.sp
Default: 32
.UNINDENT
.INDENT 0.0
.TP
.B val\-hash\-attempts: \fI<number>\fP
Limit on the number of DNSSEC hash attempts for a query.
This protects against too large numbers of cryptographic operations,
like for a deep delegation chain.
This counts DS hash attempts to match DNSKEYs.
When it is exceeded, the query fails.
.sp
Default: 32
.UNINDENT
.INDENT 0.0
.TP
.B fast\-server\-permil: \fI<number>\fP
Specify how many times out of 1000 to pick from the set of fastest servers.
0 turns the feature off.
+43 -5
View File
@@ -1838,13 +1838,15 @@ These options are part of the ``server:`` section.
@@UAHL@unbound.conf@harden-short-bufsize@@: *<yes or no>*
Very small EDNS buffer sizes from queries are ignored.
Very small EDNS buffer sizes from queries are ignored and are instead
set to the normal UDP packet size (512 bytes).
Default: yes (per :rfc:`6891`)
@@UAHL@unbound.conf@harden-large-queries@@: *<yes or no>*
Very large queries are ignored.
The cutoff value is chosen to be the normal UDP packet size (512 bytes).
Default is no, since it is legal protocol wise to send these, and could be
necessary for operation if TSIG or EDNS payload is very large.
@@ -1952,6 +1954,17 @@ These options are part of the ``server:`` section.
Default: no
@@UAHL@unbound.conf@harden-cname-follow@@: *<yes or no>*
Harden CNAME redirections by following them.
If no, then upstream CNAME and DNAME redirections are allowed in a
response without checking with further messages if those are valid.
It can only really be disabled safely on localhost net or encrypted
connectivity.
Default is on to protect the cache integrity.
Default: yes
@@UAHL@unbound.conf@use-caps-for-id@@: *<yes or no>*
Use 0x20-encoded random bits in the query to foil spoof attempts.
This perturbs the lowercase and uppercase of query names sent to authority
@@ -2077,7 +2090,10 @@ These options are part of the ``server:`` section.
@@UAHL@unbound.conf@do-not-query-localhost@@: *<yes or no>*
If yes, localhost is added to the
:ref:`do-not-query-address<unbound.conf.do-not-query-address>` entries,
both IPv6 ``::1`` and IPv4 ``127.0.0.1/8``.
both IPv4 ``127.0.0.1/8`` (also ``::ffff:127.0.0.0/104``) and IPv6 ``::1``.
Additionally, the zero subnets ``0.0.0.0/8`` (also ``::ffff:0:0/96``) and
``::`` are added to the list since on some systems they route to
localhost as well.
If no, then localhost can be used to send queries to.
Default: yes
@@ -2155,11 +2171,12 @@ These options are part of the ``server:`` section.
The ordering of the modules is significant, the order decides the order
of processing.
Setting this to just "iterator" will result in a non-validating server.
Setting this to "validator iterator" will turn on DNSSEC validation.
Setting this to just ``"iterator"`` results in a non-validating server.
Setting this to ``"validator iterator"`` (default) enables the DNSSEC
validator module but not DNSSEC validation.
.. note::
You must also set trust-anchors for validation to be useful.
To turn on DNSSEC validation you must configure trust-anchors.
Adding ``respip`` to the front will cause RPZ processing to be done on all
queries.
@@ -2226,6 +2243,9 @@ These options are part of the ``server:`` section.
It is possible to use wildcards with this statement, the wildcard is
expanded on start and on reload.
A wildcard that matches no files is not an error: the entry loads no
trust anchors, and the condition is logged at operational verbosity.
Default: "" (no trusted keys file)
@@ -3501,6 +3521,24 @@ These options are part of the ``server:`` section.
Default: no
@@UAHL@unbound.conf@auth-task-threads@@: *<number of threads>*
If nonzero, the number of threads to start to process zone transfers
for authority zones, and also RPZ zones.
The zone transfer is processed in a thread, that does not interrupt
the resolver.
For RPZ zones that means the old RPZ zone continues to be used, while
the task is processed.
The thread allocates the new zone data, and this keeps another copy of
the zone data in memory during processing.
The result is swapped into the resolver when the thread is done.
The value 0 disables the threading, one of the worker threads performs
the processing. Without threading enabled, use the value 0.
Default: 0
.. _unbound.conf.remote:
Remote Control Options
+1 -1
View File
@@ -128,5 +128,5 @@ int reply_callback(struct query_info* qinfo,
((int *)env->dyn_env)[1],
((int *)env->dyn_env)[2]);
}
return 0;
return 1;
}
+2 -1
View File
@@ -1167,7 +1167,8 @@ 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(sq->subnet_sent || sq->subnet_sent_no_subnet)
qstate->is_subnet_answer = 1;
if(verbosity >= VERB_ALGO) {
subnet_log_print("reply has edns subnet",
edns_opt_list_find(
+7 -3
View File
@@ -59,6 +59,11 @@
static int
ipsecmod_apply_cfg(struct ipsecmod_env* ipsecmod_env, struct config_file* cfg)
{
if(cfg->ipsecmod_whitelist &&
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
return 0;
if(!cfg->ipsecmod_enabled)
return 1;
if(!cfg->ipsecmod_hook || (cfg->ipsecmod_hook && !cfg->ipsecmod_hook[0])) {
log_err("ipsecmod: missing ipsecmod-hook.");
return 0;
@@ -68,9 +73,6 @@ ipsecmod_apply_cfg(struct ipsecmod_env* ipsecmod_env, struct config_file* cfg)
cfg->ipsecmod_hook, strerror(errno));
return 0;
}
if(cfg->ipsecmod_whitelist &&
!ipsecmod_whitelist_apply_cfg(ipsecmod_env, cfg))
return 0;
return 1;
}
@@ -626,6 +628,8 @@ ipsecmod_inform_super(struct module_qstate* qstate, int id,
verbose(VERB_ALGO, "super has no ipsecmod state");
return;
}
if(!siq->enabled)
return;
if(qstate->return_msg) {
struct ub_packed_rrset_key* rrset_key = reply_find_answer_rrset(
+19 -1
View File
@@ -46,6 +46,7 @@
#include "services/cache/dns.h"
#include "util/net_help.h"
#include "util/data/dname.h"
#include "util/config_file.h"
#include "sldns/rrdef.h"
#include "sldns/pkthdr.h"
@@ -107,7 +108,8 @@ 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 msg_lame_empty, int msg_lame_referral)
int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral,
struct config_file* cfg)
{
uint8_t* origzone = (uint8_t*)"\000"; /* the default */
struct ub_packed_rrset_key* s;
@@ -130,6 +132,16 @@ response_type_from_server(int rdset,
if( (msg->rep->flags&BIT_RA) &&
!(msg->rep->flags&BIT_AA) && !rdset)
return RESPONSE_TYPE_REC_LAME;
if(!cfg->harden_cname_follow /* follow CNAME chain */) {
/* If the CNAME chain is allowed, see if there is a
* SOA record, if so, the chain is complete to the
* end of it, otherwise it could be a partial chain.*/
for(i=msg->rep->an_numrrsets; i<msg->rep->an_numrrsets+msg->rep->ns_numrrsets; i++) {
s = msg->rep->rrsets[i];
if(ntohs(s->rk.type) == LDNS_RR_TYPE_SOA)
return RESPONSE_TYPE_ANSWER;
}
}
/* it could be a CNAME with NXDOMAIN rcode */
for(i=0; i<msg->rep->an_numrrsets; i++) {
s = msg->rep->rrsets[i];
@@ -162,6 +174,7 @@ response_type_from_server(int rdset,
if(msg->rep->an_numrrsets > 0) {
uint8_t* mname = request->qname;
size_t mname_len = request->qname_len;
int sawanswer = 0;
/* Now look at the answer section first. 3 states: our
* answer is there directly, our answer is there after
@@ -197,6 +210,7 @@ response_type_from_server(int rdset,
* the answer, we only provisionally say
* 'ANSWER' -- it very well could be a
* REFERRAL. */
sawanswer = 1;
break;
}
@@ -214,6 +228,10 @@ response_type_from_server(int rdset,
* still got to here, then it is a CNAME response.
* (This is regardless of the AA bit at this point) */
if(mname != request->qname) {
if(!cfg->harden_cname_follow /* allow CNAMEs */ &&
sawanswer /* The last was not CNAME, and
there is an answer RRset. */ )
return RESPONSE_TYPE_ANSWER;
return RESPONSE_TYPE_CNAME;
}
}
+5 -2
View File
@@ -45,6 +45,7 @@
struct dns_msg;
struct query_info;
struct delegpt;
struct config_file;
/**
* The response type is used to interpret the response.
@@ -115,7 +116,7 @@ enum response_type response_type_from_cache(struct dns_msg* msg,
* detection, mostly).
*
* @param rdset: if RD bit was sent in query sent by unbound.
* @param msg: the message from the cache.
* @param msg: the message.
* @param request: the request that generated the response.
* @param dp: The delegation point that was being queried
* when the response was returned.
@@ -124,10 +125,12 @@ enum response_type response_type_from_cache(struct dns_msg* msg,
* is lame, before it became empty.
* @param msg_lame_referral: returned true if the reply has a referral before
* scrub.
* @param cfg: config with options.
* @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 msg_lame_empty, int msg_lame_referral);
int* empty_nodata_found, int msg_lame_empty, int msg_lame_referral,
struct config_file* cfg);
#endif /* ITERATOR_ITER_RESPTYPE_H */
+28 -4
View File
@@ -524,7 +524,7 @@ scrub_normalize(sldns_buffer* pkt, struct msg_parse* msg,
* server, scrub down the length to something
* shorter. This deletes everything after the limit
* is reached. The iterator is going to look up
* the content one by one anyway. */
* the content one by one, if harden-cname-follow . */
remove_rrset("normalize: removing because too many cnames:",
pkt, msg, prev, &rrset);
continue;
@@ -911,8 +911,8 @@ store_rrset(sldns_buffer* pkt, struct msg_parse* msg, struct module_env* env,
packed_rrset_ttl_add(d, now);
ref.key = k;
ref.id = k->id;
/*ignore ret: it was in the cache, ref updated */
(void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, now);
/* if it was in the cache, ref updated */
rrset_cache_update_unlock(env->rrset_cache, &ref, env->alloc, now);
}
/**
@@ -1039,6 +1039,8 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
uint8_t* ns_rrset_dname = NULL;
int added_rrlen_ede = 0;
struct rrset_parse* rrset, *prev;
uint8_t* sname = qinfo->qname;
size_t snamelen = qinfo->qname_len;
prev = NULL;
rrset = msg->rrset_first;
@@ -1046,6 +1048,7 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
* it can be used from the cache. After normalization, an initial
* DNAME will have a correctly synthesized CNAME after it. */
if(rrset && rrset->type == LDNS_RR_TYPE_DNAME &&
env->cfg->harden_cname_follow /* CNAME chain is cut off, one DNAME is allowed here. */ &&
rrset->section == LDNS_SECTION_ANSWER &&
pkt_strict_sub(pkt, qinfo->qname, rrset->dname) &&
pkt_sub(pkt, rrset->dname, zonename)) {
@@ -1061,12 +1064,33 @@ scrub_sanitize(sldns_buffer* pkt, struct msg_parse* msg,
* ANY queries get query name in answer section.
* Remainders of CNAME chains are cut off and resolved by iterator. */
while(rrset && rrset->section == LDNS_SECTION_ANSWER) {
if(dname_pkt_compare(pkt, qinfo->qname, rrset->dname) != 0) {
if(!env->cfg->harden_cname_follow /* CNAME chain is allowed to stay */ &&
rrset->type == LDNS_RR_TYPE_DNAME &&
pkt_strict_sub(pkt, sname, rrset->dname) &&
pkt_sub(pkt, rrset->dname, zonename)) {
/* This DNAME is allowed to stay, the synthesized
* CNAME follows next. */
prev = rrset;
rrset = rrset->rrset_all_next;
continue;
}
if(dname_pkt_compare(pkt, sname, rrset->dname) != 0) {
if(has_additional(rrset->type)) del_addi = 1;
remove_rrset("sanitize: removing extraneous answer "
"RRset:", pkt, msg, prev, &rrset);
continue;
}
if(!env->cfg->harden_cname_follow /* CNAME chain is allowed to stay */ &&
qinfo->qtype != LDNS_RR_TYPE_ANY &&
rrset->type == LDNS_RR_TYPE_CNAME &&
dname_pkt_compare(pkt, sname, rrset->dname) == 0) {
/* Follow the CNAME chain, and allow the elements
* that match the CNAME chain. Also allow a DNAME
* in front. */
if(!parse_get_cname_target(rrset, &sname, &snamelen,
pkt))
return 0;
}
prev = rrset;
rrset = rrset->rrset_all_next;
}
+27 -2
View File
@@ -1215,8 +1215,8 @@ iter_store_parentside_rrset(struct module_env* env,
rrset->entry.hash = rrset_key_hash(&rrset->rk);
ref.key = rrset;
ref.id = rrset->id;
/* ignore ret: if it was in the cache, ref updated */
(void)rrset_cache_update(env->rrset_cache, &ref, env->alloc, *env->now);
/* if it was in the cache, ref updated */
rrset_cache_update_unlock(env->rrset_cache, &ref, env->alloc, *env->now);
}
/** fetch NS record from reply, if any */
@@ -1712,3 +1712,28 @@ deleg_port_number(struct module_env* env)
return env->cfg->ssl_port;
return -1;
}
void
shorten_answer_cname(struct reply_info* rep, uint8_t* cutoff)
{
size_t i, found = 0, removenum;
uint8_t* sname = NULL;
size_t snamelen = 0;
for(i=0; i<rep->an_numrrsets; i++) {
if(query_dname_compare(rep->rrsets[i]->rk.dname, cutoff) == 0) {
found = 1;
removenum = i;
break;
}
if(ntohs(rep->rrsets[i]->rk.type) == LDNS_RR_TYPE_CNAME) {
get_cname_target(rep->rrsets[i], &sname, &snamelen);
if(query_dname_compare(sname, cutoff) == 0) {
found = 1;
removenum = i+1;
break;
}
}
}
if(!found) return; /* not found */
val_reply_remove_answers(rep, removenum, rep->an_numrrsets-removenum);
}
+3
View File
@@ -486,4 +486,7 @@ void iter_make_minimal(struct reply_info* rep);
/** See if we need a different port number */
int deleg_port_number(struct module_env* env);
/** Shorten reply CNAME chain to cutoff, cutoff is excluded. */
void shorten_answer_cname(struct reply_info* rep, uint8_t* cutoff);
#endif /* ITERATOR_ITER_UTILS_H */
+68 -5
View File
@@ -3189,7 +3189,7 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
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->msg_lame_empty, iq->msg_lame_referral);
iq->msg_lame_empty, iq->msg_lame_referral, qstate->env->cfg);
iq->chase_to_rd = 0;
/* remove TC flag, if this is erroneously set by TCP upstream */
iq->response->rep->flags &= ~BIT_TC;
@@ -3302,6 +3302,47 @@ processQueryResponse(struct module_qstate* qstate, struct iter_qstate* iq,
* to send another query with a new qtype. */
type = RESPONSE_TYPE_ANSWER;
}
if(type == RESPONSE_TYPE_ANSWER &&
!qstate->env->cfg->harden_cname_follow /* cname chain from upstream is allowed */ &&
qstate->env->auth_zones &&
/* Check for CNAMEs in answer and RPZ after the CNAME. */
reply_find_rrset_section_an(
iq->response->rep, iq->qchase.qname,
iq->qchase.qname_len, LDNS_RR_TYPE_CNAME,
iq->qchase.qclass) != NULL) {
/* If this is an answer with CNAMEs in front, and
* RPZ wants to modify after CNAME(s), cut off, the
* remainder, and treat as the CNAME response */
size_t i;
uint8_t* origname = iq->qchase.qname;
size_t orignamelen = iq->qchase.qname_len;
for(i=0; i<iq->response->rep->an_numrrsets; i++) {
struct dns_msg* forged_response;
if(ntohs(iq->response->rep->rrsets[i]->rk.type) ==
LDNS_RR_TYPE_DNAME) {
continue;
}
if(ntohs(iq->response->rep->rrsets[i]->rk.type) !=
LDNS_RR_TYPE_CNAME) {
break;
}
get_cname_target(iq->response->rep->rrsets[i],
&iq->qchase.qname, &iq->qchase.qname_len);
forged_response = rpz_callback_from_iterator_cname(qstate, iq);
if(forged_response) {
/* Cut off the answer section at this point.
* RPZ is going to make an answer, in the
* processInit after the CNAME(s) in front
* are handled. */
shorten_answer_cname(iq->response->rep,
iq->qchase.qname);
type = RESPONSE_TYPE_CNAME;
break;
}
}
iq->qchase.qname = origname;
iq->qchase.qname_len = orignamelen;
}
/* handle each of the type cases */
if(type == RESPONSE_TYPE_ANSWER) {
@@ -3804,7 +3845,7 @@ processPrimeResponse(struct module_qstate* qstate, int id)
type = response_type_from_server(
(int)((iq->chase_flags&BIT_RD) || iq->chase_to_rd),
iq->response, &iq->qchase, iq->dp, NULL, iq->msg_lame_empty,
iq->msg_lame_referral);
iq->msg_lame_referral, qstate->env->cfg);
if(type == RESPONSE_TYPE_ANSWER) {
qstate->return_rcode = LDNS_RCODE_NOERROR;
qstate->return_msg = iq->response;
@@ -3954,15 +3995,32 @@ processDSNSResponse(struct module_qstate* qstate, int id,
struct module_qstate* forq)
{
struct iter_qstate* foriq = (struct iter_qstate*)forq->minfo[id];
int sec_an = 0, sec_ns = 0;
/* if the finished (iq->response) query has no NS set: continue
* up to look for the right dp; nothing to change, do DPNSstate */
if(qstate->return_rcode != LDNS_RCODE_NOERROR)
return; /* seek further */
/* find the NS RRset (without allowing CNAMEs) */
if(!reply_find_rrset(qstate->return_msg->rep, qstate->qinfo.qname,
qstate->qinfo.qname_len, LDNS_RR_TYPE_NS,
qstate->qinfo.qclass)){
/* Usually, the response has a NS in the answer section, since that
* was the query type. And it is then the child side part of the NS
* set. This child side part would be used if next up a delegation
* point was constructed from cache, for example. But now it uses that
* child side part for constructing a delegation point for the DS
* lookup.
* If that is not there, we can pick up the NS from the authority
* section as well, like from a referral. */
if(reply_find_rrset_section_an(qstate->return_msg->rep,
qstate->qinfo.qname, qstate->qinfo.qname_len,
LDNS_RR_TYPE_NS, qstate->qinfo.qclass))
sec_an = 1;
if(!sec_an && reply_find_rrset_section_ns(qstate->return_msg->rep,
qstate->qinfo.qname, qstate->qinfo.qname_len,
LDNS_RR_TYPE_NS, qstate->qinfo.qclass))
sec_ns = 1;
if(!sec_an && !sec_ns) {
/* We probably hit an intermediate label, without a type NS
* record there. To find the nameservers, it must go up more.*/
return; /* seek further */
}
@@ -3975,6 +4033,11 @@ processDSNSResponse(struct module_qstate* qstate, int id,
errinf(qstate, "malloc failure, in DS search");
return; /* dp==NULL in QUERYTARGETS makes SERVFAIL */
}
if(sec_an) {
/* The NS is in the answer section, this is not a parent side,
* but a child side response for it. */
foriq->dp->has_parent_side_NS = 0;
}
/* success, go query the querytargets in the new dp (and go down) */
}
+49
View File
@@ -0,0 +1,49 @@
/*
* libunbound/authload.h - prototypes for auth load 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
* auth load service.
*/
#ifndef LIBUNBOUND_AUTHLOAD_H
#define LIBUNBOUND_AUTHLOAD_H
/** The worker routine that services the auth load connection. */
void worker_auth_load_service_cb(int fd, short bits, void* arg);
#endif /* LIBUNBOUND_AUTHLOAD_H */
+1 -1
View File
@@ -86,7 +86,7 @@ context_finalize(struct ub_ctx* ctx)
return UB_NOMEM;
if(!local_zones_apply_cfg(ctx->local_zones, cfg))
return UB_INITFAIL;
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, &is_rpz,
if(!auth_zones_apply_cfg(ctx->env->auth_zones, cfg, 1, 1, &is_rpz,
ctx->env, &ctx->mods))
return UB_INITFAIL;
if(!(ctx->env->fwds = forwards_create()) ||
+5 -2
View File
@@ -409,7 +409,7 @@ if [ "$DOWIN" = "yes" ]; then
info "git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound"
git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound || error_cleanup "git clone failed"
cd unbound || error_cleanup "Unbound not exported correctly from git"
rm -rf .git .travis.yml .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information"
rm -rf .git .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information"
# on a re-configure the cache may no longer be valid...
if test -f mingw32-config.cache; then rm mingw32-config.cache; fi
@@ -603,11 +603,13 @@ info "git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound"
git clone --depth=1 --no-tags -b $GITBRANCH $GITREPO unbound || error_cleanup "git clone failed"
cd unbound || error_cleanup "Unbound not exported correctly from git"
rm -rf .git .travis.yml .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information"
rm -rf .git .gitattributes .github .gitignore || error_cleanup "Failed to remove .git tracking and ci information"
info "Adding libtool utils (libtoolize)."
libtoolize -c --install || libtoolize -c || error_cleanup "Libtoolize failed."
# Turn this off, if the git repo times out for lookups.
if test "updateconfigsub" = "false"; then
# https://www.gnu.org/software/gettext/manual/html_node/config_002eguess.html
info "Updating config.guess and config.sub"
wget -O config.guess 'https://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD'
@@ -621,6 +623,7 @@ if [ `uname -s | grep -i -c darwin` -ne 0 ]; then
xattr -d com.apple.quarantine config.sub
fi
fi
fi
info "Building configure script (autoreconf)."
autoreconf -f || error_cleanup "Autoconf failed."
+122 -5
View File
@@ -23,12 +23,15 @@ This example relies on the following functionalities:
Registering inplace callback functions
--------------------------------------
There are four types of inplace callback functions:
There are seven types of inplace callback functions:
- `inplace callback reply functions`_
- `inplace callback reply_cache functions`_
- `inplace callback reply_local functions`_
- `inplace callback reply_servfail functions`_
- `inplace callback query functions`_
- `inplace callback query_response functions`_
- `inplace callback edns_back_parsed functions`_
Inplace callback reply functions
@@ -61,7 +64,9 @@ The callback function's prototype is the following:
release. Current parameters:
``repinfo``: Reply information for a communication point (comm_reply).
:return: True on success, False on failure.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
"""
@@ -105,7 +110,9 @@ The callback function's prototype is the following:
release. Current parameters:
``repinfo``: Reply information for a communication point (comm_reply).
:return: True on success, False on failure.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
For demonstration purposes we want to see if EDNS option 65002 is present
and reply with a new value.
@@ -152,7 +159,9 @@ The callback function's prototype is the following:
release. Current parameters:
``repinfo``: Reply information for a communication point (comm_reply).
:return: True on success, False on failure.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
"""
@@ -197,7 +206,9 @@ The callback function's prototype is the following:
release. Current parameters:
``repinfo``: Reply information for a communication point (comm_reply).
:return: True on success, False on failure.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
For demonstration purposes we want to reply with an empty EDNS code '65003'
and log the IP address(es) of the client(s).
@@ -214,6 +225,112 @@ We can register such function as:
log_info("python: Could not register inplace callback function.")
Inplace callback query functions
................................
Called before sending a query to a backend server.
The callback function's prototype is the following:
.. code-block:: python
def inplace_query_callback(qinfo, flags, qstate, addr, zone, region, **kwargs):
"""
Function that will be registered as an inplace callback function.
It will be called before sending a query to a backend server.
:param qinfo: query_info struct;
:param flags: flags of the query;
:param qstate: module qstate. opt_lists are available here;
:param addr: struct sockaddr_storage. Address of the backend server;
:param zone: zone name in binary;
:param region: region to allocate temporary data. Needs to be used when we
want to append a new option to opt_lists.
:param **kwargs: Dictionary that may contain parameters added in a future
release.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
"""
.. note:: The function's name is irrelevant.
We can register such function as:
.. code-block:: python
if not register_inplace_cb_query(inplace_query_callback, env, id):
log_info("python: Could not register inplace callback function.")
Inplace callback query_response functions
.........................................
Called after receiving a reply from a backend server.
The callback function's prototype is the following:
.. code-block:: python
def inplace_query_response_callback(qstate, response, **kwargs):
"""
Function that will be registered as an inplace callback function.
It will be called after receiving a reply from a backend server.
:param qstate: module qstate. opt_lists are available here;
:param response: struct dns_msg. The reply received from the backend server;
:param **kwargs: Dictionary that may contain parameters added in a future
release.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
"""
.. note:: The function's name is irrelevant.
We can register such function as:
.. code-block:: python
if not register_inplace_cb_query_response(inplace_query_response_callback, env, id):
log_info("python: Could not register inplace callback function.")
Inplace callback edns_back_parsed functions
...........................................
Called after EDNS is parsed on a reply from a backend server.
The callback function's prototype is the following:
.. code-block:: python
def inplace_edns_back_parsed_call(qstate, **kwargs):
"""
Function that will be registered as an inplace callback function.
It will be called after EDNS is parsed on a reply from a backend server.
:param qstate: module qstate. opt_lists are available here;
:param **kwargs: Dictionary that may contain parameters added in a future
release.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
"""
.. note:: The function's name is irrelevant.
We can register such function as:
.. code-block:: python
if not register_inplace_cb_edns_back_parsed_call(inplace_edns_back_parsed_call, env, id):
log_info("python: Could not register inplace callback function.")
Testing
~~~~~~~
+32 -6
View File
@@ -95,7 +95,9 @@ def inplace_reply_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
release. Current parameters:
``repinfo``: Reply information for a communication point (comm_reply).
:return: True on success, False on failure.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
"""
log_info("python: called back while replying.")
@@ -123,7 +125,9 @@ def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
release. Current parameters:
``repinfo``: Reply information for a communication point (comm_reply).
:return: True on success, False on failure.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
For demonstration purposes we want to see if EDNS option 65002 is present
and reply with a new value.
@@ -147,6 +151,12 @@ def inplace_cache_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
else:
log_info("python: *failed to add new option code 65002*")
return False
# If replying with another code is not crucial for operation
# we can soft fail instead and allow further callback
# processing by Unbound.
# else:
# log_info("python: *failed to add new option code 65002*")
# return True
break
return True
@@ -173,7 +183,9 @@ def inplace_local_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
release. Current parameters:
``repinfo``: Reply information for a communication point (comm_reply).
:return: True on success, False on failure.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
"""
log_info("python: called back while replying with local data or chaos"
@@ -203,7 +215,9 @@ def inplace_servfail_callback(qinfo, qstate, rep, rcode, edns, opt_list_out,
release. Current parameters:
``repinfo``: Reply information for a communication point (comm_reply).
:return: True on success, False on failure.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
For demonstration purposes we want to reply with an empty EDNS code '65003'
and log the IP address of the client.
@@ -240,6 +254,10 @@ def inplace_query_callback(qinfo, flags, qstate, addr, zone, region, **kwargs):
want to append a new option to opt_lists.
:param **kwargs: Dictionary that may contain parameters added in a future
release.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
"""
log_info("python: outgoing query to {}@{}".format(addr.addr, addr.port))
return True
@@ -254,6 +272,10 @@ def inplace_query_response_callback(qstate, response, **kwargs):
:param response: struct dns_msg. The reply received from the backend server;
:param **kwargs: Dictionary that may contain parameters added in a future
release.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
"""
log_dns_msg(
"python: incoming reply from {}{}".format(qstate.reply.addr, os.linesep),
@@ -265,11 +287,15 @@ def inplace_query_response_callback(qstate, response, **kwargs):
def inplace_edns_back_parsed_call(qstate, **kwargs):
"""
Function that will be registered as an inplace callback function.
It will be called after EDNS is parsed on a reply from a backend server..
It will be called after EDNS is parsed on a reply from a backend server.
:param qstate: module qstate. opt_lists are available here;
:param **kwargs: Dictionary that may contain parameters added in a future
release.
:return: True on success, False on failure. Failure terminates any further
callback processing. If this module is ephemeral it is advised
to clean up and return success instead.
"""
log_info("python: edns parsed")
return True
@@ -348,7 +374,7 @@ def inform_super(id, qstate, superqstate, qdata): return True
def operate(id, event, qstate, qdata):
if (event == MODULE_EVENT_NEW) or (event == MODULE_EVENT_PASS):
qstate.ext_state[id] = MODULE_WAIT_MODULE
qstate.ext_state[id] = MODULE_WAIT_MODULE
return True
elif event == MODULE_EVENT_MODDONE:
+14 -14
View File
@@ -79,7 +79,7 @@
i+(int)((unsigned int)name[i]) < len) {
memmove(buf, name + i + 1, (unsigned int)name[i]);
buf[(unsigned int)name[i]] = 0;
PyList_SetItem(list, cnt, PyString_FromString(buf));
PyList_SetItem(list, cnt, PyUnicode_FromString(buf));
}
i += ((unsigned int)name[i]) + 1;
cnt++;
@@ -96,7 +96,7 @@
list = PyList_New(len);
for (i=0; i < len; i++) {
PyList_SET_ITEM(list, i, PyString_FromString(array[i]));
PyList_SET_ITEM(list, i, PyUnicode_FromString(array[i]));
}
return list;
}
@@ -207,7 +207,7 @@ struct query_info {
char buf[LDNS_MAX_DOMAINLEN];
buf[0] = '\0';
dname_str((uint8_t*)PyBytes_AsString(dname), buf);
return PyString_FromString(buf);
return PyUnicode_FromString(buf);
}
%}
@@ -345,7 +345,7 @@ struct packed_rrset_data {
PyObject* _get_data_rr_len(struct packed_rrset_data* d, int idx) {
if ((d != NULL) && (idx >= 0) &&
((size_t)idx < (d->count+d->rrsig_count)))
return PyInt_FromLong(d->rr_len[idx]);
return PyLong_FromLong(d->rr_len[idx]);
return Py_None;
}
void _set_data_rr_ttl(struct packed_rrset_data* d, int idx, uint32_t ttl)
@@ -357,7 +357,7 @@ struct packed_rrset_data {
PyObject* _get_data_rr_ttl(struct packed_rrset_data* d, int idx) {
if ((d != NULL) && (idx >= 0) &&
((size_t)idx < (d->count+d->rrsig_count)))
return PyInt_FromLong(d->rr_ttl[idx]);
return PyLong_FromLong(d->rr_ttl[idx]);
return Py_None;
}
PyObject* _get_data_rr_data(struct packed_rrset_data* d, int idx) {
@@ -555,12 +555,12 @@ struct sockaddr_storage {};
if (ss->ss_family == AF_INET) {
const struct sockaddr_in *sa4 = (struct sockaddr_in *)ss;
return PyInt_FromLong(ntohs(sa4->sin_port));
return PyLong_FromLong(ntohs(sa4->sin_port));
}
if (ss->ss_family == AF_INET6) {
const struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)ss;
return PyInt_FromLong(ntohs(sa6->sin6_port));
return PyLong_FromLong(ntohs(sa6->sin6_port));
}
return Py_None;
@@ -574,7 +574,7 @@ struct sockaddr_storage {};
}
sa6 = (struct sockaddr_in6 *)ss;
return PyInt_FromLong(ntohl(sa6->sin6_flowinfo));
return PyLong_FromLong(ntohl(sa6->sin6_flowinfo));
}
PyObject *_sockaddr_storage_scope_id(const struct sockaddr_storage *ss) {
@@ -585,7 +585,7 @@ struct sockaddr_storage {};
}
sa6 = (struct sockaddr_in6 *)ss;
return PyInt_FromLong(ntohl(sa6->sin6_scope_id));
return PyLong_FromLong(ntohl(sa6->sin6_scope_id));
}
%}
@@ -661,7 +661,7 @@ struct edns_option {
%inline %{
PyObject* _edns_option_opt_code_get(struct edns_option* option) {
uint16_t opt_code = option->opt_code;
return PyInt_FromLong(opt_code);
return PyLong_FromLong(opt_code);
}
PyObject* _edns_option_opt_data_get(struct edns_option* option) {
@@ -1627,7 +1627,7 @@ int edns_opt_list_append(struct edns_option** list, uint16_t code, size_t len,
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_edns);
@@ -1711,7 +1711,7 @@ out:
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_qinfo);
@@ -1765,7 +1765,7 @@ out:
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_qstate);
@@ -1814,7 +1814,7 @@ out:
}
result = PyObject_Call(func, py_args, py_kwargs);
if (result) {
res = PyInt_AsLong(result);
res = PyLong_AsLong(result);
}
out:
Py_XDECREF(py_qstate);
+4 -4
View File
@@ -246,14 +246,14 @@ log_py_err(void)
}
/* And it should be a string all ready to go - duplicate it. */
if (!PyString_Check(obResult) && !PyUnicode_Check(obResult)) {
if (!PyBytes_Check(obResult) && !PyUnicode_Check(obResult)) {
log_err("pythonmod: cannot print exception, "
"StringIO.getvalue() result did not String_Check"
" or Unicode_Check");
goto cleanup;
}
if(PyString_Check(obResult)) {
result = PyString_AsString(obResult);
if(PyBytes_Check(obResult)) {
result = PyBytes_AsString(obResult);
} else {
ascstr = PyUnicode_AsASCIIString(obResult);
result = PyBytes_AsString(ascstr);
@@ -450,7 +450,7 @@ int pythonmod_init(struct module_env* env, int id)
pe->data = PyDict_New();
/* add the script filename to the global "mod_env" for trivial access */
fname = PyString_FromString(pe->fname);
fname = PyUnicode_FromString(pe->fname);
if(PyDict_SetItemString(pe->data, "script", fname) < 0) {
log_err("pythonmod: could not add item to dictionary");
Py_XDECREF(fname);
+1
View File
@@ -734,6 +734,7 @@ respip_data_answer(enum respip_action action,
if(!new_rep)
return -1;
rp->rk.flags |= PACKED_RRSET_FIXEDTTL; /* avoid adjusting TTL */
rp->entry.hash = rrset_key_hash(&rp->rk);
new_rep->rrsets[rrset_id] = rp;
*redirect_rrsetp = rp;
+1985
View File
File diff suppressed because it is too large Load Diff
+311
View File
@@ -0,0 +1,311 @@
/*
* services/authload.h - authoritative zone load thread
*
* 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 contains the auth load thread. This loads authority zone
* and RPZ zone information in a thread, in a separate memory structure.
* When it is done, the information is swapped over to the running server.
*/
#ifndef SERVICES_AUTHLOAD_H
#define SERVICES_AUTHLOAD_H
#include "util/locks.h"
#include "util/rbtree.h"
struct worker;
struct daemon;
struct auth_xfer;
struct module_env;
struct auth_load_task;
struct comm_timer;
/**
* General information for auth load threads. The number of active threads.
*/
struct auth_load_general_info {
/** lock on this structure. It is after the auth_zones lock, and
* after the auth_xfer locks. */
lock_basic_type lock;
/** The number of active auth load threads. */
int num_auth_load_threads;
/** The number of active downloads, zone transfers in progress.
* These are going to need an auth load thread when done. The counter
* is decremented when the thread and transfer have completed. */
int num_auth_transfers;
/** The auth zone xfer transfer wait list */
struct auth_xfer* wait_transfer_list;
/** The last item of the wait_transfer list. */
struct auth_xfer* wait_transfer_last;
/** To resume from a waiting item, the callback, at zero timeout is
* used. That breaks out of callbacks and handles the items there.
* If the timer is set, this is true. */
int resume_timer_enabled;
/** The resume timer for the wait_transfer list. */
struct comm_timer* resume_timer;
/** The worker env for the resume timer. It is set in the event base
* of that worker. */
struct module_env* resume_env;
};
/**
* The types of notifications that the auth load thread sends around.
*/
enum auth_load_notification_type {
/** This is sent to make the auth load thread perform exit */
auth_load_notification_exit
};
/**
* The auth load thread. The thread runs to load authority zone information
* and RPZ information into memory. It loads into a copy. Then that is swapped
* over to the running server. This keeps the server responsive while the
* information is loaded.
*/
struct auth_load_thread {
/** the thread number for the thread,
* must be first to cast thread arg to int* in checklock code. */
int threadnum;
/** 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
/** communication socket pair, that sends commands */
int commpair[2];
/** if the thread has to quit */
int need_to_quit;
/** the event that listens on the worker to commpair,
* it receives content from the auth load thread. */
void* service_event;
/** if the event that listens on the worker has
* been added to the comm base. */
int service_event_is_added;
/** the worker that the auth load is connected to */
struct worker* worker;
/** if the thread is inserted in the tree at the worker. */
int tree_inserted;
/** the rbtree node for the worker tree of auth load threads. */
rbnode_type node;
/** The task that the thread is working on */
struct auth_load_task* task;
};
/**
* The types of tasks that the auth load can perform.
*/
enum auth_load_task_type {
AUTH_LOAD_TASK_TRANSFER,
AUTH_LOAD_TASK_ZONEFILE_READ,
AUTH_LOAD_TASK_ZONEFILE_WRITE,
AUTH_LOAD_TASK_HTTPCHUNKS
};
/**
* The task for the auth load. The task can be to load a zone transfer, AXFR,
* IXFR, from zonefile, and from a http read, from chunks.
*/
struct auth_load_task {
/** The type of the task */
enum auth_load_task_type task_type;
/** The task is connected with this worker */
struct worker* worker;
/** The zone name */
uint8_t* name;
/** The zone namelen */
size_t namelen;
/** The zone class */
uint16_t dclass;
/** name of the host that the transfer comes from. */
char* host;
/** file part of the url that the transfer comes from, or NULL. */
char* file;
/** Set if the host is http transfer, if false it is AXFR or IXFR. */
int on_http;
/** Set if the transfer is doing IXFR */
int on_ixfr;
/** Set if the transfer is an IXFR but we detected an AXFR contents */
int on_ixfr_is_axfr;
/** The zone is an rpz zone. */
int is_rpz;
/** The etag if any, alloced. */
char* etag;
/** Set if the ixfr failed. (So that there can be backoff to AXFR). */
int ixfr_fail;
/** current serial (from SOA), if we have no zone, 0
* This is for checking the IXFR result. */
uint32_t serial;
/** the data chunks, or NULL, to process. */
struct auth_chunk* chunks_first;
/** last data chunk */
struct auth_chunk* chunks_last;
/** size of data in data chunks. */
size_t chunks_total;
/** time taken for the task */
struct timeval time_taken;
/** time taken for the reload part of the task */
struct timeval time_reload;
/** memory used for the task */
size_t mem_used;
};
/**
* Add a new task to be performed by the auth load thread.
* It starts a thread.
* @param xfr: zone transfer to start for.
* @param worker: worker that is connected to the task.
* @param etag: the etag, if any.
* @return false on failure.
*/
int auth_load_add_task_xfr(struct auth_xfer* xfr, struct worker* worker,
char* etag);
/**
* Add a new task to be performed by the auth load thread.
* It starts a thread. This writes to zonefile.
* @param name: name of zone, wireformat.
* @param namelen: length of name.
* @param dclass: class of the zone.
* @param env: the module env.
* @param chunk_list: for writes after http, the chunk list with data.
* @return false on failure to create the thread.
*/
int auth_load_add_task_write(uint8_t* name, size_t namelen, uint16_t dclass,
struct module_env* env, struct auth_chunk* chunk_list);
/** See if there is a quit signal, true if so. */
int auth_load_thread_poll_for_quit(struct auth_load_thread* thr);
/**
* Create auth load info structure.
* @return NULL on failure.
*/
struct auth_load_general_info* auth_load_info_create(void);
/**
* Delete auth load info structure.
* @param auth_load_info: to delete.
*/
void auth_load_info_delete(struct auth_load_general_info* auth_load_info);
/**
* Clean up the auth load info. Removes pending timer, if that is enabled.
* @param auth_load_info: to clean up.
*/
void auth_load_info_cleanup(struct auth_load_general_info* auth_load_info);
/**
* Grab a new thread from the auth load count.
* @param env: with auth_load_info with the active thread count.
* and config file, with configured maximum.
* @return false on failure, like too many active, true if successful.
*/
int auth_load_info_grab_thread(struct module_env* env);
/**
* Release thread from auth load count. It is done.
* @param env: with auth_load_info with the active thread count.
*/
void auth_load_info_release_thread(struct module_env* env);
/**
* Grab a new transfer in progress, this is limited by the auth load count.
* @param env: with auth_load_info with the active transfer number.
* and config file, with configured maximum.
* @return false on failure, like too many active, true if successful.
*/
int auth_load_info_grab_transfer_in_progress(struct module_env* env);
/**
* Release transfer from active count. It is done.
* @param env: with auth_load_info with the active transfer count.
*/
void auth_load_info_release_transfer_in_progress(struct module_env* env);
/**
* Make transfer active in the in progress transfer count.
* @param xfr: the xfr is in progress
* @return false if not possible.
*/
int xfr_transfer_grab_active(struct auth_xfer* xfr);
/**
* Release active transfer from in progress transfer count.
* @param xfr: the xfr is no longer in progress.
*/
void xfr_transfer_release_active(struct auth_xfer* xfr);
/**
* Add transfer to wait_transfer list. It can not become active right now.
* @param xfr: the xfr is put on the wait_transfer list.
*/
void xfr_transfer_wait_active(struct auth_xfer* xfr);
/**
* Remove xfr from wait_transfer list
* @param xfr: the xfr is removed from the wait_transfer list.
*/
void xfr_transfer_remove_wait_transfer_list(struct auth_xfer* xfr);
/** The timer callback for the wait_transfer resume timer. */
void auth_load_resume_timer_cb(void* arg);
/** Schedule pick up of waiting transfers. */
void auth_load_schedule_waiting_pickup(struct module_env* env);
/** Compare auth load tree entries, in the worker auth load tree. */
int auth_load_tree_cmp(const void* a, const void* b);
/** Delete tasks for the zone. The write and xfr tasks for that name, class
* are sent a quit signal, and the thread is joined, as it exits. */
void auth_load_del_zone_tasks(struct worker* worker, uint8_t* name,
size_t namelen, uint16_t dclass);
/** Stop all the auth load threads. */
void auth_load_stop_threads(struct daemon* daemon);
#endif /* SERVICES_AUTHLOAD_H */
+648 -161
View File
File diff suppressed because it is too large Load Diff
+72 -2
View File
@@ -65,6 +65,7 @@ struct auth_probe;
struct auth_transfer;
struct auth_master;
struct auth_chunk;
struct auth_load_thread;
/**
* Authoritative zones, shared.
@@ -125,6 +126,8 @@ struct auth_zone {
int zone_expired;
/** zone is a slave zone (it has masters) */
int zone_is_slave;
/** store etag */
char etag[128];
/** for downstream: this zone answers queries towards the downstream
* clients */
int for_downstream;
@@ -150,6 +153,8 @@ struct auth_zone {
int zonemd_callback_perform_write;
/** chunklist to write for chunked transfer. */
struct auth_chunk* perform_write_chunk_list;
/** The zonemd transfer is an active transfer (for auth load info) */
int zonemd_transfer_active;
/** zone has been deleted */
int zone_deleted;
/** deletelist pointer, unused normally except during delete */
@@ -404,6 +409,15 @@ struct auth_transfer {
size_t chunks_total;
/** start time of the transfer */
struct timeval start_time;
/** if the transfer is active and in the in progress count. */
int active_transfer;
/** if the transfer is on the wait_transfer list (it waits to
* become active). */
int on_wait_transfer_list;
/** If on the wait_transfer list, the previous list item. */
struct auth_xfer* wait_transfer_prev;
/** If on the wait_transfer list, the next list item. */
struct auth_xfer* wait_transfer_next;
/** list of upstream masters for this zone, from config */
struct auth_master* masters;
@@ -514,13 +528,15 @@ struct auth_zones* auth_zones_create(void);
* @param az: auth zones structure
* @param cfg: config to apply.
* @param setup: if true, also sets up values in the auth zones structure
* @param readauth: if true, reads zone files. False to omit zone file read,
* for use by checkconf.
* @param is_rpz: set to 1 if at least one RPZ zone is configured.
* @param env: environment for offline verification.
* @param mods: modules in environment.
* @return false on failure.
*/
int auth_zones_apply_cfg(struct auth_zones* az, struct config_file* cfg,
int setup, int* is_rpz, struct module_env* env,
int setup, int readauth, int* is_rpz, struct module_env* env,
struct module_stack* mods);
/** initial pick up of worker timeouts, ties events to worker event loop
@@ -545,7 +561,15 @@ void auth_zones_delete(struct auth_zones* az);
/**
* Write auth zone data to file, in zonefile format.
*/
int auth_zone_write_file(struct auth_zone* z, const char* fname);
int auth_zone_write_file(struct auth_zone* z, const char* fname,
struct auth_load_thread* thr);
/** write to zonefile after zone has updated, reacquires z readlock.
* The chunk list is freed on return.
* If the zone is gone, chunk_list is freed (if non NULL). */
void zone_write_after_update_reacq(uint8_t* name, size_t namelen,
uint16_t dclass, struct module_env* env,
struct auth_chunk* chunk_list, struct auth_load_thread* thr);
/**
* Use auth zones to lookup the answer to a query.
@@ -861,4 +885,50 @@ 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);
/** Get memory usage of auth zone */
size_t auth_zone_get_mem(struct auth_zone* z);
/** create domain with the given name */
struct auth_data* az_domain_create(struct auth_zone* z, uint8_t* nm,
size_t nmlen);
/** helper traverse to delete zones */
void auth_data_del(rbnode_type* n, void* arg);
/** Pick up xfr task from wait_transfer resumption. xfr is locked on entry,
* unlocked at return. */
void xfr_pick_up_transfer(struct auth_xfer* xfr, struct module_env* env);
/** Handle the end of an auth load task. */
void xfr_process_load_end_transfer(struct auth_xfer* xfr,
struct module_env* env, uint8_t status, int ixfr_fail,
struct timeval* time_taken, struct timeval* time_reload,
size_t mem_used, size_t chunks_total, struct auth_chunk* chunk_list);
/** Handle the end of an auth load task to write. */
void auth_zone_process_load_end_write(struct module_env* env);
/** Log preview of http transfer */
void xfr_http_preview(const char* file, struct auth_chunk* chunk_list);
/** Check syntax of first part of the http download */
int xfr_http_syntax_check(uint8_t* name, size_t namelen, uint16_t dclass,
const char* host, const char* file, struct auth_chunk* chunk_list,
struct sldns_buffer* scratch_buffer);
/** Apply http transfer to auth_zone */
int xfr_apply_http(uint8_t* name, size_t namelen, const char* host,
const char* file, struct auth_chunk* chunk_list, struct auth_zone* z,
struct sldns_buffer* scratch_buffer, char* etag,
struct auth_load_thread* thr);
/** Apply IXFR transfer to auth_zone */
int xfr_apply_ixfr(struct auth_chunk* chunk_list, uint32_t xfr_serial,
struct auth_zone* z, struct sldns_buffer* scratch_buffer,
struct auth_load_thread* thr);
/** Apply AXFR transfer to auth_zone */
int xfr_apply_axfr(struct auth_chunk* chunk_list, struct auth_zone* z,
struct sldns_buffer* scratch_buffer, struct auth_load_thread* thr);
#endif /* SERVICES_AUTHZONE_H */
+6 -3
View File
@@ -95,7 +95,8 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
case 2: /* ref updated, cache is superior */
if(region) {
struct ub_packed_rrset_key* ck;
lock_rw_rdlock(&rep->ref[i].key->entry.lock);
/* the entry is already readlocked from the
* check in rrset_cache_update. */
/* if deleted rrset, do not copy it */
if(rep->ref[i].key->id == 0 ||
rep->ref[i].id != rep->ref[i].key->id)
@@ -116,6 +117,8 @@ store_rrsets(struct module_env* env, struct reply_info* rep, time_t now,
qrep->serve_expired_ttl = qrep->ttl + SERVE_EXPIRED_TTL;
}
}
} else {
lock_rw_unlock(&rep->ref[i].key->entry.lock);
}
/* no break: also copy key item */
/* the line below is matched by gcc regex and silences
@@ -1208,9 +1211,9 @@ dns_cache_store(struct module_env* env, struct query_info* msgqinf,
rep->rrsets[i]->entry.data, *env->now);
ref.key = rep->rrsets[i];
ref.id = rep->rrsets[i]->id;
/*ignore ret: it was in the cache, ref updated */
/* if it was in the cache, ref updated */
/* no leeway for typeNS */
(void)rrset_cache_update(env->rrset_cache, &ref,
rrset_cache_update_unlock(env->rrset_cache, &ref,
env->alloc,
((ntohs(ref.key->rk.type)==LDNS_RR_TYPE_NS
&& !pside) ? qstarttime:*env->now + leeway));
+16 -3
View File
@@ -239,9 +239,13 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
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 */
if(equal) {
ub_packed_rrset_parsedelete(k, alloc);
/* return readlocked item. */
return 2;
}
lock_rw_unlock(&e->lock);
ub_packed_rrset_parsedelete(k, alloc);
if(equal) return 2;
return 1;
}
lock_rw_unlock(&e->lock);
@@ -269,6 +273,15 @@ rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
return 0;
}
void rrset_cache_update_unlock(struct rrset_cache* r, struct rrset_ref* ref,
struct alloc_cache* alloc, time_t timenow)
{
int ret = rrset_cache_update(r, ref, alloc, timenow);
if(ret == 2) {
lock_rw_unlock(&ref->key->entry.lock);
}
}
/** See if the name is a within signer authority */
static int
dname_subdomain_rrsig_signers(uint8_t* dname,
@@ -333,8 +346,8 @@ void rrset_cache_update_wildcard(struct rrset_cache* rrset_cache,
rrset->entry.hash = rrset_key_hash(&rrset->rk);
ref.key = rrset;
ref.id = rrset->id;
/* ignore ret: if it was in the cache, ref updated */
(void)rrset_cache_update(rrset_cache, &ref, alloc, timenow);
/* if it was in the cache, ref updated */
rrset_cache_update_unlock(rrset_cache, &ref, alloc, timenow);
}
/** Grace period in seconds for TTL=0 DNAME rrsets (RFC 2308: do not cache).
+6
View File
@@ -129,10 +129,16 @@ void rrset_cache_touch(struct rrset_cache* r, struct ub_packed_rrset_key* key,
* 1: reference updated, item is inserted in cache.
* 2: reference updated, item in cache is considered superior.
* also the rdata is equal (but other parameters in cache are superior).
* In case 2 the item is returned under a readlock. The caller must
* unlock.
*/
int rrset_cache_update(struct rrset_cache* r, struct rrset_ref* ref,
struct alloc_cache* alloc, time_t timenow);
/** The rrset_cache_update routine that unlocks at end */
void rrset_cache_update_unlock(struct rrset_cache* r, struct rrset_ref* ref,
struct alloc_cache* alloc, time_t timenow);
/**
* Update or add an rrset in the rrset cache using a wildcard dname.
* Generates wildcard dname by prepending the wildcard label to the closest
+22 -4
View File
@@ -1341,13 +1341,33 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if((is_doq) && !(is_https || is_ssl)) do_tcp = 0;
if(do_auto) {
enum listen_type auto_port_type;
ub_sock = calloc(1, sizeof(struct unbound_socket));
if(!ub_sock)
return 0;
if(is_dnscrypt) {
auto_port_type = listen_type_udpancil_dnscrypt;
add = "udpancil_dnscrypt";
} else if(is_doq) {
auto_port_type = listen_type_doq;
add = "doq";
if(if_listens_on(ifname, port, 53, NULL)) {
log_err("DNS over QUIC is strictly not "
"allowed on port 53 as per RFC 9250. "
"Port 53 is for DNS datagrams. Error "
"for interface '%s'.", ifname);
free(ub_sock->addr);
free(ub_sock);
return 0;
}
} else {
auto_port_type = listen_type_udpancil;
add = "udpancil";
}
if((s = make_sock_port(SOCK_DGRAM, ifname, port, hints, 1,
&noip6, rcv, snd, reuseport, transparent,
tcp_mss, nodelay, freebind, use_systemd, dscp, ub_sock,
(is_dnscrypt?"udpancil_dnscrypt":"udpancil"))) == -1) {
add)) == -1) {
free(ub_sock->addr);
free(ub_sock);
if(noip6) {
@@ -1366,9 +1386,7 @@ ports_create_if(const char* ifname, int do_auto, int do_udp, int do_tcp,
if (sock_queue_timeout && !set_recvtimestamp(s)) {
log_warn("socket timestamping is not available");
}
if(!port_insert(list, s, is_dnscrypt
?listen_type_udpancil_dnscrypt:listen_type_udpancil,
is_pp2, ub_sock)) {
if(!port_insert(list, s, auto_port_type, is_pp2, ub_sock)) {
sock_close(s);
free(ub_sock->addr);
free(ub_sock);
+2 -2
View File
@@ -198,7 +198,7 @@ parse_dname(const char* str, uint8_t** res, size_t* len, int* labs)
}
/** create a new localzone */
static struct local_zone*
struct local_zone*
local_zone_create(uint8_t* nm, size_t len, int labs,
enum localzone_type t, uint16_t dclass)
{
@@ -534,7 +534,7 @@ lz_find_create_node(struct local_zone* z, uint8_t* nm, size_t nmlen,
* records. An artificial soa_negative record with a modified TTL (minimum of
* the TTL and the SOA.MINIMUM) is also created and marked for usage with
* negative answers and to avoid allocations during those answers. */
static int
int
lz_mark_soa_for_zone(struct local_zone* z, struct ub_packed_rrset_key* soa_rrset,
uint8_t* rdata, size_t rdata_len, time_t ttl, const char* rrstr)
{
+10
View File
@@ -688,4 +688,14 @@ lz_enter_zone(struct local_zones* zones, const char* name, const char* type,
*/
void
lz_init_parents(struct local_zones* zones);
/** create a new localzone */
struct local_zone* local_zone_create(uint8_t* nm, size_t len, int labs,
enum localzone_type t, uint16_t dclass);
/** Mark the SOA record for the zone. */
int lz_mark_soa_for_zone(struct local_zone* z,
struct ub_packed_rrset_key* soa_rrset, uint8_t* rdata,
size_t rdata_len, time_t ttl, const char* rrstr);
#endif /* SERVICES_LOCALZONE_H */
+7 -3
View File
@@ -3945,11 +3945,15 @@ setup_http_user_agent(sldns_buffer* buf, struct config_file* cfg)
/** setup http request headers in buffer for sending query to destination */
static int
setup_http_request(sldns_buffer* buf, char* host, char* path,
struct config_file* cfg)
struct config_file* cfg, const char* etag)
{
sldns_buffer_clear(buf);
sldns_buffer_printf(buf, "GET /%s HTTP/1.1\r\n", path);
sldns_buffer_printf(buf, "Host: %s\r\n", host);
if (etag) {
verbose(VERB_ALGO, "sending along ETag %s in http request", etag);
sldns_buffer_printf(buf, "If-None-Match: %s\r\n", etag);
}
setup_http_user_agent(buf, cfg);
/* We do not really do multiple queries per connection,
* but this header setting is also not needed.
@@ -3966,7 +3970,7 @@ struct comm_point*
outnet_comm_point_for_http(struct outside_network* outnet,
comm_point_callback_type* cb, void* cb_arg,
struct sockaddr_storage* to_addr, socklen_t to_addrlen, int timeout,
int ssl, char* host, char* path, struct config_file* cfg)
int ssl, char* host, char* path, struct config_file* cfg, char* etag)
{
/* cp calls cb with err=NETEVENT_DONE when transfer is done */
struct comm_point* cp;
@@ -4004,7 +4008,7 @@ outnet_comm_point_for_http(struct outside_network* outnet,
comm_point_start_listening(cp, fd, timeout);
/* setup http request in cp->buffer */
if(!setup_http_request(cp->buffer, host, path, cfg)) {
if(!setup_http_request(cp->buffer, host, path, cfg, etag)) {
log_err("error setting up http request");
comm_point_delete(cp);
return NULL;
+1 -1
View File
@@ -854,7 +854,7 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet,
struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
comm_point_callback_type* cb, void* cb_arg,
struct sockaddr_storage* to_addr, socklen_t to_addrlen, int timeout,
int ssl, char* host, char* path, struct config_file* cfg);
int ssl, char* host, char* path, struct config_file* cfg, char* etag);
/** connect tcp connection to addr, 0 on failure */
int outnet_tcp_connect(int s, struct sockaddr_storage* addr, socklen_t addrlen);
+79 -33
View File
@@ -506,24 +506,37 @@ delete_cname_override(struct rpz* r)
static int
rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p)
{
enum rpz_action action_override;
if(p->rpz_taglist && p->rpz_taglistlen) {
r->taglistlen = p->rpz_taglistlen;
r->taglist = memdup(p->rpz_taglist, r->taglistlen);
if(!r->taglist) {
uint8_t* taglist = memdup(p->rpz_taglist, p->rpz_taglistlen);
if(!taglist) {
log_err("malloc failure on RPZ taglist alloc");
return 0;
}
if(r->taglist)
free(r->taglist);
r->taglist = taglist;
r->taglistlen = p->rpz_taglistlen;
} else {
/* free taglist, if any */
if(r->taglist) {
free(r->taglist);
r->taglist = NULL;
r->taglistlen = 0;
}
}
if(p->rpz_action_override) {
r->action_override = rpz_config_to_action(p->rpz_action_override);
action_override = rpz_config_to_action(p->rpz_action_override);
}
else
r->action_override = RPZ_NO_OVERRIDE_ACTION;
action_override = RPZ_NO_OVERRIDE_ACTION;
if(r->action_override == RPZ_CNAME_OVERRIDE_ACTION) {
if(action_override == RPZ_CNAME_OVERRIDE_ACTION) {
uint8_t nm[LDNS_MAX_DOMAINLEN+1];
size_t nmlen = sizeof(nm);
struct regional* newr;
struct ub_packed_rrset_key* cname_override;
if(!p->rpz_cname) {
log_err("rpz: override with cname action found, but no "
@@ -536,33 +549,50 @@ rpz_apply_cfg_elements(struct rpz* r, struct config_auth* p)
p->rpz_cname);
return 0;
}
r->cname_override = new_cname_override(r->region, nm, nmlen);
if(!r->cname_override) {
newr = regional_create_custom(sizeof(struct regional));
if(!newr) {
log_err("malloc failure on RPZ cname override region");
return 0;
}
cname_override = new_cname_override(newr, nm, nmlen);
if(!cname_override) {
regional_destroy(newr);
return 0;
}
regional_destroy(r->region);
r->region = newr;
r->cname_override = cname_override;
} else {
delete_cname_override(r);
}
r->action_override = action_override;
r->log = p->rpz_log;
r->signal_nxdomain_ra = p->rpz_signal_nxdomain_ra;
if(p->rpz_log_name) {
if(!(r->log_name = strdup(p->rpz_log_name))) {
char* log_name = strdup(p->rpz_log_name);
if(!log_name) {
log_err("malloc failure on RPZ log_name strdup");
return 0;
}
if(r->log_name)
free(r->log_name);
r->log_name = log_name;
} else {
/* free logname, if any */
if(r->log_name) {
free(r->log_name);
r->log_name = NULL;
}
}
return 1;
}
struct rpz*
rpz_create(struct config_auth* p)
rpz_create_empty(void)
{
struct rpz* r = calloc(1, sizeof(*r));
if(!r)
goto err;
r->region = regional_create_custom(sizeof(struct regional));
if(!r->region) {
goto err;
}
return NULL;
if(!(r->local_zones = local_zones_create())){
goto err;
@@ -586,6 +616,35 @@ rpz_create(struct config_auth* p)
if(r->ns_set == NULL) {
goto err;
}
return r;
err:
if(r) {
if(r->local_zones)
local_zones_delete(r->local_zones);
if(r->nsdname_zones)
local_zones_delete(r->nsdname_zones);
if(r->respip_set)
respip_set_delete(r->respip_set);
if(r->client_set != NULL)
rpz_clientip_synthesized_set_delete(r->client_set);
if(r->ns_set != NULL)
rpz_clientip_synthesized_set_delete(r->ns_set);
free(r);
}
return NULL;
}
struct rpz*
rpz_create(struct config_auth* p)
{
struct rpz* r = rpz_create_empty();
if(!r)
goto err;
r->region = regional_create_custom(sizeof(struct regional));
if(!r->region) {
goto err;
}
if(!rpz_apply_cfg_elements(r, p))
goto err;
@@ -616,22 +675,6 @@ rpz_config(struct rpz* r, struct config_auth* p)
{
/* If the zonefile changes, it is read later, after which
* rpz_clear and rpz_finish_config is called. */
/* free taglist, if any */
if(r->taglist) {
free(r->taglist);
r->taglist = NULL;
r->taglistlen = 0;
}
/* free logname, if any */
if(r->log_name) {
free(r->log_name);
r->log_name = NULL;
}
delete_cname_override(r);
if(!rpz_apply_cfg_elements(r, p))
return 0;
return 1;
@@ -2078,6 +2121,7 @@ rpz_synthesize_localdata_from_rrset(struct rpz* ATTR_UNUSED(r), struct module_qs
* actual data. So that the actual network data and fake data
* are kept track of separately. */
rp->rk.flags |= PACKED_RRSET_RPZ;
rp->entry.hash = rrset_key_hash(&rp->rk);
new_reply_info->rrsets[0] = rp;
msg->rep = new_reply_info;
if(!rpz_add_soa(msg->rep, ms, az))
@@ -2243,6 +2287,7 @@ rpz_synthesize_cname_override_msg(struct rpz* r, struct module_qstate* ms,
* actual data. So that the actual network data and fake data
* are kept track of separately. */
rp->rk.flags |= PACKED_RRSET_RPZ;
rp->entry.hash = rrset_key_hash(&rp->rk);
new_reply_info->rrsets[0] = rp;
msg->rep = new_reply_info;
@@ -2849,7 +2894,8 @@ size_t rpz_get_mem(struct rpz* r)
m += r->taglistlen;
if(r->log_name)
m += strlen(r->log_name) + 1;
m += regional_get_mem(r->region);
if(r->region)
m += regional_get_mem(r->region);
m += local_zones_get_mem(r->local_zones);
m += local_zones_get_mem(r->nsdname_zones);
m += respip_set_get_mem(r->respip_set);
+3
View File
@@ -219,6 +219,9 @@ void rpz_delete(struct rpz* r);
*/
int rpz_clear(struct rpz* r);
/** Create empty RPZ structure, useful as a proxy for entering data. */
struct rpz* rpz_create_empty(void);
/**
* Create RPZ. RPZ must be added to linked list after creation.
* @return: the newly created RPZ
+2
View File
@@ -197,6 +197,8 @@ sldns_fget_token_l(FILE *f, char *token, const char *delim, size_t limit, int *l
}
*t = '\0';
if (c == EOF) {
if(p != 0 || quoted)
return -1;
return (ssize_t)i;
}
+24 -5
View File
@@ -842,8 +842,7 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len,
sldns_write_uint16(rr+dname_len+8, (uint16_t)(rr_cur_len-dname_len-10));
*rr_len = rr_cur_len;
/* SVCB/HTTPS handling */
if ((rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS)
&& !was_unknown_rr_format) {
if (rr_type == LDNS_RR_TYPE_SVCB || rr_type == LDNS_RR_TYPE_HTTPS) {
size_t rdata_len = rr_cur_len - dname_len - 10;
uint8_t *rdata = rr+dname_len + 10;
@@ -875,7 +874,14 @@ rrinternal_parse_rdata(sldns_buffer* strbuf, char* token, size_t token_len,
rdata_len -= 1;
rdata += 1;
return sldns_str2wire_check_svcbparams(rdata, rdata_len);
status = sldns_str2wire_check_svcbparams(rdata, rdata_len);
/* For RFC3597 generic-form input, preserve unprintable records.
* Those could have appeared due to secondary zones, and also
* unbound writing invalid-format records out in generic form.
* If it can be parsed, it fixes the svcparam ordering. */
if(was_unknown_rr_format && status != LDNS_WIREPARSE_ERR_OK)
status = LDNS_WIREPARSE_ERR_OK;
return status;
}
return LDNS_WIREPARSE_ERR_OK;
@@ -2304,6 +2310,8 @@ int sldns_str2wire_loc_buf(const char* str, uint8_t* rd, size_t* len)
if (isdigit((unsigned char) *my_str)) {
s = strtod(my_str, &my_str);
if(s > 60.0)
return LDNS_WIREPARSE_ERR_SYNTAX;
}
/* skip blanks before northerness */
@@ -2362,6 +2370,8 @@ north:
if (isdigit((unsigned char) *my_str)) {
s = strtod(my_str, &my_str);
if(s > 60.0)
return LDNS_WIREPARSE_ERR_SYNTAX;
}
/* skip blanks before easterness */
@@ -2394,8 +2404,17 @@ east:
longitude = equator - longitude;
}
altitude = (uint32_t)(strtod(my_str, &my_str)*100.0 +
10000000.0 + 0.5);
while (isblank((unsigned char) *my_str)) {
my_str++;
}
/* altitude */
if(!(isdigit((unsigned char) *my_str) || *my_str == '-'))
return LDNS_WIREPARSE_ERR_SYNTAX;
s = strtod(my_str, &my_str);
if(s < -100000.0 || s > 42849672.95)
return LDNS_WIREPARSE_ERR_SYNTAX;
altitude = (uint32_t)(s*100.0 + 10000000.0 + 0.5);
if (*my_str == 'm' || *my_str == 'M') {
my_str++;
}
+13 -6
View File
@@ -90,6 +90,7 @@ usage(void)
printf("Usage: unbound-checkconf [file]\n");
printf(" Checks unbound configuration file for errors.\n");
printf("file if omitted %s is used.\n", CONFIGFILE);
printf("-a read zone files of auth-zones and RPZ.\n");
printf("-o option print value of option to stdout.\n");
printf("-f output full pathname with chroot applied, eg. with -o pidfile.\n");
printf("-q quiet (suppress output on success).\n");
@@ -1166,11 +1167,12 @@ check_hints(struct config_file* cfg)
/** check auth zones */
static void
check_auth(struct config_file* cfg)
check_auth(struct config_file* cfg, int readauth)
{
int is_rpz = 0;
struct auth_zones* az = auth_zones_create();
if(!az || !auth_zones_apply_cfg(az, cfg, 0, &is_rpz, NULL, NULL)) {
if(!az || !auth_zones_apply_cfg(az, cfg, 0, readauth, &is_rpz, NULL,
NULL)) {
fatal_exit("Could not setup authority zones");
}
if(is_rpz && !strstr(cfg->module_conf, "respip"))
@@ -1180,7 +1182,8 @@ check_auth(struct config_file* cfg)
/** check config file */
static void
checkconf(const char* cfgfile, const char* opt, int final, int quiet)
checkconf(const char* cfgfile, const char* opt, int final, int quiet,
int readauth)
{
char oldwd[4096];
struct config_file* cfg = config_create();
@@ -1212,7 +1215,7 @@ checkconf(const char* cfgfile, const char* opt, int final, int quiet)
#endif
check_fwd(cfg);
check_hints(cfg);
check_auth(cfg);
check_auth(cfg, readauth);
if(!quiet) { printf("unbound-checkconf: no errors in %s\n", cfgfile); }
config_delete(cfg);
}
@@ -1228,6 +1231,7 @@ int main(int argc, char* argv[])
int c;
int final = 0;
int quiet = 0;
int readauth = 0;
const char* f;
const char* opt = NULL;
const char* cfgfile = CONFIGFILE;
@@ -1240,8 +1244,11 @@ int main(int argc, char* argv[])
cfgfile = CONFIGFILE;
#endif /* USE_WINSOCK */
/* parse the options */
while( (c=getopt(argc, argv, "fhqo:")) != -1) {
while( (c=getopt(argc, argv, "afhqo:")) != -1) {
switch(c) {
case 'a':
readauth = 1;
break;
case 'f':
final = 1;
break;
@@ -1264,7 +1271,7 @@ int main(int argc, char* argv[])
if(argc == 1)
f = argv[0];
else f = cfgfile;
checkconf(f, opt, final, quiet);
checkconf(f, opt, final, quiet, readauth);
checklock_stop();
return 0;
}
+40 -5
View File
@@ -92,7 +92,9 @@ struct fake_commpoint {
/** runtime ptr */
struct replay_runtime* runtime;
/** the pending entry for this commpoint (if any) */
struct fake_pending* pending;
uint8_t* pkt;
/** the length of pkt */
size_t pkt_len;
};
/** Global variable: the scenario. Saved here for when event_init is done. */
@@ -314,6 +316,29 @@ pending_list_delete(struct replay_runtime* runtime, struct fake_pending* pend)
}
}
/**
* Remove the item from the pending list, by packet content.
*/
static void
pending_list_delete_pkt(struct replay_runtime* runtime, uint8_t* pkt,
size_t pkt_len)
{
struct fake_pending** prev = &runtime->pending_list;
struct fake_pending* p = runtime->pending_list;
while(p) {
if(p->pkt_len == pkt_len &&
memcmp(pkt, p->pkt, p->pkt_len) == 0) {
*prev = p->next;
delete_fake_pending(p);
return;
}
prev = &p->next;
p = p->next;
}
}
/** number of replies in entry */
static int
count_reply_packets(struct entry* entry)
@@ -1488,7 +1513,12 @@ void comm_point_delete(struct comm_point* c)
log_assert(fc->typecode == FAKE_COMMPOINT_TYPECODE);
if(fc->type_tcp_out) {
/* remove tcp pending, so no more callbacks to it */
pending_list_delete(fc->runtime, fc->pending);
if(fc->pkt)
pending_list_delete_pkt(fc->runtime, fc->pkt, fc->pkt_len);
}
if(fc->pkt) {
free(fc->pkt);
fc->pkt = NULL;
}
free(c);
}
@@ -1825,7 +1855,6 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet,
fc->cb = cb;
fc->cb_arg = cb_arg;
fc->runtime = runtime;
fc->pending = pend;
/* used by authzone transfers */
/* create pending item */
@@ -1866,6 +1895,9 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet,
pend->pkt_len = sldns_buffer_limit(pend->buffer);
pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len);
if(!pend->pkt) fatal_exit("out of memory");
fc->pkt_len = pend->pkt_len;
fc->pkt = memdup(pend->pkt, pend->pkt_len);
if(!fc->pkt) fatal_exit("out of memory");
log_info("testbound: created fake pending for tcp_out");
@@ -1879,7 +1911,7 @@ struct comm_point* outnet_comm_point_for_tcp(struct outside_network* outnet,
struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
comm_point_callback_type* cb, void* cb_arg,
struct sockaddr_storage* to_addr, socklen_t to_addrlen, int timeout,
int ssl, char* host, char* path, struct config_file* cfg)
int ssl, char* host, char* path, struct config_file* cfg, char* etag)
{
struct replay_runtime* runtime = (struct replay_runtime*)
outnet->base;
@@ -1902,6 +1934,7 @@ struct comm_point* outnet_comm_point_for_http(struct outside_network* outnet,
(void)host;
(void)path;
(void)cfg;
(void)etag;
/* handle http comm point and return contents from test script */
return (struct comm_point*)fc;
@@ -1918,7 +1951,6 @@ int comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
log_err("malloc failure");
return 0;
}
fc->pending = pend;
/* used by authzone transfers */
/* create pending item */
pend->buffer = sldns_buffer_new(sldns_buffer_limit(packet) + 10);
@@ -1957,6 +1989,9 @@ int comm_point_send_udp_msg(struct comm_point *c, sldns_buffer* packet,
pend->pkt_len = sldns_buffer_limit(pend->buffer);
pend->pkt = memdup(sldns_buffer_begin(pend->buffer), pend->pkt_len);
if(!pend->pkt) fatal_exit("out of memory");
fc->pkt_len = pend->pkt_len;
fc->pkt = memdup(pend->pkt, pend->pkt_len);
if(!fc->pkt) fatal_exit("out of memory");
log_info("testbound: created fake pending for send_udp_msg");
+3
View File
@@ -264,6 +264,9 @@ setup_config(FILE* in, int* lineno, int* pass_argc, char* pass_argv[])
fprintf(cfg, " pidfile: \"\"\n");
fprintf(cfg, " val-log-level: 2\n");
fprintf(cfg, " log-servfail: yes\n");
/* the extra thread needs pipe communication that is not available
* from fake_event calls. So auth-task-threads: 0 disables them. */
fprintf(cfg, " auth-task-threads: 0\n");
fprintf(cfg, "remote-control: control-enable: no\n");
while(fgets(line, MAX_LINE_LEN-1, in)) {
parse = line;
+7 -7
View File
@@ -387,7 +387,7 @@ hex_buffer2wire(sldns_buffer *data_buffer)
uint8_t *wire = (uint8_t*)malloc(MAX_PACKETLEN);
if(!wire) error("out of memory");
hexbuf = (uint8_t*)malloc(MAX_PACKETLEN);
hexbuf = (uint8_t*)malloc(MAX_PACKETLEN * 2);
if(!hexbuf) error("out of memory");
for (data_buf_pos = 0; data_buf_pos < sldns_buffer_position(data_buffer); data_buf_pos++) {
c = (int) data_wire[data_buf_pos];
@@ -402,7 +402,7 @@ hex_buffer2wire(sldns_buffer *data_buffer)
(c >= 'a' && c <= 'f') ||
(c >= 'A' && c <= 'F') )
{
if (hexbufpos >= MAX_PACKETLEN) {
if (hexbufpos >= MAX_PACKETLEN * 2) {
error("buffer overflow");
free(hexbuf);
return 0;
@@ -422,7 +422,7 @@ hex_buffer2wire(sldns_buffer *data_buffer)
}
break;
case 2:
if (hexbufpos >= MAX_PACKETLEN) {
if (hexbufpos >= MAX_PACKETLEN * 2) {
error("buffer overflow");
free(hexbuf);
return 0;
@@ -433,13 +433,13 @@ hex_buffer2wire(sldns_buffer *data_buffer)
}
}
if (hexbufpos >= MAX_PACKETLEN) {
if (hexbufpos >= MAX_PACKETLEN * 2) {
/*verbose("packet size reached\n");*/
}
/* lenient mode: length must be multiple of 2 */
if (hexbufpos % 2 != 0) {
if (hexbufpos >= MAX_PACKETLEN) {
if (hexbufpos >= MAX_PACKETLEN * 2) {
error("buffer overflow");
free(hexbuf);
return 0;
@@ -630,7 +630,7 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate,
add_section = LDNS_SECTION_ADDITIONAL;
else error("%s line %d: bad section %s", name, pstate->lineno, parse);
} else if(str_keyword(&parse, "HEX_ANSWER_BEGIN")) {
hex_data_buffer = sldns_buffer_new(MAX_PACKETLEN);
hex_data_buffer = sldns_buffer_new(MAX_PACKETLEN*2);
reading_hex = 1;
} else if(str_keyword(&parse, "HEX_ANSWER_END")) {
if(!reading_hex) {
@@ -643,7 +643,7 @@ read_entry(FILE* in, const char* name, struct sldns_file_parse_state* pstate,
} else if(reading_hex) {
sldns_buffer_printf(hex_data_buffer, "%s", line);
} else if(str_keyword(&parse, "HEX_EDNSDATA_BEGIN")) {
hex_ednsdata_buffer = sldns_buffer_new(MAX_PACKETLEN);
hex_ednsdata_buffer = sldns_buffer_new(MAX_PACKETLEN*2);
reading_hex_ednsdata = 1;
} else if(str_keyword(&parse, "HEX_EDNSDATA_END")) {
if (!reading_hex_ednsdata) {
+1 -1
View File
@@ -735,7 +735,7 @@ check_read_exact(const char* name, const char* zone)
z = authtest_addzone(az, name, fname);
unit_assert(z);
outf = create_tmp_file(NULL);
if(!auth_zone_write_file(z, outf)) {
if(!auth_zone_write_file(z, outf, NULL)) {
fatal_exit("write file failed for %s", fname);
}
checkfile(fname, outf);
+84
View File
@@ -1337,6 +1337,89 @@ static void mesh_test(void)
free(c1);
}
#include "util/data/packed_rrset.h"
#include "sldns/sbuffer.h"
/** packed_rrset unit tests */
static void packed_rrset_test(void)
{
/* packed_rr_to_string assembles the dname, type, class, ttl and
* rdata of one rr into a buffer of 65535 bytes. Check that it
* refuses an rr that does not fit in there, also when the caller
* passes a dest_len that is larger than that, like the callers in
* daemon/cachedump.c and daemon/remote.c do. Without the check it
* writes past the end of the assembly buffer. */
uint8_t smalldname[] = "\003www\007example\003com";
uint8_t smallrdata[] = {0, 4, 1, 2, 3, 4};
uint8_t maxdname[LDNS_MAX_DOMAINLEN];
struct ub_packed_rrset_key rrk;
struct packed_rrset_data d;
uint8_t* rr_data[1];
size_t rr_len[1];
time_t rr_ttl[1];
size_t dest_len = 65535*4+2048; /* the size daemon/cachedump.c uses */
char* dest = (char*)malloc(dest_len);
int i;
unit_show_func("util/data/packed_rrset.c", "packed_rr_to_string");
if(!dest) fatal_exit("out of memory");
memset(&rrk, 0, sizeof(rrk));
memset(&d, 0, sizeof(d));
rrk.entry.data = &d;
rrk.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
d.count = 1;
d.rr_len = rr_len;
d.rr_ttl = rr_ttl;
d.rr_data = rr_data;
rr_ttl[0] = 3600;
/* an ordinary rr is printed, also with the large dest_len */
rrk.rk.dname = smalldname;
rrk.rk.dname_len = sizeof(smalldname);
rrk.rk.type = htons(LDNS_RR_TYPE_A);
rr_data[0] = smallrdata;
rr_len[0] = sizeof(smallrdata);
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 1);
unit_assert(strstr(dest, "1.2.3.4") != NULL);
/* a dname of the maximum length, 127 labels of one character */
for(i=0; i<127; i++) {
maxdname[i*2] = 1;
maxdname[i*2+1] = (uint8_t)'a';
}
maxdname[254] = 0;
rrk.rk.dname = maxdname;
rrk.rk.dname_len = sizeof(maxdname);
rrk.rk.type = htons(LDNS_RR_TYPE_TXT);
/* 255+2+2+4+65272 is exactly 65535, that still fits */
rr_len[0] = 65535 - 255 - 8;
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
if(!rr_data[0]) fatal_exit("out of memory");
sldns_write_uint16(rr_data[0], (uint16_t)(rr_len[0]-2));
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 1);
free(rr_data[0]);
/* one more byte of rdata does not fit and must be refused */
rr_len[0] = 65535 - 255 - 8 + 1;
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
if(!rr_data[0]) fatal_exit("out of memory");
sldns_write_uint16(rr_data[0], (uint16_t)(rr_len[0]-2));
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 0);
unit_assert(dest[0] == 0);
free(rr_data[0]);
/* the largest rdata an rr can hold, well over the buffer */
rr_len[0] = 2 + 65535;
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
if(!rr_data[0]) fatal_exit("out of memory");
sldns_write_uint16(rr_data[0], 65535);
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 0);
unit_assert(dest[0] == 0);
free(rr_data[0]);
free(dest);
}
void unit_show_func(const char* file, const char* func)
{
printf("test %s:%s\n", file, func);
@@ -1409,6 +1492,7 @@ main(int argc, char* argv[])
zonemd_test();
tcpreuse_test();
msgparse_test();
packed_rrset_test();
edns_ede_answer_encode_test();
localzone_test();
mesh_test();
+18
View File
@@ -0,0 +1,18 @@
server:
verbosity: 8
# num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 1
auth-zone:
name: "example.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load
Version: 1.0
Description: Perform AXFR for authority zone with auth load thread
CreationDate: Thu 2 Jul 09:35:40 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load.pre
Post: auth_load.post
Test: auth_load.test
AuxFiles:
Passed:
Failure:
+12
View File
@@ -0,0 +1,12 @@
# #-- auth_load.post --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# source the test var file when it's there
[ -f .tpkg.var.test ] && source .tpkg.var.test
#
# do your teardown here
. ../common.sh
kill_pid $FWD_PID
kill_pid $UNBOUND_PID
cat fwd.log
cat unbound.log
+39
View File
@@ -0,0 +1,39 @@
# #-- auth_load.pre--#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
# if no threads; exit
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
echo "have threads"
else
skip_test "no threads"
fi
get_random_port 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT auth_load.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < auth_load.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+55
View File
@@ -0,0 +1,55 @@
# #-- auth_load.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
# do the test
echo "> dig www.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
echo "> check answer"
if grep "1.2.3.4" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
if grep "auth zone example.com. details" unbound.log; then
echo "OK"
else
echo "not OK"
exit 1
fi
exit 0
+27
View File
@@ -0,0 +1,27 @@
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example.com. IN SOA
SECTION ANSWER
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example.com. IN AXFR
SECTION ANSWER
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
example.com. IN NS ns.example.net.
EXTRA_PACKET
REPLY QR AA NOERROR
SECTION QUESTION
example.com. IN AXFR
SECTION ANSWER
www.example.com. IN A 1.2.3.4
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
@@ -0,0 +1,3 @@
example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
example.com. IN NS ns.example.net.
www.example.com. IN A 1.2.3.4
+18
View File
@@ -0,0 +1,18 @@
server:
verbosity: 8
# num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 1
auth-zone:
name: "example.com"
for-upstream: yes
for-downstream: yes
url: "https://127.0.0.1:@TOPORT@/example.com.zone"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load_http
Version: 1.0
Description: Perform http transfer for authority zone with auth load thread
CreationDate: Tue 11 Aug 16:00:00 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load_http.pre
Post: auth_load_http.post
Test: auth_load_http.test
AuxFiles:
Passed:
Failure:
+12
View File
@@ -0,0 +1,12 @@
# #-- auth_load_http.post --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# source the test var file when it's there
[ -f .tpkg.var.test ] && source .tpkg.var.test
#
# do your teardown here
. ../common.sh
kill_pid $UNBOUND_PID
kill_pid $PETAL_PID
cat petal.log
cat unbound.log
+40
View File
@@ -0,0 +1,40 @@
# #-- auth_load_http.pre--#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
# if no threads; exit
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
echo "have threads"
else
skip_test "no threads"
fi
get_random_port 2
UNBOUND_PORT=$RND_PORT
PETAL_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "PETAL_PORT=$PETAL_PORT" >> .tpkg.var.test
get_make
(cd $PRE; $MAKE petal)
# start https daemon
$PRE/petal -v -a "127.0.0.1" -p $PETAL_PORT >petal.log 2>&1 &
PETAL_PID=$!
echo "PETAL_PID=$PETAL_PID" >> .tpkg.var.test
wait_petal_up petal.log
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$PETAL_PORT'/' < auth_load_http.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_unbound_up unbound.log
+55
View File
@@ -0,0 +1,55 @@
# #-- auth_load_http.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
# do the test
echo "> dig www.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
echo "> check answer"
if grep "1.2.3.4" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
if grep "auth zone example.com. details" unbound.log; then
echo "OK"
else
echo "not OK"
exit 1
fi
exit 0
+21
View File
@@ -0,0 +1,21 @@
-----BEGIN RSA PRIVATE KEY-----
MIIDfQIBAAKBwQC1xQ/Kca6zszZbcCtdOTIH2Uy2gOy/DfabMUU7TmNPm0dVE0NJ
RuN+Rm304SonpwghfP2/ULZNnuDgpG03/32yI7k/VzG6iA4hiF7tT/KAAWC/+2l1
QCsawCV2bSrFK0VhcZr7ALqXd8vkDaQ867K029ypjOQtAJ85qdO3mERy7TGtdUcu
O6hLeVet419YeQ2F8cfNxn63d7bOzNGLPW5xwaCd3UcgD+Ib0k4xfFvbinvPQUeU
J/i4YDWexFYSL+ECAwEAAQKBwCLXXQl+9O+5AEhSnd1Go1Jh0pSA7eBJOuXQcebG
Rb7ykp+6C4G2NtDziwwPRNdI6wQQQ0sym18RfyVQHydGr78/nbiIbB3HCn5e92Mh
mefzW6ow9Kvm2txLzGKA1lvoyRbNm81jnG/eygi3u7Nqd5PNv+4dHj2RkTlmxOeh
qnDMVP5md8uZPv6lYNnrnIzvLCR5vnPNdVwn89AqzI85IcDZdy0R9ZX4NBbsDgAU
6ig6uXuRXvSGiyJ/OUXSrnogaQJhAOjvkHUhVZQkPOxO90TNH4j0GdKKtbSWxIdz
lKfuJeBAEqs0TL+C6vbS81Xw3W1alyDdUBk3rJMOBqW6Ryq5HNL+j5H+Jfsh7fvc
Yle+5wHGci0P9zCFZCrY8It7n9XFIwJhAMfEi6oJa2G8waPJ1bQhxka82Tf9pnKM
XCn/1BBOFjVIx5F842cpA+zp5a62GENTGYPQTTRBB/2/ZwnW5aIkrlg54AtmbqBZ
Oh+2kJdJQD/tfoVmc5soUE2ScTHadK5RKwJhAN4w9kjkXS+MSZjX0kIMsBIBVkhh
C+aREjJqa9ir7/Ey7RvmLXdYuCxtGLRXp7/R8+rjcK49Tx6O+IRJZe042mfhbq3C
EhS1Tr86f4xXix9EXlDhs9bSxrOgcAN9Dv/opQJhAK7eBcPaav0rVfYh/8emqQHS
3fJ9Pu6WnzbEksWTFS2ff9KDGCx9YspIFJ5TF/oXDAaumGZdZrlgirm6O1kr8tGY
F97i04PZl1+bWAaWQH+1TUNI43m2WFUPE7coG2tb8QJgcddDg9VlXliZqgcETZfJ
kJmYETxrcSn3ao6v116N8yxhEgUgjkmsCTiFgx36iDVnXwK6PIt+sIu8MC7eYNa3
berrv/M21K0LRn20IWRxvUobG070weHCAgkko7fTWgr2
-----END RSA PRIVATE KEY-----
+14
View File
@@ -0,0 +1,14 @@
-----BEGIN CERTIFICATE-----
MIICFzCCAUACCQDO660L5y5LGDANBgkqhkiG9w0BAQUFADAQMQ4wDAYDVQQDEwVw
ZXRhbDAeFw0xMDA5MzAxMzQzMDFaFw0zMDA2MTcxMzQzMDFaMBAxDjAMBgNVBAMT
BXBldGFsMIHfMA0GCSqGSIb3DQEBAQUAA4HNADCByQKBwQC1xQ/Kca6zszZbcCtd
OTIH2Uy2gOy/DfabMUU7TmNPm0dVE0NJRuN+Rm304SonpwghfP2/ULZNnuDgpG03
/32yI7k/VzG6iA4hiF7tT/KAAWC/+2l1QCsawCV2bSrFK0VhcZr7ALqXd8vkDaQ8
67K029ypjOQtAJ85qdO3mERy7TGtdUcuO6hLeVet419YeQ2F8cfNxn63d7bOzNGL
PW5xwaCd3UcgD+Ib0k4xfFvbinvPQUeUJ/i4YDWexFYSL+ECAwEAATANBgkqhkiG
9w0BAQUFAAOBwQBBkX9KDP2RXbg+xPmdJ4P6CwvA5x1LZwC++ydVx4NlvT0pWicD
ZUnXjcWAJlkeOuUBAqFG7WHTrXpUUAjmdqFVq2yFjteUYBdrFz0RDB2jM9feeKYO
mTgxdZyT9a6humxCxt5VfgT02axLjm/2AqCyFPMbf4PASoJDln01AEuZLZ8Xl2gV
bYHMnHTGoD1Hu6FNEzRgkMC6XT8X3YjHvzQhpc/qL5wEfEsinQGdX4twsuWbf8xd
q7miNnkO8vd0maw=
-----END CERTIFICATE-----
+28
View File
@@ -0,0 +1,28 @@
server:
verbosity: 8
# num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
module-config: "respip validator iterator"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 1
log-queries: yes
log-replies: yes
forward-zone:
name: "."
forward-addr: "127.0.0.1@@TOPORT@"
rpz:
name: "rpz.example.com"
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
allow-notify: 127.0.0.0/8
zonefile: "auth_load_ixfr.zone"
rpz-log: yes
rpz-log-name: "rpz.example.com"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load_ixfr
Version: 1.0
Description: Load RPZ zone with auth load thread with IXFR.
CreationDate: Thu 15 Oct 13:00:00 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load_ixfr.pre
Post: auth_load_ixfr.post
Test: auth_load_ixfr.test
AuxFiles:
Passed:
Failure:
+12
View File
@@ -0,0 +1,12 @@
# #-- auth_load_ixfr.post --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# source the test var file when it's there
[ -f .tpkg.var.test ] && source .tpkg.var.test
#
# do your teardown here
. ../common.sh
kill_pid $FWD_PID
kill_pid $UNBOUND_PID
cat fwd.log
cat unbound.log
+39
View File
@@ -0,0 +1,39 @@
# #-- auth_load_ixfr.pre--#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
# if no threads; exit
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
echo "have threads"
else
skip_test "no threads"
fi
get_random_port 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT auth_load_ixfr.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < auth_load_ixfr.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+88
View File
@@ -0,0 +1,88 @@
# #-- auth_load_ixfr.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
# do the test
$PRE/streamtcp -f 127.0.0.1@$UNBOUND_PORT rpz.example.com. NOTIFY IN
wait_logfile unbound.log "auth zone rpz.example.com. updated to serial 2" 10
# The answer is rewritten by RPZ, that is loaded in the auth load thread.
echo "> dig www.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
echo "> check answer"
if grep "1.2.3.5" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
echo "> dig o3.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT o3.example.com. | tee outfile
echo "> check answer"
if grep "1.2.3.7" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
echo "> dig other.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT other.example.com. | tee outfile
echo "> check answer"
if grep "10.20.30.40" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
if grep "auth zone rpz.example.com. details" unbound.log; then
echo "OK"
else
echo "not OK"
exit 1
fi
# wait_logfile
wait_logfile unbound.log "write zonefile auth_load_ixfr.zone for rpz.example.com." 10
echo ""
echo "> auth_load_ixfr.zone"
cat auth_load_ixfr.zone
exit 0
+36
View File
@@ -0,0 +1,36 @@
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN SOA
SECTION ANSWER
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN IXFR
SECTION ANSWER
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
www.example.com.rpz.example.com. IN A 1.2.3.4
other.example.com.rpz.example.com. IN A 1.2.3.5
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600
www.example.com.rpz.example.com. IN A 1.2.3.5
o3.example.com.rpz.example.com. IN A 1.2.3.7
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 2 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR RD RA NOERROR
SECTION QUESTION
other.example.com. IN A
SECTION ANSWER
other.example.com. IN A 10.20.30.40
ENTRY_END
+9
View File
@@ -0,0 +1,9 @@
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
rpz.example.com. IN NS ns.example.net.
www.example.com.rpz.example.com. IN A 1.2.3.4
other.example.com.rpz.example.com. IN A 1.2.3.5
o2.example.com.rpz.example.com. IN A 1.2.3.6
n.example.com.rpz.example.com IN CNAME .
32.5.5.0.192.rpz-client-ip.rpz.example.com. A 1.2.3.5
32.123.2.0.192.rpz-ip.rpz.example.com. A 203.0.113.123
32.124.2.0.192.rpz-ip.rpz.example.com. CNAME .
+103
View File
@@ -0,0 +1,103 @@
server:
verbosity: 8
num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 2
auth-zone:
name: "example1.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example2.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example3.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example4.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example5.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example6.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example7.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example8.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example9.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example10.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example11.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example12.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example13.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example14.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
auth-zone:
name: "example15.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load_list
Version: 1.0
Description: Perform more transfers than the auth load thread count
CreationDate: Fri 9 Jul 15:00:00 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load_list.pre
Post: auth_load_list.post
Test: auth_load_list.test
AuxFiles:
Passed:
Failure:
+12
View File
@@ -0,0 +1,12 @@
# #-- auth_load_list.post --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# source the test var file when it's there
[ -f .tpkg.var.test ] && source .tpkg.var.test
#
# do your teardown here
. ../common.sh
kill_pid $FWD_PID
kill_pid $UNBOUND_PID
cat fwd.log
cat unbound.log
+74
View File
@@ -0,0 +1,74 @@
# #-- auth_load_list.pre--#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
# if no threads; exit
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
echo "have threads"
else
skip_test "no threads"
fi
get_random_port 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
# create auth_load_list.testns
for((i=1; i<16; i++)); do
cat >>auth_load_list.testns <<EOF
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example$i.com. IN SOA
SECTION ANSWER
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example$i.com. IN AXFR
SECTION ANSWER
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
example$i.com. IN NS ns.example.net.
EXTRA_PACKET
REPLY QR AA NOERROR
SECTION QUESTION
example$i.com. IN AXFR
SECTION ANSWER
www.example$i.com. IN A 1.2.3.4
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
ENTRY_END
EOF
done
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT auth_load_list.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < auth_load_list.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+60
View File
@@ -0,0 +1,60 @@
# #-- auth_load_list.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
# do the test
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15; do
name="www.example$i.com"
echo ""
echo "> dig $name"
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT $name | tee outfile
fi
echo "> check answer"
if grep "1.2.3.4" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
if grep "auth zone example$i.com. details" unbound.log; then
echo "OK"
else
echo "not OK"
exit 1
fi
done
echo "loop done"
exit 0
+26
View File
@@ -0,0 +1,26 @@
server:
verbosity: 8
# num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
module-config: "respip validator iterator"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 1
log-queries: yes
log-replies: yes
forward-zone:
name: "."
forward-addr: "127.0.0.1@@TOPORT@"
rpz:
name: "rpz.example.com"
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
rpz-log: yes
rpz-log-name: "rpz.example.com"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load_rpz
Version: 1.0
Description: Load RPZ zone with auth load thread
CreationDate: Tue 6 Oct 10:00:00 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load_rpz.pre
Post: auth_load_rpz.post
Test: auth_load_rpz.test
AuxFiles:
Passed:
Failure:
+12
View File
@@ -0,0 +1,12 @@
# #-- auth_load_rpz.post --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# source the test var file when it's there
[ -f .tpkg.var.test ] && source .tpkg.var.test
#
# do your teardown here
. ../common.sh
kill_pid $FWD_PID
kill_pid $UNBOUND_PID
cat fwd.log
cat unbound.log
+39
View File
@@ -0,0 +1,39 @@
# #-- auth_load_rpz.pre--#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
# if no threads; exit
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
echo "have threads"
else
skip_test "no threads"
fi
get_random_port 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
# start forwarder
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT auth_load_rpz.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' -e 's/@TOPORT\@/'$FWD_PORT'/' < auth_load_rpz.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+56
View File
@@ -0,0 +1,56 @@
# #-- auth_load_rpz.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
# do the test
# The answer is rewritten by RPZ, that is loaded in the auth load thread.
echo "> dig www.example.com."
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
if grep SERVFAIL outfile; then
echo "> try again"
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 1
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
if grep SERVFAIL outfile; then
echo "> try again"
sleep 3
dig @127.0.0.1 -p $UNBOUND_PORT www.example.com. | tee outfile
fi
echo "> check answer"
if grep "1.2.3.4" outfile; then
echo "OK"
else
echo "Not OK"
exit 1
fi
if grep "auth zone rpz.example.com. details" unbound.log; then
echo "OK"
else
echo "not OK"
exit 1
fi
exit 0
+22
View File
@@ -0,0 +1,22 @@
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN SOA
SECTION ANSWER
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
rpz.example.com. IN AXFR
SECTION ANSWER
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
rpz.example.com. IN NS ns.example.net.
www.example.com.rpz.example.com. IN A 1.2.3.4
rpz.example.com. IN SOA ns.example.com. hostmaster.example.com. 1 3600 900 86400 3600
ENTRY_END
+21
View File
@@ -0,0 +1,21 @@
server:
verbosity: 8
num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 2
log-time-ascii: yes
log-time-iso: yes
remote-control:
control-enable: yes
control-interface: @CONTROL_PATH@/controlpipe.@CONTROL_PID@
control-use-cert: no
include: "auth.zonelist"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load_tree
Version: 1.0
Description: Exercise the auth load thread tree in the worker
CreationDate: Thu 15 Oct 09:00:00 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load_tree.pre
Post: auth_load_tree.post
Test: auth_load_tree.test
AuxFiles:
Passed:
Failure:
+13
View File
@@ -0,0 +1,13 @@
# #-- auth_load_tree.post --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# source the test var file when it's there
[ -f .tpkg.var.test ] && source .tpkg.var.test
#
# do your teardown here
. ../common.sh
kill_pid $UNBOUND_PID
kill_pid $FWD_PID
rm -f $CONTROL_PATH/controlpipe.$CONTROL_PID
cat fwd.log
cat unbound.log
+108
View File
@@ -0,0 +1,108 @@
# #-- auth_load_tree.pre--#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
# if no threads; exit
if grep -e "define HAVE_PTHREAD 1" -e "define HAVE_SOLARIS_THREADS 1" -e "define HAVE_WINDOWS_THREADS 1" $PRE/config.h; then
echo "have threads"
else
skip_test "no threads"
fi
get_random_port 2
UNBOUND_PORT=$RND_PORT
FWD_PORT=$(($RND_PORT + 1))
echo "UNBOUND_PORT=$UNBOUND_PORT" >> .tpkg.var.test
echo "FWD_PORT=$FWD_PORT" >> .tpkg.var.test
NUM_AUTH=120
echo "NUM_AUTH=$NUM_AUTH" >> .tpkg.var.test
echo "" > auth.zonelist
# start forwarder
# create auth_load_tree.testns
for((i=1; i<=$NUM_AUTH; i++)); do
cat >>auth_load_tree.testns <<EOF
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example$i.com. IN SOA
SECTION ANSWER
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
ENTRY_END
ENTRY_BEGIN
MATCH opcode qtype qname
ADJUST copy_id
REPLY QR AA NOERROR
SECTION QUESTION
example$i.com. IN AXFR
SECTION ANSWER
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
example$i.com. IN NS ns.example.net.
EXTRA_PACKET
REPLY QR AA NOERROR
SECTION QUESTION
example$i.com. IN AXFR
SECTION ANSWER
www.example$i.com. IN A 1.2.3.4
h1.example$i.com. IN A 1.2.3.5
h2.example$i.com. IN A 1.2.3.5
h3.example$i.com. IN A 1.2.3.5
h4.example$i.com. IN A 1.2.3.5
h5.example$i.com. IN A 1.2.3.5
h6.example$i.com. IN A 1.2.3.5
h7.example$i.com. IN A 1.2.3.5
h8.example$i.com. IN A 1.2.3.5
h9.example$i.com. IN A 1.2.3.5
h10.example$i.com. IN A 1.2.3.5
h11.example$i.com. IN A 1.2.3.5
h12.example$i.com. IN A 1.2.3.5
h13.example$i.com. IN A 1.2.3.5
h14.example$i.com. IN A 1.2.3.5
h15.example$i.com. IN A 1.2.3.5
h16.example$i.com. IN A 1.2.3.5
example$i.com. IN SOA ns.example$i.com. hostmaster.example$i.com. 1 3600 900 86400 3600
ENTRY_END
EOF
cat >>auth.zonelist <<EOF
auth-zone:
name: "example$i.com"
for-upstream: yes
for-downstream: yes
master: "127.0.0.1@${FWD_PORT}@"
EOF
done
get_ldns_testns
$LDNS_TESTNS -p $FWD_PORT auth_load_tree.testns >fwd.log 2>&1 &
FWD_PID=$!
echo "FWD_PID=$FWD_PID" >> .tpkg.var.test
# make config file
CONTROL_PATH=/tmp
CONTROL_PID=$$
sed -e 's/@PORT\@/'$UNBOUND_PORT'/' \
-e 's/@TOPORT\@/'$FWD_PORT'/' \
-e 's?@CONTROL_PATH\@?'$CONTROL_PATH'?' \
-e 's/@CONTROL_PID@/'$CONTROL_PID'/' \
< auth_load_tree.conf > ub.conf
# start unbound in the background
$PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
#valgrind --leak-check=full --show-reachable=yes $PRE/unbound -d -c ub.conf >unbound.log 2>&1 &
UNBOUND_PID=$!
echo "UNBOUND_PID=$UNBOUND_PID" >> .tpkg.var.test
echo "CONTROL_PATH=$CONTROL_PATH" >> .tpkg.var.test
echo "CONTROL_PID=$CONTROL_PID" >> .tpkg.var.test
cat .tpkg.var.test
wait_ldns_testns_up fwd.log
wait_unbound_up unbound.log
+32
View File
@@ -0,0 +1,32 @@
# #-- auth_load_tree.test --#
# source the master var file when it's there
[ -f ../.tpkg.var.master ] && source ../.tpkg.var.master
# use .tpkg.var.test for in test variable passing
[ -f .tpkg.var.test ] && source .tpkg.var.test
PRE="../.."
. ../common.sh
# While the updates are in progress,
# perform:
# - reload
# - stop
# This exercises the auth load thread tree in the worker that keeps
# track of the connected auth load threads to the worker thread.
# do the test
echo "> unbound-control reload"
$PRE/unbound-control -c ub.conf reload
if test $? -ne 0; then
echo "wrong exit value."
exit 1
else
echo "exit value: OK"
fi
# wait enough to have the reload cause re-fetch to happen during the exit.
# for valgrind .4, without .04
#sleep .4
sleep 0.04
exit 0
+18
View File
@@ -0,0 +1,18 @@
diff --git a/services/authload.c b/services/authload.c
index 314d1d40b..b0c7336ea 100644
--- a/services/authload.c
+++ b/services/authload.c
@@ -709,6 +709,13 @@ auth_load_thread_process(struct auth_load_thread* thr)
if(gettimeofday(&start, NULL) < 0)
log_err("gettimeofday: %s", strerror(errno));
+ if(1) {
+ struct timespec dur;
+ dur.tv_sec = 1;
+ dur.tv_nsec = 500ULL * 1000000ULL;
+ nanosleep(&dur, NULL);
+ }
+
/* apply data */
if(task->task_type == AUTH_LOAD_TASK_ZONEFILE_WRITE) {
if(!auth_load_process_write(thr))
+27
View File
@@ -0,0 +1,27 @@
server:
verbosity: 8
# num-threads: 1
interface: 127.0.0.1
port: @PORT@
use-syslog: no
directory: ""
pidfile: "unbound.pid"
module-config: "respip validator iterator"
chroot: ""
username: ""
do-not-query-localhost: no
auth-task-threads: 1
log-queries: yes
log-replies: yes
forward-zone:
name: "."
forward-addr: "127.0.0.1@@TOPORT@"
rpz:
name: "rpz.example.com"
zonefile: "auth_load_write.zone"
for-downstream: yes
master: "127.0.0.1@@TOPORT@"
rpz-log: yes
rpz-log-name: "rpz.example.com"
+16
View File
@@ -0,0 +1,16 @@
BaseName: auth_load_write
Version: 1.0
Description: Write zonefile with auth load thread
CreationDate: Wed 7 Oct 10:00:00 CEST 2026
Maintainer: dr. W.C.A. Wijngaards
Category:
Component:
CmdDepends:
Depends:
Help:
Pre: auth_load_write.pre
Post: auth_load_write.post
Test: auth_load_write.test
AuxFiles:
Passed:
Failure:

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