Compare commits

...

29 Commits

Author SHA1 Message Date
Michał Kępień
1530bf8b55 Update BIND version to 9.17.14 2021-06-08 09:00:49 +02:00
Michał Kępień
2f2cd937bb Add a CHANGES marker 2021-06-08 09:00:49 +02:00
Michał Kępień
c9ee795246 Merge branch 'michal/prepare-documentation-for-bind-9.17.14' into 'v9_17_14-release'
Prepare documentation for BIND 9.17.14

See merge request isc-private/bind9!298
2021-06-08 06:59:38 +00:00
Michał Kępień
ef810d8b1a Prepare release notes for BIND 9.17.14 2021-06-08 08:41:36 +02:00
Michał Kępień
765b5794f4 Reorder release notes 2021-06-08 08:41:36 +02:00
Michał Kępień
8dce3f7649 Tweak and reword release notes 2021-06-08 08:41:36 +02:00
Michał Kępień
64bf0083bd Tweak and reword recent CHANGES entries 2021-06-08 08:41:36 +02:00
Michał Kępień
4f574a5ee4 Remove leftover release note for GL #2603 2021-06-08 08:41:36 +02:00
Ondřej Surý
be01f589d9 Merge branch '2732-pause-the-dbiterator-in-dumptostream' into 'main'
Pause the dbiterator when dumping the zone to the disk

Closes #2732

See merge request isc-projects/bind9!5150
2021-06-04 09:05:52 +00:00
Ondřej Surý
7e59b8a4a1 Pause the dbiterator when dumping the zone to the disk
When we rewrote the zone dumping to use the separate threadpool, the
dumping would acquire the read lock for the whole time the zone dumping
process is dumping the zone.

When combined with incoming IXFR that tries to acquire the write lock on
the same rwlock, we would end up blocking all the other readers.

In this commit, we pause the dbiterator every time we get next record
and before start dumping it to the disk.
2021-06-04 08:25:05 +00:00
Mark Andrews
7fef01201d Merge branch '2751-serve-stale-tests-false-negative' into 'main'
Resolve "serve-stale tests false negative"

Closes #2751

See merge request isc-projects/bind9!5143
2021-06-03 08:40:38 +00:00
Mark Andrews
af95cb8ccc Address test race condition in serve-stale
the dig.out.test# files could still be being written when the
content greps where being made.
2021-06-03 18:20:14 +10:00
Mark Andrews
d242ccfbdf Merge branch '2750-provide-more-insight-into-why-the-timer_test-is-failing' into 'main'
Resolve "Provide more insight into why the timer_test is failing."

Closes #2750

See merge request isc-projects/bind9!5142
2021-06-03 07:31:26 +00:00
Mark Andrews
66d1df57cb Report which assertion failed when calling set_global_error 2021-06-03 11:55:31 +10:00
Mark Andrews
5bd7caba9c Merge branch '2724-statschannel-system-test-sometimes-hangs' into 'main'
Resolve "statschannel system test sometimes hangs"

Closes #2724

See merge request isc-projects/bind9!5123
2021-06-02 22:37:10 +00:00
Mark Andrews
02726cb66e Add timeout to url get requests
to prevent the system test taking forever on failures.
2021-06-02 22:18:21 +00:00
Ondřej Surý
0dded90ae4 Merge branch '2746-fix-the-typo-in-setsockopt_off' into 'main'
Fix copy&paste error in setsockopt_off

Closes #2746

