]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bind9/bin/named/interfacemgr.c
This commit was generated by cvs2svn to compensate for changes in r171829,
[FreeBSD/FreeBSD.git] / contrib / bind9 / 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.76.18.8 2006/07/20 01:10:30 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         if (result != ISC_R_SUCCESS) {
312                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
313                                  "binding TCP socket: %s",
314                                  isc_result_totext(result));
315                 goto tcp_bind_failure;
316         }
317         result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
318         if (result != ISC_R_SUCCESS) {
319                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
320                                  "listening on TCP socket: %s",
321                                  isc_result_totext(result));
322                 goto tcp_listen_failure;
323         }
324
325         /* 
326          * If/when there a multiple filters listen to the
327          * result.
328          */
329         (void)isc_socket_filter(ifp->tcpsocket, "dataready");
330
331         result = ns_clientmgr_createclients(ifp->clientmgr,
332                                             ifp->ntcptarget, ifp,
333                                             ISC_TRUE);
334         if (result != ISC_R_SUCCESS) {
335                 UNEXPECTED_ERROR(__FILE__, __LINE__,
336                                  "TCP ns_clientmgr_createclients(): %s",
337                                  isc_result_totext(result));
338                 goto accepttcp_failure;
339         }
340         return (ISC_R_SUCCESS);
341
342  accepttcp_failure:
343  tcp_listen_failure:
344  tcp_bind_failure:
345         isc_socket_detach(&ifp->tcpsocket);
346  tcp_socket_failure:
347         return (ISC_R_SUCCESS);
348 }
349
350 static isc_result_t
351 ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
352                    const char *name, ns_interface_t **ifpret,
353                    isc_boolean_t accept_tcp)
354 {
355         isc_result_t result;
356         ns_interface_t *ifp = NULL;
357         REQUIRE(ifpret != NULL && *ifpret == NULL);
358
359         result = ns_interface_create(mgr, addr, name, &ifp);
360         if (result != ISC_R_SUCCESS)
361                 return (result);
362
363         result = ns_interface_listenudp(ifp);
364         if (result != ISC_R_SUCCESS)
365                 goto cleanup_interface;
366
367         if (accept_tcp == ISC_TRUE) {
368                 result = ns_interface_accepttcp(ifp);
369                 if (result != ISC_R_SUCCESS) {
370                         /*
371                          * XXXRTH We don't currently have a way to easily stop
372                          * dispatch service, so we currently return
373                          * ISC_R_SUCCESS (the UDP stuff will work even if TCP
374                          * creation failed).  This will be fixed later.
375                          */
376                         result = ISC_R_SUCCESS;
377                 }
378         }
379         *ifpret = ifp;
380         return (ISC_R_SUCCESS);
381
382  cleanup_interface:
383         ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
384         ns_interface_detach(&ifp);
385         return (result);
386 }
387
388 void
389 ns_interface_shutdown(ns_interface_t *ifp) {
390         if (ifp->clientmgr != NULL)
391                 ns_clientmgr_destroy(&ifp->clientmgr);
392 }
393
394 static void
395 ns_interface_destroy(ns_interface_t *ifp) {
396         isc_mem_t *mctx = ifp->mgr->mctx;
397         REQUIRE(NS_INTERFACE_VALID(ifp));
398
399         ns_interface_shutdown(ifp);
400
401         if (ifp->udpdispatch != NULL) {
402                 dns_dispatch_changeattributes(ifp->udpdispatch, 0,
403                                               DNS_DISPATCHATTR_NOLISTEN);
404                 dns_dispatch_detach(&ifp->udpdispatch);
405         }
406         if (ifp->tcpsocket != NULL)
407                 isc_socket_detach(&ifp->tcpsocket);
408
409         DESTROYLOCK(&ifp->lock);
410
411         ns_interfacemgr_detach(&ifp->mgr);
412
413         ifp->magic = 0;
414         isc_mem_put(mctx, ifp, sizeof(*ifp));
415 }
416
417 void
418 ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
419         REQUIRE(NS_INTERFACE_VALID(source));
420         LOCK(&source->lock);
421         INSIST(source->references > 0);
422         source->references++;
423         UNLOCK(&source->lock);
424         *target = source;
425 }
426
427 void
428 ns_interface_detach(ns_interface_t **targetp) {
429         isc_result_t need_destroy = ISC_FALSE;
430         ns_interface_t *target = *targetp;
431         REQUIRE(target != NULL);
432         REQUIRE(NS_INTERFACE_VALID(target));
433         LOCK(&target->lock);
434         REQUIRE(target->references > 0);
435         target->references--;
436         if (target->references == 0)
437                 need_destroy = ISC_TRUE;
438         UNLOCK(&target->lock);
439         if (need_destroy)
440                 ns_interface_destroy(target);
441         *targetp = NULL;
442 }
443
444 /*%
445  * Search the interface list for an interface whose address and port
446  * both match those of 'addr'.  Return a pointer to it, or NULL if not found.
447  */
448 static ns_interface_t *
449 find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
450         ns_interface_t *ifp;
451         for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
452              ifp = ISC_LIST_NEXT(ifp, link)) {
453                 if (isc_sockaddr_equal(&ifp->addr, addr))
454                         break;
455         }
456         return (ifp);
457 }
458
459 /*%
460  * Remove any interfaces whose generation number is not the current one.
461  */
462 static void
463 purge_old_interfaces(ns_interfacemgr_t *mgr) {
464         ns_interface_t *ifp, *next;
465         for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
466                 INSIST(NS_INTERFACE_VALID(ifp));
467                 next = ISC_LIST_NEXT(ifp, link);
468                 if (ifp->generation != mgr->generation) {
469                         char sabuf[256];
470                         ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
471                         isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
472                         isc_log_write(IFMGR_COMMON_LOGARGS,
473                                       ISC_LOG_INFO,
474                                       "no longer listening on %s", sabuf);
475                         ns_interface_shutdown(ifp);
476                         ns_interface_detach(&ifp);
477                 }
478         }
479 }
480
481 static isc_result_t
482 clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
483         dns_acl_t *newacl = NULL;
484         isc_result_t result;
485         result = dns_acl_create(mctx, 10, &newacl);
486         if (result != ISC_R_SUCCESS)
487                 return (result);
488         dns_acl_detach(aclp);
489         dns_acl_attach(newacl, aclp);
490         dns_acl_detach(&newacl);
491         return (ISC_R_SUCCESS);
492 }
493
494 static isc_boolean_t
495 listenon_is_ip6_any(ns_listenelt_t *elt) {
496         if (elt->acl->length != 1)
497                 return (ISC_FALSE);
498         if (elt->acl->elements[0].negative == ISC_FALSE &&
499             elt->acl->elements[0].type == dns_aclelementtype_any)
500                 return (ISC_TRUE);  /* listen-on-v6 { any; } */
501         return (ISC_FALSE); /* All others */
502 }
503
504 static isc_result_t
505 setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
506         isc_result_t result;
507         dns_aclelement_t elt;
508         unsigned int family;
509         unsigned int prefixlen;
510
511         family = interface->address.family;
512         
513         elt.type = dns_aclelementtype_ipprefix;
514         elt.negative = ISC_FALSE;
515         elt.u.ip_prefix.address = interface->address;
516         elt.u.ip_prefix.prefixlen = (family == AF_INET) ? 32 : 128;
517         result = dns_acl_appendelement(mgr->aclenv.localhost, &elt);
518         if (result != ISC_R_SUCCESS)
519                 return (result);
520
521         result = isc_netaddr_masktoprefixlen(&interface->netmask,
522                                              &prefixlen);
523
524         /* Non contigious netmasks not allowed by IPv6 arch. */
525         if (result != ISC_R_SUCCESS && family == AF_INET6)
526                 return (result);
527
528         if (result != ISC_R_SUCCESS) {
529                 isc_log_write(IFMGR_COMMON_LOGARGS,
530                               ISC_LOG_WARNING,
531                               "omitting IPv4 interface %s from "
532                               "localnets ACL: %s",
533                               interface->name,
534                               isc_result_totext(result));
535         } else {
536                 elt.u.ip_prefix.prefixlen = prefixlen;
537                 if (dns_acl_elementmatch(mgr->aclenv.localnets, &elt,
538                                          NULL) == ISC_R_NOTFOUND) {
539                         result = dns_acl_appendelement(mgr->aclenv.localnets,
540                                                        &elt);
541                         if (result != ISC_R_SUCCESS)
542                                 return (result);
543                 }
544         }
545
546         return (ISC_R_SUCCESS);
547 }
548
549 static void
550 setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface,
551                in_port_t port)
552
553         isc_sockaddr_t *addr;
554         isc_sockaddr_t *old;
555
556         addr = isc_mem_get(mgr->mctx, sizeof(*addr));
557         if (addr == NULL)
558                 return;
559
560         isc_sockaddr_fromnetaddr(addr, &interface->address, port);
561
562         for (old = ISC_LIST_HEAD(mgr->listenon);
563              old != NULL;
564              old = ISC_LIST_NEXT(old, link))
565                 if (isc_sockaddr_equal(addr, old))
566                         break;  
567
568         if (old != NULL)
569                 isc_mem_put(mgr->mctx, addr, sizeof(*addr));
570         else
571                 ISC_LIST_APPEND(mgr->listenon, addr, link);
572 }
573
574 static void
575 clearlistenon(ns_interfacemgr_t *mgr) {
576         isc_sockaddr_t *old;
577
578         old = ISC_LIST_HEAD(mgr->listenon);
579         while (old != NULL) {
580                 ISC_LIST_UNLINK(mgr->listenon, old, link);
581                 isc_mem_put(mgr->mctx, old, sizeof(*old));
582                 old = ISC_LIST_HEAD(mgr->listenon);
583         }
584 }
585
586 static isc_result_t
587 do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
588         isc_boolean_t verbose)
589 {
590         isc_interfaceiter_t *iter = NULL;
591         isc_boolean_t scan_ipv4 = ISC_FALSE;
592         isc_boolean_t scan_ipv6 = ISC_FALSE;
593         isc_boolean_t adjusting = ISC_FALSE;
594         isc_boolean_t ipv6only = ISC_TRUE;
595         isc_boolean_t ipv6pktinfo = ISC_TRUE;
596         isc_result_t result;
597         isc_netaddr_t zero_address, zero_address6;
598         ns_listenelt_t *le;
599         isc_sockaddr_t listen_addr;
600         ns_interface_t *ifp;
601         isc_boolean_t log_explicit = ISC_FALSE;
602         isc_boolean_t dolistenon;
603
604         if (ext_listen != NULL)
605                 adjusting = ISC_TRUE;
606
607         if (isc_net_probeipv6() == ISC_R_SUCCESS)
608                 scan_ipv6 = ISC_TRUE;
609 #ifdef WANT_IPV6
610         else
611                 isc_log_write(IFMGR_COMMON_LOGARGS,
612                               verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
613                               "no IPv6 interfaces found");
614 #endif
615
616         if (isc_net_probeipv4() == ISC_R_SUCCESS)
617                 scan_ipv4 = ISC_TRUE;
618         else
619                 isc_log_write(IFMGR_COMMON_LOGARGS,
620                               verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
621                               "no IPv4 interfaces found");
622
623         /*
624          * A special, but typical case; listen-on-v6 { any; }.
625          * When we can make the socket IPv6-only, open a single wildcard
626          * socket for IPv6 communication.  Otherwise, make separate socket
627          * for each IPv6 address in order to avoid accepting IPv4 packets
628          * as the form of mapped addresses unintentionally unless explicitly
629          * allowed.
630          */
631 #ifndef ISC_ALLOW_MAPPED
632         if (scan_ipv6 == ISC_TRUE &&
633             isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
634                 ipv6only = ISC_FALSE;
635                 log_explicit = ISC_TRUE;
636         }
637 #endif
638         if (scan_ipv6 == ISC_TRUE &&
639             isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
640                 ipv6pktinfo = ISC_FALSE;
641                 log_explicit = ISC_TRUE;
642         }
643         if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) {
644                 for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
645                      le != NULL;
646                      le = ISC_LIST_NEXT(le, link)) {
647                         struct in6_addr in6a;
648
649                         if (!listenon_is_ip6_any(le))
650                                 continue;
651
652                         in6a = in6addr_any;
653                         isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
654
655                         ifp = find_matching_interface(mgr, &listen_addr);
656                         if (ifp != NULL) {
657                                 ifp->generation = mgr->generation;
658                         } else {
659                                 isc_log_write(IFMGR_COMMON_LOGARGS,
660                                               ISC_LOG_INFO,
661                                               "listening on IPv6 "
662                                               "interfaces, port %u",
663                                               le->port);
664                                 result = ns_interface_setup(mgr, &listen_addr,
665                                                             "<any>", &ifp,
666                                                             ISC_TRUE);
667                                 if (result == ISC_R_SUCCESS)
668                                         ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
669                                 else
670                                         isc_log_write(IFMGR_COMMON_LOGARGS,
671                                                       ISC_LOG_ERROR,
672                                                       "listening on all IPv6 "
673                                                       "interfaces failed");
674                                 /* Continue. */
675                         }
676                 }
677         }
678
679         isc_netaddr_any(&zero_address);
680         isc_netaddr_any6(&zero_address6);
681
682         result = isc_interfaceiter_create(mgr->mctx, &iter);
683         if (result != ISC_R_SUCCESS)
684                 return (result);
685
686         if (adjusting == ISC_FALSE) {
687                 result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
688                 if (result != ISC_R_SUCCESS)
689                         goto cleanup_iter;
690                 result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
691                 if (result != ISC_R_SUCCESS)
692                         goto cleanup_iter;
693                 clearlistenon(mgr);
694         }
695
696         for (result = isc_interfaceiter_first(iter);
697              result == ISC_R_SUCCESS;
698              result = isc_interfaceiter_next(iter))
699         {
700                 isc_interface_t interface;
701                 ns_listenlist_t *ll;
702                 unsigned int family; 
703
704                 result = isc_interfaceiter_current(iter, &interface);
705                 if (result != ISC_R_SUCCESS)
706                         break;
707
708                 family = interface.address.family;
709                 if (family != AF_INET && family != AF_INET6)
710                         continue;
711                 if (scan_ipv4 == ISC_FALSE && family == AF_INET)
712                         continue;
713                 if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
714                         continue;
715
716                 /*
717                  * Test for the address being nonzero rather than testing
718                  * INTERFACE_F_UP, because on some systems the latter
719                  * follows the media state and we could end up ignoring
720                  * the interface for an entire rescan interval due to
721                  * a temporary media glitch at rescan time.
722                  */
723                 if (family == AF_INET &&
724                     isc_netaddr_equal(&interface.address, &zero_address)) {
725                         continue;
726                 }
727                 if (family == AF_INET6 &&
728                     isc_netaddr_equal(&interface.address, &zero_address6)) {
729                         continue;
730                 }
731
732                 if (adjusting == ISC_FALSE) {
733                         result = setup_locals(mgr, &interface);
734                         if (result != ISC_R_SUCCESS)
735                                 goto ignore_interface;
736                 }
737
738                 ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
739                 dolistenon = ISC_TRUE;
740                 for (le = ISC_LIST_HEAD(ll->elts);
741                      le != NULL;
742                      le = ISC_LIST_NEXT(le, link))
743                 {
744                         int match;
745                         isc_boolean_t ipv6_wildcard = ISC_FALSE;
746                         isc_netaddr_t listen_netaddr;
747                         isc_sockaddr_t listen_sockaddr;
748
749                         /*
750                          * Construct a socket address for this IP/port
751                          * combination.
752                          */
753                         if (family == AF_INET) {
754                                 isc_netaddr_fromin(&listen_netaddr,
755                                                    &interface.address.type.in);
756                         } else {
757                                 isc_netaddr_fromin6(&listen_netaddr,
758                                                     &interface.address.type.in6);
759                                 isc_netaddr_setzone(&listen_netaddr,
760                                                     interface.address.zone);
761                         }
762                         isc_sockaddr_fromnetaddr(&listen_sockaddr,
763                                                  &listen_netaddr,
764                                                  le->port);
765
766                         /*
767                          * See if the address matches the listen-on statement;
768                          * if not, ignore the interface.
769                          */
770                         (void)dns_acl_match(&listen_netaddr, NULL, le->acl,
771                                             &mgr->aclenv, &match, NULL);
772                         if (match <= 0)
773                                 continue;
774
775                         if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) {
776                                 setup_listenon(mgr, &interface, le->port);
777                                 dolistenon = ISC_FALSE;
778                         }
779
780                         /*
781                          * The case of "any" IPv6 address will require
782                          * special considerations later, so remember it.
783                          */
784                         if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
785                             listenon_is_ip6_any(le))
786                                 ipv6_wildcard = ISC_TRUE;
787
788                         /*
789                          * When adjusting interfaces with extra a listening
790                          * list, see if the address matches the extra list.
791                          * If it does, and is also covered by a wildcard
792                          * interface, we need to listen on the address
793                          * explicitly.
794                          */
795                         if (adjusting == ISC_TRUE) {
796                                 ns_listenelt_t *ele;
797
798                                 match = 0;
799                                 for (ele = ISC_LIST_HEAD(ext_listen->elts);
800                                      ele != NULL;
801                                      ele = ISC_LIST_NEXT(ele, link)) {
802                                         (void)dns_acl_match(&listen_netaddr,
803                                                             NULL, ele->acl,
804                                                             NULL, &match, NULL);
805                                         if (match > 0 && ele->port == le->port)
806                                                 break;
807                                         else
808                                                 match = 0;
809                                 }
810                                 if (ipv6_wildcard == ISC_TRUE && match == 0)
811                                         continue;
812                         }
813
814                         ifp = find_matching_interface(mgr, &listen_sockaddr);
815                         if (ifp != NULL) {
816                                 ifp->generation = mgr->generation;
817                         } else {
818                                 char sabuf[ISC_SOCKADDR_FORMATSIZE];
819
820                                 if (adjusting == ISC_FALSE &&
821                                     ipv6_wildcard == ISC_TRUE)
822                                         continue;
823
824                                 if (log_explicit && family == AF_INET6 &&
825                                     !adjusting && listenon_is_ip6_any(le)) {
826                                         isc_log_write(IFMGR_COMMON_LOGARGS,
827                                                       verbose ? ISC_LOG_INFO :
828                                                               ISC_LOG_DEBUG(1),
829                                                       "IPv6 socket API is "
830                                                       "incomplete; explicitly "
831                                                       "binding to each IPv6 "
832                                                       "address separately");
833                                         log_explicit = ISC_FALSE;
834                                 }
835                                 isc_sockaddr_format(&listen_sockaddr,
836                                                     sabuf, sizeof(sabuf));
837                                 isc_log_write(IFMGR_COMMON_LOGARGS,
838                                               ISC_LOG_INFO,
839                                               "%s"
840                                               "listening on %s interface "
841                                               "%s, %s",
842                                               (adjusting == ISC_TRUE) ?
843                                               "additionally " : "",
844                                               (family == AF_INET) ?
845                                               "IPv4" : "IPv6",
846                                               interface.name, sabuf);
847
848                                 result = ns_interface_setup(mgr,
849                                                             &listen_sockaddr,
850                                                             interface.name,
851                                                             &ifp,
852                                                             (adjusting == ISC_TRUE) ?
853                                                             ISC_FALSE :
854                                                             ISC_TRUE);
855
856                                 if (result != ISC_R_SUCCESS) {
857                                         isc_log_write(IFMGR_COMMON_LOGARGS,
858                                                       ISC_LOG_ERROR,
859                                                       "creating %s interface "
860                                                       "%s failed; interface "
861                                                       "ignored",
862                                                       (family == AF_INET) ?
863                                                       "IPv4" : "IPv6",
864                                                       interface.name);
865                                 }
866                                 /* Continue. */
867                         }
868
869                 }
870                 continue;
871
872         ignore_interface:
873                 isc_log_write(IFMGR_COMMON_LOGARGS,
874                               ISC_LOG_ERROR,
875                               "ignoring %s interface %s: %s",
876                               (family == AF_INET) ? "IPv4" : "IPv6",
877                               interface.name, isc_result_totext(result));
878                 continue;
879         }
880         if (result != ISC_R_NOMORE)
881                 UNEXPECTED_ERROR(__FILE__, __LINE__,
882                                  "interface iteration failed: %s",
883                                  isc_result_totext(result));
884         else 
885                 result = ISC_R_SUCCESS;
886  cleanup_iter:
887         isc_interfaceiter_destroy(&iter);
888         return (result);
889 }
890
891 static void
892 ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
893                       isc_boolean_t verbose)
894 {
895         isc_boolean_t purge = ISC_TRUE;
896
897         REQUIRE(NS_INTERFACEMGR_VALID(mgr));
898
899         mgr->generation++;      /* Increment the generation count. */
900
901         if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS)
902                 purge = ISC_FALSE;
903
904         /*
905          * Now go through the interface list and delete anything that
906          * does not have the current generation number.  This is
907          * how we catch interfaces that go away or change their
908          * addresses.
909          */
910         if (purge)
911                 purge_old_interfaces(mgr);
912
913         /*
914          * Warn if we are not listening on any interface, unless
915          * we're in lwresd-only mode, in which case that is to 
916          * be expected.
917          */
918         if (ext_listen == NULL &&
919             ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) {
920                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
921                               "not listening on any interfaces");
922         }
923 }
924
925 void
926 ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
927         ns_interfacemgr_scan0(mgr, NULL, verbose);
928 }
929
930 void
931 ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
932                        isc_boolean_t verbose)
933 {
934         ns_interfacemgr_scan0(mgr, list, verbose);
935 }
936
937 void
938 ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
939         LOCK(&mgr->lock);
940         ns_listenlist_detach(&mgr->listenon4);
941         ns_listenlist_attach(value, &mgr->listenon4);
942         UNLOCK(&mgr->lock);
943 }
944
945 void
946 ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
947         LOCK(&mgr->lock);
948         ns_listenlist_detach(&mgr->listenon6);
949         ns_listenlist_attach(value, &mgr->listenon6);
950         UNLOCK(&mgr->lock);
951 }
952
953 void
954 ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) {
955         ns_interface_t *interface;
956
957         LOCK(&mgr->lock);
958         interface = ISC_LIST_HEAD(mgr->interfaces);
959         while (interface != NULL) {
960                 if (interface->clientmgr != NULL)
961                         ns_client_dumprecursing(f, interface->clientmgr);
962                 interface = ISC_LIST_NEXT(interface, link);
963         }
964         UNLOCK(&mgr->lock);
965 }
966
967 isc_boolean_t
968 ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
969         isc_sockaddr_t *old;
970
971         old = ISC_LIST_HEAD(mgr->listenon);
972         for (old = ISC_LIST_HEAD(mgr->listenon);
973              old != NULL;
974              old = ISC_LIST_NEXT(old, link))
975                 if (isc_sockaddr_equal(old, addr))
976                         return (ISC_TRUE);
977         return (ISC_FALSE);
978 }