Commit Graph

91 Commits

Author SHA1 Message Date
Ondřej Surý
bca8604bf3 Fix the data race when read-writing sock->active by using cmpxchg
(cherry picked from commit 8797e5efd5)
2020-10-22 15:00:07 -07:00
Ondřej Surý
301e4145de Fix the isc_nm_closedown() to actually close the pending connections
1. The isc__nm_tcp_send() and isc__nm_tcp_read() was not checking
   whether the socket was still alive and scheduling reads/sends on
   closed socket.

2. The isc_nm_read(), isc_nm_send() and isc_nm_resumeread() have been
   changed to always return the error conditions via the callbacks, so
   they always succeed.  This applies to all protocols (UDP, TCP and
   TCPDNS).

(cherry picked from commit f7c82e406e)
2020-10-22 15:00:00 -07:00
Mark Andrews
da0a7a34ec Complete the isc_nmhandle_detach() in the worker thread.
isc_nmhandle_detach() needs to complete in the same thread
as shutdown_walk_cb() to avoid a race.  Clear the caller's
pointer then pass control to the worker if necessary.

    WARNING: ThreadSanitizer: data race
    Write of size 8 at 0x000000000001 by thread T1:
    #0 isc_nmhandle_detach lib/isc/netmgr/netmgr.c:1258:15
    #1 control_command bin/named/controlconf.c:388:3
    #2 dispatch lib/isc/task.c:1152:7
    #3 run lib/isc/task.c:1344:2

    Previous read of size 8 at 0x000000000001 by thread T2:
    #0 isc_nm_pauseread lib/isc/netmgr/netmgr.c:1449:33
    #1 recv_data lib/isccc/ccmsg.c:109:2
    #2 isc__nm_tcp_shutdown lib/isc/netmgr/tcp.c:1157:4
    #3 shutdown_walk_cb lib/isc/netmgr/netmgr.c:1515:3
    #4 uv_walk <null>
    #5 process_queue lib/isc/netmgr/netmgr.c:659:4
    #6 process_normal_queue lib/isc/netmgr/netmgr.c:582:10
    #7 process_queues lib/isc/netmgr/netmgr.c:590:8
    #8 async_cb lib/isc/netmgr/netmgr.c:548:2
    #9 <null> <null>

(cherry picked from commit f95ba8aa20)
2020-10-15 11:03:47 +11:00
Ondřej Surý
53d6a11a0e Clone the csock in accept_connection(), not in callback
If we clone the csock (children socket) in TCP accept_connection()
instead of passing the ssock (server socket) to the call back and
cloning it there we unbreak the assumption that every socket is handled
inside it's own worker thread and therefore we can get rid of (at least)
callback locking.

(cherry picked from commit e8b56acb49)
2020-10-08 08:16:54 +02:00
Ondřej Surý
69e6c8467c Change the isc__nm_tcpdns_stoplistening() to be asynchronous event
The isc__nm_tcpdns_stoplistening() would call isc__nmsocket_clearcb()
that would clear the .accept_cb from non-netmgr thread.  Change the
tcpdns_stoplistening to enqueue ievent that would get processed in the
right netmgr thread to avoid locking.

(cherry picked from commit d86a74d8a4)
2020-10-08 08:16:53 +02:00
Ondřej Surý
ccd2902a02 Split reusing the addr/port and load-balancing socket options
The SO_REUSEADDR, SO_REUSEPORT and SO_REUSEPORT_LB has different meaning
on different platform. In this commit, we split the function to set the
reuse of address/port and setting the load-balancing into separate
functions.

The libuv library already have multiplatform support for setting
SO_REUSEADDR and SO_REUSEPORT that allows binding to the same address
and port, but unfortunately, when used after the load-balancing socket
options have been already set, it overrides the previous setting, so we
need our own helper function to enable the SO_REUSEADDR/SO_REUSEPORT
first and then enable the load-balancing socket option.

(cherry picked from commit fd975a551d)
2020-10-05 16:19:23 +02:00
Ondřej Surý
5cff119533 Use uv_os_sock_t instead of uv_os_fd_t for sockets
On POSIX based systems both uv_os_sock_t and uv_os_fd_t are both typedef
to int.  That's not true on Windows, where uv_os_sock_t is SOCKET and
uv_os_fd_t is HANDLE and they differ in level of indirection.

