Commit Graph

8727 Commits

Author SHA1 Message Date
Ondřej Surý
9dd8deaf01 Call the connected dns_dispatch callback asynchronously
The dns_request code is very sensitive about calling the connected and
deadlocks when the timing is "right" in several places.  Move the call
to the connected callback to the (udp|tcp)_connected() functions, so
they are called asynchronously instead of directly from
the (udp|tcp)_dispentry_cancel() functions.
2022-12-21 12:13:35 +01:00
Ondřej Surý
3fac4ca57e Ignore TCP dispatches that have zero references
The TCP dispatches are removed from the dispatchmgr->list in the
dispatch_destroy() and there's a brief period of time where
dns_dispatch_gettcp() can find a dispatch in connected state that's
being destroyed.

Set the dispatch state to DNS_DISPATCHSTATE_NONE in the TCP connection
callback if there are no responses waiting, and ignore TCP dispatches
with zero references in dns_dispatch_gettcp().
2022-12-21 12:13:35 +01:00
Ondřej Surý
90cd14f620 Fix assignment vs comparison typo in tcp_connected()
In tcp_connected() a typo has turned a DbC check into an assignment
breaking the state machine and making the dns_dispatch_gettcp() try to
attach to dispatch in process of destruction.
2022-12-21 12:13:20 +01:00
Ondřej Surý
7310e2b424 Don't remove dispatches in CANCELED state from the list
In dns_dispatch_gettcp(), we can't remove canceled dispatches from the
mgr->list because ISC_LIST_NEXT() would fail in the next iteration.
2022-12-21 12:13:20 +01:00
Ondřej Surý
6d22d03208 Ignore TCP dispatches in DNS_DISPATCHSTATE_NONE state
The TCP dispatches in DNS_DISPATCHSTATE_NONE could be either very
fresh or those could be dispatches that failed connecting to the
destination.  Ignore them when trying to connect to an existing
TCP dispatch via dns_dispatch_gettcp().
2022-12-21 12:13:20 +01:00
Artem Boldariev
cce52fa4a2 BIND: use Stream DNS for DNS over TCP connections
This commit makes BIND use the new Stream DNS transport for DNS over
TCP.
2022-12-20 22:13:53 +02:00
Artem Boldariev
03e33a014c BIND: use Stream DNS for DNS over TLS connections
This commit makes BIND use the new Stream DNS transport for DNS over
TLS.
2022-12-20 22:13:52 +02:00
Ondřej Surý
6bd2b34180 Enable auto-reallocation for all isc_buffer_allocate() buffers
When isc_buffer_t buffer is created with isc_buffer_allocate() assume
that we want it to always auto-reallocate instead of having an extra
call to enable auto-reallocation.
2022-12-20 19:13:48 +01:00
Ondřej Surý
135ec7a0f0 Remove single use isc_buffer_putdecint() function
The isc_buffer_putdecint() could be easily replaced with
isc_buffer_printf() with just a small overhead of calling vsnprintf()
twice instead once.  This is not on a hot-path (dns_catz unit), so we
can ignore the overhead and instead have less single-use code in favor
of using reusable more generic function.
2022-12-20 19:13:48 +01:00
Ondřej Surý
aea251f3bc Change the isc_buffer_reserve() to take just buffer pointer
The isc_buffer_reserve() would be passed a reference to the buffer
pointer, which was unnecessary as the pointer would never be changed
in the current implementation.  Remove the extra dereference.
2022-12-20 19:13:48 +01:00
Ondřej Surý
6f317f27ea Fix the thread safety in the dns_dispatch unit
The dispatches are not thread-bound, and used freely between various
threads (see the dns_resolver and dns_request units for details).

This refactoring make sure that all non-const dns_dispatch_t and
dns_dispentry_t members are accessed under a lock, and both object now
track their internal state (NONE, CONNECTING, CONNECTED, CANCELED)
instead of guessing the state from the state of various struct members.

During the refactoring, the artificial limit DNS_DISPATCH_SOCKSQUOTA on
UDP sockets per dispatch was removed as the limiting needs to happen and
happens on in dns_resolver and limiting the number of UDP sockets
artificially in dispatch could lead to unpredictable behaviour in case
one dispatch has the limit exhausted by others are idle.

The TCP artificial limit of DNS_DISPATCH_MAXREQUESTS makes even less
sense as the TCP connections are only reused in the dns_request API
that's not a heavy user of the outgoing connections.

