b212892c8e1a9af53ef14ebe054e7ba9c5627369
[dragonfly.git] / contrib / bind-9.3 / bin / named / interfacemgr.c
1 /*
2  * Copyright (C) 2004  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.15 2004/08/10 04:56:23 jinmei 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         strncpy(ifp->name, name, sizeof(ifp->name));
186         ifp->name[sizeof(ifp->name)-1] = '\0';
187         ifp->clientmgr = NULL;
188
189         result = isc_mutex_init(&ifp->lock);
190         if (result != ISC_R_SUCCESS)
191                 goto lock_create_failure;
192
193         result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,
194                                      ns_g_timermgr,
195                                      &ifp->clientmgr);
196         if (result != ISC_R_SUCCESS) {
197                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
198                               "ns_clientmgr_create() failed: %s",
199                               isc_result_totext(result));
200                 goto clientmgr_create_failure;
201         }
202
203         ifp->udpdispatch = NULL;
204
205         ifp->tcpsocket = NULL;
206         /*
207          * Create a single TCP client object.  It will replace itself
208          * with a new one as soon as it gets a connection, so the actual
209          * connections will be handled in parallel even though there is
210          * only one client initially.
211          */
212         ifp->ntcptarget = 1;
213         ifp->ntcpcurrent = 0;
214
215         ISC_LINK_INIT(ifp, link);
216
217         ns_interfacemgr_attach(mgr, &ifp->mgr);
218         ISC_LIST_APPEND(mgr->interfaces, ifp, link);
219
220         ifp->references = 1;
221         ifp->magic = IFACE_MAGIC;
222         *ifpret = ifp;
223
224         return (ISC_R_SUCCESS);
225
226  clientmgr_create_failure:
227         DESTROYLOCK(&ifp->lock);
228  lock_create_failure:
229         ifp->magic = 0;
230         isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
231
232         return (ISC_R_UNEXPECTED);
233 }
234
235 static isc_result_t
236 ns_interface_listenudp(ns_interface_t *ifp) {
237         isc_result_t result;
238         unsigned int attrs;
239         unsigned int attrmask;
240
241         attrs = 0;
242         attrs |= DNS_DISPATCHATTR_UDP;
243         if (isc_sockaddr_pf(&ifp->addr) == AF_INET)
244                 attrs |= DNS_DISPATCHATTR_IPV4;
245         else
246                 attrs |= DNS_DISPATCHATTR_IPV6;
247         attrs |= DNS_DISPATCHATTR_NOLISTEN;
248         attrmask = 0;
249         attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
250         attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
251         result = dns_dispatch_getudp(ifp->mgr->dispatchmgr, ns_g_socketmgr,
252                                      ns_g_taskmgr, &ifp->addr,
253                                      4096, 1000, 32768, 8219, 8237,
254                                      attrs, attrmask, &ifp->udpdispatch);
255         if (result != ISC_R_SUCCESS) {
256                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
257                               "could not listen on UDP socket: %s",
258                               isc_result_totext(result));
259                 goto udp_dispatch_failure;
260         }
261
262         result = ns_clientmgr_createclients(ifp->clientmgr, ns_g_cpus,
263                                             ifp, ISC_FALSE);
264         if (result != ISC_R_SUCCESS) {
265                 UNEXPECTED_ERROR(__FILE__, __LINE__,
266                                  "UDP ns_clientmgr_createclients(): %s",
267                                  isc_result_totext(result));
268                 goto addtodispatch_failure;
269         }
270         return (ISC_R_SUCCESS);
271
272  addtodispatch_failure:
273         dns_dispatch_changeattributes(ifp->udpdispatch, 0,
274                                       DNS_DISPATCHATTR_NOLISTEN);
275         dns_dispatch_detach(&ifp->udpdispatch);
276  udp_dispatch_failure:
277         return (result);
278 }
279
280 static isc_result_t
281 ns_interface_accepttcp(ns_interface_t *ifp) {
282         isc_result_t result;
283
284         /*
285          * Open a TCP socket.
286          */
287         result = isc_socket_create(ifp->mgr->socketmgr,
288                                    isc_sockaddr_pf(&ifp->addr),
289                                    isc_sockettype_tcp,
290                                    &ifp->tcpsocket);
291         if (result != ISC_R_SUCCESS) {
292                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
293                                  "creating TCP socket: %s",
294                                  isc_result_totext(result));
295                 goto tcp_socket_failure;
296         }
297 #ifndef ISC_ALLOW_MAPPED
298         isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE);
299 #endif
300         result = isc_socket_bind(ifp->tcpsocket, &ifp->addr);
301         if (result != ISC_R_SUCCESS) {
302                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
303                                  "binding TCP socket: %s",
304                                  isc_result_totext(result));
305                 goto tcp_bind_failure;
306         }
307         result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
308         if (result != ISC_R_SUCCESS) {
309                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
310                                  "listening on TCP socket: %s",
311                                  isc_result_totext(result));
312                 goto tcp_listen_failure;
313         }
314
315         /* 
316          * If/when there a multiple filters listen to the
317          * result.
318          */
319         (void)isc_socket_filter(ifp->tcpsocket, "dataready");
320
321         result = ns_clientmgr_createclients(ifp->clientmgr,
322                                             ifp->ntcptarget, ifp,
323                                             ISC_TRUE);
324         if (result != ISC_R_SUCCESS) {
325                 UNEXPECTED_ERROR(__FILE__, __LINE__,
326                                  "TCP ns_clientmgr_createclients(): %s",
327                                  isc_result_totext(result));
328                 goto accepttcp_failure;
329         }
330         return (ISC_R_SUCCESS);
331
332  accepttcp_failure:
333  tcp_listen_failure:
334  tcp_bind_failure:
335         isc_socket_detach(&ifp->tcpsocket);
336  tcp_socket_failure:
337         return (ISC_R_SUCCESS);
338 }
339
340 static isc_result_t
341 ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
342                    const char *name, ns_interface_t **ifpret,
343                    isc_boolean_t accept_tcp)
344 {
345         isc_result_t result;
346         ns_interface_t *ifp = NULL;
347         REQUIRE(ifpret != NULL && *ifpret == NULL);
348
349         result = ns_interface_create(mgr, addr, name, &ifp);
350         if (result != ISC_R_SUCCESS)
351                 return (result);
352
353         result = ns_interface_listenudp(ifp);
354         if (result != ISC_R_SUCCESS)
355                 goto cleanup_interface;
356
357         if (accept_tcp == ISC_TRUE) {
358                 result = ns_interface_accepttcp(ifp);
359                 if (result != ISC_R_SUCCESS) {
360                         /*
361                          * XXXRTH We don't currently have a way to easily stop
362                          * dispatch service, so we currently return
363                          * ISC_R_SUCCESS (the UDP stuff will work even if TCP
364                          * creation failed).  This will be fixed later.
365                          */
366                         result = ISC_R_SUCCESS;
367                 }
368         }
369         *ifpret = ifp;
370         return (ISC_R_SUCCESS);
371
372  cleanup_interface:
373         ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
374         ns_interface_detach(&ifp);
375         return (result);
376 }
377
378 void
379 ns_interface_shutdown(ns_interface_t *ifp) {
380         if (ifp->clientmgr != NULL)
381                 ns_clientmgr_destroy(&ifp->clientmgr);
382 }
383
384 static void
385 ns_interface_destroy(ns_interface_t *ifp) {
386         isc_mem_t *mctx = ifp->mgr->mctx;
387         REQUIRE(NS_INTERFACE_VALID(ifp));
388
389         ns_interface_shutdown(ifp);
390
391         if (ifp->udpdispatch != NULL) {
392                 dns_dispatch_changeattributes(ifp->udpdispatch, 0,
393                                               DNS_DISPATCHATTR_NOLISTEN);
394                 dns_dispatch_detach(&ifp->udpdispatch);
395         }
396         if (ifp->tcpsocket != NULL)
397                 isc_socket_detach(&ifp->tcpsocket);
398
399         DESTROYLOCK(&ifp->lock);
400
401         ns_interfacemgr_detach(&ifp->mgr);
402
403         ifp->magic = 0;
404         isc_mem_put(mctx, ifp, sizeof(*ifp));
405 }
406
407 void
408 ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
409         REQUIRE(NS_INTERFACE_VALID(source));
410         LOCK(&source->lock);
411         INSIST(source->references > 0);
412         source->references++;
413         UNLOCK(&source->lock);
414         *target = source;
415 }
416
417 void
418 ns_interface_detach(ns_interface_t **targetp) {
419         isc_result_t need_destroy = ISC_FALSE;
420         ns_interface_t *target = *targetp;
421         REQUIRE(target != NULL);
422         REQUIRE(NS_INTERFACE_VALID(target));
423         LOCK(&target->lock);
424         REQUIRE(target->references > 0);
425         target->references--;
426         if (target->references == 0)
427                 need_destroy = ISC_TRUE;
428         UNLOCK(&target->lock);
429         if (need_destroy)
430                 ns_interface_destroy(target);
431         *targetp = NULL;
432 }
433
434 /*
435  * Search the interface list for an interface whose address and port
436  * both match those of 'addr'.  Return a pointer to it, or NULL if not found.
437  */
438 static ns_interface_t *
439 find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
440         ns_interface_t *ifp;
441         for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
442              ifp = ISC_LIST_NEXT(ifp, link)) {
443                 if (isc_sockaddr_equal(&ifp->addr, addr))
444                         break;
445         }
446         return (ifp);
447 }
448
449 /*
450  * Remove any interfaces whose generation number is not the current one.
451  */
452 static void
453 purge_old_interfaces(ns_interfacemgr_t *mgr) {
454         ns_interface_t *ifp, *next;
455         for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
456                 INSIST(NS_INTERFACE_VALID(ifp));
457                 next = ISC_LIST_NEXT(ifp, link);
458                 if (ifp->generation != mgr->generation) {
459                         char sabuf[256];
460                         ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
461                         isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
462                         isc_log_write(IFMGR_COMMON_LOGARGS,
463                                       ISC_LOG_INFO,
464                                       "no longer listening on %s", sabuf);
465                         ns_interface_shutdown(ifp);
466                         ns_interface_detach(&ifp);
467                 }
468         }
469 }
470
471 static isc_result_t
472 clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
473         dns_acl_t *newacl = NULL;
474         isc_result_t result;
475         result = dns_acl_create(mctx, 10, &newacl);
476         if (result != ISC_R_SUCCESS)
477                 return (result);
478         dns_acl_detach(aclp);
479         dns_acl_attach(newacl, aclp);
480         dns_acl_detach(&newacl);
481         return (ISC_R_SUCCESS);
482 }
483
484 static isc_boolean_t
485 listenon_is_ip6_any(ns_listenelt_t *elt) {
486         if (elt->acl->length != 1)
487                 return (ISC_FALSE);
488         if (elt->acl->elements[0].negative == ISC_FALSE &&
489             elt->acl->elements[0].type == dns_aclelementtype_any)
490                 return (ISC_TRUE);  /* listen-on-v6 { any; } */
491         return (ISC_FALSE); /* All others */
492 }
493
494 static isc_result_t
495 setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
496         isc_result_t result;
497         dns_aclelement_t elt;
498         unsigned int family;
499         unsigned int prefixlen;
500
501         family = interface->address.family;
502         
503         elt.type = dns_aclelementtype_ipprefix;
504         elt.negative = ISC_FALSE;
505         elt.u.ip_prefix.address = interface->address;
506         elt.u.ip_prefix.prefixlen = (family == AF_INET) ? 32 : 128;
507         result = dns_acl_appendelement(mgr->aclenv.localhost, &elt);
508         if (result != ISC_R_SUCCESS)
509                 return (result);
510
511         result = isc_netaddr_masktoprefixlen(&interface->netmask,
512                                              &prefixlen);
513
514         /* Non contigious netmasks not allowed by IPv6 arch. */
515         if (result != ISC_R_SUCCESS && family == AF_INET6)
516                 return (result);
517
518         if (result != ISC_R_SUCCESS) {
519                 isc_log_write(IFMGR_COMMON_LOGARGS,
520                               ISC_LOG_WARNING,
521                               "omitting IPv4 interface %s from "
522                               "localnets ACL: %s",
523                               interface->name,
524                               isc_result_totext(result));
525         } else {
526                 elt.u.ip_prefix.prefixlen = prefixlen;
527                 if (dns_acl_elementmatch(mgr->aclenv.localnets, &elt,
528                                          NULL) == ISC_R_NOTFOUND) {
529                         result = dns_acl_appendelement(mgr->aclenv.localnets,
530                                                        &elt);
531                         if (result != ISC_R_SUCCESS)
532                                 return (result);
533                 }
534         }
535
536         return (ISC_R_SUCCESS);
537 }
538
539 static isc_result_t
540 do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
541         isc_boolean_t verbose)
542 {
543         isc_interfaceiter_t *iter = NULL;
544         isc_boolean_t scan_ipv4 = ISC_FALSE;
545         isc_boolean_t scan_ipv6 = ISC_FALSE;
546         isc_boolean_t adjusting = ISC_FALSE;
547         isc_boolean_t ipv6only = ISC_TRUE;
548         isc_boolean_t ipv6pktinfo = ISC_TRUE;
549         isc_result_t result;
550         isc_netaddr_t zero_address, zero_address6;
551         ns_listenelt_t *le;
552         isc_sockaddr_t listen_addr;
553         ns_interface_t *ifp;
554         isc_boolean_t log_explicit = ISC_FALSE;
555
556         if (ext_listen != NULL)
557                 adjusting = ISC_TRUE;
558
559         if (isc_net_probeipv6() == ISC_R_SUCCESS)
560                 scan_ipv6 = ISC_TRUE;
561 #ifdef WANT_IPV6
562         else
563                 isc_log_write(IFMGR_COMMON_LOGARGS,
564                               verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
565                               "no IPv6 interfaces found");
566 #endif
567
568         if (isc_net_probeipv4() == ISC_R_SUCCESS)
569                 scan_ipv4 = ISC_TRUE;
570         else
571                 isc_log_write(IFMGR_COMMON_LOGARGS,
572                               verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
573                               "no IPv4 interfaces found");
574
575         /*
576          * A special, but typical case; listen-on-v6 { any; }.
577          * When we can make the socket IPv6-only, open a single wildcard
578          * socket for IPv6 communication.  Otherwise, make separate socket
579          * for each IPv6 address in order to avoid accepting IPv4 packets
580          * as the form of mapped addresses unintentionally unless explicitly
581          * allowed.
582          */
583 #ifndef ISC_ALLOW_MAPPED
584         if (scan_ipv6 == ISC_TRUE &&
585             isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
586                 ipv6only = ISC_FALSE;
587                 log_explicit = ISC_TRUE;
588         }
589 #endif
590         if (scan_ipv6 == ISC_TRUE &&
591             isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
592                 ipv6pktinfo = ISC_FALSE;
593                 log_explicit = ISC_TRUE;
594         }
595         if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) {
596                 for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
597                      le != NULL;
598                      le = ISC_LIST_NEXT(le, link)) {
599                         struct in6_addr in6a;
600
601                         if (!listenon_is_ip6_any(le))
602                                 continue;
603
604                         in6a = in6addr_any;
605                         isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
606
607                         ifp = find_matching_interface(mgr, &listen_addr);
608                         if (ifp != NULL) {
609                                 ifp->generation = mgr->generation;
610                         } else {
611                                 isc_log_write(IFMGR_COMMON_LOGARGS,
612                                               ISC_LOG_INFO,
613                                               "listening on IPv6 "
614                                               "interfaces, port %u",
615                                               le->port);
616                                 result = ns_interface_setup(mgr, &listen_addr,
617                                                             "<any>", &ifp,
618                                                             ISC_TRUE);
619                                 if (result == ISC_R_SUCCESS)
620                                         ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
621                                 else
622                                         isc_log_write(IFMGR_COMMON_LOGARGS,
623                                                       ISC_LOG_ERROR,
624                                                       "listening on all IPv6 "
625                                                       "interfaces failed");
626                                 /* Continue. */
627                         }
628                 }
629         }
630
631         isc_netaddr_any(&zero_address);
632         isc_netaddr_any6(&zero_address6);
633
634         result = isc_interfaceiter_create(mgr->mctx, &iter);
635         if (result != ISC_R_SUCCESS)
636                 return (result);
637
638         if (adjusting == ISC_FALSE) {
639                 result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
640                 if (result != ISC_R_SUCCESS)
641                         goto cleanup_iter;
642                 result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
643                 if (result != ISC_R_SUCCESS)
644                         goto cleanup_iter;
645         }
646
647         for (result = isc_interfaceiter_first(iter);
648              result == ISC_R_SUCCESS;
649              result = isc_interfaceiter_next(iter))
650         {
651                 isc_interface_t interface;
652                 ns_listenlist_t *ll;
653                 unsigned int family; 
654
655                 result = isc_interfaceiter_current(iter, &interface);
656                 if (result != ISC_R_SUCCESS)
657                         break;
658
659                 family = interface.address.family;
660                 if (family != AF_INET && family != AF_INET6)
661                         continue;
662                 if (scan_ipv4 == ISC_FALSE && family == AF_INET)
663                         continue;
664                 if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
665                         continue;
666
667                 /*
668                  * Test for the address being nonzero rather than testing
669                  * INTERFACE_F_UP, because on some systems the latter
670                  * follows the media state and we could end up ignoring
671                  * the interface for an entire rescan interval due to
672                  * a temporary media glitch at rescan time.
673                  */
674                 if (family == AF_INET &&
675                     isc_netaddr_equal(&interface.address, &zero_address)) {
676                         continue;
677                 }
678                 if (family == AF_INET6 &&
679                     isc_netaddr_equal(&interface.address, &zero_address6)) {
680                         continue;
681                 }
682
683                 if (adjusting == ISC_FALSE) {
684                         result = setup_locals(mgr, &interface);
685                         if (result != ISC_R_SUCCESS)
686                                 goto ignore_interface;
687                 }
688
689                 ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
690                 for (le = ISC_LIST_HEAD(ll->elts);
691                      le != NULL;
692                      le = ISC_LIST_NEXT(le, link))
693                 {
694                         int match;
695                         isc_boolean_t ipv6_wildcard = ISC_FALSE;
696                         isc_netaddr_t listen_netaddr;
697                         isc_sockaddr_t listen_sockaddr;
698
699                         /*
700                          * Construct a socket address for this IP/port
701                          * combination.
702                          */
703                         if (family == AF_INET) {
704                                 isc_netaddr_fromin(&listen_netaddr,
705                                                    &interface.address.type.in);
706                         } else {
707                                 isc_netaddr_fromin6(&listen_netaddr,
708                                                     &interface.address.type.in6);
709                                 isc_netaddr_setzone(&listen_netaddr,
710                                                     interface.address.zone);
711                         }
712                         isc_sockaddr_fromnetaddr(&listen_sockaddr,
713                                                  &listen_netaddr,
714                                                  le->port);
715
716                         /*
717                          * See if the address matches the listen-on statement;
718                          * if not, ignore the interface.
719                          */
720                         result = dns_acl_match(&listen_netaddr, NULL,
721                                                le->acl, &mgr->aclenv,
722                                                &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                                         dns_acl_match(&listen_netaddr, NULL,
749                                                       ele->acl, NULL,
750                                                       &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 }