Coverage Report

Created: 2026-01-24 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/netmgr/udp.c
Line
Count
Source
1
/*
2
 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
3
 *
4
 * SPDX-License-Identifier: MPL-2.0
5
 *
6
 * This Source Code Form is subject to the terms of the Mozilla Public
7
 * License, v. 2.0. If a copy of the MPL was not distributed with this
8
 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
9
 *
10
 * See the COPYRIGHT file distributed with this work for additional
11
 * information regarding copyright ownership.
12
 */
13
14
#include <unistd.h>
15
16
#include <isc/async.h>
17
#include <isc/atomic.h>
18
#include <isc/barrier.h>
19
#include <isc/buffer.h>
20
#include <isc/errno.h>
21
#include <isc/magic.h>
22
#include <isc/mem.h>
23
#include <isc/netmgr.h>
24
#include <isc/random.h>
25
#include <isc/refcount.h>
26
#include <isc/region.h>
27
#include <isc/result.h>
28
#include <isc/sockaddr.h>
29
#include <isc/stdtime.h>
30
#include <isc/thread.h>
31
#include <isc/util.h>
32
#include <isc/uv.h>
33
34
#include "../loop_p.h"
35
#include "netmgr-int.h"
36
37
#ifdef HAVE_NET_ROUTE_H
38
#include <net/route.h>
39
#if defined(RTM_VERSION) && defined(RTM_NEWADDR) && defined(RTM_DELADDR)
40
#define USE_ROUTE_SOCKET      1
41
#define ROUTE_SOCKET_PF       PF_ROUTE
42
#define ROUTE_SOCKET_PROTOCOL 0
43
#define MSGHDR          rt_msghdr
44
#define MSGTYPE         rtm_type
45
#endif /* if defined(RTM_VERSION) && defined(RTM_NEWADDR) && \
46
  * defined(RTM_DELADDR) */
47
#endif /* ifdef HAVE_NET_ROUTE_H */
48
49
#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
50
#include <linux/netlink.h>
51
#include <linux/rtnetlink.h>
52
#if defined(RTM_NEWADDR) && defined(RTM_DELADDR)
53
#define USE_ROUTE_SOCKET      1
54
#define USE_NETLINK       1
55
#define ROUTE_SOCKET_PF       PF_NETLINK
56
#define ROUTE_SOCKET_PROTOCOL NETLINK_ROUTE
57
#define MSGHDR          nlmsghdr
58
#define MSGTYPE         nlmsg_type
59
#endif /* if defined(RTM_NEWADDR) && defined(RTM_DELADDR) */
60
#endif /* if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H) \
61
  */
62
63
static void
64
udp_send_cb(uv_udp_send_t *req, int status);
65
66
static void
67
udp_close_cb(uv_handle_t *handle);
68
69
static uv_os_sock_t
70
0
isc__nm_udp_lb_socket(sa_family_t sa_family) {
71
0
  isc_result_t result;
72
0
  uv_os_sock_t sock = -1;
73
74
0
  result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &sock);
75
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
76
77
0
  (void)isc__nm_socket_disable_pmtud(sock, sa_family);
78
0
  (void)isc__nm_socket_v6only(sock, sa_family);
79
80
0
  result = isc__nm_socket_reuse(sock, 1);
81
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
82
83
0
  if (isc__netmgr->load_balance_sockets) {
84
0
    result = isc__nm_socket_reuse_lb(sock);
85
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
86
0
  }
87
88
0
  return sock;
89
0
}
90
91
/*
92
 * Asynchronous 'udplisten' call handler: start listening on a UDP socket.
93
 */