As a side note, the fact that UDP and TCP dispatch pretends to be same
thing, but in fact the connected UDP is handled from dns_dispentry_t and
dns_dispatch_t acts as a broker, but connected TCP is handled from
dns_dispatch_t and dns_dispatchmgr_t acts as a broker doesn't really
help the clarity of this unit.

This refactoring kept to API almost same - only dns_dispatch_cancel()
and dns_dispatch_done() were merged into dns_dispatch_done() as we need
to cancel active netmgr handles in any case to not leave dangling
connections around.  The functions handling UDP and TCP have been mostly
split to their matching counterparts and the dns_dispatch_<function>
functions are now thing wrappers that call <udp|tcp>_dispatch_<function>
based on the socket type.

More debugging-level logging was added to the unit to accomodate for
this fact.
2022-12-19 11:42:13 +01:00
Ondřej Surý
32ff134eeb Fix reference counting in get_attached_entry (again)
When get_attached_entry() encounters entry that would be expired, it
needs to get reference to the entry before calling maybe_expire_entry(),
so the ADB entry doesn't get destroyed inside the its own lock.

This creeped into the code base again during review, so I am adding
an extra comment to prevent this.
2022-12-16 21:48:43 +01:00
Ondřej Surý
0b661b6f95 Don't expire fresh ADB names and entries
The overmem cleaning in ADB could become overzealous and clean fresh ADB
names and entries.  Add a safety check to not clean any ADB names and
entries that are below ADB_CACHE_MINIMUM threshold.
2022-12-15 16:15:19 +01:00
Ondřej Surý
59dee0b078 Exclude the ADB hashmaps from ADB overmem accounting
The ADB overmem accounting would include the memory used by hashtables
thus vastly reducing the space that can be used for ADB names and
entries when the hashtables would grow.  Create own memory context for
the ADB names and entries hash tables.
2022-12-15 16:14:16 +01:00
Ondřej Surý
a27ea1bba0 Lock the adbname and adbentry prior to unlocking hash locks
There was a datarace that could expire a freshly created ADB names and
entries between the return from get_attached_{name,entry} and locking it
again.  Lock the ADB name and ADB entry inside the hash table lock, so
they won't get expired until the full initialization has been complete.
2022-12-15 15:19:22 +01:00
Aram Sargsyan
72b1760ea6 Fix logging a uint32_t SOA serial value in dns_catz_update_from_db()
The dns_catz_update_from_db() function prints serial number as a signed
number (with "%d" in the format string), but the `vers` variable's type
is 'uint32_t'. This breaks serials bigger than 2^31.

Use PRIu32 instead of "d" in the format string.
2022-12-15 13:24:58 +00:00
Aram Sargsyan
03442d922b Clean up and refactor dns_adb_getcookie()
The dns_adb_getcookie() doesn't use the 'adb' parameter, remove it.

Refactor the dns_adb_getcookie() function to just return the size of
the cookie when the caller passes 'NULL' as the 'cookie' argument.
2022-12-15 12:34:26 +00:00
Ondřej Surý
578de673b1 Replace zonemgr_keymgmt own hash table with isc_hashmap
Instead of maintaining own hashtable implementation for zonemgr_keymgmt,
use isc_hashmap that already can resize (grow and shrink).
2022-12-14 19:37:07 +01:00
Ondřej Surý
b8c7dc2dc2 Expire names in shutdown_names() under the lock
Since there could be fetches running, we need to run expire_name() under
the lock when shutting down the names.
2022-12-14 18:49:18 +01:00
Ondřej Surý
5466a48fc9 Try next server on resolver timeout
Instead of resending to the same server on the (dispatch) timeout in the
resolver, try the next server.
2022-12-14 18:49:18 +01:00
Ondřej Surý
7292ee6d92 Fix intermittent memory leak in dns_resolver unit
A rdataset could have been left unassociated on the error path in the
resume_dslookup() in the dns_resolver unit.  Clone the rdataset after
the error check, so it's not cloned before we check whether we can make
further progress chasing DS records.
2022-12-14 10:48:06 +01:00
Tony Finch
c18a9a208d Fix a typo RSASHA236 -> RSASHA256
Use dns_secalg_format() to avoid error-prone repetition.
2022-12-13 16:58:02 +00:00
Ondřej Surý
79115a0c3b Implement proper reference counting for dns_keyfileio_t
Instead of relying on hash table search when using the keys, implement a
proper reference counting in dns_keyfileio_t objects, and attach/detach
the objects to the zone.
2022-12-09 14:27:44 +01:00
Ondřej Surý
fb1acd6736 Release unused key file IO lock objects
Due to off-by-one error in zonemgr_keymgmt_delete, unused key file IO
lock objects were never freed and they were kept until the server
shutdown.  Adjust the returned value by -1 to accomodate the fact that
the atomic_fetch_*() functions return the value before the operation and
not current value after the operation.
2022-12-08 08:30:30 +01:00
Mark Andrews
1a39328feb Remove different zero TTL handling for rdataset iterator
Zero TTL handling does not need to be different for 'rdatasetiter_first'
and 'rdatasetiter_next' and it interacts badly with 'bind_rdatadataset'
which makes different determinations.
2022-12-07 22:20:02 +00:00
Mark Andrews
85048ddeee Add dns_db_allrdatasets options
'DNS_DB_STALEOK' returns stale rdatasets as well as current rdatasets.

