Merge from vendor branch GDB:
[dragonfly.git] / contrib / bind-9.2.4rc7 / 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.7 2004/08/10 04:58:00 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         result = isc_socket_bind(ifp->tcpsocket, &ifp->addr);
298         if (result != ISC_R_SUCCESS) {
299                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
300                                  "binding TCP socket: %s",
301                                  isc_result_totext(result));
302                 goto tcp_bind_failure;
303         }
304         result = isc_socket_listen(ifp->tcpsocket, 3);
305         if (result != ISC_R_SUCCESS) {
306                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
307                                  "listening on TCP socket: %s",
308                                  isc_result_totext(result));
309                 goto tcp_listen_failure;
310         }
311
312         result = ns_clientmgr_createclients(ifp->clientmgr,
313                                             ifp->ntcptarget, ifp,
314                                             ISC_TRUE);
315         if (result != ISC_R_SUCCESS) {
316                 UNEXPECTED_ERROR(__FILE__, __LINE__,
317                                  "TCP ns_clientmgr_createclients(): %s",
318                                  isc_result_totext(result));
319                 goto accepttcp_failure;
320         }
321         return (ISC_R_SUCCESS);
322
323  accepttcp_failure:
324  tcp_listen_failure:
325  tcp_bind_failure:
326         isc_socket_detach(&ifp->tcpsocket);
327  tcp_socket_failure:
328         return (ISC_R_SUCCESS);
329 }
330
331 static isc_result_t
332 ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
333                    const char *name, ns_interface_t **ifpret)
334 {
335         isc_result_t result;
336         ns_interface_t *ifp = NULL;
337         REQUIRE(ifpret != NULL && *ifpret == NULL);
338
339         result = ns_interface_create(mgr, addr, name, &ifp);
340         if (result != ISC_R_SUCCESS)
341                 return (result);
342
343         result = ns_interface_listenudp(ifp);
344         if (result != ISC_R_SUCCESS)
345                 goto cleanup_interface;
346
347         result = ns_interface_accepttcp(ifp);
348         if (result != ISC_R_SUCCESS) {
349                 /*
350                  * XXXRTH We don't currently have a way to easily stop dispatch
351                  * service, so we currently return ISC_R_SUCCESS (the UDP stuff
352                  * will work even if TCP creation failed).  This will be fixed
353                  * later.
354                  */
355                 result = ISC_R_SUCCESS;
356         }
357         *ifpret = ifp;
358         return (ISC_R_SUCCESS);
359
360  cleanup_interface:
361         ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
362         ns_interface_detach(&ifp);
363         return (result);
364 }
365
366 void
367 ns_interface_shutdown(ns_interface_t *ifp) {
368         if (ifp->clientmgr != NULL)
369                 ns_clientmgr_destroy(&ifp->clientmgr);
370 }
371
372 static void
373 ns_interface_destroy(ns_interface_t *ifp) {
374         isc_mem_t *mctx = ifp->mgr->mctx;
375         REQUIRE(NS_INTERFACE_VALID(ifp));
376
377         ns_interface_shutdown(ifp);
378
379         if (ifp->udpdispatch != NULL) {
380                 dns_dispatch_changeattributes(ifp->udpdispatch, 0,
381                                               DNS_DISPATCHATTR_NOLISTEN);
382                 dns_dispatch_detach(&ifp->udpdispatch);
383         }
384         if (ifp->tcpsocket != NULL)
385                 isc_socket_detach(&ifp->tcpsocket);
386
387         DESTROYLOCK(&ifp->lock);
388
389         ns_interfacemgr_detach(&ifp->mgr);
390
391         ifp->magic = 0;
392         isc_mem_put(mctx, ifp, sizeof(*ifp));
393 }
394
395 void
396 ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
397         REQUIRE(NS_INTERFACE_VALID(source));
398         LOCK(&source->lock);
399         INSIST(source->references > 0);
400         source->references++;
401         UNLOCK(&source->lock);
402         *target = source;
403 }
404
405 void
406 ns_interface_detach(ns_interface_t **targetp) {
407         isc_result_t need_destroy = ISC_FALSE;
408         ns_interface_t *target = *targetp;
409         REQUIRE(target != NULL);
410         REQUIRE(NS_INTERFACE_VALID(target));
411         LOCK(&target->lock);
412         REQUIRE(target->references > 0);
413         target->references--;
414         if (target->references == 0)
415                 need_destroy = ISC_TRUE;
416         UNLOCK(&target->lock);
417         if (need_destroy)
418                 ns_interface_destroy(target);
419         *targetp = NULL;
420 }
421
422 /*
423  * Search the interface list for an interface whose address and port
424  * both match those of 'addr'.  Return a pointer to it, or NULL if not found.
425  */
426 static ns_interface_t *
427 find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
428         ns_interface_t *ifp;
429         for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
430              ifp = ISC_LIST_NEXT(ifp, link)) {
431                 if (isc_sockaddr_equal(&ifp->addr, addr))
432                         break;
433         }
434         return (ifp);
435 }
436
437 /*
438  * Remove any interfaces whose generation number is not the current one.
439  */
440 static void
441 purge_old_interfaces(ns_interfacemgr_t *mgr) {
442         ns_interface_t *ifp, *next;
443         for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
444                 INSIST(NS_INTERFACE_VALID(ifp));
445                 next = ISC_LIST_NEXT(ifp, link);
446                 if (ifp->generation != mgr->generation) {
447                         char sabuf[256];
448                         ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
449                         isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
450                         isc_log_write(IFMGR_COMMON_LOGARGS,
451                                       ISC_LOG_INFO,
452                                       "no longer listening on %s", sabuf);
453                         ns_interface_shutdown(ifp);
454                         ns_interface_detach(&ifp);
455                 }
456         }
457 }
458
459 static isc_result_t
460 clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
461         dns_acl_t *newacl = NULL;
462         isc_result_t result;
463         result = dns_acl_create(mctx, 10, &newacl);
464         if (result != ISC_R_SUCCESS)
465                 return (result);
466         dns_acl_detach(aclp);
467         dns_acl_attach(newacl, aclp);
468         dns_acl_detach(&newacl);
469         return (ISC_R_SUCCESS);
470 }
471
472 static isc_result_t
473 do_ipv4(ns_interfacemgr_t *mgr) {
474         isc_interfaceiter_t *iter = NULL;
475         isc_result_t result;
476
477         result = isc_interfaceiter_create(mgr->mctx, &iter);
478         if (result != ISC_R_SUCCESS)
479                 return (result);
480
481         result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
482         if (result != ISC_R_SUCCESS)
483                 goto cleanup_iter;
484         result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
485         if (result != ISC_R_SUCCESS)
486                 goto cleanup_iter;
487
488         for (result = isc_interfaceiter_first(iter);
489              result == ISC_R_SUCCESS;
490              result = isc_interfaceiter_next(iter))
491         {
492                 ns_interface_t *ifp;
493                 isc_interface_t interface;
494                 ns_listenelt_t *le;
495                 dns_aclelement_t elt;
496                 unsigned int prefixlen;
497
498                 result = isc_interfaceiter_current(iter, &interface);
499                 if (result != ISC_R_SUCCESS)
500                         break;
501
502                 if (interface.address.family != AF_INET)
503                         continue;
504
505                 if ((interface.flags & INTERFACE_F_UP) == 0)
506                         continue;
507
508                 elt.type = dns_aclelementtype_ipprefix;
509                 elt.negative = ISC_FALSE;
510                 elt.u.ip_prefix.address = interface.address;
511                 elt.u.ip_prefix.prefixlen = 32;
512                 result = dns_acl_appendelement(mgr->aclenv.localhost, &elt);
513                 if (result != ISC_R_SUCCESS)
514                         goto ignore_interface;
515
516                 result = isc_netaddr_masktoprefixlen(&interface.netmask,
517                                                      &prefixlen);
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                         /* XXX suppress duplicates */
528                         result = dns_acl_appendelement(mgr->aclenv.localnets,
529                                                        &elt);
530                         if (result != ISC_R_SUCCESS)
531                                 goto ignore_interface;
532                 }
533
534                 for (le = ISC_LIST_HEAD(mgr->listenon4->elts);
535                      le != NULL;
536                      le = ISC_LIST_NEXT(le, link))
537                 {
538                         int match;
539                         isc_netaddr_t listen_netaddr;
540                         isc_sockaddr_t listen_sockaddr;
541
542                         /*
543                          * Construct a socket address for this IP/port
544                          * combination.
545                          */
546                         isc_netaddr_fromin(&listen_netaddr,
547                                            &interface.address.type.in);
548                         isc_sockaddr_fromnetaddr(&listen_sockaddr,
549                                                  &listen_netaddr,
550                                                  le->port);
551
552                         /*
553                          * See if the address matches the listen-on statement;
554                          * if not, ignore the interface.
555                          */
556                         result = dns_acl_match(&listen_netaddr, NULL,
557                                                le->acl, &mgr->aclenv,
558                                                &match, NULL);
559                         if (match <= 0)
560                                 continue;
561
562                         ifp = find_matching_interface(mgr, &listen_sockaddr);
563                         if (ifp != NULL) {
564                                 ifp->generation = mgr->generation;
565                         } else {
566                                 char sabuf[ISC_SOCKADDR_FORMATSIZE];
567                                 isc_sockaddr_format(&listen_sockaddr,
568                                                     sabuf, sizeof(sabuf));
569                                 isc_log_write(IFMGR_COMMON_LOGARGS,
570                                               ISC_LOG_INFO,
571                                               "listening on IPv4 interface "
572                                               "%s, %s", interface.name, sabuf);
573
574                                 result = ns_interface_setup(mgr,
575                                                             &listen_sockaddr,
576                                                             interface.name,
577                                                             &ifp);
578                                 if (result != ISC_R_SUCCESS) {
579                                         isc_log_write(IFMGR_COMMON_LOGARGS,
580                                                  ISC_LOG_ERROR,
581                                                  "creating IPv4 interface %s "
582                                                  "failed; interface ignored",
583                                                  interface.name);
584                                 }
585                                 /* Continue. */
586                         }
587
588                 }
589                 continue;
590
591         ignore_interface:
592                 isc_log_write(IFMGR_COMMON_LOGARGS,
593                               ISC_LOG_ERROR,
594                               "ignoring IPv4 interface %s: %s",
595                               interface.name, isc_result_totext(result));
596                 continue;
597         }
598         if (result != ISC_R_NOMORE)
599                 UNEXPECTED_ERROR(__FILE__, __LINE__,
600                                  "IPv4: interface iteration failed: %s",
601                                  isc_result_totext(result));
602         else 
603                 result = ISC_R_SUCCESS;
604  cleanup_iter:
605         isc_interfaceiter_destroy(&iter);
606         return (result);
607 }
608
609 static isc_boolean_t
610 listenon_is_ip6_none(ns_listenelt_t *elt) {
611         if (elt->acl->length == 0)
612                 return (ISC_TRUE); /* listen-on-v6 { } */
613         if (elt->acl->length > 1)
614                 return (ISC_FALSE);  /* listen-on-v6 { ...; ...; } */
615         if (elt->acl->elements[0].negative == ISC_TRUE &&
616             elt->acl->elements[0].type == dns_aclelementtype_any)
617                 return (ISC_TRUE);  /* listen-on-v6 { none; } */
618         return (ISC_FALSE); /* All others */
619 }
620
621 static isc_boolean_t
622 listenon_is_ip6_any(ns_listenelt_t *elt) {
623         if (elt->acl->length != 1)
624                 return (ISC_FALSE);
625         if (elt->acl->elements[0].negative == ISC_FALSE &&
626             elt->acl->elements[0].type == dns_aclelementtype_any)
627                 return (ISC_TRUE);  /* listen-on-v6 { any; } */
628         return (ISC_FALSE); /* All others */
629 }
630
631 static isc_result_t
632 do_ipv6(ns_interfacemgr_t *mgr) {
633         isc_result_t result;
634         ns_interface_t *ifp;
635         isc_sockaddr_t listen_addr;
636         struct in6_addr in6a;
637         ns_listenelt_t *le;
638
639         for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
640              le != NULL;
641              le = ISC_LIST_NEXT(le, link))
642         {
643                 if (listenon_is_ip6_none(le))
644                         continue;
645                 if (! listenon_is_ip6_any(le)) {
646                         isc_log_write(IFMGR_COMMON_LOGARGS,
647                                       ISC_LOG_ERROR,
648                                       "bad IPv6 listen-on list: "
649                                       "must be 'any' or 'none'");
650                         return (ISC_R_FAILURE);
651                 }
652
653                 in6a = in6addr_any;
654                 isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
655
656                 ifp = find_matching_interface(mgr, &listen_addr);
657                 if (ifp != NULL) {
658                         ifp->generation = mgr->generation;
659                 } else {
660                         isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_INFO,
661                                       "listening on IPv6 interfaces, port %u",
662                                       le->port);
663                         result = ns_interface_setup(mgr, &listen_addr,
664                                                     "<any>", &ifp);
665                         if (result != ISC_R_SUCCESS) {
666                                 isc_log_write(IFMGR_COMMON_LOGARGS,
667                                               ISC_LOG_ERROR,
668                                               "listening on IPv6 interfaces "
669                                               "failed");
670                                 /* Continue. */
671                         }
672                 }
673         }
674         return (ISC_R_SUCCESS);
675 }
676
677 void
678 ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
679         isc_boolean_t purge = ISC_TRUE;
680
681         REQUIRE(NS_INTERFACEMGR_VALID(mgr));
682
683         mgr->generation++;      /* Increment the generation count. */
684
685         if (isc_net_probeipv6() == ISC_R_SUCCESS) {
686                 if (do_ipv6(mgr) != ISC_R_SUCCESS)
687                         purge = ISC_FALSE;
688         }
689 #ifdef WANT_IPV6
690         else
691                 isc_log_write(IFMGR_COMMON_LOGARGS,
692                               verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
693                               "no IPv6 interfaces found");
694 #endif
695
696         if (isc_net_probeipv4() == ISC_R_SUCCESS) {
697                 if (do_ipv4(mgr) != ISC_R_SUCCESS)
698                         purge = ISC_FALSE;
699         } else
700                 isc_log_write(IFMGR_COMMON_LOGARGS,
701                               verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
702                               "no IPv4 interfaces found");
703
704         /*
705          * Now go through the interface list and delete anything that
706          * does not have the current generation number.  This is
707          * how we catch interfaces that go away or change their
708          * addresses.
709          */
710         if (purge)
711                 purge_old_interfaces(mgr);
712
713         /*
714          * Warn if we are not listening on any interface, unless
715          * we're in lwresd-only mode, in which case that is to 
716          * be expected.
717          */
718         if (ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly)
719                 isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
720                               "not listening on any interfaces");
721 }
722
723 void
724 ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
725         LOCK(&mgr->lock);
726         ns_listenlist_detach(&mgr->listenon4);
727         ns_listenlist_attach(value, &mgr->listenon4);
728         UNLOCK(&mgr->lock);
729 }
730
731 void
732 ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
733         LOCK(&mgr->lock);
734         ns_listenlist_detach(&mgr->listenon6);
735         ns_listenlist_attach(value, &mgr->listenon6);
736         UNLOCK(&mgr->lock);
737 }
738