Coverage Report

Created: 2026-04-05 06:47

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/bind9/lib/isc/netmgr/streamdns.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 <limits.h>
15
#include <unistd.h>
16
17
#include <isc/async.h>
18
#include <isc/atomic.h>
19
#include <isc/result.h>
20
#include <isc/thread.h>
21
22
#include "netmgr-int.h"
23
24
/*
25
 * Stream DNS is a unified transport capable of serving both DNS over
26
 * TCP and DNS over TLS.  It is built on top of
27
 * 'isc_dnsstream_assembler_t' which is used for assembling DNS
28
 * messages in the format used for DNS over TCP out of incoming data.
29
 * It is built on top of 'isc_buffer_t' optimised for small (>= 512
30
 * bytes) DNS messages. For small messages it uses a small static
31
 * memory buffer, but it can automatically switch to a larger
32
 * dynamically allocated memory buffer for larger ones. This way we
33
 * avoid unnecessary memory allocation requests in most cases, as most
34
 * DNS messages are small.
35
 *
36
 * The use of 'isc_dnsstream_assembler_t' allows decoupling DNS
37
 * message assembling code from networking code itself, making it
38
 * easier to test.
39
 *
40
 * To understand how the part responsible for reading of data works,
41
 * start by looking at 'streamdns_on_dnsmessage_data_cb()' (the DNS
42
 * message data processing callback) and
43
 * 'streamdns_handle_incoming_data()' which passes incoming data to
44
 * the 'isc_dnsstream_assembler_t' object within the socket.
45
 *
46
 * The writing is done in a simpler manner due to the fact that we
47
 * have full control over the data. For each write request we attempt
48
 * to allocate a 'streamdns_send_req_t' structure, whose main purpose
49
 * is to keep the data required for the send request processing.
50
 *
51
 * When processing write requests there is an important optimisation:
52
 * we attempt to reuse 'streamdns_send_req_t' objects again, in order
53
 * to avoid memory allocations when requesting memory for the new
54
 * 'streamdns_send_req_t' object.
55
 *
56
 * To understand how sending is done, start by looking at
57
 * 'isc__nm_streamdns_send()'. Additionally also take a look at
58
 * 'streamdns_get_send_req()' and 'streamdns_put_send_req()' which are
59
 * responsible for send requests allocation/reuse and initialisation.
60
 *
61
 * The rest of the code is mostly wrapping code to expose the
62
 * functionality of the underlying transport, which at the moment
63
 * could be either TCP or TLS.
64
 */
65
66
typedef struct streamdns_send_req {
67
  isc_nm_cb_t cb;      /* send callback */
68
  void *cbarg;       /* send callback argument */
69
  isc_nmhandle_t *dnshandle; /* Stream DNS socket handle */
70
} streamdns_send_req_t;
71
72
static streamdns_send_req_t *
73
streamdns_get_send_req(isc_nmsocket_t *sock, isc_mem_t *mctx,
74
           isc__nm_uvreq_t *req);
75
76
static void
77
streamdns_put_send_req(isc_mem_t *mctx, streamdns_send_req_t *send_req,
78
           const bool force_destroy);
79
80
static void
81
streamdns_readcb(isc_nmhandle_t *handle, isc_result_t result,
82
     isc_region_t *region, void *cbarg);
83
84
static void
85
streamdns_failed_read_cb(isc_nmsocket_t *sock, const isc_result_t result,
86
       const bool async);
87
88
static void
89
streamdns_try_close_unused(isc_nmsocket_t *sock);
90
91
static bool
92
streamdns_closing(isc_nmsocket_t *sock);
93
94
static void
95
streamdns_resume_processing(void *arg);
96
static void
97
async_streamdns_resume_processing(void *arg);
98
99
static void
100
0
streamdns_resumeread(isc_nmsocket_t *sock, isc_nmhandle_t *transphandle) {
101
0
  if (!sock->streamdns.reading) {
102
0
    sock->streamdns.reading = true;
103
0
    isc_nm_read(transphandle, streamdns_readcb, (void *)sock);
104
0
  }
105
0
}
106
107
static void
108
0
streamdns_readmore(isc_nmsocket_t *sock, isc_nmhandle_t *transphandle) {
109
0
  streamdns_resumeread(sock, transphandle);
110
111
  /* Restart the timer only if there's a last single active handle */
112
0
  isc_nmhandle_t *handle = ISC_LIST_HEAD(sock->active_handles);
113
0
  INSIST(handle != NULL);
114
0
  if (ISC_LIST_NEXT(handle, active_link) == NULL) {
115
0
    isc__nmsocket_timer_start(sock);
116
0
  }
117
0
}
118
119
static void
120
0
streamdns_pauseread(isc_nmsocket_t *sock, isc_nmhandle_t *transphandle) {
121
0
  if (sock->streamdns.reading) {
122
0
    sock->streamdns.reading = false;
123
0
    isc_nm_read_stop(transphandle);
124
0
  }
125
0
}
126
127
static bool
128
streamdns_on_complete_dnsmessage(isc_dnsstream_assembler_t *dnsasm,
129
         isc_region_t *restrict region,
130
         isc_nmsocket_t *sock,
131
0
         isc_nmhandle_t *transphandle) {
132
0
  const bool last_datum = isc_dnsstream_assembler_remaininglength(
133
0
          dnsasm) == region->length;
134
  /*
135
   * Stop after one message if a client connection.
136
   */
137
0
  bool stop = sock->client;
138
139
0
  sock->reading = false;
140
0
  if (sock->recv_cb != NULL) {
141
0
    if (!sock->client) {
142
      /*
143
       * We must allocate a new handle object, as we
144
       * need to ensure that after processing of this
145
       * message has been completed and the handle
146
       * gets destroyed, 'nsock->closehandle_cb'
147
       * (streamdns_resume_processing()) is invoked.
148
       * That is required for pipelining support.
149
       */
150
0
      isc_nmhandle_t *handle = isc__nmhandle_get(
151
0
        sock, &sock->peer, &sock->iface);
152
0
      sock->recv_cb(handle, ISC_R_SUCCESS, region,
153
0
              sock->recv_cbarg);
154
0
      isc_nmhandle_detach(&handle);
155
0
    } else {
156
      /*
157
       * As on the client side we are supposed to stop
158
       * reading/processing after receiving one
159
       * message, we can use the 'sock->recv_handle'
160
       * from which we would need to detach before
161
       * calling the read callback anyway.
162
       */
163
0
      isc_nmhandle_t *recv_handle = sock->recv_handle;
164
0
      sock->recv_handle = NULL;
165
0
      sock->recv_cb(recv_handle, ISC_R_SUCCESS, region,
166
0
              sock->recv_cbarg);
167
0
      isc_nmhandle_detach(&recv_handle);
168
0
    }
169
170
0
    if (streamdns_closing(sock)) {
171
0
      stop = true;
172
0
    }
173
0
  } else {
174
0
    stop = true;
175
0
  }
176
177
0
  if (sock->active_handles_max != 0 &&
178
0
      (sock->active_handles_cur >= sock->active_handles_max))
179
0
  {
180
0
    stop = true;
181
0
  }
182
0
  INSIST(sock->active_handles_cur <= sock->active_handles_max);
183
184
0
  isc__nmsocket_timer_stop(sock);
185
0
  if (stop) {
186
0
    streamdns_pauseread(sock, transphandle);
187
0
  } else if (last_datum) {
188
    /*
189
     * We have processed all data, need to read more.
190
     * The call also restarts the timer.
191
     */
192
0
    streamdns_readmore(sock, transphandle);
193
0
  } else {
194
    /*
195
     * Process more DNS messages in the next loop tick.
196
     */
197
0
    streamdns_pauseread(sock, transphandle);
198
0
    isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
199
0
    isc_async_run(sock->worker->loop,
200
0
            async_streamdns_resume_processing, sock);
201
0
  }
202
203
0
  return false;
204
0
}
205
206
/*
207
 * This function, alongside 'streamdns_handle_incoming_data()',
208
 * connects networking code to the 'isc_dnsstream_assembler_t'. It is
209
 * responsible for making decisions regarding reading from the
210
 * underlying transport socket as well as controlling the read timer.
211
 */