94
static void
95
0
start_udp_child_job(void *arg) {
96
0
  isc_nmsocket_t *sock = arg;
97
98
0
  REQUIRE(VALID_NMSOCK(sock));
99
0
  REQUIRE(VALID_NMSOCK(sock->parent));
100
0
  REQUIRE(sock->type == isc_nm_udpsocket);
101
0
  REQUIRE(sock->tid == isc_tid());
102
103
0
  int r, uv_bind_flags = 0;
104
0
  int uv_init_flags = 0;
105
0
  sa_family_t sa_family = sock->iface.type.sa.sa_family;
106
0
  isc_result_t result = ISC_R_UNSET;
107
0
  isc_loop_t *loop = sock->worker->loop;
108
109
0
  (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
110
111
0
#if HAVE_DECL_UV_UDP_RECVMMSG
112
0
  uv_init_flags |= UV_UDP_RECVMMSG;
113
0
#endif
114
0
  r = uv_udp_init_ex(&loop->loop, &sock->uv_handle.udp, uv_init_flags);
115
0
  UV_RUNTIME_CHECK(uv_udp_init_ex, r);
116
0
  uv_handle_set_data(&sock->uv_handle.handle, sock);
117
  /* This keeps the socket alive after everything else is gone */
118
0
  isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
119
120
0
  r = uv_timer_init(&loop->loop, &sock->read_timer);
121
0
  UV_RUNTIME_CHECK(uv_timer_init, r);
122
0
  uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
123
124
0
  r = uv_udp_open(&sock->uv_handle.udp, sock->fd);
125
0
  if (r < 0) {
126
0
    isc__nm_closesocket(sock->fd);
127
0
    isc__nm_incstats(sock, STATID_OPENFAIL);
128
0
    goto done;
129
0
  }
130
0
  isc__nm_incstats(sock, STATID_OPEN);
131
132
0
  if (sa_family == AF_INET6) {
133
0
    uv_bind_flags |= UV_UDP_IPV6ONLY;
134
0
  }
135
136
0
  if (isc__netmgr->load_balance_sockets) {
137
0
    r = isc__nm_udp_freebind(&sock->uv_handle.udp,
138
0
           &sock->parent->iface.type.sa,
139
0
           uv_bind_flags);
140
0
    if (r < 0) {
141
0
      isc__nm_incstats(sock, STATID_BINDFAIL);
142
0
      goto done;
143
0
    }
144
0
  } else if (sock->tid == 0) {
145
    /* This thread is first, bind the socket */
146
0
    r = isc__nm_udp_freebind(&sock->uv_handle.udp,
147
0
           &sock->parent->iface.type.sa,
148
0
           uv_bind_flags);
149
0
    if (r < 0) {
150
0
      isc__nm_incstats(sock, STATID_BINDFAIL);
151
0
      goto done;
152
0
    }
153
0
    sock->parent->uv_handle.udp.flags = sock->uv_handle.udp.flags;
154
0
  } else {
155
    /* The socket is already bound, just copy the flags */
156
0
    sock->uv_handle.udp.flags = sock->parent->uv_handle.udp.flags;
157
0
  }
158
159
0
  isc__nm_set_network_buffers(&sock->uv_handle.handle);
160
161
0
  r = uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb,
162
0
            isc__nm_udp_read_cb);
163
0
  if (r != 0) {
164
0
    isc__nm_incstats(sock, STATID_BINDFAIL);
165
0
    goto done;
166
0
  }
167
168
0
done:
169
0
  result = isc_uverr2result(r);
170
171
0
  sock->result = result;
172
173
0
  REQUIRE(!loop->paused);
174
175
0
  if (sock->tid != 0) {
176
0
    isc_barrier_wait(&sock->parent->listen_barrier);
177
0
  }
178
0
}
179
180
static void
181
start_udp_child(isc_sockaddr_t *iface, isc_nmsocket_t *sock, uv_os_sock_t fd,
182
0
    isc_tid_t tid) {
183
0
  isc__networker_t *worker = isc__networker_get(tid);
184
0
  isc_nmsocket_t *csock = &sock->children[tid];
185
186
0
  isc__nmsocket_init(csock, worker, isc_nm_udpsocket, iface, sock);
187
0
  csock->recv_cb = sock->recv_cb;
188
0
  csock->recv_cbarg = sock->recv_cbarg;
189
0
  csock->inactive_handles_max = ISC_NM_NMHANDLES_MAX;
190
191
0
  if (isc__netmgr->load_balance_sockets) {
192
0
    csock->fd = isc__nm_udp_lb_socket(iface->type.sa.sa_family);
193
0
  } else {
194
0
    csock->fd = dup(fd);
195
0
  }
196
0
  INSIST(csock->fd >= 0);
197
198
0
  if (tid == 0) {
199
0
    start_udp_child_job(csock);
200
0
  } else {
201
0
    isc_async_run(worker->loop, start_udp_child_job, csock);
202
0
  }
203
0
}
204
205
isc_result_t
206
isc_nm_listenudp(uint32_t workers, isc_sockaddr_t *iface, isc_nm_recv_cb_t cb,
207
0
     void *cbarg, isc_nmsocket_t **sockp) {
208
0
  isc_result_t result = ISC_R_UNSET;
209
0
  isc_nmsocket_t *sock = NULL;
210
0
  uv_os_sock_t fd = -1;
211
0
  isc__networker_t *worker = isc__networker_get(0);
212
213
0
  REQUIRE(isc_tid() == 0);
214
215
0
  if (isc__nm_closing(worker)) {
216
0
    return ISC_R_SHUTTINGDOWN;
217
0
  }
218
219
0
  sock = isc_mempool_get(worker->nmsocket_pool);
220
0
  isc__nmsocket_init(sock, worker, isc_nm_udplistener, iface, NULL);
221
222
0
  if (workers == ISC_NM_LISTEN_ALL) {
223
0
    sock->nchildren = (uint32_t)isc__netmgr->nloops;
224
0
  } else {
225
0
    sock->nchildren = workers;
226
0
  }
227
0
  REQUIRE(sock->nchildren <= isc__netmgr->nloops);
228
229
0
  sock->children = isc_mem_cget(worker->mctx, sock->nchildren,
230
0
              sizeof(sock->children[0]));
231
232
0
  isc__nmsocket_barrier_init(sock);
233
234
0
  sock->recv_cb = cb;
235
0
  sock->recv_cbarg = cbarg;
236
237
0
  if (!isc__netmgr->load_balance_sockets) {
238
0
    fd = isc__nm_udp_lb_socket(iface->type.sa.sa_family);
239
0
  }
240
241
0
  start_udp_child(iface, sock, fd, 0);
242
0
  result = sock->children[0].result;
243
0
  INSIST(result != ISC_R_UNSET);
244
245
0
  for (size_t i = 1; i < sock->nchildren; i++) {
246
0
    start_udp_child(iface, sock, fd, i);
247
0
  }
248
249
0
  isc_barrier_wait(&sock->listen_barrier);
250
251
0
  if (!isc__netmgr->load_balance_sockets) {
252
0
    isc__nm_closesocket(fd);
253
0
  }
254
255
  /*
256
   * If any of the child sockets have failed then isc_nm_listenudp
257
   * fails.
258
   */
259
0
  for (size_t i = 1; i < sock->nchildren; i++) {
260
0
    if (result == ISC_R_SUCCESS &&
261
0
        sock->children[i].result != ISC_R_SUCCESS)
262
0
    {
263
0
      result = sock->children[i].result;
264
0
    }
265
0
  }
266
267
0
  if (result != ISC_R_SUCCESS) {
268
0
    sock->active = false;
269
0
    isc__nm_udp_stoplistening(sock);
270
0
    isc_nmsocket_close(&sock);
271
272
0
    return result;
273
0
  }
274
275
0
  sock->active = true;
276
277
0
  *sockp = sock;
278
0
  return ISC_R_SUCCESS;
279
0
}
280
281
#ifdef USE_ROUTE_SOCKET
282
static isc_result_t
283
0
route_socket(uv_os_sock_t *fdp) {
284
0
  uv_os_sock_t fd = -1;
285
0
#ifdef USE_NETLINK
286
0
  struct sockaddr_nl sa;
287
0
  int r;
288
0
#endif
289
290
0
  RETERR(isc__nm_socket(ROUTE_SOCKET_PF, SOCK_RAW, ROUTE_SOCKET_PROTOCOL,
291
0
            &fd));
292
293
0
#ifdef USE_NETLINK
294
0
  sa.nl_family = PF_NETLINK;
295
0
  sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR;
296
0
  r = bind(fd, (struct sockaddr *)&sa, sizeof(sa));
297
0
  if (r < 0) {
298
0
    isc__nm_closesocket(fd);
299
0
    return isc_errno_toresult(r);
300
0
  }
301
0
#endif
302
303
0
  *fdp = fd;
304
0
  return ISC_R_SUCCESS;
305
0
}
306
307
static isc_result_t
308
0
route_connect_direct(isc_nmsocket_t *sock) {
309
0
  isc__networker_t *worker = NULL;
310
0
  int r;
311
312
0
  REQUIRE(sock->tid == isc_tid());
313
314
0
  worker = sock->worker;
315
316
0
  sock->connecting = true;
317
318
0
  r = uv_udp_init(&worker->loop->loop, &sock->uv_handle.udp);
319
0
  UV_RUNTIME_CHECK(uv_udp_init, r);
320
0
  uv_handle_set_data(&sock->uv_handle.handle, sock);
321
322
0
  r = uv_timer_init(&worker->loop->loop, &sock->read_timer);
323
0
  UV_RUNTIME_CHECK(uv_timer_init, r);
324
0
  uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
325
326
0
  if (isc__nm_closing(worker)) {
327
0
    return ISC_R_SHUTTINGDOWN;
328
0
  }
329
330
0
  r = uv_udp_open(&sock->uv_handle.udp, sock->fd);
331
0
  if (r != 0) {
332
0
    return isc_uverr2result(r);
333
0
  }
334
335
0
  isc__nm_set_network_buffers(&sock->uv_handle.handle);
336
337
0
  sock->connecting = false;
338
0
  sock->connected = true;
339
340
0
  return ISC_R_SUCCESS;
341
0
}
342
343
#endif /* USE_ROUTE_SOCKET */
344
345
isc_result_t
346
0
isc_nm_routeconnect(isc_nm_cb_t cb, void *cbarg) {
347
0
#ifdef USE_ROUTE_SOCKET
348
0
  isc_result_t result = ISC_R_SUCCESS;
349
0
  isc_nmsocket_t *sock = NULL;
350
0
  isc__nm_uvreq_t *req = NULL;
351
0
  isc__networker_t *worker = isc__networker_current();
352
0
  uv_os_sock_t fd = -1;
353
354
0
  REQUIRE(isc_tid() == 0);
355
356
0
  if (isc__nm_closing(worker)) {
357
0
    return ISC_R_SHUTTINGDOWN;
358
0
  }
359
360
0
  RETERR(route_socket(&fd));
361
362
0
  sock = isc_mempool_get(worker->nmsocket_pool);
363
0
  isc__nmsocket_init(sock, worker, isc_nm_udpsocket, NULL, NULL);
364
365
0
  sock->connect_cb = cb;
366
0
  sock->connect_cbarg = cbarg;
367
0
  sock->client = true;
368
0
  sock->route_sock = true;
369
0
  sock->fd = fd;
370
371
0
  req = isc__nm_uvreq_get(sock);
372
0
  req->cb.connect = cb;
373
0
  req->cbarg = cbarg;
374
0
  req->handle = isc__nmhandle_get(sock, NULL, NULL);
375
376
0
  sock->active = true;
377
378
0
  result = route_connect_direct(sock);
379
0
  if (result != ISC_R_SUCCESS) {
380
0
    sock->active = false;
381
0
    isc__nm_udp_close(sock);
382
0
  }
383
384
0
  isc__nm_connectcb(sock, req, result, true);
385
386
0
  isc__nmsocket_detach(&sock);
387
388
0
  return ISC_R_SUCCESS;
389
#else  /* USE_ROUTE_SOCKET */
390
  UNUSED(mgr);
391
  UNUSED(cb);
392
  UNUSED(cbarg);
393
  UNUSED(extrahandlesize);
394
  return ISC_R_NOTIMPLEMENTED;
395
#endif /* USE_ROUTE_SOCKET */
396
0
}
397
398
/*
399
 * Asynchronous 'udpstop' call handler: stop listening on a UDP socket.
400
 */
