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 /*! \file */
15
16 #include <stdbool.h>
17
18 #include <isc/interfaceiter.h>
19 #include <isc/netmgr.h>
20 #include <isc/os.h>
21 #include <isc/random.h>
22 #include <isc/string.h>
23 #include <isc/task.h>
24 #include <isc/util.h>
25
26 #include <dns/acl.h>
27 #include <dns/dispatch.h>
28
29 #include <ns/client.h>
30 #include <ns/interfacemgr.h>
31 #include <ns/log.h>
32 #include <ns/server.h>
33 #include <ns/stats.h>
34
35 #ifdef HAVE_NET_ROUTE_H
36 #include <net/route.h>
37 #if defined(RTM_VERSION) && defined(RTM_NEWADDR) && defined(RTM_DELADDR)
38 #define USE_ROUTE_SOCKET 1
39 #define ROUTE_SOCKET_PROTOCOL PF_ROUTE
40 #define MSGHDR rt_msghdr
41 #define MSGTYPE rtm_type
42 #endif /* if defined(RTM_VERSION) && defined(RTM_NEWADDR) && \
43 * defined(RTM_DELADDR) */
44 #endif /* ifdef HAVE_NET_ROUTE_H */
45
46 #if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
47 #include <linux/netlink.h>
48 #include <linux/rtnetlink.h>
49 #if defined(RTM_NEWADDR) && defined(RTM_DELADDR)
50 #define USE_ROUTE_SOCKET 1
51 #define ROUTE_SOCKET_PROTOCOL PF_NETLINK
52 #define MSGHDR nlmsghdr
53 #define MSGTYPE nlmsg_type
54 #endif /* if defined(RTM_NEWADDR) && defined(RTM_DELADDR) */
55 #endif /* if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H) \
56 */
57
58 #ifdef TUNE_LARGE
59 #define UDPBUFFERS 32768
60 #else /* ifdef TUNE_LARGE */
61 #define UDPBUFFERS 1000
62 #endif /* TUNE_LARGE */
63
64 #define IFMGR_MAGIC ISC_MAGIC('I', 'F', 'M', 'G')
65 #define NS_INTERFACEMGR_VALID(t) ISC_MAGIC_VALID(t, IFMGR_MAGIC)
66
67 #define IFMGR_COMMON_LOGARGS \
68 ns_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR
69
70 /*% nameserver interface manager structure */
71 struct ns_interfacemgr {
72 unsigned int magic; /*%< Magic number. */
73 isc_refcount_t references;
74 isc_mutex_t lock;
75 isc_mem_t *mctx; /*%< Memory context. */
76 ns_server_t *sctx; /*%< Server context. */
77 isc_taskmgr_t *taskmgr; /*%< Task manager. */
78 isc_task_t *excl; /*%< Exclusive task. */
79 isc_timermgr_t *timermgr; /*%< Timer manager. */
80 isc_socketmgr_t *socketmgr; /*%< Socket manager. */
81 isc_nm_t *nm; /*%< Net manager. */
82 int ncpus; /*%< Number of workers . */
83 dns_dispatchmgr_t *dispatchmgr;
84 unsigned int generation; /*%< Current generation no. */
85 ns_listenlist_t *listenon4;
86 ns_listenlist_t *listenon6;
87 dns_aclenv_t aclenv; /*%< Localhost/localnets ACLs */
88 ISC_LIST(ns_interface_t) interfaces; /*%< List of interfaces. */
89 ISC_LIST(isc_sockaddr_t) listenon;
90 int backlog; /*%< Listen queue size */
91 unsigned int udpdisp; /*%< UDP dispatch count */
92 atomic_bool shuttingdown; /*%< Interfacemgr is shutting
93 * down */
94 #ifdef USE_ROUTE_SOCKET
95 isc_task_t *task;
96 isc_socket_t *route;
97 unsigned char buf[2048];
98 #endif /* ifdef USE_ROUTE_SOCKET */
99 };
100
101 static void
102 purge_old_interfaces(ns_interfacemgr_t *mgr);
103
104 static void
105 clearlistenon(ns_interfacemgr_t *mgr);
106
107 #ifdef USE_ROUTE_SOCKET
108 static void
route_event(isc_task_t * task,isc_event_t * event)109 route_event(isc_task_t *task, isc_event_t *event) {
110 isc_socketevent_t *sevent = NULL;
111 ns_interfacemgr_t *mgr = NULL;
112 isc_region_t r;
113 isc_result_t result;
114 struct MSGHDR *rtm;
115 bool done = true;
116
117 UNUSED(task);
118
119 REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
120 mgr = event->ev_arg;
121 sevent = (isc_socketevent_t *)event;
122
123 if (sevent->result != ISC_R_SUCCESS) {
124 if (sevent->result != ISC_R_CANCELED) {
125 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
126 "automatic interface scanning "
127 "terminated: %s",
128 isc_result_totext(sevent->result));
129 }
130 ns_interfacemgr_detach(&mgr);
131 isc_event_free(&event);
132 return;
133 }
134
135 rtm = (struct MSGHDR *)mgr->buf;
136 #ifdef RTM_VERSION
137 if (rtm->rtm_version != RTM_VERSION) {
138 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
139 "automatic interface rescanning disabled: "
140 "rtm->rtm_version mismatch (%u != %u) "
141 "recompile required",
142 rtm->rtm_version, RTM_VERSION);
143 ns_interfacemgr_detach(&mgr);
144 isc_event_free(&event);
145 return;
146 }
147 #endif /* ifdef RTM_VERSION */
148
149 switch (rtm->MSGTYPE) {
150 case RTM_NEWADDR:
151 case RTM_DELADDR:
152 if (mgr->route != NULL && mgr->sctx->interface_auto) {
153 ns_interfacemgr_scan(mgr, false);
154 }
155 break;
156 default:
157 break;
158 }
159
160 LOCK(&mgr->lock);
161 if (mgr->route != NULL) {
162 /*
163 * Look for next route event.
164 */
165 r.base = mgr->buf;
166 r.length = sizeof(mgr->buf);
167 result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
168 route_event, mgr);
169 if (result == ISC_R_SUCCESS) {
170 done = false;
171 }
172 }
173 UNLOCK(&mgr->lock);
174
175 if (done) {
176 ns_interfacemgr_detach(&mgr);
177 }
178 isc_event_free(&event);
179 return;
180 }
181 #endif /* ifdef USE_ROUTE_SOCKET */
182
183 isc_result_t
ns_interfacemgr_create(isc_mem_t * mctx,ns_server_t * sctx,isc_taskmgr_t * taskmgr,isc_timermgr_t * timermgr,isc_socketmgr_t * socketmgr,isc_nm_t * nm,dns_dispatchmgr_t * dispatchmgr,isc_task_t * task,unsigned int udpdisp,dns_geoip_databases_t * geoip,int ncpus,ns_interfacemgr_t ** mgrp)184 ns_interfacemgr_create(isc_mem_t *mctx, ns_server_t *sctx,
185 isc_taskmgr_t *taskmgr, isc_timermgr_t *timermgr,
186 isc_socketmgr_t *socketmgr, isc_nm_t *nm,
187 dns_dispatchmgr_t *dispatchmgr, isc_task_t *task,
188 unsigned int udpdisp, dns_geoip_databases_t *geoip,
189 int ncpus, ns_interfacemgr_t **mgrp) {
190 isc_result_t result;
191 ns_interfacemgr_t *mgr;
192
193 #ifndef USE_ROUTE_SOCKET
194 UNUSED(task);
195 #endif /* ifndef USE_ROUTE_SOCKET */
196
197 REQUIRE(mctx != NULL);
198 REQUIRE(mgrp != NULL);
199 REQUIRE(*mgrp == NULL);
200
201 mgr = isc_mem_get(mctx, sizeof(*mgr));
202
203 mgr->mctx = NULL;
204 isc_mem_attach(mctx, &mgr->mctx);
205
206 mgr->sctx = NULL;
207 ns_server_attach(sctx, &mgr->sctx);
208
209 isc_mutex_init(&mgr->lock);
210
211 mgr->excl = NULL;
212 result = isc_taskmgr_excltask(taskmgr, &mgr->excl);
213 if (result != ISC_R_SUCCESS) {
214 goto cleanup_lock;
215 }
216
217 mgr->taskmgr = taskmgr;
218 mgr->timermgr = timermgr;
219 mgr->socketmgr = socketmgr;
220 mgr->nm = nm;
221 mgr->dispatchmgr = dispatchmgr;
222 mgr->generation = 1;
223 mgr->listenon4 = NULL;
224 mgr->listenon6 = NULL;
225 mgr->udpdisp = udpdisp;
226 mgr->ncpus = ncpus;
227 atomic_init(&mgr->shuttingdown, false);
228
229 ISC_LIST_INIT(mgr->interfaces);
230 ISC_LIST_INIT(mgr->listenon);
231
232 /*
233 * The listen-on lists are initially empty.
234 */
235 result = ns_listenlist_create(mctx, &mgr->listenon4);
236 if (result != ISC_R_SUCCESS) {
237 goto cleanup_ctx;
238 }
239 ns_listenlist_attach(mgr->listenon4, &mgr->listenon6);
240
241 result = dns_aclenv_init(mctx, &mgr->aclenv);
242 if (result != ISC_R_SUCCESS) {
243 goto cleanup_listenon;
244 }
245 #if defined(HAVE_GEOIP2)
246 mgr->aclenv.geoip = geoip;
247 #else /* if defined(HAVE_GEOIP2) */
248 UNUSED(geoip);
249 #endif /* if defined(HAVE_GEOIP2) */
250
251 #ifdef USE_ROUTE_SOCKET
252 mgr->route = NULL;
253 result = isc_socket_create(mgr->socketmgr, ROUTE_SOCKET_PROTOCOL,
254 isc_sockettype_raw, &mgr->route);
255 switch (result) {
256 case ISC_R_NOPERM:
257 case ISC_R_SUCCESS:
258 case ISC_R_NOTIMPLEMENTED:
259 case ISC_R_FAMILYNOSUPPORT:
260 break;
261 default:
262 goto cleanup_aclenv;
263 }
264
265 mgr->task = NULL;
266 if (mgr->route != NULL) {
267 isc_task_attach(task, &mgr->task);
268 }
269 isc_refcount_init(&mgr->references, (mgr->route != NULL) ? 2 : 1);
270 #else /* ifdef USE_ROUTE_SOCKET */
271 isc_refcount_init(&mgr->references, 1);
272 #endif /* ifdef USE_ROUTE_SOCKET */
273 mgr->magic = IFMGR_MAGIC;
274 *mgrp = mgr;
275
276 #ifdef USE_ROUTE_SOCKET
277 if (mgr->route != NULL) {
278 isc_region_t r = { mgr->buf, sizeof(mgr->buf) };
279
280 result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
281 route_event, mgr);
282 if (result != ISC_R_SUCCESS) {
283 isc_task_detach(&mgr->task);
284 isc_socket_detach(&mgr->route);
285 ns_interfacemgr_detach(&mgr);
286 }
287 }
288 #endif /* ifdef USE_ROUTE_SOCKET */
289 return (ISC_R_SUCCESS);
290
291 #ifdef USE_ROUTE_SOCKET
292 cleanup_aclenv:
293 dns_aclenv_destroy(&mgr->aclenv);
294 #endif /* ifdef USE_ROUTE_SOCKET */
295 cleanup_listenon:
296 ns_listenlist_detach(&mgr->listenon4);
297 ns_listenlist_detach(&mgr->listenon6);
298 cleanup_lock:
299 isc_mutex_destroy(&mgr->lock);
300 cleanup_ctx:
301 ns_server_detach(&mgr->sctx);
302 isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
303 return (result);
304 }
305
306 static void
ns_interfacemgr_destroy(ns_interfacemgr_t * mgr)307 ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
308 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
309
310 isc_refcount_destroy(&mgr->references);
311
312 #ifdef USE_ROUTE_SOCKET
313 if (mgr->route != NULL) {
314 isc_socket_detach(&mgr->route);
315 }
316 if (mgr->task != NULL) {
317 isc_task_detach(&mgr->task);
318 }
319 #endif /* ifdef USE_ROUTE_SOCKET */
320 dns_aclenv_destroy(&mgr->aclenv);
321 ns_listenlist_detach(&mgr->listenon4);
322 ns_listenlist_detach(&mgr->listenon6);
323 clearlistenon(mgr);
324 isc_mutex_destroy(&mgr->lock);
325 if (mgr->sctx != NULL) {
326 ns_server_detach(&mgr->sctx);
327 }
328 if (mgr->excl != NULL) {
329 isc_task_detach(&mgr->excl);
330 }
331 mgr->magic = 0;
332 isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
333 }
334
335 void
ns_interfacemgr_setbacklog(ns_interfacemgr_t * mgr,int backlog)336 ns_interfacemgr_setbacklog(ns_interfacemgr_t *mgr, int backlog) {
337 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
338 LOCK(&mgr->lock);
339 mgr->backlog = backlog;
340 UNLOCK(&mgr->lock);
341 }
342
343 dns_aclenv_t *
ns_interfacemgr_getaclenv(ns_interfacemgr_t * mgr)344 ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) {
345 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
346
347 return (&mgr->aclenv);
348 }
349
350 void
ns_interfacemgr_attach(ns_interfacemgr_t * source,ns_interfacemgr_t ** target)351 ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) {
352 REQUIRE(NS_INTERFACEMGR_VALID(source));
353 isc_refcount_increment(&source->references);
354 *target = source;
355 }
356
357 void
ns_interfacemgr_detach(ns_interfacemgr_t ** targetp)358 ns_interfacemgr_detach(ns_interfacemgr_t **targetp) {
359 ns_interfacemgr_t *target = *targetp;
360 *targetp = NULL;
361 REQUIRE(target != NULL);
362 REQUIRE(NS_INTERFACEMGR_VALID(target));
363 if (isc_refcount_decrement(&target->references) == 1) {
364 ns_interfacemgr_destroy(target);
365 }
366 }
367
368 void
ns_interfacemgr_shutdown(ns_interfacemgr_t * mgr)369 ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
370 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
371
372 /*%
373 * Shut down and detach all interfaces.
374 * By incrementing the generation count, we make purge_old_interfaces()
375 * consider all interfaces "old".
376 */
377 mgr->generation++;
378 atomic_store(&mgr->shuttingdown, true);
379 #ifdef USE_ROUTE_SOCKET
380 LOCK(&mgr->lock);
381 if (mgr->route != NULL) {
382 isc_socket_cancel(mgr->route, mgr->task, ISC_SOCKCANCEL_RECV);
383 isc_socket_detach(&mgr->route);
384 isc_task_detach(&mgr->task);
385 }
386 UNLOCK(&mgr->lock);
387 #endif /* ifdef USE_ROUTE_SOCKET */
388 purge_old_interfaces(mgr);
389 }
390
391 static isc_result_t
ns_interface_create(ns_interfacemgr_t * mgr,isc_sockaddr_t * addr,const char * name,ns_interface_t ** ifpret)392 ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
393 const char *name, ns_interface_t **ifpret) {
394 ns_interface_t *ifp;
395 isc_result_t result;
396 int disp;
397
398 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
399
400 ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
401 *ifp = (ns_interface_t){ .generation = mgr->generation,
402 .addr = *addr,
403 .dscp = -1 };
404
405 strlcpy(ifp->name, name, sizeof(ifp->name));
406
407 isc_mutex_init(&ifp->lock);
408
409 for (disp = 0; disp < MAX_UDP_DISPATCH; disp++) {
410 ifp->udpdispatch[disp] = NULL;
411 }
412
413 /*
414 * Create a single TCP client object. It will replace itself
415 * with a new one as soon as it gets a connection, so the actual
416 * connections will be handled in parallel even though there is
417 * only one client initially.
418 */
419 isc_refcount_init(&ifp->ntcpaccepting, 0);
420 isc_refcount_init(&ifp->ntcpactive, 0);
421
422 ISC_LINK_INIT(ifp, link);
423
424 ns_interfacemgr_attach(mgr, &ifp->mgr);
425 LOCK(&mgr->lock);
426 ISC_LIST_APPEND(mgr->interfaces, ifp, link);
427 UNLOCK(&mgr->lock);
428
429 isc_refcount_init(&ifp->references, 1);
430 ifp->magic = IFACE_MAGIC;
431
432 result = ns_clientmgr_create(mgr->mctx, mgr->sctx, mgr->taskmgr,
433 mgr->timermgr, ifp, mgr->ncpus,
434 &ifp->clientmgr);
435 if (result != ISC_R_SUCCESS) {
436 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
437 "ns_clientmgr_create() failed: %s",
438 isc_result_totext(result));
439 goto failure;
440 }
441
442 *ifpret = ifp;
443
444 return (ISC_R_SUCCESS);
445
446 failure:
447 isc_mutex_destroy(&ifp->lock);
448
449 ifp->magic = 0;
450 isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
451
452 return (ISC_R_UNEXPECTED);
453 }
454
455 static isc_result_t
ns_interface_listenudp(ns_interface_t * ifp)456 ns_interface_listenudp(ns_interface_t *ifp) {
457 isc_result_t result;
458
459 /* Reserve space for an ns_client_t with the netmgr handle */
460 result = isc_nm_listenudp(ifp->mgr->nm, &ifp->addr, ns__client_request,
461 ifp, sizeof(ns_client_t),
462 &ifp->udplistensocket);
463 return (result);
464 }
465
466 static isc_result_t
ns_interface_listentcp(ns_interface_t * ifp)467 ns_interface_listentcp(ns_interface_t *ifp) {
468 isc_result_t result;
469
470 result = isc_nm_listentcpdns(
471 ifp->mgr->nm, &ifp->addr, ns__client_request, ifp,
472 ns__client_tcpconn, ifp, sizeof(ns_client_t), ifp->mgr->backlog,
473 &ifp->mgr->sctx->tcpquota, &ifp->tcplistensocket);
474 if (result != ISC_R_SUCCESS) {
475 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
476 "creating TCP socket: %s",
477 isc_result_totext(result));
478 }
479
480 /*
481 * We call this now to update the tcp-highwater statistic:
482 * this is necessary because we are adding to the TCP quota just
483 * by listening.
484 */
485 result = ns__client_tcpconn(NULL, ISC_R_SUCCESS, ifp);
486 if (result != ISC_R_SUCCESS) {
487 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
488 "connecting TCP socket: %s",
489 isc_result_totext(result));
490 }
491
492 #if 0
493 #ifndef ISC_ALLOW_MAPPED
494 isc_socket_ipv6only(ifp->tcpsocket,true);
495 #endif /* ifndef ISC_ALLOW_MAPPED */
496
497 if (ifp->dscp != -1) {
498 isc_socket_dscp(ifp->tcpsocket,ifp->dscp);
499 }
500
501 (void)isc_socket_filter(ifp->tcpsocket,"dataready");
502 #endif /* if 0 */
503 return (result);
504 }
505
506 static isc_result_t
ns_interface_setup(ns_interfacemgr_t * mgr,isc_sockaddr_t * addr,const char * name,ns_interface_t ** ifpret,isc_dscp_t dscp,bool * addr_in_use)507 ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
508 const char *name, ns_interface_t **ifpret, isc_dscp_t dscp,
509 bool *addr_in_use) {
510 isc_result_t result;
511 ns_interface_t *ifp = NULL;
512 REQUIRE(ifpret != NULL && *ifpret == NULL);
513 REQUIRE(addr_in_use == NULL || !*addr_in_use);
514
515 result = ns_interface_create(mgr, addr, name, &ifp);
516 if (result != ISC_R_SUCCESS) {
517 return (result);
518 }
519
520 ifp->dscp = dscp;
521
522 result = ns_interface_listenudp(ifp);
523 if (result != ISC_R_SUCCESS) {
524 if ((result == ISC_R_ADDRINUSE) && (addr_in_use != NULL)) {
525 *addr_in_use = true;
526 }
527 goto cleanup_interface;
528 }
529
530 if (((mgr->sctx->options & NS_SERVER_NOTCP) == 0)) {
531 result = ns_interface_listentcp(ifp);
532 if (result != ISC_R_SUCCESS) {
533 if ((result == ISC_R_ADDRINUSE) &&
534 (addr_in_use != NULL)) {
535 *addr_in_use = true;
536 }
537
538 /*
539 * XXXRTH We don't currently have a way to easily stop
540 * dispatch service, so we currently return
541 * ISC_R_SUCCESS (the UDP stuff will work even if TCP
542 * creation failed). This will be fixed later.
543 */
544 result = ISC_R_SUCCESS;
545 }
546 }
547 *ifpret = ifp;
548 return (result);
549
550 cleanup_interface:
551 LOCK(&ifp->mgr->lock);
552 ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
553 UNLOCK(&ifp->mgr->lock);
554 ns_interface_shutdown(ifp);
555 ns_interface_detach(&ifp);
556 return (result);
557 }
558
559 void
ns_interface_shutdown(ns_interface_t * ifp)560 ns_interface_shutdown(ns_interface_t *ifp) {
561 if (ifp->udplistensocket != NULL) {
562 isc_nm_stoplistening(ifp->udplistensocket);
563 isc_nmsocket_close(&ifp->udplistensocket);
564 }
565 if (ifp->tcplistensocket != NULL) {
566 isc_nm_stoplistening(ifp->tcplistensocket);
567 isc_nmsocket_close(&ifp->tcplistensocket);
568 }
569 if (ifp->clientmgr != NULL) {
570 ns_clientmgr_destroy(&ifp->clientmgr);
571 }
572 }
573
574 static void
ns_interface_destroy(ns_interface_t * ifp)575 ns_interface_destroy(ns_interface_t *ifp) {
576 REQUIRE(NS_INTERFACE_VALID(ifp));
577
578 isc_mem_t *mctx = ifp->mgr->mctx;
579
580 ns_interface_shutdown(ifp);
581
582 for (int disp = 0; disp < ifp->nudpdispatch; disp++) {
583 if (ifp->udpdispatch[disp] != NULL) {
584 dns_dispatch_changeattributes(
585 ifp->udpdispatch[disp], 0,
586 DNS_DISPATCHATTR_NOLISTEN);
587 dns_dispatch_detach(&(ifp->udpdispatch[disp]));
588 }
589 }
590
591 if (ifp->tcpsocket != NULL) {
592 isc_socket_detach(&ifp->tcpsocket);
593 }
594
595 isc_mutex_destroy(&ifp->lock);
596
597 ns_interfacemgr_detach(&ifp->mgr);
598
599 isc_refcount_destroy(&ifp->ntcpactive);
600 isc_refcount_destroy(&ifp->ntcpaccepting);
601
602 ifp->magic = 0;
603
604 isc_mem_put(mctx, ifp, sizeof(*ifp));
605 }
606
607 void
ns_interface_attach(ns_interface_t * source,ns_interface_t ** target)608 ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
609 REQUIRE(NS_INTERFACE_VALID(source));
610 isc_refcount_increment(&source->references);
611 *target = source;
612 }
613
614 void
ns_interface_detach(ns_interface_t ** targetp)615 ns_interface_detach(ns_interface_t **targetp) {
616 ns_interface_t *target = *targetp;
617 *targetp = NULL;
618 REQUIRE(target != NULL);
619 REQUIRE(NS_INTERFACE_VALID(target));
620 if (isc_refcount_decrement(&target->references) == 1) {
621 ns_interface_destroy(target);
622 }
623 }
624
625 /*%
626 * Search the interface list for an interface whose address and port
627 * both match those of 'addr'. Return a pointer to it, or NULL if not found.
628 */
629 static ns_interface_t *
find_matching_interface(ns_interfacemgr_t * mgr,isc_sockaddr_t * addr)630 find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
631 ns_interface_t *ifp;
632 LOCK(&mgr->lock);
633 for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
634 ifp = ISC_LIST_NEXT(ifp, link))
635 {
636 if (isc_sockaddr_equal(&ifp->addr, addr)) {
637 break;
638 }
639 }
640 UNLOCK(&mgr->lock);
641 return (ifp);
642 }
643
644 /*%
645 * Remove any interfaces whose generation number is not the current one.
646 */
647 static void
purge_old_interfaces(ns_interfacemgr_t * mgr)648 purge_old_interfaces(ns_interfacemgr_t *mgr) {
649 ns_interface_t *ifp, *next;
650 LOCK(&mgr->lock);
651 for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
652 INSIST(NS_INTERFACE_VALID(ifp));
653 next = ISC_LIST_NEXT(ifp, link);
654 if (ifp->generation != mgr->generation) {
655 char sabuf[256];
656 ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
657 isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
658 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO,
659 "no longer listening on %s", sabuf);
660 ns_interface_shutdown(ifp);
661 ns_interface_detach(&ifp);
662 }
663 }
664 UNLOCK(&mgr->lock);
665 }
666
667 static isc_result_t
clearacl(isc_mem_t * mctx,dns_acl_t ** aclp)668 clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
669 dns_acl_t *newacl = NULL;
670 isc_result_t result;
671 result = dns_acl_create(mctx, 0, &newacl);
672 if (result != ISC_R_SUCCESS) {
673 return (result);
674 }
675 dns_acl_detach(aclp);
676 dns_acl_attach(newacl, aclp);
677 dns_acl_detach(&newacl);
678 return (ISC_R_SUCCESS);
679 }
680
681 static bool
listenon_is_ip6_any(ns_listenelt_t * elt)682 listenon_is_ip6_any(ns_listenelt_t *elt) {
683 REQUIRE(elt && elt->acl);
684 return (dns_acl_isany(elt->acl));
685 }
686
687 static isc_result_t
setup_locals(ns_interfacemgr_t * mgr,isc_interface_t * interface)688 setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
689 isc_result_t result;
690 unsigned int prefixlen;
691 isc_netaddr_t *netaddr;
692
693 netaddr = &interface->address;
694
695 /* First add localhost address */
696 prefixlen = (netaddr->family == AF_INET) ? 32 : 128;
697 result = dns_iptable_addprefix(mgr->aclenv.localhost->iptable, netaddr,
698 prefixlen, true);
699 if (result != ISC_R_SUCCESS) {
700 return (result);
701 }
702
703 /* Then add localnets prefix */
704 result = isc_netaddr_masktoprefixlen(&interface->netmask, &prefixlen);
705
706 /* Non contiguous netmasks not allowed by IPv6 arch. */
707 if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6) {
708 return (result);
709 }
710
711 if (result != ISC_R_SUCCESS) {
712 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
713 "omitting IPv4 interface %s from "
714 "localnets ACL: %s",
715 interface->name, isc_result_totext(result));
716 return (ISC_R_SUCCESS);
717 }
718
719 if (prefixlen == 0U) {
720 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
721 "omitting %s interface %s from localnets ACL: "
722 "zero prefix length detected",
723 (netaddr->family == AF_INET) ? "IPv4" : "IPv6",
724 interface->name);
725 return (ISC_R_SUCCESS);
726 }
727
728 result = dns_iptable_addprefix(mgr->aclenv.localnets->iptable, netaddr,
729 prefixlen, true);
730 if (result != ISC_R_SUCCESS) {
731 return (result);
732 }
733
734 return (ISC_R_SUCCESS);
735 }
736
737 static void
setup_listenon(ns_interfacemgr_t * mgr,isc_interface_t * interface,in_port_t port)738 setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface,
739 in_port_t port) {
740 isc_sockaddr_t *addr;
741 isc_sockaddr_t *old;
742
743 addr = isc_mem_get(mgr->mctx, sizeof(*addr));
744
745 isc_sockaddr_fromnetaddr(addr, &interface->address, port);
746
747 LOCK(&mgr->lock);
748 for (old = ISC_LIST_HEAD(mgr->listenon); old != NULL;
749 old = ISC_LIST_NEXT(old, link))
750 {
751 if (isc_sockaddr_equal(addr, old)) {
752 break;
753 }
754 }
755
756 if (old != NULL) {
757 isc_mem_put(mgr->mctx, addr, sizeof(*addr));
758 } else {
759 ISC_LIST_APPEND(mgr->listenon, addr, link);
760 }
761 UNLOCK(&mgr->lock);
762 }
763
764 static void
clearlistenon(ns_interfacemgr_t * mgr)765 clearlistenon(ns_interfacemgr_t *mgr) {
766 isc_sockaddr_t *old;
767
768 LOCK(&mgr->lock);
769 old = ISC_LIST_HEAD(mgr->listenon);
770 while (old != NULL) {
771 ISC_LIST_UNLINK(mgr->listenon, old, link);
772 isc_mem_put(mgr->mctx, old, sizeof(*old));
773 old = ISC_LIST_HEAD(mgr->listenon);
774 }
775 UNLOCK(&mgr->lock);
776 }
777
778 static isc_result_t
do_scan(ns_interfacemgr_t * mgr,bool verbose)779 do_scan(ns_interfacemgr_t *mgr, bool verbose) {
780 isc_interfaceiter_t *iter = NULL;
781 bool scan_ipv4 = false;
782 bool scan_ipv6 = false;
783 bool ipv6only = true;
784 bool ipv6pktinfo = true;
785 isc_result_t result;
786 isc_netaddr_t zero_address, zero_address6;
787 ns_listenelt_t *le;
788 isc_sockaddr_t listen_addr;
789 ns_interface_t *ifp;
790 bool log_explicit = false;
791 bool dolistenon;
792 char sabuf[ISC_SOCKADDR_FORMATSIZE];
793 bool tried_listening;
794 bool all_addresses_in_use;
795
796 if (isc_net_probeipv6() == ISC_R_SUCCESS) {
797 scan_ipv6 = true;
798 } else if ((mgr->sctx->options & NS_SERVER_DISABLE6) == 0) {
799 isc_log_write(IFMGR_COMMON_LOGARGS,
800 verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
801 "no IPv6 interfaces found");
802 }
803
804 if (isc_net_probeipv4() == ISC_R_SUCCESS) {
805 scan_ipv4 = true;
806 } else if ((mgr->sctx->options & NS_SERVER_DISABLE4) == 0) {
807 isc_log_write(IFMGR_COMMON_LOGARGS,
808 verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
809 "no IPv4 interfaces found");
810 }
811
812 /*
813 * A special, but typical case; listen-on-v6 { any; }.
814 * When we can make the socket IPv6-only, open a single wildcard
815 * socket for IPv6 communication. Otherwise, make separate
816 * socket for each IPv6 address in order to avoid accepting IPv4
817 * packets as the form of mapped addresses unintentionally
818 * unless explicitly allowed.
819 */
820 #ifndef ISC_ALLOW_MAPPED
821 if (scan_ipv6 && isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
822 ipv6only = false;
823 log_explicit = true;
824 }
825 #endif /* ifndef ISC_ALLOW_MAPPED */
826 if (scan_ipv6 && isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
827 ipv6pktinfo = false;
828 log_explicit = true;
829 }
830 if (scan_ipv6 && ipv6only && ipv6pktinfo) {
831 for (le = ISC_LIST_HEAD(mgr->listenon6->elts); le != NULL;
832 le = ISC_LIST_NEXT(le, link))
833 {
834 struct in6_addr in6a;
835
836 if (!listenon_is_ip6_any(le)) {
837 continue;
838 }
839
840 in6a = in6addr_any;
841 isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
842
843 ifp = find_matching_interface(mgr, &listen_addr);
844 if (ifp != NULL) {
845 ifp->generation = mgr->generation;
846 if (le->dscp != -1 && ifp->dscp == -1) {
847 ifp->dscp = le->dscp;
848 } else if (le->dscp != ifp->dscp) {
849 isc_sockaddr_format(&listen_addr, sabuf,
850 sizeof(sabuf));
851 isc_log_write(IFMGR_COMMON_LOGARGS,
852 ISC_LOG_WARNING,
853 "%s: conflicting DSCP "
854 "values, using %d",
855 sabuf, ifp->dscp);
856 }
857 } else {
858 isc_log_write(IFMGR_COMMON_LOGARGS,
859 ISC_LOG_INFO,
860 "listening on IPv6 "
861 "interfaces, port %u",
862 le->port);
863 result = ns_interface_setup(mgr, &listen_addr,
864 "<any>", &ifp,
865 le->dscp, NULL);
866 if (result == ISC_R_SUCCESS) {
867 ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
868 } else {
869 isc_log_write(IFMGR_COMMON_LOGARGS,
870 ISC_LOG_ERROR,
871 "listening on all IPv6 "
872 "interfaces failed");
873 }
874 /* Continue. */
875 }
876 }
877 }
878
879 isc_netaddr_any(&zero_address);
880 isc_netaddr_any6(&zero_address6);
881
882 result = isc_interfaceiter_create(mgr->mctx, &iter);
883 if (result != ISC_R_SUCCESS) {
884 return (result);
885 }
886
887 result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
888 if (result != ISC_R_SUCCESS) {
889 goto cleanup_iter;
890 }
891 result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
892 if (result != ISC_R_SUCCESS) {
893 goto cleanup_iter;
894 }
895 clearlistenon(mgr);
896
897 tried_listening = false;
898 all_addresses_in_use = true;
899 for (result = isc_interfaceiter_first(iter); result == ISC_R_SUCCESS;
900 result = isc_interfaceiter_next(iter))
901 {
902 isc_interface_t interface;
903 ns_listenlist_t *ll;
904 unsigned int family;
905
906 result = isc_interfaceiter_current(iter, &interface);
907 if (result != ISC_R_SUCCESS) {
908 break;
909 }
910
911 family = interface.address.family;
912 if (family != AF_INET && family != AF_INET6) {
913 continue;
914 }
915 if (!scan_ipv4 && family == AF_INET) {
916 continue;
917 }
918 if (!scan_ipv6 && family == AF_INET6) {
919 continue;
920 }
921
922 /*
923 * Test for the address being nonzero rather than testing
924 * INTERFACE_F_UP, because on some systems the latter
925 * follows the media state and we could end up ignoring
926 * the interface for an entire rescan interval due to
927 * a temporary media glitch at rescan time.
928 */
929 if (family == AF_INET &&
930 isc_netaddr_equal(&interface.address, &zero_address)) {
931 continue;
932 }
933 if (family == AF_INET6 &&
934 isc_netaddr_equal(&interface.address, &zero_address6)) {
935 continue;
936 }
937
938 /*
939 * If running with -T fixedlocal, then we only
940 * want 127.0.0.1 and ::1 in the localhost ACL.
941 */
942 if (((mgr->sctx->options & NS_SERVER_FIXEDLOCAL) != 0) &&
943 !isc_netaddr_isloopback(&interface.address))
944 {
945 goto listenon;
946 }
947
948 result = setup_locals(mgr, &interface);
949 if (result != ISC_R_SUCCESS) {
950 goto ignore_interface;
951 }
952
953 listenon:
954 ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
955 dolistenon = true;
956 for (le = ISC_LIST_HEAD(ll->elts); le != NULL;
957 le = ISC_LIST_NEXT(le, link)) {
958 int match;
959 bool ipv6_wildcard = false;
960 isc_netaddr_t listen_netaddr;
961 isc_sockaddr_t listen_sockaddr;
962
963 /*
964 * Construct a socket address for this IP/port
965 * combination.
966 */
967 if (family == AF_INET) {
968 isc_netaddr_fromin(&listen_netaddr,
969 &interface.address.type.in);
970 } else {
971 isc_netaddr_fromin6(
972 &listen_netaddr,
973 &interface.address.type.in6);
974 isc_netaddr_setzone(&listen_netaddr,
975 interface.address.zone);
976 }
977 isc_sockaddr_fromnetaddr(&listen_sockaddr,
978 &listen_netaddr, le->port);
979
980 /*
981 * See if the address matches the listen-on statement;
982 * if not, ignore the interface.
983 */
984 (void)dns_acl_match(&listen_netaddr, NULL, le->acl,
985 &mgr->aclenv, &match, NULL);
986 if (match <= 0) {
987 continue;
988 }
989
990 if (dolistenon) {
991 setup_listenon(mgr, &interface, le->port);
992 dolistenon = false;
993 }
994
995 /*
996 * The case of "any" IPv6 address will require
997 * special considerations later, so remember it.
998 */
999 if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
1000 listenon_is_ip6_any(le)) {
1001 ipv6_wildcard = true;
1002 }
1003
1004 ifp = find_matching_interface(mgr, &listen_sockaddr);
1005 if (ifp != NULL) {
1006 ifp->generation = mgr->generation;
1007 if (le->dscp != -1 && ifp->dscp == -1) {
1008 ifp->dscp = le->dscp;
1009 } else if (le->dscp != ifp->dscp) {
1010 isc_sockaddr_format(&listen_sockaddr,
1011 sabuf,
1012 sizeof(sabuf));
1013 isc_log_write(IFMGR_COMMON_LOGARGS,
1014 ISC_LOG_WARNING,
1015 "%s: conflicting DSCP "
1016 "values, using %d",
1017 sabuf, ifp->dscp);
1018 }
1019 } else {
1020 bool addr_in_use = false;
1021
1022 if (ipv6_wildcard) {
1023 continue;
1024 }
1025
1026 if (log_explicit && family == AF_INET6 &&
1027 listenon_is_ip6_any(le)) {
1028 isc_log_write(
1029 IFMGR_COMMON_LOGARGS,
1030 verbose ? ISC_LOG_INFO
1031 : ISC_LOG_DEBUG(1),
1032 "IPv6 socket API is "
1033 "incomplete; explicitly "
1034 "binding to each IPv6 "
1035 "address separately");
1036 log_explicit = false;
1037 }
1038 isc_sockaddr_format(&listen_sockaddr, sabuf,
1039 sizeof(sabuf));
1040 isc_log_write(
1041 IFMGR_COMMON_LOGARGS, ISC_LOG_INFO,
1042 "listening on %s interface "
1043 "%s, %s",
1044 (family == AF_INET) ? "IPv4" : "IPv6",
1045 interface.name, sabuf);
1046
1047 result = ns_interface_setup(
1048 mgr, &listen_sockaddr, interface.name,
1049 &ifp, le->dscp, &addr_in_use);
1050
1051 tried_listening = true;
1052 if (!addr_in_use) {
1053 all_addresses_in_use = false;
1054 }
1055
1056 if (result != ISC_R_SUCCESS) {
1057 isc_log_write(IFMGR_COMMON_LOGARGS,
1058 ISC_LOG_ERROR,
1059 "creating %s interface "
1060 "%s failed; interface "
1061 "ignored",
1062 (family == AF_INET) ? "IP"
1063 "v4"
1064 : "IP"
1065 "v"
1066 "6",
1067 interface.name);
1068 }
1069 /* Continue. */
1070 }
1071 }
1072 continue;
1073
1074 ignore_interface:
1075 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
1076 "ignoring %s interface %s: %s",
1077 (family == AF_INET) ? "IPv4" : "IPv6",
1078 interface.name, isc_result_totext(result));
1079 continue;
1080 }
1081 if (result != ISC_R_NOMORE) {
1082 UNEXPECTED_ERROR(__FILE__, __LINE__,
1083 "interface iteration failed: %s",
1084 isc_result_totext(result));
1085 } else {
1086 result = ((tried_listening && all_addresses_in_use)
1087 ? ISC_R_ADDRINUSE
1088 : ISC_R_SUCCESS);
1089 }
1090 cleanup_iter:
1091 isc_interfaceiter_destroy(&iter);
1092 return (result);
1093 }
1094
1095 static isc_result_t
ns_interfacemgr_scan0(ns_interfacemgr_t * mgr,bool verbose)1096 ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, bool verbose) {
1097 isc_result_t result;
1098 bool purge = true;
1099
1100 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1101
1102 mgr->generation++; /* Increment the generation count. */
1103
1104 result = do_scan(mgr, verbose);
1105 if ((result != ISC_R_SUCCESS) && (result != ISC_R_ADDRINUSE)) {
1106 purge = false;
1107 }
1108
1109 /*
1110 * Now go through the interface list and delete anything that
1111 * does not have the current generation number. This is
1112 * how we catch interfaces that go away or change their
1113 * addresses.
1114 */
1115 if (purge) {
1116 purge_old_interfaces(mgr);
1117 }
1118
1119 /*
1120 * Warn if we are not listening on any interface.
1121 */
1122 if (ISC_LIST_EMPTY(mgr->interfaces)) {
1123 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
1124 "not listening on any interfaces");
1125 }
1126
1127 return (result);
1128 }
1129
1130 bool
ns_interfacemgr_islistening(ns_interfacemgr_t * mgr)1131 ns_interfacemgr_islistening(ns_interfacemgr_t *mgr) {
1132 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1133
1134 return (ISC_LIST_EMPTY(mgr->interfaces) ? false : true);
1135 }
1136
1137 isc_result_t
ns_interfacemgr_scan(ns_interfacemgr_t * mgr,bool verbose)1138 ns_interfacemgr_scan(ns_interfacemgr_t *mgr, bool verbose) {
1139 isc_result_t result;
1140 bool unlock = false;
1141
1142 /*
1143 * Check for success because we may already be task-exclusive
1144 * at this point. Only if we succeed at obtaining an exclusive
1145 * lock now will we need to relinquish it later.
1146 */
1147 result = isc_task_beginexclusive(mgr->excl);
1148 if (result == ISC_R_SUCCESS) {
1149 unlock = true;
1150 }
1151
1152 result = ns_interfacemgr_scan0(mgr, verbose);
1153
1154 if (unlock) {
1155 isc_task_endexclusive(mgr->excl);
1156 }
1157
1158 return (result);
1159 }
1160
1161 void
ns_interfacemgr_setlistenon4(ns_interfacemgr_t * mgr,ns_listenlist_t * value)1162 ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
1163 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1164
1165 LOCK(&mgr->lock);
1166 ns_listenlist_detach(&mgr->listenon4);
1167 ns_listenlist_attach(value, &mgr->listenon4);
1168 UNLOCK(&mgr->lock);
1169 }
1170
1171 void
ns_interfacemgr_setlistenon6(ns_interfacemgr_t * mgr,ns_listenlist_t * value)1172 ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
1173 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1174
1175 LOCK(&mgr->lock);
1176 ns_listenlist_detach(&mgr->listenon6);
1177 ns_listenlist_attach(value, &mgr->listenon6);
1178 UNLOCK(&mgr->lock);
1179 }
1180
1181 void
ns_interfacemgr_dumprecursing(FILE * f,ns_interfacemgr_t * mgr)1182 ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) {
1183 ns_interface_t *interface;
1184
1185 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1186
1187 LOCK(&mgr->lock);
1188 interface = ISC_LIST_HEAD(mgr->interfaces);
1189 while (interface != NULL) {
1190 if (interface->clientmgr != NULL) {
1191 ns_client_dumprecursing(f, interface->clientmgr);
1192 }
1193 interface = ISC_LIST_NEXT(interface, link);
1194 }
1195 UNLOCK(&mgr->lock);
1196 }
1197
1198 bool
ns_interfacemgr_listeningon(ns_interfacemgr_t * mgr,const isc_sockaddr_t * addr)1199 ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr,
1200 const isc_sockaddr_t *addr) {
1201 isc_sockaddr_t *old;
1202 bool result = false;
1203
1204 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1205 /*
1206 * If the manager is shutting down it's safer to
1207 * return true.
1208 */
1209 if (atomic_load(&mgr->shuttingdown)) {
1210 return (true);
1211 }
1212 LOCK(&mgr->lock);
1213 for (old = ISC_LIST_HEAD(mgr->listenon); old != NULL;
1214 old = ISC_LIST_NEXT(old, link))
1215 {
1216 if (isc_sockaddr_equal(old, addr)) {
1217 result = true;
1218 break;
1219 }
1220 }
1221 UNLOCK(&mgr->lock);
1222
1223 return (result);
1224 }
1225
1226 ns_server_t *
ns_interfacemgr_getserver(ns_interfacemgr_t * mgr)1227 ns_interfacemgr_getserver(ns_interfacemgr_t *mgr) {
1228 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1229
1230 return (mgr->sctx);
1231 }
1232
1233 ns_interface_t *
ns__interfacemgr_getif(ns_interfacemgr_t * mgr)1234 ns__interfacemgr_getif(ns_interfacemgr_t *mgr) {
1235 ns_interface_t *head;
1236 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1237 LOCK(&mgr->lock);
1238 head = ISC_LIST_HEAD(mgr->interfaces);
1239 UNLOCK(&mgr->lock);
1240 return (head);
1241 }
1242
1243 ns_interface_t *
ns__interfacemgr_nextif(ns_interface_t * ifp)1244 ns__interfacemgr_nextif(ns_interface_t *ifp) {
1245 ns_interface_t *next;
1246 LOCK(&ifp->lock);
1247 next = ISC_LIST_NEXT(ifp, link);
1248 UNLOCK(&ifp->lock);
1249 return (next);
1250 }
1251