212
static bool
213
streamdns_on_dnsmessage_data_cb(isc_dnsstream_assembler_t *dnsasm,
214
        const isc_result_t result,
215
        isc_region_t *restrict region, void *cbarg,
216
0
        void *userarg) {
217
0
  isc_nmsocket_t *sock = (isc_nmsocket_t *)cbarg;
218
0
  isc_nmhandle_t *transphandle = (isc_nmhandle_t *)userarg;
219
220
0
  switch (result) {
221
0
  case ISC_R_SUCCESS:
222
    /*
223
     * A complete DNS message has been assembled from the incoming
224
     * data. Let's process it.
225
     */
226
0
    return streamdns_on_complete_dnsmessage(dnsasm, region, sock,
227
0
              transphandle);
228
0
  case ISC_R_RANGE:
229
    /*
230
     * It seems that someone attempts to send us some binary junk
231
     * over the socket, as the beginning of the next message tells
232
     * us the there is an empty (0-sized) DNS message to receive.
233
     * We should treat it as a hard error.
234
     */
235
0
    streamdns_failed_read_cb(sock, result, false);
236
0
    return false;
237
0
  case ISC_R_NOMORE:
238
    /*
239
     * We do not have enough data to process the next message and
240
     * thus we need to resume reading from the socket.
241
     */
242
0
    if (sock->recv_handle != NULL) {
243
0
      streamdns_readmore(sock, transphandle);
244
0
    }
245
0
    return false;
246
0
  default:
247
0
    UNREACHABLE();
248
0
  };
249
0
}
250
251
static void
252
streamdns_handle_incoming_data(isc_nmsocket_t *sock,
253
             isc_nmhandle_t *transphandle,
254
0
             void *restrict data, size_t len) {
255
0
  isc_dnsstream_assembler_t *dnsasm = sock->streamdns.input;
256
257
  /*
258
   * Try to process the received data or, when 'data == NULL' and
259
   * 'len == 0', try to resume processing of the data within the
260
   * internal buffers or resume reading, if there is no any.
261
   */
262
0
  isc_dnsstream_assembler_incoming(dnsasm, transphandle, data, len);
263
0
  streamdns_try_close_unused(sock);
264
0
}
265
266
static isc_nmsocket_t *
267
streamdns_sock_new(isc__networker_t *worker, const isc_nmsocket_type_t type,
268
0
       isc_sockaddr_t *addr, const bool is_server) {
269
0
  isc_nmsocket_t *sock;
270
0
  INSIST(type == isc_nm_streamdnssocket ||
271
0
         type == isc_nm_streamdnslistener);
272
273
0
  sock = isc_mempool_get(worker->nmsocket_pool);
274
0
  isc__nmsocket_init(sock, worker, type, addr, NULL);
275
0
  sock->result = ISC_R_UNSET;
276
0
  if (type == isc_nm_streamdnssocket) {
277
0
    sock->read_timeout = isc_nm_getinitialtimeout();
278
0
    sock->client = !is_server;
279
0
    sock->connecting = !is_server;
280
0
    sock->streamdns.input = isc_dnsstream_assembler_new(
281
0
      sock->worker->mctx, streamdns_on_dnsmessage_data_cb,
282
0
      sock);
283
0
  }
284
285
0
  return sock;
286
0
}
287
288
static void
289
streamdns_call_connect_cb(isc_nmsocket_t *sock, isc_nmhandle_t *handle,
290
0
        const isc_result_t result) {
291
0
  sock->connecting = false;
292
0
  INSIST(sock->connect_cb != NULL);
293
0
  sock->connect_cb(handle, result, sock->connect_cbarg);
294
0
  if (result != ISC_R_SUCCESS) {
295
0
    isc__nmsocket_clearcb(handle->sock);
296
0
  } else {
297
0
    sock->connected = true;
298
0
  }
299
0
  streamdns_try_close_unused(sock);
300
0
}
301
302
static void
303
streamdns_save_alpn_status(isc_nmsocket_t *dnssock,
304
0
         isc_nmhandle_t *transp_handle) {
305
0
  const unsigned char *alpn = NULL;
306
0
  unsigned int alpnlen = 0;
307
308
0
  isc__nmhandle_get_selected_alpn(transp_handle, &alpn, &alpnlen);
309
0
  if (alpn != NULL && alpnlen == ISC_TLS_DOT_PROTO_ALPN_ID_LEN &&
310
0
      memcmp(ISC_TLS_DOT_PROTO_ALPN_ID, alpn,
311
0
       ISC_TLS_DOT_PROTO_ALPN_ID_LEN) == 0)
312
0
  {
313
0
    dnssock->streamdns.dot_alpn_negotiated = true;
314
0
  }
315
0
}
316
317
static void
318
streamdns_transport_connected(isc_nmhandle_t *handle, isc_result_t result,
319
0
            void *cbarg) {
320
0
  isc_nmsocket_t *sock = (isc_nmsocket_t *)cbarg;
321
0
  isc_nmhandle_t *streamhandle = NULL;
322
323
0
  REQUIRE(VALID_NMSOCK(sock));
324
325
0
  sock->tid = isc_tid();
326
0
  if (result == ISC_R_EOF) {
327
    /*
328
     * The transport layer (probably TLS) has returned EOF during
329
     * connection establishment. That means that connection has
330
     * been "cancelled" (for compatibility with old transport
331
     * behaviour).
332
     */
333
0
    result = ISC_R_CANCELED;
334
0
    goto error;
335
0
  } else if (result == ISC_R_TLSERROR) {
336
    /*
337
     * In some of the cases when the old code would return
338
     * ISC_R_CANCELLED, the new code could return generic
339
     * ISC_R_TLSERROR code. However, the old code does not expect
340
     * that.
341
     */
342
0
    result = ISC_R_CANCELED;
343
0
    goto error;
344
0
  } else if (result != ISC_R_SUCCESS) {
345
0
    goto error;
346
0
  }
347
348
0
  INSIST(VALID_NMHANDLE(handle));
349
350
0
  sock->iface = isc_nmhandle_localaddr(handle);
351
0
  sock->peer = isc_nmhandle_peeraddr(handle);
352
0
  if (isc__nmsocket_closing(handle->sock)) {
353
0
    result = ISC_R_SHUTTINGDOWN;
354
0
    goto error;
355
0
  }
356
357
0
  isc_nmhandle_attach(handle, &sock->outerhandle);
358
0
  sock->active = true;
359
360
0
  handle->sock->streamdns.sock = sock;
361
362
0
  streamdns_save_alpn_status(sock, handle);
363
0
  isc__nmhandle_set_manual_timer(sock->outerhandle, true);
364
0
  streamhandle = isc__nmhandle_get(sock, &sock->peer, &sock->iface);
365
0
  (void)isc_nmhandle_set_tcp_nodelay(sock->outerhandle, true);
366
0
  streamdns_call_connect_cb(sock, streamhandle, result);
367
0
  isc_nmhandle_detach(&streamhandle);
368
369
0
  return;
370
0
error:
371
0
  if (handle != NULL) {
372
    /*
373
     * Let's save the error description (if any) so that
374
     * e.g. 'dig' could produce a usable error message.
375
     */
376
0
    INSIST(VALID_NMHANDLE(handle));
377
0
    sock->streamdns.tls_verify_error =
378
0
      isc_nm_verify_tls_peer_result_string(handle);
379
0
  }
380
0
  streamhandle = isc__nmhandle_get(sock, NULL, NULL);
381
0
  sock->closed = true;
382
0
  streamdns_call_connect_cb(sock, streamhandle, result);
383
0
  isc_nmhandle_detach(&streamhandle);
384
0
  isc__nmsocket_detach(&sock);
385
0
}
386
387
void
388
isc_nm_streamdnsconnect(isc_sockaddr_t *local, isc_sockaddr_t *peer,
389
      isc_nm_cb_t cb, void *cbarg, unsigned int timeout,
390
      isc_tlsctx_t *tlsctx, const char *sni_hostname,
391
      isc_tlsctx_client_session_cache_t *client_sess_cache,
392
      isc_nm_proxy_type_t proxy_type,
393
0
      isc_nm_proxyheader_info_t *proxy_info) {
394
0
  isc_nmsocket_t *nsock = NULL;
395
0
  isc__networker_t *worker = isc__networker_current();
396
397
0
  if (isc__nm_closing(worker)) {
398
0
    cb(NULL, ISC_R_SHUTTINGDOWN, cbarg);
399
0
    return;
400
0
  }
401
402
0
  nsock = streamdns_sock_new(worker, isc_nm_streamdnssocket, local,
403
0
           false);
404
0
  nsock->connect_cb = cb;
405
0
  nsock->connect_cbarg = cbarg;
406
0
  nsock->connect_timeout = timeout;
407
408
0
  switch (proxy_type) {
409
0
  case ISC_NM_PROXY_NONE:
410
0
    if (tlsctx == NULL) {
411
0
      INSIST(client_sess_cache == NULL);
412
0
      isc_nm_tcpconnect(local, peer,
413
0
            streamdns_transport_connected, nsock,
414
0
            nsock->connect_timeout);
415
0
    } else {
416
0
      isc_nm_tlsconnect(
417
0
        local, peer, streamdns_transport_connected,
418
0
        nsock, tlsctx, sni_hostname, client_sess_cache,
419
0
        nsock->connect_timeout, false, proxy_info);
420
0
    }
421
0
    break;
422
0
  case ISC_NM_PROXY_PLAIN:
423
0
    if (tlsctx == NULL) {
424
0
      isc_nm_proxystreamconnect(local, peer,
425
0
              streamdns_transport_connected,
426
0
              nsock, nsock->connect_timeout,
427
0
              NULL, NULL, NULL, proxy_info);
428
0
    } else {
429
0
      isc_nm_tlsconnect(
430
0
        local, peer, streamdns_transport_connected,
431
0
        nsock, tlsctx, sni_hostname, client_sess_cache,
432
0
        nsock->connect_timeout, true, proxy_info);
433
0
    }
434
0
    break;
435
0
  case ISC_NM_PROXY_ENCRYPTED:
436
0
    INSIST(tlsctx != NULL);
437
0
    isc_nm_proxystreamconnect(
438
0
      local, peer, streamdns_transport_connected, nsock,
439
0
      nsock->connect_timeout, tlsctx, sni_hostname,
440
0
      client_sess_cache, proxy_info);
441
0
    break;
442
0
  default:
443
0
    UNREACHABLE();
444
0
  }
445
0
}
446
447
bool
448
0
isc__nmsocket_streamdns_timer_running(isc_nmsocket_t *sock) {
449
0
  isc_nmsocket_t *transp_sock;
450
451
0
  REQUIRE(VALID_NMSOCK(sock));
452
0
  REQUIRE(sock->type == isc_nm_streamdnssocket);
453
454
0
  if (sock->outerhandle == NULL) {
455
0
    return false;
456
0
  }
457
458
0
  INSIST(VALID_NMHANDLE(sock->outerhandle));
459
0
  transp_sock = sock->outerhandle->sock;
460
0
  INSIST(VALID_NMSOCK(transp_sock));
461
462
0
  return isc__nmsocket_timer_running(transp_sock);
463
0
}
464
465
void
466
0
isc__nmsocket_streamdns_timer_stop(isc_nmsocket_t *sock) {
467
0
  isc_nmsocket_t *transp_sock;
468
469
0
  REQUIRE(VALID_NMSOCK(sock));
470
0
  REQUIRE(sock->type == isc_nm_streamdnssocket);
471
472
0
  if (sock->outerhandle == NULL) {
473
0
    return;
474
0
  }
475
476
0
  INSIST(VALID_NMHANDLE(sock->outerhandle));
477
0
  transp_sock = sock->outerhandle->sock;
478
0
  INSIST(VALID_NMSOCK(transp_sock));
479
480
0
  isc__nmsocket_timer_stop(transp_sock);
481
0
}
482
483
void
484
0
isc__nmsocket_streamdns_timer_restart(isc_nmsocket_t *sock) {
485
0
  isc_nmsocket_t *transp_sock;
486
487
0
  REQUIRE(VALID_NMSOCK(sock));
488
0
  REQUIRE(sock->type == isc_nm_streamdnssocket);
489
490
0
  if (sock->outerhandle == NULL) {
491
0
    return;
492
0
  }
493
494
0
  INSIST(VALID_NMHANDLE(sock->outerhandle));
495
0
  transp_sock = sock->outerhandle->sock;
496
0
  INSIST(VALID_NMSOCK(transp_sock));
497
498
0
  isc__nmsocket_timer_restart(transp_sock);
499
0
}
500
501
static void
502
streamdns_failed_read_cb(isc_nmsocket_t *sock, const isc_result_t result,
503
0
       const bool async) {
504
0
  REQUIRE(VALID_NMSOCK(sock));
505
0
  REQUIRE(result != ISC_R_SUCCESS);
506
507
  /* Nobody is reading from the socket yet */
508
0
  if (sock->recv_handle == NULL) {
509
0
    goto destroy;
510
0
  }
511
512
0
  if (sock->client && result == ISC_R_TIMEDOUT) {
513
0
    if (sock->recv_cb != NULL) {
514
0
      isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL);
515
0
      isc__nm_readcb(sock, req, ISC_R_TIMEDOUT, false);
516
0
    }
517
518
0
    if (isc__nmsocket_timer_running(sock)) {
519
      /* Timer was restarted, bail-out */
520
0
      return;
521
0
    }
522
523
0
    isc__nmsocket_clearcb(sock);
524
525
0
    goto destroy;
526
0
  }