401
static void
402
0
stop_udp_child_job(void *arg) {
403
0
  isc_nmsocket_t *sock = arg;
404
0
  REQUIRE(VALID_NMSOCK(sock));
405
0
  REQUIRE(sock->tid == isc_tid());
406
0
  REQUIRE(sock->parent != NULL);
407
408
0
  sock->active = false;
409
410
0
  isc__nm_udp_close(sock);
411
412
0
  REQUIRE(!sock->worker->loop->paused);
413
0
  isc_barrier_wait(&sock->parent->stop_barrier);
414
0
}
415
416
static void
417
0
stop_udp_child(isc_nmsocket_t *sock) {
418
0
  REQUIRE(VALID_NMSOCK(sock));
419
420
0
  if (sock->tid == 0) {
421
0
    stop_udp_child_job(sock);
422
0
  } else {
423
0
    isc_async_run(sock->worker->loop, stop_udp_child_job, sock);
424
0
  }
425
0
}
426
427
void
428
0
isc__nm_udp_stoplistening(isc_nmsocket_t *sock) {
429
0
  REQUIRE(VALID_NMSOCK(sock));
430
0
  REQUIRE(sock->type == isc_nm_udplistener);
431
0
  REQUIRE(sock->tid == isc_tid());
432
0
  REQUIRE(sock->tid == 0);
433
0
  REQUIRE(!sock->closing);
434
435
0
  sock->closing = true;
436
437
  /* Mark the parent socket inactive */
438
0
  sock->active = false;
439
440
  /* Stop all the other threads' children */
441
0
  for (size_t i = 1; i < sock->nchildren; i++) {
442
0
    stop_udp_child(&sock->children[i]);
443
0
  }
444
445
  /* Stop the child for the main thread */
446
0
  stop_udp_child(&sock->children[0]);
447
448
  /* Stop the parent */
449
0
  sock->closed = true;
450
0
  isc__nmsocket_prep_destroy(sock);
451
0
}
452
453
/*
454
 * udp_recv_cb handles incoming UDP packet from uv.  The buffer here is
455
 * reused for a series of packets, so we need to allocate a new one.
456
 * This new one can be reused to send the response then.
457
 */
