2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-30 22:15:20 +00:00
Commit Graph

14256 Commits

Author SHA1 Message Date
Aram Sargsyan
ac889684c7 Unlink the query under cleanup_query
In the cleanup code of fctx_query() function there is a code path
where 'query' is linked to 'fctx' and it is being destroyed.

Make sure that 'query' is unlinked before destroying it.
2022-10-21 08:08:37 +00:00
Evan Hunt
305a50dbe1 ensure RPZ lookups handle CD=1 correctly
RPZ rewrites called dns_db_findext() without passing through the
client database options; as as result, if the client set CD=1,
DNS_DBFIND_PENDINGOK was not used as it should have been, and
cache lookups failed, resulting in failure of the rewrite.
2022-10-19 11:36:11 -07:00
Ondřej Surý
13959781cb Serialize the HTTP/1.1 statschannel requests
The statschannel truncated test still terminates abruptly sometimes and
it doesn't return the answer for the first query.  This might happen
when the second process_request() discovers there's not enough space
before the sending is complete and the connection is terminated before
the client gets the data.

Change the isc_http, so it pauses the reading when it receives the data
and resumes it only after the sending has completed or there's
incomplete request waiting for more data.

This makes the request processing slightly less efficient, but also less
taxing for the server, because previously all requests that has been
received via single TCP read would be processed in the loop and the
sends would be queued after the read callback has processed a full
buffer.
2022-10-19 14:45:36 +02:00
Ondřej Surý
dfaae53b9a Fix the non-developer build with OpenSSL 1.0.2
In non-developer build, a wrong condition prevented the
isc__tls_malloc_ex, isc__tls_realloc_ex and isc__tls_free_ex to be
defined.  This was causing FTBFS on platforms with OpenSSL 1.0.2.
2022-10-19 14:41:10 +02:00
Artem Boldariev
09dcc914b4 TLS Stream: handle successful TLS handshake after listener shutdown
It was possible that accept callback can be called after listener
shutdown. In such a case the callback pointer equals NULL, leading to
segmentation fault. This commit fixes that.
2022-10-18 18:30:24 +03:00
Matthijs Mekking
a1d57fc8cb Change log level when doing rekey
This log happens when BIND checks the parental-agents if the DS has
been published. But if you don't have parental-agents set up, the list
of keys to check will be empty and the result will be ISC_R_NOTFOUND.
This is not an error, so change the log level to debug in this case.
2022-10-18 16:23:35 +02:00
Ondřej Surý
5e20c2ccfb Replace (void *)-1 with ISC_LINK_TOMBSTONE
Instead of having "arbitrary" (void *)-1 to define non-linked, add a
ISC_LINK_TOMBSTONE(type) macro that replaces the "magic" value with a
define.
2022-10-18 11:36:15 +02:00
Ondřej Surý
cb3c36b8bf Add ISC_{LIST,LINK}_INITIALIZER for designated initializers
Since we are using designated initializers, we were missing initializers
for ISC_LIST and ISC_LINK, add them, so you can do

    *foo = (foo_t){ .list = ISC_LIST_INITIALIZER };

Instead of:

    *foo = (foo_t){ 0 };
    ISC_LIST_INIT(foo->list);
2022-10-18 11:36:15 +02:00
Artem Boldariev
5ab2c0ebb3 Synchronise stop listening operation for multi-layer transports
This commit introduces a primitive isc__nmsocket_stop() which performs
shutting down on a multilayered socket ensuring the proper order of
the operations.

The shared data within the socket object can be destroyed after the
call completed, as it is guaranteed to not be used from within the
context of other worker threads.
2022-10-18 12:06:00 +03:00
Tony Finch
26ed03a61e Include the function name when reporting unexpected errors
I.e. print the name of the function in BIND that called the system
function that returned an error. Since it was useful for pthreads
code, it seems worthwhile doing so everywhere.
2022-10-17 13:43:59 +01:00
Tony Finch
a34a2784b1 De-duplicate some calls to strerror_r()
Specifically, when reporting an unexpected or fatal error.
2022-10-17 11:58:26 +01:00
Tony Finch
ec50c58f52 De-duplicate __FILE__, __LINE__
Mostly generated automatically with the following semantic patch,
except where coccinelle was confused by #ifdef in lib/isc/net.c

