The brackets are not included in the host component of the parsed
URL/URI. Change the parser to include the brackets.
(cherry picked from commit f85d9f5ef3)
RFC 9110 Section 4.1 recommends at least 8000 octets, and 65535
is too excessive. Limit the maximum length to 8192 octets.
(cherry picked from commit efa8ca2267)
The isc_url_parse() function failed to check the input buffer's
length and assumed that it can't be bigger than UINT16_MAX, because
both the 'off' and 'len' fields of the 'isc_url_parser_t' structure
are uint16_t.
Add a check to not accept a buffer longer than UINT16_MAX.
(cherry picked from commit b878f82409)
The function had a single caller, the HTTP/2 request-path handling in
the network manager, and its semantics (strlen() of the source clamped
to the requested size) amounted to an obscured bounded string copy.
Replace the only use with a plain allocation and strlcpy(), and drop the
function.
(cherry picked from commit 5f068a307f)
This:
- makes sure all variables are initialized
- adds missing curly braces for single line statements
- use proper comment for fallthrough case statements
(cherry picked from commit 5b34773627)
Pull in upstream commit a875a01 from h2o/picohttpparser: enforce use of
CRLF in chunk headers, by rejecting bare CR / LF. Replaces the lenient
CHUNKED_IN_CHUNK_CRLF state with strict CHUNKED_IN_CHUNK_HEADER_EXPECT_LF,
CHUNKED_IN_CHUNK_DATA_EXPECT_CR and CHUNKED_IN_CHUNK_DATA_EXPECT_LF states.
Synced with the h2o/picohttpparser upstream repository up to commit
f4d94b48b31e0abae029ebeafcfd9ca0680ede58.
This commit is just hygiene and consistency by keeping the vendored copy
current.
Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit cfd7fd867b)
Callbacks for libuv stream reads do not signal zero-length reads as a
failure signal but rather as EAGAIN/EWOULDBLOCK. This can trigger an
assertion when a zero-length read is pushed onto a PROXYv2 endpoint that
has not yet processed the headers as it expects a non-NULL region of
positive length.
(cherry picked from commit 20d3ef1643)
Offloaded work used two different mechanisms: a per-loop isc_helper
thread for CPU-bound crypto (DNSSEC validation, message signature
checks) and the process-global libuv thread pool for blocking I/O (zone
load and dump, inbound transfer apply). Neither could cancel a queued
task, and the two disagreed about exclusive mode — the helper paused
with its loop under isc_loopmgr_pause() but the libuv pool did not, so
blocking offloaded work kept running while a loop held the exclusive
lock.
Unify both behind isc_work: each loop gets its own worker thread per
lane — FAST for short, bounded tasks and SLOW for long, blocking ones —
fed by a private queue. Separate lanes keep a short crypto task off the
path of a multi-second zone dump once both run on per-loop workers;
every lane parks with isc_loopmgr_pause() so exclusive mode now quiesces
offloaded work too; and a still-queued task can be canceled before it
starts (isc_work_cancel). isc_helper is removed and its callers select a
lane.
(cherry picked from commit a5f13b3410)
On a submit failure, client_send() nullifies sock->h2->connect.cstream
and frees the stream before returning the error. The error: label in
isc__nm_http_request() reloaded that pointer and dereferenced it
unconditionally, reading through a NULL stream. The function is only
used by the DoH unit tests -- production DoH client send goes through
isc__nm_http_send()/client_httpsend(), whose submit failure is reported
via the NULL-safe send callback -- so this is a latent defect in the
test helper rather than a reachable named crash.
Skip the read callback when the stream has already been detached and
let the caller report the failure from the error result it receives.
Assisted-by: Claude:claude-opus-4-8
(cherry picked from commit 7df91b7634)
The adaptive isc_rwlock (the modified C-RW-WP variant) synchronizes a
reader against a writer through a store-buffer handshake across two
independent atomic objects: the reader publishes its arrival in
readers_ingress and then reads writers_lock, while the writer publishes
its lock in writers_lock and then reads the reader indicator. With the
acquire/release ordering introduced by the 2021 simplification, neither
side is forced to observe the other's publish store before its own check
load, so on weak-memory targets a reader could see writers_lock unlocked
while the writer sees the indicator empty, and both would enter their
critical sections at once.
Restore the sequentially consistent ordering the original algorithm
specifies on the handshake atomics. The single total order over the
seq_cst operations is what forbids the overlap; targeting individual
fences is both more fragile and, on x86, more expensive. On x86 this
ordering is free (seq_cst loads remain plain loads and the RMWs remain
lock-prefixed); the added cost falls only on the weak-memory targets that
actually need it.
(cherry picked from commit b11bf7a45e)
A new ISC_ATTR_WARN_UNUSED_RESULT macro now defines
__attribute__((warn_unused_result)) and is used for
dns_rdata_fromstruct().
(cherry picked from commit 07c8c1d242)
Normally, the tid_count is initialized only once at the beginning of the
application. The only exception is the pattern in the unit test where
isc_loopmgr is repeatedly created and torn down and each creation of
isc_loopmgr_t calls isc__tid_initcount() with the previous value.
ThreadSanitizer sees that as write operation on unprotected memory are
reports this as data race even though the value has not really changed.
This has been fixed by skipping the tid_count value update on repeated
calls.
(cherry picked from commit a570e37c06)
Until now, the dispatcher silently dropped UDP responses from the
expected peer that carried the wrong DNS message id and kept listening
for the correct id to arrive within the read timeout. An off-path
attacker who knows the destination address and source port of an
outgoing fetch could exploit that quiet retry window to flood the
resolver with guessed responses; with a gigabit link the per-query
success probability grows linearly with the number of guesses that
arrive before the legitimate answer or the timeout.
Treat any such mismatch as a possible spoofing attempt and let the
resolver immediately retry the same query over TCP, the same control
path the truncation handler already uses.
Add a resolver statistics counter - exposed as 'queries retried over TCP
after a response with mismatched query id' in rndc stats and
'MismatchTCP' in the statistics channel
Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit 11bca1051f)
After the send callback completes, the UV request is freed but
the HTTP/2 socket's write buffer still points to the freed memory.
If nghttp2 subsequently needs to send frames (e.g. SETTINGS ACK),
the server_read_callback reads from the dangling buffer.
Clear the write buffer before freeing the UV request.
(cherry picked from commit 6afc4270e0323a52262802d553dda8233df36d42)
Replace the hysteretic hi_water/lo_water switch with a stochastic
check: always false below lo_water, always true at or above hi_water,
linearly ramped probability in between. This spreads cache cleaning
across many inserts instead of triggering a thundering herd once the
hi_water mark is crossed (which causes every addrdataset to enter the
LRU purge path simultaneously and serializes lookups behind the node
write locks).
The is_overmem atomic and its stores are no longer needed and are
removed. The existing tests that asserted specific hysteretic state
transitions are simplified to check only the deterministic boundaries.
(cherry picked from commit ee24d2a1c3361dcc1c48fb29bb2e0b91bc3405e8)
OPENSSL_cleanup() in OpenSSL 4 doesn't free the memory, and that is
not compatible with BIND 9's memory leak detection code. Don't use
custom allocation/deallocation functions for OpenSSL's internal memory
management in the tls.c module.
See https://github.com/openssl/openssl/pull/29721
(cherry picked from commit 4ede6edc54)
isc__ratelimiter_tick() and isc_ratelimiter_shutdown() each pulled
events out of rl->pending into a function-local list, dropped the
mutex, and then iterated. ISC_LIST_APPEND leaves the link in the
LINKED state, so a concurrent isc_ratelimiter_dequeue() saw an
event as still queued, called ISC_LIST_UNLINK against rl->pending —
which patched the prev/next of the local list — and freed the
event before dispatch finished, producing either an INSIST in the
unlink macro or a use-after-free in the dispatch loop.
isc_async_run() is a non-blocking wfcq enqueue, so there is no
benefit to dropping the mutex around it. Unlink each event and
hand it to isc_async_run() while still holding rl->lock; the
existing ISC_LINK_LINKED check in dequeue then correctly
distinguishes "still queued and cancellable" from "already taken".
Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit 4d465f4fa5)
The INSIST in isc_radix_insert() checks node->data[RADIX_V4] and
node->node_num[RADIX_V4] twice due to a copy-paste error, never
verifying the RADIX_V6 fields.
Fix the second pair to check RADIX_V6.
(cherry picked from commit 3f15f2d9e5)
A helper macro that returns the current value of a pointer and sets
it to NULL in one expression, useful for transferring ownership in
designated initializers.
(cherry picked from commit 0f3be0beb8)
isc_buffer_init() is given MAX_DNS_MESSAGE_SIZE (65535) as capacity but
only h2->content_length bytes are allocated. This makes the buffer
believe it has more space than actually allocated. A secondary bounds
check (new_bufsize <= h2->content_length) prevents actual overflow, but
the buffer invariant is violated.
Pass h2->content_length as the capacity to match the allocation.
(cherry picked from commit 8e240bbb5f)
We return DNS_R_NOVALIDSIG if we detected a deadlock. Then in
'validate_async_done()', this result value is used to check if we
need to fall back to insecure. As part of that we create a new fetch
but that fails because of the detected deadlock. This results in a loop
of deadlock detected, fallback to insecure, deadlock detected, ...
Add a new result value, ISC_R_DEADLOCK, and return this instead when
we have detected a deadlock. This will be treated as a generic error,
as there is no special handling for this result value.
(cherry picked from commit bc1d177cc2)
The previous code was incorrectly clearing errno after calling
strtol but before testing the result rather than clearing it and
then calling strtol so that changes to errno can be correctly
determined.
(cherry picked from commit d3ffa1f007)
Starting from OpenSSL 4 the the X509_get_subject_name() function
returns a 'const' pointer to a name instead of a regular pointer.
Duplicate the name before operating on it, then free it.
(cherry picked from commit 336c523b79)
When TLS creation fails in tlslisten_acceptcb(), tlssock->server
was not detached before detaching tlssock itself.
(cherry picked from commit 2ab3d7c075)
Add a REQUIRE(isc_loop() == loop) assertion to isc_work_enqueue()
to strictly enforce that work is enqueued from the loop it is
assigned to. This loudly prohibits cross-thread queue manipulation
before it inevitably turns into a concurrency debugging nightmare.
(cherry picked from commit f1311d2d19)
NSEC3 hashes are required to fit within a single DNS label. Since there
are 5 bits per label byte without pad characters, the maximum hash size
is floor(63*5/8) (39 bytes).
This patch enforces this maximum length for unknown algorithms, while
strictly enforcing the exact expected digest length for known algorithms
like SHA-1.
(cherry picked from commit 3801d0ebbf)
This better reflects the true nature of the function as we are reading
the ephemeral port range which is not related to UDP at all.
(cherry picked from commit 295139f8ca)
For Linux >= 6.8:
Since 2023, Linux has introduced a change to the IP_LOCAL_PORT_RANGE
socket option that eliminates the need for the random window
shifting (implemented as a fallback in the next commit).
By setting IP_LOCAL_PORT_RANGE option, we tell the kernel to use better
approach to the source port selection.
For Linux << 6.8:
This implement selecting port by random shifting range leveraging the
IP_LOCAL_PORT_RANGE socket option. The network manager is initialized
with the ephemeral port range (on startup and on reconfig) and then for
every outgoing TCP connection, we define a custom port range (1000
ports) and then randomly shift the custom range within the system range.
This helps the kernel to reduce the search space to the custom window
between <random_offset, random_offset + 1000>.
Reference:
https://blog.cloudflare.com/linux-transport-protocol-port-selection-performance/#kernel
(cherry picked from commit 04c81b55d2)
Since 2015, Linux has introduced a new socket option to overcome TCP
limitations: When an application needs to force a source IP on an active
TCP socket it has to use bind(IP, port=x). As most applications do not
want to deal with already used ports, x is often set to 0, meaning the
kernel is in charge to find an available port. But kernel does not know
yet if this socket is going to be a listener or be connected. This
IP_BIND_ADDRESS_NO_PORT socket option ask the kernel to ignore the 0
port provided by application in bind(IP, port=0) and only remember the
given IP address. The port will be automatically chosen at connect()
time, in a way that allows sharing a source port as long as the 4-tuples
are unique.
Enable IP_BIND_ADDRESS_NO_PORT on the outgoing TCP sockets to overcome
this TCP limitation.
(cherry picked from commit 2c48fcaeed)
The function was already marked as never failing, always returning
ISC_R_SUCCESS, so there was a lot of dead code around checking whether
the result would be ISC_R_SUCCESS. This has been cleaned up.
(cherry picked from commit c3ec414d88)
This adds the following enum isc_one_or_more and isc_zero_or_more
which specify if one or more or zeror or more bytes are required
when reading the unbounded base64 / hex encoded data.
(cherry picked from commit 07610f8566)
C23 now has qualifier preserving standard functions for strchr,
bsearch, strpbrk, strrchr, strstr, memchr. There where a few places
where the return value was not assigned to a const qualified pointer.
These have been fixed.
(cherry picked from commit af379e10cc)
While building on uclibc this error is thrown:
In file included from ./include/dns/log.h:20,
from callbacks.c:19:
../../lib/isc/include/isc/log.h:141:9: error: unknown type name ‘off_t’
141 | off_t maximum_size;
| ^~~~~
This is due to missing include unistd.h, so let's add it on top of
isc/log.h
Signed-off-by: Giulio Benetti <giulio.benetti@benettiengineering.com>
(cherry picked from commit 0e43f62c12)
previously, there were over 40 separate definitions of CHECK macros, of
which most used "goto cleanup", and the rest "goto failure" or "goto
out". there were another 10 definitions of RETERR, of which most were
identical to CHECK, but some simply returned a result code instead of
jumping to a cleanup label.
this has now been standardized throughout the code base: RETERR is for
returning an error code in the case of an error, and CHECK is for jumping
to a cleanup tag, which is now always called "cleanup". both macros are
defined in isc/util.h.
(cherry picked from commit 52bba5cc34)
Instead of just crashing when memory allocation fails, also print a
message saying "Out of memory!", the size of the allocation that failed,
total allocated memory from all memory contexts and value of errno.
(cherry picked from commit b0194004d9)
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.
(cherry picked from commit 4d307ac67a)
Upstream has removed the atomics implementation of CMM_LOAD_SHARED and
CMM_STORE_SHARED as these can be used also with non-stdatomics types.
As we only use the CMM api with stdatomics types, we can restore the
previous behaviour to prevent ThreadSanitizer warnings.
(cherry picked from commit 539be61b68)
Call to `streamdns_resume_processing` is asynchronous but the socket
passed as argument is not attached when scheduling the call.
While there is no reproducible way (so far) to make the socket reference
number down to 0 before `streamdns_resume_processing` is called, attach
the socket before scheduling the call. This guard against an hypothetic
case where, for some reasons, the socket refcount would reach 0, and be
freed from memory when `streamdns_resume_processing` is called.
(cherry picked from commit 7c8b517d56)
Since we are using system routines for randomness, there's no point
in spending time and run the statistical suite for testing PRNG.
(cherry picked from commit 90b3def5e9)
When the arc4random_uniform() is called on NetBSD with upper_bound that
makes no sense statistically (0 or 1), the call crashes the calling
program. Fix this by returning 0 when upper bound is < 2 as does Linux,
FreeBSD and NetBSD. (Hint: System CSPRNG should never crash.)
(cherry picked from commit 871bce312b)
Use arc4random on platforms where available. arc4random() provides high
quality cryptographically-secure pseudo-random numbers and is generally
recommended for application use.
The uv_random() call unfortunately uses getentropy() on platforms like
MacOS, OpenBSD or NetBSD which is not recommended for application use.
(cherry picked from commit 4db9e5d90e)
It was discovered in an upcoming academic paper that a xoshiro128**
internal state can be recovered by an external 3rd party allowing to
predict UDP ports and DNS IDs in the outgoing queries. This could lead
to an attacker spoofing the DNS answers with great efficiency and
poisoning the DNS cache.
Change the internal random generator to system CSPRNG with buffering to
avoid excessive syscalls.
Thanks Omer Ben Simhon and Amit Klein of Hebrew University of Jerusalem
for responsibly reporting this to us. Very cool research!
(cherry picked from commit cffcab9d5f)
Clang 20 is complaining about passing NULL to an argument with 'nonnull'
attribute. Mark these two functions with the same attribute to assure
that these two function also don't accept NULL as an argument.
(cherry picked from commit 9e350c1774)
libuv expects file descriptors <= STDERR_FILENO are in use. otherwise,
it may abort when closing a file descriptor it opened.
See https://github.com/libuv/libuv/pull/4559Closes#5226
(cherry picked from commit 5cfdbeba72)