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