@@ expression list args; @@
- UNEXPECTED_ERROR(__FILE__, __LINE__, args)
+ UNEXPECTED_ERROR(args)
@@ expression list args; @@
- FATAL_ERROR(__FILE__, __LINE__, args)
+ FATAL_ERROR(args)
2022-10-17 11:58:26 +01:00
Aram Sargsyan
fddaebb285 Handle large numbers when parsing/printing a duration
The isccfg_duration_fromtext() function is truncating large numbers
to 32 bits instead of capping or rejecting them, i.e. 64424509445,
which is 0xf00000005, gets parsed as 32-bit value 5 (0x00000005).

Fail parsing a duration if any of its components is bigger than
32 bits. Using those kind of big numbers has no practical use case
for a duration.

The isccfg_duration_toseconds() function can overflow the 32 bit
seconds variable when calculating the duration from its component
parts.

To avoid that, use 64-bit calculation and return UINT32_MAX if the
calculated value is bigger than UINT32_MAX. Again, a number this big
has no practical use case anyway.

The buffer for the generated duration string is limited to 64 bytes,
which, in theory, is smaller than the longest possible generated
duration string.

Use 80 bytes instead, calculated by the '7 x (10 + 1) + 3' formula,
where '7' is the count of the duration's parts (year, month, etc.), '10'
is their maximum length when printed as a decimal number, '1' is their
indicator character (Y, M, etc.), and 3 is two more indicators (P and T)
and the terminating NUL character.
2022-10-17 08:45:45 +00:00
Aram Sargsyan
dc55f1ebb9 Fix an off-by-one error in cfg_print_duration()
The cfg_print_duration() checks added previously in the 'duration_test'
unit test uncovered a bug in cfg_print_duration().

When calculating the current 'str' pointer of the generated text in the
buffer 'buf', it erroneously adds 1 byte to compensate for that part's
indicator character. For example, to add 12 minutes, it needs to add
2 + 1 = 3 characters, where 2 is the length of "12", and 1 is the length
of "M" (for minute). The mistake was that the length of the indicator
is already included in 'durationlen[i]', so there is no need to
calculate it again.

In the result of this mistake the current pointer can advance further
than needed and end up after the zero-byte instead of right on it, which
essentially cuts off any further generated text. For example, for a
5 minutes and 30 seconds duration, instead of having this:

    'P', 'T', '5', 'M', '3', '0', 'S', '\0'

The function generates this:

    'P', 'T', '5', 'M', '\0', '3', '0', 'S', '\0'

Fix the bug by adding to 'str' just 'durationlen[i]' instead of
'durationlen[i] + 1'.
2022-10-17 08:45:26 +00:00
Aram Sargsyan
9440910187 Fix a logical bug in cfg_print_duration()
The cfg_print_duration() function prints a ISO 8601 duration value
converted from an array of integers, where the parts of the date and
time are stored.

durationlen[6], which holds the "seconds" part of the duration, has
a special case in cfg_print_duration() to ensure that when there are
no values in the duration, the result still can be printed as "PT0S",
instead of just "P", so it can be a valid ISO 8601 duration value.

There is a logical error in one of the two special case code paths,
when it checks that no value from the "date" part is defined, and no
"hour" or "minute" from the "time" part are defined.

Because of the error, durationlen[6] can be used uninitialized, in
which case the second parameter passed to snprintf() (which is the
maximum allowed length) can contain a garbage value.

This can not be exploited because the buffer is still big enough to
hold the maximum possible amount of characters generated by the "%u%c"
format string.

Fix the logical bug, and initialize the 'durationlen' array to zeros
to be a little safer from other similar errors.
2022-10-17 08:45:09 +00:00
Tony Finch
45b2d8938b Simplify and speed up DNS name compression
All we need for compression is a very small hash set of compression
offsets, because most of the information we need (the previously added
names) can be found in the message using the compression offsets.

This change combines dns_compress_find() and dns_compress_add() into
one function dns_compress_name() that both finds any existing suffix,
and adds any new prefix to the table. The old split led to performance
problems caused by duplicate names in the compression context.

Compression contexts are now either small or large, which the caller
chooses depending on the expected size of the message. There is no
dynamic resizing.

There is a behaviour change: compression now acts on all the labels in
each name, instead of just the last few.

