Remove building with NOCRYPTO option
[minix.git] / external / bsd / bind / dist / bin / named / interfacemgr.c
blobba19b3a8612df3ead1a2e4099ac0b1e713cf42e6
1 /* $NetBSD: interfacemgr.c,v 1.10 2015/07/08 17:28:55 christos Exp $ */
3 /*
4 * Copyright (C) 2004-2009, 2011-2015 Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (C) 1999-2002 Internet Software Consortium.
7 * Permission to use, copy, modify, and/or distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
12 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
13 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
14 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
16 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17 * PERFORMANCE OF THIS SOFTWARE.
20 /* Id: interfacemgr.c,v 1.101 2011/11/09 18:44:03 each Exp */
22 /*! \file */
24 #include <config.h>
26 #include <isc/interfaceiter.h>
27 #include <isc/os.h>
28 #include <isc/string.h>
29 #include <isc/task.h>
30 #include <isc/util.h>
32 #include <dns/acl.h>
33 #include <dns/dispatch.h>
35 #include <named/client.h>
36 #include <named/log.h>
37 #include <named/interfacemgr.h>
38 #include <named/server.h>
40 #ifdef HAVE_NET_ROUTE_H
41 #include <net/route.h>
42 #if defined(RTM_VERSION) && defined(RTM_NEWADDR) && defined(RTM_DELADDR)
43 #define USE_ROUTE_SOCKET 1
44 #define ROUTE_SOCKET_PROTOCOL PF_ROUTE
45 #define MSGHDR rt_msghdr
46 #define MSGTYPE rtm_type
47 #endif
48 #endif
50 #if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
51 #include <linux/netlink.h>
52 #include <linux/rtnetlink.h>
53 #if defined(RTM_NEWADDR) && defined(RTM_DELADDR)
54 #define USE_ROUTE_SOCKET 1
55 #define ROUTE_SOCKET_PROTOCOL PF_NETLINK
56 #define MSGHDR nlmsghdr
57 #define MSGTYPE nlmsg_type
58 #endif
59 #endif
61 #ifdef TUNE_LARGE
62 #define UDPBUFFERS 32768
63 #else
64 #define UDPBUFFERS 1000
65 #endif /* TUNE_LARGE */
67 #define IFMGR_MAGIC ISC_MAGIC('I', 'F', 'M', 'G')
68 #define NS_INTERFACEMGR_VALID(t) ISC_MAGIC_VALID(t, IFMGR_MAGIC)
70 #define IFMGR_COMMON_LOGARGS \
71 ns_g_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR
73 /*% nameserver interface manager structure */
74 struct ns_interfacemgr {
75 unsigned int magic; /*%< Magic number. */
76 int references;
77 isc_mutex_t lock;
78 isc_mem_t * mctx; /*%< Memory context. */
79 isc_taskmgr_t * taskmgr; /*%< Task manager. */
80 isc_socketmgr_t * socketmgr; /*%< Socket manager. */
81 dns_dispatchmgr_t * dispatchmgr;
82 unsigned int generation; /*%< Current generation no. */
83 ns_listenlist_t * listenon4;
84 ns_listenlist_t * listenon6;
85 dns_aclenv_t aclenv; /*%< Localhost/localnets ACLs */
86 ISC_LIST(ns_interface_t) interfaces; /*%< List of interfaces. */
87 ISC_LIST(isc_sockaddr_t) listenon;
88 #ifdef USE_ROUTE_SOCKET
89 isc_task_t * task;
90 isc_socket_t * route;
91 unsigned char buf[2048];
92 #endif
95 static void
96 purge_old_interfaces(ns_interfacemgr_t *mgr);
98 static void
99 clearlistenon(ns_interfacemgr_t *mgr);
101 #ifdef USE_ROUTE_SOCKET
102 static void
103 route_event(isc_task_t *task, isc_event_t *event) {
104 isc_socketevent_t *sevent = NULL;
105 ns_interfacemgr_t *mgr = NULL;
106 isc_region_t r;
107 isc_result_t result;
108 struct MSGHDR *rtm;
109 isc_boolean_t done = ISC_TRUE;
111 UNUSED(task);
113 REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
114 mgr = event->ev_arg;
115 sevent = (isc_socketevent_t *)event;
117 if (sevent->result != ISC_R_SUCCESS) {
118 if (sevent->result != ISC_R_CANCELED)
119 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
120 "automatic interface scanning "
121 "terminated: %s",
122 isc_result_totext(sevent->result));
123 ns_interfacemgr_detach(&mgr);
124 isc_event_free(&event);
125 return;
128 rtm = (struct MSGHDR *)mgr->buf;
129 #ifdef RTM_VERSION
130 if (rtm->rtm_version != RTM_VERSION) {
131 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
132 "automatic interface rescanning disabled: "
133 "rtm->rtm_version mismatch (%u != %u) "
134 "recompile required", rtm->rtm_version,
135 RTM_VERSION);
136 ns_interfacemgr_detach(&mgr);
137 isc_event_free(&event);
138 return;
140 #endif
142 switch (rtm->MSGTYPE) {
143 case RTM_NEWADDR:
144 case RTM_DELADDR:
145 if (mgr->route != NULL && ns_g_server->interface_auto)
146 ns_server_scan_interfaces(ns_g_server);
147 break;
148 default:
149 break;
152 LOCK(&mgr->lock);
153 if (mgr->route != NULL) {
155 * Look for next route event.
157 r.base = mgr->buf;
158 r.length = sizeof(mgr->buf);
159 result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
160 route_event, mgr);
161 if (result == ISC_R_SUCCESS)
162 done = ISC_FALSE;
164 UNLOCK(&mgr->lock);
166 if (done)
167 ns_interfacemgr_detach(&mgr);
168 isc_event_free(&event);
169 return;
171 #endif
173 isc_result_t
174 ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
175 isc_socketmgr_t *socketmgr,
176 dns_dispatchmgr_t *dispatchmgr,
177 isc_task_t *task, ns_interfacemgr_t **mgrp)
179 isc_result_t result;
180 ns_interfacemgr_t *mgr;
182 #ifndef USE_ROUTE_SOCKET
183 UNUSED(task);
184 #endif
186 REQUIRE(mctx != NULL);
187 REQUIRE(mgrp != NULL);
188 REQUIRE(*mgrp == NULL);
190 mgr = isc_mem_get(mctx, sizeof(*mgr));
191 if (mgr == NULL)
192 return (ISC_R_NOMEMORY);
194 mgr->mctx = NULL;
195 isc_mem_attach(mctx, &mgr->mctx);
197 result = isc_mutex_init(&mgr->lock);
198 if (result != ISC_R_SUCCESS)
199 goto cleanup_mem;
201 mgr->taskmgr = taskmgr;
202 mgr->socketmgr = socketmgr;
203 mgr->dispatchmgr = dispatchmgr;
204 mgr->generation = 1;
205 mgr->listenon4 = NULL;
206 mgr->listenon6 = NULL;
208 ISC_LIST_INIT(mgr->interfaces);
209 ISC_LIST_INIT(mgr->listenon);
212 * The listen-on lists are initially empty.
214 result = ns_listenlist_create(mctx, &mgr->listenon4);
215 if (result != ISC_R_SUCCESS)
216 goto cleanup_mem;
217 ns_listenlist_attach(mgr->listenon4, &mgr->listenon6);
219 result = dns_aclenv_init(mctx, &mgr->aclenv);
220 if (result != ISC_R_SUCCESS)
221 goto cleanup_listenon;
222 #ifdef HAVE_GEOIP
223 mgr->aclenv.geoip = ns_g_geoip;
224 #endif
226 #ifdef USE_ROUTE_SOCKET
227 mgr->route = NULL;
228 result = isc_socket_create(mgr->socketmgr, ROUTE_SOCKET_PROTOCOL,
229 isc_sockettype_raw, &mgr->route);
230 switch (result) {
231 case ISC_R_NOPERM:
232 case ISC_R_SUCCESS:
233 case ISC_R_NOTIMPLEMENTED:
234 case ISC_R_FAMILYNOSUPPORT:
235 break;
236 default:
237 goto cleanup_aclenv;
240 mgr->task = NULL;
241 if (mgr->route != NULL)
242 isc_task_attach(task, &mgr->task);
243 mgr->references = (mgr->route != NULL) ? 2 : 1;
244 #else
245 mgr->references = 1;
246 #endif
247 mgr->magic = IFMGR_MAGIC;
248 *mgrp = mgr;
250 #ifdef USE_ROUTE_SOCKET
251 if (mgr->route != NULL) {
252 isc_region_t r = { mgr->buf, sizeof(mgr->buf) };
254 result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
255 route_event, mgr);
256 if (result != ISC_R_SUCCESS) {
257 isc_task_detach(&mgr->task);
258 isc_socket_detach(&mgr->route);
259 ns_interfacemgr_detach(&mgr);
262 #endif
263 return (ISC_R_SUCCESS);
265 #ifdef USE_ROUTE_SOCKET
266 cleanup_aclenv:
267 dns_aclenv_destroy(&mgr->aclenv);
268 #endif
269 cleanup_listenon:
270 ns_listenlist_detach(&mgr->listenon4);
271 ns_listenlist_detach(&mgr->listenon6);
272 cleanup_mem:
273 isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
274 return (result);
277 static void
278 ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
279 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
281 #ifdef USE_ROUTE_SOCKET
282 if (mgr->route != NULL)
283 isc_socket_detach(&mgr->route);
284 if (mgr->task != NULL)
285 isc_task_detach(&mgr->task);
286 #endif
287 dns_aclenv_destroy(&mgr->aclenv);
288 ns_listenlist_detach(&mgr->listenon4);
289 ns_listenlist_detach(&mgr->listenon6);
290 clearlistenon(mgr);
291 DESTROYLOCK(&mgr->lock);
292 mgr->magic = 0;
293 isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
296 dns_aclenv_t *
297 ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) {
298 return (&mgr->aclenv);
301 void
302 ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) {
303 REQUIRE(NS_INTERFACEMGR_VALID(source));
304 LOCK(&source->lock);
305 INSIST(source->references > 0);
306 source->references++;
307 UNLOCK(&source->lock);
308 *target = source;
311 void
312 ns_interfacemgr_detach(ns_interfacemgr_t **targetp) {
313 isc_result_t need_destroy = ISC_FALSE;
314 ns_interfacemgr_t *target = *targetp;
315 REQUIRE(target != NULL);
316 REQUIRE(NS_INTERFACEMGR_VALID(target));
317 LOCK(&target->lock);
318 REQUIRE(target->references > 0);
319 target->references--;
320 if (target->references == 0)
321 need_destroy = ISC_TRUE;
322 UNLOCK(&target->lock);
323 if (need_destroy)
324 ns_interfacemgr_destroy(target);
325 *targetp = NULL;
328 void
329 ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
330 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
333 * Shut down and detach all interfaces.
334 * By incrementing the generation count, we make purge_old_interfaces()
335 * consider all interfaces "old".
337 mgr->generation++;
338 #ifdef USE_ROUTE_SOCKET
339 LOCK(&mgr->lock);
340 if (mgr->route != NULL) {
341 isc_socket_cancel(mgr->route, mgr->task, ISC_SOCKCANCEL_RECV);
342 isc_socket_detach(&mgr->route);
343 isc_task_detach(&mgr->task);
345 UNLOCK(&mgr->lock);
346 #endif
347 purge_old_interfaces(mgr);
351 static isc_result_t
352 ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
353 const char *name, ns_interface_t **ifpret)
355 ns_interface_t *ifp;
356 isc_result_t result;
357 int disp;
359 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
361 ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
362 if (ifp == NULL)
363 return (ISC_R_NOMEMORY);
365 ifp->mgr = NULL;
366 ifp->generation = mgr->generation;
367 ifp->addr = *addr;
368 ifp->flags = 0;
369 strncpy(ifp->name, name, sizeof(ifp->name));
370 ifp->name[sizeof(ifp->name)-1] = '\0';
371 ifp->clientmgr = NULL;
373 result = isc_mutex_init(&ifp->lock);
374 if (result != ISC_R_SUCCESS)
375 goto lock_create_failure;
377 result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,
378 ns_g_timermgr,
379 &ifp->clientmgr);
380 if (result != ISC_R_SUCCESS) {
381 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
382 "ns_clientmgr_create() failed: %s",
383 isc_result_totext(result));
384 goto clientmgr_create_failure;
387 for (disp = 0; disp < MAX_UDP_DISPATCH; disp++)
388 ifp->udpdispatch[disp] = NULL;
390 ifp->tcpsocket = NULL;
393 * Create a single TCP client object. It will replace itself
394 * with a new one as soon as it gets a connection, so the actual
395 * connections will be handled in parallel even though there is
396 * only one client initially.
398 ifp->ntcptarget = 1;
399 ifp->ntcpcurrent = 0;
400 ifp->nudpdispatch = 0;
402 ifp->dscp = -1;
404 ISC_LINK_INIT(ifp, link);
406 ns_interfacemgr_attach(mgr, &ifp->mgr);
407 ISC_LIST_APPEND(mgr->interfaces, ifp, link);
409 ifp->references = 1;
410 ifp->magic = IFACE_MAGIC;
411 *ifpret = ifp;
413 return (ISC_R_SUCCESS);
415 clientmgr_create_failure:
416 DESTROYLOCK(&ifp->lock);
418 lock_create_failure:
419 ifp->magic = 0;
420 isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
422 return (ISC_R_UNEXPECTED);
425 static isc_result_t
426 ns_interface_listenudp(ns_interface_t *ifp) {
427 isc_result_t result;
428 unsigned int attrs;
429 unsigned int attrmask;
430 int disp, i;
432 attrs = 0;
433 attrs |= DNS_DISPATCHATTR_UDP;
434 if (isc_sockaddr_pf(&ifp->addr) == AF_INET)
435 attrs |= DNS_DISPATCHATTR_IPV4;
436 else
437 attrs |= DNS_DISPATCHATTR_IPV6;
438 attrs |= DNS_DISPATCHATTR_NOLISTEN;
439 attrmask = 0;
440 attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
441 attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
443 ifp->nudpdispatch = ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH);
444 for (disp = 0; disp < ifp->nudpdispatch; disp++) {
445 result = dns_dispatch_getudp_dup(ifp->mgr->dispatchmgr,
446 ns_g_socketmgr,
447 ns_g_taskmgr, &ifp->addr,
448 4096, UDPBUFFERS,
449 32768, 8219, 8237,
450 attrs, attrmask,
451 &ifp->udpdispatch[disp],
452 disp == 0
453 ? NULL
454 : ifp->udpdispatch[0]);
455 if (result != ISC_R_SUCCESS) {
456 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
457 "could not listen on UDP socket: %s",
458 isc_result_totext(result));
459 goto udp_dispatch_failure;
464 result = ns_clientmgr_createclients(ifp->clientmgr, ifp->nudpdispatch,
465 ifp, ISC_FALSE);
466 if (result != ISC_R_SUCCESS) {
467 UNEXPECTED_ERROR(__FILE__, __LINE__,
468 "UDP ns_clientmgr_createclients(): %s",
469 isc_result_totext(result));
470 goto addtodispatch_failure;
473 return (ISC_R_SUCCESS);
475 addtodispatch_failure:
476 for (i = disp - 1; i <= 0; i--) {
477 dns_dispatch_changeattributes(ifp->udpdispatch[i], 0,
478 DNS_DISPATCHATTR_NOLISTEN);
479 dns_dispatch_detach(&(ifp->udpdispatch[i]));
481 ifp->nudpdispatch = 0;
483 udp_dispatch_failure:
484 return (result);
487 static isc_result_t
488 ns_interface_accepttcp(ns_interface_t *ifp) {
489 isc_result_t result;
492 * Open a TCP socket.
494 result = isc_socket_create(ifp->mgr->socketmgr,
495 isc_sockaddr_pf(&ifp->addr),
496 isc_sockettype_tcp,
497 &ifp->tcpsocket);
498 if (result != ISC_R_SUCCESS) {
499 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
500 "creating TCP socket: %s",
501 isc_result_totext(result));
502 goto tcp_socket_failure;
504 isc_socket_setname(ifp->tcpsocket, "dispatcher", NULL);
505 #ifndef ISC_ALLOW_MAPPED
506 isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE);
507 #endif
508 result = isc_socket_bind(ifp->tcpsocket, &ifp->addr,
509 ISC_SOCKET_REUSEADDRESS);
510 if (result != ISC_R_SUCCESS) {
511 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
512 "binding TCP socket: %s",
513 isc_result_totext(result));
514 goto tcp_bind_failure;
517 if (ifp->dscp != -1)
518 isc_socket_dscp(ifp->tcpsocket, ifp->dscp);
520 result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
521 if (result != ISC_R_SUCCESS) {
522 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
523 "listening on TCP socket: %s",
524 isc_result_totext(result));
525 goto tcp_listen_failure;
529 * If/when there a multiple filters listen to the
530 * result.
532 (void)isc_socket_filter(ifp->tcpsocket, "dataready");
534 result = ns_clientmgr_createclients(ifp->clientmgr,
535 ifp->ntcptarget, ifp,
536 ISC_TRUE);
537 if (result != ISC_R_SUCCESS) {
538 UNEXPECTED_ERROR(__FILE__, __LINE__,
539 "TCP ns_clientmgr_createclients(): %s",
540 isc_result_totext(result));
541 goto accepttcp_failure;
543 return (ISC_R_SUCCESS);
545 accepttcp_failure:
546 tcp_listen_failure:
547 tcp_bind_failure:
548 isc_socket_detach(&ifp->tcpsocket);
549 tcp_socket_failure:
550 return (ISC_R_SUCCESS);
553 static isc_result_t
554 ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
555 const char *name, ns_interface_t **ifpret,
556 isc_boolean_t accept_tcp, isc_dscp_t dscp)
558 isc_result_t result;
559 ns_interface_t *ifp = NULL;
560 REQUIRE(ifpret != NULL && *ifpret == NULL);
562 result = ns_interface_create(mgr, addr, name, &ifp);
563 if (result != ISC_R_SUCCESS)
564 return (result);
566 ifp->dscp = dscp;
568 result = ns_interface_listenudp(ifp);
569 if (result != ISC_R_SUCCESS)
570 goto cleanup_interface;
572 if (!ns_g_notcp && accept_tcp == ISC_TRUE) {
573 result = ns_interface_accepttcp(ifp);
574 if (result != ISC_R_SUCCESS) {
576 * XXXRTH We don't currently have a way to easily stop
577 * dispatch service, so we currently return
578 * ISC_R_SUCCESS (the UDP stuff will work even if TCP
579 * creation failed). This will be fixed later.
581 result = ISC_R_SUCCESS;
584 *ifpret = ifp;
585 return (result);
587 cleanup_interface:
588 ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
589 ns_interface_detach(&ifp);
590 return (result);
593 void
594 ns_interface_shutdown(ns_interface_t *ifp) {
595 if (ifp->clientmgr != NULL)
596 ns_clientmgr_destroy(&ifp->clientmgr);
599 static void
600 ns_interface_destroy(ns_interface_t *ifp) {
601 isc_mem_t *mctx = ifp->mgr->mctx;
602 int disp;
604 REQUIRE(NS_INTERFACE_VALID(ifp));
606 ns_interface_shutdown(ifp);
608 for (disp = 0; disp < ifp->nudpdispatch; disp++)
609 if (ifp->udpdispatch[disp] != NULL) {
610 dns_dispatch_changeattributes(ifp->udpdispatch[disp], 0,
611 DNS_DISPATCHATTR_NOLISTEN);
612 dns_dispatch_detach(&(ifp->udpdispatch[disp]));
615 if (ifp->tcpsocket != NULL)
616 isc_socket_detach(&ifp->tcpsocket);
618 DESTROYLOCK(&ifp->lock);
620 ns_interfacemgr_detach(&ifp->mgr);
622 ifp->magic = 0;
623 isc_mem_put(mctx, ifp, sizeof(*ifp));
626 void
627 ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
628 REQUIRE(NS_INTERFACE_VALID(source));
629 LOCK(&source->lock);
630 INSIST(source->references > 0);
631 source->references++;
632 UNLOCK(&source->lock);
633 *target = source;
636 void
637 ns_interface_detach(ns_interface_t **targetp) {
638 isc_result_t need_destroy = ISC_FALSE;
639 ns_interface_t *target = *targetp;
640 REQUIRE(target != NULL);
641 REQUIRE(NS_INTERFACE_VALID(target));
642 LOCK(&target->lock);
643 REQUIRE(target->references > 0);
644 target->references--;
645 if (target->references == 0)
646 need_destroy = ISC_TRUE;
647 UNLOCK(&target->lock);
648 if (need_destroy)
649 ns_interface_destroy(target);
650 *targetp = NULL;
654 * Search the interface list for an interface whose address and port
655 * both match those of 'addr'. Return a pointer to it, or NULL if not found.
657 static ns_interface_t *
658 find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
659 ns_interface_t *ifp;
660 for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
661 ifp = ISC_LIST_NEXT(ifp, link)) {
662 if (isc_sockaddr_equal(&ifp->addr, addr))
663 break;
665 return (ifp);
669 * Remove any interfaces whose generation number is not the current one.
671 static void
672 purge_old_interfaces(ns_interfacemgr_t *mgr) {
673 ns_interface_t *ifp, *next;
674 for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
675 INSIST(NS_INTERFACE_VALID(ifp));
676 next = ISC_LIST_NEXT(ifp, link);
677 if (ifp->generation != mgr->generation) {
678 char sabuf[256];
679 ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
680 isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
681 isc_log_write(IFMGR_COMMON_LOGARGS,
682 ISC_LOG_INFO,
683 "no longer listening on %s", sabuf);
684 ns_interface_shutdown(ifp);
685 ns_interface_detach(&ifp);
690 static isc_result_t
691 clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
692 dns_acl_t *newacl = NULL;
693 isc_result_t result;
694 result = dns_acl_create(mctx, 0, &newacl);
695 if (result != ISC_R_SUCCESS)
696 return (result);
697 dns_acl_detach(aclp);
698 dns_acl_attach(newacl, aclp);
699 dns_acl_detach(&newacl);
700 return (ISC_R_SUCCESS);
703 static isc_boolean_t
704 listenon_is_ip6_any(ns_listenelt_t *elt) {
705 REQUIRE(elt && elt->acl);
706 return dns_acl_isany(elt->acl);
709 static isc_result_t
710 setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
711 isc_result_t result;
712 unsigned int prefixlen;
713 isc_netaddr_t *netaddr;
715 netaddr = &interface->address;
717 /* First add localhost address */
718 prefixlen = (netaddr->family == AF_INET) ? 32 : 128;
719 result = dns_iptable_addprefix(mgr->aclenv.localhost->iptable,
720 netaddr, prefixlen, ISC_TRUE);
721 if (result != ISC_R_SUCCESS)
722 return (result);
724 /* Then add localnets prefix */
725 result = isc_netaddr_masktoprefixlen(&interface->netmask,
726 &prefixlen);
728 /* Non contiguous netmasks not allowed by IPv6 arch. */
729 if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6)
730 return (result);
732 if (result != ISC_R_SUCCESS) {
733 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
734 "omitting IPv4 interface %s from "
735 "localnets ACL: %s", interface->name,
736 isc_result_totext(result));
737 return (ISC_R_SUCCESS);
740 if (prefixlen == 0U) {
741 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
742 "omitting %s interface %s from localnets ACL: "
743 "zero prefix length detected",
744 (netaddr->family == AF_INET) ? "IPv4" : "IPv6",
745 interface->name);
746 return (ISC_R_SUCCESS);
749 result = dns_iptable_addprefix(mgr->aclenv.localnets->iptable,
750 netaddr, prefixlen, ISC_TRUE);
751 if (result != ISC_R_SUCCESS)
752 return (result);
754 return (ISC_R_SUCCESS);
757 static void
758 setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface,
759 in_port_t port)
761 isc_sockaddr_t *addr;
762 isc_sockaddr_t *old;
764 addr = isc_mem_get(mgr->mctx, sizeof(*addr));
765 if (addr == NULL)
766 return;
768 isc_sockaddr_fromnetaddr(addr, &interface->address, port);
770 for (old = ISC_LIST_HEAD(mgr->listenon);
771 old != NULL;
772 old = ISC_LIST_NEXT(old, link))
773 if (isc_sockaddr_equal(addr, old))
774 break;
776 if (old != NULL)
777 isc_mem_put(mgr->mctx, addr, sizeof(*addr));
778 else
779 ISC_LIST_APPEND(mgr->listenon, addr, link);
782 static void
783 clearlistenon(ns_interfacemgr_t *mgr) {
784 isc_sockaddr_t *old;
786 old = ISC_LIST_HEAD(mgr->listenon);
787 while (old != NULL) {
788 ISC_LIST_UNLINK(mgr->listenon, old, link);
789 isc_mem_put(mgr->mctx, old, sizeof(*old));
790 old = ISC_LIST_HEAD(mgr->listenon);
794 static isc_result_t
795 do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
796 isc_boolean_t verbose)
798 isc_interfaceiter_t *iter = NULL;
799 isc_boolean_t scan_ipv4 = ISC_FALSE;
800 isc_boolean_t scan_ipv6 = ISC_FALSE;
801 isc_boolean_t adjusting = ISC_FALSE;
802 isc_boolean_t ipv6only = ISC_TRUE;
803 isc_boolean_t ipv6pktinfo = ISC_TRUE;
804 isc_result_t result;
805 isc_netaddr_t zero_address, zero_address6;
806 ns_listenelt_t *le;
807 isc_sockaddr_t listen_addr;
808 ns_interface_t *ifp;
809 isc_boolean_t log_explicit = ISC_FALSE;
810 isc_boolean_t dolistenon;
811 char sabuf[ISC_SOCKADDR_FORMATSIZE];
813 if (ext_listen != NULL)
814 adjusting = ISC_TRUE;
816 if (isc_net_probeipv6() == ISC_R_SUCCESS)
817 scan_ipv6 = ISC_TRUE;
818 #ifdef WANT_IPV6
819 else if (!ns_g_disable6)
820 isc_log_write(IFMGR_COMMON_LOGARGS,
821 verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
822 "no IPv6 interfaces found");
823 #endif
825 if (isc_net_probeipv4() == ISC_R_SUCCESS)
826 scan_ipv4 = ISC_TRUE;
827 else if (!ns_g_disable4)
828 isc_log_write(IFMGR_COMMON_LOGARGS,
829 verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
830 "no IPv4 interfaces found");
833 * A special, but typical case; listen-on-v6 { any; }.
834 * When we can make the socket IPv6-only, open a single wildcard
835 * socket for IPv6 communication. Otherwise, make separate socket
836 * for each IPv6 address in order to avoid accepting IPv4 packets
837 * as the form of mapped addresses unintentionally unless explicitly
838 * allowed.
840 #ifndef ISC_ALLOW_MAPPED
841 if (scan_ipv6 == ISC_TRUE &&
842 isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
843 ipv6only = ISC_FALSE;
844 log_explicit = ISC_TRUE;
846 #endif
847 if (scan_ipv6 == ISC_TRUE &&
848 isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
849 ipv6pktinfo = ISC_FALSE;
850 log_explicit = ISC_TRUE;
852 if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) {
853 for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
854 le != NULL;
855 le = ISC_LIST_NEXT(le, link)) {
856 struct in6_addr in6a;
858 if (!listenon_is_ip6_any(le))
859 continue;
861 in6a = in6addr_any;
862 isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
864 ifp = find_matching_interface(mgr, &listen_addr);
865 if (ifp != NULL) {
866 ifp->generation = mgr->generation;
867 if (le->dscp != -1 && ifp->dscp == -1)
868 ifp->dscp = le->dscp;
869 else if (le->dscp != ifp->dscp) {
870 isc_sockaddr_format(&listen_addr,
871 sabuf,
872 sizeof(sabuf));
873 isc_log_write(IFMGR_COMMON_LOGARGS,
874 ISC_LOG_WARNING,
875 "%s: conflicting DSCP "
876 "values, using %d",
877 sabuf, ifp->dscp);
879 } else {
880 isc_log_write(IFMGR_COMMON_LOGARGS,
881 ISC_LOG_INFO,
882 "listening on IPv6 "
883 "interfaces, port %u",
884 le->port);
885 result = ns_interface_setup(mgr, &listen_addr,
886 "<any>", &ifp,
887 ISC_TRUE,
888 le->dscp);
889 if (result == ISC_R_SUCCESS)
890 ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
891 else
892 isc_log_write(IFMGR_COMMON_LOGARGS,
893 ISC_LOG_ERROR,
894 "listening on all IPv6 "
895 "interfaces failed");
896 /* Continue. */
901 isc_netaddr_any(&zero_address);
902 isc_netaddr_any6(&zero_address6);
904 result = isc_interfaceiter_create(mgr->mctx, &iter);
905 if (result != ISC_R_SUCCESS)
906 return (result);
908 if (adjusting == ISC_FALSE) {
909 result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
910 if (result != ISC_R_SUCCESS)
911 goto cleanup_iter;
912 result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
913 if (result != ISC_R_SUCCESS)
914 goto cleanup_iter;
915 clearlistenon(mgr);
918 for (result = isc_interfaceiter_first(iter);
919 result == ISC_R_SUCCESS;
920 result = isc_interfaceiter_next(iter))
922 isc_interface_t interface;
923 ns_listenlist_t *ll;
924 unsigned int family;
926 result = isc_interfaceiter_current(iter, &interface);
927 if (result != ISC_R_SUCCESS)
928 break;
930 family = interface.address.family;
931 if (family != AF_INET && family != AF_INET6)
932 continue;
933 if (scan_ipv4 == ISC_FALSE && family == AF_INET)
934 continue;
935 if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
936 continue;
939 * Test for the address being nonzero rather than testing
940 * INTERFACE_F_UP, because on some systems the latter
941 * follows the media state and we could end up ignoring
942 * the interface for an entire rescan interval due to
943 * a temporary media glitch at rescan time.
945 if (family == AF_INET &&
946 isc_netaddr_equal(&interface.address, &zero_address)) {
947 continue;
949 if (family == AF_INET6 &&
950 isc_netaddr_equal(&interface.address, &zero_address6)) {
951 continue;
954 if (adjusting == ISC_FALSE) {
955 result = setup_locals(mgr, &interface);
956 if (result != ISC_R_SUCCESS)
957 goto ignore_interface;
960 ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
961 dolistenon = ISC_TRUE;
962 for (le = ISC_LIST_HEAD(ll->elts);
963 le != NULL;
964 le = ISC_LIST_NEXT(le, link))
966 int match;
967 isc_boolean_t ipv6_wildcard = ISC_FALSE;
968 isc_netaddr_t listen_netaddr;
969 isc_sockaddr_t listen_sockaddr;
972 * Construct a socket address for this IP/port
973 * combination.
975 if (family == AF_INET) {
976 isc_netaddr_fromin(&listen_netaddr,
977 &interface.address.type.in);
978 } else {
979 isc_netaddr_fromin6(&listen_netaddr,
980 &interface.address.type.in6);
981 isc_netaddr_setzone(&listen_netaddr,
982 interface.address.zone);
984 isc_sockaddr_fromnetaddr(&listen_sockaddr,
985 &listen_netaddr,
986 le->port);
989 * See if the address matches the listen-on statement;
990 * if not, ignore the interface.
992 (void)dns_acl_match(&listen_netaddr, NULL, le->acl,
993 &mgr->aclenv, &match, NULL);
994 if (match <= 0)
995 continue;
997 if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) {
998 setup_listenon(mgr, &interface, le->port);
999 dolistenon = ISC_FALSE;
1003 * The case of "any" IPv6 address will require
1004 * special considerations later, so remember it.
1006 if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
1007 listenon_is_ip6_any(le))
1008 ipv6_wildcard = ISC_TRUE;
1011 * When adjusting interfaces with extra a listening
1012 * list, see if the address matches the extra list.
1013 * If it does, and is also covered by a wildcard
1014 * interface, we need to listen on the address
1015 * explicitly.
1017 if (adjusting == ISC_TRUE) {
1018 ns_listenelt_t *ele;
1020 match = 0;
1021 for (ele = ISC_LIST_HEAD(ext_listen->elts);
1022 ele != NULL;
1023 ele = ISC_LIST_NEXT(ele, link)) {
1024 (void)dns_acl_match(&listen_netaddr,
1025 NULL, ele->acl,
1026 NULL, &match, NULL);
1027 if (match > 0 &&
1028 (ele->port == le->port ||
1029 ele->port == 0))
1030 break;
1031 else
1032 match = 0;
1034 if (ipv6_wildcard == ISC_TRUE && match == 0)
1035 continue;
1038 ifp = find_matching_interface(mgr, &listen_sockaddr);
1039 if (ifp != NULL) {
1040 ifp->generation = mgr->generation;
1041 if (le->dscp != -1 && ifp->dscp == -1)
1042 ifp->dscp = le->dscp;
1043 else if (le->dscp != ifp->dscp) {
1044 isc_sockaddr_format(&listen_sockaddr,
1045 sabuf,
1046 sizeof(sabuf));
1047 isc_log_write(IFMGR_COMMON_LOGARGS,
1048 ISC_LOG_WARNING,
1049 "%s: conflicting DSCP "
1050 "values, using %d",
1051 sabuf, ifp->dscp);
1053 } else {
1054 if (adjusting == ISC_FALSE &&
1055 ipv6_wildcard == ISC_TRUE)
1056 continue;
1058 if (log_explicit && family == AF_INET6 &&
1059 !adjusting && listenon_is_ip6_any(le)) {
1060 isc_log_write(IFMGR_COMMON_LOGARGS,
1061 verbose ? ISC_LOG_INFO :
1062 ISC_LOG_DEBUG(1),
1063 "IPv6 socket API is "
1064 "incomplete; explicitly "
1065 "binding to each IPv6 "
1066 "address separately");
1067 log_explicit = ISC_FALSE;
1069 isc_sockaddr_format(&listen_sockaddr,
1070 sabuf, sizeof(sabuf));
1071 isc_log_write(IFMGR_COMMON_LOGARGS,
1072 ISC_LOG_INFO,
1073 "%s"
1074 "listening on %s interface "
1075 "%s, %s",
1076 (adjusting == ISC_TRUE) ?
1077 "additionally " : "",
1078 (family == AF_INET) ?
1079 "IPv4" : "IPv6",
1080 interface.name, sabuf);
1082 result = ns_interface_setup(mgr,
1083 &listen_sockaddr,
1084 interface.name,
1085 &ifp,
1086 (adjusting == ISC_TRUE) ?
1087 ISC_FALSE : ISC_TRUE,
1088 le->dscp);
1090 if (result != ISC_R_SUCCESS) {
1091 isc_log_write(IFMGR_COMMON_LOGARGS,
1092 ISC_LOG_ERROR,
1093 "creating %s interface "
1094 "%s failed; interface "
1095 "ignored",
1096 (family == AF_INET) ?
1097 "IPv4" : "IPv6",
1098 interface.name);
1100 /* Continue. */
1104 continue;
1106 ignore_interface:
1107 isc_log_write(IFMGR_COMMON_LOGARGS,
1108 ISC_LOG_ERROR,
1109 "ignoring %s interface %s: %s",
1110 (family == AF_INET) ? "IPv4" : "IPv6",
1111 interface.name, isc_result_totext(result));
1112 continue;
1114 if (result != ISC_R_NOMORE)
1115 UNEXPECTED_ERROR(__FILE__, __LINE__,
1116 "interface iteration failed: %s",
1117 isc_result_totext(result));
1118 else
1119 result = ISC_R_SUCCESS;
1120 cleanup_iter:
1121 isc_interfaceiter_destroy(&iter);
1122 return (result);
1125 static void
1126 ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
1127 isc_boolean_t verbose)
1129 isc_boolean_t purge = ISC_TRUE;
1131 REQUIRE(NS_INTERFACEMGR_VALID(mgr));
1133 mgr->generation++; /* Increment the generation count. */
1135 if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS)
1136 purge = ISC_FALSE;
1139 * Now go through the interface list and delete anything that
1140 * does not have the current generation number. This is
1141 * how we catch interfaces that go away or change their
1142 * addresses.
1144 if (purge)
1145 purge_old_interfaces(mgr);
1148 * Warn if we are not listening on any interface, unless
1149 * we're in lwresd-only mode, in which case that is to
1150 * be expected.
1152 if (ext_listen == NULL &&
1153 ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) {
1154 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
1155 "not listening on any interfaces");
1159 void
1160 ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
1161 ns_interfacemgr_scan0(mgr, NULL, verbose);
1164 void
1165 ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
1166 isc_boolean_t verbose)
1168 ns_interfacemgr_scan0(mgr, list, verbose);
1171 void
1172 ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
1173 LOCK(&mgr->lock);
1174 ns_listenlist_detach(&mgr->listenon4);
1175 ns_listenlist_attach(value, &mgr->listenon4);
1176 UNLOCK(&mgr->lock);
1179 void
1180 ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
1181 LOCK(&mgr->lock);
1182 ns_listenlist_detach(&mgr->listenon6);
1183 ns_listenlist_attach(value, &mgr->listenon6);
1184 UNLOCK(&mgr->lock);
1187 void
1188 ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) {
1189 ns_interface_t *interface;
1191 LOCK(&mgr->lock);
1192 interface = ISC_LIST_HEAD(mgr->interfaces);
1193 while (interface != NULL) {
1194 if (interface->clientmgr != NULL)
1195 ns_client_dumprecursing(f, interface->clientmgr);
1196 interface = ISC_LIST_NEXT(interface, link);
1198 UNLOCK(&mgr->lock);
1201 isc_boolean_t
1202 ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
1203 isc_sockaddr_t *old;
1205 for (old = ISC_LIST_HEAD(mgr->listenon);
1206 old != NULL;
1207 old = ISC_LIST_NEXT(old, link))
1208 if (isc_sockaddr_equal(old, addr))
1209 return (ISC_TRUE);
1210 return (ISC_FALSE);