458
void
459
isc__nm_udp_read_cb(uv_udp_t *handle, ssize_t nrecv, const uv_buf_t *buf,
460
0
        const struct sockaddr *addr, unsigned int flags) {
461
0
  isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)handle);
462
0
  isc__nm_uvreq_t *req = NULL;
463
0
  uint32_t maxudp;
464
0
  isc_result_t result;
465
0
  isc_sockaddr_t sockaddr, *sa = NULL;
466
467
0
  REQUIRE(VALID_NMSOCK(sock));
468
0
  REQUIRE(sock->tid == isc_tid());
469
470
  /*
471
   * When using recvmmsg(2), if no errors occur, there will be a final
472
   * callback with nrecv set to 0, addr set to NULL and the buffer
473
   * pointing at the initially allocated data with the UV_UDP_MMSG_CHUNK
474
   * flag cleared and the UV_UDP_MMSG_FREE flag set.
475
   */
476
0
#if HAVE_DECL_UV_UDP_MMSG_FREE
477
0
  if ((flags & UV_UDP_MMSG_FREE) == UV_UDP_MMSG_FREE) {
478
0
    INSIST(nrecv == 0);
479
0
    INSIST(addr == NULL);
480
0
    goto free;
481
0
  }
482
#else
483
  UNUSED(flags);
484
#endif
485
  /*
486
   * Possible reasons to return now without processing:
487
   *
488
   * - If we're simulating a firewall blocking UDP packets
489
   *   bigger than 'maxudp' bytes for testing purposes.
490
   */
491
0
  maxudp = atomic_load_relaxed(&isc__netmgr->maxudp);
492
0
  if (maxudp != 0 && (uint32_t)nrecv > maxudp) {
493
    /*
494
     * We need to keep the read_cb intact in case, so the
495
     * readtimeout_cb can trigger and not crash because of
496
     * missing read_req.
497
     */
498
0
    goto free;
499
0
  }
500
501
  /*
502
   * - If there was a networking error.
503
   */
504
0
  if (nrecv < 0) {
505
0
    isc__nm_failed_read_cb(sock, isc_uverr2result(nrecv), false);
506
0
    goto free;
507
0
  }
508
509
  /*
510
   * - If the network manager is shutting down
511
   */
512
0
  if (isc__nm_closing(sock->worker)) {
513
0
    isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false);
514
0
    goto free;
515
0
  }
516
517
  /*
518
   * - If the socket is no longer active.
519
   */
