Compare commits

..
Author SHA1 Message Date
Witold Kręcicki a28b46d60c WiP 2020-04-08 22:58:18 +02:00
Witold Kręcicki 2524abe0b7 Allow uvreq to not be bound to socket (e.g. for TCP connection initiation) 2020-04-03 12:41:01 +02:00
Witold Kręcicki 59bb3e9b72 Clean quota callback after calling it 2020-04-03 12:39:11 +02:00
Witold Kręcicki bb991c356f Redesigned TCP accepting: one listen/accept loop, passing the connected socket.
Instead of using bind() and passing the listening socket to the children
threads using uv_export/uv_import use one thread that does the accepting,
and then passes the connected socket using uv_export/uv_import to a random
worker. The previous solution had thundering herd problems (all workers
waking up on one connection and trying to accept()), this one avoids this
and is simpler.
The tcp clients quota is simplified with isc_quota_attach_cb - a callback
is issued when the quota is available.
2020-04-03 12:39:11 +02:00
Matthijs Mekking 663047ac8b Merge branch '1179-dnssec-stats-oom-kill' into 'master'
Resolve "OOM issue after upgrade from 9.14.3 to 9.14.4"

Closes #1179

See merge request isc-projects/bind9!3304
2020-04-03 07:59:11 +00:00
Matthijs Mekking 386890a161 Update release notes 2020-04-03 09:27:15 +02:00
Matthijs Mekking c1723b2535 Replace hard coded value with constant 2020-04-03 09:27:15 +02:00
Matthijs Mekking 1596d3b498 Merge if blocks in statschannel.c 2020-04-03 09:27:15 +02:00
Matthijs Mekking 44b49955e1 Replace sign operation bool with enum 2020-04-03 09:27:15 +02:00
Matthijs Mekking b2028e26da Embed algorithm in key tag counter
Key tags are not unique across algorithms.
2020-04-03 09:27:15 +02:00
Matthijs Mekking eb6a8b47d7 Group the keyid with the counters
Rather than group key ids together, group key id with its
corresponding counters. This should make growing / shrinking easier
than having keyids then counters.
2020-04-03 09:27:15 +02:00
Matthijs Mekking 31e8b2b13c Add test for many keys
Add a statschannel test case for DNSSEC sign metrics that has more
keys than there are allocated stats counters for.  This will produce
gibberish, but at least it should not crash.
2020-04-03 09:27:15 +02:00
Matthijs Mekking 705810d577 Redesign dnssec sign statistics
The first attempt to add DNSSEC sign statistics was naive: for each
zone we allocated 64K counters, twice.  In reality each zone has at
most four keys, so the new approach only has room for four keys per
zone. If after a rollover more keys have signed the zone, existing
keys are rotated out.

The DNSSEC sign statistics has three counters per key, so twelve
counters per zone. First counter is actually a key id, so it is
clear what key contributed to the metrics.  The second counter
tracks the number of generated signatures, and the third tracks
how many of those are refreshes.

This means that in the zone structure we no longer need two separate
references to DNSSEC sign metrics: both the resign and refresh stats
are kept in a single dns_stats structure.

Incrementing dnssecsignstats:

Whenever a dnssecsignstat is incremented, we look up the key id
to see if we already are counting metrics for this key.  If so,
we update the corresponding operation counter (resign or
refresh).

If the key is new, store the value in a new counter and increment
corresponding counter.

If all slots are full, we rotate the keys and overwrite the last
slot with the new key.

Dumping dnssecsignstats:

Dumping dnssecsignstats is no longer a simple wrapper around
isc_stats_dump, but uses the same principle.  The difference is that
rather than dumping the index (key tag) and counter, we have to look
up the corresponding counter.
2020-04-03 09:27:11 +02:00
Matthijs Mekking 157eb5cd30 Merge branch '1706-dnssec-policy-migration' into 'master'
Resolve "Changing from auto-dnssec maintain to dnssec-policy x immediately deletes existing keys"

Closes #1706

See merge request isc-projects/bind9!3322
2020-04-03 06:54:46 +00:00
Matthijs Mekking 551acb44f4 Test migration to dnssec-policy, change algorithm
Add a test to ensure migration from 'auto-dnssec maintain;' to
dnssec-policy works even if the algorithm is changed.  The existing
keys should not be removed immediately, but their goal should be
changed to become hidden, and the new keys with the different
algorithm should be introduced immediately.
2020-04-03 08:29:22 +02:00
Matthijs Mekking 2389fcb4dc Only initialize goal on active keys
If we initialize goals on all keys, superfluous keys that match
the policy all desire to be active.  For example, there are six
keys available for a policy that needs just two, we only want to
set the goal state to OMNIPRESENT on two keys, not six.
2020-04-03 08:29:22 +02:00
Matthijs Mekking f47e697da3 Update documentation with !1706 fix 2020-04-03 08:29:22 +02:00
Matthijs Mekking 7f43520893 Test migration to dnssec-policy, retire old keys
Migrating from 'auto-dnssec maintain;' to dnssec-policy did not
work properly, mainly because the legacy keys were initialized
badly.  Earlier commit deals with migration where existing keys
match the policy.  This commit deals with migration where existing
keys do not match the policy.  In that case, named must not
immediately delete the existing keys, but gracefully roll to the
dnssec-policy.

However, named did remove the existing keys immediately.  This is
because the legacy key states were initialized badly.  Because
those keys had their states initialized to HIDDEN or RUMOURED, the
keymgr decides that they can be removed (because only when the key
has its states in OMNIPRESENT it can be used safely).

The original thought to initialize key states to HIDDEN (and
RUMOURED to deal with existing keys) was to ensure that those keys
will go through the required propagation time before the keymgr
decides they can be used safely.  However, those keys are already
in the zone for a long time and making the key states represent
otherwise is dangerous: keys may be pulled out of the zone while
in fact they are required to establish the chain of trust.

Fix initializing key states for existing keys by looking more closely
at the time metadata.  Add TTL and propagation delays to the time
metadata and see if the DNSSEC records have been propagated.
Initialize the state to OMNIPRESENT if so, otherwise initialize to
RUMOURED.  If the time metadata is in the future, or does not exist,
keep initializing the state to HIDDEN.

The added test makes sure that new keys matching the policy are
introduced, but existing keys are kept in the zone until the new
keys have been propagated.
2020-04-03 08:29:22 +02:00
Matthijs Mekking a224754d59 Tweak kasp system test
A few kasp system test tweaks to improve test failure debugging and
deal with tests related to migration to dnssec-policy.

1. When clearing a key, set lifetime to "none".  If "none", skip
   expect no lifetime set in the state file.  Legacy keys that
   are migrated but don't match the dnssec-policy will not have a
   lifetime.

2. The kasp system test prints which key id and file it is checking.
   Log explicitly if we are checking the id or a file.

3. Add quotes around "ID" when setting the key id, for consistency.

4. Fix a typo (non -> none).

5. Print which key ids are found, this way it is easier to see what
   KEY[1-4] failed to match one of the key files.
2020-04-03 08:29:22 +02:00
Matthijs Mekking 6801899134 Fix and test migration to dnssec-policy
Migrating from 'auto-dnssec maintain;' to dnssec-policy did not
work properly, mainly because the legacy keys were initialized
badly. Several adjustments in the keymgr are required to get it right:

- Set published time on keys when we calculate prepublication time.
  This is not strictly necessary, but it is weird to have an active
  key without the published time set.

- Initalize key states also before matching keys. Determine the
  target state by looking at existing time metadata: If the time
  data is set and is in the past, it is a hint that the key and
  its corresponding records have been published in the zone already,
  and the state is initialized to RUMOURED. Otherwise, initialize it
  as HIDDEN. This fixes migration to dnssec-policy from existing
  keys.

- Initialize key goal on keys that match key policy to OMNIPRESENT.
  These may be existing legacy keys that are being migrated.

- A key that has its goal to OMNIPRESENT *or* an active key can
  match a kasp key.  The code was changed with CHANGE 5354 that
  was a bugfix to prevent creating new KSK keys for zones in the
  initial stage of signing.  However, this caused problems for
  restarts when rollovers are in progress, because an outroducing
  key can still be an active key.

The test for this introduces a new KEY property 'legacy'.  This is
used to skip tests related to .state files.
2020-04-03 08:29:22 +02:00
Ondřej Surý 49b42e7fcc Merge branch '1717-rwlock-contention-in-isc_log_wouldlog-api-performance-impact' into 'master'
Reduce rwlock contention in isc_log_wouldlog()

Closes #1717

See merge request isc-projects/bind9!3321
2020-04-03 05:01:33 +00:00
Ondřej SurýandOndřej Surý 3a24eacbb6 Reduce rwlock contention in isc_log_wouldlog()
The rwlock introduced to protect the .logconfig member of isc_log_t
structure caused a significant performance drop because of the rwlock
contention.  It was also found, that the debug_level member of said
structure was not protected from concurrent read/writes.

The .dynamic and .highest_level members of isc_logconfig_t structure
were actually just cached values pulled from the assigned channels.

We introduced an even higher cache level for .dynamic and .highest_level
members directly into the isc_log_t structure, so we don't have to
access the .logconfig member in the isc_log_wouldlog() function.
2020-04-02 11:23:16 +02:00
Evan Hunt 8e74974ce1 Merge branch '1447-incremental-rpz-update' into 'master'
incrementally clean up old RPZ records during updates

Closes #1447

See merge request isc-projects/bind9!3318
2020-04-01 03:38:31 +00:00
Evan Hunt 899f9440c0 CHANGES and release note 2020-03-31 19:41:41 -07:00
Evan Hunt 32da119ed8 incrementally clean up old RPZ records during updates
After an RPZ zone is updated via zone transfer, the RPZ summary
database is updated, inserting the newly added names in the policy
zone and deleting the newly removed ones. The first part of this
was quantized so it would not run too long and starve other tasks
during large updates, but the second part was not quantized, so
that an update in which a large number of records were deleted
could cause named to become briefly unresponsive.
2020-03-31 19:41:41 -07:00
Mark Andrews 0c350fbcb7 Merge branch 'marka-empty-release-notes' into 'master'
add empty release notes for 9.17.1

See merge request isc-projects/bind9!3313
2020-03-31 03:31:38 +00:00
Mark Andrews 503e2dff64 add empty release notes for 9.17.1 2020-03-31 14:10:49 +11:00
Witold Krecicki d02a58adc0 Merge branch '1700-proper-tcp-resuming' into 'master'
Deactivate the handle before sending the async close callback.

Closes #1700

See merge request isc-projects/bind9!3303
2020-03-30 10:27:01 +00:00
Witold Kręcicki 01c4c3301e Deactivate the handle before sending the async close callback.
We could have a race between handle closing and processing async
callback. Deactivate the handle before issuing the callback - we
have the socket referenced anyway so it's not a problem.
2020-03-30 10:26:05 +02:00
Witold Krecicki 2df610a882 Merge branch 'wpk/quota-callback' into 'master'
isc_quota_attach_cb - quota attach function with a callback.

See merge request isc-projects/bind9!3280
2020-03-30 08:17:31 +00:00
Witold Kręcicki d151a10f30 Add a quota attach function with a callback, some code cleanups.
We introduce a isc_quota_attach_cb function - if ISC_R_QUOTA is returned
at the time the function is called, then a callback will be called when
there's quota available (with quota already attached). The callbacks are
organized as a LIFO queue in the quota structure.
It's needed for TCP client quota -  with old networking code we had one
single place where tcp clients quota was processed so we could resume
accepting when the we had spare slots, but it's gone with netmgr - now
we need to notify the listener/accepter that there's quota available so
that it can resume accepting.

Remove unused isc_quota_force() function.

The isc_quote_reserve and isc_quota_release were used only internally
from the quota.c and the tests.  We should not expose API we are not
using.
2020-03-30 07:43:10 +00:00
Mark Andrews 5826c85a22 Merge branch '1678-bind-fails-to-build-with-mysql-support-against-mysql8-mysql-connector-8' into 'master'
Resolve "BIND fails to build with MYSQL support against mysql8/mysql-connector-8"

Closes #1678

See merge request isc-projects/bind9!3235
2020-03-26 22:03:11 +00:00
Ondřej SurýandMark Andrews 715b7a7cec Use compound literals in mysql_options() call
Makes use of compound literals instead of using extra my_bool
variable just to hold "true/1" value.
2020-03-26 20:36:43 +00:00
Mark Andrews c6d5d5c88f Typedef my_bool if missing.
ORACLE MySQL 8.0 has dropped the my_bool type, so we need to reinstate
it back when compiling with that version or higher.  MariaDB is still
keeping the my_bool type.  The numbering between the two (MariaDB 5.x
jumped to MariaDB 10.x) doesn't make the life of the developer easy.
2020-03-26 20:36:43 +00:00
Mark Andrews 7af9883b48 remove unused variable 2020-03-26 20:36:43 +00:00
Michał Kępień 3377bc4b02 Merge branch 'michal/misc-gitlab-ci-yml-cleanups' into 'master'
Miscellaneous .gitlab-ci.yml cleanups

See merge request isc-projects/bind9!3298
2020-03-26 10:40:13 +00:00
Michał Kępień 3d121ede6c Remove unused YAML anchors
Some YAML anchors defined in .gitlab-ci.yml are not subsequently used.
Remove them to prevent confusion.
2020-03-26 11:03:52 +01:00
Michał Kępień 3d264dbe81 Do not install compiledb in cppcheck job
compiledb is already included in the Docker image used by the cppcheck
job.  Do not attempt installing it again.
2020-03-26 11:03:52 +01:00
Michał Kępień 0c898084cd Include compiler name in all build/test job names
Most build/test job names already contain a "clang", "gcc", or "msvc"
prefix which indicates the compiler used for a given job.  Apply that
naming convention to all build/test job names.
2020-03-26 11:03:52 +01:00
Michał Kępień 84463f33bf Refactor TSAN unit test job definitions
Multiple YAML keys have identical values for both TSAN unit test job
definitions.  Extract these common keys to a YAML anchor and use it in
TSAN unit test job definitions to reduce code duplication.
2020-03-26 11:03:52 +01:00
Michał Kępień 6ebce9425e Run "kyua report-html" for TSAN unit test jobs
Definitions of jobs running unit tests under TSAN contain an
"after_script" YAML key.  Since the "unit_test_job" anchor is included
in those job definitions before "after_script" is defined, the
job-specific value of that key overrides the one defined in the included
anchor.  This prevents "kyua report-html" from being run for TSAN unit
test jobs.  Moving the invocation of "kyua report-html" to the "script"
key in the "unit_test_job" anchor is not acceptable as it would cause
the exit code of that command to determine the result of all unit test
jobs and we need that to be the exit code of "make unit".  Instead, add
"kyua report-html" invocations to the "after_script" key of TSAN unit
test job definitions to address the problem without affecting other job
definitions.
2020-03-26 11:03:52 +01:00
Michał Kępień a9aa295f1f Refactor TSAN system test job definitions
Multiple YAML keys have identical values for both TSAN system test job
definitions.  Extract these common keys to a YAML anchor and use it in
TSAN system test job definitions to reduce code duplication.
2020-03-26 11:03:52 +01:00
Michał Kępień 8ef01c7b50 Drop "before_script" key from TSAN job definitions
Both "system_test_job" and "unit_test_job" YAML anchors contain a
"before_script" key.  TSAN job definitions first specify their own value
of the "before_script" key and then include the aforementioned YAML
anchors, which results in the value of the "before_script" key being
overridden with the value specified by the included anchor.  Given this,
remove "before_script" definitions specific to TSAN jobs as they serve
no practical purpose.
2020-03-26 11:03:52 +01:00
Michał Kępień 6325c0993a Define TSAN options in a global variable
All assignments for the TSAN_OPTIONS variable are identical across the
entire .gitlab-ci.yml file.  Define a global TSAN_OPTIONS_COMMON
variable and use it in job definitions to reduce code duplication.
2020-03-26 11:03:52 +01:00
Ondřej Surý 4167eba3c3 Merge branch '1679-fix-the-typecase-to-isc_stdtime_get' into 'master'
Correct the typecast of .tv_sec in isc_stdtime_get()

Closes #1679

See merge request isc-projects/bind9!3294
2020-03-25 21:31:34 +00:00
Ondřej Surý 7c8179c503 Correct the typecast of .tv_sec in isc_stdtime_get() 2020-03-25 22:08:50 +01:00
Ondřej Surý 03727c1462 Merge branch '1679-fix-the-tv_nsec_check' into 'master'
Fix the tv_nsec check in isc_stdtime_get()

Closes #1679

See merge request isc-projects/bind9!3292
2020-03-25 19:28:59 +00:00
Ondřej Surý 0d06a62dd1 Fix the tv_nsec check in isc_stdtime_get() 2020-03-25 19:06:50 +01:00
Ondřej Surý 4154677f2e Merge branch 'ondrej/no-clang-on-debian-sid' into 'master'
Rewrite .gitlab-ci.yml to have 'base_image' and other GitLab CI improvements

See merge request isc-projects/bind9!3279
2020-03-25 17:05:27 +00:00
Ondřej Surý 281531d82b Replace clang:stretch:amd64 build with clang:buster:amd64 build (+ add missing system test) 2020-03-25 18:04:24 +01:00
Ondřej Surý ec72d1100d Replace bear with compiledb and drop MAKE_COMMAND because we don't need it 2020-03-25 18:04:24 +01:00
Ondřej Surý 5f5721aa11 Adjust the GitLab CI jobs to match the new images
The custom builds (oot, asan, tsan) were mostly built using Debian sid
amd64 image.  The problem was that this image broke too easily, because
it's Debian "unstable" after all.

This commit introduces "base_image" that should be most stable with
extra bits on top (clang, coccinelle, cppcheck, ...).  Currently, that
would be Debian buster amd64.

Other changes introduced by this commit:

* Change the default clang version to 10
* Run both ASAN and TSAN with both gcc and clang compilers
* Remove Clang Debian stretch i386 job
2020-03-25 18:04:24 +01:00
Ondřej Surý d07c3d6c8c Merge branch 'ondrej/scan-build-10-fixes' into 'master'
Fix new warnings reported by scan-build from LLVM/Clang 10

See merge request isc-projects/bind9!3285
2020-03-25 17:02:55 +00:00
Ondřej Surý ddd0d356e5 Fix 'Dereference of null pointer' from scan-build-10
These are mostly false positives, the clang-analyzer FAQ[1] specifies
why and how to fix it:

> The reason the analyzer often thinks that a pointer can be null is
> because the preceding code checked compared it against null. So if you
> are absolutely sure that it cannot be null, remove the preceding check
> and, preferably, add an assertion as well.

The 4 warnings reported are:

dnssec-cds.c:781:4: warning: Access to field 'base' results in a dereference of a null pointer (loaded from variable 'buf')
                        isc_buffer_availableregion(buf, &r);
                        ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/builds/isc-projects/bind9/lib/isc/include/isc/buffer.h:996:36: note: expanded from macro 'isc_buffer_availableregion'
                                   ^
/builds/isc-projects/bind9/lib/isc/include/isc/buffer.h:821:16: note: expanded from macro 'ISC__BUFFER_AVAILABLEREGION'
                (_r)->base = isc_buffer_used(_b);              \
                             ^~~~~~~~~~~~~~~~~~~
/builds/isc-projects/bind9/lib/isc/include/isc/buffer.h:152:29: note: expanded from macro 'isc_buffer_used'
        ((void *)((unsigned char *)(b)->base + (b)->used)) /*d*/
                                   ^~~~~~~~~
1 warning generated.

--