'DNS_DB_EXPIREDOK' returns expired rdatasets as well as current
rdatasets. This option is currently only set when DNS_DB_STALEOK is
also set.
2022-12-07 22:20:02 +00:00
Mark Andrews
7695c36a5d Extend dns_db_allrdatasets to control interation results
Add an options parameter to control what rdatasets are returned when
iteratating over the node.  Specific modes will be added later.
2022-12-07 22:20:02 +00:00
Mark Andrews
3bdab2d111 Properly select active rdatasets when iterating across node
Active rdatasets where not being properly selected in rdatasetiter_first
and rdatasetiter_next.
2022-12-07 22:20:02 +00:00
Mark Andrews
90249e4aa5 Revert "Fix rndc dumpdb -expired for stuck cache contents"
This reverts commit f8d866c6ef.
2022-12-07 22:20:02 +00:00
Ondřej Surý
715343c31d Remove dead code from dns_cache_flush()
After removing the cache cleaning mechanism, we don't need to db
iterator in dns_cache_flush() anymore.
2022-12-07 19:11:08 +01:00
Ondřej Surý
c2be97eeff Fix reference counting in get_attached_entry
When get_attached_entry() encounters entry that would be expired, it
needs to get reference to the entry before calling maybe_expire_entry(),
so the ADB entry doesn't get destroyed inside the its own lock.
2022-12-07 16:16:22 +01:00
Mark Andrews
b1086a5561 Add missing DbC magic checks
Checking for value != NULL is not sufficient to detect use after
free errors.
2022-12-07 09:04:08 +11:00
Mark Andrews
35839e91d8 Call dns_db_updatenotify_unregister earlier
dns_db_updatenotify_unregister needed to be called earlier to ensure
that listener->onupdate_arg always points to a valid object.  The
existing lazy cleanup in rbtdb_free did not ensure that.
2022-12-07 09:04:08 +11:00
Mark Andrews
f13e71e551 Suppress duplicate dns_db_updatenotify_register registrations
Duplicate dns_db_updatenotify_register registrations need to be
suppressed to ensure that dns_db_updatenotify_unregister is successful.
2022-12-07 09:04:08 +11:00
Mark Andrews
e8e40e2e01 Check that DS records are only present at delegations
This extends the integrity check to look for stray DS records
in the zone.
2022-12-06 23:27:40 +11:00
Mark Andrews
94008863de Add RUNTIME_CHECK for dns_rdata_tostruct 2022-12-04 21:41:02 +00:00
Ondřej Surý
7e4e125e5e Refactor the dns_resolver fetch context hash tables and locking
This is second in the series of fixing the usage of hashtables in the
dns_adb and the dns_resolver units.

Currently, the fetch buckets (used to hold the fetch context) and zone
buckets (used to hold per-domain counters) would never get cleaned from
the memory.  Combined with the fact that the hashtable now grows as
needed (instead of using hashtable as buckets), the memory usage in the
resolver can just grow and it never drops down.

In this commit, the usage of hashtables (hashmaps) has been completely
rewritten, so there are no "buckets" and all the matching conditions are
directly mapped into the hashtable key:

 1. For per-domain counter hashtable, this is simple as the lowercase
    domain name is used directly as a counter.

 2. For fetch context hashtable, this requires copying some extra flags
    back and forth in the key.

As we don't hold the "buckets" forever, the cleaning mechanism has been
rewritten as well:

 1. For per-domain counter hashtable, this is again much simpler, as we
    only need to check whether the usage counter is still zero under the
    lock and bail-out on cleaning if the counter is in use.

 2. For fetch context hashtable, this is more complicated as the fetch
    context cannot be reused after it has been finished.  The algorithm
    is different, the fetch context is always removed from the
    hashtable, but if we find the fetch context that has been marked
    as finished in the lookup function, we help with the cleaning from
    the hashtable and try again.