520
0
  if (!isc__nmsocket_active(sock)) {
521
0
    isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
522
0
    goto free;
523
0
  }
524
525
  /*
526
   * End of the current (iteration) datagram stream, just free the buffer.
527
   * The callback with nrecv == 0 and addr == NULL is called for both
528
   * normal UDP sockets and recvmmsg sockets at the end of every event
529
   * loop iteration.
530
   */
531
0
  if (nrecv == 0 && addr == NULL) {
532
0
    INSIST(flags == 0);
533
0
    goto free;
534
0
  }
535
536
  /*
537
   * We could receive an empty datagram in which case:
538
   * nrecv == 0 and addr != NULL
539
   */
540
0
  INSIST(addr != NULL);
541
542
0
  if (!sock->route_sock) {
543
0
    result = isc_sockaddr_fromsockaddr(&sockaddr, addr);
544
0
    RUNTIME_CHECK(result == ISC_R_SUCCESS);
545
0
    sa = &sockaddr;
546
0
  }
547
548
0
  req = isc__nm_get_read_req(sock, sa);
549
550
  /*
551
   * The callback will be called synchronously, because result is
552
   * ISC_R_SUCCESS, so we are ok of passing the buf directly.
553
   */
554
0
  req->uvbuf.base = buf->base;
555
0
  req->uvbuf.len = nrecv;
556
557
0
  sock->reading = false;
558
559
  /*
560
   * The client isc_nm_read() expects just a single message, so we need to
561
   * stop reading now.  The reading could be restarted in the read
562
   * callback with another isc_nm_read() call.
563
   */
564
0
  if (sock->client) {
565
0
    isc__nmsocket_timer_stop(sock);
566
0
    isc__nm_stop_reading(sock);
567
0
    isc__nmsocket_clearcb(sock);
568
0
  }
569
570
0
  REQUIRE(!sock->processing);
571
0
  sock->processing = true;
572
0
  isc__nm_readcb(sock, req, ISC_R_SUCCESS, false);
573
0
  sock->processing = false;
574
575
0
free:
576
0
#if HAVE_DECL_UV_UDP_MMSG_CHUNK
577
  /*
578
   * When using recvmmsg(2), chunks will have the UV_UDP_MMSG_CHUNK flag
579
   * set, those must not be freed.
580
   */
581
0
  if ((flags & UV_UDP_MMSG_CHUNK) == UV_UDP_MMSG_CHUNK) {
582
0
    return;
583
0
  }
584
0
#endif
585
586
  /*
587
   * When using recvmmsg(2), if a UDP socket error occurs, nrecv will be <
588
   * 0. In either scenario, the callee can now safely free the provided
589
   * buffer.
590
   */
591
0
  if (nrecv < 0) {
592
    /*
593
     * The buffer may be a null buffer on error.
594
     */
595
0
    if (buf->base == NULL && buf->len == 0) {
596
0
      return;
597
0
    }
598
0
  }
599
600
0
  isc__nm_free_uvbuf(sock, buf);
601
0
}
602
603
static void
604
0
udp_send_cb(uv_udp_send_t *req, int status) {
605
0
  isc_result_t result = ISC_R_SUCCESS;
606
0
  isc__nm_uvreq_t *uvreq = uv_handle_get_data((uv_handle_t *)req);
607
0
  isc_nmsocket_t *sock = NULL;
608
609
0
  REQUIRE(VALID_UVREQ(uvreq));
610
0
  REQUIRE(VALID_NMHANDLE(uvreq->handle));
611
612
0
  sock = uvreq->sock;
613
614
0
  REQUIRE(VALID_NMSOCK(sock));
615
0
  REQUIRE(sock->tid == isc_tid());
616
617
0
  if (status < 0) {
618
0
    isc__nm_incstats(sock, STATID_SENDFAIL);
619
0
    isc__nm_failed_send_cb(sock, uvreq, isc_uverr2result(status),
620
0
               false);
621
0
    return;
622
0
  }
623
624
0
  isc__nm_sendcb(sock, uvreq, result, false);
625
0
}
626
627
static _Atomic(isc_stdtime_t) last_udpsends_log = 0;
628
629
static bool
630
0
can_log_udp_sends(void) {
631
0
  isc_stdtime_t now = isc_stdtime_now();
632
0
  isc_stdtime_t last = atomic_exchange_relaxed(&last_udpsends_log, now);
633
0
  if (now != last) {
634
0
    return true;
635
0
  }
636
637
0
  return false;
638
0
}
639
640
/*
641
 * Send the data in 'region' to a peer via a UDP socket. We try to find
642
 * a proper sibling/child socket so that we won't have to jump to
643
 * another thread.
644
 */