527
528
0
  isc_dnsstream_assembler_clear(sock->streamdns.input);
529
530
  /* Nobody expects the callback if isc_nm_read() wasn't called */
531
0
  if (!sock->client || sock->reading) {
532
0
    sock->reading = false;
533
534
0
    if (sock->recv_cb != NULL) {
535
0
      isc__nm_uvreq_t *req = isc__nm_get_read_req(sock, NULL);
536
0
      isc__nmsocket_clearcb(sock);
537
0
      isc__nm_readcb(sock, req, result, async);
538
0
    }
539
0
  }
540
541
0
destroy:
542
0
  isc__nmsocket_prep_destroy(sock);
543
0
}
544
545
void
546
isc__nm_streamdns_failed_read_cb(isc_nmsocket_t *sock, isc_result_t result,
547
0
         const bool async) {
548
0
  REQUIRE(result != ISC_R_SUCCESS);
549
0
  REQUIRE(sock->type == isc_nm_streamdnssocket);
550
0
  sock->streamdns.reading = false;
551
0
  streamdns_failed_read_cb(sock, result, async);
552
0
}
553
554
static void
555
streamdns_readcb(isc_nmhandle_t *handle, isc_result_t result,
556
0
     isc_region_t *region, void *cbarg) {
557
0
  isc_nmsocket_t *sock = (isc_nmsocket_t *)cbarg;
558
559
0
  REQUIRE(VALID_NMHANDLE(handle));
560
0
  REQUIRE(VALID_NMSOCK(sock));
561
0
  REQUIRE(sock->tid == isc_tid());
562
563
0
  if (result != ISC_R_SUCCESS) {
564
0
    streamdns_failed_read_cb(sock, result, false);
565
0
    return;
566
0
  } else if (streamdns_closing(sock)) {
567
0
    streamdns_failed_read_cb(sock, ISC_R_CANCELED, false);
568
0
    return;
569
0
  }
570
571
0
  streamdns_handle_incoming_data(sock, handle, region->base,
572
0
               region->length);
573
0
}
574
575
static void
576
0
streamdns_try_close_unused(isc_nmsocket_t *sock) {
577
0
  if (sock->recv_handle == NULL && sock->streamdns.nsending == 0) {
578
    /*
579
     * The socket is unused after calling the callback. Let's close
580
     * the underlying connection.
581
     */
582
    /* FIXME: call failed_read_cb(?) */
583
0
    if (sock->outerhandle != NULL) {
584
0
      isc_nmhandle_detach(&sock->outerhandle);
585
0
    }
586
0
    isc__nmsocket_prep_destroy(sock);
587
0
  }
588
0
}
589
590
static streamdns_send_req_t *
591
streamdns_get_send_req(isc_nmsocket_t *sock, isc_mem_t *mctx,
592
0
           isc__nm_uvreq_t *req) {
593
0
  streamdns_send_req_t *send_req;
594
595
0
  if (sock->streamdns.send_req != NULL) {
596
    /*
597
     * We have a previously allocated object - let's use that.
598
     * That should help reducing stress on the memory allocator.
599
     */
600
0
    send_req = (streamdns_send_req_t *)sock->streamdns.send_req;
601
0
    sock->streamdns.send_req = NULL;
602
0
  } else {
603
    /* Allocate a new object. */
604
0
    send_req = isc_mem_get(mctx, sizeof(*send_req));
605
0
    *send_req = (streamdns_send_req_t){ 0 };
606
0
  }
607
608
  /* Initialise the send request object */
609
0
  send_req->cb = req->cb.send;
610
0
  send_req->cbarg = req->cbarg;
611
0
  isc_nmhandle_attach(req->handle, &send_req->dnshandle);
612
613
0
  sock->streamdns.nsending++;
614
615
0
  return send_req;
616
0
}
617
618
static void
619
streamdns_put_send_req(isc_mem_t *mctx, streamdns_send_req_t *send_req,
620
0
           const bool force_destroy) {
621
  /*
622
   * Attempt to put the object for reuse later if we are not
623
   * wrapping up.
624
   */
625
0
  if (!force_destroy) {
626
0
    isc_nmsocket_t *sock = send_req->dnshandle->sock;
627
0
    sock->streamdns.nsending--;
628
0
    isc_nmhandle_detach(&send_req->dnshandle);
629
0
    if (sock->streamdns.send_req == NULL) {
630
0
      sock->streamdns.send_req = send_req;
631
      /*
632
       * An object has been recycled,
633
       * if not - we are going to destroy it.
634
       */
635
0
      return;
636
0
    }
637
0
  }
638
639
0
  isc_mem_put(mctx, send_req, sizeof(*send_req));
640
0
}
641
642
static void
643
0
streamdns_writecb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
644
0
  streamdns_send_req_t *send_req = (streamdns_send_req_t *)cbarg;