Couple of additional changes have been implemented in this refactoring
as those were needed for correct functionality and could not be split
into individual commits (or would not make sense as seperate commits):

 1. The dns_resolver_createfetch() has an option to create "unshared"
    fetch.  The "unshared" fetch will never get matched, so there's
    little point in storing the "unshared" fetch in the hashtable.
    Therefore the "unshared" fetches are now detached from the
    hashtable and live just on their own.

 2. Replace the custom reference counting with ISC_REFCOUNT_DECL/IMPL
    macros for better tracing.

 3. fctx_done_detach() is idempotent, it makes the "final" detach (the
    one matching the create function) only once.  But that also means
    that it has to be called before the detach that kept the fetch
    context alive in the callback.  A new macro fctx_done_unref() has
    been added to allow this code flow:

    fctx_done_unref(fctx, result);
    fctx_detach(&fctx);

    Doing this the other way around could cause fctx to get destroyed in
    the fctx_unref() first and fctx_done_detach() would cause UAF.

 4. The resume_qmin() and resume_dslookup() callbacks have been
    refactored for more readability and simpler code paths.  The
    validated() callback has also received some of the simplifications,
    but it should be refactored in the future as it is bit of spaghetti
    now.
2022-12-01 11:42:46 +01:00
Evan Hunt
09ee254514 change dns_db_settask() to _setloop()
The mechanism for associating a worker task to a database now
uses loops rather than tasks.

For this reason, the parameters to dns_cache_create() have been
updated to take a loop manager rather than a task manager.
2022-11-30 11:47:35 -08:00
Tony Finch
a8f1d0c19c Compress zone transfers properly
After change 5995, zone transfers were using a small
compression context that only had space for the first
few dozen names in each message. They now use a large
compression context with enough space for every name.
2022-11-30 12:16:09 +00:00
Ondřej Surý
1816244725 Don't log "final reference detached" on INFO level
The "final reference detached" message was meant to be DEBUG(1), but was
instead kept at INFO level.  Move it to the DEBUG(1) logging level, so
it's not printed under normal operations.
2022-11-30 11:04:45 +01:00
Ondřej Surý
35d8d72dd8 Keep the unlink adb entries until expiration
Currently, the ADB uses TTL of 0 for ADB names that the server is
authoritative for and TTL of 10 seconds for HINT and GLUE ADB names.

This requires the unlinked ADB entries to be kept around, because they
would disappear too quickly.  This especially affect the root zone as
the trust level is "ultimate" for the root zone nameservers.

This commit restores the ability to keep the unlinked ADB entries in the
database for later reuse, restores printing the unlinked entries and
adds some extra cleaning of the unlinked ADB entries on the tail of the
LRU list (similar to what we are doing for the ADB names).
2022-11-30 10:03:24 +01:00
Ondřej Surý
50f357cb36 Refactor the dns_adb unit
The dns_adb unit has been refactored to be much simpler.  Following
changes have been made:

1. Simplify the ADB to always allow GLUE and hints

   There were only two places where dns_adb_createfind() was used - in
   the dns_resolver unit where hints and GLUE addresses were ok, and in
   the dns_zone where dns_adb_createfind() would be called without
   DNS_ADBFIND_HINTOK and DNS_ADBFIND_GLUEOK set.

   Simplify the logic by allowing hint and GLUE addresses when looking
   up the nameserver addresses to notify.  The difference is negligible
   and would cause a difference in the notified addresses only when
   there's mismatch between the parent and child addresses and we
   haven't cached the child addresses yet.

2. Drop the namebuckets and entrybuckets

   Formerly, the namebuckets and entrybuckets were used to reduced the
   lock contention when accessing the double-linked lists stored in each
   bucket.  In the previous refactoring, the custom hashtable for the
   buckets has been replaced with isc_ht/isc_hashmap, so only a single
   item (mostly, see below) would end up in each bucket.

   Removing the entrybuckets has been straightforward, the only matching
   was done on the isc_sockaddr_t member of the dns_adbentry.

   Removing the zonebuckets required GLUEOK and HINTOK bits to be
   removed because the find could match entries with-or-without the bits
   set, and creating a custom key that stores the
   DNS_ADBFIND_STARTATZONE in the first byte of the key, so we can do a
   straightforward lookup into the hashtable without traversing a list
   that contains items with different flags.

3. Remove unassociated entries from ADB database

   Previously, the adbentries could live in the ADB database even after
   unlinking them from dns_adbnames.  Such entries would show up as
   "Unassociated entries" in the ADB dump.  The benefit of keeping such
   entries is little - the chance that we link such entry to a adbname
   is small, and it's simpler to evict unlinked entries from the ADB
   cache (and the hashtable) than create second LRU cleaning mechanism.

   Unlinked ADB entries are now directly deleted from the hash
   table (hashmap) upon destruction.

