- make tcp listening IPC pipe name saner
- put the pipe in /tmp on unices
- add pid to the pipe name to avoid conflicts between processes
- fsync directory in which the pipe resides to make sure that the
child threads will see it and be able to open it
even when worker is paused (e.g. interface reconfiguration). This is
needed to prevent deadlocks when reconfiguring interfaces - as network
manager is paused then, but we still need to stop/start listening.
- Proper handling of TCP listen errors in netmgr - bind to the socket first,
then return the error code.
When listening for TCP connections we create a socket, bind it
and then pass it over IPC to all threads - which then listen on
in and accept connections. This sounds broken, but it's the
official way of dealing with multithreaded TCP listeners in libuv,
and works on all platforms supported by libuv.
In decrement_reference only test node->down if the tree lock
is held. As node->down is not always tested in
decrement_reference we need to test that it is non NULL in
cleanup_dead_nodes prior to removing the node from the rbt
tree. Additionally it is not always possible to aquire the
node lock and reactivate a node when adding parent nodes.
Reactivate such nodes in cleanup_dead_nodes if required.
This commit makes some minor changes to the trust anchor code:
1. Replace the undescriptive n1, n2 and n3 identifiers with slightly
better rdata1, rdata2, and rdata3.
2. Fix an occurrence where in the error log message a static number
32 was printed, rather than the rdata3 length.
3. Add a default case to the switch statement checking DS digest
algorithms to catch unknown algorithms.
For BIND 9.16+, TLS aware compiler is required, and using
ISC_THREAD_LOCAL is preferred way of using Thread Local Storage. The
isc_thread_key API is no longer used anywhere and hence was removed from
BIND 9.
Previously, the irs_context API used isc_thread_key API for TLS, which is
fairly complicated and requires initialization of memory contexts, etc.
This part of code was refactored to use a ISC_THREAD_LOCAL pointer which
greatly simplifies the whole code related to storing TLS variables.
Previously, the dns_geoip API used isc_thread_key API for TLS, which is
fairly complicated and requires initialization of memory contexts, etc.
This part of code was refactored to use a ISC_THREAD_LOCAL pointer which
greatly simplifies the whole code related to storing TLS variables, and
creating the local memory context was moved to named and stored in the
named_g_geoip global context.
Previously, the dns_dt API used isc_thread_key API for TLS, which is
fairly complicated and requires initialization of memory contexts, etc.
This part of code was refactored to use a ISC_THREAD_LOCAL pointer which
greatly simplifies the whole code related to storing TLS variables.
Previously, the dns_name API used isc_thread_key API for TLS, which is
fairly complicated and requires initialization of memory contexts, etc.
This part of code was refactored to use a ISC_THREAD_LOCAL pointer which
greatly simplifies the whole code related to storing TLS variables.
The new ISC_THREAD_LOCAL macro unifies usage of platform dependent
Thread Local Storage definition thread_local vs __thread vs
__declspec(thread) to a single macro.
The commit also unifies the required level of support for TLS as for
some parts of the code it was mandatory and for some parts of the code
it wasn't.
FCTX_ATTR_SHUTTINGDOWN needs to be set and tested while holding the node
lock but the rest of the attributes don't as they are task locked. Making
fctx->attributes atomic allows both behaviours without races.
This prevents races on fctx->client whenever a new fetch joins a existing
fetch (by calling fctx_join) as it is now invariant for the active life of
fctx.
The indentation for dumping the master zone was driven by two
global variables dns_master_indent and dns_master_indentstr. In
threaded mode, this becomes prone to data access races, so this commit
converts the global variables into a local per-context tuple that
consist of count and string.
- restore support for tcp-initial-timeout, tcp-idle-timeout,
tcp-keepalive-timeout and tcp-advertised-timeout configuration
options, which were ineffective previously.
- add timeout support for TCP and TCPDNS connections to protect against
slowloris style attacks. currently, all timeouts are hard-coded.
- rework and simplify the TCPDNS state machine.
We were not reseting the keynode value when iterating over DNSKEYs in
RRSET, so we weren't checking all DNSKEYs against all trust anchors. This
commit fixes the issue by resetting keynode with every loop.
The dns_adb_beginudpfetch() is called only for UDP queries, but
the dns_adb_endudpfetch() is called for all queries, including
TCP. This messages the quota counting in adb.c.
- TSAN can't handle more than 64 locks in one thread, lock ADB bucket-by-bucket
in TSAN mode. This means that the dump won't be consistent but it's good
enough for testing
- Use proper order when unlocking adb->namelocks and adb->entrylocks when
dumping ADB.
isc_mem_traceflag_test messes with stdout/stderr, which can cause
problems with subsequent tests (no output, libuv problems). Moving that
test case to the end ensures there are no side effects.
close the uv_handle for the worker async channel, and call
uv_loop_close() on shutdown to ensure that the event loop's
internal resources are properly freed.
when the TCPDNS_CLIENTS_PER_CONN limit has been exceeded for a TCP
DNS connection, switch to sequential mode to ensure that memory cannot
be exhausted by too many simultaneous queries.
-Wl,-z,interpose is not supported.
-Wl,rpath=<path> is not supported use -Wl,rpath,<path> instead.
Use @SO@ for loadable extension.
Use -L <path> -l libwrap instead of libwrap.sa.
use empty placeholder KEYDATA records for all trust anchors, not just
DS-style trust anchors.
this revealed a pre-existing bug: keyfetch_done() skips keys without
the SEP bit when populating the managed-keys zone. consequently, if a
zone only has a single ZSK which is configured as trust anchor and no
KSKs, then no KEYDATA record is ever written to the managed-keys zone
when keys are refreshed.
that was how the root server in the dnssec system test was configured.
however, previously, the KEYDATA was created when the key was
initialized; this prevented us from noticing the bug until now.
configuring a ZSK as an RFC 5011 trust anchor is not forbidden by the
spec, but it is highly unusual and not well defined. so for the time
being, I have modified the system test to generate both a KSK and ZSK
for the root zone, enabling the test to pass.
we should consider adding code to detect this condition and allow keys
without the SEP bit to be used as trust anchors if no key with the SEP
bit is available, or at minimum, log a warning.
note: this also needs further refactoring.
- when initializing RFC 5011 for a name, we populate the managed-keys
zone with KEYDATA records derived from the initial-key trust anchors.
however, with initial-ds trust anchors, there is no key. but the
managed-keys zone still must have a KEYDATA record for the name,
otherwise zone_refreshkeys() won't refresh that key. so, for
initial-ds trust anchors, we now add an empty KEYDATA record and set
the key refresh timer so that the real keys will be looked up as soon
as possible.
- when a key refresh query is done, we verify it against the
trust anchor; this is done in two ways, one with the DS RRset
set up during configuration if present, or with the keys linked
from each keynode in the list if not. because there are two different
verification methods, the loop structure is overly complex and should
be simplified.
- the keyfetch_done() and sync_keyzone() functions are both too long
and should be broken into smaller functions.
note: this is a frankensteinian kluge which needs further refactoring.
the keytable started as an RBT where the node->data points to a list of
dns_keynode structures, each of which points to a single dst_key.
later it was modified so that the list could instead point to a single
"null" keynode structure, which does not reference a key; this means
a trust anchor has been configured but the RFC 5011 refresh failed.
in this branch it is further updated to allow the first keynode in
the list to point to an rdatalist of DS-style trust anchors. these will
be used by the validator to populate 'val->dsset' when validating a zone
key.
a DS style trust anchor can be updated as a result of RFC 5011
processing to contain DST keys instead; this results in the DS list
being freed. the reverse is not possible; attempting to add a DS-style
trust anchor if a key-style trust anchor is already in place results
in an error.
later, this should be refactored to use rdatalists for both DS-style
and key-style trust anchors, but we're keeping the existing code for
old-style trust anchors for now.
- val->keynode and val->seensig were set but never used.
- val->nearest, val->soaset, val->soaname, val->nsecset and val->nsec3set
were never used at all.
- pull out the code that checks whether a key was signed by a trust
anchor into a separate function, anchor_signed().
- pull out the code that looks up a DS while validating a zone key
into a separate function, get_dsset().
- check in create_validator() whether the sigrdataset is bound, so that
we can always pass in &val->fsigrdataset during an insecurity proof;
this will allow a reduction of code duplication.
- also simplified some calls: don't pass siginfo where val->siginfo
is sufficient, don't INSIST where returning false is sufficient.
- also added header comments to several local functions.
- the netmgr was not correctly being specified when creating the task
manager, and was cleaned up in the wrong order when shutting down.
- on freebsd, timer_test appears to be prone to failure if the
netmgr is set up and torn down before and after ever test case, but
less so if it's only set up once at the beginning and once at the
end.
This commit renames isctest {mctx,lctx} to test_{mctx,lctx} and cleans
up their usage in the individual unit tests. This allows embedding
library .c files directly into the unit tests.
- ns__client_request() is now called by netmgr with an isc_nmhandle_t
parameter. The handle can then be permanently associated with an
ns_client object.
- The task manager is paused so that isc_task events that may be
triggred during client processing will not fire until after the netmgr is
finished with it. Before any asynchronous event, the client MUST
call isc_nmhandle_ref(client->handle), to prevent the client from
being reset and reused while waiting for an event to process. When
the asynchronous event is complete, isc_nmhandle_unref(client->handle)
must be called to ensure the handle can be reused later.
- reference counting of client objects is now handled in the nmhandle
object. when the handle references drop to zero, the client's "reset"
callback is used to free temporary resources and reiniialize it,
whereupon the handle (and associated client) is placed in the
"inactive handles" queue. when the sysstem is shutdown and the
handles are cleaned up, the client's "put" callback is called to free
all remaining resources.
- because client allocation is no longer handled in the same way,
the '-T clienttest' option has now been removed and is no longer
used by any system tests.
- the unit tests require wrapping the isc_nmhandle_unref() function;
when LD_WRAP is supported, that is used. otherwise we link a
libwrap.so interposer library and use that.
This allows a task to be temporary disabled so that objects won't be
processed simultaneously by libuv events and isc_task events. When a
task is paused, currently running events may complete, but no further
event will added to the run queue will be executed until the task is
unpaused.
When a task manager is created, we can now specify an `isc_nm`
object to associate with it; thereafter when the task manager is
placed into exclusive mode, the network manager will be paused.
This is a replacement for the existing isc_socket and isc_socketmgr
implementation. It uses libuv for asynchronous network communication;
"networker" objects will be distributed across worker threads reading
incoming packets and sending them for processing.
UDP listener sockets automatically create an array of "child" sockets
so each worker can listen separately.
TCP sockets are shared amongst worker threads.
A TCPDNS socket is a wrapper around a TCP socket, which handles the
the two-byte length field at the beginning of DNS messages over TCP.
(Other wrapper socket types can be implemented in the future to handle
DNS over TLS, DNS over HTTPS, etc.)
The double-locked queue implementation is still currently in use
in ns_client, but will be replaced by a fetch-and-add array queue.
This commit moves it from queue.h to list.h so that queue.h can be
used for the new data structure, and clean up dependencies between
list.h and types.h. Later, when the ISC_QUEUE is no longer is use,
it will be removed completely.
'dnssec-policy' can now also be set on the options and view level and
a zone that does not set 'dnssec-policy' explicitly will inherit it
from the view or options level.
This requires a new keyword to be introduced: 'none'. If set to
'none' the zone will not be DNSSEC maintained, in other words it will
stay unsigned. You can use this to break the inheritance. Of course
you can also break the inheritance by referring to a different
policy.
The keywords 'default' and 'none' are not allowed when configuring
your own dnssec-policy statement.
Add appropriate tests for checking the configuration (checkconf)
and add tests to the kasp system test to verify the inheritance
works.
Edit the kasp system test such that it can deal with unsigned zones
and views (so setting a TSIG on the query).
The kasp system tests are updated with 'check_cds' calls that will
verify that the correct CDS and CDNSKEY records are published during
a rollover and that they are signed with the correct KSK.
This requires a change in 'dnssec.c' to check the kasp key states
whether the CDS/CDNSKEY of a key should be published or not. If no
kasp state exist, fall back to key timings.
The 'sign_apex()' function has special processing for signing the
DNSKEY RRset such that it will always be signed with the active
KSK. Since CDS and CDNSKEY are also signed with the KSK, it
should have the same special processing. The special processing is
moved into a new function 'tickle_apex_rrset()' and is applied to
all three RR types (DNSKEY, CDS, CDNSKEY).
In addition, when kasp is involved, update the DNSKEY TTL accordingly
to what is in the policy.
Update dns_dnssec_keyactive to differentiate between the roles ZSK
and KSK. A key is active if it is signing but that differs per role.
A ZSK is signing if its ZRRSIG state is in RUMOURED or OMNIPRESENT,
a KSK is signing if its KRRSIG state is in RUMOURED or OMNIPRESENT.
This means that a key can be actively signing for one role but not
the other. Add checks in inline signing (zone.c and update.c) to
cover the case where a CSK is active in its KSK role but not the ZSK
role.
Update the signing code in lib/dns/zone.c and lib/dns/update.c to
use kasp logic if a dnssec-policy is enabled.
This means zones with dnssec-policy should no longer follow
'update-check-ksk' and 'dnssec-dnskey-kskonly' logic, instead the
KASP keys configured dictate which RRset gets signed with what key.
Also use the next rekey event from the key manager rather than
setting it to one hour.
Mark the zone dynamic, as otherwise a zone with dnssec-policy is
not eligble for automatic DNSSEC maintenance.
Update dns_dnssec_get_hints and dns_dnssec_keyactive to use dst_key
functions and thus if dnssec-policy/KASP is used the key states are
being considered.
Add a new variable to 'struct dns_dnsseckey' to signal whether this
key is a zone-signing key (it is no longer true that ksk == !zsk).
Also introduce a hint for revoke.
Update 'dns_dnssec_findzonekeys' and 'dns_dnssec_findmatchingkeys'
to also read the key state file, if available.
Remove 'allzsk' from 'dns_dnssec_updatekeys' as this was only a
hint for logging.
Also make get_hints() (now dns_dnssec_get_hints()) public so that
we can use it in the key manager.
Add a key manager to named. If a 'dnssec-policy' is set, 'named'
will run a key manager on the matching keys. This will do a couple
of things:
1. Create keys when needed (in case of rollover for example)
according to the set policy.
2. Retire keys that are in excess of the policy.
3. Maintain key states according to "Flexible and Robust Key
Rollover" [1]. After key manager ran, key files will be saved to
disk.
[1] https://matthijsmekking.nl/static/pdf/satin2012-Schaeffer.pdf
KEY GENERATION
Create keys according to DNSSEC policy. Zones configured with
'dnssec-policy' will allow 'named' to create DNSSEC keys (similar
to dnssec-keymgr) if not available.
KEY ROLLOVER
Rather than determining the desired state from timing metadata,
add a key state goal. Any keys that are created or picked from the
key ring and selected to be a successor has its key state goal set
to OMNIPRESENT (this key wants to be signing!). At the same time,
a key that is being retired has its key state goal set to HIDDEN.
The keymgr state machine with the three rules will make sure no
introduction or withdrawal of DNSSEC records happens too soon.
KEY TIMINGS
All timings are based on RFC 7583.
The keymgr will return when the next action is happening so
that the zone can set the proper rekey event. Prior to this change
the rekey event will run every hour by default (configurable),
but with kasp we can determine exactly when we need to run again.
The prepublication time is derived from policy.
Add a couple of dst_key functions for determining hints that
consider key states if they are available.
- dst_key_is_unused:
A key has no timing metadata set other than Created.
- dst_key_is_published:
A key has publish timing metadata <= now, DNSKEY state in
RUMOURED or OMNIPRESENT.
- dst_key_is_active:
A key has active timing metadata <= now, RRSIG state in
RUMOURED or OMNIPRESENT.
- dst_key_is_signing:
KSK is_signing and is_active means different things than
for a ZSK. A ZSK is active means it is also signing, but
a KSK always signs its DNSKEY RRset but is considered
active if its DS is present (rumoured or omnipresent).
- dst_key_is_revoked:
A key has revoke timing metadata <= now.
- dst_key_is_removed:
A key has delete timing metadata <= now, DNSKEY state in
UNRETENTIVE or HIDDEN.
When doing rollover in a timely manner we need to have access to the
relevant kasp configured durations.
Most of these are simple get functions, but 'dns_kasp_signdelay'
will calculate the maximum time that is needed with this policy to
resign the complete zone (taking into account the refresh interval
and signature validity).
Introduce parent-propagation-delay, parent-registration-delay,
parent-ds-ttl, zone-max-ttl, zone-propagation-delay.
When signing a zone with dnssec-policy, we don't mind DNSSEC records.
This is useful for testing purposes, and perhaps it is better to
signal this behavior with a different configuration option.
Introduce a new option '-s' for dnssec-settime that when manipulating
timing metadata, it also updates the key state file.
For testing purposes, add options to dnssec-settime to set key
states and when they last changed.
The dst code adds ways to write and read the new key states and
timing metadata. It updates the parsing code for private key files
to not parse the newly introduced metadata (these are for state
files only).
Introduce key goal (the state the key wants to be in).
When reading a key from file, you can set the DST_TYPE_STATE option
to also read the key state.
This expects the Algorithm and Length fields go above the metadata,
so update the write functionality to do so accordingly.
Introduce new DST metadata types for KSK, ZSK, Lifetime and the
timing metadata used in state files.
Write functions to access various elements of the kasp structure,
and the kasp keys. This in preparation of code in dnssec-keygen,
dnssec-settime, named...
Add a number of metadata variables (lifetime, ksk and zsk role).
For the roles we add a new type of metadata (booleans).
Add a function to write the state of the key to a separate file.
Only write out known metadata to private file. With the
introduction of the numeric metadata "Lifetime", adjust the write
private key file functionality to only write out metadata it knows
about.