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