A small benchmark suggests this is about 2x faster.
2022-10-17 08:45:44 +02:00
Artem Boldariev
d62eb206f7 Fix isc_nmsocket_set_tlsctx()
During loop manager refactoring isc_nmsocket_set_tlsctx() was not
properly adapted. The function is expected to broadcast the new TLS
context for every worker, but this behaviour was accidentally broken.
2022-10-14 23:06:31 +03:00
Ondřej Surý
cedfc97974 Improve reporting for pthread_once errors
Replace all uses of RUNTIME_CHECK() in lib/isc/include/isc/once.h with
PTHEADS_RUNTIME_CHECK(), in order to improve error reporting for any
once-related run-time failures (by augmenting error messages with
file/line/caller information and the error string corresponding to
errno).
2022-10-14 16:39:21 +02:00
Ondřej Surý
beecde7120 Rewrite isc_httpd using picohttpparser and isc_url_parse
Rewrite the isc_httpd to be more robust.

1. Replace the hand-crafted HTTP request parser with picohttpparser for
   parsing the whole HTTP/1.0 and HTTP/1.1 requests.  Limit the number
   of allowed headers to 10 (arbitrary number).

2. Replace the hand-crafted URL parser with isc_url_parse for parsing
   the URL from the HTTP request.

3. Increase the receive buffer to match the isc_netmgr buffers, so we
   can at least receive two full isc_nm_read()s.  This makes the
   truncation processing much simpler.

4. Process the received buffer from single isc_nm_read() in a single
   loop and schedule the sends to be independent of each other.

The first two changes makes the code simpler and rely on already
existing libraries that we already had (isc_url based on nodejs) or are
used elsewhere (picohttpparser).

The second two changes remove the artificial "truncation" limit on
parsing multiple request.  Now only a request that has too many
headers (currently 10) or is too big (so, the receive buffer fills up
without reaching end of the request) will end the connection.

We can be benevolent here with the limites, because the statschannel
channel is by definition private and access must be allowed only to
administrators of the server.  There are no timers, no rate-limiting, no
upper limit on the number of requests that can be served, etc.
2022-10-14 11:26:54 +02:00
Ondřej Surý
3a8884f024 Add picohttpparser.{c.h} from https://github.com/h2o/picohttpparser
PicoHTTPParser is a tiny, primitive, fast HTTP request/response parser.

Unlike most parsers, it is stateless and does not allocate memory by
itself. All it does is accept pointer to buffer and the output
structure, and setups the pointers in the latter to point at the
necessary portions of the buffer.
2022-10-14 11:26:54 +02:00
Petr Špaček
53b3ceacd4 Replace #define DNS_NAMEATTR_ with struct of bools
sizeof(dns_name_t) did not change but the boolean attributes are now
separated as one-bit structure members. This allows debuggers to
pretty-print dns_name_t attributes without any special hacks, plus we
got rid of manual bit manipulation code.
2022-10-13 17:04:02 +02:00
Petr Špaček
8a3aa8bda4 Fix latent bug in RBT node attributes handling
Originally RBT node stored three lowest bits from dns_name_t attributes.
This had a curious side-effect noticed by Tony Finch:

If you create an rbt node from a DYNAMIC name then the flag will be
propagated through dns_rbt_namefromnode() ... if you subsequently call
dns_name_free() it will try to isc_mem_put() a piece of an rbt node ...
but dns_name_free() REQUIRE()s that the name is dynamic so in the usual
case where rbt nodes are created from non-dynamic names, this kind of
code will fail an assertion.

This is a bug it dates back to june 1999 when NAMEATTR_DYNAMIC was
invented.

Apparently it does not happen often :-)
I'm planning to get rid of DNS_NAMEATTR_ definitions and bit operations,
so removal of this "three-bit-subset" assignment is a first step.

We can keep only the ABSOLUTE flag in RBT node and nothing else because
names attached to rbt nodes are always readonly: The internal node_name()
function always sets the NAMEATTR_READONLY when making a dns_name that
refers to the node's name, so the READONLY flag will be set in the name
returned by dns_rbt_namefromnode().