byname_test.c:308:34: warning: Access to field 'fwdtable' results in a dereference of a null pointer (loaded from variable 'view')
                RUNTIME_CHECK(dns_fwdtable_add(view->fwdtable, dns_rootname,
                                               ^~~~~~~~~~~~~~
/builds/isc-projects/bind9/lib/isc/include/isc/util.h:318:52: note: expanded from macro 'RUNTIME_CHECK'
                                                   ^~~~
/builds/isc-projects/bind9/lib/isc/include/isc/error.h:50:21: note: expanded from macro 'ISC_ERROR_RUNTIMECHECK'
        ((void)(ISC_LIKELY(cond) ||  \
                           ^~~~
/builds/isc-projects/bind9/lib/isc/include/isc/likely.h:23:43: note: expanded from macro 'ISC_LIKELY'
                                            ^
1 warning generated.

--

./rndc.c:255:6: warning: Dereference of null pointer (loaded from variable 'host')
        if (*host == '/') {
            ^~~~~
1 warning generated.

--

./main.c:1254:9: warning: Access to field 'sctx' results in a dereference of a null pointer (loaded from variable 'named_g_server')
        sctx = named_g_server->sctx;
               ^~~~~~~~~~~~~~~~~~~~
1 warning generated.

References:
1. https://clang-analyzer.llvm.org/faq.html#null_pointer
2020-03-25 17:33:22 +01:00
Ondřej Surý 262f087bcf Fix 'Dead nested assignment's from scan-build-10
The 3 warnings reported are:

os.c:872:7: warning: Although the value stored to 'ptr' is used in the enclosing expression, the value is never actually read from 'ptr'
        if ((ptr = strtok_r(command, " \t", &last)) == NULL) {
             ^     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
1 warning generated.

--

rpz.c:1117:10: warning: Although the value stored to 'zbits' is used in the enclosing expression, the value is never actually read from 'zbits'
        return (zbits &= x);
                ^        ~
1 warning generated.

--

openssleddsa_link.c:532:10: warning: Although the value stored to 'err' is used in the enclosing expression, the value is never actually read from 'err'
        while ((err = ERR_get_error()) != 0) {
                ^     ~~~~~~~~~~~~~~~
1 warning generated.
2020-03-25 17:33:07 +01:00
Witold Krecicki ec9f80cabc Merge branch 'wpk/tcpdns-refactoring' into 'master'
netmgr refactoring: use generic functions when operating on sockets.

See merge request isc-projects/bind9!3269
2020-03-24 20:57:21 +00:00
Witold Kręcicki 5fedd21e16 netmgr refactoring: use generic functions when operating on sockets.
tcpdns used transport-specific functions to operate on the outer socket.
Use generic ones instead, and select the proper call in netmgr.c.
Make the missing functions (e.g. isc_nm_read) generic and add type-specific
calls (isc__nm_tcp_read). This is the preparation for netmgr TLS layer.
2020-03-24 20:31:43 +00:00
53 changed files with 2451 additions and 1081 deletions
+217 -203
View File
@@ -15,11 +15,10 @@ variables:
BUILD_PARALLEL_JOBS: 6
TEST_PARALLEL_JOBS: 6
MAKE_COMMAND: make
CONFIGURE: ./configure
CLANG: clang-9
SCAN_BUILD: scan-build-9
SYMBOLIZER: /usr/lib/llvm-9/bin/llvm-symbolizer
CLANG: clang-10
SCAN_BUILD: scan-build-10
SYMBOLIZER: /usr/lib/llvm-10/bin/llvm-symbolizer
ASAN_SYMBOLIZER_PATH: "$SYMBOLIZER"
CLANG_FORMAT: clang-format-10
@@ -27,6 +26,7 @@ variables:
# Pass run-time flags to AddressSanitizer to get core dumps on error.
ASAN_OPTIONS_COMMON: abort_on_error=1:disable_coredump=0:unmap_shadow_on_exit=1
TSAN_OPTIONS_COMMON: "second_deadlock_stack=1 history_size=7 log_exe_name=true log_path=tsan external_symbolizer_path=$SYMBOLIZER"
TARBALL_COMPRESSOR: xz
TARBALL_EXTENSION: xz
@@ -98,10 +98,6 @@ stages:
image: "$CI_REGISTRY_IMAGE:debian-stretch-amd64"
<<: *linux_amd64
.debian-stretch-i386: &debian_stretch_i386_image
image: "$CI_REGISTRY_IMAGE:debian-stretch-i386"
<<: *linux_i386
.debian-buster-amd64: &debian_buster_amd64_image
image: "$CI_REGISTRY_IMAGE:debian-buster-amd64"
<<: *linux_amd64
@@ -136,17 +132,15 @@ stages:
image: "$CI_REGISTRY_IMAGE:ubuntu-xenial-amd64"
<<: *linux_amd64
.ubuntu-xenial-i386: &ubuntu_xenial_i386_image
image: "$CI_REGISTRY_IMAGE:ubuntu-xenial-i386"
<<: *linux_i386
.ubuntu-bionic-amd64: &ubuntu_bionic_amd64_image
image: "$CI_REGISTRY_IMAGE:ubuntu-bionic-amd64"
<<: *linux_amd64
.ubuntu-bionic-i386: &ubuntu_bionic_i386_image
image: "$CI_REGISTRY_IMAGE:ubuntu-bionic-i386"
<<: *linux_i386
# Base image
# This is a meta image that is used as a base for non-specific jobs
.base: &base_image
<<: *debian_buster_amd64_image
### Job Templates
@@ -168,12 +162,12 @@ stages:
.precheck: &precheck_job
<<: *default_triggering_rules
<<: *debian_sid_amd64_image
<<: *base_image
stage: precheck
.autoconf: &autoconf_job
<<: *release_branch_triggering_rules
<<: *debian_sid_amd64_image
<<: *base_image
stage: precheck
script:
- autoreconf -fi
@@ -203,11 +197,11 @@ stages:
- test -n "${OOT_BUILD_WORKSPACE}" && mkdir "${OOT_BUILD_WORKSPACE}" && cd "${OOT_BUILD_WORKSPACE}"
script:
- *configure
- ${MAKE_COMMAND} -j${BUILD_PARALLEL_JOBS:-1} -k all V=1
- make -j${BUILD_PARALLEL_JOBS:-1} -k all V=1
- test -z "${RUN_MAKE_INSTALL}" || make install
- test -z "${RUN_MAKE_INSTALL}" || sh util/check-make-install
needs:
- job: autoreconf:sid:amd64
- job: autoreconf
artifacts: true
artifacts:
untracked: true
@@ -237,7 +231,7 @@ stages:
- 'Set-Item -path "Env:CL" -value "/MP$([Math]::Truncate($BUILD_PARALLEL_JOBS/2))"'
- '& msbuild.exe /maxCpuCount:2 /t:Build /p:Configuration=$VSCONF bind9.sln'
needs:
- job: autoreconf:sid:amd64
- job: autoreconf
artifacts: false
artifacts:
untracked: true
@@ -254,7 +248,7 @@ stages:
export SLOT=$(sh -x bin/tests/prepare-softhsm2.sh)
test -n "${SLOT}" && test "${SLOT}" -gt 0
.system_test: &system_test_job
.system_test_common: &system_test_common
<<: *default_triggering_rules
stage: system
before_script:
@@ -263,11 +257,27 @@ stages:
script:
- ( cd bin/tests/system && make -j${TEST_PARALLEL_JOBS:-1} -k test V=1 )
- test -s bin/tests/system/systests.output
.system_test: &system_test_job
<<: *system_test_common
artifacts:
untracked: true
expire_in: "1 day"
when: on_failure
.system_test_tsan: &system_test_tsan_job
<<: *system_test_common
allow_failure: true
after_script:
- find bin -name 'tsan.*' -exec python3 util/parse_tsan.py {} \;
artifacts:
expire_in: "1 day"
paths:
- bin/tests/system/*/tsan.*
- bin/tests/system/*/*/tsan.*
- tsan/
when: on_failure
.kyua_report: &kyua_report_html |
kyua --logfile /dev/null report-html \
--force \
@@ -299,7 +309,7 @@ stages:
- tags
- web
.unit_test: &unit_test_job
.unit_test_common: &unit_test_common
<<: *default_triggering_rules
stage: unit
before_script:
@@ -308,40 +318,45 @@ stages:
- make unit
after_script:
- *kyua_report_html
.unit_test: &unit_test_job
<<: *unit_test_common
artifacts:
untracked: true
expire_in: "1 day"
when: on_failure
.unit_test_tsan: &unit_test_tsan_job
<<: *unit_test_common
allow_failure: true
after_script:
- *kyua_report_html
- find lib -name 'tsan.*' -exec python3 util/parse_tsan.py {} \;
artifacts:
expire_in: "1 day"
paths:
- lib/*/tests/tsan.*
- tsan/
- kyua.log
- kyua.results
- kyua_html/
when: on_failure
.cppcheck_args: &run_cppcheck |
cppcheck --enable=warning,performance,portability,information,missingInclude \
--include=config.h \
--quiet \
--std=c11 \
--language=c \
--project=compile_commands.json \
--error-exitcode=2 \
-j ${TEST_PARALLEL_JOBS:-1} \
--xml \
--output-file=cppcheck.results \
--relative-paths="$CI_PROJECT_DIR" \
--inline-suppr \
--suppressions-list=util/suppressions.txt
cppcheck --enable=warning,performance,portability,information,missingInclude --include=config.h --std=c11 --language=c --project=compile_commands.json --error-exitcode=2 -j ${TEST_PARALLEL_JOBS:-1} --xml --output-file=cppcheck.results --relative-paths="$CI_PROJECT_DIR" --inline-suppr --suppressions-list=util/suppressions.txt
.cppcheck_report: &cppcheck_report_html |
cppcheck-htmlreport --title="BIND 9 ($CI_COMMIT_SHORT_SHA) Cppcheck Report" \
--file=cppcheck.results \
--report-dir=cppcheck_html/
cppcheck-htmlreport --title="BIND 9 ($CI_COMMIT_SHORT_SHA) Cppcheck Report" --file=cppcheck.results --report-dir=cppcheck_html/
.cppcheck: &cppcheck_job
<<: *default_triggering_rules
stage: postcheck
before_script:
script:
- *configure
- (make -nwk all || true) | compiledb
- export GCC_VERSION=$(gcc --version | sed -n 's/.*\([0-9]\+\)\.[0-9]\+\.[0-9]\+.*/\1/p')
- sed -i "/gcc\",/a\"-DCPPCHECK\", \"-D__STDC__\", \"-D__GNUC__=${GCC_VERSION}\"," compile_commands.json
script:
- *run_cppcheck
after_script:
- *cppcheck_report_html
artifacts:
paths:
@@ -350,15 +365,18 @@ stages:
- cppcheck_html/
expire_in: "1 day"
when: on_failure
needs:
- job: autoreconf
artifacts: true
### Job Definitions
# Jobs in the precheck stage
autoreconf:sid:amd64:
autoreconf:
<<: *autoconf_job
misc:sid:amd64:
misc:
<<: *precheck_job
script:
- sh util/check-ans-prereq.sh
@@ -386,24 +404,23 @@ misc:sid:amd64:
expire_in: "1 day"
when: on_failure
💾:sid:amd64:
clang-format:
<<: *precheck_job
needs: []
script:
- if [ -r .clang-format ]; then "${CLANG_FORMAT}" -i -style=file $(git ls-files '*.c' '*.h'); fi
- if test "$(git status --porcelain | grep -Ev '\?\?' | wc -l)" -gt "0"; then git status --short; exit 1; fi
🐞:sid:amd64:
coccinelle:
<<: *precheck_job
<<: *debian_buster_amd64_image
needs: []
script:
- util/check-cocci
- if test "$(git status --porcelain | grep -Ev '\?\?' | wc -l)" -gt "0"; then git status --short; exit 1; fi
tarball-create:sid:amd64:
tarball-create:
stage: precheck
<<: *debian_sid_amd64_image
<<: *base_image
script:
- source version
- export BIND_DIRECTORY="bind-${MAJORVER}.${MINORVER}.${PATCHVER}${RELEASETYPE}${RELEASEVER}"
@@ -420,27 +437,27 @@ tarball-create:sid:amd64:
# Jobs for doc builds on Debian Sid (amd64)
docs:sid:amd64:
docs:
<<: *release_branch_triggering_rules
<<: *debian_sid_amd64_image
<<: *base_image
stage: docs
script:
- ./configure || cat config.log
- make -C doc/misc docbook
- make -C doc/arm Bv9ARM.html
needs:
- job: autoreconf:sid:amd64
- job: autoreconf
artifacts: true
artifacts:
paths:
- doc/arm/
expire_in: "1 month"
push:docs:sid:amd64:
<<: *debian_sid_amd64_image
push:docs:
<<: *base_image
stage: push
needs:
- job: docs:sid:amd64
- job: docs
artifacts: false
script:
- curl -X POST -F token=$GITLAB_PAGES_DOCS_TRIGGER_TOKEN -F ref=master $GITLAB_PAGES_DOCS_TRIGGER_URL
@@ -600,9 +617,9 @@ unit:gcc:buster:amd64:
-o scan-build.reports \
make -j${BUILD_PARALLEL_JOBS:-1} all V=1
scan-build:buster:amd64:
scan-build:
<<: *default_triggering_rules
<<: *debian_buster_amd64_image
<<: *base_image
stage: postcheck
variables:
CC: "${CLANG}"
@@ -613,7 +630,7 @@ scan-build:buster:amd64:
- *configure
- *scan_build
needs:
- job: autoreconf:sid:amd64
- job: autoreconf
artifacts: true
artifacts:
paths:
@@ -629,7 +646,6 @@ gcc:sid:amd64:
CFLAGS: "${CFLAGS_COMMON} -O3"
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2"
RUN_MAKE_INSTALL: 1
MAKE_COMMAND: bear --use-cc=${CC} --verbose make
<<: *debian_sid_amd64_image
<<: *build_job
@@ -647,64 +663,61 @@ unit:gcc:sid:amd64:
- job: gcc:sid:amd64
artifacts: true
cppcheck:gcc:sid:amd64:
<<: *debian_sid_amd64_image
cppcheck:
<<: *base_image
<<: *cppcheck_job
needs:
- job: gcc:sid:amd64
artifacts: true
# Job for out-of-tree GCC build on Debian Sid (amd64)
oot:sid:amd64:
gcc:out-of-tree:
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -O3"
CFLAGS: "${CFLAGS_COMMON} -Og"
CONFIGURE: ../configure
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2"
RUN_MAKE_INSTALL: 1
OOT_BUILD_WORKSPACE: workspace
<<: *debian_sid_amd64_image
<<: *base_image
<<: *build_job
# Jobs for tarball GCC builds on Debian Sid (amd64)
tarball:sid:amd64:
gcc:tarball:
variables:
CC: gcc
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2"
RUN_MAKE_INSTALL: 1
<<: *debian_sid_amd64_image
<<: *base_image
<<: *build_job
before_script:
- tar --extract --file bind-*.tar.${TARBALL_EXTENSION}
- rm -f bind-*.tar.${TARBALL_EXTENSION}
- cd bind-*
needs:
- job: tarball-create:sid:amd64
- job: tarball-create
artifacts: true
only:
- tags
system:tarball:sid:amd64:
<<: *debian_sid_amd64_image
system:gcc:tarball:
<<: *base_image
<<: *system_test_job
before_script:
- cd bind-*
- *setup_interfaces
needs:
- job: tarball:sid:amd64
- job: gcc:tarball
artifacts: true
only:
- tags
unit:tarball:sid:amd64:
<<: *debian_sid_amd64_image
unit:gcc:tarball:
<<: *base_image
<<: *unit_test_job
before_script:
- cd bind-*
needs:
- job: tarball:sid:amd64
- job: gcc:tarball
artifacts: true
only:
- tags
@@ -714,8 +727,8 @@ unit:tarball:sid:amd64:
gcc:sid:arm64:
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -O2"
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2"
CFLAGS: "${CFLAGS_COMMON} -Og"
EXTRA_CONFIGURE: "--with-libidn2"
<<: *debian_sid_arm64_image
<<: *build_job
@@ -739,7 +752,7 @@ gcc:sid:i386:
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON}"
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2 --without-python"
EXTRA_CONFIGURE: "--with-libidn2 --without-python"
<<: *debian_sid_i386_image
<<: *build_job
@@ -853,39 +866,93 @@ unit:gcc:bionic:amd64:
- job: gcc:bionic:amd64
artifacts: true
# Jobs for GCC builds with ASAN enabled on Debian Sid (amd64)
# Jobs for builds with ASAN enabled
asan:sid:amd64:
gcc:asan:
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0"
LDFLAGS: "-fsanitize=address,undefined"
EXTRA_CONFIGURE: "--with-libidn2"
<<: *debian_sid_amd64_image
<<: *base_image
<<: *build_job
system:asan:sid:amd64:
system:gcc:asan:
variables:
ASAN_OPTIONS: ${ASAN_OPTIONS_COMMON}
<<: *debian_sid_amd64_image
<<: *base_image
<<: *system_test_job
needs:
- job: asan:sid:amd64
- job: gcc:asan
artifacts: true
unit:asan:sid:amd64:
unit:gcc:asan:
variables:
ASAN_OPTIONS: ${ASAN_OPTIONS_COMMON}
<<: *debian_sid_amd64_image
<<: *base_image
<<: *unit_test_job
needs:
- job: asan:sid:amd64
- job: gcc:asan
artifacts: true
# Jobs for GCC builds with TSAN enabled on Debian Sid (amd64)
clang:asan:
variables:
CC: ${CLANG}
CFLAGS: "${CFLAGS_COMMON} -fsanitize=address,undefined -DISC_MEM_USE_INTERNAL_MALLOC=0"
LDFLAGS: "-fsanitize=address,undefined"
EXTRA_CONFIGURE: "--with-libidn2"
<<: *base_image
<<: *build_job
tsan:buster:amd64:
<<: *debian_buster_amd64_image
system:clang:asan:
variables:
ASAN_OPTIONS: ${ASAN_OPTIONS_COMMON}
<<: *base_image
<<: *system_test_job
needs:
- job: gcc:asan
artifacts: true
unit:clang:asan:
variables:
ASAN_OPTIONS: ${ASAN_OPTIONS_COMMON}
<<: *base_image
<<: *unit_test_job
needs:
- job: gcc:asan
artifacts: true
# Jobs for builds with TSAN enabled
gcc:tsan:
<<: *base_image
<<: *build_job
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -fsanitize=thread -DISC_MEM_USE_INTERNAL_MALLOC=0"
LDFLAGS: "-fsanitize=thread"
EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock"
system:gcc:tsan:
variables:
TSAN_OPTIONS: ${TSAN_OPTIONS_COMMON}
<<: *base_image
<<: *system_test_tsan_job
needs:
- job: gcc:tsan
artifacts: true
unit:gcc:tsan:
variables:
TSAN_OPTIONS: ${TSAN_OPTIONS_COMMON}
<<: *base_image
<<: *unit_test_tsan_job
needs:
- job: gcc:tsan
artifacts: true
clang:tsan:
<<: *base_image
<<: *build_job
variables:
CC: "${CLANG}"
@@ -893,146 +960,93 @@ tsan:buster:amd64:
LDFLAGS: "-fsanitize=thread"
EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock"
system:tsan:buster:amd64:
system:clang:tsan:
variables:
TSAN_OPTIONS: "second_deadlock_stack=1 history_size=7 log_exe_name=true log_path=tsan external_symbolizer_path=$SYMBOLIZER exitcode=0"
before_script:
- *setup_interfaces
- echo $TSAN_OPTIONS
<<: *debian_buster_amd64_image
<<: *system_test_job
TSAN_OPTIONS: ${TSAN_OPTIONS_COMMON}
<<: *base_image
<<: *system_test_tsan_job
needs:
- job: tsan:buster:amd64
artifacts: true
allow_failure: true
after_script:
- find bin -name 'tsan.*' -exec python3 util/parse_tsan.py {} \;
artifacts:
expire_in: "1 day"
paths:
- bin/tests/system/*/tsan.*
- bin/tests/system/*/*/tsan.*
- tsan/
when: on_failure
unit:tsan:buster:amd64:
variables:
TSAN_OPTIONS: "second_deadlock_stack=1 history_size=7 log_exe_name=true log_path=tsan external_symbolizer_path=$SYMBOLIZER"
before_script:
- echo $TSAN_OPTIONS
- lib/isc/tests/result_test
<<: *debian_buster_amd64_image
<<: *unit_test_job
needs:
- job: tsan:buster:amd64
artifacts: true
allow_failure: true
after_script:
- find lib -name 'tsan.*' -exec python3 util/parse_tsan.py {} \;
artifacts:
expire_in: "1 day"
paths:
- lib/*/tests/tsan.*
- tsan/
- kyua.log
- kyua.results
- kyua_html/
when: on_failure
rwlock:sid:amd64:
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -Wall -Wextra -O2 -g -DISC_MEM_USE_INTERNAL_MALLOC=0"
EXTRA_CONFIGURE: "--with-libidn2 --enable-pthread-rwlock"
<<: *debian_sid_amd64_image
<<: *build_job
system:rwlock:sid:amd64:
<<: *debian_sid_amd64_image
<<: *system_test_job
needs:
- job: rwlock:sid:amd64
- job: clang:tsan
artifacts: true
unit:rwlock:sid:amd64:
<<: *debian_sid_amd64_image
<<: *unit_test_job
unit:clang:tsan:
variables:
TSAN_OPTIONS: ${TSAN_OPTIONS_COMMON}
<<: *base_image
<<: *unit_test_tsan_job
needs:
- job: rwlock:sid:amd64
- job: clang:tsan
artifacts: true
# Jobs for mutex-based atomics on Debian SID (amd64)
mutexatomics:sid:amd64:
gcc:mutexatomics:
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -DISC_MEM_USE_INTERNAL_MALLOC=0"
EXTRA_CONFIGURE: "--with-libidn2 --enable-mutex-atomics"
<<: *debian_sid_amd64_image
<<: *base_image
<<: *build_job
system:mutexatomics:sid:amd64:
<<: *debian_sid_amd64_image
system:gcc:mutexatomics:
<<: *base_image
<<: *system_test_job
needs:
- job: mutexatomics:sid:amd64
- job: gcc:mutexatomics
artifacts: true
unit:mutexatomics:sid:amd64:
<<: *debian_sid_amd64_image
unit:gcc:mutexatomics:
<<: *base_image
<<: *unit_test_job
needs:
- job: mutexatomics:sid:amd64
- job: gcc:mutexatomics
artifacts: true
# Jobs for Clang builds on Debian Stretch (amd64)
# Jobs for Clang builds on Debian Buster (amd64)
clang:stretch:amd64:
clang:buster:amd64:
variables:
CC: clang
CC: ${CLANG}
CFLAGS: "${CFLAGS_COMMON} -Wenum-conversion"
EXTRA_CONFIGURE: "--with-python=python3"
<<: *debian_stretch_amd64_image
<<: *debian_buster_amd64_image
<<: *build_job
unit:clang:stretch:amd64:
<<: *debian_stretch_amd64_image
<<: *unit_test_job
system:clang:buster:amd64:
<<: *debian_buster_amd64_image
<<: *system_test_job
needs:
- job: clang:stretch:amd64
- job: clang:buster:amd64
artifacts: true
# Jobs for Clang builds on Debian Stretch (i386)
clang:stretch:i386:
variables:
CC: clang
CFLAGS: "${CFLAGS_COMMON} -Wenum-conversion"
EXTRA_CONFIGURE: "--with-python=python2"
<<: *debian_stretch_i386_image
<<: *build_job
unit:clang:buster:amd64:
<<: *debian_buster_amd64_image
<<: *unit_test_job
needs:
- job: clang:buster:amd64
artifacts: true
# Jobs for PKCS#11-enabled GCC builds on Debian Sid (amd64)
pkcs11:sid:amd64:
gcc:pkcs11:
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON}"
EXTRA_CONFIGURE: "--enable-native-pkcs11 --with-pkcs11=/usr/lib/softhsm/libsofthsm2.so"
<<: *debian_sid_amd64_image
<<: *base_image
<<: *build_job
system:pkcs11:sid:amd64:
<<: *debian_sid_amd64_image
system:gcc:pkcs11:
<<: *base_image
<<: *system_test_job
needs:
- job: pkcs11:sid:amd64
- job: gcc:pkcs11
artifacts: true
unit:pkcs11:sid:amd64:
<<: *debian_sid_amd64_image
unit:gcc:pkcs11:
<<: *base_image
<<: *unit_test_job
needs:
- job: pkcs11:sid:amd64
- job: gcc:pkcs11
artifacts: true
# Jobs for Clang builds on FreeBSD 11.3 (amd64)
@@ -1144,8 +1158,8 @@ system:msvc-debug:windows:amd64:
# Job producing a release tarball
release:sid:amd64:
<<: *debian_sid_amd64_image
release:
<<: *base_image
stage: release
script:
# Determine BIND version
@@ -1174,7 +1188,7 @@ release:sid:amd64:
# Create release tarball
- tar --create --file="${CI_COMMIT_TAG}.tar.gz" --gzip release/
needs:
- job: tarball-create:sid:amd64
- job: tarball-create
artifacts: true
- job: msvc:windows:amd64
artifacts: true
@@ -1215,19 +1229,19 @@ release:sid:amd64:
| tee curl-response.txt
grep -q 'Build successfully submitted' curl-response.txt
build:coverity:sid:amd64:
<<: *debian_sid_amd64_image
stage: build
coverity:
<<: *base_image
stage: postcheck
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -O3"
CFLAGS: "${CFLAGS_COMMON} -Og"
EXTRA_CONFIGURE: "--enable-dnstap --with-libidn2"
script:
- *coverity_cache_prep
- *configure
- *coverity_build
needs:
- job: autoreconf:sid:amd64
- job: autoreconf
artifacts: true
artifacts:
paths:
@@ -1247,26 +1261,26 @@ build:coverity:sid:amd64:
# Respdiff test
respdiff:sid:amd64:
<<: *debian_sid_amd64_image
respdiff:
<<: *base_image
stage: system
variables:
CC: gcc
CFLAGS: "${CFLAGS_COMMON} -O3"
CFLAGS: "${CFLAGS_COMMON} -Og"
BIND_BASELINE_VERSION: v9_11_3
script:
- ./configure --without-make-clean
- ${MAKE_COMMAND} -j${BUILD_PARALLEL_JOBS:-1} V=1
- make -j${BUILD_PARALLEL_JOBS:-1} V=1
- *setup_interfaces
- git clone --depth 1 https://gitlab-ci-token:${CI_JOB_TOKEN}@gitlab.isc.org/isc-private/bind-qa.git
- git clone --branch "${BIND_BASELINE_VERSION}" --depth 1 https://gitlab.isc.org/isc-projects/bind9.git refbind
- cd refbind/
- ./configure --without-make-clean
- ${MAKE_COMMAND} -j${BUILD_PARALLEL_JOBS:-1} V=1
- make -j${BUILD_PARALLEL_JOBS:-1} V=1
- cd ../bind-qa/bind9/respdiff
- bash respdiff.sh -q "${PWD}/100k_mixed.txt" -c 3 -w "${PWD}/rspworkdir" "${CI_PROJECT_DIR}/refbind" "${CI_PROJECT_DIR}"
needs:
- job: tarball-create:sid:amd64
- job: tarball-create
artifacts: true
only:
- tags
@@ -1279,11 +1293,11 @@ respdiff:sid:amd64:
# ABI check
abi-check:sid:amd64:
<<: *debian_sid_amd64_image
abi-check:
<<: *base_image
stage: build
needs:
- job: autoreconf:sid:amd64
- job: autoreconf
artifacts: true
variables:
CC: gcc
@@ -1291,11 +1305,11 @@ abi-check:sid:amd64:
BIND_BASELINE_VERSION: v9_17_0
script:
- *configure
- ${MAKE_COMMAND} -j${BUILD_PARALLEL_JOBS:-1} V=1
- make -j${BUILD_PARALLEL_JOBS:-1} V=1
- git clone --branch "${BIND_BASELINE_VERSION}" --depth 1 https://gitlab.isc.org/isc-projects/bind9.git refbind
- cd refbind/
- *configure
- ${MAKE_COMMAND} -j${BUILD_PARALLEL_JOBS:-1} V=1
- make -j${BUILD_PARALLEL_JOBS:-1} V=1
- cd ..
- util/api-checker.sh . refbind
artifacts:
+24
View File
@@ -1,3 +1,27 @@
5373. [bug] Collecting DNSSEC signing operations introduced by
GL #513 (change 5254) allocated counters for every
possible key id per zone which results in a lot of
wasted memory. Fix by tracking up to four keys
per zone, rotate counters when keys are replaced.
This fixes the immediate problem of the high
memory usage, but should be improved in a future
release by growing and shrinking the number of
keys to track triggered by key rollover events.
[GL #1179]
5372. [bug] Fix migration from existing DNSSEC key files using
auto-dnssec maintain to dnssec-policy. [GL #1706]
5371. [bug] Improve incremental updates of the RPZ summary
database to reduce delays that could occur when
a policy zone update included a large number of
record deletions. [GL #1447]
5370. [bug] Deactivation of a netmgr handle associated with a
socket could be skipped in some circumstances.
Fixed by deactivating the netmgr handle before
scheduling the asynchronous close routine. [GL #1700]
5369. [func] Add the ability to specify whether or not to wait
for nameserver domain names to be looked up, with
a new RPZ modifying directive 'nsdname-wait-recurse'.
+4
View File
@@ -754,6 +754,8 @@ ds_from_cds(dns_rdatalist_t *dslist, isc_buffer_t *buf, dns_rdata_t *cds) {
dns_rdata_ds_t ds;
dns_rdata_t *rdata;
REQUIRE(buf != NULL);
rdata = rdata_get();
result = dns_rdata_tostruct(cds, &ds, NULL);
@@ -772,6 +774,8 @@ ds_from_cdnskey(dns_rdatalist_t *dslist, isc_buffer_t *buf,
isc_result_t result;
unsigned i, n;
REQUIRE(buf != NULL);
n = sizeof(dtype) / sizeof(dtype[0]);
for (i = 0; i < n; i++) {
if (dtype[i] != 0) {
+1
View File
@@ -1251,6 +1251,7 @@ setup(void) {
#endif /* if CONTRIB_DLZ */
named_server_create(named_g_mctx, &named_g_server);
ENSURE(named_g_server != NULL);
sctx = named_g_server->sctx;
/*
+32 -36
View File
@@ -1814,7 +1814,6 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
isc_stats_t *gluecachestats;
dns_stats_t *rcvquerystats;
dns_stats_t *dnssecsignstats;
dns_stats_t *dnssecrefreshstats;
uint64_t nsstat_values[ns_statscounter_max];
uint64_t gluecachestats_values[dns_gluecachestatscounter_max];
@@ -1880,6 +1879,7 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
dnssecsignstats = dns_zone_getdnssecsignstats(zone);
if (dnssecsignstats != NULL) {
/* counters type="dnssec-sign"*/
TRY0(xmlTextWriterStartElement(writer,
ISC_XMLCHAR "counters"));
TRY0(xmlTextWriterWriteAttribute(
@@ -1887,19 +1887,17 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
ISC_XMLCHAR "dnssec-sign"));
dumparg.result = ISC_R_SUCCESS;
dns_dnssecsignstats_dump(dnssecsignstats,
dnssecsignstat_dump, &dumparg,
0);
dns_dnssecsignstats_dump(
dnssecsignstats, dns_dnssecsignstats_sign,
dnssecsignstat_dump, &dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS) {
goto error;
}
/* counters type="dnssec-sign"*/
TRY0(xmlTextWriterEndElement(writer));
}
dnssecrefreshstats = dns_zone_getdnssecrefreshstats(zone);
if (dnssecrefreshstats != NULL) {
/* counters type="dnssec-refresh"*/
TRY0(xmlTextWriterStartElement(writer,
ISC_XMLCHAR "counters"));
TRY0(xmlTextWriterWriteAttribute(
@@ -1907,9 +1905,9 @@ zone_xmlrender(dns_zone_t *zone, void *arg) {
ISC_XMLCHAR "dnssec-refresh"));
dumparg.result = ISC_R_SUCCESS;
dns_dnssecsignstats_dump(dnssecrefreshstats,
dnssecsignstat_dump, &dumparg,
0);
dns_dnssecsignstats_dump(
dnssecsignstats, dns_dnssecsignstats_refresh,
dnssecsignstat_dump, &dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS) {
goto error;
}
@@ -2626,7 +2624,6 @@ zone_jsonrender(dns_zone_t *zone, void *arg) {
isc_stats_t *gluecachestats;
dns_stats_t *rcvquerystats;
dns_stats_t *dnssecsignstats;
dns_stats_t *dnssecrefreshstats;
uint64_t nsstat_values[ns_statscounter_max];
uint64_t gluecachestats_values[dns_gluecachestatscounter_max];
@@ -2708,50 +2705,49 @@ zone_jsonrender(dns_zone_t *zone, void *arg) {
dnssecsignstats = dns_zone_getdnssecsignstats(zone);
if (dnssecsignstats != NULL) {
stats_dumparg_t dumparg;
json_object *counters = json_object_new_object();
CHECKMEM(counters);
json_object *sign_counters = json_object_new_object();
CHECKMEM(sign_counters);
dumparg.type = isc_statsformat_json;
dumparg.arg = counters;
dumparg.arg = sign_counters;
dumparg.result = ISC_R_SUCCESS;
dns_dnssecsignstats_dump(dnssecsignstats,
dnssecsignstat_dump, &dumparg,
0);
dns_dnssecsignstats_dump(
dnssecsignstats, dns_dnssecsignstats_sign,
dnssecsignstat_dump, &dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS) {
json_object_put(counters);
json_object_put(sign_counters);
goto error;
}
if (json_object_get_object(counters)->count != 0) {
if (json_object_get_object(sign_counters)->count != 0) {
json_object_object_add(zoneobj, "dnssec-sign",
counters);
sign_counters);
} else {
json_object_put(counters);
json_object_put(sign_counters);
}
}
dnssecrefreshstats = dns_zone_getdnssecrefreshstats(zone);
if (dnssecrefreshstats != NULL) {
stats_dumparg_t dumparg;
json_object *counters = json_object_new_object();
CHECKMEM(counters);
json_object *refresh_counters =
json_object_new_object();
CHECKMEM(refresh_counters);
dumparg.type = isc_statsformat_json;
dumparg.arg = counters;
dumparg.arg = refresh_counters;
dumparg.result = ISC_R_SUCCESS;
dns_dnssecsignstats_dump(dnssecrefreshstats,
dnssecsignstat_dump, &dumparg,
0);
dns_dnssecsignstats_dump(
dnssecsignstats, dns_dnssecsignstats_refresh,
dnssecsignstat_dump, &dumparg, 0);
if (dumparg.result != ISC_R_SUCCESS) {
json_object_put(counters);
json_object_put(refresh_counters);
goto error;
}
if (json_object_get_object(counters)->count != 0) {
json_object_object_add(
zoneobj, "dnssec-refresh", counters);
if (json_object_get_object(refresh_counters)->count !=
0) {
json_object_object_add(zoneobj,
"dnssec-refresh",
refresh_counters);
} else {
json_object_put(counters);
json_object_put(refresh_counters);
}
}
}
+1 -1
View File
@@ -869,7 +869,7 @@ named_os_shutdownmsg(char *command, isc_buffer_t *text) {
pid_t pid;
/* Skip the command name. */
if ((ptr = strtok_r(command, " \t", &last)) == NULL) {
if (strtok_r(command, " \t", &last) == NULL) {
return;
}
-8
View File
@@ -890,7 +890,6 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
isc_stats_t *zoneqrystats;
dns_stats_t *rcvquerystats;
dns_stats_t *dnssecsignstats;
dns_stats_t *dnssecrefreshstats;
dns_zonestat_level_t statlevel = dns_zonestat_none;
int seconds;
dns_zone_t *mayberaw = (raw != NULL) ? raw : zone;
@@ -1187,18 +1186,15 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
zoneqrystats = NULL;
rcvquerystats = NULL;
dnssecsignstats = NULL;
dnssecrefreshstats = NULL;
if (statlevel == dns_zonestat_full) {
RETERR(isc_stats_create(mctx, &zoneqrystats,
ns_statscounter_max));
RETERR(dns_rdatatypestats_create(mctx, &rcvquerystats));
RETERR(dns_dnssecsignstats_create(mctx, &dnssecsignstats));
RETERR(dns_dnssecsignstats_create(mctx, &dnssecrefreshstats));
}
dns_zone_setrequeststats(zone, zoneqrystats);
dns_zone_setrcvquerystats(zone, rcvquerystats);
dns_zone_setdnssecsignstats(zone, dnssecsignstats);
dns_zone_setdnssecrefreshstats(zone, dnssecrefreshstats);
if (zoneqrystats != NULL) {
isc_stats_detach(&zoneqrystats);
@@ -1212,10 +1208,6 @@ named_zone_configure(const cfg_obj_t *config, const cfg_obj_t *vconfig,
dns_stats_detach(&dnssecsignstats);
}
if (dnssecrefreshstats != NULL) {
dns_stats_detach(&dnssecrefreshstats);
}
/*
* Configure master functionality. This applies
* to primary masters (type "master") and slaves
+3 -1
View File
@@ -252,6 +252,8 @@ get_addresses(const char *host, in_port_t port) {
isc_result_t result;
int found = 0, count;
REQUIRE(host != NULL);
if (*host == '/') {
result = isc_sockaddr_frompath(&serveraddrs[nserveraddrs],
host);
@@ -1036,7 +1038,7 @@ main(int argc, char **argv) {
fatal("'%s' is not implemented", command);
}
if (nserveraddrs == 0) {
if (nserveraddrs == 0 && servername != NULL) {
get_addresses(servername, (in_port_t)remoteport);
}
+1
View File
@@ -305,6 +305,7 @@ main(int argc, char *argv[]) {
isc_sockaddr_fromin(&sa, &ina, 53);
ISC_LIST_APPEND(sal, &sa, link);
REQUIRE(DNS_VIEW_VALID(view));
RUNTIME_CHECK(dns_fwdtable_add(view->fwdtable, dns_rootname,
&sal, dns_fwdpolicy_only) ==
ISC_R_SUCCESS);
+30
View File
@@ -24,6 +24,7 @@ options {
listen-on-v6 { none; };
allow-transfer { any; };
recursion no;
key-directory ".";
};
key rndc_key {
@@ -35,6 +36,35 @@ controls {
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
/* These are zones that migrate to dnssec-policy. */
zone "migrate.kasp" {
type master;
file "migrate.kasp.db";
auto-dnssec maintain;
allow-update { any; };
dnssec-dnskey-kskonly yes;
update-check-ksk yes;
};
zone "migrate-nomatch-algnum.kasp" {
type master;
file "migrate-nomatch-algnum.kasp.db";
auto-dnssec maintain;
allow-update { any; };
dnssec-dnskey-kskonly yes;
update-check-ksk yes;
};
zone "migrate-nomatch-alglen.kasp" {
type master;
file "migrate-nomatch-alglen.kasp.db";
auto-dnssec maintain;
allow-update { any; };
dnssec-dnskey-kskonly yes;
update-check-ksk yes;
};
/* These are alorithm rollover test zones. */
zone "step1.algorithm-roll.kasp" {
type master;
file "step1.algorithm-roll.kasp.db";
+25
View File
@@ -35,6 +35,31 @@ controls {
inet 10.53.0.6 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
/* These are zones that migrate to dnssec-policy. */
zone "migrate.kasp" {
type master;
file "migrate.kasp.db";
allow-update { any; };
dnssec-policy "migrate";
};
zone "migrate-nomatch-algnum.kasp" {
type master;
file "migrate-nomatch-algnum.kasp.db";
allow-update { any; };
dnssec-policy "migrate-nomatch-algnum";
};
zone "migrate-nomatch-alglen.kasp" {
type master;
file "migrate-nomatch-alglen.kasp.db";
allow-update { any; };
dnssec-policy "migrate-nomatch-alglen";
};
/*
* Zones for testing KSK/ZSK algorithm roll.
*/
zone "step1.algorithm-roll.kasp" {
type master;
file "step1.algorithm-roll.kasp.db";
@@ -48,3 +48,56 @@ dnssec-policy "ecdsa256" {
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};
dnssec-policy "migrate" {
dnskey-ttl 300;
keys {
ksk key-directory lifetime unlimited algorithm ECDSAP256SHA256;
zsk key-directory lifetime P60D algorithm ECDSAP256SHA256;
};
};
/*
* This policy tests migration from existing keys with 1024 bits RSASHA1 keys
* to ECDSAP256SHA256 keys.
*/
dnssec-policy "migrate-nomatch-algnum" {
dnskey-ttl 300;
keys {
ksk key-directory lifetime unlimited algorithm ecdsa256;
zsk key-directory lifetime P60D algorithm ecdsa256;
};
// Together 12h
zone-propagation-delay 3600;
max-zone-ttl 11h;
// Together 24h
parent-registration-delay 21h;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};
/*
* This policy tests migration from existing keys with 1024 bits RSASHA1 keys
* to 2048 bits RSASHA1 keys.
*/
dnssec-policy "migrate-nomatch-alglen" {
dnskey-ttl 300;
keys {
ksk key-directory lifetime unlimited algorithm rsasha1 2048;
zsk key-directory lifetime P60D algorithm rsasha1 2048;
};
// Together 12h
zone-propagation-delay 3600;
max-zone-ttl 11h;
// Together 24h
parent-registration-delay 21h;
parent-propagation-delay pt1h;
parent-ds-ttl 7200;
};
+49
View File
@@ -39,6 +39,54 @@ R="RUMOURED"
O="OMNIPRESENT"
U="UNRETENTIVE"
# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy.
setup migrate.kasp
echo "$zone" >> zones
KSK=$($KEYGEN -a ECDSAP256SHA256 -f KSK -L 300 $zone 2> keygen.out.$zone.1)
ZSK=$($KEYGEN -a ECDSAP256SHA256 -L 300 $zone 2> keygen.out.$zone.2)
$SETTIME -P now -P sync now -A now "$KSK" > settime.out.$zone.1 2>&1
$SETTIME -P now -A now "$ZSK" > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 5 "$KSK" >> "$infile"
private_type_record $zone 5 "$ZSK" >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy, but this
# time the existing keys do not match the policy. The existing keys are
# RSASHA1 keys, and will be migrated to a dnssec-policy that dictates
# ECDSAP256SHA256 keys.
setup migrate-nomatch-algnum.kasp
echo "$zone" >> zones
KSK=$($KEYGEN -a RSASHA1 -b 2048 -f KSK -L 300 $zone 2> keygen.out.$zone.1)
ZSK=$($KEYGEN -a RSASHA1 -b 1024 -L 300 $zone 2> keygen.out.$zone.2)
Tds="now-24h" # Time according to dnssec-policy that DS will be OMNIPRESENT
Tkey="now-3900s" # DNSKEY TTL + propagation delay
Tsig="now-12h" # Zone's maximum TTL + propagation delay
$SETTIME -P $Tkey -P sync $Tds -A $Tkey "$KSK" > settime.out.$zone.1 2>&1
$SETTIME -P $Tsig -A $Tsig "$ZSK" > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 5 "$KSK" >> "$infile"
private_type_record $zone 5 "$ZSK" >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
# Set up a zone with auto-dnssec maintain to migrate to dnssec-policy, but this
# time the existing keys do not match the policy. The existing keys are
# 1024 bits RSASHA1 keys, and will be migrated to a dnssec-policy that
# dictates 2048 bits RSASHA1 keys.
setup migrate-nomatch-alglen.kasp
echo "$zone" >> zones
KSK=$($KEYGEN -a RSASHA1 -b 1024 -f KSK -L 300 $zone 2> keygen.out.$zone.1)
ZSK=$($KEYGEN -a RSASHA1 -b 1024 -L 300 $zone 2> keygen.out.$zone.2)
Tds="now-24h" # Time according to dnssec-policy that DS will be OMNIPRESENT
Tkey="now-3900s" # DNSKEY TTL + propagation delay
Tsig="now-12h" # Zone's maximum TTL + propagation delay
$SETTIME -P $Tkey -P sync $Tds -A $Tkey "$KSK" > settime.out.$zone.1 2>&1
$SETTIME -P $Tsig -A $Tsig "$ZSK" > settime.out.$zone.2 2>&1
cat template.db.in "${KSK}.key" "${ZSK}.key" > "$infile"
private_type_record $zone 5 "$KSK" >> "$infile"
private_type_record $zone 5 "$ZSK" >> "$infile"
$SIGNER -S -x -s now-1h -e now+2w -o $zone -O full -f $zonefile $infile > signer.out.$zone.1 2>&1
#
# The zones at algorithm-roll.kasp represent the various steps of a ZSK/KSK
# algorithm rollover.
@@ -47,6 +95,7 @@ U="UNRETENTIVE"
# Step 1:
# Introduce the first key. This will immediately be active.
setup step1.algorithm-roll.kasp
echo "$zone" >> zones
KSK=$($KEYGEN -a RSASHA1 -f KSK -L 3600 $zone 2> keygen.out.$zone.1)
ZSK=$($KEYGEN -a RSASHA1 -L 3600 $zone 2> keygen.out.$zone.2)
TactN="now"
+414 -69
View File
@@ -55,6 +55,7 @@ VIEW2="4xILSZQnuO1UKubXHkYUsvBRPu8="
# STATE_DS=18
# EXPECT_ZRRSIG=19
# EXPECT_KRRSIG=20
# LEGACY=21
key_key() {
echo "${1}__${2}"
@@ -77,7 +78,7 @@ key_clear() {
key_set "$1" "ROLE" 'none'
key_set "$1" "KSK" 'no'
key_set "$1" "ZSK" 'no'
key_set "$1" "LIFETIME" '0'
key_set "$1" "LIFETIME" 'none'
key_set "$1" "ALG_NUM" '0'
key_set "$1" "ALG_STR" 'none'
key_set "$1" "ALG_LEN" '0'
@@ -93,6 +94,7 @@ key_clear() {
key_set "$1" "STATE_DS" 'none'
key_set "$1" "EXPECT_ZRRSIG" 'no'
key_set "$1" "EXPECT_KRRSIG" 'no'
key_set "$1" "LEGACY" 'no'
}
# Start clear.
@@ -238,6 +240,7 @@ check_key() {
_length=$(key_get "$1" "ALG_LEN")
_dnskey_ttl="$DNSKEY_TTL"
_lifetime=$(key_get "$1" LIFETIME)
_legacy=$(key_get "$1" LEGACY)
_published=$(key_get "$1" PUBLISHED)
_active=$(key_get "$1" ACTIVE)
@@ -277,10 +280,13 @@ check_key() {
# Check file existence.
[ -s "$KEY_FILE" ] || ret=1
[ -s "$PRIVATE_FILE" ] || ret=1
[ -s "$STATE_FILE" ] || ret=1
if [ "$_legacy" == "no" ]; then
[ -s "$STATE_FILE" ] || ret=1
fi
[ "$ret" -eq 0 ] || log_error "${BASE_FILE} files missing"
[ "$ret" -eq 0 ] || return
test $_log -eq 1 && echo_i "check key $BASE_FILE"
test $_log -eq 1 && echo_i "check key file $BASE_FILE"
# Check the public key file.
grep "This is a ${_role2} key, keyid ${_key_id}, for ${_zone}." "$KEY_FILE" > /dev/null || log_error "mismatch top comment in $KEY_FILE"
@@ -289,106 +295,134 @@ check_key() {
grep "Private-key-format: v1.3" "$PRIVATE_FILE" > /dev/null || log_error "mismatch private key format in $PRIVATE_FILE"
grep "Algorithm: ${_alg_num} (${_alg_string})" "$PRIVATE_FILE" > /dev/null || log_error "mismatch algorithm in $PRIVATE_FILE"
# Now check the key state file.
grep "This is the state of key ${_key_id}, for ${_zone}." "$STATE_FILE" > /dev/null || log_error "mismatch top comment in $STATE_FILE"
grep "Lifetime: ${_lifetime}" "$STATE_FILE" > /dev/null || log_error "mismatch lifetime in $STATE_FILE"
grep "Algorithm: ${_alg_num}" "$STATE_FILE" > /dev/null || log_error "mismatch algorithm in $STATE_FILE"
grep "Length: ${_length}" "$STATE_FILE" > /dev/null || log_error "mismatch length in $STATE_FILE"
grep "KSK: ${_ksk}" "$STATE_FILE" > /dev/null || log_error "mismatch ksk in $STATE_FILE"
grep "ZSK: ${_zsk}" "$STATE_FILE" > /dev/null || log_error "mismatch zsk in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "This is the state of key ${_key_id}, for ${_zone}." "$STATE_FILE" > /dev/null || log_error "mismatch top comment in $STATE_FILE"
if [ "$_lifetime" == "none" ]; then
grep "Lifetime: " "$STATE_FILE" > /dev/null && log_error "unexpected lifetime in $STATE_FILE"
else
grep "Lifetime: ${_lifetime}" "$STATE_FILE" > /dev/null || log_error "mismatch lifetime in $STATE_FILE"
fi
grep "Algorithm: ${_alg_num}" "$STATE_FILE" > /dev/null || log_error "mismatch algorithm in $STATE_FILE"
grep "Length: ${_length}" "$STATE_FILE" > /dev/null || log_error "mismatch length in $STATE_FILE"
grep "KSK: ${_ksk}" "$STATE_FILE" > /dev/null || log_error "mismatch ksk in $STATE_FILE"
grep "ZSK: ${_zsk}" "$STATE_FILE" > /dev/null || log_error "mismatch zsk in $STATE_FILE"
# Check key states.
if [ "$_goal" = "none" ]; then
grep "GoalState: " "$STATE_FILE" > /dev/null && log_error "unexpected goal state in $STATE_FILE"
else
grep "GoalState: ${_goal}" "$STATE_FILE" > /dev/null || log_error "mismatch goal state in $STATE_FILE"
fi
# Check key states.
if [ "$_goal" = "none" ]; then
grep "GoalState: " "$STATE_FILE" > /dev/null && log_error "unexpected goal state in $STATE_FILE"
else
grep "GoalState: ${_goal}" "$STATE_FILE" > /dev/null || log_error "mismatch goal state in $STATE_FILE"
fi
if [ "$_state_dnskey" = "none" ]; then
grep "DNSKEYState: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey state in $STATE_FILE"
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey change in $STATE_FILE"
else
grep "DNSKEYState: ${_state_dnskey}" "$STATE_FILE" > /dev/null || log_error "mismatch dnskey state in $STATE_FILE"
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null || log_error "mismatch dnskey change in $STATE_FILE"
fi
if [ "$_state_dnskey" = "none" ]; then
grep "DNSKEYState: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey state in $STATE_FILE"
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null && log_error "unexpected dnskey change in $STATE_FILE"
else
grep "DNSKEYState: ${_state_dnskey}" "$STATE_FILE" > /dev/null || log_error "mismatch dnskey state in $STATE_FILE"
grep "DNSKEYChange: " "$STATE_FILE" > /dev/null || log_error "mismatch dnskey change in $STATE_FILE"
fi
if [ "$_state_zrrsig" = "none" ]; then
grep "ZRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig state in $STATE_FILE"
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig change in $STATE_FILE"
else
grep "ZRRSIGState: ${_state_zrrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig state in $STATE_FILE"
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig change in $STATE_FILE"
fi
if [ "$_state_zrrsig" = "none" ]; then
grep "ZRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig state in $STATE_FILE"
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected zrrsig change in $STATE_FILE"
else
grep "ZRRSIGState: ${_state_zrrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig state in $STATE_FILE"
grep "ZRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch zrrsig change in $STATE_FILE"
fi
if [ "$_state_krrsig" = "none" ]; then
grep "KRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig state in $STATE_FILE"
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig change in $STATE_FILE"
else
grep "KRRSIGState: ${_state_krrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch krrsig state in $STATE_FILE"
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch krrsig change in $STATE_FILE"
fi
if [ "$_state_krrsig" = "none" ]; then
grep "KRRSIGState: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig state in $STATE_FILE"
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null && log_error "unexpected krrsig change in $STATE_FILE"
else
grep "KRRSIGState: ${_state_krrsig}" "$STATE_FILE" > /dev/null || log_error "mismatch krrsig state in $STATE_FILE"
grep "KRRSIGChange: " "$STATE_FILE" > /dev/null || log_error "mismatch krrsig change in $STATE_FILE"
fi
if [ "$_state_ds" = "none" ]; then
grep "DSState: " "$STATE_FILE" > /dev/null && log_error "unexpected ds state in $STATE_FILE"
grep "DSChange: " "$STATE_FILE" > /dev/null && log_error "unexpected ds change in $STATE_FILE"
else
grep "DSState: ${_state_ds}" "$STATE_FILE" > /dev/null || log_error "mismatch ds state in $STATE_FILE"
grep "DSChange: " "$STATE_FILE" > /dev/null || log_error "mismatch ds change in $STATE_FILE"
if [ "$_state_ds" = "none" ]; then
grep "DSState: " "$STATE_FILE" > /dev/null && log_error "unexpected ds state in $STATE_FILE"
grep "DSChange: " "$STATE_FILE" > /dev/null && log_error "unexpected ds change in $STATE_FILE"
else
grep "DSState: ${_state_ds}" "$STATE_FILE" > /dev/null || log_error "mismatch ds state in $STATE_FILE"
grep "DSChange: " "$STATE_FILE" > /dev/null || log_error "mismatch ds change in $STATE_FILE"
fi
fi
# Check timing metadata.
if [ "$_published" = "none" ]; then
grep "; Publish:" "$KEY_FILE" > /dev/null && log_error "unexpected publish comment in $KEY_FILE"
grep "Publish:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected publish in $PRIVATE_FILE"
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
fi
else
grep "; Publish:" "$KEY_FILE" > /dev/null || log_error "mismatch publish comment in $KEY_FILE ($KEY_PUBLISHED)"
grep "Publish:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch publish in $PRIVATE_FILE ($KEY_PUBLISHED)"
grep "Published:" "$STATE_FILE" > /dev/null || log_error "mismatch publish in $STATE_FILE ($KEY_PUBLISHED)"
grep "; Publish:" "$KEY_FILE" > /dev/null || log_error "mismatch publish comment in $KEY_FILE"
grep "Publish:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch publish in $PRIVATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Published:" "$STATE_FILE" > /dev/null || log_error "mismatch publish in $STATE_FILE"
fi
fi
if [ "$_active" = "none" ]; then
grep "; Activate:" "$KEY_FILE" > /dev/null && log_error "unexpected active comment in $KEY_FILE"
grep "Activate:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected active in $PRIVATE_FILE"
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
fi
else
grep "; Activate:" "$KEY_FILE" > /dev/null || log_error "mismatch active comment in $KEY_FILE"
grep "Activate:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch active in $PRIVATE_FILE"
grep "Active: " "$STATE_FILE" > /dev/null || log_error "mismatch active in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Active: " "$STATE_FILE" > /dev/null || log_error "mismatch active in $STATE_FILE"
fi
fi
if [ "$_retired" = "none" ]; then
grep "; Inactive:" "$KEY_FILE" > /dev/null && log_error "unexpected retired comment in $KEY_FILE"
grep "Inactive:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected retired in $PRIVATE_FILE"
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
fi
else
grep "; Inactive:" "$KEY_FILE" > /dev/null || log_error "mismatch retired comment in $KEY_FILE"
grep "Inactive:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch retired in $PRIVATE_FILE"
grep "Retired: " "$STATE_FILE" > /dev/null || log_error "mismatch retired in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Retired: " "$STATE_FILE" > /dev/null || log_error "mismatch retired in $STATE_FILE"
fi
fi
if [ "$_revoked" = "none" ]; then
grep "; Revoke:" "$KEY_FILE" > /dev/null && log_error "unexpected revoked comment in $KEY_FILE"
grep "Revoke:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected revoked in $PRIVATE_FILE"
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
fi
else
grep "; Revoke:" "$KEY_FILE" > /dev/null || log_error "mismatch revoked comment in $KEY_FILE"
grep "Revoke:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch revoked in $PRIVATE_FILE"
grep "Revoked: " "$STATE_FILE" > /dev/null || log_error "mismatch revoked in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Revoked: " "$STATE_FILE" > /dev/null || log_error "mismatch revoked in $STATE_FILE"
fi
fi
if [ "$_removed" = "none" ]; then
grep "; Delete:" "$KEY_FILE" > /dev/null && log_error "unexpected removed comment in $KEY_FILE"
grep "Delete:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected removed in $PRIVATE_FILE"
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
fi
else
grep "; Delete:" "$KEY_FILE" > /dev/null || log_error "mismatch removed comment in $KEY_FILE"
grep "Delete:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch removed in $PRIVATE_FILE"
grep "Removed: " "$STATE_FILE" > /dev/null || log_error "mismatch removed in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Removed: " "$STATE_FILE" > /dev/null || log_error "mismatch removed in $STATE_FILE"
fi
fi
grep "; Created:" "$KEY_FILE" > /dev/null || log_error "mismatch created comment in $KEY_FILE"
grep "Created:" "$PRIVATE_FILE" > /dev/null || log_error "mismatch created in $PRIVATE_FILE"
grep "Generated: " "$STATE_FILE" > /dev/null || log_error "mismatch generated in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Generated: " "$STATE_FILE" > /dev/null || log_error "mismatch generated in $STATE_FILE"
fi
}
# Check the key with key id $1 and see if it is unused.
@@ -424,20 +458,24 @@ key_unused() {
# Check timing metadata.
grep "; Publish:" "$KEY_FILE" > /dev/null && log_error "unexpected publish comment in $KEY_FILE"
grep "Publish:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected publish in $PRIVATE_FILE"
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
grep "; Activate:" "$KEY_FILE" > /dev/null && log_error "unexpected active comment in $KEY_FILE"
grep "Activate:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected active in $PRIVATE_FILE"
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
grep "; Inactive:" "$KEY_FILE" > /dev/null && log_error "unexpected retired comment in $KEY_FILE"
grep "Inactive:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected retired in $PRIVATE_FILE"
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
grep "; Revoke:" "$KEY_FILE" > /dev/null && log_error "unexpected revoked comment in $KEY_FILE"
grep "Revoke:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected revoked in $PRIVATE_FILE"
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
grep "; Delete:" "$KEY_FILE" > /dev/null && log_error "unexpected removed comment in $KEY_FILE"
grep "Publish:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected publish in $PRIVATE_FILE"
grep "Activate:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected active in $PRIVATE_FILE"
grep "Inactive:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected retired in $PRIVATE_FILE"
grep "Revoke:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected revoked in $PRIVATE_FILE"
grep "Delete:" "$PRIVATE_FILE" > /dev/null && log_error "unexpected removed in $PRIVATE_FILE"
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
if [ "$_legacy" == "no" ]; then
grep "Published: " "$STATE_FILE" > /dev/null && log_error "unexpected publish in $STATE_FILE"
grep "Active: " "$STATE_FILE" > /dev/null && log_error "unexpected active in $STATE_FILE"
grep "Retired: " "$STATE_FILE" > /dev/null && log_error "unexpected retired in $STATE_FILE"
grep "Revoked: " "$STATE_FILE" > /dev/null && log_error "unexpected revoked in $STATE_FILE"
grep "Removed: " "$STATE_FILE" > /dev/null && log_error "unexpected removed in $STATE_FILE"
fi
}
# Test: dnssec-verify zone $1.
@@ -848,7 +886,7 @@ check_keys()
for _id in $_ids; do
# There are three key files with the same algorithm.
# Check them until a match is found.
echo_i "check key $_id"
echo_i "check key id $_id"
if [ "no" = "$(key_get KEY1 ID)" ] && [ "$(key_get KEY1 EXPECT)" = "yes" ]; then
ret=0
@@ -863,19 +901,19 @@ check_keys()
if [ "no" = "$(key_get KEY3 ID)" ] && [ "$(key_get KEY3 EXPECT)" = "yes" ]; then
ret=0
check_key "KEY3" "$_id"
test "$ret" -eq 0 && key_set KEY3 ID "$KEY_ID" && continue
test "$ret" -eq 0 && key_set KEY3 "ID" "$KEY_ID" && continue
fi
if [ "no" = "$(key_get KEY4 ID)" ] && [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
ret=0
check_key "KEY4" "$_id"
test "$ret" -eq 0 && key_set KEY4 ID "$KEY_ID" && continue
test "$ret" -eq 0 && key_set KEY4 "ID" "$KEY_ID" && continue
fi
# This may be an unused key. Assume algorithm of KEY1.
ret=0 && key_unused "$_id" "$(key_get KEY1 ALG_NUM)"
test "$ret" -eq 0 && continue
# If ret is still non-zero, non of the files matched.
# If ret is still non-zero, none of the files matched.
test "$ret" -eq 0 || echo_i "failed"
status=$((status+1))
done
@@ -885,15 +923,19 @@ check_keys()
ret=0
if [ "$(key_get KEY1 EXPECT)" = "yes" ]; then
echo_i "KEY1 ID $(key_get KEY1 ID)"
test "no" = "$(key_get KEY1 ID)" && log_error "No KEY1 found for zone ${ZONE}"
fi
if [ "$(key_get KEY2 EXPECT)" = "yes" ]; then
echo_i "KEY2 ID $(key_get KEY2 ID)"
test "no" = "$(key_get KEY2 ID)" && log_error "No KEY2 found for zone ${ZONE}"
fi
if [ "$(key_get KEY3 EXPECT)" = "yes" ]; then
echo_i "KEY3 ID $(key_get KEY3 ID)"
test "no" = "$(key_get KEY3 ID)" && log_error "No KEY3 found for zone ${ZONE}"
fi
if [ "$(key_get KEY4 EXPECT)" = "yes" ]; then
echo_i "KEY4 ID $(key_get KEY4 ID)"
test "no" = "$(key_get KEY4 ID)" && log_error "No KEY4 found for zone ${ZONE}"
fi
test "$ret" -eq 0 || echo_i "failed"
@@ -2821,7 +2863,166 @@ dnssec_verify
# interval.
check_next_key_event 3600
# Reconfig dnssec-policy (triggering algorithm roll).
#
# Testing good migration.
#
set_zone "migrate.kasp"
set_policy "none" "2" "300"
set_server "ns6" "10.53.0.6"
init_migration_match() {
key_clear "KEY1"
key_set "KEY1" "LEGACY" "yes"
set_keyrole "KEY1" "ksk"
set_keylifetime "KEY1" "0"
set_keyalgorithm "KEY1" "13" "ECDSAP256SHA256" "256"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
key_set "KEY2" "LEGACY" "yes"
set_keyrole "KEY2" "zsk"
set_keylifetime "KEY2" "5184000"
set_keyalgorithm "KEY2" "13" "ECDSAP256SHA256" "256"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
key_clear "KEY3"
key_clear "KEY4"
set_keytime "KEY1" "PUBLISHED" "yes"
set_keytime "KEY1" "ACTIVE" "yes"
set_keytime "KEY1" "RETIRED" "none"
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "rumoured"
set_keystate "KEY1" "STATE_KRRSIG" "rumoured"
set_keystate "KEY1" "STATE_DS" "rumoured"
set_keytime "KEY2" "PUBLISHED" "yes"
set_keytime "KEY2" "ACTIVE" "yes"
set_keytime "KEY2" "RETIRED" "none"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "rumoured"
set_keystate "KEY2" "STATE_ZRRSIG" "rumoured"
}
init_migration_match
# Make sure the zone is signed with legacy keys.
check_keys
check_apex
check_subdomain
dnssec_verify
# Remember legacy key tags.
_migrate_ksk=$(key_get KEY1 ID)
_migrate_zsk=$(key_get KEY2 ID)
#
# Testing migration with unmatched existing keys (different algorithm).
#
set_zone "migrate-nomatch-algnum.kasp"
set_policy "none" "2" "300"
set_server "ns6" "10.53.0.6"
init_migration_nomatch_algnum() {
key_clear "KEY1"
key_set "KEY1" "LEGACY" "yes"
set_keyrole "KEY1" "ksk"
set_keyalgorithm "KEY1" "5" "RSASHA1" "2048"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
key_set "KEY2" "LEGACY" "yes"
set_keyrole "KEY2" "zsk"
set_keyalgorithm "KEY2" "5" "RSASHA1" "1024"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
key_clear "KEY3"
key_clear "KEY4"
set_keytime "KEY1" "PUBLISHED" "yes"
set_keytime "KEY1" "ACTIVE" "yes"
set_keytime "KEY1" "RETIRED" "none"
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
set_keystate "KEY1" "STATE_DS" "omnipresent"
set_keytime "KEY2" "PUBLISHED" "yes"
set_keytime "KEY2" "ACTIVE" "yes"
set_keytime "KEY2" "RETIRED" "none"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
}
init_migration_nomatch_algnum
# Make sure the zone is signed with legacy keys.
check_keys
check_apex
check_subdomain
dnssec_verify
# Remember legacy key tags.
_migratenomatch_algnum_ksk=$(key_get KEY1 ID)
_migratenomatch_algnum_zsk=$(key_get KEY2 ID)
#
# Testing migration with unmatched existing keys (different length).
#
set_zone "migrate-nomatch-alglen.kasp"
set_policy "none" "2" "300"
set_server "ns6" "10.53.0.6"
init_migration_nomatch_alglen() {
key_clear "KEY1"
key_set "KEY1" "LEGACY" "yes"
set_keyrole "KEY1" "ksk"
set_keyalgorithm "KEY1" "5" "RSASHA1" "1024"
set_keysigning "KEY1" "yes"
set_zonesigning "KEY1" "no"
key_clear "KEY2"
key_set "KEY2" "LEGACY" "yes"
set_keyrole "KEY2" "zsk"
set_keyalgorithm "KEY2" "5" "RSASHA1" "1024"
set_keysigning "KEY2" "no"
set_zonesigning "KEY2" "yes"
key_clear "KEY3"
key_clear "KEY4"
set_keytime "KEY1" "PUBLISHED" "yes"
set_keytime "KEY1" "ACTIVE" "yes"
set_keytime "KEY1" "RETIRED" "none"
set_keystate "KEY1" "GOAL" "omnipresent"
set_keystate "KEY1" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY1" "STATE_KRRSIG" "omnipresent"
set_keystate "KEY1" "STATE_DS" "omnipresent"
set_keytime "KEY2" "PUBLISHED" "yes"
set_keytime "KEY2" "ACTIVE" "yes"
set_keytime "KEY2" "RETIRED" "none"
set_keystate "KEY2" "GOAL" "omnipresent"
set_keystate "KEY2" "STATE_DNSKEY" "omnipresent"
set_keystate "KEY2" "STATE_ZRRSIG" "omnipresent"
}
init_migration_nomatch_alglen
# Make sure the zone is signed with legacy keys.
check_keys
check_apex
check_subdomain
dnssec_verify
# Remember legacy key tags.
_migratenomatch_alglen_ksk=$(key_get KEY1 ID)
_migratenomatch_alglen_zsk=$(key_get KEY2 ID)
# Reconfig dnssec-policy (triggering algorithm roll and other dnssec-policy
# changes).
echo_i "reconfig dnssec-policy to trigger algorithm rollover"
copy_setports ns6/named2.conf.in ns6/named.conf
rndc_reconfig ns6 10.53.0.6
@@ -2854,6 +3055,150 @@ status=$((status+ret))
next_key_event_threshold=$((next_key_event_threshold+i))
#
# Testing migration.
#
set_zone "migrate.kasp"
set_policy "migrate" "2" "300"
set_server "ns6" "10.53.0.6"
# Key properties, timings and metadata should be the same as legacy keys above.
# However, because the zsk has a lifetime, kasp will set the retired time.
init_migration_match
key_set "KEY1" "LEGACY" "no"
key_set "KEY2" "LEGACY" "no"
set_keytime "KEY2" "RETIRED" "yes"
check_keys
check_apex
check_subdomain
dnssec_verify
# Check key tags, should be the same.
n=$((n+1))
echo_i "check that of zone ${ZONE} migration to dnssec-policy uses the same keys ($n)"
ret=0
[ $_migrate_ksk == $(key_get KEY1 ID) ] || log_error "mismatch ksk tag"
[ $_migrate_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
status=$((status+ret))
# Test migration to dnssec-policy, existing keys do not match key algorithm.
set_zone "migrate-nomatch-algnum.kasp"
set_policy "migrate-nomatch-algnum" "4" "300"
set_server "ns6" "10.53.0.6"
# The legacy keys need to be retired, but otherwise stay present until the
# new keys are omnipresent, and can be used to construct a chain of trust.
init_migration_nomatch_algnum
key_set "KEY1" "LEGACY" "no"
set_keytime "KEY1" "RETIRED" "yes"
set_keystate "KEY1" "GOAL" "hidden"
key_set "KEY2" "LEGACY" "no"
set_keytime "KEY2" "RETIRED" "yes"
set_keystate "KEY2" "GOAL" "hidden"
set_keyrole "KEY3" "ksk"
set_keylifetime "KEY3" "0"
set_keyalgorithm "KEY3" "13" "ECDSAP256SHA256" "256"
set_keysigning "KEY3" "yes"
set_zonesigning "KEY3" "no"
set_keyrole "KEY4" "zsk"
set_keylifetime "KEY4" "5184000"
set_keyalgorithm "KEY4" "13" "ECDSAP256SHA256" "256"
set_keysigning "KEY4" "no"
set_zonesigning "KEY4" "yes"
set_keytime "KEY3" "PUBLISHED" "yes"
set_keytime "KEY3" "ACTIVE" "yes"
set_keytime "KEY3" "RETIRED" "none"
set_keystate "KEY3" "GOAL" "omnipresent"
set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
set_keystate "KEY3" "STATE_DS" "hidden"
set_keytime "KEY4" "PUBLISHED" "yes"
set_keytime "KEY4" "ACTIVE" "yes"
set_keytime "KEY4" "RETIRED" "yes"
set_keystate "KEY4" "GOAL" "omnipresent"
set_keystate "KEY4" "STATE_DNSKEY" "rumoured"
set_keystate "KEY4" "STATE_ZRRSIG" "rumoured"
check_keys
check_apex
check_subdomain
dnssec_verify
# Check key tags, should be the same.
n=$((n+1))
echo_i "check that of zone ${ZONE} migration to dnssec-policy keeps existing keys ($n)"
ret=0
[ $_migratenomatch_algnum_ksk == $(key_get KEY1 ID) ] || log_error "mismatch ksk tag"
[ $_migratenomatch_algnum_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
status=$((status+ret))
# Test migration to dnssec-policy, existing keys do not match key length.
set_zone "migrate-nomatch-alglen.kasp"
set_policy "migrate-nomatch-alglen" "4" "300"
set_server "ns6" "10.53.0.6"
# The legacy keys need to be retired, but otherwise stay present until the
# new keys are omnipresent, and can be used to construct a chain of trust.
init_migration_nomatch_alglen
key_set "KEY1" "LEGACY" "no"
set_keytime "KEY1" "RETIRED" "yes"
set_keystate "KEY1" "GOAL" "hidden"
key_set "KEY2" "LEGACY" "no"
set_keytime "KEY2" "RETIRED" "yes"
set_keystate "KEY2" "GOAL" "hidden"
set_keyrole "KEY3" "ksk"
set_keylifetime "KEY3" "0"
set_keyalgorithm "KEY3" "5" "RSASHA1" "2048"
set_keysigning "KEY3" "yes"
set_zonesigning "KEY3" "no"
set_keyrole "KEY4" "zsk"
set_keylifetime "KEY4" "5184000"
set_keyalgorithm "KEY4" "5" "RSASHA1" "2048"
set_keysigning "KEY4" "no"
# This key is considered to be prepublished, so it is not yet signing.
set_zonesigning "KEY4" "no"
set_keytime "KEY3" "PUBLISHED" "yes"
set_keytime "KEY3" "ACTIVE" "yes"
set_keytime "KEY3" "RETIRED" "none"
set_keystate "KEY3" "GOAL" "omnipresent"
set_keystate "KEY3" "STATE_DNSKEY" "rumoured"
set_keystate "KEY3" "STATE_KRRSIG" "rumoured"
set_keystate "KEY3" "STATE_DS" "hidden"
set_keytime "KEY4" "PUBLISHED" "yes"
set_keytime "KEY4" "ACTIVE" "yes"
set_keytime "KEY4" "RETIRED" "yes"
set_keystate "KEY4" "GOAL" "omnipresent"
set_keystate "KEY4" "STATE_DNSKEY" "rumoured"
set_keystate "KEY4" "STATE_ZRRSIG" "hidden"
check_keys
check_apex
check_subdomain
dnssec_verify
# Check key tags, should be the same.
n=$((n+1))
echo_i "check that of zone ${ZONE} migration to dnssec-policy keeps existing keys ($n)"
ret=0
[ $_migratenomatch_alglen_ksk == $(key_get KEY1 ID) ] || log_error "mismatch ksk tag"
[ $_migratenomatch_alglen_zsk == $(key_get KEY2 ID) ] || log_error "mismatch zsk tag"
status=$((status+ret))
#
# Testing KSK/ZSK algorithm rollover.
#
+2 -1
View File
@@ -22,5 +22,6 @@ rm -f xml.*mem json.*mem
rm -f compressed.headers regular.headers compressed.out regular.out
rm -f ns*/managed-keys.bind*
rm -f ns2/Kdnssec* ns2/dnssec.*.id
rm -f ns2/dnssec.db.signed* ns2/dsset-dnssec.
rm -f ns2/Kmanykeys* ns2/manykeys.*.id
rm -f ns2/*.db.signed* ns2/dsset-*. ns2/*.jbk
rm -f ns2/core
@@ -34,6 +34,17 @@ controls {
inet 10.53.0.2 port @CONTROLPORT@ allow { any; } keys { rndc_key; };
};
dnssec-policy "manykeys" {
keys {
ksk lifetime unlimited algorithm 5;
zsk lifetime unlimited algorithm 5;
ksk lifetime unlimited algorithm 13;
zsk lifetime unlimited algorithm 13;
ksk lifetime unlimited algorithm 14;
zsk lifetime unlimited algorithm 14;
};
};
zone "example" {
type master;
file "example.db";
@@ -49,3 +60,10 @@ zone "dnssec" {
dnssec-dnskey-kskonly yes;
update-check-ksk yes;
};
zone "manykeys" {
type master;
file "manykeys.db.signed";
zone-statistics full;
dnssec-policy "manykeys";
};
+17 -2
View File
@@ -17,12 +17,27 @@ set -e
zone=dnssec.
infile=dnssec.db.in
zonefile=dnssec.db.signed
ksk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" -f KSK "$zone")
zsk=$("$KEYGEN" -q -a "$DEFAULT_ALGORITHM" -b "$DEFAULT_BITS" "$zone")
# Sign deliberately with a very short expiration date.
"$SIGNER" -S -x -O full -e "now"+1s -o "$zone" -f "$zonefile" "$infile" > /dev/null 2>&1
keyfile_to_key_id "$ksk" > dnssec.ksk.id
keyfile_to_key_id "$zsk" > dnssec.zsk.id
zone=manykeys.
infile=manykeys.db.in
zonefile=manykeys.db.signed
ksk8=$("$KEYGEN" -q -a RSASHA256 -b 2048 -f KSK "$zone")
zsk8=$("$KEYGEN" -q -a RSASHA256 -b 2048 "$zone")
ksk13=$("$KEYGEN" -q -a ECDSAP256SHA256 -b 256 -f KSK "$zone")
zsk13=$("$KEYGEN" -q -a ECDSAP256SHA256 -b 256 "$zone")
ksk14=$("$KEYGEN" -q -a ECDSAP384SHA384 -b 384 -f KSK "$zone")
zsk14=$("$KEYGEN" -q -a ECDSAP384SHA384 -b 384 "$zone")
# Sign deliberately with a very short expiration date.
"$SIGNER" -S -x -O full -e "now"+1s -o "$zone" -f "$zonefile" "$infile" > /dev/null 2>&1
keyfile_to_key_id "$ksk8" > manykeys.ksk8.id
keyfile_to_key_id "$zsk8" > manykeys.zsk8.id
keyfile_to_key_id "$ksk13" > manykeys.ksk13.id
keyfile_to_key_id "$zsk13" > manykeys.zsk13.id
keyfile_to_key_id "$ksk14" > manykeys.ksk14.id
keyfile_to_key_id "$zsk14" > manykeys.zsk14.id
+31 -8
View File
@@ -70,8 +70,8 @@ getzones() {
*) return 1 ;;
esac
file=`$PERL fetch.pl -p ${EXTRAPORT1} $path`
cp $file $file.$1.$2
$PERL zones-${1}.pl $file 2>/dev/null | sort > zones.out.$2
cp $file $file.$1.$3
$PERL zones-${1}.pl $file $2 2>/dev/null | sort > zones.out.$3
result=$?
return $result
}
@@ -292,11 +292,11 @@ rm -f zones.expect
# Fetch and check the dnssec sign statistics.
echo_i "fetching zone stats data after zone maintenance at startup ($n)"
if [ $PERL_XML ]; then
getzones xml x$n || ret=1
getzones xml $zone x$n || ret=1
cmp zones.out.x$n zones.expect.$n || ret=1
fi
if [ $PERL_JSON ]; then
getzones json j$n || ret=1
getzones json $zone j$n || ret=1
cmp zones.out.j$n zones.expect.$n || ret=1
fi
if [ $ret != 0 ]; then echo_i "failed"; fi
@@ -322,11 +322,11 @@ rm -f zones.expect
# Fetch and check the dnssec sign statistics.
echo_i "fetching zone stats data after dynamic update ($n)"
if [ $PERL_XML ]; then
getzones xml x$n || ret=1
getzones xml $zone x$n || ret=1
cmp zones.out.x$n zones.expect.$n || ret=1
fi
if [ $PERL_JSON ]; then
getzones json j$n || ret=1
getzones json $zone j$n || ret=1
cmp zones.out.j$n zones.expect.$n || ret=1
fi
if [ $ret != 0 ]; then echo_i "failed"; fi
@@ -349,16 +349,39 @@ cat zones.expect | sort > zones.expect.$n
rm -f zones.expect
# Fetch and check the dnssec sign statistics.
if [ $PERL_XML ]; then
getzones xml x$n || ret=1
getzones xml $zone x$n || ret=1
cmp zones.out.x$n zones.expect.$n || ret=1
fi
if [ $PERL_JSON ]; then
getzones json j$n || ret=1
getzones json $zone j$n || ret=1
cmp zones.out.j$n zones.expect.$n || ret=1
fi
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
# 4. Test a zone with more than four keys.
zone="manykeys"
ksk8_id=`cat ns2/$zone.ksk8.id`
zsk8_id=`cat ns2/$zone.zsk8.id`
ksk13_id=`cat ns2/$zone.ksk13.id`
zsk13_id=`cat ns2/$zone.zsk13.id`
ksk14_id=`cat ns2/$zone.ksk14.id`
zsk14_id=`cat ns2/$zone.zsk14.id`
ret=0
echo_i "fetch zone stats data for a zone with many keys ($n)"
# Fetch and check the dnssec sign statistics.
if [ $PERL_XML ]; then
getzones xml $zone x$n || ret=1
fi
if [ $PERL_JSON ]; then
getzones json $zone j$n || ret=1
fi
# The output is gibberish, but at least make sure it does not crash.
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
n=`expr $n + 1`
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1
+3 -2
View File
@@ -16,6 +16,7 @@
use JSON;
my $file = $ARGV[0];
my $zone = $ARGV[1];
open(INPUT, "<$file");
my $text = do{local$/;<INPUT>};
close(INPUT);
@@ -23,12 +24,12 @@ close(INPUT);
my $ref = decode_json($text);
my $dnssecsign = $ref->{views}->{_default}->{zones}[0]->{"dnssec-sign"};
my $dnssecsign = $ref->{views}->{_default}->{zones}[$zone]->{"dnssec-sign"};
my $type = "dnssec-sign operations ";
foreach $key (keys %{$dnssecsign}) {
print $type . $key . ": ". $dnssecsign->{$key} ."\n";
}
my $dnssecrefresh = $ref->{views}->{_default}->{zones}[0]->{"dnssec-refresh"};
my $dnssecrefresh = $ref->{views}->{_default}->{zones}[$zone]->{"dnssec-refresh"};
my $type = "dnssec-refresh operations ";
foreach $key (keys %{$dnssecrefresh}) {
print $type . $key . ": ". $dnssecrefresh->{$key} ."\n";
+2 -1
View File
@@ -16,10 +16,11 @@
use XML::Simple;
my $file = $ARGV[0];
my $zone = $ARGV[1];
my $ref = XMLin($file);
my $counters = $ref->{views}->{view}->{_default}->{zones}->{zone}->{dnssec}->{counters};
my $counters = $ref->{views}->{view}->{_default}->{zones}->{zone}->{$zone}->{counters};
foreach $group (@$counters) {
+9 -8
View File
@@ -62,6 +62,10 @@
#include <dlz/sdlz_helper.h>
#include <named/globals.h>
#if !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000
typedef bool my_bool;
#endif /* !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000 */
static dns_sdlzimplementation_t *dlz_mysql = NULL;
#define dbc_search_limit 30
@@ -759,9 +763,6 @@ mysql_create(const char *dlzname, unsigned int argc, char *argv[],
char *endp;
int j;
unsigned int flags = 0;
#if MYSQL_VERSION_ID >= 50000
my_bool auto_reconnect = 1;
#endif /* if MYSQL_VERSION_ID >= 50000 */
UNUSED(driverarg);
UNUSED(dlzname);
@@ -897,21 +898,21 @@ mysql_create(const char *dlzname, unsigned int argc, char *argv[],
pass = getParameterValue(argv[1], "pass=");
socket = getParameterValue(argv[1], "socket=");
#if MYSQL_VERSION_ID >= 50000
/* enable automatic reconnection. */
if (mysql_options((MYSQL *)dbi->dbconn, MYSQL_OPT_RECONNECT,
&auto_reconnect) != 0)
&(my_bool){ 1 }) != 0)
{
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DATABASE,
DNS_LOGMODULE_DLZ, ISC_LOG_WARNING,
"mysql driver failed to set "
"MYSQL_OPT_RECONNECT option, continuing");
"MYSQL_OPT_RECONNECT option, "
"continuing");
}
#endif /* if MYSQL_VERSION_ID >= 50000 */
for (j = 0; dbc == NULL && j < 4; j++)
for (j = 0; dbc == NULL && j < 4; j++) {
dbc = mysql_real_connect((MYSQL *)dbi->dbconn, host, user, pass,
dbname, port, socket, flags);
}
/* let user know if we couldn't connect. */
if (dbc == NULL) {
@@ -59,6 +59,10 @@
#include <dlz_minimal.h>
#include <dlz_pthread.h>
#if !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000
typedef bool my_bool;
#endif /* !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000 */
#define dbc_search_limit 30
#define ALLNODES 1
#define ALLOWXFR 2
@@ -812,9 +816,6 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata,
char *endp;
int j;
const char *helper_name;
#if MYSQL_VERSION_ID >= 50000
my_bool auto_reconnect = 1;
#endif /* if MYSQL_VERSION_ID >= 50000 */
#if PTHREADS
int dbcount;
int i;
@@ -1012,17 +1013,15 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata,
dbc = NULL;
#if MYSQL_VERSION_ID >= 50000
/* enable automatic reconnection. */
if (mysql_options((MYSQL *)dbi->dbconn, MYSQL_OPT_RECONNECT,
&auto_reconnect) != 0)
&(my_bool){ 1 }) != 0)
{
mysql->log(ISC_LOG_WARNING, "MySQL module failed to "
"set "
"MYSQL_OPT_RECONNECT "
"option, continuing");
}
#endif /* if MYSQL_VERSION_ID >= 50000 */
for (j = 0; dbc == NULL && j < 4; j++) {
dbc = mysql_real_connect(
@@ -61,6 +61,10 @@
#include <dlz_minimal.h>
#include <dlz_pthread.h>
#if !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000
typedef bool my_bool;
#endif /* !defined(LIBMARIADB) && MYSQL_VERSION_ID >= 80000 */
/*
* The SQL queries that will be used for lookups and updates are defined
* here. They will be processed into queries by the build_query()
@@ -1020,7 +1024,6 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata,
*/
if (mysql_thread_safe()) {
for (n = 0; n < MAX_DBI; n++) {
my_bool opt = 1;
dlz_mutex_init(&state->db[n].mutex, NULL);
dlz_mutex_lock(&state->db[n].mutex);
state->db[n].id = n;
@@ -1029,7 +1032,7 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata,
mysql_options(state->db[n].sock,
MYSQL_READ_DEFAULT_GROUP, modname);
mysql_options(state->db[n].sock, MYSQL_OPT_RECONNECT,
&opt);
&(my_bool){ 1 });
dlz_mutex_unlock(&state->db[n].mutex);
}
@@ -887,9 +887,6 @@ dlz_create(const char *dlzname, unsigned int argc, char *argv[], void **dbdata,
char *tmp = NULL;
char *endp;
const char *helper_name;
#if SQLITE3_VERSION_ID >= 50000
my_bool auto_reconnect = 1;
#endif /* if SQLITE3_VERSION_ID >= 50000 */
#if PTHREADS
int dbcount;
int i, ret;
+79
View File
@@ -0,0 +1,79 @@
<!--
- Copyright (C) Internet Systems Consortium, Inc. ("ISC")
-
- This Source Code Form is subject to the terms of the Mozilla Public
- License, v. 2.0. If a copy of the MPL was not distributed with this
- file, You can obtain one at http://mozilla.org/MPL/2.0/.
-
- See the COPYRIGHT file distributed with this work for additional
- information regarding copyright ownership.
-->
<section xml:id="relnotes-9.17.1"><info><title>Notes for BIND 9.17.1</title></info>
<section xml:id="relnotes-9.17.1-security"><info><title>Security Fixes</title></info>
<itemizedlist>
<listitem>
<para>
None.
</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="relnotes-9.17.1-known"><info><title>Known Issues</title></info>
<itemizedlist>
<listitem>
<para>
None.
</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="relnotes-9.17.1-new"><info><title>New Features</title></info>
<itemizedlist>
<listitem>
<para>
None.
</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="relnotes-9.17.1-changes"><info><title>Feature Changes</title></info>
<itemizedlist>
<listitem>
<para>
The DNSSEC sign statistics used lots of memory. The number of keys
to track is reduced to four per zone, which should be enough for
99% of all signed zones. [GL #1179]
</para>
</listitem>
</itemizedlist>
</section>
<section xml:id="relnotes-9.17.1-bugs"><info><title>Bug Fixes</title></info>
<itemizedlist>
<listitem>
<para>
When an RPZ policy zone was updated via zone transfer
and a large number of records were deleted, <command>named</command>
could become nonresponsive for a short period while deleted
names were removed from the RPZ summary database. This database
cleanup is now done incrementally over a longer period of time,
reducing such delays. [GL #1447]
</para>
</listitem>
<listitem>
<para>
Migration to dnssec-policy from existing DNSSEC strategy with
auto-dnssec maintain did not work due to bad initializing of the
key states. Fixed by looking closely at the time metadata to
set the key states to the correct values. [GL #1706]
</para>
</listitem>
</itemizedlist>
</section>
</section>
+1
View File
@@ -23,6 +23,7 @@
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="notes-platforms.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="notes-download.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="notes-9.17.1.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="notes-9.17.0.xml"/>
<xi:include xmlns:xi="http://www.w3.org/2001/XInclude" href="notes-license.xml"/>
+13 -3
View File
@@ -491,6 +491,14 @@ LIBDNS_EXTERNAL_DATA extern const char *dns_statscounter_names[];
#define DNS_RDATASTATSTYPE_ATTR(type) ((type) >> 16)
#define DNS_RDATASTATSTYPE_VALUE(b, a) (((a) << 16) | (b))
/*%
* Types of DNSSEC sign statistics operations.
*/
typedef enum {
dns_dnssecsignstats_sign = 1,
dns_dnssecsignstats_refresh = 2
} dnssecsignstats_type_t;
/*%<
* Types of dump callbacks.
*/
@@ -684,9 +692,11 @@ dns_rcodestats_increment(dns_stats_t *stats, dns_opcode_t code);
*/
void
dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id);
dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id, uint8_t alg,
dnssecsignstats_type_t operation);
/*%<
* Increment the statistics counter for the DNSKEY 'id'.
* Increment the statistics counter for the DNSKEY 'id'. The 'operation'
* determines what counter is incremented.
*
* Requires:
*\li 'stats' is a valid dns_stats_t created by dns_dnssecsignstats_create().
@@ -737,7 +747,7 @@ dns_rdatasetstats_dump(dns_stats_t *stats, dns_rdatatypestats_dumper_t dump_fn,
*/
void
dns_dnssecsignstats_dump(dns_stats_t * stats,
dns_dnssecsignstats_dump(dns_stats_t *stats, dnssecsignstats_type_t operation,
dns_dnssecsignstats_dumper_t dump_fn, void *arg,
unsigned int options);
/*%<
-17
View File
@@ -1957,9 +1957,6 @@ dns_zone_setrcvquerystats(dns_zone_t *zone, dns_stats_t *stats);
void
dns_zone_setdnssecsignstats(dns_zone_t *zone, dns_stats_t *stats);
void
dns_zone_setdnssecrefreshstats(dns_zone_t *zone, dns_stats_t *stats);
/*%<
* Set additional statistics sets to zone. These are attached to the zone
* but are not counted in the zone module; only the caller updates the
@@ -1979,9 +1976,6 @@ dns_zone_getrcvquerystats(dns_zone_t *zone);
dns_stats_t *
dns_zone_getdnssecsignstats(dns_zone_t *zone);
dns_stats_t *
dns_zone_getdnssecrefreshstats(dns_zone_t *zone);
/*%<
* Get the additional statistics for zone, if one is installed.
*
@@ -1993,17 +1987,6 @@ dns_zone_getdnssecrefreshstats(dns_zone_t *zone);
* otherwise NULL.
*/
/*%<
* Set additional statistics sets to zone. These are attached to the zone
* but are not counted in the zone module; only the caller updates the
* counters.
*
* Requires:
* \li 'zone' to be a valid zone.
*
*\li stats is a valid statistics.
*/
void
dns_zone_dialup(dns_zone_t *zone);
/*%<
+117 -48
View File
@@ -43,13 +43,13 @@
* Set key state to HIDDEN and change last changed to now,
* only if key state has not been set before.
*/
#define INITIALIZE_STATE(key, state, time) \
#define INITIALIZE_STATE(key, state, time, target) \
do { \
dst_key_state_t s; \
if (dst_key_getstate((key), (state), &s) == ISC_R_NOTFOUND) { \
isc_stdtime_t t; \
dst_key_gettime((key), DST_TIME_CREATED, &t); \
dst_key_setstate((key), (state), HIDDEN); \
dst_key_setstate((key), (state), target); \
dst_key_settime((key), (time), t); \
} \
} while (0)
@@ -105,7 +105,7 @@ static isc_stdtime_t
keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
uint32_t lifetime, isc_stdtime_t now) {
isc_result_t ret;
isc_stdtime_t active, retire, prepub;
isc_stdtime_t active, retire, pub, prepub;
bool ksk = false;
REQUIRE(key != NULL);
@@ -125,7 +125,8 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
if (ret != ISC_R_SUCCESS) {
uint32_t klifetime = 0;
/*
* An active key must have an activate timing metadata.
* An active key must have publish and activate timing
* metadata.
*/
ret = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
if (ret != ISC_R_SUCCESS) {
@@ -133,6 +134,12 @@ keymgr_prepublication_time(dns_dnsseckey_t *key, dns_kasp_t *kasp,
dst_key_settime(key->key, DST_TIME_ACTIVATE, now);
active = now;
}
ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &pub);
if (ret != ISC_R_SUCCESS) {
/* Super weird, but if it happens, set it to now. */
dst_key_settime(key->key, DST_TIME_PUBLISH, now);
pub = now;
}
ret = dst_key_getnum(key->key, DST_NUM_LIFETIME, &klifetime);
if (ret != ISC_R_SUCCESS) {
@@ -1214,19 +1221,25 @@ transition:
}
/*
* See if this key needs to be initialized with a role. A key created and
* derived from a dnssec-policy will have the required metadata available,
* otherwise these may be missing and need to be initialized.
* See if this key needs to be initialized with properties. A key created
* and derived from a dnssec-policy will have the required metadata available,
* otherwise these may be missing and need to be initialized. The key states
* will be initialized according to existing timing metadata.
*
*/
static void
keymgr_key_init_role(dns_dnsseckey_t *key) {
keymgr_key_init(dns_dnsseckey_t *key, dns_kasp_t *kasp, isc_stdtime_t now) {
bool ksk, zsk;
isc_result_t ret;
isc_stdtime_t active = 0, pub = 0, syncpub = 0;
dst_key_state_t dnskey_state = HIDDEN;
dst_key_state_t ds_state = HIDDEN;
dst_key_state_t zrrsig_state = HIDDEN;
REQUIRE(key != NULL);
REQUIRE(key->key != NULL);
/* Initialize role. */
ret = dst_key_getbool(key->key, DST_BOOL_KSK, &ksk);
if (ret != ISC_R_SUCCESS) {
ksk = ((dst_key_flags(key->key) & DNS_KEYFLAG_KSK) != 0);
@@ -1237,6 +1250,52 @@ keymgr_key_init_role(dns_dnsseckey_t *key) {
zsk = ((dst_key_flags(key->key) & DNS_KEYFLAG_KSK) == 0);
dst_key_setbool(key->key, DST_BOOL_ZSK, zsk);
}
/* Get time metadata. */
ret = dst_key_gettime(key->key, DST_TIME_ACTIVATE, &active);
if (active <= now && ret == ISC_R_SUCCESS) {
dns_ttl_t key_ttl = dst_key_getttl(key->key);
key_ttl += dns_kasp_zonepropagationdelay(kasp);
if ((active + key_ttl) <= now) {
dnskey_state = OMNIPRESENT;
} else {
dnskey_state = RUMOURED;
}
}
ret = dst_key_gettime(key->key, DST_TIME_PUBLISH, &pub);
if (pub <= now && ret == ISC_R_SUCCESS) {
dns_ttl_t zone_ttl = dns_kasp_zonemaxttl(kasp);
zone_ttl += dns_kasp_zonepropagationdelay(kasp);
if ((pub + zone_ttl) <= now) {
zrrsig_state = OMNIPRESENT;
} else {
zrrsig_state = RUMOURED;
}
}
ret = dst_key_gettime(key->key, DST_TIME_SYNCPUBLISH, &syncpub);
if (syncpub <= now && ret == ISC_R_SUCCESS) {
dns_ttl_t ds_ttl = dns_kasp_dsttl(kasp);
ds_ttl += dns_kasp_parentregistrationdelay(kasp);
ds_ttl += dns_kasp_parentpropagationdelay(kasp);
if ((syncpub + ds_ttl) <= now) {
ds_state = OMNIPRESENT;
} else {
ds_state = RUMOURED;
}
}
/* Set key states for all keys that do not have them. */
INITIALIZE_STATE(key->key, DST_KEY_DNSKEY, DST_TIME_DNSKEY,
dnskey_state);
if (ksk) {
INITIALIZE_STATE(key->key, DST_KEY_KRRSIG, DST_TIME_KRRSIG,
dnskey_state);
INITIALIZE_STATE(key->key, DST_KEY_DS, DST_TIME_DS, ds_state);
}
if (zsk) {
INITIALIZE_STATE(key->key, DST_KEY_ZRRSIG, DST_TIME_ZRRSIG,
zrrsig_state);
}
}
/*
@@ -1302,23 +1361,13 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
{
bool found_match = false;
/* Make sure this key knows about roles. */
keymgr_key_init_role(dkey);
keymgr_key_init(dkey, kasp, now);
for (kkey = ISC_LIST_HEAD(dns_kasp_keys(kasp)); kkey != NULL;
kkey = ISC_LIST_NEXT(kkey, link))
{
if (keymgr_dnsseckey_kaspkey_match(dkey, kkey)) {
found_match = true;
dst_key_format(dkey->key, keystr,
sizeof(keystr));
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
DNS_LOGMODULE_DNSSEC,
ISC_LOG_DEBUG(1),
"keymgr: DNSKEY %s (%s) matches "
"policy %s",
keystr, keymgr_keyrole(dkey->key),
dns_kasp_getname(kasp));
break;
}
}
@@ -1343,8 +1392,17 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
{
if (keymgr_dnsseckey_kaspkey_match(dkey, kkey)) {
/* Found a match. */
dst_key_format(dkey->key, keystr,
sizeof(keystr));
isc_log_write(dns_lctx, DNS_LOGCATEGORY_DNSSEC,
DNS_LOGMODULE_DNSSEC,
ISC_LOG_DEBUG(1),
"keymgr: DNSKEY %s (%s) matches "
"policy %s",
keystr, keymgr_keyrole(dkey->key),
dns_kasp_getname(kasp));
/* Initialize lifetime. */
/* Initialize lifetime if not set. */
uint32_t l;
if (dst_key_getnum(dkey->key, DST_NUM_LIFETIME,
&l) != ISC_R_SUCCESS) {
@@ -1353,18 +1411,49 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
lifetime);
}
if (dst_key_goal(dkey->key) == OMNIPRESENT) {
if (active_key != NULL) {
if (active_key) {
/* We already have an active key that
* matches the kasp policy.
*/
if (!dst_key_is_unused(dkey->key) &&
(dst_key_goal(dkey->key) ==
OMNIPRESENT) &&
!keymgr_key_is_successor(
dkey->key,
active_key->key) &&
!keymgr_key_is_successor(
active_key->key, dkey->key))
{
/*
* Multiple signing keys match
* the kasp key configuration.
* Retire excess keys.
* Retire excess keys in use.
*/
keymgr_key_retire(dkey, now);
} else {
/* Save the matched key. */
active_key = dkey;
}
continue;
}
/*
* This is possibly an active key created
* outside dnssec-policy. Initialize goal,
* if not set.
*/
dst_key_state_t goal;
if (dst_key_getstate(dkey->key, DST_KEY_GOAL,
&goal) != ISC_R_SUCCESS) {
dst_key_setstate(dkey->key,
DST_KEY_GOAL,
OMNIPRESENT);
}
/*
* Save the matched key only if it is active
* or desires to be active.
*/
if (dst_key_goal(dkey->key) == OMNIPRESENT ||
dst_key_is_active(dkey->key, now)) {
active_key = dkey;
}
}
}
@@ -1377,7 +1466,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
isc_log_write(
dns_lctx, DNS_LOGCATEGORY_DNSSEC,
DNS_LOGMODULE_DNSSEC, ISC_LOG_DEBUG(1),
"keymgr: DNSKEY %s (%s) matches "
"keymgr: DNSKEY %s (%s) is active in "
"policy %s",
keystr, keymgr_keyrole(active_key->key),
dns_kasp_getname(kasp));
@@ -1446,6 +1535,7 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
dst_key_setttl(dst_key, dns_kasp_dnskeyttl(kasp));
dst_key_settime(dst_key, DST_TIME_CREATED, now);
RETERR(dns_dnsseckey_create(mctx, &dst_key, &newkey));
keymgr_key_init(newkey, kasp, now);
} else {
newkey = candidate;
dst_key_setnum(newkey->key, DST_NUM_LIFETIME, lifetime);
@@ -1512,27 +1602,6 @@ dns_keymgr_run(const dns_name_t *origin, dns_rdataclass_t rdclass,
ISC_LIST_APPENDLIST(*keyring, newkeys, link);
}
/* Initialize key states (for keys that don't have them yet). */
for (dns_dnsseckey_t *dkey = ISC_LIST_HEAD(*keyring); dkey != NULL;
dkey = ISC_LIST_NEXT(dkey, link))
{
bool ksk = false, zsk = false;
/* Set key states for all keys that do not have them. */
INITIALIZE_STATE(dkey->key, DST_KEY_DNSKEY, DST_TIME_DNSKEY);
(void)dst_key_getbool(dkey->key, DST_BOOL_KSK, &ksk);
if (ksk) {
INITIALIZE_STATE(dkey->key, DST_KEY_KRRSIG,
DST_TIME_KRRSIG);
INITIALIZE_STATE(dkey->key, DST_KEY_DS, DST_TIME_DS);
}
(void)dst_key_getbool(dkey->key, DST_BOOL_ZSK, &zsk);
if (zsk) {
INITIALIZE_STATE(dkey->key, DST_KEY_ZRRSIG,
DST_TIME_ZRRSIG);
}
}
/* Read to update key states. */
keymgr_update(keyring, kasp, now, nexttime);
+1 -2
View File
@@ -518,7 +518,6 @@ static bool
openssleddsa_isprivate(const dst_key_t *key) {
EVP_PKEY *pkey = key->keydata.pkey;
int len;
unsigned long err;
if (pkey == NULL) {
return (false);
@@ -529,7 +528,7 @@ openssleddsa_isprivate(const dst_key_t *key) {
return (true);
}
/* can check if first error is EC_R_INVALID_PRIVATE_KEY */
while ((err = ERR_get_error()) != 0) {
while (ERR_get_error() != 0) {
/**/
}
+129 -66
View File
@@ -1114,7 +1114,8 @@ trim_zbits(dns_rpz_zbits_t zbits, dns_rpz_zbits_t found) {
x = zbits & found;
x &= (~x + 1);
x = (x << 1) - 1;
return (zbits &= x);
zbits &= x;
return (zbits);
}
/*
@@ -1780,32 +1781,85 @@ cleanup:
static void
finish_update(dns_rpz_zone_t *rpz) {
isc_result_t result;
isc_ht_t *tmpht = NULL;
isc_ht_iter_t *iter = NULL;
dns_fixedname_t fname;
char dname[DNS_NAME_FORMATSIZE];
dns_name_t *name;
LOCK(&rpz->rpzs->maint_lock);
rpz->updaterunning = false;
/*
* Iterate over old ht with existing nodes deleted to delete
* deleted nodes from RPZ
* If there's an update pending, schedule it.
*/
result = isc_ht_iter_create(rpz->nodes, &iter);
if (result != ISC_R_SUCCESS) {
char domain[DNS_NAME_FORMATSIZE];
if (rpz->updatepending == true) {
if (rpz->min_update_interval > 0) {
uint64_t defer = rpz->min_update_interval;
char dname[DNS_NAME_FORMATSIZE];
isc_interval_t interval;
dns_name_format(&rpz->origin, domain, DNS_NAME_FORMATSIZE);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
"rpz: %s: failed to create HT iterator - %s",
domain, isc_result_totext(result));
goto cleanup;
dns_name_format(&rpz->origin, dname,
DNS_NAME_FORMATSIZE);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
"rpz: %s: new zone version came "
"too soon, deferring update for "
"%" PRIu64 " seconds",
dname, defer);
isc_interval_set(&interval, (unsigned int)defer, 0);
isc_timer_reset(rpz->updatetimer, isc_timertype_once,
NULL, &interval, true);
} else {
isc_event_t *event = NULL;
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
ISC_EVENT_INIT(&rpz->updateevent,
sizeof(rpz->updateevent), 0, NULL,
DNS_EVENT_RPZUPDATED,
dns_rpz_update_taskaction, rpz, rpz,
NULL, NULL);
event = &rpz->updateevent;
isc_task_send(rpz->rpzs->updater, &event);
}
}
UNLOCK(&rpz->rpzs->maint_lock);
}
static void
cleanup_quantum(isc_task_t *task, isc_event_t *event) {
isc_result_t result = ISC_R_SUCCESS;
char domain[DNS_NAME_FORMATSIZE];
dns_rpz_zone_t *rpz = NULL;
isc_ht_iter_t *iter = NULL;
dns_fixedname_t fname;
dns_name_t *name = NULL;
int count = 0;
UNUSED(task);
REQUIRE(event != NULL);
REQUIRE(event->ev_sender != NULL);
rpz = (dns_rpz_zone_t *)event->ev_sender;
iter = (isc_ht_iter_t *)event->ev_arg;
isc_event_free(&event);
if (iter == NULL) {
/*
* Iterate over old ht with existing nodes deleted to
* delete deleted nodes from RPZ
*/
result = isc_ht_iter_create(rpz->nodes, &iter);
if (result != ISC_R_SUCCESS) {
dns_name_format(&rpz->origin, domain,
DNS_NAME_FORMATSIZE);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_MASTER, ISC_LOG_ERROR,
"rpz: %s: failed to create HT "
"iterator - %s",
domain, isc_result_totext(result));
goto cleanup;
}
}
name = dns_fixedname_initname(&fname);
for (result = isc_ht_iter_first(iter); result == ISC_R_SUCCESS;
for (result = isc_ht_iter_first(iter);
result == ISC_R_SUCCESS && count++ < DNS_RPZ_QUANTUM;
result = isc_ht_iter_delcurrent_next(iter))
{
isc_region_t region;
@@ -1819,58 +1873,62 @@ finish_update(dns_rpz_zone_t *rpz) {
dns_rpz_delete(rpz->rpzs, rpz->num, name);
}
tmpht = rpz->nodes;
rpz->nodes = rpz->newnodes;
rpz->newnodes = tmpht;
if (result == ISC_R_SUCCESS) {
isc_event_t *nevent = NULL;
LOCK(&rpz->rpzs->maint_lock);
rpz->updaterunning = false;
/*
* If there's an update pending schedule it
*/
if (rpz->updatepending == true) {
if (rpz->min_update_interval > 0) {
uint64_t defer = rpz->min_update_interval;
isc_interval_t interval;
dns_name_format(&rpz->origin, dname,
DNS_NAME_FORMATSIZE);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
"rpz: %s: new zone version came "
"too soon, deferring update for "
"%" PRIu64 " seconds",
dname, defer);
isc_interval_set(&interval, (unsigned int)defer, 0);
isc_timer_reset(rpz->updatetimer, isc_timertype_once,
NULL, &interval, true);
} else {
isc_event_t *event;
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
ISC_EVENT_INIT(&rpz->updateevent,
sizeof(rpz->updateevent), 0, NULL,
DNS_EVENT_RPZUPDATED,
dns_rpz_update_taskaction, rpz, rpz,
NULL, NULL);
event = &rpz->updateevent;
isc_task_send(rpz->rpzs->updater, &event);
}
/*
* We finished a quantum; trigger the next one and return.
*/
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
NULL, DNS_EVENT_RPZUPDATED, cleanup_quantum,
iter, rpz, NULL, NULL);
nevent = &rpz->updateevent;
isc_task_send(rpz->rpzs->updater, &nevent);
return;
} else if (result == ISC_R_NOMORE) {
isc_ht_t *tmpht = NULL;
/*
* Done with cleanup of deleted nodes; finalize
* the update.
*/
tmpht = rpz->nodes;
rpz->nodes = rpz->newnodes;
rpz->newnodes = tmpht;
finish_update(rpz);
dns_name_format(&rpz->origin, domain, DNS_NAME_FORMATSIZE);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
"rpz: %s: reload done", domain);
}
UNLOCK(&rpz->rpzs->maint_lock);
/*
* If we're here, we're finished or something went wrong.
*/
cleanup:
if (iter != NULL) {
isc_ht_iter_destroy(&iter);
}
if (rpz->newnodes != NULL) {
isc_ht_destroy(&rpz->newnodes);
}
dns_db_closeversion(rpz->updb, &rpz->updbversion, false);
dns_db_detach(&rpz->updb);
rpz_detach(&rpz);
}
static void
update_quantum(isc_task_t *task, isc_event_t *event) {
isc_result_t result = ISC_R_SUCCESS;
dns_dbnode_t *node = NULL;
dns_rpz_zone_t *rpz;
dns_rpz_zone_t *rpz = NULL;
char domain[DNS_NAME_FORMATSIZE];
dns_fixedname_t fixname;
dns_name_t *name;
dns_name_t *name = NULL;
isc_event_t *nevent = NULL;
int count = 0;
UNUSED(task);
@@ -1974,13 +2032,13 @@ update_quantum(isc_task_t *task, isc_event_t *event) {
}
if (result == ISC_R_SUCCESS) {
isc_event_t *nevent;
/*
* Pause the iterator so that the DB is not locked
* Pause the iterator so that the DB is not locked.
*/
dns_dbiterator_pause(rpz->updbit);
/*
* We finished a quantum; trigger the next one and return
* We finished a quantum; trigger the next one and return.
*/
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
@@ -1991,17 +2049,22 @@ update_quantum(isc_task_t *task, isc_event_t *event) {
return;
} else if (result == ISC_R_NOMORE) {
/*
* All done.
* Done with the new database; now we just need to
* clean up the old.
*/
finish_update(rpz);
isc_log_write(dns_lctx, DNS_LOGCATEGORY_GENERAL,
DNS_LOGMODULE_MASTER, ISC_LOG_INFO,
"rpz: %s: reload done", domain);
dns_dbiterator_destroy(&rpz->updbit);
INSIST(!ISC_LINK_LINKED(&rpz->updateevent, ev_link));
ISC_EVENT_INIT(&rpz->updateevent, sizeof(rpz->updateevent), 0,
NULL, DNS_EVENT_RPZUPDATED, cleanup_quantum,
NULL, rpz, NULL, NULL);
nevent = &rpz->updateevent;
isc_task_send(rpz->rpzs->updater, &nevent);
return;
}
/*
* If we're here, we've either finished or something went wrong,
* so clean up.
* If we're here, something went wrong, so clean up.
*/
if (rpz->updbit != NULL) {
dns_dbiterator_destroy(&rpz->updbit);
+106 -8
View File
@@ -20,6 +20,7 @@
#include <isc/stats.h>
#include <isc/util.h>
#include <dns/log.h>
#include <dns/opcode.h>
#include <dns/rdatatype.h>
#include <dns/stats.h>
@@ -93,8 +94,19 @@ typedef enum {
*/
#define RDTYPECOUNTER_MAXVAL 0x0602
/* dnssec maximum key id */
static int dnssec_keyid_max = 65535;
/*
* DNSSEC sign statistics.
*
* Per key we maintain 3 counters. The first is actually no counter but
* a key id reference. The second is the number of signatures the key created.
* The third is the number of signatures refreshed by the key.
*/
/* Maximum number of keys to keep track of for DNSSEC signing statistics. */
static int dnssecsign_max_keys = 4;
static int dnssecsign_block_size = 3;
/* Key id mask */
#define DNSSECSIGNSTATS_KEY_ID_MASK 0x0000FFFF
struct dns_stats {
unsigned int magic;
@@ -228,8 +240,12 @@ isc_result_t
dns_dnssecsignstats_create(isc_mem_t *mctx, dns_stats_t **statsp) {
REQUIRE(statsp != NULL && *statsp == NULL);
return (create_stats(mctx, dns_statstype_dnssec, dnssec_keyid_max,
statsp));
/*
* Create two counters per key, one is the key id, the other two are
* the actual counters for creating and refreshing signatures.
*/
return (create_stats(mctx, dns_statstype_dnssec,
dnssecsign_max_keys * 3, statsp));
}
/*%
@@ -342,10 +358,64 @@ dns_rcodestats_increment(dns_stats_t *stats, dns_rcode_t code) {
}
void
dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id) {
dns_dnssecsignstats_increment(dns_stats_t *stats, dns_keytag_t id, uint8_t alg,
dnssecsignstats_type_t operation) {
uint32_t kval;
REQUIRE(DNS_STATS_VALID(stats) && stats->type == dns_statstype_dnssec);
isc_stats_increment(stats->counters, (isc_statscounter_t)id);
/* Shift algorithm in front of key tag, which is 16 bits */
kval = (uint32_t)(alg << 16 | id);
/* Look up correct counter. */
for (int i = 0; i < dnssecsign_max_keys; i++) {
int idx = i * dnssecsign_block_size;
uint32_t counter = isc_stats_get_counter(stats->counters, idx);
if (counter == kval) {
/* Match */
isc_stats_increment(stats->counters, (idx + operation));
return;
}
}
/* No match found. Store key in unused slot. */
for (int i = 0; i < dnssecsign_max_keys; i++) {
int idx = i * dnssecsign_block_size;
uint32_t counter = isc_stats_get_counter(stats->counters, idx);
if (counter == 0) {
isc_stats_set(stats->counters, kval, idx);
isc_stats_increment(stats->counters, (idx + operation));
return;
}
}
/* No room, rotate keys. */
for (int i = 1; i < dnssecsign_max_keys; i++) {
int gidx = i * dnssecsign_block_size; /* Get key (get index,
gidx) */
uint32_t keyv = isc_stats_get_counter(stats->counters, gidx);
uint32_t sign = isc_stats_get_counter(
stats->counters, (gidx + dns_dnssecsignstats_sign));
uint32_t refr = isc_stats_get_counter(
stats->counters, (gidx + dns_dnssecsignstats_refresh));
int sidx = (i - 1) * dnssecsign_block_size; /* Set key, (set
index, sidx) */
isc_stats_set(stats->counters, keyv, sidx);
isc_stats_set(stats->counters, sign,
(sidx + dns_dnssecsignstats_sign));
isc_stats_set(stats->counters, refr,
(sidx + dns_dnssecsignstats_refresh));
}
/* Reset counters for new key (new index, nidx). */
int nidx = (dnssecsign_max_keys - 1) * dnssecsign_block_size;
isc_stats_set(stats->counters, kval, nidx);
isc_stats_set(stats->counters, 0, (nidx + dns_dnssecsignstats_sign));
isc_stats_set(stats->counters, 0, (nidx + dns_dnssecsignstats_refresh));
/* And increment the counter for the given operation. */
isc_stats_increment(stats->counters, (nidx + operation));
}
/*%
@@ -452,8 +522,34 @@ dnssec_dumpcb(isc_statscounter_t counter, uint64_t value, void *arg) {
dnssecarg->fn((dns_keytag_t)counter, value, dnssecarg->arg);
}
static void
dnssec_statsdump(isc_stats_t *stats, dnssecsignstats_type_t operation,
isc_stats_dumper_t dump_fn, void *arg, unsigned int options) {
int i;
for (i = 0; i < dnssecsign_max_keys; i++) {
int idx = dnssecsign_block_size * i;
uint32_t kval, val;
dns_keytag_t id;
kval = isc_stats_get_counter(stats, idx);
if (kval == 0) {
continue;
}
val = isc_stats_get_counter(stats, (idx + operation));
if ((options & ISC_STATSDUMP_VERBOSE) == 0 && val == 0) {
continue;
}
id = (dns_keytag_t)kval & DNSSECSIGNSTATS_KEY_ID_MASK;
dump_fn((isc_statscounter_t)id, val, arg);
}
}
void
dns_dnssecsignstats_dump(dns_stats_t *stats,
dns_dnssecsignstats_dump(dns_stats_t *stats, dnssecsignstats_type_t operation,
dns_dnssecsignstats_dumper_t dump_fn, void *arg0,
unsigned int options) {
dnssecsigndumparg_t arg;
@@ -462,7 +558,9 @@ dns_dnssecsignstats_dump(dns_stats_t *stats,
arg.fn = dump_fn;
arg.arg = arg0;
isc_stats_dump(stats->counters, dnssec_dumpcb, &arg, options);
dnssec_statsdump(stats->counters, operation, dnssec_dumpcb, &arg,
options);
}
static void
+4 -1
View File
@@ -1117,6 +1117,7 @@ add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
#define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
#define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
#define ID(x) dst_key_id(x)
#define ALG(x) dst_key_alg(x)
/*
@@ -1260,7 +1261,9 @@ add_sigs(dns_update_log_t *log, dns_zone_t *zone, dns_db_t *db,
/* Update DNSSEC sign statistics. */
if (dnssecsignstats != NULL) {
dns_dnssecsignstats_increment(dnssecsignstats,
dst_key_id(keys[i]));
ID(keys[i]),
(uint8_t)ALG(keys[i]),
dns_dnssecsignstats_sign);
}
}
if (!added_sig) {
-2
View File
@@ -1194,7 +1194,6 @@ dns_zone_getchecknames
dns_zone_getclass
dns_zone_getdb
dns_zone_getdbtype
dns_zone_getdnssecrefreshstats
dns_zone_getdnssecsignstats
dns_zone_getexpiretime
dns_zone_getfile
@@ -1298,7 +1297,6 @@ dns_zone_setclass
dns_zone_setdb
dns_zone_setdbtype
dns_zone_setdialup
dns_zone_setdnssecrefreshstats
dns_zone_setdnssecsignstats
dns_zone_setfile
dns_zone_setflag
+17 -41
View File
@@ -120,6 +120,7 @@
*/
#define REVOKE(x) ((dst_key_flags(x) & DNS_KEYFLAG_REVOKE) != 0)
#define KSK(x) ((dst_key_flags(x) & DNS_KEYFLAG_KSK) != 0)
#define ID(x) dst_key_id(x)
#define ALG(x) dst_key_alg(x)
/*
@@ -338,7 +339,6 @@ struct dns_zone {
isc_stats_t *requeststats;
dns_stats_t *rcvquerystats;
dns_stats_t *dnssecsignstats;
dns_stats_t *dnssecrefreshstats;
uint32_t notifydelay;
dns_isselffunc_t isself;
void *isselfarg;
@@ -1091,7 +1091,6 @@ dns_zone_create(dns_zone_t **zonep, isc_mem_t *mctx) {
zone->requeststats = NULL;
zone->rcvquerystats = NULL;
zone->dnssecsignstats = NULL;
zone->dnssecrefreshstats = NULL;
zone->notifydelay = 5;
zone->isself = NULL;
zone->isselfarg = NULL;
@@ -1270,9 +1269,6 @@ zone_free(dns_zone_t *zone) {
if (zone->dnssecsignstats != NULL) {
dns_stats_detach(&zone->dnssecsignstats);
}
if (zone->dnssecrefreshstats != NULL) {
dns_stats_detach(&zone->dnssecrefreshstats);
}
if (zone->db != NULL) {
zone_detachdb(zone);
}
@@ -6752,7 +6748,6 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_zone_t *zone,
dns_dbnode_t *node = NULL;
dns_kasp_t *kasp = dns_zone_getkasp(zone);
dns_stats_t *dnssecsignstats;
dns_stats_t *dnssecrefreshstats;
dns_rdataset_t rdataset;
dns_rdata_t sig_rdata = DNS_RDATA_INIT;
unsigned char data[1024]; /* XXX */
@@ -6926,16 +6921,17 @@ add_sigs(dns_db_t *db, dns_dbversion_t *ver, dns_name_t *name, dns_zone_t *zone,
/* Update DNSSEC sign statistics. */
dnssecsignstats = dns_zone_getdnssecsignstats(zone);
dnssecrefreshstats = dns_zone_getdnssecrefreshstats(zone);
if (dnssecsignstats != NULL) {
/* Generated a new signature. */
dns_dnssecsignstats_increment(dnssecsignstats,
ID(keys[i]),
(uint8_t)ALG(keys[i]),
dns_dnssecsignstats_sign);
/* This is a refresh. */
dns_dnssecsignstats_increment(
dns_zone_getdnssecsignstats(zone),
dst_key_id(keys[i]));
}
if (dnssecrefreshstats != NULL) {
dns_dnssecsignstats_increment(
dns_zone_getdnssecrefreshstats(zone),
dst_key_id(keys[i]));
dnssecsignstats, ID(keys[i]),
(uint8_t)ALG(keys[i]),
dns_dnssecsignstats_refresh);
}
}
@@ -7396,7 +7392,6 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
dns_rdataset_t rdataset;
dns_rdata_t rdata = DNS_RDATA_INIT;
dns_stats_t *dnssecsignstats;
dns_stats_t *dnssecrefreshstats;
isc_buffer_t buffer;
unsigned char data[1024];
@@ -7515,16 +7510,15 @@ sign_a_node(dns_db_t *db, dns_zone_t *zone, dns_name_t *name,
/* Update DNSSEC sign statistics. */
dnssecsignstats = dns_zone_getdnssecsignstats(zone);
dnssecrefreshstats = dns_zone_getdnssecrefreshstats(zone);
if (dnssecsignstats != NULL) {
/* Generated a new signature. */
dns_dnssecsignstats_increment(dnssecsignstats, ID(key),
ALG(key),
dns_dnssecsignstats_sign);
/* This is a refresh. */
dns_dnssecsignstats_increment(
dns_zone_getdnssecsignstats(zone),
dst_key_id(key));
}
if (dnssecrefreshstats != NULL) {
dns_dnssecsignstats_increment(
dns_zone_getdnssecrefreshstats(zone),
dst_key_id(key));
dnssecsignstats, ID(key), ALG(key),
dns_dnssecsignstats_refresh);
}
(*signatures)--;
@@ -18458,17 +18452,6 @@ dns_zone_setdnssecsignstats(dns_zone_t *zone, dns_stats_t *stats) {
UNLOCK_ZONE(zone);
}
void
dns_zone_setdnssecrefreshstats(dns_zone_t *zone, dns_stats_t *stats) {
REQUIRE(DNS_ZONE_VALID(zone));
LOCK_ZONE(zone);
if (stats != NULL && zone->dnssecrefreshstats == NULL) {
dns_stats_attach(stats, &zone->dnssecrefreshstats);
}
UNLOCK_ZONE(zone);
}
dns_stats_t *
dns_zone_getdnssecsignstats(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
@@ -18476,13 +18459,6 @@ dns_zone_getdnssecsignstats(dns_zone_t *zone) {
return (zone->dnssecsignstats);
}
dns_stats_t *
dns_zone_getdnssecrefreshstats(dns_zone_t *zone) {
REQUIRE(DNS_ZONE_VALID(zone));
return (zone->dnssecrefreshstats);
}
isc_stats_t *
dns_zone_getrequeststats(dns_zone_t *zone) {
/*
+6 -14
View File
@@ -177,9 +177,9 @@ isc_nm_listenudp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
*/
void
isc_nm_udp_stoplistening(isc_nmsocket_t *sock);
isc_nm_stoplistening(isc_nmsocket_t *sock);
/*%<
* Stop listening for UDP packets on socket 'sock'.
* Stop listening on socket 'sock'.
*/
void
@@ -226,6 +226,10 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
* in 'cb'.
*/
isc_result_t
isc_nm_connecttcp(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *remote, isc_nm_cb_t cb);
isc_result_t
isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
void *cbarg, size_t extrahandlesize, int backlog,
@@ -251,12 +255,6 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
* prepended with a two-byte length field, and handles buffering.
*/
void
isc_nm_tcp_stoplistening(isc_nmsocket_t *sock);
/*%<
* Stop listening on TCP socket 'sock'.
*/
isc_result_t
isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
void *cbarg, isc_nm_cb_t accept_cb, void *accept_cbarg,
@@ -285,12 +283,6 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
* 'quota' is passed to isc_nm_listentcp() when opening the raw TCP socket.
*/
void
isc_nm_tcpdns_stoplistening(isc_nmsocket_t *sock);
/*%<
* Stop listening on TCPDNS socket 'sock'.
*/
void
isc_nm_tcpdns_sequential(isc_nmhandle_t *handle);
/*%<
+38 -21
View File
@@ -40,11 +40,23 @@
ISC_LANG_BEGINDECLS
/*% isc_quota_cb - quota callback structure */
typedef struct isc_quota_cb isc_quota_cb_t;
typedef void (*isc_quota_cb_func_t)(isc_quota_t *quota, void *data);
struct isc_quota_cb {
isc_quota_cb_func_t cb_func;
void * data;
ISC_LINK(isc_quota_cb_t) link;
};
/*% isc_quota structure */
struct isc_quota {
atomic_uint_fast32_t max;
atomic_uint_fast32_t used;
atomic_uint_fast32_t soft;
atomic_uint_fast32_t waiting;
isc_mutex_t cblock;
ISC_LIST(isc_quota_cb_t) cbs;
};
void
@@ -90,41 +102,46 @@ isc_quota_getused(isc_quota_t *quota);
*/
isc_result_t
isc_quota_reserve(isc_quota_t *quota);
isc_quota_attach(isc_quota_t *quota, isc_quota_t **p);
/*%<
* Attempt to reserve one unit of 'quota'.
*
* Attempt to reserve one unit of 'quota', and also attaches '*p' to the quota
* if successful (ISC_R_SUCCESS or ISC_R_SOFTQUOTA).
*
* Returns:
* \li #ISC_R_SUCCESS Success
* \li #ISC_R_SUCCESS Success
* \li #ISC_R_SOFTQUOTA Success soft quota reached
* \li #ISC_R_QUOTA Quota is full
*/
isc_result_t
isc_quota_attach_cb(isc_quota_t *quota, isc_quota_t **p, isc_quota_cb_t *cb);
/*%<
*
* Like isc_quota_attach(), but if there's no quota left then cb->cb_func will
* be called when we are attached to quota.
* Note: It's the callee responsibility to make sure that we don't end up with
* extremely huge number of callbacks waiting - making it easy to create a
* resource exhaustion attack. For example in case of TCP listening we simply
* don't accept new connections - so the number of callbacks waiting in the
* queue is limited by listen() backlog.
*
* Returns:
* \li #ISC_R_SUCCESS Success
* \li #ISC_R_SOFTQUOTA Success soft quota reached
* \li #ISC_R_QUOTA Quota is full
*/
void
isc_quota_release(isc_quota_t *quota);
isc_quota_cb_init(isc_quota_cb_t *cb, isc_quota_cb_func_t cb_func, void *data);
/*%<
* Release one unit of quota.
*/
isc_result_t
isc_quota_attach(isc_quota_t *quota, isc_quota_t **p);
/*%<
* Like isc_quota_reserve, and also attaches '*p' to the
* quota if successful (ISC_R_SUCCESS or ISC_R_SOFTQUOTA).
*/
isc_result_t
isc_quota_force(isc_quota_t *quota, isc_quota_t **p);
/*%<
* Like isc_quota_attach, but will attach '*p' to the quota
* even if the hard quota has been exceeded.
* Initialize isc_quota_cb_t - setup the list, set the callback and data.
*/
void
isc_quota_detach(isc_quota_t **p);
/*%<
* Like isc_quota_release, and also detaches '*p' from the
* quota.
* Release one unit of quota, and also detaches '*p' from the quota.
*/
ISC_LANG_ENDDECLS
+2 -5
View File
@@ -79,11 +79,8 @@ struct isc_rwlock {
#endif /* USE_PTHREAD_RWLOCK */
isc_result_t
isc__rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota, const char *file,
unsigned int line);
#define isc_rwlock_init(l, rq, wq) isc__rwlock_init((l), (rq), (wq),\
__FILE__, __LINE__)
isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota);
isc_result_t
isc_rwlock_lock(isc_rwlock_t *rwl, isc_rwlocktype_t type);
+90 -55
View File
@@ -112,7 +112,7 @@ struct isc_logconfig {
ISC_LIST(isc_logchannellist_t) * channellists;
unsigned int channellist_count;
unsigned int duplicate_interval;
int highest_level;
int_fast32_t highest_level;
char *tag;
bool dynamic;
};
@@ -142,7 +142,7 @@ struct isc_log {
unsigned int category_count;
isc_logmodule_t *modules;
unsigned int module_count;
int debug_level;
atomic_int_fast32_t debug_level;
isc_rwlock_t lcfg_rwl;
/* Locked by isc_log lcfg_rwl */
isc_logconfig_t *logconfig;
@@ -150,6 +150,8 @@ struct isc_log {
/* Locked by isc_log lock. */
char buffer[LOG_BUFFER_SIZE];
ISC_LIST(isc_logmessage_t) messages;
atomic_bool dynamic;
atomic_int_fast32_t highest_level;
};
/*!
@@ -174,9 +176,9 @@ static const int syslog_map[] = { LOG_DEBUG, LOG_INFO, LOG_NOTICE,
* channellist in the log context, it must come first in isc_categories[].
*/
LIBISC_EXTERNAL_DATA isc_logcategory_t isc_categories[] = { { "default",
0 }, /* "default"
* must come
* first. */
0 }, /* "default
must come
first. */
{ "general", 0 },
{ NULL, 0 } };
@@ -211,6 +213,9 @@ assignchannel(isc_logconfig_t *lcfg, unsigned int category_id,
static void
sync_channellist(isc_logconfig_t *lcfg);
static void
sync_highest_level(isc_log_t *lctx, isc_logconfig_t *lcfg);
static isc_result_t
greatest_version(isc_logfile_t *file, int versions, int *greatest);
@@ -256,7 +261,7 @@ isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
lctx->category_count = 0;
lctx->modules = NULL;
lctx->module_count = 0;
lctx->debug_level = 0;
atomic_init(&lctx->debug_level, 0);
ISC_LIST_INIT(lctx->messages);
@@ -280,6 +285,9 @@ isc_log_create(isc_mem_t *mctx, isc_log_t **lctxp, isc_logconfig_t **lcfgp) {
lctx->logconfig = lcfg;
atomic_init(&lctx->highest_level, lcfg->highest_level);
atomic_init(&lctx->dynamic, lcfg->dynamic);
*lctxp = lctx;
if (lcfgp != NULL) {
*lcfgp = lcfg;
@@ -309,7 +317,7 @@ isc_logconfig_create(isc_log_t *lctx, isc_logconfig_t **lcfgp) {
/*
* Create the default channels:
* default_syslog, default_stderr, default_debug and null.
* default_syslog, default_stderr, default_debug and null.
*/
destination.facility = LOG_DAEMON;
isc_log_createchannel(lcfg, "default_syslog", ISC_LOG_TOSYSLOG, level,
@@ -362,6 +370,7 @@ isc_logconfig_use(isc_log_t *lctx, isc_logconfig_t *lcfg) {
WRLOCK(&lctx->lcfg_rwl);
old_cfg = lctx->logconfig;
lctx->logconfig = lcfg;
sync_highest_level(lctx, lcfg);
WRUNLOCK(&lctx->lcfg_rwl);
isc_logconfig_destroy(&old_cfg);
@@ -380,6 +389,11 @@ isc_log_destroy(isc_log_t **lctxp) {
*lctxp = NULL;
mctx = lctx->mctx;
/* Stop the logging as a first thing */
atomic_store_release(&lctx->debug_level, 0);
atomic_store_release(&lctx->highest_level, 0);
atomic_store_release(&lctx->dynamic, false);
WRLOCK(&lctx->lcfg_rwl);
lcfg = lctx->logconfig;
lctx->logconfig = NULL;
@@ -400,7 +414,6 @@ isc_log_destroy(isc_log_t **lctxp) {
}
lctx->buffer[0] = '\0';
lctx->debug_level = 0;
lctx->categories = NULL;
lctx->category_count = 0;
lctx->modules = NULL;
@@ -745,6 +758,13 @@ isc_log_usechannel(isc_logconfig_t *lcfg, const char *name,
}
}
/*
* Update the highest logging level, if the current lcfg is in use.
*/
if (lcfg->lctx->logconfig == lcfg) {
sync_highest_level(lctx, lcfg);
}
return (ISC_R_SUCCESS);
}
@@ -805,7 +825,7 @@ void
isc_log_setdebuglevel(isc_log_t *lctx, unsigned int level) {
REQUIRE(VALID_CONTEXT(lctx));
lctx->debug_level = level;
atomic_store_release(&lctx->debug_level, level);
/*
* Close ISC_LOG_DEBUGONLY channels if level is zero.
*/
@@ -837,7 +857,7 @@ unsigned int
isc_log_getdebuglevel(isc_log_t *lctx) {
REQUIRE(VALID_CONTEXT(lctx));
return (lctx->debug_level);
return (atomic_load_acquire(&lctx->debug_level));
}
void
@@ -988,6 +1008,12 @@ sync_channellist(isc_logconfig_t *lcfg) {
lcfg->channellist_count = lctx->category_count;
}
static void
sync_highest_level(isc_log_t *lctx, isc_logconfig_t *lcfg) {
atomic_store(&lctx->highest_level, lcfg->highest_level);
atomic_store(&lctx->dynamic, lcfg->dynamic);
}
static isc_result_t
greatest_version(isc_logfile_t *file, int versions, int *greatestp) {
char *bname, *digit_end;
@@ -1414,7 +1440,6 @@ isc_log_open(isc_logchannel_t *channel) {
bool
isc_log_wouldlog(isc_log_t *lctx, int level) {
bool ret = false;
/*
* Try to avoid locking the mutex for messages which can't
* possibly be logged to any channels -- primarily debugging
@@ -1429,15 +1454,16 @@ isc_log_wouldlog(isc_log_t *lctx, int level) {
return (false);
}
RDLOCK(&lctx->lcfg_rwl);
isc_logconfig_t *lcfg = lctx->logconfig;
if (lcfg != NULL) {
ret = (level <= lcfg->highest_level ||
(lcfg->dynamic && level <= lctx->debug_level));
if (level <= atomic_load_acquire(&lctx->highest_level)) {
return (true);
}
if (atomic_load_acquire(&lctx->dynamic) &&
level <= atomic_load_acquire(&lctx->debug_level))
{
return (true);
}
RDUNLOCK(&lctx->lcfg_rwl);
return (ret);
return (false);
}
static void
@@ -1494,13 +1520,13 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
category_channels = ISC_LIST_HEAD(lcfg->channellists[category->id]);
/*
* XXXDCL add duplicate filtering? (To not write multiple times to
* the same source via various channels).
* XXXDCL add duplicate filtering? (To not write multiple times
* to the same source via various channels).
*/
do {
/*
* If the channel list end was reached and a match was made,
* everything is finished.
* If the channel list end was reached and a match was
* made, everything is finished.
*/
if (category_channels == NULL && matched) {
break;
@@ -1510,8 +1536,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
category_channels != ISC_LIST_HEAD(lcfg->channellists[0]))
{
/*
* No category/module pair was explicitly configured.
* Try the category named "default".
* No category/module pair was explicitly
* configured. Try the category named "default".
*/
category_channels =
ISC_LIST_HEAD(lcfg->channellists[0]);
@@ -1520,8 +1546,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
if (category_channels == NULL && !matched) {
/*
* No matching module was explicitly configured
* for the category named "default". Use the internal
* default channel.
* for the category named "default". Use the
* internal default channel.
*/
category_channels = &default_channel;
}
@@ -1538,13 +1564,14 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
channel = category_channels->channel;
category_channels = ISC_LIST_NEXT(category_channels, link);
if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) &&
lctx->debug_level == 0) {
int_fast32_t dlevel = atomic_load_acquire(&lctx->debug_level);
if (((channel->flags & ISC_LOG_DEBUGONLY) != 0) && dlevel == 0)
{
continue;
}
if (channel->level == ISC_LOG_DYNAMIC) {
if (lctx->debug_level < level) {
if (dlevel < level) {
continue;
}
} else if (channel->level < level) {
@@ -1600,17 +1627,18 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
lcfg->duplicate_interval, 0);
/*
* 'oldest' is the age of the oldest messages
* which fall within the duplicate_interval
* range.
* 'oldest' is the age of the oldest
* messages which fall within the
* duplicate_interval range.
*/
TIME_NOW(&oldest);
if (isc_time_subtract(&oldest, &interval,
&oldest) != ISC_R_SUCCESS)
{
/*
* Can't effectively do the checking
* without having a valid time.
* Can't effectively do the
* checking without having a
* valid time.
*/
message = NULL;
} else {
@@ -1622,15 +1650,18 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
&oldest) < 0) {
/*
* This message is older
* than the duplicate_interval,
* so it should be dropped from
* the history.
* than the
* duplicate_interval,
* so it should be
* dropped from the
* history.
*
* Setting the interval to be
* to be longer will obviously
* not cause the expired
* message to spring back into
* existence.
* Setting the interval
* to be to be longer
* will obviously not
* cause the expired
* message to spring
* back into existence.
*/
next = ISC_LIST_NEXT(message,
link);
@@ -1648,15 +1679,17 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
}
/*
* This message is in the duplicate
* filtering interval ...
* This message is in the
* duplicate filtering interval
* ...
*/
if (strcmp(lctx->buffer,
message->text) == 0) {
/*
* ... and it is a duplicate.
* Unlock the mutex and
* get the hell out of Dodge.
* ... and it is a
* duplicate. Unlock the
* mutex and get the
* hell out of Dodge.
*/
goto unlock;
}
@@ -1713,11 +1746,12 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
/*
* If the file can be rolled, OR
* If the file no longer exists, OR
* If the file is less than the maximum size,
* (such as if it had been renamed and
* a new one touched, or it was truncated
* in place)
* ... then close it to trigger reopening.
* If the file is less than the maximum
* size, (such as if it had been renamed
* and a new one touched, or it was
* truncated in place)
* ... then close it to trigger
* reopening.
*/
if (FILE_VERSIONS(channel) !=
ISC_LOG_ROLLNEVER ||
@@ -1743,7 +1777,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
(channel->flags & ISC_LOG_OPENERR) == 0)
{
syslog(LOG_ERR,
"isc_log_open '%s' failed: %s",
"isc_log_open '%s' "
"failed: %s",
FILE_NAME(channel),
isc_result_totext(result));
channel->flags |= ISC_LOG_OPENERR;
@@ -1774,8 +1809,8 @@ isc_log_doit(isc_log_t *lctx, isc_logcategory_t *category,
/*
* If the file now exceeds its maximum size
* threshold, note it so that it will not be logged
* to any more.
* threshold, note it so that it will not be
* logged to any more.
*/
if (FILE_MAXSIZE(channel) > 0) {
INSIST(channel->type == ISC_LOG_TOFILE);
+60 -30
View File
@@ -22,6 +22,7 @@
#include <isc/mem.h>
#include <isc/netmgr.h>
#include <isc/queue.h>
#include <isc/quota.h>
#include <isc/random.h>
#include <isc/refcount.h>
#include <isc/region.h>
@@ -124,20 +125,22 @@ struct isc_nmiface {
typedef enum isc__netievent_type {
netievent_udpsend,
netievent_udprecv,
netievent_udpstop,
netievent_tcpconnect,
netievent_tcpsend,
netievent_tcprecv,
netievent_tcpstartread,
netievent_tcppauseread,
netievent_tcpchildlisten,
netievent_tcpchildstop,
netievent_closecb,
netievent_shutdown,
netievent_stop,
netievent_udpstop,
netievent_tcpchildaccept,
netievent_tcpaccept,
netievent_tcpstop,
netievent_tcpclose,
netievent_tcpdnsclose,
netievent_closecb,
netievent_shutdown,
netievent_stop,
netievent_prio = 0xff, /* event type values higher than this
* will be treated as high-priority
* events, which can be processed
@@ -178,6 +181,7 @@ typedef union {
typedef struct isc__nm_uvreq {
int magic;
isc_nm_t *mgr;
isc_nmsocket_t *sock;
isc_nmhandle_t *handle;
uv_buf_t uvbuf; /* translated isc_region_t, to be
@@ -186,8 +190,7 @@ typedef struct isc__nm_uvreq {
isc_sockaddr_t peer; /* peer address */
isc__nm_cb_t cb; /* callback */
void *cbarg; /* callback argument */
uv_pipe_t ipc; /* used for sending socket
* uv_handles to other threads */
union {
uv_req_t req;
uv_getaddrinfo_t getaddrinfo;
@@ -209,11 +212,11 @@ typedef struct isc__netievent__socket {
typedef isc__netievent__socket_t isc__netievent_udplisten_t;
typedef isc__netievent__socket_t isc__netievent_udpstop_t;
typedef isc__netievent__socket_t isc__netievent_tcpstop_t;
typedef isc__netievent__socket_t isc__netievent_tcpchildstop_t;
typedef isc__netievent__socket_t isc__netievent_tcpclose_t;
typedef isc__netievent__socket_t isc__netievent_tcpdnsclose_t;
typedef isc__netievent__socket_t isc__netievent_startread_t;
typedef isc__netievent__socket_t isc__netievent_pauseread_t;
typedef isc__netievent__socket_t isc__netievent_closecb_t;
typedef struct isc__netievent__socket_req {
isc__netievent_type type;
@@ -225,13 +228,15 @@ typedef isc__netievent__socket_req_t isc__netievent_tcpconnect_t;
typedef isc__netievent__socket_req_t isc__netievent_tcplisten_t;
typedef isc__netievent__socket_req_t isc__netievent_tcpsend_t;
typedef struct isc__netievent__socket_streaminfo {
typedef struct isc__netievent__socket_streaminfo_quota {
isc__netievent_type type;
isc_nmsocket_t *sock;
isc_uv_stream_info_t streaminfo;
} isc__netievent__socket_streaminfo_t;
isc_quota_t *quota;
} isc__netievent__socket_streaminfo_quota_t;
typedef isc__netievent__socket_streaminfo_t isc__netievent_tcpchildlisten_t;
typedef isc__netievent__socket_streaminfo_quota_t
isc__netievent_tcpchildaccept_t;
typedef struct isc__netievent__socket_handle {
isc__netievent_type type;
@@ -239,7 +244,13 @@ typedef struct isc__netievent__socket_handle {
isc_nmhandle_t *handle;
} isc__netievent__socket_handle_t;
typedef isc__netievent__socket_handle_t isc__netievent_closecb_t;
typedef struct isc__netievent__socket_quota {
isc__netievent_type type;
isc_nmsocket_t *sock;
isc_quota_t *quota;
} isc__netievent__socket_quota_t;
typedef isc__netievent__socket_quota_t isc__netievent_tcpaccept_t;
typedef struct isc__netievent_udpsend {
isc__netievent_type type;
@@ -260,7 +271,8 @@ typedef union {
isc__netievent__socket_t nis;
isc__netievent__socket_req_t nisr;
isc__netievent_udpsend_t nius;
isc__netievent__socket_streaminfo_t niss;
isc__netievent__socket_quota_t nisq;
isc__netievent__socket_streaminfo_quota_t nissq;
} isc__netievent_storage_t;
/*
@@ -323,7 +335,6 @@ typedef enum isc_nmsocket_type {
isc_nm_udplistener, /* Aggregate of nm_udpsocks */
isc_nm_tcpsocket,
isc_nm_tcplistener,
isc_nm_tcpchildlistener,
isc_nm_tcpdnslistener,
isc_nm_tcpdnssocket
} isc_nmsocket_type;
@@ -369,16 +380,7 @@ struct isc_nmsocket {
*/
isc_quota_t *quota;
isc_quota_t *pquota;
/*%
* How many connections we have not accepted due to quota?
* When we close a connection we need to accept a new one.
*/
int overquota;
/*%
* How many active connections we have?
*/
int conns;
isc_quota_cb_t quotacb;
/*%
* Socket statistics
@@ -597,11 +599,11 @@ isc__nm_uvreq_get(isc_nm_t *mgr, isc_nmsocket_t *sock);
*/
void
isc__nm_uvreq_put(isc__nm_uvreq_t **req, isc_nmsocket_t *sock);
isc__nm_uvreq_put(isc__nm_uvreq_t **req);
/*%<
* Completes the use of a UV request structure, setting '*req' to NULL.
*
* The UV request is pushed onto the 'sock->inactivereqs' stack or,
* The UV request is pushed onto the 'req->sock->inactivereqs' stack or,
* if that doesn't work, freed.
*/
@@ -647,6 +649,9 @@ isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
* Back-end implementation of isc_nm_send() for UDP handles.
*/
void
isc__nm_udp_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_async_udplisten(isc__networker_t *worker, isc__netievent_t *ev0);
@@ -665,11 +670,26 @@ isc__nm_tcp_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
* Back-end implementation of isc_nm_send() for TCP handles.
*/
isc_result_t
isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg);
void
isc__nm_tcp_close(isc_nmsocket_t *sock);
/*%<
* Close a TCP socket.
*/
isc_result_t
isc__nm_tcp_pauseread(isc_nmsocket_t *sock);
/*%<
* Pause reading on this socket, while still remembering the callback.
*/
isc_result_t
isc__nm_tcp_resumeread(isc_nmsocket_t *sock);
/*%<
* Resume reading from socket.
*
*/
void
isc__nm_tcp_shutdown(isc_nmsocket_t *sock);
@@ -677,23 +697,30 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock);
* Called on shutdown to close and clean up a listening TCP socket.
*/
void
isc__nm_tcp_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpchildlisten(isc__networker_t *worker, isc__netievent_t *ev0);
isc__nm_async_tcpaccept(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpchildaccept(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpstop(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpchildstop(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpsend(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_startread(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_pauseread(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcp_startread(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcp_pauseread(isc__networker_t *worker, isc__netievent_t *ev0);
void
isc__nm_async_tcpclose(isc__networker_t *worker, isc__netievent_t *ev0);
/*%<
* Callback handlers for asynchronous TCP events (connect, listen,
@@ -713,6 +740,9 @@ isc__nm_tcpdns_close(isc_nmsocket_t *sock);
* Close a TCPDNS socket.
*/
void
isc__nm_tcpdns_stoplistening(isc_nmsocket_t *sock);
void
isc__nm_async_tcpdnsclose(isc__networker_t *worker, isc__netievent_t *ev0);
+100 -38
View File
@@ -603,14 +603,17 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
case netievent_tcplisten:
isc__nm_async_tcplisten(worker, ievent);
break;
case netievent_tcpchildlisten:
isc__nm_async_tcpchildlisten(worker, ievent);
case netievent_tcpchildaccept:
isc__nm_async_tcpchildaccept(worker, ievent);
break;
case netievent_tcpaccept:
isc__nm_async_tcpaccept(worker, ievent);
break;
case netievent_tcpstartread:
isc__nm_async_startread(worker, ievent);
isc__nm_async_tcp_startread(worker, ievent);
break;
case netievent_tcppauseread:
isc__nm_async_pauseread(worker, ievent);
isc__nm_async_tcp_pauseread(worker, ievent);
break;
case netievent_tcpsend:
isc__nm_async_tcpsend(worker, ievent);
@@ -618,9 +621,6 @@ process_queue(isc__networker_t *worker, isc_queue_t *queue) {
case netievent_tcpstop:
isc__nm_async_tcpstop(worker, ievent);
break;
case netievent_tcpchildstop:
isc__nm_async_tcpchildstop(worker, ievent);
break;
case netievent_tcpclose:
isc__nm_async_tcpclose(worker, ievent);
break;
@@ -927,6 +927,7 @@ isc__nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
sock->ah_size * sizeof(size_t));
sock->ah_handles = isc_mem_allocate(
mgr->mctx, sock->ah_size * sizeof(isc_nmhandle_t *));
ISC_LINK_INIT(&sock->quotacb, link);
for (size_t i = 0; i < 32; i++) {
sock->ah_frees[i] = i;
sock->ah_handles[i] = NULL;
@@ -944,7 +945,6 @@ isc__nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
break;
case isc_nm_tcpsocket:
case isc_nm_tcplistener:
case isc_nm_tcpchildlistener:
if (family == AF_INET) {
sock->statsindex = tcp4statsindex;
} else {
@@ -1164,7 +1164,15 @@ isc_nmhandle_unref(isc_nmhandle_t *handle) {
}
/*
* The handle is closed. If the socket has a callback configured
* Temporarily reference the socket to ensure that it can't
* be deleted by another thread while we're deactivating the
* handle.
*/
isc_nmsocket_attach(sock, &tmp);
nmhandle_deactivate(sock, handle);
/*
* The handle is gone now. If the socket has a callback configured
* for that (e.g., to perform cleanup after request processing),
* call it now, or schedule it to run asynchronously.
*/
@@ -1174,27 +1182,16 @@ isc_nmhandle_unref(isc_nmhandle_t *handle) {
} else {
isc__netievent_closecb_t *event = isc__nm_get_ievent(
sock->mgr, netievent_closecb);
/*
* The socket will be finally detached by the closecb
* event handler.
*/
isc_nmsocket_attach(sock, &event->sock);
event->handle = handle;
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)event);
/*
* If we're doing this asynchronously, then the
* async event will take care of cleaning up the
* handle and closing the socket.
*/
return;
}
}
/*
* Temporarily reference the socket to ensure that it can't
* be deleted by another thread while we're deactivating the
* handle.
*/
isc_nmsocket_attach(sock, &tmp);
nmhandle_deactivate(sock, handle);
isc_nmsocket_detach(&tmp);
}
@@ -1249,7 +1246,7 @@ isc__nm_uvreq_get(isc_nm_t *mgr, isc_nmsocket_t *sock) {
isc__nm_uvreq_t *req = NULL;
REQUIRE(VALID_NM(mgr));
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock == NULL || VALID_NMSOCK(sock));
if (sock != NULL && atomic_load(&sock->active)) {
/* Try to reuse one */
@@ -1262,16 +1259,22 @@ isc__nm_uvreq_get(isc_nm_t *mgr, isc_nmsocket_t *sock) {
*req = (isc__nm_uvreq_t){ .magic = 0 };
req->uv_req.req.data = req;
isc_nmsocket_attach(sock, &req->sock);
isc_nm_attach(mgr, &req->mgr);
if (sock != NULL) {
isc_nmsocket_attach(sock, &req->sock);
}
req->magic = UVREQ_MAGIC;
return (req);
}
void
isc__nm_uvreq_put(isc__nm_uvreq_t **req0, isc_nmsocket_t *sock) {
isc__nm_uvreq_put(isc__nm_uvreq_t **req0) {
isc__nm_uvreq_t *req = NULL;
isc_nmhandle_t *handle = NULL;
isc_nmsocket_t *sock;
isc_nm_t *mgr;
bool reuse = false;
REQUIRE(req0 != NULL);
REQUIRE(VALID_UVREQ(*req0));
@@ -1279,8 +1282,6 @@ isc__nm_uvreq_put(isc__nm_uvreq_t **req0, isc_nmsocket_t *sock) {
req = *req0;
*req0 = NULL;
INSIST(sock == req->sock);
req->magic = 0;
/*
@@ -1288,18 +1289,25 @@ isc__nm_uvreq_put(isc__nm_uvreq_t **req0, isc_nmsocket_t *sock) {
* sock, and the netmgr won't all disappear.
*/
handle = req->handle;
req->handle = NULL;
if (!atomic_load(&sock->active) ||
!isc_astack_trypush(sock->inactivereqs, req)) {
isc_mempool_put(sock->mgr->reqpool, req);
sock = req->sock;
mgr = req->mgr;
*req = (isc__nm_uvreq_t){ .magic = 0 };
if (sock != NULL && atomic_load(&sock->active)) {
reuse = isc_astack_trypush(sock->inactivereqs, req);
}
if (!reuse) {
isc_mempool_put(mgr->reqpool, req);
}
if (handle != NULL) {
isc_nmhandle_unref(handle);
}
isc_nmsocket_detach(&sock);
if (sock != NULL) {
isc_nmsocket_detach(&sock);
}
isc_nm_detach(&mgr);
}
isc_result_t
@@ -1321,6 +1329,62 @@ isc_nm_send(isc_nmhandle_t *handle, isc_region_t *region, isc_nm_cb_t cb,
}
}
isc_result_t
isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
REQUIRE(VALID_NMHANDLE(handle));
switch (handle->sock->type) {
case isc_nm_tcpsocket:
return (isc__nm_tcp_read(handle, cb, cbarg));
default:
INSIST(0);
ISC_UNREACHABLE();
}
}
isc_result_t
isc_nm_pauseread(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
switch (sock->type) {
case isc_nm_tcpsocket:
return (isc__nm_tcp_pauseread(sock));
default:
INSIST(0);
ISC_UNREACHABLE();
}
}
isc_result_t
isc_nm_resumeread(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
switch (sock->type) {
case isc_nm_tcpsocket:
return (isc__nm_tcp_resumeread(sock));
default:
INSIST(0);
ISC_UNREACHABLE();
}
}
void
isc_nm_stoplistening(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
switch (sock->type) {
case isc_nm_udplistener:
isc__nm_udp_stoplistening(sock);
break;
case isc_nm_tcpdnslistener:
isc__nm_tcpdns_stoplistening(sock);
break;
case isc_nm_tcplistener:
isc__nm_tcp_stoplistening(sock);
break;
default:
INSIST(0);
ISC_UNREACHABLE();
}
}
void
isc__nm_async_closecb(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_closecb_t *ievent = (isc__netievent_closecb_t *)ev0;
@@ -1331,8 +1395,6 @@ isc__nm_async_closecb(isc__networker_t *worker, isc__netievent_t *ev0) {
UNUSED(worker);
nmhandle_deactivate(ievent->sock, ievent->handle);
ievent->sock->closehandle_cb(ievent->sock);
isc_nmsocket_detach(&ievent->sock);
}
+290 -314
View File
@@ -49,7 +49,7 @@ can_log_tcp_quota() {
}
static int
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req);
tcp_connect_direct(isc__nm_uvreq_t *req);
static void
tcp_close_direct(isc_nmsocket_t *sock);
@@ -68,21 +68,27 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
static void
tcp_close_cb(uv_handle_t *uvhandle);
static void
stoplistening(isc_nmsocket_t *sock);
static void
tcp_listenclose_cb(uv_handle_t *handle);
static isc_result_t
accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota);
static int
tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
isc__networker_t *worker = NULL;
tcp_connect_direct(isc__nm_uvreq_t *req) {
isc_nmsocket_t *sock;
isc__networker_t *worker;
int r;
REQUIRE(isc__nm_in_netthread());
worker = &req->mgr->workers[isc_nm_tid()];
worker = &sock->mgr->workers[isc_nm_tid()];
sock = isc_mem_get(req->mgr->mctx, sizeof(isc_nmsocket_t));
isc__nmsocket_init(sock, req->mgr, isc_nm_tcpsocket, NULL);
sock->tid = isc_nm_tid();
sock->extrahandlesize = 0;
r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
if (r != 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_OPENFAIL]);
return (r);
@@ -97,9 +103,13 @@ tcp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
return (r);
}
}
uv_handle_set_data(&sock->uv_handle.handle, sock);
r = uv_tcp_connect(&req->uv_req.connect, &sock->uv_handle.tcp,
&req->peer.type.sa, tcp_connect_cb);
if (r != 0) {
tcp_close_direct(sock);
}
return (r);
}
@@ -107,14 +117,11 @@ void
isc__nm_async_tcpconnect(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tcpconnect_t *ievent =
(isc__netievent_tcpconnect_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc__nm_uvreq_t *req = ievent->req;
UNUSED(worker);
int r;
REQUIRE(sock->type == isc_nm_tcpsocket);
REQUIRE(worker->id == ievent->req->sock->mgr->workers[isc_nm_tid()].id);
r = tcp_connect_direct(sock, req);
r = tcp_connect_direct(req);
if (r != 0) {
/* We need to issue callbacks ourselves */
tcp_connect_cb(&req->uv_req.connect, r);
@@ -153,9 +160,39 @@ tcp_connect_cb(uv_connect_t *uvreq, int status) {
req->cb.connect(NULL, isc__nm_uverr2result(status), req->cbarg);
}
isc__nm_uvreq_put(&req, sock);
isc__nm_uvreq_put(&req);
}
isc_result_t
isc_nm_connecttcp(isc_nm_t *mgr, isc_sockaddr_t *local, isc_sockaddr_t *remote, isc_nm_cb_t cb) {
isc__nm_uvreq_t *req;
isc__netievent_tcpconnect_t *ievent;
REQUIRE(VALID_NM(mgr));
req = isc__nm_uvreq_get(mgr, NULL);
if (local != NULL) {
req->local = *local;
}
req->peer = *remote;
req->cb.connect = cb;
ievent = isc__nm_get_ievent(mgr, netievent_tcpconnect);
ievent->req = req;
/*
* XXXWPK maybe we should always use random() and call connect
* directly if random value == isc_nm_tid()?
*/
if (isc__nm_in_netthread()) {
isc__nm_async_tcpconnect(&mgr->workers[isc_nm_tid()],
(isc__netievent_t *)ievent);
isc__nm_put_ievent(mgr, ievent);
} else {
int w = isc_random_uniform(mgr->nworkers);
isc__nm_enqueue_ievent(&mgr->workers[w],
(isc__netievent_t *)ievent);
}
return (ISC_R_SUCCESS);
}
isc_result_t
isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
void *cbarg, size_t extrahandlesize, int backlog,
@@ -167,11 +204,6 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
nsock = isc_mem_get(mgr->mctx, sizeof(*nsock));
isc__nmsocket_init(nsock, mgr, isc_nm_tcplistener, iface);
nsock->nchildren = mgr->nworkers;
atomic_init(&nsock->rchildren, mgr->nworkers);
nsock->children = isc_mem_get(mgr->mctx,
mgr->nworkers * sizeof(*nsock));
memset(nsock->children, 0, mgr->nworkers * sizeof(*nsock));
nsock->rcb.accept = cb;
nsock->rcbarg = cbarg;
nsock->extrahandlesize = extrahandlesize;
@@ -216,15 +248,10 @@ isc_nm_listentcp(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_cb_t cb,
}
/*
* For multi-threaded TCP listening, we create a single "parent" socket,
* bind to it, and then pass its uv_handle to a set of child sockets, one
* per worker. For thread safety, the passing of the socket's uv_handle has
* to be done via IPC socket.
*
* This design pattern is ugly but it's what's recommended by the libuv
* documentation. (A prior version of libuv had uv_export() and
* uv_import() functions which would have simplified this greatly, but
* they have been deprecated and removed.)
* For multi-threaded TCP listening, we create a single socket,
* bind to it, and start listening. On an incoming connection we accept
* it and then pass the accepted socket using uv_export/uv_import mechanism
* to child threads.
*/
void
isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
@@ -236,24 +263,6 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
REQUIRE(isc__nm_in_netthread());
REQUIRE(sock->type == isc_nm_tcplistener);
/* Initialize children now to make cleaning up easier */
for (int i = 0; i < sock->nchildren; i++) {
isc_nmsocket_t *csock = &sock->children[i];
isc__nmsocket_init(csock, sock->mgr, isc_nm_tcpchildlistener,
sock->iface);
csock->parent = sock;
csock->tid = i;
csock->pquota = sock->pquota;
csock->backlog = sock->backlog;
csock->extrahandlesize = sock->extrahandlesize;
INSIST(csock->rcb.recv == NULL && csock->rcbarg == NULL);
csock->rcb.accept = sock->rcb.accept;
csock->rcbarg = sock->rcbarg;
csock->fd = -1;
}
r = uv_tcp_init(&worker->loop, &sock->uv_handle.tcp);
if (r != 0) {
/* It was never opened */
@@ -295,39 +304,26 @@ isc__nm_async_tcplisten(isc__networker_t *worker, isc__netievent_t *ev0) {
goto done;
}
uv_handle_set_data(&sock->uv_handle.handle, sock);
/*
* For each worker, we send a 'tcpchildlisten' event with
* the exported socket.
* We're in the network thread - tcp_connection_cb won't be called
* until we leave, there's no race between this and the callback.
*/
for (int i = 0; i < sock->nchildren; i++) {
isc_nmsocket_t *csock = &sock->children[i];
isc__netievent_tcpchildlisten_t *event = NULL;
r = uv_listen((uv_stream_t *)&sock->uv_handle.tcp, sock->backlog,
tcp_connection_cb);
event = isc__nm_get_ievent(csock->mgr,
netievent_tcpchildlisten);
r = isc_uv_export(&sock->uv_handle.stream, &event->streaminfo);
if (r != 0) {
isc_log_write(
isc_lctx, ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
"uv_export failed: %s",
isc_result_totext(isc__nm_uverr2result(r)));
isc__nm_put_ievent(sock->mgr, event);
continue;
}
event->sock = csock;
if (csock->tid == isc_nm_tid()) {
isc__nm_async_tcpchildlisten(&sock->mgr->workers[i],
(isc__netievent_t *)event);
isc__nm_put_ievent(sock->mgr, event);
} else {
isc__nm_enqueue_ievent(&sock->mgr->workers[i],
(isc__netievent_t *)event);
}
if (r != 0) {
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
"uv_listen failed: %s",
isc_result_totext(isc__nm_uverr2result(r)));
uv_close(&sock->uv_handle.handle, tcp_close_cb);
sock->result = isc__nm_uverr2result(r);
atomic_store(&sock->listen_error, true);
goto done;
}
uv_handle_set_data(&sock->uv_handle.handle, sock);
atomic_store(&sock->listening, true);
done:
@@ -337,47 +333,112 @@ done:
return;
}
/*
* Connect to the parent socket and be ready to receive the uv_handle
* for the socket we'll be listening on.
*/
static void
tcp_connection_cb(uv_stream_t *server, int status) {
isc_nmsocket_t *psock = uv_handle_get_data((uv_handle_t *)server);
isc_result_t result;
UNUSED(status);
result = accept_connection(psock, NULL);
if (result != ISC_R_SUCCESS && result != ISC_R_NOCONN) {
if ((result != ISC_R_QUOTA && result != ISC_R_SOFTQUOTA) ||
can_log_tcp_quota()) {
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
"TCP connection failed: %s",
isc_result_totext(result));
}
}
}
void
isc__nm_async_tcpchildlisten(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tcpchildlisten_t *ievent =
(isc__netievent_tcpchildlisten_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
isc__nm_async_tcpchildaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
UNUSED(worker);
isc__netievent_tcpchildaccept_t *ievent =
(isc__netievent_tcpchildaccept_t *)ev0;
isc_nmsocket_t *ssock = ievent->sock;
isc_nmsocket_t *csock;
isc_nmhandle_t *handle;
isc_result_t result;
struct sockaddr_storage ss;
isc_sockaddr_t local;
int r;
REQUIRE(isc__nm_in_netthread());
REQUIRE(sock->type == isc_nm_tcpchildlistener);
REQUIRE(ssock->type == isc_nm_tcplistener);
worker = &sock->mgr->workers[isc_nm_tid()];
csock = isc_mem_get(ssock->mgr->mctx, sizeof(isc_nmsocket_t));
isc__nmsocket_init(csock, ssock->mgr, isc_nm_tcpsocket, ssock->iface);
csock->tid = isc_nm_tid();
csock->extrahandlesize = ssock->extrahandlesize;
csock->quota = ievent->quota;
ievent->quota = NULL;
uv_tcp_init(&worker->loop, (uv_tcp_t *)&sock->uv_handle.tcp);
uv_handle_set_data(&sock->uv_handle.handle, sock);
r = isc_uv_import(&sock->uv_handle.stream, &ievent->streaminfo);
worker = &ssock->mgr->workers[isc_nm_tid()];
uv_tcp_init(&worker->loop, &csock->uv_handle.tcp);
r = isc_uv_import(&csock->uv_handle.stream, &ievent->streaminfo);
if (r != 0) {
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
"uv_import failed: %s",
isc_result_totext(isc__nm_uverr2result(r)));
return;
result = isc__nm_uverr2result(r);
goto error;
}
r = uv_listen((uv_stream_t *)&sock->uv_handle.tcp, sock->backlog,
tcp_connection_cb);
r = uv_tcp_getpeername(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
&(int){ sizeof(ss) });
if (r != 0) {
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_NETMGR, ISC_LOG_ERROR,
"uv_listen failed: %s",
isc_result_totext(isc__nm_uverr2result(r)));
return;
result = isc__nm_uverr2result(r);
goto error;
}
result = isc_sockaddr_fromsockaddr(&csock->peer,
(struct sockaddr *)&ss);
if (result != ISC_R_SUCCESS) {
goto error;
}
r = uv_tcp_getsockname(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
&(int){ sizeof(ss) });
if (r != 0) {
result = isc__nm_uverr2result(r);
goto error;
}
result = isc_sockaddr_fromsockaddr(&local, (struct sockaddr *)&ss);
if (result != ISC_R_SUCCESS) {
goto error;
}
isc_nmsocket_attach(ssock, &csock->server);
handle = isc__nmhandle_get(csock, NULL, &local);
INSIST(ssock->rcb.accept != NULL);
csock->read_timeout = ssock->mgr->init;
ssock->rcb.accept(handle, ISC_R_SUCCESS, ssock->rcbarg);
isc_nmsocket_detach(&csock);
return;
error:
/*
* Detach it early to make room for other connections, otherwise
* it'd be detached later asynchronously clogging the quota.
*/
if (csock->quota != NULL) {
isc_quota_detach(&csock->quota);
}
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
ISC_LOG_ERROR, "Accepting TCP connection failed: %s",
isc_result_totext(result));
/* We need to detach it properly to make sure uv_close is called. */
isc_nmsocket_detach(&csock);
}
void
isc_nm_tcp_stoplistening(isc_nmsocket_t *sock) {
isc__nm_tcp_stoplistening(isc_nmsocket_t *sock) {
isc__netievent_tcpstop_t *ievent = NULL;
REQUIRE(VALID_NMSOCK(sock));
@@ -411,84 +472,23 @@ isc__nm_async_tcpstop(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)event);
} else {
stoplistening(sock);
uv_close((uv_handle_t *)&sock->uv_handle.tcp,
tcp_listenclose_cb);
isc__nm_drop_interlocked(sock->mgr);
}
}
static void
stoplistening(isc_nmsocket_t *sock) {
for (int i = 0; i < sock->nchildren; i++) {
isc__netievent_tcpchildstop_t *event = NULL;
/*
* We can ignore the overhead of event allocation because
* stoplistening is a rare event, and doing it this way
* simplifies sock reference counting.
*/
event = isc__nm_get_ievent(sock->mgr, netievent_tcpchildstop);
isc_nmsocket_attach(&sock->children[i], &event->sock);
if (isc_nm_tid() == sock->children[i].tid) {
isc__nm_async_tcpchildstop(&sock->mgr->workers[i],
(isc__netievent_t *)event);
isc__nm_put_ievent(sock->mgr, event);
} else {
isc__nm_enqueue_ievent(&sock->mgr->workers[i],
(isc__netievent_t *)event);
}
}
LOCK(&sock->lock);
while (atomic_load_relaxed(&sock->rchildren) > 0) {
WAIT(&sock->cond, &sock->lock);
}
UNLOCK(&sock->lock);
uv_close((uv_handle_t *)&sock->uv_handle.tcp, tcp_listenclose_cb);
}
void
isc__nm_async_tcpchildstop(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_tcpchildstop_t *ievent =
(isc__netievent_tcpchildstop_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
UNUSED(worker);
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(isc_nm_tid() == sock->tid);
REQUIRE(sock->type == isc_nm_tcpchildlistener);
REQUIRE(sock->parent != NULL);
/*
* rchildren is atomic, but we still need to change it
* under a lock because the parent is waiting on conditional
* and without it we might deadlock.
*/
LOCK(&sock->parent->lock);
atomic_fetch_sub(&sock->parent->rchildren, 1);
UNLOCK(&sock->parent->lock);
uv_close((uv_handle_t *)&sock->uv_handle.tcp, tcp_listenclose_cb);
BROADCAST(&sock->parent->cond);
}
/*
* This callback is used for closing both child and parent listening
* sockets; that's why we need to choose the proper lock.
* This callback is used for closing listening sockets
*/
static void
tcp_listenclose_cb(uv_handle_t *handle) {
isc_nmsocket_t *sock = uv_handle_get_data(handle);
isc_mutex_t *lock = ((sock->parent != NULL) ? &sock->parent->lock
: &sock->lock);
LOCK(lock);
LOCK(&sock->lock);
atomic_store(&sock->closed, true);
atomic_store(&sock->listening, false);
sock->pquota = NULL;
UNLOCK(lock);
UNLOCK(&sock->lock);
isc_nmsocket_detach(&sock);
}
@@ -519,7 +519,7 @@ readtimeout_cb(uv_timer_t *handle) {
}
isc_result_t
isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
isc__nm_tcp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
isc_nmsocket_t *sock = NULL;
isc__netievent_startread_t *ievent = NULL;
@@ -534,8 +534,8 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
ievent->sock = sock;
if (sock->tid == isc_nm_tid()) {
isc__nm_async_startread(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
isc__nm_async_tcp_startread(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
isc__nm_put_ievent(sock->mgr, ievent);
} else {
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
@@ -546,7 +546,7 @@ isc_nm_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
}
void
isc__nm_async_startread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__nm_async_tcp_startread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_startread_t *ievent = (isc__netievent_startread_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
int r;
@@ -569,7 +569,7 @@ isc__nm_async_startread(isc__networker_t *worker, isc__netievent_t *ev0) {
}
isc_result_t
isc_nm_pauseread(isc_nmsocket_t *sock) {
isc__nm_tcp_pauseread(isc_nmsocket_t *sock) {
isc__netievent_pauseread_t *ievent = NULL;
REQUIRE(VALID_NMSOCK(sock));
@@ -583,8 +583,8 @@ isc_nm_pauseread(isc_nmsocket_t *sock) {
ievent->sock = sock;
if (sock->tid == isc_nm_tid()) {
isc__nm_async_pauseread(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
isc__nm_async_tcp_pauseread(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
isc__nm_put_ievent(sock->mgr, ievent);
} else {
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
@@ -595,7 +595,7 @@ isc_nm_pauseread(isc_nmsocket_t *sock) {
}
void
isc__nm_async_pauseread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__nm_async_tcp_pauseread(isc__networker_t *worker, isc__netievent_t *ev0) {
isc__netievent_pauseread_t *ievent = (isc__netievent_pauseread_t *)ev0;
isc_nmsocket_t *sock = ievent->sock;
@@ -609,7 +609,7 @@ isc__nm_async_pauseread(isc__networker_t *worker, isc__netievent_t *ev0) {
}
isc_result_t
isc_nm_resumeread(isc_nmsocket_t *sock) {
isc__nm_tcp_resumeread(isc_nmsocket_t *sock) {
isc__netievent_startread_t *ievent = NULL;
REQUIRE(VALID_NMSOCK(sock));
@@ -625,8 +625,8 @@ isc_nm_resumeread(isc_nmsocket_t *sock) {
ievent->sock = sock;
if (sock->tid == isc_nm_tid()) {
isc__nm_async_startread(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
isc__nm_async_tcp_startread(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
isc__nm_put_ievent(sock->mgr, ievent);
} else {
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
@@ -683,130 +683,29 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
*/
}
static isc_result_t
accept_connection(isc_nmsocket_t *ssock) {
isc_result_t result;
isc_quota_t *quota = NULL;
isc_nmsocket_t *csock = NULL;
isc__networker_t *worker = NULL;
isc_nmhandle_t *handle = NULL;
struct sockaddr_storage ss;
isc_sockaddr_t local;
int r;
bool overquota = false;
REQUIRE(VALID_NMSOCK(ssock));
REQUIRE(ssock->tid == isc_nm_tid());
if (!atomic_load_relaxed(&ssock->active) ||
atomic_load_relaxed(&ssock->mgr->closing))
{
/* We're closing, bail */
return (ISC_R_CANCELED);
}
if (ssock->pquota != NULL) {
result = isc_quota_attach(ssock->pquota, &quota);
/*
* We share the quota between all TCP sockets. Others
* may have used up all the quota slots, in which case
* this socket could starve. So we only fail here if we
* already had at least one active connection on this
* socket. This guarantees that we'll maintain some level
* of service while over quota, and will resume normal
* service when the quota comes back down.
*/
if (result != ISC_R_SUCCESS) {
ssock->overquota++;
overquota = true;
if (ssock->conns > 0) {
isc__nm_incstats(
ssock->mgr,
ssock->statsindex[STATID_ACCEPTFAIL]);
return (result);
}
}
}
isc__nm_incstats(ssock->mgr, ssock->statsindex[STATID_ACCEPT]);
csock = isc_mem_get(ssock->mgr->mctx, sizeof(isc_nmsocket_t));
isc__nmsocket_init(csock, ssock->mgr, isc_nm_tcpsocket, ssock->iface);
csock->tid = isc_nm_tid();
csock->extrahandlesize = ssock->extrahandlesize;
csock->quota = quota;
quota = NULL;
worker = &ssock->mgr->workers[isc_nm_tid()];
uv_tcp_init(&worker->loop, &csock->uv_handle.tcp);
r = uv_accept(&ssock->uv_handle.stream, &csock->uv_handle.stream);
if (r != 0) {
result = isc__nm_uverr2result(r);
goto error;
}
r = uv_tcp_getpeername(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
&(int){ sizeof(ss) });
if (r != 0) {
result = isc__nm_uverr2result(r);
goto error;
}
result = isc_sockaddr_fromsockaddr(&csock->peer,
(struct sockaddr *)&ss);
if (result != ISC_R_SUCCESS) {
goto error;
}
r = uv_tcp_getsockname(&csock->uv_handle.tcp, (struct sockaddr *)&ss,
&(int){ sizeof(ss) });
if (r != 0) {
result = isc__nm_uverr2result(r);
goto error;
}
result = isc_sockaddr_fromsockaddr(&local, (struct sockaddr *)&ss);
if (result != ISC_R_SUCCESS) {
goto error;
}
isc_nmsocket_attach(ssock, &csock->server);
ssock->conns++;
handle = isc__nmhandle_get(csock, NULL, &local);
INSIST(ssock->rcb.accept != NULL);
csock->read_timeout = ssock->mgr->init;
ssock->rcb.accept(handle, ISC_R_SUCCESS, ssock->rcbarg);
isc_nmsocket_detach(&csock);
return (ISC_R_SUCCESS);
error:
static void
quota_accept_cb(isc_quota_t *quota, void *sock_) {
isc_nmsocket_t *sock = (isc_nmsocket_t *)sock_;
INSIST(VALID_NMSOCK(sock));
/*
* Detach it early to make room for other connections, otherwise
* it'd be detached later asynchronously clogging the quota.
* We need to create an event and pass it using async channel
*/
if (csock->quota != NULL) {
isc_quota_detach(&csock->quota);
}
if (overquota) {
ssock->overquota--;
}
/* We need to detach it properly to make sure uv_close is called. */
isc_nmsocket_detach(&csock);
return (result);
isc__netievent_tcpaccept_t *ievent =
isc__nm_get_ievent(sock->mgr, netievent_tcpaccept);
ievent->sock = sock;
ievent->quota = quota;
isc__nm_enqueue_ievent(&sock->mgr->workers[sock->tid],
(isc__netievent_t *)ievent);
}
static void
tcp_connection_cb(uv_stream_t *server, int status) {
isc_nmsocket_t *ssock = uv_handle_get_data((uv_handle_t *)server);
/* This is called when we get a quota callback. */
void
isc__nm_async_tcpaccept(isc__networker_t *worker, isc__netievent_t *ev0) {
isc_result_t result;
isc__netievent_tcpaccept_t *ievent = (isc__netievent_tcpaccept_t *)ev0;
UNUSED(status);
result = accept_connection(ssock);
REQUIRE(worker->id == ievent->sock->tid);
result = accept_connection(ievent->sock, ievent->quota);
if (result != ISC_R_SUCCESS && result != ISC_R_NOCONN) {
if ((result != ISC_R_QUOTA && result != ISC_R_SOFTQUOTA) ||
can_log_tcp_quota()) {
@@ -816,6 +715,104 @@ tcp_connection_cb(uv_stream_t *server, int status) {
isc_result_totext(result));
}
}
/* It was attached when we called isc_quota_attach_cb */
isc_nmsocket_detach(&ievent->sock);
}
/*
* Used to free uv_tcp_t that's used only to accept() and then export the
* socket to a child thread.
*/
static void
free_uvtcpt(uv_handle_t *uvs) {
isc_mem_t *mctx = (isc_mem_t *)uv_handle_get_data(uvs);
isc_mem_putanddetach(&mctx, uvs, sizeof(uv_tcp_t));
}
static isc_result_t
accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
isc_result_t result;
int r;
REQUIRE(VALID_NMSOCK(ssock));
REQUIRE(ssock->tid == isc_nm_tid());
if (!atomic_load_relaxed(&ssock->active) ||
atomic_load_relaxed(&ssock->mgr->closing))
{
/* We're closing, bail */
if (quota != NULL) {
isc_quota_detach(&quota);
}
return (ISC_R_CANCELED);
}
/* We can be called directly or as a callback from quota */
if (ssock->pquota != NULL && quota == NULL) {
/*
* We need to increase the reference on ssock, as might be
* queued in quota. The proper way of doing it would be
* to attach it here - before every call to quota_attach,
* and detach it afterwards but that'd be very suboptimal -
* instead, we just set it here, and attach it only if it'll
* really be used.
* XXXWPK do it 'the right way' for now, see what happens then.
*/
isc_nmsocket_t *tsock = NULL;
isc_nmsocket_attach(ssock, &tsock);
isc_quota_cb_init(&ssock->quotacb, quota_accept_cb, tsock);
result = isc_quota_attach_cb(ssock->pquota, &quota,
&ssock->quotacb);
if (result == ISC_R_QUOTA) {
isc__nm_incstats(ssock->mgr,
ssock->statsindex[STATID_ACCEPTFAIL]);
return (result);
}
/* Deinitialize & detach, just to be safe */
isc_quota_cb_init(&ssock->quotacb, NULL, NULL);
isc_nmsocket_detach(&tsock);
}
isc__nm_incstats(ssock->mgr, ssock->statsindex[STATID_ACCEPT]);
isc__networker_t *worker = &ssock->mgr->workers[isc_nm_tid()];
uv_tcp_t *uvstream = isc_mem_get(ssock->mgr->mctx, sizeof(uv_tcp_t));
isc_mem_t *mctx = NULL;
isc_mem_attach(ssock->mgr->mctx, &mctx);
uv_handle_set_data((uv_handle_t *)uvstream, mctx); /* pass it to free it
*/
mctx = NULL;
uv_tcp_init(&worker->loop, uvstream);
r = uv_accept(&ssock->uv_handle.stream, (uv_stream_t *)uvstream);
if (r != 0) {
result = isc__nm_uverr2result(r);
uv_close((uv_handle_t *)uvstream, free_uvtcpt);
isc_quota_detach(&quota);
return (result);
}
/* We have an accepted TCP socket, pass it to a random worker */
int w = isc_random_uniform(ssock->mgr->nworkers);
isc__netievent_tcpchildaccept_t *event =
isc__nm_get_ievent(ssock->mgr, netievent_tcpchildaccept);
event->sock = ssock;
event->quota = quota;
r = isc_uv_export((uv_stream_t *)uvstream, &event->streaminfo);
INSIST(r == 0);
uv_close((uv_handle_t *)uvstream, free_uvtcpt);
if (w == isc_nm_tid()) {
isc__nm_async_tcpchildaccept(&ssock->mgr->workers[w],
(isc__netievent_t *)event);
isc__nm_put_ievent(ssock->mgr, event);
} else {
isc__nm_enqueue_ievent(&ssock->mgr->workers[w],
(isc__netievent_t *)event);
}
return (ISC_R_SUCCESS);
}
isc_result_t
@@ -872,7 +869,7 @@ tcp_send_cb(uv_write_t *req, int status) {
uvreq->cb.send(uvreq->handle, result, uvreq->cbarg);
isc_nmhandle_unref(uvreq->handle);
isc__nm_uvreq_put(&uvreq, uvreq->handle->sock);
isc__nm_uvreq_put(&uvreq);
}
/*
@@ -893,7 +890,7 @@ isc__nm_async_tcpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
if (result != ISC_R_SUCCESS) {
ievent->req->cb.send(ievent->req->handle, result,
ievent->req->cbarg);
isc__nm_uvreq_put(&ievent->req, ievent->req->handle->sock);
isc__nm_uvreq_put(&ievent->req);
}
}
@@ -910,7 +907,7 @@ tcp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
if (r < 0) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_SENDFAIL]);
req->cb.send(NULL, isc__nm_uverr2result(r), req->cbarg);
isc__nm_uvreq_put(&req, sock);
isc__nm_uvreq_put(&req);
return (isc__nm_uverr2result(r));
}
@@ -943,30 +940,9 @@ tcp_close_direct(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->tid == isc_nm_tid());
REQUIRE(sock->type == isc_nm_tcpsocket);
isc_nmsocket_t *ssock = sock->server;
if (sock->quota != NULL) {
isc_quota_detach(&sock->quota);
}
if (ssock != NULL) {
ssock->conns--;
while (ssock->conns == 0 && ssock->overquota > 0) {
ssock->overquota--;
isc_result_t result = accept_connection(ssock);
if (result == ISC_R_SUCCESS || result == ISC_R_NOCONN) {
continue;
}
if ((result != ISC_R_QUOTA &&
result != ISC_R_SOFTQUOTA) ||
can_log_tcp_quota()) {
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_NETMGR,
ISC_LOG_ERROR,
"TCP connection failed: %s",
isc_result_totext(result));
}
}
}
if (sock->timer_initialized) {
sock->timer_initialized = false;
uv_timer_stop(&sock->timer);
+3 -3
View File
@@ -316,7 +316,7 @@ isc_nm_listentcpdns(isc_nm_t *mgr, isc_nmiface_t *iface, isc_nm_recv_cb_t cb,
}
void
isc_nm_tcpdns_stoplistening(isc_nmsocket_t *sock) {
isc__nm_tcpdns_stoplistening(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->type == isc_nm_tcpdnslistener);
@@ -326,7 +326,7 @@ isc_nm_tcpdns_stoplistening(isc_nmsocket_t *sock) {
sock->rcbarg = NULL;
if (sock->outer != NULL) {
isc_nm_tcp_stoplistening(sock->outer);
isc_nm_stoplistening(sock->outer);
isc_nmsocket_detach(&sock->outer);
}
}
@@ -494,7 +494,7 @@ isc__nm_tcpdns_send(isc_nmhandle_t *handle, isc_region_t *region,
*(uint16_t *)t->region.base = htons(region->length);
memmove(t->region.base + 2, region->base, region->length);
return (isc__nm_tcp_send(t->handle, &t->region, tcpdnssend_cb, t));
return (isc_nm_send(t->handle, &t->region, tcpdnssend_cb, t));
}
static void
+3 -3
View File
@@ -219,7 +219,7 @@ stoplistening(isc_nmsocket_t *sock) {
}
void
isc_nm_udp_stoplistening(isc_nmsocket_t *sock) {
isc__nm_udp_stoplistening(isc_nmsocket_t *sock) {
isc__netievent_udpstop_t *ievent = NULL;
/* We can't be launched from network thread, we'd deadlock */
@@ -439,7 +439,7 @@ isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
} else {
ievent->req->cb.send(ievent->req->handle, ISC_R_CANCELED,
ievent->req->cbarg);
isc__nm_uvreq_put(&ievent->req, ievent->req->sock);
isc__nm_uvreq_put(&ievent->req);
}
}
@@ -462,7 +462,7 @@ udp_send_cb(uv_udp_send_t *req, int status) {
uvreq->cb.send(uvreq->handle, result, uvreq->cbarg);
isc_nmhandle_unref(uvreq->handle);
isc__nm_uvreq_put(&uvreq, uvreq->sock);
isc__nm_uvreq_put(&uvreq);
}
/*
-6
View File
@@ -17,7 +17,6 @@
#include <sys/time.h>
#include <time.h>
#include <isc/log.h>
#include <isc/mutex.h>
#include <isc/once.h>
#include <isc/print.h>
@@ -295,11 +294,6 @@ isc__mutex_init(isc_mutex_t *mp, const char *file, unsigned int line) {
strerror_r(err, strbuf, sizeof(strbuf));
isc_error_fatal(file, line, "pthread_mutex_init failed: %s",
strbuf);
} else {
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, ISC_LOG_INFO,
"Initialized mutex %p at %s:%d",
mp, file, line);
}
}
#endif /* if !(ISC_MUTEX_DEBUG && defined(PTHREAD_MUTEX_ERRORCHECK)) && \
+82 -27
View File
@@ -22,14 +22,20 @@ isc_quota_init(isc_quota_t *quota, unsigned int max) {
atomic_init(&quota->max, max);
atomic_init(&quota->used, 0);
atomic_init(&quota->soft, 0);
atomic_init(&quota->waiting, 0);
ISC_LIST_INIT(quota->cbs);
isc_mutex_init(&quota->cblock);
}
void
isc_quota_destroy(isc_quota_t *quota) {
INSIST(atomic_load(&quota->used) == 0);
INSIST(atomic_load(&quota->waiting) == 0);
INSIST(ISC_LIST_EMPTY(quota->cbs));
atomic_store_release(&quota->max, 0);
atomic_store_release(&quota->used, 0);
atomic_store_release(&quota->soft, 0);
isc_mutex_destroy(&quota->cblock);
}
void
@@ -57,43 +63,79 @@ isc_quota_getused(isc_quota_t *quota) {
return (atomic_load_relaxed(&quota->used));
}
isc_result_t
isc_quota_reserve(isc_quota_t *quota) {
static isc_result_t
quota_reserve(isc_quota_t *quota) {
isc_result_t result;
uint32_t max = atomic_load_acquire(&quota->max);
uint32_t soft = atomic_load_acquire(&quota->soft);
uint32_t used = atomic_fetch_add_relaxed(&quota->used, 1);
if (max == 0 || used < max) {
if (soft == 0 || used < soft) {
result = ISC_R_SUCCESS;
} else {
result = ISC_R_SOFTQUOTA;
uint_fast32_t max = atomic_load_acquire(&quota->max);
uint_fast32_t soft = atomic_load_acquire(&quota->soft);
uint_fast32_t used = atomic_load_acquire(&quota->used);
do {
if (max != 0 && used >= max) {
return (ISC_R_QUOTA);
}
} else {
INSIST(atomic_fetch_sub_release(&quota->used, 1) > 0);
result = ISC_R_QUOTA;
}
if (soft != 0 && used >= soft) {
result = ISC_R_SOFTQUOTA;
} else {
result = ISC_R_SUCCESS;
}
} while (!atomic_compare_exchange_weak_acq_rel(&quota->used, &used,
used + 1));
return (result);
}
void
isc_quota_release(isc_quota_t *quota) {
/* Must be quota->cbslock locked */
static void
enqueue(isc_quota_t *quota, isc_quota_cb_t *cb) {
REQUIRE(cb != NULL);
ISC_LIST_ENQUEUE(quota->cbs, cb, link);
atomic_fetch_add_release(&quota->waiting, 1);
}
/* Must be quota->cbslock locked */
static isc_quota_cb_t *
dequeue(isc_quota_t *quota) {
isc_quota_cb_t *cb = ISC_LIST_HEAD(quota->cbs);
INSIST(cb != NULL);
ISC_LIST_DEQUEUE(quota->cbs, cb, link);
atomic_fetch_sub_relaxed(&quota->waiting, 1);
return (cb);
}
static void
quota_release(isc_quota_t *quota) {
/*
* This is opportunistic - we might race with a failing quota_attach_cb
* and not detect that something is waiting, but eventually someone will
* be releasing quota and will detect it, so we don't need to worry -
* and we're saving a lot by not locking cblock every time.
*/
if (atomic_load_acquire(&quota->waiting) > 0) {
isc_quota_cb_t *cb = NULL;
LOCK(&quota->cblock);
if (atomic_load_relaxed(&quota->waiting) > 0) {
cb = dequeue(quota);
}
UNLOCK(&quota->cblock);
if (cb != NULL) {
cb->cb_func(quota, cb->data);
cb->cb_func = NULL;
cb->data = NULL;
return;
}
}
INSIST(atomic_fetch_sub_release(&quota->used, 1) > 0);
}
static isc_result_t
doattach(isc_quota_t *quota, isc_quota_t **p, bool force) {
doattach(isc_quota_t *quota, isc_quota_t **p) {
isc_result_t result;
REQUIRE(p != NULL && *p == NULL);
result = isc_quota_reserve(quota);
result = quota_reserve(quota);
if (result == ISC_R_SUCCESS || result == ISC_R_SOFTQUOTA) {
*p = quota;
} else if (result == ISC_R_QUOTA && force) {
/* attach anyway */
atomic_fetch_add_relaxed(&quota->used, 1);
*p = quota;
result = ISC_R_SUCCESS;
}
return (result);
@@ -101,17 +143,30 @@ doattach(isc_quota_t *quota, isc_quota_t **p, bool force) {
isc_result_t
isc_quota_attach(isc_quota_t *quota, isc_quota_t **p) {
return (doattach(quota, p, false));
return (isc_quota_attach_cb(quota, p, NULL));
}
isc_result_t
isc_quota_force(isc_quota_t *quota, isc_quota_t **p) {
return (doattach(quota, p, true));
isc_quota_attach_cb(isc_quota_t *quota, isc_quota_t **p, isc_quota_cb_t *cb) {
isc_result_t result = doattach(quota, p);
if (result == ISC_R_QUOTA && cb != NULL) {
LOCK(&quota->cblock);
enqueue(quota, cb);
UNLOCK(&quota->cblock);
}
return (result);
}
void
isc_quota_cb_init(isc_quota_cb_t *cb, isc_quota_cb_func_t cb_func, void *data) {
ISC_LINK_INIT(cb, link);
cb->cb_func = cb_func;
cb->data = data;
}
void
isc_quota_detach(isc_quota_t **p) {
INSIST(p != NULL && *p != NULL);
isc_quota_release(*p);
quota_release(*p);
*p = NULL;
}
+4 -14
View File
@@ -20,7 +20,6 @@
#endif /* if defined(sun) && (defined(__sparc) || defined(__sparc__)) */
#include <isc/atomic.h>
#include <isc/log.h>
#include <isc/magic.h>
#include <isc/platform.h>
#include <isc/print.h>
@@ -33,16 +32,11 @@
#include <pthread.h>
isc_result_t
isc__rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota, const char *file,
unsigned int line) {
isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota) {
UNUSED(read_quota);
UNUSED(write_quota);
REQUIRE(pthread_rwlock_init(&rwl->rwlock, NULL) == 0);
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_OTHER, ISC_LOG_INFO,
"Initialized rwlock %p at %s:%d",
&rwl->rwlock, file, line);
atomic_init(&rwl->downgrade, false);
return (ISC_R_SUCCESS);
}
@@ -196,14 +190,10 @@ print_lock(const char *operation, isc_rwlock_t *rwl, isc_rwlocktype_t type) {
#endif /* ISC_RWLOCK_TRACE */
isc_result_t
isc__rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota, const char *file,
unsigned int line) {
isc_rwlock_init(isc_rwlock_t *rwl, unsigned int read_quota,
unsigned int write_quota) {
REQUIRE(rwl != NULL);
UNUSED(file);
UNUSED(line);
/*
* In case there's trouble initializing, we zero magic now. If all
* goes well, we'll set it to RWLOCK_MAGIC.
+7 -2
View File
@@ -33,7 +33,7 @@ SRCS = isctest.c aes_test.c buffer_test.c \
counter_test.c crc64_test.c errno_test.c file_test.c hash_test.c \
heap_test.c hmac_test.c ht_test.c lex_test.c \
mem_test.c md_test.c netaddr_test.c parse_test.c pool_test.c \
radix_test.c random_test.c \
quota_test.c radix_test.c random_test.c \
regex_test.c result_test.c safe_test.c siphash_test.c sockaddr_test.c \
socket_test.c socket_test.c symtab_test.c task_test.c \
taskpool_test.c time_test.c timer_test.c
@@ -46,7 +46,7 @@ TARGETS = aes_test@EXEEXT@ buffer_test@EXEEXT@ \
ht_test@EXEEXT@ \
lex_test@EXEEXT@ mem_test@EXEEXT@ md_test@EXEEXT@ \
netaddr_test@EXEEXT@ parse_test@EXEEXT@ pool_test@EXEEXT@ \
radix_test@EXEEXT@ \
quota_test@EXEEXT@ radix_test@EXEEXT@ \
random_test@EXEEXT@ regex_test@EXEEXT@ result_test@EXEEXT@ \
safe_test@EXEEXT@ siphash_test@EXEEXT@ sockaddr_test@EXEEXT@ socket_test@EXEEXT@ \
socket_test@EXEEXT@ symtab_test@EXEEXT@ task_test@EXEEXT@ \
@@ -134,6 +134,11 @@ pool_test@EXEEXT@: pool_test.@O@ isctest.@O@ ${ISCDEPLIBS}
${LDFLAGS} -o $@ pool_test.@O@ isctest.@O@ \
${ISCLIBS} ${LIBS}
quota_test@EXEEXT@: quota_test.@O@ isctest.@O@ ${ISCDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} \
${LDFLAGS} -o $@ quota_test.@O@ isctest.@O@ \
${ISCLIBS} ${LIBS}
radix_test@EXEEXT@: radix_test.@O@ isctest.@O@ ${ISCDEPLIBS}
${LIBTOOL_MODE_LINK} ${PURIFY} ${CC} ${CFLAGS} \
${LDFLAGS} -o $@ radix_test.@O@ isctest.@O@ \
+343
View File
@@ -0,0 +1,343 @@
/*
* Copyright (C) Internet Systems Consortium, Inc. ("ISC")
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* See the COPYRIGHT file distributed with this work for additional
* information regarding copyright ownership.
*/
#if HAVE_CMOCKA
#include <sched.h> /* IWYU pragma: keep */
#include <setjmp.h>
#include <stdarg.h>
#include <stddef.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#define UNIT_TESTING
#include <cmocka.h>
#include <isc/quota.h>
#include <isc/result.h>
#include <isc/thread.h>
#include <isc/util.h>
static void
isc_quota_get_set_test(void **state) {
UNUSED(state);
isc_quota_t quota;
isc_quota_t *quota2 = NULL;
isc_quota_init(&quota, 100);
assert_int_equal(isc_quota_getmax(&quota), 100);
assert_int_equal(isc_quota_getsoft(&quota), 0);
isc_quota_max(&quota, 50);
isc_quota_soft(&quota, 30);
assert_int_equal(isc_quota_getmax(&quota), 50);
assert_int_equal(isc_quota_getsoft(&quota), 30);
assert_int_equal(isc_quota_getused(&quota), 0);
isc_quota_attach(&quota, &quota2);
assert_int_equal(isc_quota_getused(&quota), 1);
isc_quota_detach(&quota2);
assert_int_equal(isc_quota_getused(&quota), 0);
isc_quota_destroy(&quota);
}
#define add_quota(quota, quotasp, exp, attached, exp_used) \
{ \
*quotasp = NULL; \
isc_result_t result = isc_quota_attach(quota, quotasp); \
assert_int_equal(result, exp); \
if (attached) { \
assert_ptr_equal(*quotasp, quota); \
} else { \
assert_null(*quotasp); \
} \
assert_int_equal(isc_quota_getused(quota), exp_used); \
}
static void
isc_quota_hard_test(void **state) {
isc_quota_t quota;
isc_quota_t *quotas[110];
int i;
UNUSED(state);
isc_quota_init(&quota, 100);
for (i = 0; i < 100; i++) {
add_quota(&quota, &quotas[i], ISC_R_SUCCESS, true, i + 1);
}
add_quota(&quota, &quotas[100], ISC_R_QUOTA, false, 100);
assert_int_equal(isc_quota_getused(&quota), 100);
isc_quota_detach(&quotas[0]);
assert_null(quotas[0]);
add_quota(&quota, &quotas[100], ISC_R_SUCCESS, true, 100);
add_quota(&quota, &quotas[101], ISC_R_QUOTA, false, 100);
for (i = 100; i > 0; i--) {
isc_quota_detach(&quotas[i]);
assert_null(quotas[i]);
assert_int_equal(isc_quota_getused(&quota), i - 1);
}
assert_int_equal(isc_quota_getused(&quota), 0);
isc_quota_destroy(&quota);
}
static void
isc_quota_soft_test(void **state) {
isc_quota_t quota;
isc_quota_t *quotas[110];
int i;
UNUSED(state);
isc_quota_init(&quota, 100);
isc_quota_soft(&quota, 50);
for (i = 0; i < 50; i++) {
add_quota(&quota, &quotas[i], ISC_R_SUCCESS, true, i + 1);
}
for (i = 50; i < 100; i++) {
add_quota(&quota, &quotas[i], ISC_R_SOFTQUOTA, true, i + 1);
}
add_quota(&quota, &quotas[i], ISC_R_QUOTA, false, 100);
for (i = 99; i >= 0; i--) {
isc_quota_detach(&quotas[i]);
assert_null(quotas[i]);
assert_int_equal(isc_quota_getused(&quota), i);
}
assert_int_equal(isc_quota_getused(&quota), 0);
isc_quota_destroy(&quota);
}
static atomic_uint_fast32_t cb_calls = ATOMIC_VAR_INIT(0);
static isc_quota_cb_t cbs[30];
static isc_quota_t *qp;
static void
callback(isc_quota_t *quota, void *data) {
int val = *(int *)data;
/* Callback is not called if we get the quota directly */
assert_int_not_equal(val, -1);
/* We get the proper quota pointer */
assert_ptr_equal(quota, qp);
/* Verify that the callbacks are called in order */
int v = atomic_fetch_add_relaxed(&cb_calls, 1);
assert_int_equal(v, val);
/*
* First 5 will be detached by the test function,
* for the last 5 - do a 'chain detach'.
*/
if (v >= 5) {
isc_quota_detach(&quota);
}
}
static void
isc_quota_callback_test(void **state) {
isc_result_t result;
isc_quota_t quota;
isc_quota_t *quotas[30];
qp = &quota;
/*
* - 10 calls that end with SUCCESS
* - 10 calls that end with SOFTQUOTA
* - 10 callbacks
*/
int ints[] = { -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
int i;
UNUSED(state);
isc_quota_init(&quota, 20);
isc_quota_soft(&quota, 10);
for (i = 0; i < 10; i++) {
quotas[i] = NULL;
isc_quota_cb_init(&cbs[i], callback, &ints[i]);
result = isc_quota_attach_cb(&quota, &quotas[i], &cbs[i]);
assert_int_equal(result, ISC_R_SUCCESS);
assert_ptr_equal(quotas[i], &quota);
assert_int_equal(isc_quota_getused(&quota), i + 1);
}
for (i = 10; i < 20; i++) {
quotas[i] = NULL;
isc_quota_cb_init(&cbs[i], callback, &ints[i]);
result = isc_quota_attach_cb(&quota, &quotas[i], &cbs[i]);
assert_int_equal(result, ISC_R_SOFTQUOTA);
assert_ptr_equal(quotas[i], &quota);
assert_int_equal(isc_quota_getused(&quota), i + 1);
}
for (i = 20; i < 30; i++) {
quotas[i] = NULL;
isc_quota_cb_init(&cbs[i], callback, &ints[i]);
result = isc_quota_attach_cb(&quota, &quotas[i], &cbs[i]);
assert_int_equal(result, ISC_R_QUOTA);
assert_ptr_equal(quotas[i], NULL);
assert_int_equal(isc_quota_getused(&quota), 20);
}
assert_int_equal(atomic_load(&cb_calls), 0);
for (i = 0; i < 5; i++) {
isc_quota_detach(&quotas[i]);
assert_null(quotas[i]);
assert_int_equal(isc_quota_getused(&quota), 20);
assert_int_equal(atomic_load(&cb_calls), i + 1);
}
/* That should cause a chain reaction */
isc_quota_detach(&quotas[5]);
assert_int_equal(atomic_load(&cb_calls), 10);
/* Release the quotas that we did not released in the callback */
for (i = 0; i < 5; i++) {
isc_quota_detach(&quotas[i]);
}
for (i = 6; i < 20; i++) {
isc_quota_detach(&quotas[i]);
assert_null(quotas[i]);
assert_int_equal(isc_quota_getused(&quota), 19 - i);
}
assert_int_equal(atomic_load(&cb_calls), 10);
assert_int_equal(isc_quota_getused(&quota), 0);
isc_quota_destroy(&quota);
}
/*
* Multithreaded quota callback test:
* - quota set to 100
* - 10 threads, each trying to get 100 quotas.
* - creates a separate thread to release it after 10ms
*/
typedef struct qthreadinfo {
atomic_uint_fast32_t direct;
atomic_uint_fast32_t callback;
isc_quota_t *quota;
isc_quota_cb_t callbacks[100];
} qthreadinfo_t;
static atomic_uint_fast32_t g_tnum = ATOMIC_VAR_INIT(0);
/* at most 10 * 100 quota_detach threads */
isc_thread_t g_threads[10 * 100];
static void *
quota_detach(void *quotap) {
isc_quota_t *quota = (isc_quota_t *)quotap;
usleep(10000);
isc_quota_detach(&quota);
return ((isc_threadresult_t)0);
}
static void
quota_callback(isc_quota_t *quota, void *data) {
qthreadinfo_t *qti = (qthreadinfo_t *)data;
atomic_fetch_add_relaxed(&qti->callback, 1);
int tnum = atomic_fetch_add_relaxed(&g_tnum, 1);
isc_thread_create(quota_detach, quota, &g_threads[tnum]);
}
static isc_threadresult_t
quota_thread(void *qtip) {
qthreadinfo_t *qti = (qthreadinfo_t *)qtip;
for (int i = 0; i < 100; i++) {
isc_quota_cb_init(&qti->callbacks[i], quota_callback, qti);
isc_quota_t *quota = NULL;
isc_result_t result = isc_quota_attach_cb(qti->quota, &quota,
&qti->callbacks[i]);
if (result == ISC_R_SUCCESS) {
atomic_fetch_add_relaxed(&qti->direct, 1);
int tnum = atomic_fetch_add_relaxed(&g_tnum, 1);
isc_thread_create(quota_detach, quota,
&g_threads[tnum]);
}
}
return ((isc_threadresult_t)0);
}
static void
isc_quota_callback_mt_test(void **state) {
UNUSED(state);
isc_quota_t quota;
int i;
isc_quota_init(&quota, 100);
static qthreadinfo_t qtis[10];
isc_thread_t threads[10];
for (i = 0; i < 10; i++) {
atomic_init(&qtis[i].direct, 0);
atomic_init(&qtis[i].callback, 0);
qtis[i].quota = &quota;
isc_thread_create(quota_thread, &qtis[i], &threads[i]);
}
for (i = 0; i < 10; i++) {
isc_thread_join(threads[i], NULL);
}
for (i = 0; i < (int)atomic_load(&g_tnum); i++) {
isc_thread_join(g_threads[i], NULL);
}
int direct = 0, callback = 0;
for (i = 0; i < 10; i++) {
direct += atomic_load(&qtis[i].direct);
callback += atomic_load(&qtis[i].callback);
}
/* Total quota gained must be 10 threads * 100 tries */
assert_int_equal(direct + callback, 10 * 100);
/*
* At least 100 must be direct, the rest is virtually random:
* - in a regular run I'm constantly getting 100:900 ratio
* - under rr - usually around ~120:880
* - under rr -h - 1000:0
*/
assert_true(direct >= 100);
isc_quota_destroy(&quota);
}
int
main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(isc_quota_get_set_test),
cmocka_unit_test(isc_quota_hard_test),
cmocka_unit_test(isc_quota_soft_test),
cmocka_unit_test(isc_quota_callback_test),
cmocka_unit_test(isc_quota_callback_mt_test),
};
return (cmocka_run_group_tests(tests, NULL, NULL));
}
#else /* HAVE_CMOCKA */
#include <stdio.h>
int
main(void) {
printf("1..0 # Skipped: cmocka not available\n");
return (0);
}
#endif /* if HAVE_CMOCKA */
+2 -2
View File
@@ -45,7 +45,7 @@ isc_stdtime_get(isc_stdtime_t *t) {
strbuf);
}
REQUIRE(ts.tv_sec > 0 && ts.tv_nsec > 0 && ts.tv_nsec < NS_PER_S);
REQUIRE(ts.tv_sec > 0 && ts.tv_nsec >= 0 && ts.tv_nsec < NS_PER_S);
*t = (unsigned int)ts.tv_sec;
*t = (isc_stdtime_t)ts.tv_sec;
}
+4 -6
View File
@@ -461,14 +461,13 @@ isc_nm_maxudp
isc_nm_send
isc_nm_setstats
isc_nm_start
isc_nm_stoplistening
isc_nm_tcp_gettimeouts
isc_nm_tcp_settimeouts
isc_nmsocket_detach
isc_nm_tcpdns_keepalive
isc_nm_tcpdns_sequential
isc_nm_tcpdns_stoplistening
isc_nm_tid
isc_nm_udp_stoplistening
isc_nmsocket_detach
isc__nm_acquire_interlocked
isc__nm_drop_interlocked
isc__nm_acquire_interlocked_force
@@ -498,16 +497,15 @@ isc_queue_dequeue
isc_queue_destroy
isc_queue_new
isc_quota_attach
isc_quota_attach_cb
isc_quota_cb_init
isc_quota_destroy
isc_quota_detach
isc_quota_force
isc_quota_getmax
isc_quota_getsoft
isc_quota_getused
isc_quota_init
isc_quota_max
isc_quota_release
isc_quota_reserve
isc_quota_soft
isc_radix_create
isc_radix_destroy
+2 -2
View File
@@ -553,11 +553,11 @@ cleanup_interface:
void
ns_interface_shutdown(ns_interface_t *ifp) {
if (ifp->udplistensocket != NULL) {
isc_nm_udp_stoplistening(ifp->udplistensocket);
isc_nm_stoplistening(ifp->udplistensocket);
isc_nmsocket_detach(&ifp->udplistensocket);
}
if (ifp->tcplistensocket != NULL) {
isc_nm_tcpdns_stoplistening(ifp->tcplistensocket);
isc_nm_stoplistening(ifp->tcplistensocket);
isc_nmsocket_detach(&ifp->tcplistensocket);
}
if (ifp->clientmgr != NULL) {
+2
View File
@@ -1471,6 +1471,7 @@
./doc/arm/masters.grammar.xml SGML 2018,2019,2020
./doc/arm/mirror.zoneopt.xml SGML 2018,2019,2020
./doc/arm/notes-9.17.0.xml SGML 2020
./doc/arm/notes-9.17.1.xml SGML 2020
./doc/arm/notes-download.xml SGML 2019,2020
./doc/arm/notes-eol.xml SGML 2019,2020
./doc/arm/notes-intro.xml SGML 2019,2020
@@ -2314,6 +2315,7 @@
./lib/isc/tests/netaddr_test.c C 2016,2018,2019,2020
./lib/isc/tests/parse_test.c C 2012,2013,2016,2018,2019,2020
./lib/isc/tests/pool_test.c C 2013,2016,2018,2019,2020
./lib/isc/tests/quota_test.c C 2020
./lib/isc/tests/radix_test.c C 2014,2016,2018,2019,2020
./lib/isc/tests/random_test.c C 2014,2015,2016,2017,2018,2019,2020
./lib/isc/tests/regex_test.c C 2013,2015,2016,2018,2019,2020