2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-28 21:17:54 +00:00

64 Commits

Author SHA1 Message Date
Ondřej Surý
cdccac4993 Fix netmgr read/connect timeout issues
- don't bother closing sockets that are already closing.
- UDP read timeout timer was not stopped after reading.
- improve handling of TCP connection failures.
2020-10-30 11:11:54 +01:00
Ondřej Surý
7a6056bc8f Add isc__nm_udp_shutdown() function
This function will be called during isc_nm_closedown() to ensure
that all UDP sockets are closed and detached.
2020-10-30 11:11:54 +01:00
Evan Hunt
5dcdc00b93 add netmgr functions to support outgoing DNS queries
- isc_nm_tcpdnsconnect() sets up up an outgoing TCP DNS connection.
- isc_nm_tcpconnect(), _udpconnect() and _tcpdnsconnect() now take a
  timeout argument to ensure connections time out and are correctly
  cleaned up on failure.
- isc_nm_read() now supports UDP; it reads a single datagram and then
  stops until the next time it's called.
- isc_nm_cancelread() now runs asynchronously to prevent assertion
  failure if reading is interrupted by a non-network thread (e.g.
  a timeout).
- isc_nm_cancelread() can now apply to UDP sockets.
- added shim code to support UDP connection in versions of libuv
  prior to 1.27, when uv_udp_connect() was added