Co-authored-by: Tony Finch <fanf@isc.org>
2022-10-13 13:08:28 +02:00
Ondřej Surý
b6b7a6886a Don't set load-balancing socket option on the UDP connect sockets
The isc_nm_udpconnect() erroneously set the reuse port with
load-balancing on the outgoing connected UDP sockets.  This socket
option makes only sense for the listening sockets.  Don't set the
load-balancing reuse port option on the outgoing UDP sockets.
2022-10-12 15:36:25 +02:00
Artem Boldariev
eaebb92f3e TLS DNS: fix certificate verification error message reporting
This commit fixes TLS DNS verification error message reporting which
we probably broke during one of the recent networking code
refactorings.

This prevent e.g. dig from producing useful error messages related to
TLS certificates verification.
2022-10-12 16:24:04 +03:00
Artem Boldariev
6789b88d25 TLS: clear error queue before doing IO or calling SSL_get_error()
Ensure that TLS error is empty before calling SSL_get_error() or doing
SSL I/O so that the result will not get affected by prior error
statuses.

In particular, the improper error handling led to intermittent unit
test failure and, thus, could be responsible for some of the system
test failures and other intermittent TLS-related issues.

See here for more details:

https://www.openssl.org/docs/man3.0/man3/SSL_get_error.html

In particular, it mentions the following:

> The current thread's error queue must be empty before the TLS/SSL
> I/O operation is attempted, or SSL_get_error() will not work
> reliably.

As we use the result of SSL_get_error() to decide on I/O operations,
we need to ensure that it works reliably by cleaning the error queue.

TLS DNS: empty error queue before attempting I/O
2022-10-12 16:24:04 +03:00
Aram Sargsyan
be95ba0119 Remove a superfluous check of sock->fd against -1
The check is left from when tcp_connect_direct() called isc__nm_socket()
and it was uncertain whether it had succeeded, but now isc__nm_socket()
is called before tcp_connect_direct(), so sock->fd cannot be -1.

    *** CID 357292:    (REVERSE_NEGATIVE)
    /lib/isc/netmgr/tcp.c: 309 in isc_nm_tcpconnect()
    303
    304     	atomic_store(&sock->active, true);
    305
    306     	result = tcp_connect_direct(sock, req);
    307     	if (result != ISC_R_SUCCESS) {
    308     		atomic_store(&sock->active, false);
    >>>     CID 357292:    (REVERSE_NEGATIVE)
    >>>     You might be using variable "sock->fd" before verifying that it is >= 0.
    309     		if (sock->fd != (uv_os_sock_t)(-1)) {
    310     			isc__nm_tcp_close(sock);
    311     		}
    312     		isc__nm_connectcb(sock, req, result, true);
    313     	}
    314
2022-10-12 08:21:35 +00:00
Petr Špaček
058c1744ba Clarify error message about missing inline-signing & dnssec-policy 2022-10-06 10:26:30 +02:00
Ondřej Surý
0dcbc6274b Record the 'edns-udp-size' in the view, not in the resolver
Getting the recorded value of 'edns-udp-size' from the resolver requires
strong attach to the dns_view because we are accessing `view->resolver`.
This is not the case in places (f.e. dns_zone unit) where `.udpsize` is
accessed.  By moving the .udpsize field from `struct dns_resolver` to
`struct dns_view`, we can access the value directly even with weakly
attached dns_view without the need to lock the view because `.udpsize`
can be accessed after the dns_view object has been shut down.
2022-10-05 11:59:36 -07:00
Ondřej Surý
bff3025396 Resolve violation of weak referencing dns_view
The dns_view implements weak and strong reference counting.  When strong
reference counting reaches zero, the adb, ntatable and resolver objects
are shut down and detached.

In dns_zone and dns_nta the dns_view was weakly attached, but the
view->resolver reference was accessed directly leading to dereferencing
the NULL pointer.