(cherry picked from commit acb6ad9e3c)
2020-10-05 16:19:23 +02:00
Ondřej Surý
601fc37efe Refactor isc__nm_socket_freebind() to take fd and sa_family as args
The isc__nm_socket_freebind() has been refactored to match other
isc__nm_socket_...() helper functions and take uv_os_fd_t and
sa_family_t as function arguments.

(cherry picked from commit 9dc01a636b)
2020-10-05 16:19:23 +02:00
Ondřej Surý
c3d721b13b Add helper function to enable DF (don't fragment) flag on UDP sockets
This commits add isc__nm_socket_dontfrag() helper functions.

(cherry picked from commit d685bbc822)
2020-10-05 16:19:23 +02:00
Ondřej Surý
72b85a4100 Add SO_REUSEPORT and SO_INCOMING_CPU helper functions
The setting of SO_REUSE**** and SO_INCOMING_CPU have been moved into a
separate helper functions.

(cherry picked from commit 5daaca7146)
2020-10-05 16:19:23 +02:00
Ondřej Surý
1126fe3b5b Refactor the pausing/unpausing and finishing the nm_thread
The isc_nm_pause(), isc_nm_resume() and finishing the nm_thread() from
nm_destroy() has been refactored, so all use the netievents instead of
directly touching the worker structure members.  This allows us to
remove most of the locking as the .paused and .finished members are
always accessed from the matching nm_thread.

When shutting down the nm_thread(), instead of issuing uv_stop(), we
just shutdown the .async handler, so all uv_loop_t events are properly
finished first and uv_run() ends gracefully with no outstanding active
handles in the loop.

(cherry picked from commit e5ab137ba3)
2020-10-01 18:09:35 +02:00
Witold Kręcicki
4a7dfd69ac tracing of active sockets and handles
If NETMGR_TRACE is defined, we now maintain a list of active sockets
in the netmgr object and a list of active handles in each socket
object; by walking the list and printing `backtrace` in a debugger
we can see where they were created, to assist in in debugging of
reference counting errors.

On shutdown, if netmgr finds there are still active sockets after
waiting, isc__nm_dump_active() will be called to log the list of
active sockets and their underlying handles, along with some details
about them.

(cherry picked from commit 00e04a86c8)
2020-10-01 18:09:35 +02:00
Evan Hunt
686b73ae25 limit the time we wait for netmgr to be destroyed
if more than 10 seconds pass while we wait for netmgr events to
finish running on shutdown, something is almost certainly wrong
and we should assert and crash.

(cherry picked from commit 2f2d60a989)
2020-10-01 18:09:35 +02:00
Ondřej Surý
5a92958fba properly lock the setting/unsetting of callbacks in isc_nmsocket_t
changes to socket callback functions were not thread safe.

(cherry picked from commit 89c534d3b9)
2020-10-01 18:09:35 +02:00
Evan Hunt
ba2e9dfb99 change from isc_nmhandle_ref/unref to isc_nmhandle attach/detach
Attaching and detaching handle pointers will make it easier to
determine where and why reference counting errors have occurred.

A handle needs to be referenced more than once when multiple
asynchronous operations are in flight, so callers must now maintain
multiple handle pointers for each pending operation. For example,
ns_client objects now contain:

        - reqhandle:    held while waiting for a request callback (query,
                        notify, update)
        - sendhandle:   held while waiting for a send callback
        - fetchhandle:  held while waiting for a recursive fetch to
                        complete
        - updatehandle: held while waiting for an update-forwarding
                        task to complete

(cherry picked from commit 57b4dde974)
2020-10-01 18:09:35 +02:00
Witold Kręcicki
0202b289c2 assorted small netmgr-related changes
- rename isc_nmsocket_t->tcphandle to statichandle
- cancelread functions now take handles instead of sockets
- add a 'client' flag in socket objects, currently unused, to
  indicate whether it is to be used as a client or server socket

(cherry picked from commit 7eb4564895)
2020-10-01 16:44:43 +02:00
Evan Hunt
7a4e97ef50 Use different allocators for UDP and TCP
Each worker has a receive buffer with space for 20 DNS messages of up
to 2^16 bytes each, and the allocator function passed to uv_read_start()
or uv_udp_recv_start() will reserve a portion of it for use by sockets.
UDP can use recvmmsg() and so it needs that entire space, but TCP reads
one message at a time.

This commit introduces separate allocator functions for TCP and UDP
setting different buffer size limits, so that libuv will provide the
correct buffer sizes to each of them.

(cherry picked from commit 38264b6a4d)
2020-10-01 16:44:43 +02:00
Witold Kręcicki
f0b089d922 netmgr: retry binding with IP_FREEBIND when EADDRNOTAVAIL is returned.
When a new IPv6 interface/address appears it's first in a tentative
state - in which we cannot bind to it, yet it's already being reported
by the route socket. Because of that BIND9 is unable to listen on any
newly detected IPv6 addresses. Fix it by setting IP_FREEBIND option (or
equivalent option on other OSes) and then retrying bind() call.

(cherry picked from commit a0f7d28967)
2020-10-01 16:44:43 +02:00
Evan Hunt
bc5ea9d65e use handles for isc_nm_pauseread() and isc_nm_resumeread()
by having these functions act on netmgr handles instead of socket
objects, they can be used in callback functions outside the netgmr.

(cherry picked from commit 55896df79d)
2020-10-01 16:44:43 +02:00
Evan Hunt
6b77bd309a Don't destroy a non-closed socket, wait for all the callbacks.
We erroneously tried to destroy a socket after issuing
isc__nm_tcp{,dns}_close. Under some (race) circumstances we could get
nm_socket_cleanup to be called twice for the same socket, causing an
access to a dead memory.

(cherry picked from commit 233f134a4f)
2020-10-01 16:44:43 +02:00
Evan Hunt
80569bf977 Make netmgr tcpdns send calls asynchronous
isc__nm_tcpdns_send() was not asynchronous and accessed socket
internal fields in an unsafe manner, which could lead to a race
condition and subsequent crash. Fix it by moving tcpdns processing
to a proper netmgr thread.

(cherry picked from commit 591b79b597)
2020-10-01 16:44:43 +02:00
Witold Kręcicki
3942b226b8 Fix a shutdown race in netmgr udp
We need to mark the socket as inactive early (and synchronously)
in the stoplistening process; otherwise we might destroy the
callback argument before we actually stop listening, and call
the callback on bad memory.

(cherry picked from commit 1cf65cd882)
2020-10-01 16:44:43 +02:00
Evan Hunt
ca39572e5d clean up outerhandle when a tcpdns socket is disconnected
this prevents a crash when some non-netmgr thread, such as a
recursive lookup, times out after the TCP socket is already
disconnected.

(cherry picked from commit 3704c4fff2)
2020-10-01 16:44:43 +02:00
Evan Hunt
d9d482e9e2 implement isc_nm_cancelread()
The isc_nm_cancelread() function cancels reading on a connected
socket and calls its read callback function with a 'result'
parameter of ISC_R_CANCELED.

(cherry picked from commit 5191ec8f86)
2020-10-01 16:44:43 +02:00
Evan Hunt
e1ebbaacea shorten the sleep in isc_nm_destroy()
when isc_nm_destroy() is called, there's a loop that waits for
other references to be detached, pausing and unpausing the netmgr
to ensure that all the workers' events are run, followed by a
1-second sleep. this caused a delay on shutdown which will be
noticeable when netmgr is used in tools other than named itself,
so the delay has now been reduced to a hundredth of a second.

(cherry picked from commit 870204fe47)
2020-10-01 16:44:43 +02:00
Evan Hunt
a9061ea123 implement isc_nm_tcpconnect()
the isc_nm_tcpconnect() function establishes a client connection via
TCP.  once the connection is esablished, a callback function will be
called with a newly created network manager handle.

(cherry picked from commit abbb79f9d1)
2020-10-01 16:44:43 +02:00
Witold Kręcicki
8db2ef9f8e allow tcpdns sockets to self-reference while connected
A TCPDNS socket creates a handle for each complete DNS message.

Previously, when all the handles were disconnected, the socket
would be closed, but the wrapped TCP socket might still have
more to read.

Now, when a connection is established, the TCPDNS socket creates
a reference to itself by attaching itself to sock->self. This
reference isn't cleared until the connection is closed via
EOF, timeout, or server shutdown. This allows the socket to remain
open even when there are no active handles for it.

(cherry picked from commit cd79b49538)
2020-10-01 16:44:43 +02:00
Evan Hunt
4209f051e9 modify reference counting within netmgr
- isc__nmhandle_get() now attaches to the sock in the nmhandle object.
  the caller is responsible for dereferencing the original socket
  pointer when necessary.
- tcpdns listener sockets attach sock->outer to the outer tcp listener
  socket. tcpdns connected sockets attach sock->outerhandle to the handle
  for the tcp connected socket.
- only listener sockets need to be attached/detached directly. connected
  sockets should only be accessed and reference-counted via their
  associated handles.

(cherry picked from commit 5ea26ee1f1)
2020-10-01 16:44:43 +02:00
Evan Hunt
573bcdf932 make isc_nmsocket_{attach,detach}{} functions private
there is no need for a caller to reference-count socket objects.
they need tto be able tto close listener sockets (i.e., those
returned by isc_nm_listen{udp,tcp,tcpdns}), and an isc_nmsocket_close()
function has been added for that. other sockets are only accessed via
handles.

(cherry picked from commit 9e740cad21)
2020-10-01 16:44:43 +02:00
Ondřej Surý
826ddb246e Revert the tree to allow cherry-picking netmgr changes from main
The following reverted changes will be picked again as part of the
netmgr sync with main branch.

Revert "Merge branch '1996-confidential-issue-v9_16' into 'security-v9_16'"

This reverts commit e160b1509f, reversing
changes made to c01e643715.

Revert "Merge branch '2038-use-freebind-when-bind-fails-v9_16' into 'v9_16'"

This reverts commit 5f8ecfb918, reversing
changes made to 23021385d5.

Revert "Merge branch '1936-blackhole-fix-v9_16' into 'v9_16'"

This reverts commit f20bc90a72, reversing
changes made to 490016ebf1.

Revert "Merge branch '1938-fix-udp-race' into 'v9_16'"

This reverts commit 0a6c7ab2a9, reversing
changes made to 4ea84740e6.

Revert "Merge branch '1947-fix-tcpdns-race' into 'v9_16'"

This reverts commit 4ea84740e6, reversing
changes made to d761cd576b.
2020-10-01 16:44:43 +02:00
Evan Hunt
df698d73f4 update all copyright headers to eliminate the typo 2020-09-14 16:50:58 -07:00
Evan Hunt
9a372f2bce Use different allocators for UDP and TCP
Each worker has a receive buffer with space for 20 DNS messages of up
to 2^16 bytes each, and the allocator function passed to uv_read_start()
or uv_udp_recv_start() will reserve a portion of it for use by sockets.
UDP can use recvmmsg() and so it needs that entire space, but TCP reads
one message at a time.

This commit introduces separate allocator functions for TCP and UDP
setting different buffer size limits, so that libuv will provide the
correct buffer sizes to each of them.
2020-08-05 12:57:58 +02:00
Witold Kręcicki
a12076cc52 netmgr: retry binding with IP_FREEBIND when EADDRNOTAVAIL is returned.
When a new IPv6 interface/address appears it's first in a tentative
state - in which we cannot bind to it, yet it's already being reported
by the route socket. Because of that BIND9 is unable to listen on any
newly detected IPv6 addresses. Fix it by setting IP_FREEBIND option (or
equivalent option on other OSes) and then retrying bind() call.

(cherry picked from commit a0f7d28967)
2020-07-31 13:33:06 +02:00
Witold Kręcicki
4582ef3bb2 Fix a shutdown race in netmgr udp.
We need to mark the socket as inactive early (and synchronously)
in the stoplistening process - otherwise we might destroy the
callback argument before actually stopping listening, and call
the callback on a bad memory.
2020-06-26 01:44:03 -07:00
Witold Kręcicki
97e44fa3df Make netmgr tcpdns send calls asynchronous.
isc__nm_tcpdns_send() was not asynchronous and accessed socket
internal fields in an unsafe manner, which could lead to a race
condition and subsequent crash. Fix it by moving the whole tcpdns
processing to a proper netmgr thread.
2020-06-26 01:18:27 -07:00
Ondřej Surý
8b4fe6c6c5 Add missing acquire memory barrier in isc_nmhandle_unref
The ThreadSanitizer uses system synchronization primitives to check for
data race.  The netmgr handle->references was missing acquire memory
barrier before resetting and reusing the memory occupied by isc_nmhandle_t.

(cherry picked from commit 1013c0930e)
2020-06-16 08:58:33 +02:00
Witold Kręcicki
818afe613f Redesigned TCP accepting: one listen/accept loop, passing the connected socket.
Instead of using bind() and passing the listening socket to the children
threads using uv_export/uv_import use one thread that does the accepting,
and then passes the connected socket using uv_export/uv_import to a random
worker. The previous solution had thundering herd problems (all workers
waking up on one connection and trying to accept()), this one avoids this
and is simpler.
The tcp clients quota is simplified with isc_quota_attach_cb - a callback
is issued when the quota is available.

(cherry picked from commit 60629e5b0b)
2020-06-03 23:00:52 +02:00
Witold Kręcicki
3461aab083 Clear sock->magic to 0 when destroying a netmgr socket
(cherry picked from commit 7ef756f639)
2020-05-30 07:50:30 +02:00
Witold Kręcicki
4ceddeee78 Add missing isc_mutex_destroy and isc_conditional_destroy calls.
While harmless on Linux, missing isc_{mutex,conditional}_destroy
causes a memory leak on *BSD. Missing calls were added.

(cherry picked from commit a8807d9a7b)
2020-05-30 07:50:30 +02:00
Evan Hunt
00c816778d change 'expr == true' to 'expr' in conditionals
(cherry picked from commit 68a1c9d679)
2020-05-25 17:03:59 -07:00
Witold Kręcicki
786a289dfb Don't free udp recv buffer if UV_UDP_MMSG_CHUNK is set
(cherry picked from commit 83049ceabf)
2020-05-01 11:27:46 +02:00
Ondřej Surý
0e9b0d79fb Remove the extra decstats on STATID_ACTIVE for children sockets
(cherry picked from commit 26842ac25c)
2020-04-03 20:22:56 +02:00
Witold Kręcicki
365636dbc9 netmgr refactoring: use generic functions when operating on sockets.
tcpdns used transport-specific functions to operate on the outer socket.
Use generic ones instead, and select the proper call in netmgr.c.
Make the missing functions (e.g. isc_nm_read) generic and add type-specific
calls (isc__nm_tcp_read). This is the preparation for netmgr TLS layer.

(cherry picked from commit 5fedd21e16)
2020-04-03 13:44:28 +02:00
Witold Kręcicki
3274650123 Deactivate the handle before sending the async close callback.
We could have a race between handle closing and processing async
callback. Deactivate the handle before issuing the callback - we
have the socket referenced anyway so it's not a problem.
2020-03-30 10:54:12 +00:00
Witold Kręcicki
11b80da9ff Limit TCP connection quota logging to 1/s
(cherry picked from commit fc9792eae8)
2020-03-05 23:27:56 +00:00
Witold Kręcicki
b85de76816 Proper accounting of active TCP connections
(cherry picked from commit fc9e2276ca)
2020-03-05 23:27:56 +00:00
Witold Kręcicki
fbc81f4ed7 Increase inactivehandles and inactivereqs size for better reuse.
(cherry picked from commit 4791263def)
2020-02-28 10:05:25 +01:00
Witold Kręcicki
85c2f8dab5 Make nm->recvbuf larger and heap allocated, to allow uv_recvmmsg usage.
Upcoming version of libuv will suport uv_recvmmsg and uv_sendmmsg. To
use uv_recvmmsg we need to provide a larger buffer and be able to
properly free it.
2020-02-18 14:21:16 +01:00
Ondřej Surý
829b461c54 Merge branch '46-enforce-clang-format-rules' into 'master'
Start enforcing the clang-format rules on changed files

Closes #46

See merge request isc-projects/bind9!3063

(cherry picked from commit a04cdde45d)

d2b5853b Start enforcing the clang-format rules on changed files
618947c6 Switch AlwaysBreakAfterReturnType from TopLevelDefinitions to All
654927c8 Add separate .clang-format files for headers
5777c44a Reformat using the new rules
60d29f69 Don't enforce copyrights on .clang-format
2020-02-14 08:45:59 +00:00
Ondřej Surý
cdef20bb66 Merge branch 'each-style-tweak' into 'master'
adjust clang-format options to get closer to ISC style

See merge request isc-projects/bind9!3061

(cherry picked from commit d3b49b6675)

0255a974 revise .clang-format and add a C formatting script in util
e851ed0b apply the modified style
2020-02-14 05:35:29 +00:00