645
void
646
isc__nm_udp_send(isc_nmhandle_t *handle, const isc_region_t *region,
647
0
     isc_nm_cb_t cb, void *cbarg) {
648
0
  isc_nmsocket_t *sock = handle->sock;
649
0
  const isc_sockaddr_t *peer = &handle->peer;
650
0
  const struct sockaddr *sa = NULL;
651
0
  isc__nm_uvreq_t *uvreq = NULL;
652
0
  isc__networker_t *worker = NULL;
653
0
  uint32_t maxudp;
654
0
  int r;
655
0
  isc_result_t result;
656
657
0
  REQUIRE(VALID_NMSOCK(sock));
658
0
  REQUIRE(sock->type == isc_nm_udpsocket);
659
0
  REQUIRE(sock->tid == isc_tid());
660
661
0
  worker = sock->worker;
662
0
  maxudp = atomic_load(&isc__netmgr->maxudp);
663
0
  sa = sock->connected ? NULL : &peer->type.sa;
664
665
  /*
666
   * We're simulating a firewall blocking UDP packets bigger than
667
   * 'maxudp' bytes, for testing purposes.
668
   *
669
   * The client would ordinarily have unreferenced the handle
670
   * in the callback, but that won't happen in this case, so
671
   * we need to do so here.
672
   */
673
0
  if (maxudp != 0 && region->length > maxudp) {
674
0
    isc_nmhandle_detach(&handle);
675
0
    return;
676
0
  }
677
678
0
  uvreq = isc__nm_uvreq_get(sock);
679
0
  uvreq->uvbuf.base = (char *)region->base;
680
0
  uvreq->uvbuf.len = region->length;
681
682
0
  isc_nmhandle_attach(handle, &uvreq->handle);
683
684
0
  uvreq->cb.send = cb;
685
0
  uvreq->cbarg = cbarg;
686
687
0
  if (isc__nm_closing(worker)) {
688
0
    result = ISC_R_SHUTTINGDOWN;
689
0
    goto fail;
690
0
  }
691
692
0
  if (isc__nmsocket_closing(sock)) {
693
0
    result = ISC_R_CANCELED;
694
0
    goto fail;
695
0
  }
696
697
0
  if (uv_udp_get_send_queue_size(&sock->uv_handle.udp) >
698
0
      ISC_NETMGR_UDP_SENDBUF_SIZE)
699
0
  {
700
    /*
701
     * The kernel UDP send queue is full, try sending the UDP
702
     * response synchronously instead of just failing.
703
     */
704
0
    r = uv_udp_try_send(&sock->uv_handle.udp, &uvreq->uvbuf, 1, sa);
705
0
    if (r < 0) {
706
0
      if (can_log_udp_sends()) {
707
0
        isc__netmgr_log(
708
0
          ISC_LOG_ERROR,
709
0
          "Sending UDP messages failed: %s",
710
0
          isc_result_totext(isc_uverr2result(r)));
711
0
      }
712
713
0
      isc__nm_incstats(sock, STATID_SENDFAIL);
714
0
      result = isc_uverr2result(r);
715
0
      goto fail;
716
0
    }
717
718
0
    RUNTIME_CHECK(r == (int)region->length);
719
0
    isc__nm_sendcb(sock, uvreq, ISC_R_SUCCESS, true);
720
721
0
  } else {
722
    /* Send the message asynchronously */
723
0
    r = uv_udp_send(&uvreq->uv_req.udp_send, &sock->uv_handle.udp,
724
0
        &uvreq->uvbuf, 1, sa, udp_send_cb);
725
0
    if (r < 0) {
726
0
      isc__nm_incstats(sock, STATID_SENDFAIL);
727
0
      result = isc_uverr2result(r);
728
0
      goto fail;
729
0
    }
730
0
  }
731
0
  return;
732
0
fail:
733
0
  isc__nm_failed_send_cb(sock, uvreq, result, true);
734
0
}
735
736
static isc_result_t
737
0
udp_connect_direct(isc_nmsocket_t *sock, isc__nm_uvreq_t *req) {
738
0
  int uv_bind_flags = 0;
739
0
  int r;
740
0
  isc__networker_t *worker = sock->worker;
741
0
  isc_result_t result;
742
743
0
  r = uv_udp_init(&worker->loop->loop, &sock->uv_handle.udp);
744
0
  UV_RUNTIME_CHECK(uv_udp_init, r);
745
0
  uv_handle_set_data(&sock->uv_handle.handle, sock);
746
747
0
  r = uv_timer_init(&worker->loop->loop, &sock->read_timer);
748
0
  UV_RUNTIME_CHECK(uv_timer_init, r);
749
0
  uv_handle_set_data((uv_handle_t *)&sock->read_timer, sock);
750
751
0
  r = uv_udp_open(&sock->uv_handle.udp, sock->fd);
752
0
  if (r != 0) {
753
0
    isc__nm_incstats(sock, STATID_OPENFAIL);
754
0
    return isc_uverr2result(r);
755
0
  }
756
0
  isc__nm_incstats(sock, STATID_OPEN);
757
758
  /*
759
   * uv_udp_open() enables REUSE_ADDR, we need to disable it again.
760
   */
761
0
  result = isc__nm_socket_reuse(sock->fd, 0);
762
0
  RUNTIME_CHECK(result == ISC_R_SUCCESS);
763
764
0
  if (sock->iface.type.sa.sa_family == AF_INET6) {
765
0
    uv_bind_flags |= UV_UDP_IPV6ONLY;
766
0
  }
767
768
0
#if HAVE_DECL_UV_UDP_LINUX_RECVERR
769
0
  uv_bind_flags |= UV_UDP_LINUX_RECVERR;
770
0
#endif
771
772
0
  r = uv_udp_bind(&sock->uv_handle.udp, &sock->iface.type.sa,
773
0
      uv_bind_flags);
774
0
  if (r != 0) {
775
0
    isc__nm_incstats(sock, STATID_BINDFAIL);
776
0
    return isc_uverr2result(r);
777
0
  }
778
779
0
  isc__nm_set_network_buffers(&sock->uv_handle.handle);
780
781
  /*
782
   * On FreeBSD the UDP connect() call sometimes results in a
783
   * spurious transient EADDRINUSE. Try a few more times before
784
   * giving up.
785
   */
786
0
  do {
787
0
    r = uv_udp_connect(&sock->uv_handle.udp, &req->peer.type.sa);
788
0
  } while (r == UV_EADDRINUSE && --req->connect_tries > 0);
789
0
  if (r != 0) {
790
0
    isc__nm_incstats(sock, STATID_CONNECTFAIL);
791
0
    return isc_uverr2result(r);
792
0
  }
793
0
  isc__nm_incstats(sock, STATID_CONNECT);
794
795
0
  return ISC_R_SUCCESS;
796
0
}
797
798
void
799
isc_nm_udpconnect(isc_sockaddr_t *local, isc_sockaddr_t *peer, isc_nm_cb_t cb,
800
0
      void *cbarg, unsigned int timeout) {
801
0
  isc_result_t result = ISC_R_SUCCESS;
802
0
  isc_nmsocket_t *sock = NULL;
803
0
  isc__nm_uvreq_t *req = NULL;
804
0
  sa_family_t sa_family;
805
0
  isc__networker_t *worker = isc__networker_current();
806
0
  uv_os_sock_t fd = -1;
807
808
0
  REQUIRE(local != NULL);
809
0
  REQUIRE(peer != NULL);
810
811
0
  if (isc__nm_closing(worker)) {
812
0
    cb(NULL, ISC_R_SHUTTINGDOWN, cbarg);
813
0
    return;
814
0
  }
815
816
0
  sa_family = peer->type.sa.sa_family;
817
818
0
  result = isc__nm_socket(sa_family, SOCK_DGRAM, 0, &fd);
819
0
  if (result != ISC_R_SUCCESS) {
820
0
    cb(NULL, result, cbarg);
821
0
    return;
822
0
  }
823
824
  /* Initialize the new socket */
825
0
  sock = isc_mempool_get(worker->nmsocket_pool);
826
0
  isc__nmsocket_init(sock, worker, isc_nm_udpsocket, local, NULL);
827
828
0
  sock->connect_cb = cb;
829
0
  sock->connect_cbarg = cbarg;
830
0
  sock->read_timeout = timeout;
831
0
  sock->peer = *peer;
832
0
  sock->client = true;
833
834
0
  sock->fd = fd;
835
836
0
  (void)isc__nm_socket_disable_pmtud(sock->fd, sa_family);
837
838
0
  (void)isc__nm_socket_min_mtu(sock->fd, sa_family);
839
840
  /* Initialize the request */
841
0
  req = isc__nm_uvreq_get(sock);
842
0
  req->cb.connect = cb;
843
0
  req->cbarg = cbarg;
844
0
  req->peer = *peer;
845
0
  req->local = *local;
846
0
  req->handle = isc__nmhandle_get(sock, &req->peer, &sock->iface);
847
848
0
  sock->active = true;
849
0
  sock->connecting = true;
850
851
0
  result = udp_connect_direct(sock, req);
852
0
  if (result != ISC_R_SUCCESS) {
853
0
    sock->active = false;
854
0
    isc__nm_failed_connect_cb(sock, req, result, true);
855
0
    isc__nmsocket_detach(&sock);
856
0
    return;
857
0
  }
858
859
0
  sock->connecting = false;
860
0
  sock->connected = true;
861
862
0
  isc__nm_connectcb(sock, req, ISC_R_SUCCESS, true);
863
0
  isc__nmsocket_detach(&sock);
864
0
}
865
866
void
867
isc__nm_udp_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
868
0
         bool async) {
869
0
  REQUIRE(VALID_NMSOCK(sock));
870
0
  REQUIRE(result != ISC_R_SUCCESS);
871
0
  REQUIRE(sock->tid == isc_tid());
872
873
  /*
874
   * For UDP server socket, we don't have child socket via
875
   * "accept", so we:
876
   * - we continue to read
877
   * - we don't clear the callbacks
878
   * - we don't destroy it (only stoplistening could do that)
879
   */
880
881
0
  if (sock->client) {
882
0
    isc__nmsocket_timer_stop(sock);
883
0
    isc__nm_stop_reading(sock);
884
0
  }
885
886
  /* Nobody expects the callback if isc_nm_read() wasn't called */
887
0
  if (sock->reading) {
888
0
    sock->reading = false;
889
890
0
    if (sock->recv_cb != NULL) {
891
0
      isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL);
892
0
      isc__nm_readcb(sock, req, result, async);
893
0
    }
894
0
  }