See merge request isc-projects/bind9!5138
2021-06-02 16:09:48 +00:00
Ondřej Surý
22aa929aac Add CHANGES and release note for [GL #2746] 2021-06-02 17:47:14 +02:00
Ondřej Surý
f14d870d15 Fix copy&paste error in setsockopt_off
Because of copy&paste error the setsockopt_off macro would enable
the socket option instead of disabling it.
2021-06-02 17:47:14 +02:00
Michał Kępień
5e1a48a605 Merge branch '2540-check-dname-resolution-via-itself' into 'main'
Check DNAME resolution via itself

Closes #2540

See merge request isc-projects/bind9!5135
2021-06-02 12:49:05 +00:00
Mark Andrews
cbdea694e8 Check DNAME resolution via itself 2021-06-02 14:20:35 +02:00
Michał Kępień
715dc196e2 Merge branch '2467-add-a-system-test-checking-a-malformed-ixfr' into 'main'
Add a system test checking a malformed IXFR

Closes #2467

See merge request isc-projects/bind9!5132
2021-06-02 11:35:55 +00:00
Mark Andrews
5547003a3d Add a system test checking a malformed IXFR
Make sure an incoming IXFR containing an SOA record which is not placed
at the apex of the transferred zone does not result in a broken version
of the zone being served by named and/or a subsequent crash.
2021-06-02 13:15:25 +02:00
Ondřej Surý
c70d9c4e9a Merge branch 'ondrej/fix-uv_udp_connect-detection' into 'main'
Cleanup the remaining of HAVE_UV_<func> macros

See merge request isc-projects/bind9!5127
2021-06-02 09:56:20 +00:00
Ondřej Surý
67afea6cfc Cleanup the remaining of HAVE_UV_<func> macros
While cleaning up the usage of HAVE_UV_<func> macros, we forgot to
cleanup the HAVE_UV_UDP_CONNECT in the actual code and
HAVE_UV_TRANSLATE_SYS_ERROR and this was causing Windows build to fail
on uv_udp_send() because the socket was already connected and we were
falsely assuming that it was not.

The platforms with autoconf support were not affected, because we were
still checking for the functions from the configure.
2021-06-02 11:23:36 +02:00
Ondřej Surý
479dc58877 Merge branch 'ondrej/add-libnghttp2-dev-to-lgtm.yml' into 'main'
Add libnghttp2-dev to .lgtm.yml

See merge request isc-projects/bind9!5125
2021-06-02 07:35:39 +00:00
Ondřej Surý
d67e16ae3c Add libnghttp2-dev to .lgtm.yml
The LGTM.com configuration was missing required library, so the
"Extraction" step of the analysis was failing.
2021-06-02 09:33:27 +02:00
Artem Boldariev
2fc89e0353 Merge branch 'artem-http-write-buffering' into 'main'
HTTP/2 write buffering

See merge request isc-projects/bind9!5121
2021-06-01 18:28:34 +00:00
Artem Boldariev
35d0027f36 HTTP/2 write buffering
This commit adds the ability to consolidate HTTP/2 write requests if
there is already one in flight. If it is the case, the code will
consolidate multiple subsequent write request into a larger one
allowing to utilise the network in a more efficient way by creating
larger TCP packets as well as by reducing TLS records overhead (by
creating large TLS records instead of multiple small ones).

This optimisation is especially efficient for clients, creating many
concurrent HTTP/2 streams over a transport connection at once.  This
way, the code might create a small amount of multi-kilobyte requests
instead of many 50-120 byte ones.

In fact, it turned out to work so well that I had to add a work-around
to the code to ensure compatibility with the flamethrower, which, at
the time of writing, does not support TLS records larger than two
kilobytes. Now the code tries to flush the write buffer after 1.5
kilobyte, which is still pretty adequate for our use case.

Essentially, this commit implements a recommendation given by nghttp2
library:

https://nghttp2.org/documentation/nghttp2_session_mem_send.html
2021-06-01 21:07:45 +03:00
22 changed files with 509 additions and 184 deletions

View File

@@ -13,6 +13,7 @@ extraction:
- "libidn2-dev"
- "libmaxminddb-dev"
- "libuv1-dev"
- "libnghttp2-dev"
configure:
command:
- "autoreconf -fi"

69
CHANGES
View File

@@ -1,48 +1,59 @@
5651. [func] Refactor zone dumping to be processed asynchronously
via the uv_work_t thread pool API. [GL #2732]
--- 9.17.14 released ---
5650. [bug] Prevent a crash that could occur if serve-stale
was enabled and a prefetch was triggered during a
query restart. [GL #2733]
5652. [bug] A copy-and-paste error in change 5584 caused the
IP_DONTFRAG socket option to be enabled instead of
disabled. This has been fixed. [GL #2746]
5649. [bug] If a query was answered with stale data on a server
with DNS64 enabled, an assertion could occur if a
non-stale answer arrived afterward. [GL #2731]
5651. [func] Refactor zone dumping to be processed asynchronously via
the uv_work_t thread pool API. [GL #2732]
5648. [bug] The calculation of the estimated IXFR transaction
size by dns_journal_iter_init() was invalid. [GL #2685]
5650. [bug] Prevent a crash that could occur if serve-stale was
enabled and a prefetch was triggered during a query
restart. [GL #2733]
5647. [func] The interfacemgr has been refactored to use fewer
clientmgr objects, which in turn use fewer memory
contexts and tasks. This should result in less
5649. [bug] If a query was answered with stale data on a server with
DNS64 enabled, an assertion could occur if a non-stale
answer arrived afterward. [GL #2731]
5648. [bug] The calculation of the estimated IXFR transaction size
in dns_journal_iter_init() was invalid. [GL #2685]
5647. [func] The interface manager has been refactored to use fewer
client manager objects, which in turn use fewer memory
contexts and tasks. This should result in less
fragmented memory and better startup performance.
[GL #2433]
5646. [bug] The default TCP timeout for rndc has been increased
to 60 seconds. This was its original value, but it
had been inadvertently lowered to 10. [GL #2643]
5646. [bug] The default TCP timeout for rndc has been increased to
60 seconds. This was its original value, but it had been
inadvertently lowered to 10 when rndc was updated to use
the network manager. [GL #2643]
5645. [cleanup] Remove the rarely-used dns_name_copy() function
and rename dns_name_copynf() to dns_name_copy().
[GL !5081]
5645. [cleanup] Remove the rarely-used dns_name_copy() function and
rename dns_name_copynf() to dns_name_copy(). [GL !5081]
5644. [bug] Fix a race condition in reading and writing key files
for KASP zones in multiple views. [GL #1875]
for zones using KASP and configured in multiple views.
[GL #1875]
5643. [placeholder]
5642. [bug] Check "key-directory" conflicts in "named.conf" for
zones in multiple views with different "dnssec-policy".
[GL #2463].
5642. [bug] Zones which are configured in multiple views with
different values set for "dnssec-policy" and with
identical values set for "key-directory" are now
detected and treated as a configuration error.
[GL #2463]
5641. [bug] Address potential memory leak in dst_key_fromnamedfile.
[GL #2689]
5641. [bug] Address a potential memory leak in
dst_key_fromnamedfile(). [GL #2689]
5640. [func] Add new configuration option to set the operating system
receive and send buffers. [GL #2313]
5640. [func] Add new configuration options for setting the size of
receive and send buffers in the operating system:
"tcp-receive-buffer", "tcp-send-buffer",
"udp-receive-buffer", and "udp-send-buffer". [GL #2313]
5639. [bug] Check that the first and last SOA record of an AXFR
are consistent. [GL #2528]
5639. [bug] Check that the first and last SOA record of an AXFR are
consistent. [GL #2528]
--- 9.17.13 released ---

View File

@@ -80,6 +80,34 @@ sub reply_handler {
$rr = new Net::DNS::RR("$synth2 $ttl $qclass DNAME .");
push @ans, $rr;
$rcode = "NOERROR";
# The following three code branches referring to the "example.dname"
# zone are necessary for the resolver variant of the CVE-2021-25215
# regression test to work. A named instance cannot be used for
# serving the DNAME records below as a version of BIND vulnerable to
# CVE-2021-25215 would crash while answering the queries asked by
# the tested resolver.
} elsif ($qname eq "ns3.example.dname") {
if ($qtype eq "A") {
my $rr = new Net::DNS::RR("$qname $ttl $qclass A 10.53.0.3");
push @ans, $rr;
}
if ($qtype eq "AAAA") {
my $rr = new Net::DNS::RR("example.dname. $ttl $qclass SOA . . 0 0 0 0 $ttl");
push @auth, $rr;
}
$rcode = "NOERROR";
} elsif ($qname eq "self.example.self.example.dname") {
my $rr = new Net::DNS::RR("self.example.dname. $ttl $qclass DNAME dname.");
push @ans, $rr;
$rr = new Net::DNS::RR("$qname $ttl $qclass CNAME self.example.dname.");
push @ans, $rr;
$rcode = "NOERROR";
} elsif ($qname eq "self.example.dname") {
if ($qtype eq "DNAME") {
my $rr = new Net::DNS::RR("$qname $ttl $qclass DNAME dname.");
push @ans, $rr;
}
$rcode = "NOERROR";
} else {
$rcode = "REFUSED";
}

View File

@@ -24,6 +24,10 @@ ns2.example. A 10.53.0.2
example.broken. NS ns3.example.broken.
ns3.example.broken. A 10.53.0.3
; for the resolver variant of the CVE-2021-25215 regression test
example.dname. NS ns3.example.dname.
ns3.example.dname. A 10.53.0.3
domain0.nil. NS ns2.domain0.nil
domain1.nil. NS ns2.domain0.nil
domain2.nil. NS ns2.domain0.nil

View File

@@ -16,3 +16,5 @@ ns2 86400 AAAA fd92:7065:b8e:ffff::2
@ 86400 AAAA 1:2:3::4
* 86400 A 1.2.3.4
* 86400 AAAA 1:2:3::4
; CVE-2021-25215 regression test data
self 86400 DNAME nil.

View File

@@ -295,5 +295,23 @@ grep 'status: NOERROR' dig.out.7.$n > /dev/null 2>&1 || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
# Regression test for CVE-2021-25215 (authoritative server).
n=`expr $n + 1`
echo_i "checking DNAME resolution via itself (authoritative) ($n)"
ret=0
$DIG $DIGOPTS @10.53.0.2 DNAME self.domain0.self.domain0.nil. > dig.out.2.$n 2>&1
grep 'status: NOERROR' dig.out.2.$n > /dev/null 2>&1 || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
# Regression test for CVE-2021-25215 (recursive resolver).
n=`expr $n + 1`
echo_i "checking DNAME resolution via itself (recursive) ($n)"
ret=0
$DIG $DIGOPTS @10.53.0.7 DNAME self.example.self.example.dname. > dig.out.7.$n 2>&1
grep 'status: NOERROR' dig.out.7.$n > /dev/null 2>&1 || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=`expr $status + $ret`
echo_i "exit status: $status"
[ $status -eq 0 ] || exit 1

View File

@@ -108,7 +108,7 @@ if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "testing AXFR fallback after IXFR failure ($n)"
echo_i "testing AXFR fallback after IXFR failure (not exact error) ($n)"
ret=0
# Provide a broken IXFR response and a working fallback AXFR response
@@ -142,6 +142,66 @@ $DIG $DIGOPTS @10.53.0.1 nil. TXT | grep 'fallback AXFR' >/dev/null || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "testing AXFR fallback after IXFR failure (bad SOA owner) ($n)"
ret=0
# Prepare for checking the logs later on.
nextpart ns1/named.run >/dev/null
# Provide a broken IXFR response and a working fallback AXFR response.
sendcmd <<EOF
/SOA/
nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300
/IXFR/
nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300
nil. 300 SOA ns.nil. root.nil. 3 300 300 604800 300
bad-owner. 300 SOA ns.nil. root.nil. 4 300 300 604800 300
test.nil. 300 TXT "serial 4, malformed IXFR"
nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300
/AXFR/
nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300
/AXFR/
nil. 300 NS ns.nil.
test.nil. 300 TXT "serial 4, fallback AXFR"
/AXFR/
nil. 300 SOA ns.nil. root.nil. 4 300 300 604800 300
EOF
$RNDCCMD 10.53.0.1 refresh nil | sed 's/^/ns1 /' | cat_i
# A broken server would accept the malformed IXFR and apply its contents to the
# zone. A fixed one would reject the IXFR and fall back to AXFR. Both IXFR and
# AXFR above bring the nil. zone up to serial 4, but we cannot reliably query
# for the SOA record to check whether the transfer was finished because a broken
# server would send back SERVFAIL responses to SOA queries after accepting the
# malformed IXFR. Instead, check transfer progress by querying for a TXT record
# at test.nil. which is present in both IXFR and AXFR (with different contents).
_wait_until_transfer_is_finished() {
$DIG $DIGOPTS +tries=1 +time=1 @10.53.0.1 test.nil. TXT > dig.out.test$n.1 &&
grep -q -F "serial 4" dig.out.test$n.1
}
if ! retry_quiet 10 _wait_until_transfer_is_finished; then
echo_i "timed out waiting for version 4 of zone nil. to be transferred"
ret=1
fi
# At this point a broken server would be serving a zone with no SOA records.
# Try crashing it by triggering a SOA refresh query.
$RNDCCMD 10.53.0.1 refresh nil | sed 's/^/ns1 /' | cat_i
# Do not wait until the zone refresh completes - even if a crash has not
# happened by now, a broken server would never serve the record which is only
# present in the fallback AXFR, so checking for that is enough to verify if a
# server is broken or not; if it is, it is bound to crash shortly anyway.
$DIG $DIGOPTS test.nil. TXT @10.53.0.1 > dig.out.test$n.2 || ret=1
grep -q -F "serial 4, fallback AXFR" dig.out.test$n.2 || ret=1
# Ensure the expected error is logged.
nextpart ns1/named.run | grep -q -F "SOA name mismatch" || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "testing ixfr-from-differences option ($n)"
# ns3 is primary; ns4 is secondary

View File

@@ -1705,20 +1705,25 @@ n=$((n+1))
echo_i "check not in cache longttl.example times out (stale-answer-client-timeout 1.8) ($n)"
ret=0
wait_for_log 3 "longttl.example client timeout, stale answer unavailable" ns3/named.run || ret=1
waitfile() {
check_results() {
[ -s "$1" ] || return 1
grep "connection timed out" "$1" > /dev/null || return 1
return 0
}
retry_quiet 3 waitfile dig.out.test$n || ret=1
grep "connection timed out" dig.out.test$n > /dev/null || ret=1
retry_quiet 3 check_results dig.out.test$n || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))
n=$((n+1))
echo_i "check not in cache longttl.example comes from authoritative (stale-answer-client-timeout 1.8) ($n)"
ret=0
retry_quiet 7 waitfile dig.out.test$n || ret=1
grep "status: NOERROR" dig.out.test$n > /dev/null || ret=1
grep "ANSWER: 1," dig.out.test$n > /dev/null || ret=1
check_results() {
[ -s "$1" ] || return 1
grep "status: NOERROR" "$1" > /dev/null || return 1
grep "ANSWER: 1," "$1" > /dev/null || return 1
return 0
}
retry_quiet 7 check_results dig.out.test$n || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status+ret))

View File

@@ -22,7 +22,8 @@ from helper import fmt
# JSON helper functions
def fetch_zones_json(statsip, statsport):
r = requests.get("http://{}:{}/json/v1/zones".format(statsip, statsport))
r = requests.get("http://{}:{}/json/v1/zones".format(statsip, statsport),
timeout=600)
assert r.status_code == 200
data = r.json()
@@ -31,7 +32,8 @@ def fetch_zones_json(statsip, statsport):
def fetch_traffic_json(statsip, statsport):
r = requests.get("http://{}:{}/json/v1/traffic".format(statsip, statsport))
r = requests.get("http://{}:{}/json/v1/traffic".format(statsip, statsport),
timeout=600)
assert r.status_code == 200
data = r.json()

View File

@@ -23,7 +23,8 @@ from helper import fmt
# XML helper functions
def fetch_zones_xml(statsip, statsport):
r = requests.get("http://{}:{}/xml/v3/zones".format(statsip, statsport))
r = requests.get("http://{}:{}/xml/v3/zones".format(statsip, statsport),
timeout=600)
assert r.status_code == 200
root = ET.fromstring(r.text)
@@ -47,7 +48,8 @@ def fetch_traffic_xml(statsip, statsport):
return out
r = requests.get("http://{}:{}/xml/v3/traffic".format(statsip, statsport))
r = requests.get("http://{}:{}/xml/v3/traffic".format(statsip, statsport),
timeout=600)
assert r.status_code == 200
root = ET.fromstring(r.text)

View File

@@ -14,7 +14,7 @@
#
m4_define([bind_VERSION_MAJOR], 9)dnl
m4_define([bind_VERSION_MINOR], 17)dnl
m4_define([bind_VERSION_PATCH], 13)dnl
m4_define([bind_VERSION_PATCH], 14)dnl
m4_define([bind_VERSION_EXTRA], )dnl
m4_define([bind_DESCRIPTION], [(Development Release)])dnl
m4_define([bind_SRCID], [m4_esyscmd_s([git rev-parse --short HEAD | cut -b1-7])])dnl
@@ -593,18 +593,6 @@ AC_CHECK_HEADERS([pthread_np.h], [], [], [#include <pthread.h>])
AC_MSG_CHECKING([for libuv])
PKG_CHECK_MODULES([LIBUV], [libuv >= 1.0.0], [],
[AC_MSG_ERROR([libuv not found])])
AX_SAVE_FLAGS([libuv])
CFLAGS="$CFLAGS $LIBUV_CFLAGS"
LIBS="$LIBS $LIBUV_LIBS"
# Those functions are only provided in newer versions of libuv, we'll be emulating them
# for now
AC_CHECK_FUNCS([uv_handle_get_data uv_handle_set_data])
AC_CHECK_FUNCS([uv_req_get_data uv_req_set_data])
AC_CHECK_FUNCS([uv_udp_connect uv_translate_sys_error uv_sleep])
AC_CHECK_FUNCS([uv_os_getenv uv_os_setenv])
AX_RESTORE_FLAGS([libuv])
# libnghttp2
AC_MSG_CHECKING([for libnghttp2])

View File

@@ -52,7 +52,7 @@ https://www.isc.org/download/. There you will find additional
information about each release, source code, and pre-compiled versions
for Microsoft Windows operating systems.
.. include:: ../notes/notes-current.rst
.. include:: ../notes/notes-9.17.14.rst
.. include:: ../notes/notes-9.17.13.rst
.. include:: ../notes/notes-9.17.12.rst
.. include:: ../notes/notes-9.17.11.rst

View File

@@ -0,0 +1,63 @@
..
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, you can obtain one at https://mozilla.org/MPL/2.0/.
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
Notes for BIND 9.17.14
----------------------
New Features
~~~~~~~~~~~~
- New configuration options, ``tcp-receive-buffer``,
``tcp-send-buffer``, ``udp-receive-buffer``, and ``udp-send-buffer``,
have been added. These options allow the operator to fine-tune the
receiving and sending buffers in the operating system. On busy
servers, increasing the size of the receive buffers can prevent the
server from dropping packets during short traffic spikes, and
decreasing it can prevent the server from becoming clogged with
queries that are too old and have already timed out. :gl:`#2313`
Feature Changes
~~~~~~~~~~~~~~~
- Zone dumping tasks are now run on separate asynchronous thread pools.
This change prevents zone dumping from blocking network I/O.
:gl:`#2732`
- The interface handling code has been refactored to use fewer
resources, which should lead to less memory fragmentation and better
startup performance. :gl:`#2433`
Bug Fixes
~~~~~~~~~
- The calculation of the estimated IXFR transaction size in
``dns_journal_iter_init()`` was invalid. This resulted in excessive
AXFR-style IXFR responses. :gl:`#2685`
- Fixed an assertion failure that could occur if stale data was used to
answer a query, and then a prefetch was triggered after the query was
restarted (for example, to follow a CNAME). :gl:`#2733`
- If a query was answered with stale data on a server with DNS64
enabled, an assertion could occur if a non-stale answer arrived
afterward. This has been fixed. :gl:`#2731`
- Fixed an error which caused the ``IP_DONTFRAG`` socket option to be
enabled instead of disabled, leading to errors when sending oversized
UDP packets. :gl:`#2746`
- Zones which are configured in multiple views, with different values
set for ``dnssec-policy`` and with identical values set for
``key-directory``, are now detected and treated as a configuration
error. :gl:`#2463`
- A race condition could occur when reading and writing key files for
zones using KASP and configured in multiple views. This has been
fixed. :gl:`#1875`

View File

@@ -1,74 +0,0 @@
..
Copyright (C) Internet Systems Consortium, Inc. ("ISC")
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, you can obtain one at https://mozilla.org/MPL/2.0/.
See the COPYRIGHT file distributed with this work for additional
information regarding copyright ownership.
Notes for BIND 9.17.14
----------------------
Security Fixes
~~~~~~~~~~~~~~
- None.
Known Issues
~~~~~~~~~~~~
- None.
New Features
~~~~~~~~~~~~
- New configuration options, ``tcp-receive-buffer``, ``tcp-send-buffer``,
``udp-receive-buffer``, and ``udp-send-buffer``, have been added. These
options allows the operator to fine tune the receiving and sending
buffers in the operating system. On busy servers, increasing the value
of the receive buffers can prevent the server from dropping the packets
during short spikes, and decreasing the value would prevent the server to
became clogged up with queries that are too old and have already timeouted
on the receiving side. :gl:`#2313`
- Run zone dumping tasks on separate asynchronous thread pools. This change
makes zone dumping no longer block networking I/O. :gl:`#2732`
Removed Features
~~~~~~~~~~~~~~~~
- None.
Feature Changes
~~~~~~~~~~~~~~~
- The interface handling code has been refactored to use fewer resources,
which should lead to less memory fragmentation and better startup
performance. :gl:`#2433`
Bug Fixes
~~~~~~~~~
- Fix a race condition in reading and writing key files for KASP zones in
multiple views. :gl:`#1875`
- Check ``key-directory`` conflicts in ``named.conf`` for zones in multiple
views with different ``dnssec-policy``. Using the same ``key-directory`` for
such zones is not allowed. :gl:`#2463`
- ``named-checkconf`` now complains if zones with ``dnssec-policy`` reference
the same zone file more than once. :gl:`#2603`
- The calculation of the estimated IXFR transaction size by
`dns_journal_iter_init()` was invalid. This resulted in excessive
AXFR-style-IXFR responses. :gl:`#2685`
- If a query was answered with stale data on a server with DNS64 enabled,
an assertion could occur if a non-stale answer arrived afterward. This
has been fixed. :gl:`#2731`
- Fixed an assertion failure that could occur if stale data was used
to answer a query, and then a prefetch was triggered after the query
was restarted (for example, to follow a CNAME). :gl:`#2733`

View File

@@ -254,7 +254,6 @@ struct dns_dumpctx {
isc_mutex_t lock;
isc_refcount_t references;
atomic_bool canceled;
bool first;
bool do_date;
isc_stdtime_t now;
FILE *f;
@@ -1578,7 +1577,6 @@ dumpctx_create(isc_mem_t *mctx, dns_db_t *db, dns_dbversion_t *version,
dctx->done = NULL;
dctx->done_arg = NULL;
dctx->task = NULL;
dctx->first = true;
atomic_init(&dctx->canceled, false);
dctx->file = NULL;
dctx->tmpfile = NULL;
@@ -1737,7 +1735,6 @@ dumptostream(dns_dumpctx_t *dctx) {
char *bufmem;
dns_name_t *name;
dns_fixedname_t fixname;
isc_time_t start;
bufmem = isc_mem_get(dctx->mctx, initial_buffer_length);
@@ -1745,32 +1742,24 @@ dumptostream(dns_dumpctx_t *dctx) {
name = dns_fixedname_initname(&fixname);
if (dctx->first) {
CHECK(writeheader(dctx));
CHECK(writeheader(dctx));
/*
* Fast format is not currently written incrementally,
* so we make the call to dns_db_serialize() here.
* If the database is anything other than an rbtdb,
* this should result in not implemented
*/
if (dctx->format == dns_masterformat_map) {
result = dns_db_serialize(dctx->db, dctx->version,
dctx->f);
goto cleanup;
}
result = dns_dbiterator_first(dctx->dbiter);
if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
goto cleanup;
}
dctx->first = false;
} else {
result = ISC_R_SUCCESS;
/*
* Fast format is not currently written incrementally,
* so we make the call to dns_db_serialize() here.
* If the database is anything other than an rbtdb,
* this should result in not implemented
*/
if (dctx->format == dns_masterformat_map) {
result = dns_db_serialize(dctx->db, dctx->version, dctx->f);
goto cleanup;
}
result = dns_dbiterator_first(dctx->dbiter);
if (result != ISC_R_SUCCESS && result != ISC_R_NOMORE) {
goto cleanup;
}
isc_time_now(&start);
while (result == ISC_R_SUCCESS) {
dns_rdatasetiter_t *rdsiter = NULL;
dns_dbnode_t *node = NULL;
@@ -1790,6 +1779,10 @@ dumptostream(dns_dumpctx_t *dctx) {
}
dctx->tctx.neworigin = origin;
}
result = dns_dbiterator_pause(dctx->dbiter);
RUNTIME_CHECK(result == ISC_R_SUCCESS);
result = dns_db_allrdatasets(dctx->db, node, dctx->version,
dctx->now, &rdsiter);
if (result != ISC_R_SUCCESS) {

View File

@@ -21,6 +21,7 @@
#include <isc/print.h>
#include <isc/tls.h>
#include <isc/url.h>
#include <isc/util.h>
#include "netmgr-int.h"
@@ -58,6 +59,19 @@
#define MIN_SUCCESSFUL_HTTP_STATUS (200)
#define MAX_SUCCESSFUL_HTTP_STATUS (299)
/* This definition sets the upper limit of pending write buffer to an
* adequate enough value. That is done mostly to fight a limitation
* for a max TLS record size in flamethrower (2K). In a perfect world
* this constant should not be required, if we ever move closer to
* that state, the constant, and corresponding code, should be
* removed. For now the limit seems adequate enough to fight
* "tinygrams" problem. */
#define FLUSH_HTTP_WRITE_BUFFER_AFTER (1536)
/* This switch is here mostly to test the code interoperability with
* buggy implementations */
#define ENABLE_HTTP_WRITE_BUFFERING 1
#define SUCCESSFUL_HTTP_STATUS(code) \
((code) >= MIN_SUCCESSFUL_HTTP_STATUS && \
(code) <= MAX_SUCCESSFUL_HTTP_STATUS)
@@ -104,6 +118,8 @@ typedef struct http_cstream {
#define HTTP2_SESSION_MAGIC ISC_MAGIC('H', '2', 'S', 'S')
#define VALID_HTTP2_SESSION(t) ISC_MAGIC_VALID(t, HTTP2_SESSION_MAGIC)
typedef ISC_LIST(isc__nm_uvreq_t) isc__nm_http_pending_callbacks_t;
struct isc_nm_http_session {
unsigned int magic;
isc_refcount_t references;
@@ -130,6 +146,9 @@ struct isc_nm_http_session {
size_t bufsize;
isc_tlsctx_t *tlsctx;
isc__nm_http_pending_callbacks_t pending_write_callbacks;
isc_buffer_t *pending_write_data;
};
typedef enum isc_http_error_responses {
@@ -151,6 +170,7 @@ typedef struct isc_http_send_req {
isc_region_t data;
isc_nm_cb_t cb;
void *cbarg;
isc__nm_http_pending_callbacks_t pending_write_callbacks;
} isc_http_send_req_t;
static bool
@@ -187,6 +207,10 @@ finish_http_session(isc_nm_http_session_t *session);
static void
http_transpost_tcp_nodelay(isc_nmhandle_t *transphandle);
static void
call_pending_callbacks(isc__nm_http_pending_callbacks_t pending_callbacks,
isc_result_t result);
static bool
http_session_active(isc_nm_http_session_t *session) {
REQUIRE(VALID_HTTP2_SESSION(session));
@@ -251,6 +275,7 @@ new_session(isc_mem_t *mctx, isc_tlsctx_t *tctx,
isc_mem_attach(mctx, &session->mctx);
ISC_LIST_INIT(session->cstreams);
ISC_LIST_INIT(session->sstreams);
ISC_LIST_INIT(session->pending_write_callbacks);
*sessionp = session;
}
@@ -431,6 +456,15 @@ finish_http_session(isc_nm_http_session_t *session) {
} else {
server_call_failed_read_cb(ISC_R_UNEXPECTED, session);
}
call_pending_callbacks(session->pending_write_callbacks,
ISC_R_UNEXPECTED);
ISC_LIST_INIT(session->pending_write_callbacks);
if (session->pending_write_data != NULL) {
isc_buffer_free(&session->pending_write_data);
}
isc_nmhandle_detach(&session->handle);
}
@@ -890,6 +924,18 @@ http_readcb(isc_nmhandle_t *handle, isc_result_t result, isc_region_t *region,
http_do_bio(session, NULL, NULL, NULL);
}
static void
call_pending_callbacks(isc__nm_http_pending_callbacks_t pending_callbacks,
isc_result_t result) {
isc__nm_uvreq_t *cbreq = ISC_LIST_HEAD(pending_callbacks);
while (cbreq != NULL) {
isc__nm_uvreq_t *next = ISC_LIST_NEXT(cbreq, link);
ISC_LIST_UNLINK(pending_callbacks, cbreq, link);
isc__nm_sendcb(cbreq->handle->sock, cbreq, result, false);
cbreq = next;
}
}
static void
http_writecb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
isc_http_send_req_t *req = (isc_http_send_req_t *)arg;
@@ -903,6 +949,8 @@ http_writecb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
INSIST(session->handle == handle);
}
call_pending_callbacks(req->pending_write_callbacks, result);
if (req->cb != NULL) {
req->cb(req->httphandle, result, req->cbarg);
isc_nmhandle_detach(&req->httphandle);
@@ -911,8 +959,8 @@ http_writecb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
isc_mem_put(session->mctx, req->data.base, req->data.length);
isc_mem_put(session->mctx, req, sizeof(*req));
http_do_bio(session, NULL, NULL, NULL);
session->sending--;
http_do_bio(session, NULL, NULL, NULL);
isc_nmhandle_detach(&transphandle);
if (result != ISC_R_SUCCESS && session->sending == 0) {
finish_http_session(session);
@@ -920,31 +968,187 @@ http_writecb(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
isc__nm_httpsession_detach(&session);
}
static void
move_pending_send_callbacks(isc_nm_http_session_t *session,
isc_http_send_req_t *send) {
STATIC_ASSERT(
sizeof(session->pending_write_callbacks) ==
sizeof(send->pending_write_callbacks),
"size of pending writes requests callbacks lists differs");
memmove(&send->pending_write_callbacks,
&session->pending_write_callbacks,
sizeof(session->pending_write_callbacks));
ISC_LIST_INIT(session->pending_write_callbacks);
}
static bool
http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle,
isc_nm_cb_t cb, void *cbarg) {
isc_http_send_req_t *send = NULL;
const uint8_t *data = NULL;
size_t pending;
size_t total = 0;
uint8_t tmp_data[8192] = { 0 };
uint8_t *prepared_data = &tmp_data[0];
#ifdef ENABLE_HTTP_WRITE_BUFFERING
size_t max_total_write_size = 0;
#endif /* ENABLE_HTTP_WRITE_BUFFERING */
if (!http_session_active(session) ||
!nghttp2_session_want_write(session->ngsession))
(!nghttp2_session_want_write(session->ngsession) &&
session->pending_write_data == NULL))
{
return (false);
}
pending = nghttp2_session_mem_send(session->ngsession, &data);
if (pending == 0) {
while (nghttp2_session_want_write(session->ngsession)) {
const uint8_t *data = NULL;
const size_t pending =
nghttp2_session_mem_send(session->ngsession, &data);
const size_t new_total = total + pending;
/* reallocate buffer if required */
if (new_total > sizeof(tmp_data)) {
uint8_t *old_prepared_data = prepared_data;
const bool allocated = prepared_data != tmp_data;
prepared_data = isc_mem_get(session->mctx, new_total);
memmove(prepared_data, old_prepared_data, total);
if (allocated) {
isc_mem_put(session->mctx, old_prepared_data,
total);
}
}
memmove(&prepared_data[total], data, pending);
total = new_total;
}
#ifdef ENABLE_HTTP_WRITE_BUFFERING
max_total_write_size = total;
if (session->pending_write_data != NULL) {
max_total_write_size +=
isc_buffer_usedlength(session->pending_write_data);
}
/* Here we are trying to flush the pending writes buffer earlier
* to avoid hitting unnecessary limitations on a TLS record size
* within some tools (e.g. flamethrower). */
if (max_total_write_size >= FLUSH_HTTP_WRITE_BUFFER_AFTER) {
/* Case 1: We have equal or more than
* FLUSH_HTTP_WRITE_BUFFER_AFTER bytes to send. Let's put the
* data which we have just obtained from nghttp2 into the
* pending write buffer and flush it. */
/* Let's allocate a new write buffer if there is none. */
if (session->pending_write_data == NULL) {
isc_buffer_allocate(session->mctx,
&session->pending_write_data,
max_total_write_size);
}
isc_buffer_putmem(session->pending_write_data, prepared_data,
total);
if (prepared_data != &tmp_data[0]) {
isc_mem_put(session->mctx, prepared_data, total);
}
total = max_total_write_size;
prepared_data = isc_buffer_base(session->pending_write_data);
} else if (session->sending > 0 && total > 0) {
/* Case 2: There is one or more write requests in flight and
* we have some new data form nghttp2 to send. Let's put the
* write callback (if any) into the pending write callbacks
* list and add the new data into the pending write
* buffer. Then let's return from the function: as soon as the
* "in-flight" write callback get's called or we have reached
* FLUSH_HTTP_WRITE_BUFFER_AFTER bytes in the write buffer, we
* will flush the buffer. */
if (cb != NULL) {
isc__nm_uvreq_t *newcb = isc__nm_uvreq_get(
httphandle->sock->mgr, httphandle->sock);
INSIST(VALID_NMHANDLE(httphandle));
newcb->cb.send = cb;
newcb->cbarg = cbarg;
isc_nmhandle_attach(httphandle, &newcb->handle);
ISC_LIST_APPEND(session->pending_write_callbacks, newcb,
link);
}
if (session->pending_write_data == NULL) {
isc_buffer_allocate(session->mctx,
&session->pending_write_data,
total);
isc_buffer_setautorealloc(session->pending_write_data,
true);
}
isc_buffer_putmem(session->pending_write_data, prepared_data,
total);
if (prepared_data != &tmp_data[0]) {
isc_mem_put(session->mctx, prepared_data, total);
}
return (false);
} else if (session->sending == 0 && total == 0 &&
session->pending_write_data != NULL)
{
/* Case 3: There is no write in flight and we haven't got
* anything new from nghttp2, but there is some data pending
* in the write buffer. Let's flush the buffer. */
isc_region_t region = { 0 };
total = isc_buffer_usedlength(session->pending_write_data);
INSIST(total > 0);
INSIST(prepared_data == &tmp_data[0]);
isc_buffer_usedregion(session->pending_write_data, &region);
INSIST(total == region.length);
prepared_data = region.base;
} else {
/* The other cases are, uninteresting, fall-through ones. */
/* In the following cases (4-6) we will just bail out. */
/* Case 4: There is nothing new to send, nor anything in the
* write buffer. */
/* Case 5: There is nothing new to send and there is write
* request(s) in flight. */
/* Case 6: There is nothing new to send nor there are any
* write requests in flight. */
/* Case 7: There is some new data to send and there are no any
* write requests in flight: Let's send the data.*/
INSIST((total == 0 && session->pending_write_data == NULL) ||
(total == 0 && session->sending > 0) ||
(total == 0 && session->sending == 0) ||
(total > 0 && session->sending == 0));
}
#else
INSIST(session->pending_write_data == NULL);
INSIST(ISC_LIST_EMPTY(session->pending_write_callbacks));
#endif /* ENABLE_HTTP_WRITE_BUFFERING */
if (total == 0) {
INSIST(prepared_data == &tmp_data[0]);
/* No data returned */
return (false);
}
send = isc_mem_get(session->mctx, sizeof(*send));
*send = (isc_http_send_req_t){
.data.base = isc_mem_get(session->mctx, pending),
.data.length = pending,
};
memmove(send->data.base, data, pending);
if (prepared_data == &tmp_data[0]) {
*send = (isc_http_send_req_t){
.data.base = isc_mem_get(session->mctx, total),
.data.length = total,
};
memmove(send->data.base, tmp_data, total);
} else if (session->pending_write_data != NULL) {
*send = (isc_http_send_req_t){
.data.base = isc_mem_get(session->mctx, total),
.data.length = total,
};
memmove(send->data.base,
isc_buffer_base(session->pending_write_data), total);
isc_buffer_free(&session->pending_write_data);
} else {
*send = (isc_http_send_req_t){
.data.base = prepared_data,
.data.length = total,
};
}
isc_nmhandle_attach(session->handle, &send->transphandle);
isc__nm_httpsession_attach(session, &send->session);
@@ -955,6 +1159,8 @@ http_send_outgoing(isc_nm_http_session_t *session, isc_nmhandle_t *httphandle,
isc_nmhandle_attach(httphandle, &send->httphandle);
}
move_pending_send_callbacks(session, send);
session->sending++;
isc_nm_send(session->handle, &send->data, http_writecb, send);
return (true);
@@ -975,8 +1181,9 @@ http_do_bio(isc_nm_http_session_t *session, isc_nmhandle_t *send_httphandle,
finish_http_session(session);
}
return;
} else if ((nghttp2_session_want_read(session->ngsession) == 0 &&
nghttp2_session_want_write(session->ngsession) == 0))
} else if (nghttp2_session_want_read(session->ngsession) == 0 &&
nghttp2_session_want_write(session->ngsession) == 0 &&
session->pending_write_data == NULL)
{
session->closing = true;
return;

View File

@@ -2985,7 +2985,7 @@ isc__nm_closesocket(uv_os_sock_t sock) {
setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
#define setsockopt_off(socket, level, name) \
setsockopt(socket, level, name, &(int){ 1 }, sizeof(int))
setsockopt(socket, level, name, &(int){ 0 }, sizeof(int))
isc_result_t
isc__nm_socket_freebind(uv_os_sock_t fd, sa_family_t sa_family) {

View File

@@ -578,7 +578,7 @@ udp_send_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req,
return (ISC_R_CANCELED);
}
#ifdef HAVE_UV_UDP_CONNECT
#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
/*
* If we used uv_udp_connect() (and not the shim version for
* older versions of libuv), then the peer address has to be

View File

@@ -36,11 +36,11 @@ isc_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
#ifdef WIN32
return (uv_translate_sys_error(err));
#else /* WIN32 */
#ifdef HAVE_UV_TRANSLATE_SYS_ERROR
#if UV_VERSION_HEX >= UV_VERSION(1, 10, 0)
return (uv_translate_sys_error(errno));
#else
return (-errno);
#endif /* HAVE_UV_TRANSLATE_SYS_ERROR */
#endif /* UV_VERSION_HEX >= UV_VERSION(1, 10, 0) */
#endif /* WIN32 */
}

View File

@@ -694,7 +694,7 @@ mock_udpconnect_uv_udp_bind(void **state __attribute__((unused))) {
RESET_RETURN;
}
#if HAVE_UV_UDP_CONNECT
#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
static void
mock_udpconnect_uv_udp_connect(void **state __attribute__((unused))) {
WILL_RETURN(uv_udp_connect, UV_ENOMEM);
@@ -2730,7 +2730,7 @@ main(void) {
nm_setup, nm_teardown),
cmocka_unit_test_setup_teardown(mock_udpconnect_uv_udp_bind,
nm_setup, nm_teardown),
#if HAVE_UV_UDP_CONNECT
#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
cmocka_unit_test_setup_teardown(mock_udpconnect_uv_udp_connect,
nm_setup, nm_teardown),
#endif

View File

@@ -155,25 +155,38 @@ set_global_error(isc_result_t result) {
}
static void
subthread_assert_true(bool expected) {
subthread_assert_true(bool expected, const char *file, unsigned int line) {
if (!expected) {
printf("# %s:%u subthread_assert_true\n", file, line);
set_global_error(ISC_R_UNEXPECTED);
}
}
#define subthread_assert_true(expected) \
subthread_assert_true(expected, __FILE__, __LINE__)
static void
subthread_assert_int_equal(int observed, int expected) {
subthread_assert_int_equal(int observed, int expected, const char *file,
unsigned int line) {
if (observed != expected) {
printf("# %s:%u subthread_assert_int_equal(%d != %d)\n", file,
line, observed, expected);
set_global_error(ISC_R_UNEXPECTED);
}
}
#define subthread_assert_int_equal(observed, expected) \
subthread_assert_int_equal(observed, expected, __FILE__, __LINE__)
static void
subthread_assert_result_equal(isc_result_t result, isc_result_t expected) {
subthread_assert_result_equal(isc_result_t result, isc_result_t expected,
const char *file, unsigned int line) {
if (result != expected) {
printf("# %s:%u subthread_assert_result_equal(%u != %u)\n",
file, line, result, expected);
set_global_error(result);
}
}
#define subthread_assert_result_equal(observed, expected) \
subthread_assert_result_equal(observed, expected, __FILE__, __LINE__)
static void
ticktock(isc_task_t *task, isc_event_t *event) {

View File

@@ -26,6 +26,8 @@
#define UNIT_TESTING
#include <cmocka.h>
#include "../netmgr/uv-compat.h"
/* uv_udp_t */
int
@@ -33,13 +35,13 @@ __wrap_uv_udp_open(uv_udp_t *handle, uv_os_sock_t sock);
int
__wrap_uv_udp_bind(uv_udp_t *handle, const struct sockaddr *addr,
unsigned int flags);
#if HAVE_UV_UDP_CONNECT
#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
int
__wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr);
int
__wrap_uv_udp_getpeername(const uv_udp_t *handle, struct sockaddr *name,
int *namelen);
#endif /* HAVE_UV_UDP_CONNECT */
#endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
int
__wrap_uv_udp_getsockname(const uv_udp_t *handle, struct sockaddr *name,
int *namelen);
@@ -114,7 +116,7 @@ __wrap_uv_udp_bind(uv_udp_t *handle, const struct sockaddr *addr,
static atomic_int __state_uv_udp_connect
__attribute__((unused)) = ATOMIC_VAR_INIT(0);
#if HAVE_UV_UDP_CONNECT
#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
int
__wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
if (atomic_load(&__state_uv_udp_connect) == 0) {
@@ -122,12 +124,12 @@ __wrap_uv_udp_connect(uv_udp_t *handle, const struct sockaddr *addr) {
}
return (atomic_load(&__state_uv_udp_connect));
}
#endif /* HAVE_UV_UDP_CONNECT */
#endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
static atomic_int __state_uv_udp_getpeername
__attribute__((unused)) = ATOMIC_VAR_INIT(0);
#if HAVE_UV_UDP_CONNECT
#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
int
__wrap_uv_udp_getpeername(const uv_udp_t *handle, struct sockaddr *name,
int *namelen) {
@@ -136,7 +138,7 @@ __wrap_uv_udp_getpeername(const uv_udp_t *handle, struct sockaddr *name,
}
return (atomic_load(&__state_uv_udp_getpeername));
}
#endif /* HAVE_UV_UDP_CONNECT */
#endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
static atomic_int __state_uv_udp_getsockname = ATOMIC_VAR_INIT(0);
int
@@ -274,10 +276,10 @@ __wrap_uv_fileno(const uv_handle_t *handle, uv_os_fd_t *fd) {
#define uv_udp_open(...) __wrap_uv_udp_open(__VA_ARGS__)
#define uv_udp_bind(...) __wrap_uv_udp_bind(__VA_ARGS__)
#if HAVE_UV_UDP_CONNECT
#if UV_VERSION_HEX >= UV_VERSION(1, 27, 0)
#define uv_udp_connect(...) __wrap_uv_udp_connect(__VA_ARGS__)
#define uv_udp_getpeername(...) __wrap_uv_udp_getpeername(__VA_ARGS__)
#endif /* HAVE_UV_UDP_CONNECT */
#endif /* UV_VERSION_HEX >= UV_VERSION(1, 27, 0) */
#define uv_udp_getsockname(...) __wrap_uv_udp_getsockname(__VA_ARGS__)
#define uv_udp_send(...) __wrap_uv_udp_send(__VA_ARGS__)
#define uv_udp_recv_start(...) __wrap_uv_udp_recv_start(__VA_ARGS__)