]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/bind9/bin/named/interfacemgr.c
Update BIND to 9.9.8
[FreeBSD/stable/9.git] / contrib / bind9 / bin / named / interfacemgr.c
1 /*
2  * Copyright (C) 2004-2009, 2011-2015  Internet Systems Consortium, Inc. ("ISC")
3  * Copyright (C) 1999-2002  Internet Software Consortium.
4  *
5  * Permission to use, copy, modify, and/or distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
10  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
11  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
12  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
14  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15  * PERFORMANCE OF THIS SOFTWARE.
16  */
17
18 /* $Id: interfacemgr.c,v 1.101 2011/11/09 18:44:03 each Exp $ */
19
20 /*! \file */
21
22 #include <config.h>
23
24 #include <isc/interfaceiter.h>
25 #include <isc/os.h>
26 #include <isc/string.h>
27 #include <isc/task.h>
28 #include <isc/util.h>
29
30 #include <dns/acl.h>
31 #include <dns/dispatch.h>
32
33 #include <named/client.h>
34 #include <named/log.h>
35 #include <named/interfacemgr.h>
36
37 #define IFMGR_MAGIC                     ISC_MAGIC('I', 'F', 'M', 'G')
38 #define NS_INTERFACEMGR_VALID(t)        ISC_MAGIC_VALID(t, IFMGR_MAGIC)
39
40 #define IFMGR_COMMON_LOGARGS \
41         ns_g_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR
42
43 /*% nameserver interface manager structure */
44 struct ns_interfacemgr {
45         unsigned int            magic;          /*%< Magic number. */
46         int                     references;
47         isc_mutex_t             lock;
48         isc_mem_t *             mctx;           /*%< Memory context. */
49         isc_taskmgr_t *         taskmgr;        /*%< Task manager. */
50         isc_socketmgr_t *       socketmgr;      /*%< Socket manager. */
51         dns_dispatchmgr_t *     dispatchmgr;
52         unsigned int            generation;     /*%< Current generation no. */
53         ns_listenlist_t *       listenon4;
54         ns_listenlist_t *       listenon6;
55         dns_aclenv_t            aclenv;         /*%< Localhost/localnets ACLs */
56         ISC_LIST(ns_interface_t) interfaces;    /*%< List of interfaces. */
57         ISC_LIST(isc_sockaddr_t) listenon;
58 };
59
60 static void
61 purge_old_interfaces(ns_interfacemgr_t *mgr);
62
63 static void
64 clearlistenon(ns_interfacemgr_t *mgr);
65
66 isc_result_t
67 ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
68                        isc_socketmgr_t *socketmgr,
69                        dns_dispatchmgr_t *dispatchmgr,
70                        ns_interfacemgr_t **mgrp)
71 {
72         isc_result_t result;
73         ns_interfacemgr_t *mgr;
74
75         REQUIRE(mctx != NULL);
76         REQUIRE(mgrp != NULL);
77         REQUIRE(*mgrp == NULL);
78
79         mgr = isc_mem_get(mctx, sizeof(*mgr));
80         if (mgr == NULL)
81                 return (ISC_R_NOMEMORY);
82
83         mgr->mctx = NULL;
84         isc_mem_attach(mctx, &mgr->mctx);
85
86         result = isc_mutex_init(&mgr->lock);
87         if (result != ISC_R_SUCCESS)
88                 goto cleanup_mem;
89
90         mgr->taskmgr = taskmgr;
91         mgr->socketmgr = socketmgr;
92         mgr->dispatchmgr = dispatchmgr;
93         mgr->generation = 1;
94         mgr->listenon4 = NULL;
95         mgr->listenon6 = NULL;
96
97         ISC_LIST_INIT(mgr->interfaces);
98         ISC_LIST_INIT(mgr->listenon);
99
100         /*
101          * The listen-on lists are initially empty.
102          */
103         result = ns_listenlist_create(mctx, &mgr->listenon4);
104         if (result != ISC_R_SUCCESS)
105                 goto cleanup_mem;
106         ns_listenlist_attach(mgr->listenon4, &mgr->listenon6);
107
108         result = dns_aclenv_init(mctx, &mgr->aclenv);
109         if (result != ISC_R_SUCCESS)
110                 goto cleanup_listenon;
111
112         mgr->references = 1;
113         mgr->magic = IFMGR_MAGIC;
114         *mgrp = mgr;
115         return (ISC_R_SUCCESS);
116
117  cleanup_listenon:
118         ns_listenlist_detach(&mgr->listenon4);
119         ns_listenlist_detach(&mgr->listenon6);
120  cleanup_mem:
121         isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
122         return (result);
123 }
124
125 static void
126 ns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
127         REQUIRE(NS_INTERFACEMGR_VALID(mgr));
128         dns_aclenv_destroy(&mgr->aclenv);
129         ns_listenlist_detach(&mgr->listenon4);
130         ns_listenlist_detach(&mgr->listenon6);
131         clearlistenon(mgr);
132         DESTROYLOCK(&mgr->lock);
133         mgr->magic = 0;
134         isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
135 }
136
137 dns_aclenv_t *
138 ns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) {
139         return (&mgr->aclenv);
140 }
141
142 void
143 ns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) {
144         REQUIRE(NS_INTERFACEMGR_VALID(source));
145         LOCK(&source->lock);
146         INSIST(source->references > 0);
147         source->references++;
148         UNLOCK(&source->lock);
149         *target = source;
150 }
151
152 void
153 ns_interfacemgr_detach(ns_interfacemgr_t **targetp) {
154         isc_result_t need_destroy = ISC_FALSE;
155         ns_interfacemgr_t *target = *targetp;
156         REQUIRE(target != NULL);
157         REQUIRE(NS_INTERFACEMGR_VALID(target));
158         LOCK(&target->lock);
159         REQUIRE(target->references > 0);
160         target->references--;
161         if (target->references == 0)
162                 need_destroy = ISC_TRUE;
163         UNLOCK(&target->lock);
164         if (need_destroy)
165                 ns_interfacemgr_destroy(target);
166         *targetp = NULL;
167 }
168
169 void
170 ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
171         REQUIRE(NS_INTERFACEMGR_VALID(mgr));
172
173         /*%
174          * Shut down and detach all interfaces.
175          * By incrementing the generation count, we make purge_old_interfaces()
176          * consider all interfaces "old".
177          */
178         mgr->generation++;
179         purge_old_interfaces(mgr);
180 }
181
182
183 static isc_result_t
184 ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
185                     const char *name, ns_interface_t **ifpret)
186 {
187         ns_interface_t *ifp;
188         isc_result_t result;
189         int disp;
190
191         REQUIRE(NS_INTERFACEMGR_VALID(mgr));
192
193         ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
194         if (ifp == NULL)
195                 return (ISC_R_NOMEMORY);
196
197         ifp->mgr = NULL;
198         ifp->generation = mgr->generation;
199         ifp->addr = *addr;
200         ifp->flags = 0;
201         strncpy(ifp->name, name, sizeof(ifp->name));
202         ifp->name[sizeof(ifp->name)-1] = '\0';
203         ifp->clientmgr = NULL;
204
205         result = isc_mutex_init(&ifp->lock);
206         if (result != ISC_R_SUCCESS)
207                 goto lock_create_failure;
208
209         result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,
210                                      ns_g_timermgr,
211                                      &ifp->clientmgr);
212         if (result != ISC_R_SUCCESS) {
213                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
214                               "ns_clientmgr_create() failed: %s",
215                               isc_result_totext(result));
216                 goto clientmgr_create_failure;
217         }
218
219         for (disp = 0; disp < MAX_UDP_DISPATCH; disp++)
220                 ifp->udpdispatch[disp] = NULL;
221
222         ifp->tcpsocket = NULL;
223
224         /*
225          * Create a single TCP client object.  It will replace itself
226          * with a new one as soon as it gets a connection, so the actual
227          * connections will be handled in parallel even though there is
228          * only one client initially.
229          */
230         ifp->ntcptarget = 1;
231         ifp->ntcpcurrent = 0;
232         ifp->nudpdispatch = 0;
233
234         ISC_LINK_INIT(ifp, link);
235
236         ns_interfacemgr_attach(mgr, &ifp->mgr);
237         ISC_LIST_APPEND(mgr->interfaces, ifp, link);
238
239         ifp->references = 1;
240         ifp->magic = IFACE_MAGIC;
241         *ifpret = ifp;
242
243         return (ISC_R_SUCCESS);
244
245  clientmgr_create_failure:
246         DESTROYLOCK(&ifp->lock);
247
248  lock_create_failure:
249         ifp->magic = 0;
250         isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
251
252         return (ISC_R_UNEXPECTED);
253 }
254
255 static isc_result_t
256 ns_interface_listenudp(ns_interface_t *ifp) {
257         isc_result_t result;
258         unsigned int attrs;
259         unsigned int attrmask;
260         int disp, i;
261
262         attrs = 0;
263         attrs |= DNS_DISPATCHATTR_UDP;
264         if (isc_sockaddr_pf(&ifp->addr) == AF_INET)
265                 attrs |= DNS_DISPATCHATTR_IPV4;
266         else
267                 attrs |= DNS_DISPATCHATTR_IPV6;
268         attrs |= DNS_DISPATCHATTR_NOLISTEN;
269         attrmask = 0;
270         attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
271         attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
272
273         ifp->nudpdispatch = ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH);
274         for (disp = 0; disp < ifp->nudpdispatch; disp++) {
275                 result = dns_dispatch_getudp_dup(ifp->mgr->dispatchmgr,
276                                                  ns_g_socketmgr,
277                                                  ns_g_taskmgr, &ifp->addr,
278                                                  4096, 1000, 32768, 8219, 8237,
279                                                  attrs, attrmask,
280                                                  &ifp->udpdispatch[disp],
281                                                  disp == 0
282                                                     ? NULL
283                                                     : ifp->udpdispatch[0]);
284                 if (result != ISC_R_SUCCESS) {
285                         isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
286                                       "could not listen on UDP socket: %s",
287                                       isc_result_totext(result));
288                         goto udp_dispatch_failure;
289                 }
290
291         }
292
293         result = ns_clientmgr_createclients(ifp->clientmgr, ifp->nudpdispatch,
294                                             ifp, ISC_FALSE);
295         if (result != ISC_R_SUCCESS) {
296                 UNEXPECTED_ERROR(__FILE__, __LINE__,
297                                  "UDP ns_clientmgr_createclients(): %s",
298                                  isc_result_totext(result));
299                 goto addtodispatch_failure;
300         }
301
302         return (ISC_R_SUCCESS);
303
304  addtodispatch_failure:
305         for (i = disp - 1; i >= 0; i--) {
306                 dns_dispatch_changeattributes(ifp->udpdispatch[i], 0,
307                                               DNS_DISPATCHATTR_NOLISTEN);
308                 dns_dispatch_detach(&(ifp->udpdispatch[i]));
309         }
310         ifp->nudpdispatch = 0;
311
312  udp_dispatch_failure:
313         return (result);
314 }
315
316 static isc_result_t
317 ns_interface_accepttcp(ns_interface_t *ifp) {
318         isc_result_t result;
319
320         /*
321          * Open a TCP socket.
322          */
323         result = isc_socket_create(ifp->mgr->socketmgr,
324                                    isc_sockaddr_pf(&ifp->addr),
325                                    isc_sockettype_tcp,
326                                    &ifp->tcpsocket);
327         if (result != ISC_R_SUCCESS) {
328                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
329                                  "creating TCP socket: %s",
330                                  isc_result_totext(result));
331                 goto tcp_socket_failure;
332         }
333         isc_socket_setname(ifp->tcpsocket, "dispatcher", NULL);
334 #ifndef ISC_ALLOW_MAPPED
335         isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE);
336 #endif
337         result = isc_socket_bind(ifp->tcpsocket, &ifp->addr,
338                                  ISC_SOCKET_REUSEADDRESS);
339         if (result != ISC_R_SUCCESS) {
340                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
341                                  "binding TCP socket: %s",
342                                  isc_result_totext(result));
343                 goto tcp_bind_failure;
344         }
345         result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
346         if (result != ISC_R_SUCCESS) {
347                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
348                                  "listening on TCP socket: %s",
349                                  isc_result_totext(result));
350                 goto tcp_listen_failure;
351         }
352
353         /*
354          * If/when there a multiple filters listen to the
355          * result.
356          */
357         (void)isc_socket_filter(ifp->tcpsocket, "dataready");
358
359         result = ns_clientmgr_createclients(ifp->clientmgr,
360                                             ifp->ntcptarget, ifp,
361                                             ISC_TRUE);
362         if (result != ISC_R_SUCCESS) {
363                 UNEXPECTED_ERROR(__FILE__, __LINE__,
364                                  "TCP ns_clientmgr_createclients(): %s",
365                                  isc_result_totext(result));
366                 goto accepttcp_failure;
367         }
368         return (ISC_R_SUCCESS);
369
370  accepttcp_failure:
371  tcp_listen_failure:
372  tcp_bind_failure:
373         isc_socket_detach(&ifp->tcpsocket);
374  tcp_socket_failure:
375         return (ISC_R_SUCCESS);
376 }
377
378 static isc_result_t
379 ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
380                    const char *name, ns_interface_t **ifpret,
381                    isc_boolean_t accept_tcp)
382 {
383         isc_result_t result;
384         ns_interface_t *ifp = NULL;
385         REQUIRE(ifpret != NULL && *ifpret == NULL);
386
387         result = ns_interface_create(mgr, addr, name, &ifp);
388         if (result != ISC_R_SUCCESS)
389                 return (result);
390
391         result = ns_interface_listenudp(ifp);
392         if (result != ISC_R_SUCCESS)
393                 goto cleanup_interface;
394
395         if (!ns_g_notcp && accept_tcp == ISC_TRUE) {
396                 result = ns_interface_accepttcp(ifp);
397                 if (result != ISC_R_SUCCESS) {
398                         /*
399                          * XXXRTH We don't currently have a way to easily stop
400                          * dispatch service, so we currently return
401                          * ISC_R_SUCCESS (the UDP stuff will work even if TCP
402                          * creation failed).  This will be fixed later.
403                          */
404                         result = ISC_R_SUCCESS;
405                 }
406         }
407         *ifpret = ifp;
408         return (result);
409
410  cleanup_interface:
411         ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
412         ns_interface_detach(&ifp);
413         return (result);
414 }
415
416 void
417 ns_interface_shutdown(ns_interface_t *ifp) {
418         if (ifp->clientmgr != NULL)
419                 ns_clientmgr_destroy(&ifp->clientmgr);
420 }
421
422 static void
423 ns_interface_destroy(ns_interface_t *ifp) {
424         isc_mem_t *mctx = ifp->mgr->mctx;
425         int disp;
426
427         REQUIRE(NS_INTERFACE_VALID(ifp));
428
429         ns_interface_shutdown(ifp);
430
431         for (disp = 0; disp < ifp->nudpdispatch; disp++)
432                 if (ifp->udpdispatch[disp] != NULL) {
433                         dns_dispatch_changeattributes(ifp->udpdispatch[disp], 0,
434                                                     DNS_DISPATCHATTR_NOLISTEN);
435                         dns_dispatch_detach(&(ifp->udpdispatch[disp]));
436                 }
437
438         if (ifp->tcpsocket != NULL)
439                 isc_socket_detach(&ifp->tcpsocket);
440
441         DESTROYLOCK(&ifp->lock);
442
443         ns_interfacemgr_detach(&ifp->mgr);
444
445         ifp->magic = 0;
446         isc_mem_put(mctx, ifp, sizeof(*ifp));
447 }
448
449 void
450 ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
451         REQUIRE(NS_INTERFACE_VALID(source));
452         LOCK(&source->lock);
453         INSIST(source->references > 0);
454         source->references++;
455         UNLOCK(&source->lock);
456         *target = source;
457 }
458
459 void
460 ns_interface_detach(ns_interface_t **targetp) {
461         isc_result_t need_destroy = ISC_FALSE;
462         ns_interface_t *target = *targetp;
463         REQUIRE(target != NULL);
464         REQUIRE(NS_INTERFACE_VALID(target));
465         LOCK(&target->lock);
466         REQUIRE(target->references > 0);
467         target->references--;
468         if (target->references == 0)
469                 need_destroy = ISC_TRUE;
470         UNLOCK(&target->lock);
471         if (need_destroy)
472                 ns_interface_destroy(target);
473         *targetp = NULL;
474 }
475
476 /*%
477  * Search the interface list for an interface whose address and port
478  * both match those of 'addr'.  Return a pointer to it, or NULL if not found.
479  */
480 static ns_interface_t *
481 find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
482         ns_interface_t *ifp;
483         for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
484              ifp = ISC_LIST_NEXT(ifp, link)) {
485                 if (isc_sockaddr_equal(&ifp->addr, addr))
486                         break;
487         }
488         return (ifp);
489 }
490
491 /*%
492  * Remove any interfaces whose generation number is not the current one.
493  */
494 static void
495 purge_old_interfaces(ns_interfacemgr_t *mgr) {
496         ns_interface_t *ifp, *next;
497         for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
498                 INSIST(NS_INTERFACE_VALID(ifp));
499                 next = ISC_LIST_NEXT(ifp, link);
500                 if (ifp->generation != mgr->generation) {
501                         char sabuf[256];
502                         ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
503                         isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
504                         isc_log_write(IFMGR_COMMON_LOGARGS,
505                                       ISC_LOG_INFO,
506                                       "no longer listening on %s", sabuf);
507                         ns_interface_shutdown(ifp);
508                         ns_interface_detach(&ifp);
509                 }
510         }
511 }
512
513 static isc_result_t
514 clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
515         dns_acl_t *newacl = NULL;
516         isc_result_t result;
517         result = dns_acl_create(mctx, 0, &newacl);
518         if (result != ISC_R_SUCCESS)
519                 return (result);
520         dns_acl_detach(aclp);
521         dns_acl_attach(newacl, aclp);
522         dns_acl_detach(&newacl);
523         return (ISC_R_SUCCESS);
524 }
525
526 static isc_boolean_t
527 listenon_is_ip6_any(ns_listenelt_t *elt) {
528         REQUIRE(elt && elt->acl);
529         return dns_acl_isany(elt->acl);
530 }
531
532 static isc_result_t
533 setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
534         isc_result_t result;
535         unsigned int prefixlen;
536         isc_netaddr_t *netaddr;
537
538         netaddr = &interface->address;
539
540         /* First add localhost address */
541         prefixlen = (netaddr->family == AF_INET) ? 32 : 128;
542         result = dns_iptable_addprefix(mgr->aclenv.localhost->iptable,
543                                        netaddr, prefixlen, ISC_TRUE);
544         if (result != ISC_R_SUCCESS)
545                 return (result);
546
547         /* Then add localnets prefix */
548         result = isc_netaddr_masktoprefixlen(&interface->netmask,
549                                              &prefixlen);
550
551         /* Non contiguous netmasks not allowed by IPv6 arch. */
552         if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6)
553                 return (result);
554
555         if (result != ISC_R_SUCCESS) {
556                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
557                               "omitting IPv4 interface %s from "
558                               "localnets ACL: %s", interface->name,
559                               isc_result_totext(result));
560                 return (ISC_R_SUCCESS);
561         }
562
563         if (prefixlen == 0U) {
564                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
565                               "omitting %s interface %s from localnets ACL: "
566                               "zero prefix length detected",
567                               (netaddr->family == AF_INET) ? "IPv4" : "IPv6",
568                               interface->name);
569                 return (ISC_R_SUCCESS);
570         }
571
572         result = dns_iptable_addprefix(mgr->aclenv.localnets->iptable,
573                                        netaddr, prefixlen, ISC_TRUE);
574         if (result != ISC_R_SUCCESS)
575                 return (result);
576
577         return (ISC_R_SUCCESS);
578 }
579
580 static void
581 setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface,
582                in_port_t port)
583 {
584         isc_sockaddr_t *addr;
585         isc_sockaddr_t *old;
586
587         addr = isc_mem_get(mgr->mctx, sizeof(*addr));
588         if (addr == NULL)
589                 return;
590
591         isc_sockaddr_fromnetaddr(addr, &interface->address, port);
592
593         for (old = ISC_LIST_HEAD(mgr->listenon);
594              old != NULL;
595              old = ISC_LIST_NEXT(old, link))
596                 if (isc_sockaddr_equal(addr, old))
597                         break;
598
599         if (old != NULL)
600                 isc_mem_put(mgr->mctx, addr, sizeof(*addr));
601         else
602                 ISC_LIST_APPEND(mgr->listenon, addr, link);
603 }
604
605 static void
606 clearlistenon(ns_interfacemgr_t *mgr) {
607         isc_sockaddr_t *old;
608
609         old = ISC_LIST_HEAD(mgr->listenon);
610         while (old != NULL) {
611                 ISC_LIST_UNLINK(mgr->listenon, old, link);
612                 isc_mem_put(mgr->mctx, old, sizeof(*old));
613                 old = ISC_LIST_HEAD(mgr->listenon);
614         }
615 }
616
617 static isc_result_t
618 do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
619         isc_boolean_t verbose)
620 {
621         isc_interfaceiter_t *iter = NULL;
622         isc_boolean_t scan_ipv4 = ISC_FALSE;
623         isc_boolean_t scan_ipv6 = ISC_FALSE;
624         isc_boolean_t adjusting = ISC_FALSE;
625         isc_boolean_t ipv6only = ISC_TRUE;
626         isc_boolean_t ipv6pktinfo = ISC_TRUE;
627         isc_result_t result;
628         isc_netaddr_t zero_address, zero_address6;
629         ns_listenelt_t *le;
630         isc_sockaddr_t listen_addr;
631         ns_interface_t *ifp;
632         isc_boolean_t log_explicit = ISC_FALSE;
633         isc_boolean_t dolistenon;
634
635         if (ext_listen != NULL)
636                 adjusting = ISC_TRUE;
637
638         if (isc_net_probeipv6() == ISC_R_SUCCESS)
639                 scan_ipv6 = ISC_TRUE;
640 #ifdef WANT_IPV6
641         else if (!ns_g_disable6)
642                 isc_log_write(IFMGR_COMMON_LOGARGS,
643                               verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
644                               "no IPv6 interfaces found");
645 #endif
646
647         if (isc_net_probeipv4() == ISC_R_SUCCESS)
648                 scan_ipv4 = ISC_TRUE;
649         else if (!ns_g_disable4)
650                 isc_log_write(IFMGR_COMMON_LOGARGS,
651                               verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
652                               "no IPv4 interfaces found");
653
654         /*
655          * A special, but typical case; listen-on-v6 { any; }.
656          * When we can make the socket IPv6-only, open a single wildcard
657          * socket for IPv6 communication.  Otherwise, make separate socket
658          * for each IPv6 address in order to avoid accepting IPv4 packets
659          * as the form of mapped addresses unintentionally unless explicitly
660          * allowed.
661          */
662 #ifndef ISC_ALLOW_MAPPED
663         if (scan_ipv6 == ISC_TRUE &&
664             isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
665                 ipv6only = ISC_FALSE;
666                 log_explicit = ISC_TRUE;
667         }
668 #endif
669         if (scan_ipv6 == ISC_TRUE &&
670             isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
671                 ipv6pktinfo = ISC_FALSE;
672                 log_explicit = ISC_TRUE;
673         }
674         if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) {
675                 for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
676                      le != NULL;
677                      le = ISC_LIST_NEXT(le, link)) {
678                         struct in6_addr in6a;
679
680                         if (!listenon_is_ip6_any(le))
681                                 continue;
682
683                         in6a = in6addr_any;
684                         isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
685
686                         ifp = find_matching_interface(mgr, &listen_addr);
687                         if (ifp != NULL) {
688                                 ifp->generation = mgr->generation;
689                         } else {
690                                 isc_log_write(IFMGR_COMMON_LOGARGS,
691                                               ISC_LOG_INFO,
692                                               "listening on IPv6 "
693                                               "interfaces, port %u",
694                                               le->port);
695                                 result = ns_interface_setup(mgr, &listen_addr,
696                                                             "<any>", &ifp,
697                                                             ISC_TRUE);
698                                 if (result == ISC_R_SUCCESS)
699                                         ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
700                                 else
701                                         isc_log_write(IFMGR_COMMON_LOGARGS,
702                                                       ISC_LOG_ERROR,
703                                                       "listening on all IPv6 "
704                                                       "interfaces failed");
705                                 /* Continue. */
706                         }
707                 }
708         }
709
710         isc_netaddr_any(&zero_address);
711         isc_netaddr_any6(&zero_address6);
712
713         result = isc_interfaceiter_create(mgr->mctx, &iter);
714         if (result != ISC_R_SUCCESS)
715                 return (result);
716
717         if (adjusting == ISC_FALSE) {
718                 result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
719                 if (result != ISC_R_SUCCESS)
720                         goto cleanup_iter;
721                 result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
722                 if (result != ISC_R_SUCCESS)
723                         goto cleanup_iter;
724                 clearlistenon(mgr);
725         }
726
727         for (result = isc_interfaceiter_first(iter);
728              result == ISC_R_SUCCESS;
729              result = isc_interfaceiter_next(iter))
730         {
731                 isc_interface_t interface;
732                 ns_listenlist_t *ll;
733                 unsigned int family;
734
735                 result = isc_interfaceiter_current(iter, &interface);
736                 if (result != ISC_R_SUCCESS)
737                         break;
738
739                 family = interface.address.family;
740                 if (family != AF_INET && family != AF_INET6)
741                         continue;
742                 if (scan_ipv4 == ISC_FALSE && family == AF_INET)
743                         continue;
744                 if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
745                         continue;
746
747                 /*
748                  * Test for the address being nonzero rather than testing
749                  * INTERFACE_F_UP, because on some systems the latter
750                  * follows the media state and we could end up ignoring
751                  * the interface for an entire rescan interval due to
752                  * a temporary media glitch at rescan time.
753                  */
754                 if (family == AF_INET &&
755                     isc_netaddr_equal(&interface.address, &zero_address)) {
756                         continue;
757                 }
758                 if (family == AF_INET6 &&
759                     isc_netaddr_equal(&interface.address, &zero_address6)) {
760                         continue;
761                 }
762
763                 if (adjusting == ISC_FALSE) {
764                         result = setup_locals(mgr, &interface);
765                         if (result != ISC_R_SUCCESS)
766                                 goto ignore_interface;
767                 }
768
769                 ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
770                 dolistenon = ISC_TRUE;
771                 for (le = ISC_LIST_HEAD(ll->elts);
772                      le != NULL;
773                      le = ISC_LIST_NEXT(le, link))
774                 {
775                         int match;
776                         isc_boolean_t ipv6_wildcard = ISC_FALSE;
777                         isc_netaddr_t listen_netaddr;
778                         isc_sockaddr_t listen_sockaddr;
779
780                         /*
781                          * Construct a socket address for this IP/port
782                          * combination.
783                          */
784                         if (family == AF_INET) {
785                                 isc_netaddr_fromin(&listen_netaddr,
786                                                    &interface.address.type.in);
787                         } else {
788                                 isc_netaddr_fromin6(&listen_netaddr,
789                                                     &interface.address.type.in6);
790                                 isc_netaddr_setzone(&listen_netaddr,
791                                                     interface.address.zone);
792                         }
793                         isc_sockaddr_fromnetaddr(&listen_sockaddr,
794                                                  &listen_netaddr,
795                                                  le->port);
796
797                         /*
798                          * See if the address matches the listen-on statement;
799                          * if not, ignore the interface.
800                          */
801                         (void)dns_acl_match(&listen_netaddr, NULL, le->acl,
802                                             &mgr->aclenv, &match, NULL);
803                         if (match <= 0)
804                                 continue;
805
806                         if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) {
807                                 setup_listenon(mgr, &interface, le->port);
808                                 dolistenon = ISC_FALSE;
809                         }
810
811                         /*
812                          * The case of "any" IPv6 address will require
813                          * special considerations later, so remember it.
814                          */
815                         if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
816                             listenon_is_ip6_any(le))
817                                 ipv6_wildcard = ISC_TRUE;
818
819                         /*
820                          * When adjusting interfaces with extra a listening
821                          * list, see if the address matches the extra list.
822                          * If it does, and is also covered by a wildcard
823                          * interface, we need to listen on the address
824                          * explicitly.
825                          */
826                         if (adjusting == ISC_TRUE) {
827                                 ns_listenelt_t *ele;
828
829                                 match = 0;
830                                 for (ele = ISC_LIST_HEAD(ext_listen->elts);
831                                      ele != NULL;
832                                      ele = ISC_LIST_NEXT(ele, link)) {
833                                         (void)dns_acl_match(&listen_netaddr,
834                                                             NULL, ele->acl,
835                                                             NULL, &match, NULL);
836                                         if (match > 0 &&
837                                             (ele->port == le->port ||
838                                             ele->port == 0))
839                                                 break;
840                                         else
841                                                 match = 0;
842                                 }
843                                 if (ipv6_wildcard == ISC_TRUE && match == 0)
844                                         continue;
845                         }
846
847                         ifp = find_matching_interface(mgr, &listen_sockaddr);
848                         if (ifp != NULL) {
849                                 ifp->generation = mgr->generation;
850                         } else {
851                                 char sabuf[ISC_SOCKADDR_FORMATSIZE];
852
853                                 if (adjusting == ISC_FALSE &&
854                                     ipv6_wildcard == ISC_TRUE)
855                                         continue;
856
857                                 if (log_explicit && family == AF_INET6 &&
858                                     !adjusting && listenon_is_ip6_any(le)) {
859                                         isc_log_write(IFMGR_COMMON_LOGARGS,
860                                                       verbose ? ISC_LOG_INFO :
861                                                               ISC_LOG_DEBUG(1),
862                                                       "IPv6 socket API is "
863                                                       "incomplete; explicitly "
864                                                       "binding to each IPv6 "
865                                                       "address separately");
866                                         log_explicit = ISC_FALSE;
867                                 }
868                                 isc_sockaddr_format(&listen_sockaddr,
869                                                     sabuf, sizeof(sabuf));
870                                 isc_log_write(IFMGR_COMMON_LOGARGS,
871                                               ISC_LOG_INFO,
872                                               "%s"
873                                               "listening on %s interface "
874                                               "%s, %s",
875                                               (adjusting == ISC_TRUE) ?
876                                               "additionally " : "",
877                                               (family == AF_INET) ?
878                                               "IPv4" : "IPv6",
879                                               interface.name, sabuf);
880
881                                 result = ns_interface_setup(mgr,
882                                                             &listen_sockaddr,
883                                                             interface.name,
884                                                             &ifp,
885                                                             (adjusting == ISC_TRUE) ?
886                                                             ISC_FALSE :
887                                                             ISC_TRUE);
888
889                                 if (result != ISC_R_SUCCESS) {
890                                         isc_log_write(IFMGR_COMMON_LOGARGS,
891                                                       ISC_LOG_ERROR,
892                                                       "creating %s interface "
893                                                       "%s failed; interface "
894                                                       "ignored",
895                                                       (family == AF_INET) ?
896                                                       "IPv4" : "IPv6",
897                                                       interface.name);
898                                 }
899                                 /* Continue. */
900                         }
901
902                 }
903                 continue;
904
905         ignore_interface:
906                 isc_log_write(IFMGR_COMMON_LOGARGS,
907                               ISC_LOG_ERROR,
908                               "ignoring %s interface %s: %s",
909                               (family == AF_INET) ? "IPv4" : "IPv6",
910                               interface.name, isc_result_totext(result));
911                 continue;
912         }
913         if (result != ISC_R_NOMORE)
914                 UNEXPECTED_ERROR(__FILE__, __LINE__,
915                                  "interface iteration failed: %s",
916                                  isc_result_totext(result));
917         else
918                 result = ISC_R_SUCCESS;
919  cleanup_iter:
920         isc_interfaceiter_destroy(&iter);
921         return (result);
922 }
923
924 static void
925 ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
926                       isc_boolean_t verbose)
927 {
928         isc_boolean_t purge = ISC_TRUE;
929
930         REQUIRE(NS_INTERFACEMGR_VALID(mgr));
931
932         mgr->generation++;      /* Increment the generation count. */
933
934         if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS)
935                 purge = ISC_FALSE;
936
937         /*
938          * Now go through the interface list and delete anything that
939          * does not have the current generation number.  This is
940          * how we catch interfaces that go away or change their
941          * addresses.
942          */
943         if (purge)
944                 purge_old_interfaces(mgr);
945
946         /*
947          * Warn if we are not listening on any interface, unless
948          * we're in lwresd-only mode, in which case that is to
949          * be expected.
950          */
951         if (ext_listen == NULL &&
952             ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) {
953                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
954                               "not listening on any interfaces");
955         }
956 }
957
958 void
959 ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
960         ns_interfacemgr_scan0(mgr, NULL, verbose);
961 }
962
963 void
964 ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
965                        isc_boolean_t verbose)
966 {
967         ns_interfacemgr_scan0(mgr, list, verbose);
968 }
969
970 void
971 ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
972         LOCK(&mgr->lock);
973         ns_listenlist_detach(&mgr->listenon4);
974         ns_listenlist_attach(value, &mgr->listenon4);
975         UNLOCK(&mgr->lock);
976 }
977
978 void
979 ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
980         LOCK(&mgr->lock);
981         ns_listenlist_detach(&mgr->listenon6);
982         ns_listenlist_attach(value, &mgr->listenon6);
983         UNLOCK(&mgr->lock);
984 }
985
986 void
987 ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) {
988         ns_interface_t *interface;
989
990         LOCK(&mgr->lock);
991         interface = ISC_LIST_HEAD(mgr->interfaces);
992         while (interface != NULL) {
993                 if (interface->clientmgr != NULL)
994                         ns_client_dumprecursing(f, interface->clientmgr);
995                 interface = ISC_LIST_NEXT(interface, link);
996         }
997         UNLOCK(&mgr->lock);
998 }
999
1000 isc_boolean_t
1001 ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
1002         isc_sockaddr_t *old;
1003
1004         for (old = ISC_LIST_HEAD(mgr->listenon);
1005              old != NULL;
1006              old = ISC_LIST_NEXT(old, link))
1007                 if (isc_sockaddr_equal(old, addr))
1008                         return (ISC_TRUE);
1009         return (ISC_FALSE);
1010 }