895
896
0
  if (sock->client) {
897
0
    isc__nmsocket_clearcb(sock);
898
0
    isc__nmsocket_prep_destroy(sock);
899
0
    return;
900
0
  }
901
0
}
902
903
void
904
0
isc__nm_udp_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb, void *cbarg) {
905
0
  isc_nmsocket_t *sock = NULL;
906
0
  isc_result_t result;
907
908
0
  REQUIRE(VALID_NMHANDLE(handle));
909
910
0
  sock = handle->sock;
911
912
0
  REQUIRE(VALID_NMSOCK(sock));
913
0
  REQUIRE(sock->type == isc_nm_udpsocket);
914
0
  REQUIRE(sock->statichandle == handle);
915
0
  REQUIRE(sock->tid == isc_tid());
916
917
  /*
918
   * We need to initialize the callback before checking for shutdown
919
   * conditions, so the callback is always called even on error condition.
920
   */
921
0
  sock->recv_cb = cb;
922
0
  sock->recv_cbarg = cbarg;
923
0
  sock->reading = true;
924
925
0
  if (isc__nm_closing(sock->worker)) {
926
0
    result = ISC_R_SHUTTINGDOWN;
927
0
    goto fail;
928
0
  }
929
930
0
  if (isc__nmsocket_closing(sock)) {
931
0
    result = ISC_R_CANCELED;
932
0
    goto fail;
933
0
  }
934
935
0
  result = isc__nm_start_reading(sock);
936
0
  if (result != ISC_R_SUCCESS) {
937
0
    goto fail;
938
0
  }
939
940
0
  isc__nmsocket_timer_restart(sock);
941
0
  return;
942
943
0
fail:
944
0
  sock->reading = true; /* required by the next call */
945
0
  isc__nm_failed_read_cb(sock, result, true);
946
0
}
947
948
static void
949
0
udp_close_cb(uv_handle_t *handle) {
950
0
  isc_nmsocket_t *sock = uv_handle_get_data(handle);
951
0
  uv_handle_set_data(handle, NULL);
952
953
0
  REQUIRE(VALID_NMSOCK(sock));
954
0
  REQUIRE(sock->tid == isc_tid());
955
0
  REQUIRE(sock->closing);
956
0
  REQUIRE(!sock->closed);
957
958
0
  sock->closed = true;
959
960
0
  isc__nm_incstats(sock, STATID_CLOSE);
961
962
0
  if (sock->parent != NULL) {
963
    /* listening socket (listen) */
964
0
    isc__nmsocket_detach(&sock);
965
0
  } else {
966
    /* client and server sockets */
967
0
    sock->connected = false;
968
0
    isc__nmsocket_prep_destroy(sock);
969
0
  }
970
0
}
971
972
void
973
0
isc__nm_udp_close(isc_nmsocket_t *sock) {
974
0
  REQUIRE(VALID_NMSOCK(sock));
975
0
  REQUIRE(sock->type == isc_nm_udpsocket);
976
0
  REQUIRE(sock->tid == isc_tid());
977
0
  REQUIRE(!sock->closing);
978
979
0
  sock->closing = true;
980
981
0
  isc__nmsocket_clearcb(sock);
982
0
  isc__nmsocket_timer_stop(sock);
983
0
  isc__nm_stop_reading(sock);
984
985
  /*
986
   * The order of the close operation is important here, the uv_close()
987
   * gets scheduled in the reverse order, so we need to close the timer
988
   * last, so its gone by the time we destroy the socket
989
   */
990
991
  /* 2. close the listening socket */
992
0
  isc__nmsocket_clearcb(sock);
993
0
  isc__nm_stop_reading(sock);
994
0
  uv_close(&sock->uv_handle.handle, udp_close_cb);
995
996
  /* 1. close the read timer */
997
0
  isc__nmsocket_timer_stop(sock);
998
0
  uv_close((uv_handle_t *)&sock->read_timer, NULL);
999
0
}
1000
1001
void
1002
0
isc__nm_udp_shutdown(isc_nmsocket_t *sock) {
1003
0
  REQUIRE(VALID_NMSOCK(sock));
1004
0
  REQUIRE(sock->tid == isc_tid());
1005
0
  REQUIRE(sock->type == isc_nm_udpsocket);
1006
1007
  /*
1008
   * If the socket is active, mark it inactive and
1009
   * continue. If it isn't active, stop now.
1010
   */
1011
0
  if (!sock->active) {
1012
0
    return;
1013
0
  }
1014
0
  sock->active = false;
1015
1016
  /* uv_udp_connect is synchronous, we can't be in connected state */
1017
0
  REQUIRE(!sock->connecting);
1018
1019
  /*
1020
   * When the client detaches the last handle, the
1021
   * sock->statichandle would be NULL, in that case, nobody is
1022
   * interested in the callback.
1023
   */
1024
0
  if (sock->statichandle != NULL) {
1025
0
    isc__nm_failed_read_cb(sock, ISC_R_SHUTTINGDOWN, false);
1026
0
    return;
1027
0
  }
1028
1029
  /* Destroy the non-listening socket */
1030
0
  if (sock->parent == NULL) {
1031
0
    isc__nmsocket_prep_destroy(sock);
1032
0
    return;
1033
0
  }
1034
1035
  /* Destroy the listening socket if on the same loop */
1036
0
  if (sock->tid == sock->parent->tid) {
1037
0
    isc__nmsocket_prep_destroy(sock->parent);
1038
0
  }
1039
0
}