Add dns_view_getresolver() method which attaches to view->resolver
object under the lock (if it still exists) ensuring the dns_resolver
will be kept referenced until not needed.
2022-10-05 11:59:36 -07:00
Tony Finch
138908b211 Avoid dead code warning when using a constant boolean
The value of `sign_bit` is platform-dependent but constant at compile
time. Use a cast to convert the boolean `sign_bit` to 0 or 1 instead of
ternary `?:` because one branch of the conditional is dead code. (We
could leave out the cast to `size_t` but our style prefers to handle
booleans more explicitly, hence the `?:` that caused the issue.)

    *** CID 358310:  Possible Control flow issues  (DEADCODE)
    /lib/isc/resource.c: 118 in isc_resource_setlimit()
    112     		 * rlim_t, and whether rlim_t has a sign bit.
    113     		 */
    114     		isc_resourcevalue_t rlim_max = UINT64_MAX;
    115     		size_t wider = sizeof(rlim_max) - sizeof(rlim_t);
    116     		bool sign_bit = (double)(rlim_t)-1 < 0;
    117
    >>>     CID 358310:  Possible Control flow issues  (DEADCODE)
    >>>     Execution cannot reach the expression "1" inside this statement: "rlim_max >>= 8UL * wider + ...".
    118     		rlim_max >>= CHAR_BIT * wider + (sign_bit ? 1 : 0);
    119     		rlim_value = ISC_MIN(value, rlim_max);
    120     	}
    121
    122     	rl.rlim_cur = rl.rlim_max = rlim_value;
    123     	unixresult = setrlimit(unixresource, &rl);
2022-10-05 15:51:05 +00:00
Ondřej Surý
e18b6fb6a6 Use isc_mem_regetx() when appropriate
While refactoring the isc_mem_getx(...) usage, couple places were
identified where the memory was resized manually.  Use the
isc_mem_reget(...) that was introduced in [GL !5440] to resize the
arrays via function rather than a custom code.
2022-10-05 16:44:05 +02:00
Ondřej Surý
c0598d404c Use designated initializers instead of memset()/MEM_ZERO for structs
In several places, the structures were cleaned with memset(...)) and
thus the semantic patch converted the isc_mem_get(...) to
isc_mem_getx(..., ISC_MEM_ZERO).  Use the designated initializer to
initialized the structures instead of zeroing the memory with
ISC_MEM_ZERO flag as this better matches the intended purpose.
2022-10-05 16:44:05 +02:00
Ondřej Surý
c1d26b53eb Add and use semantic patch to replace isc_mem_get/allocate+memset
Add new semantic patch to replace the straightfoward uses of:

  ptr = isc_mem_{get,allocate}(..., size);
  memset(ptr, 0, size);

with the new API call:

  ptr = isc_mem_{get,allocate}x(..., size, ISC_MEM_ZERO);
2022-10-05 16:44:05 +02:00
Ondřej Surý
dbf5672f32 Replace isc_mem_*_aligned(..., alignment) with isc_mem_*x(..., flags)
Previously, the isc_mem_get_aligned() and friends took alignment size as
one of the arguments.  Replace the specific function with more generic
extended variant that now accepts ISC_MEM_ALIGN(alignment) for aligned
allocations and ISC_MEM_ZERO for allocations that zeroes
the (re-)allocated memory before returning the pointer to the caller.
2022-10-05 16:44:05 +02:00
Matthijs Mekking
0681b15225 If refresh stale RRset times out, start stale-refresh-time
The previous commit failed some tests because we expect that if a
fetch fails and we have stale candidates in cache, the
stale-refresh-time window is started. This means that if we hit a stale
entry in cache and answering stale data is allowed, we don't bother
resolving it again for as long we are within the stale-refresh-time
window.

This is useful for two reasons:
- If we failed to fetch the RRset that we are looking for, we are not
  hammering the authoritative servers.

- Successor clients don't need to wait for stale-answer-client-timeout
  to get their DNS response, only the first one to query will take
  the latency penalty.

The latter is not useful when stale-answer-client-timeout is 0 though.

So this exception code only to make sure we don't try to refresh the
RRset again if it failed to do so recently.
2022-10-05 08:20:48 +02:00
Matthijs Mekking
64d51285d5 Reuse recursion type code for refresh stale RRset
Refreshing a stale RRset is similar to prefetching an RRset, so
reuse the existing code. When refreshing an RRset we need to clear
all db options related to serve-stale so that stale RRsets in cache
are ignored during the refresh.

We no longer need to set the "nodetach" flag, because the refresh
fetch is now a "fetch and forget". So we can detach from the client
in the query_send().

This code will break some serve-stale test cases, this will be fixed
in the successor commit.

