A catalog zone is updated in an offloaded thread, which is not
stopped during a reconfiguration in an exclusive mode, and so
can cause a race condition with it.
Waiting for the offloaded threads to complete their work before
entering into the exclusive mode can potentially cause unwanted
delays, because offloaded threads are generally "allowed" to take
a longer amount of time before they complete.
Add a dns_catz_zone_prereconfig()/dns_catz_zone_postreconfig() pair
of functions which currently just lock the catalog zone when
reconfiguring it. The change should eliminate the race.
As a side note, there was already a similar pair of functions,
dns_catz_prereconfig() and dns_catz_postreconfig() which are called
before and after reconfiguring a 'dns_catz_zones_t' object.
Below are the stack traces of the reconfiguration thread which has
asserted, and a catalog zone update thread which was caught in the
middle of its work despite the fact that the exclusive mode is
turned on.
Stack trace of thread 23859:
#0 0x00007f80e7b8e52f raise (libc.so.6)
#1 0x00007f80e7b61e65 abort (libc.so.6)
#2 0x0000000000422558 assertion_failed (named)
#3 0x00007f80eaa6799e isc_assertion_failed (libisc-9.18.41.so)
#4 0x00007f80ea5bc788 dns_catz_entry_getname (libdns-9.18.41.so)
#5 0x000000000042ce0e catz_reconfigure (named)
#6 0x000000000042d3c5 configure_catz_zone (named)
#7 0x000000000042d7a4 configure_catz (named)
#8 0x0000000000430645 configure_view (named)
#9 0x000000000043d998 load_configuration (named)
#10 0x000000000044184f loadconfig (named)
#11 0x0000000000442525 named_server_reconfigcommand (named)
#12 0x000000000041b277 named_control_docommand (named)
#13 0x000000000041c74a control_command (named)
#14 0x00007f80eaa912ae task_run (libisc-9.18.41.so)
#15 0x00007f80eaa914cd isc_task_run (libisc-9.18.41.so)
#16 0x00007f80eaa46435 isc__nm_async_task (libisc-9.18.41.so)
#17 0x00007f80eaa467aa process_netievent (libisc-9.18.41.so)
#18 0x00007f80eaa475a6 process_queue (libisc-9.18.41.so)
#19 0x00007f80eaa46227 process_all_queues (libisc-9.18.41.so)
#20 0x00007f80eaa462a1 async_cb (libisc-9.18.41.so)
#21 0x00007f80e8d01893 uv__async_io.part.3 (libuv.so.1)
#22 0x00007f80e8d13ac4 uv__io_poll (libuv.so.1)
#23 0x00007f80e8d023fb uv_run (libuv.so.1)
#24 0x00007f80eaa45ced nm_thread (libisc-9.18.41.so)
#25 0x00007f80eaa9bda3 isc__trampoline_run (libisc-9.18.41.so)
#26 0x00007f80e7f1e1ca start_thread (libpthread.so.0)
#27 0x00007f80e7b798d3 __clone (libc.so.6)
...
...
Stack trace of thread 23912:
#0 0x00007f80ea5bc2da dns_catz_options_setdefault (libdns-9.18.41.so)
#1 0x00007f80ea5bd411 dns__catz_zones_merge (libdns-9.18.41.so)
#2 0x00007f80ea5c3c2f dns__catz_update_cb (libdns-9.18.41.so)
#3 0x00007f80eaa4fee9 isc__nm_work_run (libisc-9.18.41.so)
#4 0x00007f80eaa9bda3 isc__trampoline_run (libisc-9.18.41.so)
#5 0x00007f80eaa4ff48 isc__nm_work_cb (libisc-9.18.41.so)
#6 0x00007f80e8cfc75e worker (libuv.so.1)
#7 0x00007f80e7f1e1ca start_thread (libpthread.so.0)
#8 0x00007f80e7b798d3 __clone (libc.so.6)
We had a common pattern in the code that looks like this:
if (dns_rdataset_isassociated(rdataset)) {
dns_rdataset_disassociate(rdataset);
}
add a helper macro that checks for rdataset != NULL and the above
called dns_rdataset_cleanup(rdataset).
The bitset packing of the resign_lsb and heap_index in struct vecheader
was causing a race condition, since both bindrdataset and heap
operations tried to access the same byte (even though they are accessing
different fields).
While heap operations are protected by the node lock of the header being
inserted, they aren't protected by the node locks of the headers being
displaced, leading to the race condition.
This commit fixes the issue by reverting the struct packing
optimization.
This is a new seek function for dbiterator that is meant to find an
NSEC3 node in a zone database. The difference with dns_dbiterator_seek
is that if the node does not exist, this seek function will point the
iterator to the next NSEC3 name.
Add an implementation of rdataset specialized for authoritative
workloads. For now, it is a copy of rdataslab, with redundant fields
from the header removed.
The removal of the foundname and name parameters from various qp.c
functions led to formatting issues. Restore the correct formatting via
clang-format.
Outside of unit tests, the name parameter in dns_qpiter_<...> and
dns_qpchain_<...> is only used in context where the name can be
extracted directly from the underlying node.
This commits modifies the signatures of dns_qpiter_<...> and
dns_qpchain_<...> not to have a name parameter. Where the name parameter
was needed, we now query the node and copy the name directly from it.
This allows us to remove maybe_set_name from qp.c. Besides simplifying
the API, this leads to a performance speedup for NXDOMAIN handling,
as we avoid calling maybe_set_name inside step, and maybe_set_name is
very inefficient.
A copy of the implementation maybe_set_name is retained for the unit
tests.
The `foundname` parameter in dns_qp_lookup is used only in the unit
tests. This commit simplifies the API by removing it, and modifying the
unit tests to extract the name from pval.
This commit implements a batch update function for qpzone. The main
reason for this is speed: using addrdataset would cause a qp transaction
per rrdataset added, leading to a substantial slowdown compared to
RBTDB. The new API results in a qp transaction per applied diff.
This commit adds a layer of indirection to the apply_diff logic used by
IXFR and resigning by having the database updates go through a vtable.
We do this in three steps:
- We extend dns_rdatacallbacks_t vtable to allow subtraction and
resigning.
- We add a new set of api (begin|commit|abort)update to the dbmethods
vtable, that model an incremental update that can be aborted.
- We extract the core logic of diff_apply into a function that
satisfies the new interface.
- We make diff_apply use this new function, and log the results.
The intent of this commit is to allow databases to expose a batch
incremental update implementation, just like they expose a custom
batch creation implementation through (begin|end)load.
Instead of just flagging the qpcache node to be dirty, add the headers
to be cleaned to the dirty list and when cleaning the node, only walk
through the dirty node, not all the slabtops.
Document the way `__attribute__((__constructor__))` and
`__attribute__((__destructor__))` must be used in BIND9 libraries in
order to avoid unexpected behaviors with other third-party libraries.
In commit aea251f3bc, `isc_buffer_reserve()` was changed to
take a simple `isc_buffer_t *` instead of `isc_buffer_t **`.
A number of functions calling it have now been similarly
modified.
Wrap 'dns_keymgr_status()' in 'dns_zone_dnssecstatus()' so we can easily
retrieve the zone string name and refresh key time value.
In addition to the current time, output when the next key event is
expected.
Don't log keys that are completely hidden unless verbose is set.
Don't log key state values unless verbose is set, or they are in a
weird state.
For expected key states, log a more useful message of the stage of
the rollover. If we are in the middle of a key rollover, don't log
when the next key rollover is scheduled.
Condense the output for better readability.
Maintain the relationship between the parent and child fetch and when
creating a new child fetch, properly check the resolution loops that
would lead to a new fetch would join one of the parent's fetch contexts.
now that the EDNS state is stored within dns_message_t, it's no longer
necessary to have a public API call to build an opt rdataset; we can
just have dns_message_setopt() build the opt record internally.
The new dns_message_ednsinit() and dns_message_ednsaddopt() functions
allow EDNS options to be added to a message one at a time; it is no
longer necessary to construct a full array of EDNS options and set
them all at once.
This allows us to simplify EDNS option handling code, and in the
future it wlil allow plugins to add EDNS options to existing
messages.
as previously mentioned in commit c65b2868ab, a cfg_obj_t
configuration tree structure takes up considerably more space than
the canonical text. since the zone configuration saved in the zone
object using dns_zone_setcfg() is only currently used for "rndc
showzone", it can be saved as text more efficiently than as an
object tree. (and, if a tree were needed, the text could be
re-parsed quickly; zone configuration text is generally small.)
Scheduling and rescheduling a zonefetch is also similar. Refactor into
zonefetch functions. This also increments and decrements the zone's
internal reference counter in the same module, which may be less
confusing when reading the code.
Introduce the `dns_zone_isexpired()` API which returns `true` when a
secondary, mirror, etc. zone is expired.
This internally use the `DNS_ZONEFLG_EXPIRED` which was already set when
the zone gets expired, but never used.
The flag `DNS_ZONEFLG_EXPIRED` is also now cleared when the expiration
time of the zone is updated and in the future.
CID 638286: Concurrent data access violations (MISSING_LOCK). This
complains about accessing "zone->notifyctx.notify_acl" without holding
the lock "dns_zone.lock". Elsewhere, reading this data does have the
lock, so it makes sense that in the getter function this must also be
so. However, the function is unused so we can just remove it.
CID 638287: Concurrent data access violations (MISSING_LOCK). This
complains about accessing "zone->locked" without holding the lock
"dns_zone.lock". I think this is a false positive as "dns__zone_lock()"
and "dns__zone_unlock() are wrappers around "LOCK_ZONE()" and
"UNLOCK_ZONE()" and where these macros were used they were only
replaced with the internal zone functions. Moreover, "zone->locked"
is only accessed in these macros (and "TRYLOCK_ZONE()" and
"LOCKED_ZONE()").
Move dns_notify_destroy, dns_notify_log, dns_notify_cancel,
dns_notify_queue, dns_notify_isqueued, dns_notify_find_address, and
notify related static functions over to the notify source files.
Part of refactoring zone.c is to move the notify code into its own
source files. This commit initiates this work by creating notify.[c,h]
and move notify_create() and the notify state and context there.
The function notify_create() cannot fail, so it can return void instead
of isc_result_t.
instead of using an opaque ns_cfgctx pointer to store the configuration
data to be used by addzone and modzone, there are now fields in the
dns_view object to store the view configuration and LMDB database
environment. the global configuration is now stored in the named_server
object, along with the ACL context.
when configuring a zone, we can now save the zone's configuration
object in the zone itself by calling dns_zone_setcfg(). this can
then be used by "rndc showzone" to print the zone's configuration,
which is simpler than searching for it using the new-zones
configuration, and allows it to work even if "allow-new-zones"
is disabled.
When generating a new key, dnssec-keygen checks for possible
key ID collisions with existing keys. The dnssec.c:findmatchingkeys()
function, which is supposed to get the list of the existing keys,
fails to do that for the existing KEY rrtype keys (i.e. generated
using 'dnssec-keygen -T KEY') because it doesn't pass down to the
dst_key_fromnamedfile() -> dst_key_read_public() functions the type
of the keys it's interested in. Fix the issue by introducing a new
function parameter which tells in which type of keys the caller is
currently interested in.
the functions dns_dumpctx_db() and dns_dumpctx_version() are used in
only one place, to get the serial number of the version being dumped.
it's simpler to expose the serial number through its own call,
dns_dumpctx_serial(), and remove the others.
if a zone reload is already in progress when 'rndc reload <zone>' is
run, currently the message returned in "zone reload queued", which
is correct, but it's identical to the message returned when a reload
was *not* in progress, so the user can't easily tell what happened.
a user could reload a zone twice and not realize that only one
reload actually took place.
this has been addressed by changing the message returned to
"zone reload was already queued".
a new result code ISC_R_LOADING has been added to signal this
condition, taking the place of ISC_R_RELOAD, which was obsolete
and has been removed.
Since the "tkey-gssapi-credential" statement has been previously
deprecated, mark it as ancient and remove all code related to it:
- The code processing the "tkey-gssapi-credential" statement in the
configuration is the only user of the dst_gssapi_acquirecred() and
dst_gssapi_releasecred() functions, so remove them along with their
static helper functions and a backup definition of the
GSS_KRB5_MECHANISM macro.
- When calling gss_accept_sec_context(), pass GSS_C_NO_CREDENTIAL
instead of the credential acquired by gss_acquire_cred().
(Previously, NULL was passed when "tkey-gssapi-credential" was not
specified. Kerberos headers define GSS_C_NO_CREDENTIAL as
(gss_cred_id_t) 0, so the logic was effectively the same, but using
the GSS_C_NO_CREDENTIAL macro is more appropriate.) This renders
the 'cred' parameter for dst_gssapi_acceptctx() redundant, so remove
it from the prototype of the latter. (Contrary to what the
documentation for dst_gssapi_acceptctx() claims,
dst_gssapi_releasecred() does not need to subsequently be called to
free the GSS-API context; a dst_gssapi_deletectx() call in
gssapi_destroy() takes care of that when the dynamically generated
TSIG key is destroyed.)
- Remove the 'gsscred' member from struct dns_tkeyctx, along with its
related dns_gss_cred_id_t typedef.
Update the relevant sections of the ARM and code comments accordingly.
This makes the "tkey-gssapi-keytab" statement the only way to set up
GSS-TSIG in named.
Remove redundant code from bin/named/tkeyconf.c while at it.
To prevent spoofed unsigned DNAME responses being accepted retry
response with unsigned DNAMEs over TCP if the response is not TSIG
signed or there isn't a good DNS CLIENT COOKIE.
Names for reverse resolution are now shared and accessible from
dns/name.h header as those are used by ptr_12.c and byaddr.c files.
(Also, for consistency, move deprecated ip6.int. name in name.h, even
though it is used only by ptr_12.c).
Add an API to parse and extract either an IPv4 or IPv6 address from
a name using the reverse format. It takes care of family detection,
and returns a generic error in case of syntax error.
After a full sign we no longer have to need to take the sign delay into
account. Update the timing checks in keymgr_transition_time to determine
the start of the interval: Either the last change, or if SigPublish/
SigDelete is set. The latter case indicates a full sign was done and
so we no longer have to take the sign delay into account.
When introducing the kasp logic, a full sign of the zone did not
generate new signatures for the new active keys during a ZSK rollover.
The introduced kasp logic ensured that the rollover is performed
smoothly, as in the signatures are only replaced if the old signature
is close to expiring (depending on the signatures-refresh option).
Fix by maintaining a fullsign boolean value in the signing structure,
that will ensure the RRsets are signed with the correct key, rather
than a similar good key.
In case of a fullsign, we can also remove signatures from inactive
keys.
Remove the unused dns_zone_signwithkey function.
The DST_ALGORITHM_FORMATSIZE constant is unused. It could be used in
dst_kasp_key_format, but instead we will use DNS_NAME_FORMATSIZE
because it is used in other places too. Clean up the unused constant.
With named-checkconf -k you can check your configuration including
checking the dnssec-policy keys against the configured keystores. If
there is a mismatch in the key files versus the policy, named-checkconf
will fail. This is useful for running before migrating to dnssec-policy.
For logging purposes, introduce a function that writes the identifying
information about a policy key into a string.
Allow a dnssec key to be initialized outside the keymgr code.
Add 'log_errors' to 'cfg_kasp_fromconfig' to avoid duplicate error
logs.