645
0
  isc_mem_t *mctx;
646
0
  isc_nm_cb_t cb;
647
0
  void *send_cbarg;
648
0
  isc_nmhandle_t *dnshandle = NULL;
649
650
0
  REQUIRE(VALID_NMHANDLE(handle));
651
0
  REQUIRE(VALID_NMHANDLE(send_req->dnshandle));
652
0
  REQUIRE(VALID_NMSOCK(send_req->dnshandle->sock));
653
0
  REQUIRE(send_req->dnshandle->sock->tid == isc_tid());
654
655
0
  mctx = send_req->dnshandle->sock->worker->mctx;
656
0
  cb = send_req->cb;
657
0
  send_cbarg = send_req->cbarg;
658
659
0
  isc_nmhandle_attach(send_req->dnshandle, &dnshandle);
660
  /* try to keep the send request object for reuse */
661
0
  streamdns_put_send_req(mctx, send_req, false);
662
0
  cb(dnshandle, result, send_cbarg);
663
0
  streamdns_try_close_unused(dnshandle->sock);
664
0
  isc_nmhandle_detach(&dnshandle);
665
0
}
666
667
static bool
668
0
streamdns_closing(isc_nmsocket_t *sock) {
669
0
  return isc__nmsocket_closing(sock) || isc__nm_closing(sock->worker) ||
670
0
         sock->outerhandle == NULL ||
671
0
         (sock->outerhandle != NULL &&
672
0
    isc__nmsocket_closing(sock->outerhandle->sock));
673
0
}
674
675
static void
676
0
streamdns_resume_processing(void *arg) {
677
0
  isc_nmsocket_t *sock = (isc_nmsocket_t *)arg;
678
679
0
  REQUIRE(VALID_NMSOCK(sock));
680
0
  REQUIRE(sock->tid == isc_tid());
681
0
  REQUIRE(!sock->client);
682
683
0
  if (streamdns_closing(sock)) {
684
0
    return;
685
0
  }
686
687
0
  if (sock->active_handles_max != 0 &&
688
0
      (sock->active_handles_cur >= sock->active_handles_max))
689
0
  {
690
0
    return;
691
0
  }
692
693
0
  streamdns_handle_incoming_data(sock, sock->outerhandle, NULL, 0);
694
0
}
695
696
static void
697
0
async_streamdns_resume_processing(void *arg) {
698
0
  isc_nmsocket_t *sock = (isc_nmsocket_t *)arg;
699
700
0
  streamdns_resume_processing(sock);
701
702
0
  isc__nmsocket_detach(&sock);
703
0
}
704
705
static isc_result_t
706
0
streamdns_accept_cb(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
707
0
  isc_nmsocket_t *listensock = (isc_nmsocket_t *)cbarg;
708
0
  isc_nmsocket_t *nsock;
709
0
  isc_sockaddr_t iface;
710
0
  isc_tid_t tid = isc_tid();
711
712
0
  REQUIRE(VALID_NMHANDLE(handle));
713
0
  REQUIRE(VALID_NMSOCK(handle->sock));
714
715
0
  if (isc__nm_closing(handle->sock->worker)) {
716
0
    return ISC_R_SHUTTINGDOWN;
717
0
  } else if (result != ISC_R_SUCCESS) {
718
0
    return result;
719
0
  }
720
721
0
  REQUIRE(VALID_NMSOCK(listensock));
722
0
  REQUIRE(listensock->type == isc_nm_streamdnslistener);
723
724
0
  iface = isc_nmhandle_localaddr(handle);
725
0
  nsock = streamdns_sock_new(handle->sock->worker, isc_nm_streamdnssocket,
726
0
           &iface, true);
727
0
  nsock->recv_cb = listensock->recv_cb;
728
0
  nsock->recv_cbarg = listensock->recv_cbarg;
729
730
0
  nsock->peer = isc_nmhandle_peeraddr(handle);
731
0
  nsock->tid = tid;
732
0
  nsock->read_timeout = isc_nm_getinitialtimeout();
733
0
  nsock->accepting = true;
734
0
  nsock->active = true;
735
736
0
  isc__nmsocket_attach(handle->sock, &nsock->listener);
737
0
  isc_nmhandle_attach(handle, &nsock->outerhandle);
738
0
  handle->sock->streamdns.sock = nsock;
739
740
0
  streamdns_save_alpn_status(nsock, handle);
741
742
0
  nsock->recv_handle = isc__nmhandle_get(nsock, NULL, &iface);
743
0
  INSIST(listensock->accept_cb != NULL);
744
0
  result = listensock->accept_cb(nsock->recv_handle, result,
745
0
               listensock->accept_cbarg);
746
0
  if (result != ISC_R_SUCCESS) {
747
0
    isc_nmhandle_detach(&nsock->recv_handle);
748
0
    isc__nmsocket_detach(&nsock->listener);
749
0
    isc_nmhandle_detach(&nsock->outerhandle);
750
0
    nsock->closed = true;
751
0
    goto exit;
752
0
  }
753
754
0
  nsock->closehandle_cb = streamdns_resume_processing;
755
0
  isc__nmhandle_set_manual_timer(nsock->outerhandle, true);
756
  /* settimeout restarts the timer */
757
0
  isc_nmhandle_settimeout(nsock->outerhandle, isc_nm_getinitialtimeout());
758
0
  (void)isc_nmhandle_set_tcp_nodelay(nsock->outerhandle, true);
759
0
  streamdns_handle_incoming_data(nsock, nsock->outerhandle, NULL, 0);
760
761
0
exit:
762
0
  nsock->accepting = false;
763
764
0
  return result;
765
0
}
766
767
isc_result_t
768
isc_nm_listenstreamdns(uint32_t workers, isc_sockaddr_t *iface,
769
           isc_nm_recv_cb_t recv_cb, void *recv_cbarg,
770
           isc_nm_accept_cb_t accept_cb, void *accept_cbarg,
771
           int backlog, isc_quota_t *quota, isc_tlsctx_t *tlsctx,
772
0
           isc_nm_proxy_type_t proxy_type, isc_nmsocket_t **sockp) {
773
0
  isc_result_t result = ISC_R_FAILURE;
774
0
  isc_nmsocket_t *listener = NULL;
775
0
  isc__networker_t *worker = isc__networker_current();
776
777
0
  REQUIRE(isc_tid() == 0);
778
779
0
  if (isc__nm_closing(worker)) {
780
0
    return ISC_R_SHUTTINGDOWN;
781
0
  }
782
783
0
  listener = streamdns_sock_new(worker, isc_nm_streamdnslistener, iface,
784
0
              true);
785
0
  listener->accept_cb = accept_cb;
786
0
  listener->accept_cbarg = accept_cbarg;
787
0
  listener->recv_cb = recv_cb;
788
0
  listener->recv_cbarg = recv_cbarg;
789
790
0
  switch (proxy_type) {
791
0
  case ISC_NM_PROXY_NONE:
792
0
    if (tlsctx == NULL) {
793
0
      result = isc_nm_listentcp(
794
0
        workers, iface, streamdns_accept_cb, listener,
795
0
        backlog, quota, &listener->outer);
796
0
    } else {
797
0
      result = isc_nm_listentls(workers, iface,
798
0
              streamdns_accept_cb, listener,
799
0
              backlog, quota, tlsctx, false,
800
0
              &listener->outer);
801
0
    }
802
0
    break;
803
0
  case ISC_NM_PROXY_PLAIN:
804
0
    if (tlsctx == NULL) {
805
0
      result = isc_nm_listenproxystream(
806
0
        workers, iface, streamdns_accept_cb, listener,
807
0
        backlog, quota, NULL, &listener->outer);
808
0
    } else {
809
0
      result = isc_nm_listentls(
810
0
        workers, iface, streamdns_accept_cb, listener,
811
0
        backlog, quota, tlsctx, true, &listener->outer);
812
0
    }
813
0
    break;
814
0
  case ISC_NM_PROXY_ENCRYPTED:
815
0
    INSIST(tlsctx != NULL);
816
0
    result = isc_nm_listenproxystream(
817
0
      workers, iface, streamdns_accept_cb, listener, backlog,
818
0
      quota, tlsctx, &listener->outer);
819
0
    break;
820
0
  default:
821
0
    UNREACHABLE();
822
0
  };
823
824
0
  if (result != ISC_R_SUCCESS) {
825
0
    listener->closed = true;
826
0
    isc__nmsocket_detach(&listener);
827
0
    return result;
828
0
  }
829
830
  /* copy the actual port we're listening on into sock->iface */
831
0
  if (isc_sockaddr_getport(iface) == 0) {
832
0
    listener->iface = listener->outer->iface;
833
0
  }
834
835
0
  listener->result = result;
836
0
  listener->active = true;
837
0
  INSIST(listener->outer->streamdns.listener == NULL);
838
0
  listener->nchildren = listener->outer->nchildren;
839
0
  isc__nmsocket_attach(listener, &listener->outer->streamdns.listener);
840
841
0
  *sockp = listener;
842
843
0
  return result;
844
0
}
845
846
void
847
0
isc__nm_streamdns_cleanup_data(isc_nmsocket_t *sock) {
848
0
  switch (sock->type) {
849
0
  case isc_nm_streamdnssocket:
850
0
    isc_dnsstream_assembler_free(&sock->streamdns.input);
851
0
    INSIST(sock->streamdns.nsending == 0);
852
0
    if (sock->streamdns.send_req != NULL) {
853
0
      isc_mem_t *mctx = sock->worker->mctx;
854
0
      streamdns_put_send_req(mctx,
855
0
                 (streamdns_send_req_t *)
856
0
                   sock->streamdns.send_req,
857
0
                 true);
858
0
    }
859
0
    break;
860
0
  case isc_nm_streamdnslistener:
861
0
    if (sock->outer) {
862
0
      isc__nmsocket_detach(&sock->outer);
863
0
    }
864
0
    break;
865
0
  case isc_nm_tlslistener:
866
0
  case isc_nm_tcplistener:
867
0
  case isc_nm_proxystreamlistener:
868
0
    if (sock->streamdns.listener != NULL) {
869
0
      isc__nmsocket_detach(&sock->streamdns.listener);
870
0
    }
871
0
    break;
872
0
  case isc_nm_tlssocket:
873
0
  case isc_nm_tcpsocket:
874
0
  case isc_nm_proxystreamsocket:
875
0
    if (sock->streamdns.sock != NULL) {
876
0
      isc__nmsocket_detach(&sock->streamdns.sock);
877
0
    }
878
0
    break;
879
0
  default:
880
0
    return;
881
0
  }
882
0
}
883
884
static void
885
0
streamdns_read_cb(void *arg) {
886
0
  isc_nmsocket_t *sock = arg;
887
888
0
  REQUIRE(VALID_NMSOCK(sock));
889
0
  REQUIRE(sock->tid == isc_tid());
890
891
0
  if (streamdns_closing(sock)) {
892
0
    streamdns_failed_read_cb(sock, ISC_R_CANCELED, false);
893
0
    goto detach;
894
0
  }
895
896
0
  if (sock->streamdns.reading) {
897
0
    goto detach;
898
0
  }
899
900
0
  INSIST(VALID_NMHANDLE(sock->outerhandle));
901
0
  streamdns_handle_incoming_data(sock, sock->outerhandle, NULL, 0);
902
0
detach:
903
0
  isc__nmsocket_detach(&sock);
904
0
}
905
906
void
907
isc__nm_streamdns_read(isc_nmhandle_t *handle, isc_nm_recv_cb_t cb,
908
0
           void *cbarg) {
909
0
  isc_nmsocket_t *sock = NULL;
910
0
  bool closing = false;
911
912
0
  REQUIRE(VALID_NMHANDLE(handle));
913
0
  sock = handle->sock;
914
0
  REQUIRE(VALID_NMSOCK(sock));
915
0
  REQUIRE(sock->type == isc_nm_streamdnssocket);
916
0
  REQUIRE(sock->recv_handle == handle || sock->recv_handle == NULL);
917
0
  REQUIRE(sock->tid == isc_tid());
918
919
0
  closing = streamdns_closing(sock);
920
921
0
  sock->recv_cb = cb;
922
0
  sock->recv_cbarg = cbarg;
923
0
  sock->reading = true;
924
0
  if (sock->recv_handle == NULL) {
925
0
    isc_nmhandle_attach(handle, &sock->recv_handle);
926
0
  }
927
928
  /*
929
   * In some cases there is little sense in making the operation
930
   * asynchronous as we just want to start reading from the
931
   * underlying transport.
932
   */
933
0
  if (!closing && isc_dnsstream_assembler_result(sock->streamdns.input) ==
934
0
        ISC_R_UNSET)
935
0
  {
936
0
    isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
937
0
    streamdns_read_cb(sock);
938
0
    return;
939
0
  }
940
941
  /*
942
   * We want the read operation to be asynchronous in most cases
943
   * because:
944
   *
945
   * 1. A read operation might be initiated from within the read
946
   *    callback itself.
947
   *
948
   * 2. Due to the above, we need to make the operation
949
   *    asynchronous to keep the socket state consistent.
950
   */
951
952
0
  isc__nmsocket_attach(sock, &(isc_nmsocket_t *){ NULL });
953
0
  isc_job_run(sock->worker->loop, &sock->job, streamdns_read_cb, sock);
954
0
}
955
956
void
957
isc__nm_streamdns_send(isc_nmhandle_t *handle, const isc_region_t *region,
958
0
           isc_nm_cb_t cb, void *cbarg) {
959
0
  isc__nm_uvreq_t *uvreq = NULL;
960
0
  isc_nmsocket_t *sock = NULL;
961
0
  streamdns_send_req_t *send_req;
962
0
  isc_mem_t *mctx;
963
0
  isc_region_t data = { 0 };
964
965
0
  REQUIRE(VALID_NMHANDLE(handle));
966
0
  REQUIRE(VALID_NMSOCK(handle->sock));
967
0
  REQUIRE(region->length <= UINT16_MAX);
968
969
0
  sock = handle->sock;
970
971
0
  REQUIRE(sock->type == isc_nm_streamdnssocket);
972
0
  REQUIRE(sock->tid == isc_tid());
973
974
0
  uvreq = isc__nm_uvreq_get(sock);
975
0
  isc_nmhandle_attach(handle, &uvreq->handle);
976
0
  uvreq->cb.send = cb;
977
0
  uvreq->cbarg = cbarg;
978
0
  uvreq->uvbuf.base = (char *)region->base;
979
0
  uvreq->uvbuf.len = region->length;
980
981
0
  if (streamdns_closing(sock)) {
982
0
    isc__nm_failed_send_cb(sock, uvreq, ISC_R_CANCELED, true);
983
0
    return;
984
0
  }
985
986
  /*
987
   * As when sending, we, basically, handing data to the underlying
988
   * transport, we can treat the operation synchronously, as the
989
   * transport code will take care of the asynchronicity if required.
990
   */
991
0
  mctx = sock->worker->mctx;
992
0
  send_req = streamdns_get_send_req(sock, mctx, uvreq);
993
0
  data.base = (unsigned char *)uvreq->uvbuf.base;
994
0
  data.length = uvreq->uvbuf.len;
995
0
  isc__nm_senddns(sock->outerhandle, &data, streamdns_writecb,
996
0
      (void *)send_req);
997
998
0
  isc__nm_uvreq_put(&uvreq);
999
0
}
1000
1001
static void
1002
0
streamdns_close_direct(isc_nmsocket_t *sock) {
1003
0
  REQUIRE(VALID_NMSOCK(sock));
1004
0
  REQUIRE(sock->tid == isc_tid());
1005
1006
0
  if (sock->outerhandle != NULL) {
1007
0
    sock->streamdns.reading = false;
1008
0
    isc__nmsocket_timer_stop(sock);
1009
0
    isc_nm_read_stop(sock->outerhandle);
1010
0
    isc_nmhandle_close(sock->outerhandle);
1011
0
    isc_nmhandle_detach(&sock->outerhandle);
1012
0
  }
1013
1014
0
  if (sock->listener != NULL) {
1015
0
    isc__nmsocket_detach(&sock->listener);
1016
0
  }
1017
1018
0
  if (sock->recv_handle != NULL) {
1019
0
    isc_nmhandle_detach(&sock->recv_handle);
1020
0
  }
1021
1022
  /* Further cleanup performed in isc__nm_streamdns_cleanup_data() */
1023
0
  isc_dnsstream_assembler_clear(sock->streamdns.input);
1024
0
  sock->closed = true;
1025
0
  sock->active = false;
1026
0
}
1027
1028
void
1029
0
isc__nm_streamdns_close(isc_nmsocket_t *sock) {
1030
0
  REQUIRE(VALID_NMSOCK(sock));
1031
0
  REQUIRE(sock->type == isc_nm_streamdnssocket);
1032
0
  REQUIRE(sock->tid == isc_tid());
1033
0
  REQUIRE(!sock->closing);
1034
1035
0
  sock->closing = true;
1036
1037
0
  streamdns_close_direct(sock);
1038
0
}
1039
1040
void
1041
0
isc__nm_streamdns_stoplistening(isc_nmsocket_t *sock) {
1042
0
  REQUIRE(VALID_NMSOCK(sock));
1043
0
  REQUIRE(sock->type == isc_nm_streamdnslistener);
1044
1045
0
  isc__nmsocket_stop(sock);
1046
0
}
1047
1048
void
1049
0
isc__nmhandle_streamdns_cleartimeout(isc_nmhandle_t *handle) {
1050
0
  isc_nmsocket_t *sock = NULL;
1051
1052
0
  REQUIRE(VALID_NMHANDLE(handle));
1053
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1054
0
  REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
1055
1056
0
  sock = handle->sock;
1057
0
  if (sock->outerhandle != NULL) {
1058
0
    INSIST(VALID_NMHANDLE(sock->outerhandle));
1059
0
    isc_nmhandle_cleartimeout(sock->outerhandle);
1060
0
  }
1061
0
}
1062
1063
void
1064
0
isc__nmhandle_streamdns_settimeout(isc_nmhandle_t *handle, uint32_t timeout) {
1065
0
  isc_nmsocket_t *sock = NULL;
1066
1067
0
  REQUIRE(VALID_NMHANDLE(handle));
1068
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1069
0
  REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
1070
1071
0
  sock = handle->sock;
1072
0
  if (sock->outerhandle != NULL) {
1073
0
    INSIST(VALID_NMHANDLE(sock->outerhandle));
1074
0
    isc_nmhandle_settimeout(sock->outerhandle, timeout);
1075
0
  }
1076
0
}
1077
1078
void
1079
0
isc__nmhandle_streamdns_keepalive(isc_nmhandle_t *handle, bool value) {
1080
0
  isc_nmsocket_t *sock = NULL;
1081
1082
0
  REQUIRE(VALID_NMHANDLE(handle));
1083
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1084
0
  REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
1085
1086
0
  sock = handle->sock;
1087
0
  if (sock->outerhandle != NULL) {
1088
0
    INSIST(VALID_NMHANDLE(sock->outerhandle));
1089
0
    isc_nmhandle_keepalive(sock->outerhandle, value);
1090
0
  }
1091
0
}
1092
1093
void
1094
isc__nmhandle_streamdns_setwritetimeout(isc_nmhandle_t *handle,
1095
0
          uint32_t timeout) {
1096
0
  isc_nmsocket_t *sock = NULL;
1097
1098
0
  REQUIRE(VALID_NMHANDLE(handle));
1099
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1100
0
  REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
1101
1102
0
  sock = handle->sock;
1103
0
  if (sock->outerhandle != NULL) {
1104
0
    INSIST(VALID_NMHANDLE(sock->outerhandle));
1105
0
    isc_nmhandle_setwritetimeout(sock->outerhandle, timeout);
1106
0
  }
1107
0
}
1108
1109
bool
1110
0
isc__nm_streamdns_has_encryption(const isc_nmhandle_t *handle) {
1111
0
  isc_nmsocket_t *sock = NULL;
1112
1113
0
  REQUIRE(VALID_NMHANDLE(handle));
1114
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1115
0
  REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
1116
1117
0
  sock = handle->sock;
1118
0
  if (sock->outerhandle != NULL) {
1119
0
    INSIST(VALID_NMHANDLE(sock->outerhandle));
1120
0
    return isc_nm_has_encryption(sock->outerhandle);
1121
0
  }
1122
1123
0
  return false;
1124
0
}
1125
1126
const char *
1127
0
isc__nm_streamdns_verify_tls_peer_result_string(const isc_nmhandle_t *handle) {
1128
0
  isc_nmsocket_t *sock = NULL;
1129
1130
0
  REQUIRE(VALID_NMHANDLE(handle));
1131
0
  REQUIRE(VALID_NMSOCK(handle->sock));
1132
0
  REQUIRE(handle->sock->type == isc_nm_streamdnssocket);
1133
1134
0
  sock = handle->sock;
1135
0
  if (sock->outerhandle != NULL) {
1136
0
    INSIST(VALID_NMHANDLE(sock->outerhandle));
1137
0
    return isc_nm_verify_tls_peer_result_string(sock->outerhandle);
1138
0
  } else if (sock->streamdns.tls_verify_error != NULL) {
1139
0
    return sock->streamdns.tls_verify_error;
1140
0
  }
1141
1142
0
  return NULL;
1143
0
}
1144
1145
void
1146
0
isc__nm_streamdns_set_tlsctx(isc_nmsocket_t *listener, isc_tlsctx_t *tlsctx) {
1147
0
  REQUIRE(VALID_NMSOCK(listener));
1148
0
  REQUIRE(listener->type == isc_nm_streamdnslistener);
1149
1150
0
  if (listener->outer != NULL) {
1151
0
    INSIST(VALID_NMSOCK(listener->outer));
1152
0
    isc_nmsocket_set_tlsctx(listener->outer, tlsctx);
1153
0
  }
1154
0
}
1155
1156
isc_result_t
1157
0
isc__nm_streamdns_xfr_checkperm(isc_nmsocket_t *sock) {
1158
0
  isc_result_t result = ISC_R_NOPERM;
1159
1160
0
  REQUIRE(VALID_NMSOCK(sock));
1161
0
  REQUIRE(sock->type == isc_nm_streamdnssocket);
1162
1163
0
  if (sock->outerhandle != NULL) {
1164
0
    if (isc_nm_has_encryption(sock->outerhandle) &&
1165
0
        !sock->streamdns.dot_alpn_negotiated)
1166
0
    {
1167
0
      result = ISC_R_DOTALPNERROR;
1168
0
    } else {
1169
0
      result = ISC_R_SUCCESS;
1170
0
    }
1171
0
  }
1172
1173
0
  return result;
1174
0
}
1175
1176
void
1177
0
isc__nmsocket_streamdns_reset(isc_nmsocket_t *sock) {
1178
0
  REQUIRE(VALID_NMSOCK(sock));
1179
0
  REQUIRE(sock->type == isc_nm_streamdnssocket);
1180
1181
0
  if (sock->outerhandle == NULL) {
1182
0
    return;
1183
0
  }
1184
1185
0
  INSIST(VALID_NMHANDLE(sock->outerhandle));
1186
0
  isc__nmsocket_reset(sock->outerhandle->sock);
1187
0
}