all these functions will be used to support outgoing queries in dig,
xfrin, dispatch, etc.
2020-10-30 11:11:54 +01:00
Ondřej Surý
8797e5efd5 Fix the data race when read-writing sock->active by using cmpxchg 2020-10-22 11:46:58 -07:00
Ondřej Surý
f7c82e406e 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).
2020-10-22 11:37:16 -07:00
Mark Andrews
f95ba8aa20 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>
2020-10-12 17:51:09 +11:00
Ondřej Surý
d86a74d8a4 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.
2020-10-08 07:24:31 +02:00
Ondřej Surý
fd975a551d 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.
2020-10-05 15:18:28 +02:00
Ondřej Surý
acb6ad9e3c 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.
2020-10-05 15:18:28 +02:00
Ondřej Surý
9dc01a636b 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.
2020-10-05 15:18:24 +02:00
Ondřej Surý
d685bbc822 Add helper function to enable DF (don't fragment) flag on UDP sockets
This commits add isc__nm_socket_dontfrag() helper functions.
2020-10-05 14:55:20 +02:00
Ondřej Surý
5daaca7146 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.
2020-10-05 14:54:24 +02:00
Ondřej Surý
e5ab137ba3 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.
2020-09-28 11:17:11 +02:00
Evan Hunt
dcee985b7f update all copyright headers to eliminate the typo 2020-09-14 16:20:40 -07:00
Witold Kręcicki
00e04a86c8 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.
2020-09-11 12:17:57 -07:00
Ondřej Surý
89c534d3b9 properly lock the setting/unsetting of callbacks in isc_nmsocket_t
changes to socket callback functions were not thread safe.
2020-09-11 12:17:57 -07:00
Witold Kręcicki
7eb4564895 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
2020-09-11 10:24:36 -07:00
Evan Hunt
38264b6a4d 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:23 +02:00
Witold Kręcicki
a0f7d28967 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.
2020-07-31 12:44:22 +02:00
Evan Hunt
233f134a4f 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.
2020-07-01 17:35:10 +02:00
Evan Hunt
23c7373d68 restore "blackhole" functionality
the blackhole ACL was accidentally disabled with respect to client
queries during the netmgr conversion.

in order to make this work for TCP, it was necessary to add a return
code to the accept callback functions passed to isc_nm_listentcp() and
isc_nm_listentcpdns().
2020-06-30 17:29:09 -07:00
Evan Hunt
591b79b597 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.
2020-06-26 00:19:42 -07:00
Evan Hunt
3704c4fff2 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.
2020-06-26 00:19:42 -07:00
Evan Hunt
5191ec8f86 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.
2020-06-19 12:33:26 -07:00
Evan Hunt
abbb79f9d1 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.
2020-06-19 09:41:37 +02:00
Witold Kręcicki
cd79b49538 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.
2020-06-19 09:39:50 +02:00
Evan Hunt
5ea26ee1f1 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.
2020-06-19 09:39:50 +02:00
Evan Hunt
9e740cad21 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.
2020-06-19 09:39:50 +02:00
Witold Kręcicki
60629e5b0b 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.
2020-05-13 08:45:27 +02:00
Witold Kręcicki
01c4c3301e 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:26:05 +02:00
Witold Kręcicki
5fedd21e16 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.
2020-03-24 20:31:43 +00:00
Witold Kręcicki
fc9e2276ca Proper accounting of active TCP connections 2020-03-05 18:02:27 +00:00
Evan Hunt
ba0313e649 fix spelling errors reported by Fossies. 2020-02-21 15:05:08 +11:00
Witold Kręcicki
a0d36d7601 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 12:17:55 +01:00
Ondřej Surý
5777c44ad0 Reformat using the new rules 2020-02-14 09:31:05 +01:00
Evan Hunt
e851ed0bb5 apply the modified style 2020-02-13 15:05:06 -08:00
Ondřej Surý
f50b1e0685 Use clang-format to reformat the source files 2020-02-12 15:04:17 +01:00
Witold Kręcicki
f75a9e32be netmgr: fix a non-thread-safe access to libuv structures
In tcp and udp stoplistening code we accessed libuv structures
from a different thread, which caused a shutdown crash when named
was under load. Also added additional DbC checks making sure we're
in a proper thread when accessing uv_ functions.
2020-01-20 22:28:36 +01:00
Witold Kręcicki
16908ec3d9 netmgr: don't send to an inactive (closing) udp socket
We had a race in which n UDP socket could have been already closing
by libuv but we still sent data to it. Mark socket as not-active
when stopping listening and verify that socket is not active when
trying to send data to it.
2020-01-20 22:28:36 +01:00
Witold Kręcicki
eda4300bbb netmgr: have a single source of truth for tcpdns callback
We pass interface as an opaque argument to tcpdns listening socket.
If we stop listening on an interface but still have in-flight connections
the opaque 'interface' is not properly reference counted, and we might
hit a dead memory. We put just a single source of truth in a listening
socket and make the child sockets use that instead of copying the
value from listening socket. We clean the callback when we stop listening.
2020-01-15 17:22:13 +01:00
Witold Kręcicki
525c583145 netmgr:
- isc__netievent_storage_t was to small to contain
   isc__netievent__socket_streaminfo_t on Windows
 - handle isc_uv_export and isc_uv_import errors properly
 - rewrite isc_uv_export and isc_uv_import on Windows
2020-01-15 14:08:44 +01:00
Evan Hunt
80a5c9f5c8 associate socket stats counters with netmgr socket objects
- the socket stat counters have been moved from socket.h to stats.h.
- isc_nm_t now attaches to the same stats counter group as
  isc_socketmgr_t, so that both managers can increment the same
  set of statistics
- isc__nmsocket_init() now takes an interface as a paramter so that
  the address family can be determined when initializing the socket.
- based on the address family and socket type, a group of statistics
  counters will be associated with the socket - for example, UDP4Active
  with IPv4 UDP sockets and TCP6Active with IPv6 TCP sockets.  note
  that no counters are currently associated with TCPDNS sockets; those
  stats will be handled by the underlying TCP socket.
- the counters are not actually used by netmgr sockets yet; counter
  increment and decrement calls will be added in a later commit.
2020-01-13 14:05:02 -08:00
Evan Hunt
e38004457c netmgr fixes:
- use UV_{TC,UD}P_IPV6ONLY for IPv6 sockets, keeping the pre-netmgr
   behaviour.
 - add a new listening_error bool flag which is set if the child
   listener fails to start listening. This fixes a bug where named would
   hang if, e.g.,  we failed to bind to a TCP socket.
2020-01-13 10:54:17 -08:00
Witold Kręcicki
67c1ca9a79 Use isc_uv_export() to pass bound TCP listening socket to child listeners.
For multithreaded TCP listening we need to pass a bound socket to all
listening threads. Instead of using uv_pipe handle passing method which
is quite complex (lots of callbacks, each of them with its own error
handling) we now use isc_uv_export() to export the socket, pass it as a
member of the isc__netievent_tcpchildlisten_t structure, and then
isc_uv_import() it in the child thread, simplifying the process
significantly.
2020-01-13 10:53:44 -08:00
Diego Fronza
ed9853e739 Fix tcp-highwater stats updating
After the network manager rewrite, tcp-higwater stats was only being
updated when a valid DNS query was received over tcp.

It turns out tcp-quota is updated right after a tcp connection is
accepted, before any data is read, so in the event that some client
connect but don't send a valid query, it wouldn't be taken into
account to update tcp-highwater stats, that is wrong.

This commit fix tcp-highwater to update its stats whenever a tcp connection
is established, independent of what happens after (timeout/invalid
request, etc).
2019-12-12 11:23:10 -08:00
Evan Hunt
31b3980ef0 shorten some names
reduce line breaks and general unwieldiness by changing some
function, type, and parameter names.
2019-12-09 21:44:04 +01:00
Witold Kręcicki
86a847314a Fix a race in socket destruction - we need to remove handle from socket in async close callback or we might race between destruction in the callback and in the original nmhandle_unref 2019-12-09 21:44:04 +01:00
Evan Hunt
c7b86d1cac Style fixes 2019-12-09 21:44:03 +01:00
Witold Kręcicki
3e66b7ba1c Fix a race in tcpdns close with uv_close on timer
stop timers before closing

netmgr: tcpdns_close needs to be asynchronous, it manipulates sock->timer
2019-12-09 21:43:45 +01:00
Witold Kręcicki
0bf74ac792 netmgr:
- make tcp listening IPC pipe name saner
 - put the pipe in /tmp on unices
 - add pid to the pipe name to avoid conflicts between processes
 - fsync directory in which the pipe resides to make sure that the
   child threads will see it and be able to open it
2019-12-09 21:43:45 +01:00