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