TODO: add explanation why the serve-stale test cases fail.
2022-10-05 08:20:48 +02:00
Matthijs Mekking
5fb8e555bc Add new recursion type for refreshing stale RRset
Refreshing a stale RRset is similar to a prefetch query, so we can
refactor this code to use the new recursion types introduced in !5883.
2022-10-05 08:20:48 +02:00
Ondřej Surý
c14a4ac763 Add a case-insensitive option directly to siphash 2-4 implementation
Formerly, the isc_hash32() would have to change the key in a local copy
to make it case insensitive.  Change the isc_siphash24() and
isc_halfsiphash24() functions to lowercase the input directly when
reading it from the memory and converting the uint8_t * array to
64-bit (respectively 32-bit numbers).
2022-10-04 10:32:40 +02:00
Mark Andrews
5f07fe8cbb Use strnstr implementation from FreeBSD if not provided by OS 2022-10-04 14:21:41 +11:00
Mark Andrews
6d561d3886 Add support for 'dohpath' to SVCB (and HTTPS)
dohpath is specfied in draft-ietf-add-svcb-dns and has a value
of 7.  It must be a relative path (start with a /), be encoded
as UTF8 and contain the variable dns ({?dns}).
2022-10-04 14:21:41 +11:00
Tony Finch
4e37a6f77a Avoid signed integer overflow in isc_resource_setlimit()
On systems with signed rlim_t the old code calculated its maximum
value by shifting 1 into the sign bit, which is undefined behaviour.
Avoid the bug by using an unsigned shift.
2022-10-03 11:37:17 +00:00
Ondřej Surý
01f0f9dcdc Don't stop timer from dns__nta_shutdown()
The dns__nta_shutdown() could be run from different threads and it was
accessing nta->timer unlocked.  Don't check and stop the timer from
dns__nta_shutdown() directly, but leave it for the async callback.
2022-09-30 15:24:20 +02:00
Ondřej Surý
477eb22c12 Refactor isc_ratelimiter API
Because the dns_zonemgr_create() was run before the loopmgr was started,
the isc_ratelimiter API was more complicated that it had to be.  Move
the dns_zonemgr_create() to run_server() task which is run on the main
loop, and simplify the isc_ratelimiter API implementation.

The isc_timer is now created in the isc_ratelimiter_create() and
starting the timer is now separate async task as is destroying the timer
in case it's not launched from the loop it was created on.  The
ratelimiter tick now doesn't have to create and destroy timer logic and
just stops the timer when there's no more work to do.

This should also solve all the races that were causing the
isc_ratelimiter to be left dangling because the timer was stopped before
the last reference would be detached.
2022-09-30 10:36:30 +02:00
Ondřej Surý
09b50d2237 Fix small problems in the isc_ratelimiter 2022-09-30 09:50:17 +02:00
Ondřej Surý
1e2ededb07 Add missing DbC check for name##_detach in ISC_REFCOUNT_IMPL macro
The detach function in the ISC_REFCOUNT_IMPL macro was missing DbC
checks, add them.
2022-09-30 09:50:17 +02:00
Tony Finch
a4930e1969 Improve DBC in isc_mem_free
Unlike standard free(), isc_mem_free() is not a no-op when passed a
NULL pointer. For size accounting purposes it calls sallocx(), which
crashes when passed a NULL pointer. To get more helpful diagnostics,
REQUIRE() that the pointer is not NULL so that when the programmer
makes a mistake they get a backtrace that shows what went wrong.
2022-09-29 10:07:34 +00:00
Ondřej Surý
173c352452 Call the isc__nm_udp_send() callbacks asynchronously on shutdown
The isc__nm_udp_send() callback would be called synchronously when
shutting down or when the socket has been closed.  This could lead to
double locking in the calling code and thus those callbacks needs to be
called asynchronously.
2022-09-29 11:06:58 +02:00
Aram Sargsyan
3d7103bd21 Fix dynamic update forwarding when using a TLS-enabled primary
Now that the 'dns_request' supports using TLS transport, implement
dynamic update forwarding using DoT when the primary server is
configured to use a TLS transport.

Previously, when using such configuration, the dynamic update forwarding
feature was broken.
2022-09-28 09:01:05 +00:00
Mark Andrews
a47235f4f5 Check BN_dup results in rsa_check 2022-09-28 09:24:34 +10:00
Mark Andrews
483c5a1978 Free 'n' on error path in rsa_check 2022-09-28 09:24:34 +10:00