4. Cleanup expired entries from the hash table

   When buckets were still in place, the code would keep the buckets
   always allocated and never shrink the hash table (hashmap).  With
   proper reference counting in place, we can delete the adbnames from
   the hash table and the LRU list.

5. Stop purging the names early when we hit the time limit

   Because the LRU list is now time ordered, we can stop purging the
   names when we find a first entry that doesn't fullfil our time-based
   eviction criteria because no further entry on the LRU list will meet
   the criteria.

Future work:

1. Lock contention

   In this commit, the focus was on correctness of the data structure,
   but in the future, the lock contention in the ADB database needs to
   be addressed.  Currently, we use simple mutex to lock the hash
   tables, because we almost always need to use a write lock for
   properly purging the hashtables.  The ADB database needs to be
   sharded (similar to the effect that buckets had in the past).  Each
   shard would contain own hashmap and own LRU list.

2. Time-based purging

   The ADB names and entries stay intact when there are no lookups.
   When we add separate shards, a timer needs to be added for time-based
   cleaning in case there's no traffic hashing to the inactive shard.

3. Revisit the 30 minutes limit

   The ADB cache is capped at 30 minutes.  This needs to be revisited,
   and at least the limit should be configurable (in both directions).
2022-11-30 10:03:24 +01:00
Ondřej Surý
66d8bb03cb Create per-thread task for dns_adb resolver fetches
The dns_adb would serialize all fetches on a single task.  Create a
per-thread task, so the fetches will stay local to the thread that
initiated the fetch.
2022-11-30 10:03:24 +01:00
Ondřej Surý
0d4ef6fcd7 Expire namehooks when purging stale ADB names
Instead of trying to expire entries from adbentrybuckets, expire the
namehooks while purging the stale ADB names.
2022-11-30 10:03:23 +01:00
Ondřej Surý
557a71a6f9 Purge stale ADB names globaly, not per bucket
Before the refactoring, there was only few buckets with many names in
them, so cleaning up stale ADB names per-bucket made sense.  After the
refactoring, each bucket directly maps to ADB name, so purging has been
effectively disabled.

Create a global LRU list for ADB names (and ADB entries) and purge the
stale ADB names globally.
2022-11-30 10:03:23 +01:00
Ondřej Surý
327768e280 dns_adb: Remove deadnames and deadentries
Previously, the name and entry buckets were much larger, so the dead
names and entries were moved to a secondary list to be cleaned
later (f.e. after the already running fetch has been canceled).  After
the last refactoring, the bucket now contains only the name (entry)
itself and thus the extra list has a little use.  Remove the .deadnames
and .deadentries from dns_adbnamebucket_t and dns_adbentrybucket_t
structures.
2022-11-30 10:03:23 +01:00
Ondřej Surý
77659e7392 Refactor dns_rpz unit to use single reference counting
The dns_rpz_zones structure was using .refs and .irefs for strong and
weak reference counting.  Rewrite the unit to use just a single
reference counting + shutdown sequence (dns_rpz_destroy_rpzs) that must
be called by the creator of the dns_rpz_zones_t object.  Remove the
reference counting from the dns_rpz_zone structure as it is not needed
because the zone objects are fully embedded into the dns_rpz_zones
structure and dns_rpz_zones_t object must never be destroyed before all
dns_rpz_zone_t objects.

The dns_rps_zones_t reference counting uses the new ISC_REFCOUNT_TRACE
capability - enable by defining DNS_RPZ_TRACE in the dns/rpz.h header.

Additionally, add magic numbers to the dns_rpz_zone and dns_rpz_zones
structures.
2022-11-30 09:59:35 +01:00
Ondřej Surý
fa275a59da Remove the unused cache cleaning mechanism from dns_cache API
The dns_cache API contained a cache cleaning mechanism that would be
disabled for 'rbt' based cache.  As named doesn't have any other cache
implementations, remove the cache cleaning mechanism from dns_cache API.
2022-11-29 13:48:33 -08:00
Ondřej Surý
5e4a26856c Remove the dead external cache cleaning mechanism from RBTDB
The RBTDB has own cache cleaning mechanism and therefor the iterator
.cleaning member would never be set to true.  Remove the code that
checks for iterator->cleaning from the RBTDB.
2022-11-29 13:48:33 -08:00
Michal Nowak
afdb41a5aa Update sources to Clang 15 formatting 2022-11-29 08:54:34 +01:00