1135446Strhodes/* 2254897Serwin * Copyright (C) 2004-2009, 2011-2013 Internet Systems Consortium, Inc. ("ISC") 3135446Strhodes * Copyright (C) 1999-2002 Internet Software Consortium. 4135446Strhodes * 5182645Sdougb * Permission to use, copy, modify, and/or distribute this software for any 6135446Strhodes * purpose with or without fee is hereby granted, provided that the above 7135446Strhodes * copyright notice and this permission notice appear in all copies. 8135446Strhodes * 9135446Strhodes * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 10135446Strhodes * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 11135446Strhodes * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 12135446Strhodes * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 13135446Strhodes * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 14135446Strhodes * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 15135446Strhodes * PERFORMANCE OF THIS SOFTWARE. 16135446Strhodes */ 17135446Strhodes 18254897Serwin/* $Id: interfacemgr.c,v 1.101 2011/11/09 18:44:03 each Exp $ */ 19135446Strhodes 20170222Sdougb/*! \file */ 21170222Sdougb 22135446Strhodes#include <config.h> 23135446Strhodes 24135446Strhodes#include <isc/interfaceiter.h> 25254897Serwin#include <isc/os.h> 26135446Strhodes#include <isc/string.h> 27135446Strhodes#include <isc/task.h> 28135446Strhodes#include <isc/util.h> 29135446Strhodes 30135446Strhodes#include <dns/acl.h> 31135446Strhodes#include <dns/dispatch.h> 32135446Strhodes 33135446Strhodes#include <named/client.h> 34135446Strhodes#include <named/log.h> 35135446Strhodes#include <named/interfacemgr.h> 36135446Strhodes 37135446Strhodes#define IFMGR_MAGIC ISC_MAGIC('I', 'F', 'M', 'G') 38135446Strhodes#define NS_INTERFACEMGR_VALID(t) ISC_MAGIC_VALID(t, IFMGR_MAGIC) 39135446Strhodes 40135446Strhodes#define IFMGR_COMMON_LOGARGS \ 41135446Strhodes ns_g_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR 42135446Strhodes 43170222Sdougb/*% nameserver interface manager structure */ 44135446Strhodesstruct ns_interfacemgr { 45170222Sdougb unsigned int magic; /*%< Magic number. */ 46135446Strhodes int references; 47135446Strhodes isc_mutex_t lock; 48170222Sdougb isc_mem_t * mctx; /*%< Memory context. */ 49170222Sdougb isc_taskmgr_t * taskmgr; /*%< Task manager. */ 50170222Sdougb isc_socketmgr_t * socketmgr; /*%< Socket manager. */ 51135446Strhodes dns_dispatchmgr_t * dispatchmgr; 52170222Sdougb unsigned int generation; /*%< Current generation no. */ 53135446Strhodes ns_listenlist_t * listenon4; 54135446Strhodes ns_listenlist_t * listenon6; 55170222Sdougb dns_aclenv_t aclenv; /*%< Localhost/localnets ACLs */ 56170222Sdougb ISC_LIST(ns_interface_t) interfaces; /*%< List of interfaces. */ 57170222Sdougb ISC_LIST(isc_sockaddr_t) listenon; 58135446Strhodes}; 59135446Strhodes 60135446Strhodesstatic void 61135446Strhodespurge_old_interfaces(ns_interfacemgr_t *mgr); 62135446Strhodes 63170222Sdougbstatic void 64170222Sdougbclearlistenon(ns_interfacemgr_t *mgr); 65170222Sdougb 66135446Strhodesisc_result_t 67135446Strhodesns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, 68135446Strhodes isc_socketmgr_t *socketmgr, 69135446Strhodes dns_dispatchmgr_t *dispatchmgr, 70135446Strhodes ns_interfacemgr_t **mgrp) 71135446Strhodes{ 72135446Strhodes isc_result_t result; 73135446Strhodes ns_interfacemgr_t *mgr; 74135446Strhodes 75135446Strhodes REQUIRE(mctx != NULL); 76135446Strhodes REQUIRE(mgrp != NULL); 77135446Strhodes REQUIRE(*mgrp == NULL); 78135446Strhodes 79135446Strhodes mgr = isc_mem_get(mctx, sizeof(*mgr)); 80135446Strhodes if (mgr == NULL) 81135446Strhodes return (ISC_R_NOMEMORY); 82135446Strhodes 83254402Serwin mgr->mctx = NULL; 84254402Serwin isc_mem_attach(mctx, &mgr->mctx); 85254402Serwin 86135446Strhodes result = isc_mutex_init(&mgr->lock); 87135446Strhodes if (result != ISC_R_SUCCESS) 88135446Strhodes goto cleanup_mem; 89135446Strhodes 90135446Strhodes mgr->taskmgr = taskmgr; 91135446Strhodes mgr->socketmgr = socketmgr; 92135446Strhodes mgr->dispatchmgr = dispatchmgr; 93135446Strhodes mgr->generation = 1; 94135446Strhodes mgr->listenon4 = NULL; 95135446Strhodes mgr->listenon6 = NULL; 96186462Sdougb 97135446Strhodes ISC_LIST_INIT(mgr->interfaces); 98170222Sdougb ISC_LIST_INIT(mgr->listenon); 99135446Strhodes 100135446Strhodes /* 101135446Strhodes * The listen-on lists are initially empty. 102135446Strhodes */ 103135446Strhodes result = ns_listenlist_create(mctx, &mgr->listenon4); 104135446Strhodes if (result != ISC_R_SUCCESS) 105135446Strhodes goto cleanup_mem; 106135446Strhodes ns_listenlist_attach(mgr->listenon4, &mgr->listenon6); 107135446Strhodes 108135446Strhodes result = dns_aclenv_init(mctx, &mgr->aclenv); 109135446Strhodes if (result != ISC_R_SUCCESS) 110135446Strhodes goto cleanup_listenon; 111135446Strhodes 112135446Strhodes mgr->references = 1; 113135446Strhodes mgr->magic = IFMGR_MAGIC; 114135446Strhodes *mgrp = mgr; 115135446Strhodes return (ISC_R_SUCCESS); 116135446Strhodes 117135446Strhodes cleanup_listenon: 118135446Strhodes ns_listenlist_detach(&mgr->listenon4); 119135446Strhodes ns_listenlist_detach(&mgr->listenon6); 120135446Strhodes cleanup_mem: 121254402Serwin isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr)); 122135446Strhodes return (result); 123135446Strhodes} 124135446Strhodes 125135446Strhodesstatic void 126135446Strhodesns_interfacemgr_destroy(ns_interfacemgr_t *mgr) { 127135446Strhodes REQUIRE(NS_INTERFACEMGR_VALID(mgr)); 128135446Strhodes dns_aclenv_destroy(&mgr->aclenv); 129135446Strhodes ns_listenlist_detach(&mgr->listenon4); 130135446Strhodes ns_listenlist_detach(&mgr->listenon6); 131170222Sdougb clearlistenon(mgr); 132135446Strhodes DESTROYLOCK(&mgr->lock); 133135446Strhodes mgr->magic = 0; 134254402Serwin isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr)); 135135446Strhodes} 136135446Strhodes 137135446Strhodesdns_aclenv_t * 138135446Strhodesns_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) { 139135446Strhodes return (&mgr->aclenv); 140135446Strhodes} 141135446Strhodes 142135446Strhodesvoid 143135446Strhodesns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) { 144135446Strhodes REQUIRE(NS_INTERFACEMGR_VALID(source)); 145135446Strhodes LOCK(&source->lock); 146135446Strhodes INSIST(source->references > 0); 147135446Strhodes source->references++; 148135446Strhodes UNLOCK(&source->lock); 149135446Strhodes *target = source; 150135446Strhodes} 151135446Strhodes 152135446Strhodesvoid 153135446Strhodesns_interfacemgr_detach(ns_interfacemgr_t **targetp) { 154135446Strhodes isc_result_t need_destroy = ISC_FALSE; 155135446Strhodes ns_interfacemgr_t *target = *targetp; 156135446Strhodes REQUIRE(target != NULL); 157135446Strhodes REQUIRE(NS_INTERFACEMGR_VALID(target)); 158135446Strhodes LOCK(&target->lock); 159135446Strhodes REQUIRE(target->references > 0); 160135446Strhodes target->references--; 161135446Strhodes if (target->references == 0) 162135446Strhodes need_destroy = ISC_TRUE; 163135446Strhodes UNLOCK(&target->lock); 164135446Strhodes if (need_destroy) 165135446Strhodes ns_interfacemgr_destroy(target); 166135446Strhodes *targetp = NULL; 167135446Strhodes} 168135446Strhodes 169135446Strhodesvoid 170135446Strhodesns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) { 171135446Strhodes REQUIRE(NS_INTERFACEMGR_VALID(mgr)); 172135446Strhodes 173170222Sdougb /*% 174135446Strhodes * Shut down and detach all interfaces. 175135446Strhodes * By incrementing the generation count, we make purge_old_interfaces() 176135446Strhodes * consider all interfaces "old". 177135446Strhodes */ 178135446Strhodes mgr->generation++; 179135446Strhodes purge_old_interfaces(mgr); 180135446Strhodes} 181135446Strhodes 182135446Strhodes 183135446Strhodesstatic isc_result_t 184135446Strhodesns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, 185135446Strhodes const char *name, ns_interface_t **ifpret) 186135446Strhodes{ 187135446Strhodes ns_interface_t *ifp; 188135446Strhodes isc_result_t result; 189254897Serwin int disp; 190135446Strhodes 191135446Strhodes REQUIRE(NS_INTERFACEMGR_VALID(mgr)); 192254897Serwin 193135446Strhodes ifp = isc_mem_get(mgr->mctx, sizeof(*ifp)); 194135446Strhodes if (ifp == NULL) 195135446Strhodes return (ISC_R_NOMEMORY); 196254897Serwin 197135446Strhodes ifp->mgr = NULL; 198135446Strhodes ifp->generation = mgr->generation; 199135446Strhodes ifp->addr = *addr; 200165071Sdougb ifp->flags = 0; 201135446Strhodes strncpy(ifp->name, name, sizeof(ifp->name)); 202135446Strhodes ifp->name[sizeof(ifp->name)-1] = '\0'; 203135446Strhodes ifp->clientmgr = NULL; 204135446Strhodes 205135446Strhodes result = isc_mutex_init(&ifp->lock); 206135446Strhodes if (result != ISC_R_SUCCESS) 207135446Strhodes goto lock_create_failure; 208135446Strhodes 209135446Strhodes result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr, 210135446Strhodes ns_g_timermgr, 211135446Strhodes &ifp->clientmgr); 212135446Strhodes if (result != ISC_R_SUCCESS) { 213135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, 214135446Strhodes "ns_clientmgr_create() failed: %s", 215135446Strhodes isc_result_totext(result)); 216135446Strhodes goto clientmgr_create_failure; 217135446Strhodes } 218135446Strhodes 219254897Serwin for (disp = 0; disp < MAX_UDP_DISPATCH; disp++) 220254897Serwin ifp->udpdispatch[disp] = NULL; 221135446Strhodes 222135446Strhodes ifp->tcpsocket = NULL; 223254897Serwin 224135446Strhodes /* 225135446Strhodes * Create a single TCP client object. It will replace itself 226135446Strhodes * with a new one as soon as it gets a connection, so the actual 227135446Strhodes * connections will be handled in parallel even though there is 228135446Strhodes * only one client initially. 229135446Strhodes */ 230135446Strhodes ifp->ntcptarget = 1; 231135446Strhodes ifp->ntcpcurrent = 0; 232254897Serwin ifp->nudpdispatch = 0; 233135446Strhodes 234135446Strhodes ISC_LINK_INIT(ifp, link); 235135446Strhodes 236135446Strhodes ns_interfacemgr_attach(mgr, &ifp->mgr); 237135446Strhodes ISC_LIST_APPEND(mgr->interfaces, ifp, link); 238135446Strhodes 239135446Strhodes ifp->references = 1; 240135446Strhodes ifp->magic = IFACE_MAGIC; 241135446Strhodes *ifpret = ifp; 242135446Strhodes 243135446Strhodes return (ISC_R_SUCCESS); 244135446Strhodes 245135446Strhodes clientmgr_create_failure: 246135446Strhodes DESTROYLOCK(&ifp->lock); 247254897Serwin 248135446Strhodes lock_create_failure: 249135446Strhodes ifp->magic = 0; 250135446Strhodes isc_mem_put(mgr->mctx, ifp, sizeof(*ifp)); 251135446Strhodes 252135446Strhodes return (ISC_R_UNEXPECTED); 253135446Strhodes} 254135446Strhodes 255135446Strhodesstatic isc_result_t 256135446Strhodesns_interface_listenudp(ns_interface_t *ifp) { 257135446Strhodes isc_result_t result; 258135446Strhodes unsigned int attrs; 259135446Strhodes unsigned int attrmask; 260254897Serwin int disp, i; 261135446Strhodes 262135446Strhodes attrs = 0; 263135446Strhodes attrs |= DNS_DISPATCHATTR_UDP; 264135446Strhodes if (isc_sockaddr_pf(&ifp->addr) == AF_INET) 265135446Strhodes attrs |= DNS_DISPATCHATTR_IPV4; 266135446Strhodes else 267135446Strhodes attrs |= DNS_DISPATCHATTR_IPV6; 268135446Strhodes attrs |= DNS_DISPATCHATTR_NOLISTEN; 269135446Strhodes attrmask = 0; 270135446Strhodes attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP; 271135446Strhodes attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6; 272254897Serwin 273254897Serwin ifp->nudpdispatch = ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH); 274254897Serwin for (disp = 0; disp < ifp->nudpdispatch; disp++) { 275254897Serwin result = dns_dispatch_getudp_dup(ifp->mgr->dispatchmgr, 276254897Serwin ns_g_socketmgr, 277254897Serwin ns_g_taskmgr, &ifp->addr, 278254897Serwin 4096, 1000, 32768, 8219, 8237, 279254897Serwin attrs, attrmask, 280254897Serwin &ifp->udpdispatch[disp], 281254897Serwin disp == 0 282254897Serwin ? NULL 283254897Serwin : ifp->udpdispatch[0]); 284254897Serwin if (result != ISC_R_SUCCESS) { 285254897Serwin isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, 286254897Serwin "could not listen on UDP socket: %s", 287254897Serwin isc_result_totext(result)); 288254897Serwin goto udp_dispatch_failure; 289254897Serwin } 290254897Serwin 291135446Strhodes } 292135446Strhodes 293254897Serwin result = ns_clientmgr_createclients(ifp->clientmgr, ifp->nudpdispatch, 294135446Strhodes ifp, ISC_FALSE); 295135446Strhodes if (result != ISC_R_SUCCESS) { 296135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 297135446Strhodes "UDP ns_clientmgr_createclients(): %s", 298135446Strhodes isc_result_totext(result)); 299135446Strhodes goto addtodispatch_failure; 300135446Strhodes } 301254897Serwin 302135446Strhodes return (ISC_R_SUCCESS); 303135446Strhodes 304135446Strhodes addtodispatch_failure: 305254897Serwin for (i = disp - 1; i <= 0; i--) { 306254897Serwin dns_dispatch_changeattributes(ifp->udpdispatch[i], 0, 307254897Serwin DNS_DISPATCHATTR_NOLISTEN); 308254897Serwin dns_dispatch_detach(&(ifp->udpdispatch[i])); 309254897Serwin } 310254897Serwin ifp->nudpdispatch = 0; 311254897Serwin 312135446Strhodes udp_dispatch_failure: 313135446Strhodes return (result); 314135446Strhodes} 315135446Strhodes 316135446Strhodesstatic isc_result_t 317135446Strhodesns_interface_accepttcp(ns_interface_t *ifp) { 318135446Strhodes isc_result_t result; 319135446Strhodes 320135446Strhodes /* 321135446Strhodes * Open a TCP socket. 322135446Strhodes */ 323135446Strhodes result = isc_socket_create(ifp->mgr->socketmgr, 324135446Strhodes isc_sockaddr_pf(&ifp->addr), 325135446Strhodes isc_sockettype_tcp, 326135446Strhodes &ifp->tcpsocket); 327135446Strhodes if (result != ISC_R_SUCCESS) { 328135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, 329135446Strhodes "creating TCP socket: %s", 330135446Strhodes isc_result_totext(result)); 331135446Strhodes goto tcp_socket_failure; 332135446Strhodes } 333193149Sdougb isc_socket_setname(ifp->tcpsocket, "dispatcher", NULL); 334135446Strhodes#ifndef ISC_ALLOW_MAPPED 335135446Strhodes isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE); 336135446Strhodes#endif 337182645Sdougb result = isc_socket_bind(ifp->tcpsocket, &ifp->addr, 338182645Sdougb ISC_SOCKET_REUSEADDRESS); 339135446Strhodes if (result != ISC_R_SUCCESS) { 340135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, 341135446Strhodes "binding TCP socket: %s", 342135446Strhodes isc_result_totext(result)); 343135446Strhodes goto tcp_bind_failure; 344135446Strhodes } 345135446Strhodes result = isc_socket_listen(ifp->tcpsocket, ns_g_listen); 346135446Strhodes if (result != ISC_R_SUCCESS) { 347135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR, 348135446Strhodes "listening on TCP socket: %s", 349135446Strhodes isc_result_totext(result)); 350135446Strhodes goto tcp_listen_failure; 351135446Strhodes } 352135446Strhodes 353186462Sdougb /* 354135446Strhodes * If/when there a multiple filters listen to the 355135446Strhodes * result. 356135446Strhodes */ 357135446Strhodes (void)isc_socket_filter(ifp->tcpsocket, "dataready"); 358135446Strhodes 359135446Strhodes result = ns_clientmgr_createclients(ifp->clientmgr, 360135446Strhodes ifp->ntcptarget, ifp, 361135446Strhodes ISC_TRUE); 362135446Strhodes if (result != ISC_R_SUCCESS) { 363135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 364135446Strhodes "TCP ns_clientmgr_createclients(): %s", 365135446Strhodes isc_result_totext(result)); 366135446Strhodes goto accepttcp_failure; 367135446Strhodes } 368135446Strhodes return (ISC_R_SUCCESS); 369135446Strhodes 370135446Strhodes accepttcp_failure: 371135446Strhodes tcp_listen_failure: 372135446Strhodes tcp_bind_failure: 373135446Strhodes isc_socket_detach(&ifp->tcpsocket); 374135446Strhodes tcp_socket_failure: 375135446Strhodes return (ISC_R_SUCCESS); 376135446Strhodes} 377135446Strhodes 378135446Strhodesstatic isc_result_t 379135446Strhodesns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, 380135446Strhodes const char *name, ns_interface_t **ifpret, 381135446Strhodes isc_boolean_t accept_tcp) 382135446Strhodes{ 383135446Strhodes isc_result_t result; 384135446Strhodes ns_interface_t *ifp = NULL; 385135446Strhodes REQUIRE(ifpret != NULL && *ifpret == NULL); 386135446Strhodes 387135446Strhodes result = ns_interface_create(mgr, addr, name, &ifp); 388135446Strhodes if (result != ISC_R_SUCCESS) 389135446Strhodes return (result); 390135446Strhodes 391135446Strhodes result = ns_interface_listenudp(ifp); 392135446Strhodes if (result != ISC_R_SUCCESS) 393135446Strhodes goto cleanup_interface; 394135446Strhodes 395135446Strhodes if (accept_tcp == ISC_TRUE) { 396135446Strhodes result = ns_interface_accepttcp(ifp); 397135446Strhodes if (result != ISC_R_SUCCESS) { 398135446Strhodes /* 399135446Strhodes * XXXRTH We don't currently have a way to easily stop 400135446Strhodes * dispatch service, so we currently return 401135446Strhodes * ISC_R_SUCCESS (the UDP stuff will work even if TCP 402135446Strhodes * creation failed). This will be fixed later. 403135446Strhodes */ 404135446Strhodes result = ISC_R_SUCCESS; 405135446Strhodes } 406135446Strhodes } 407135446Strhodes *ifpret = ifp; 408225361Sdougb return (result); 409135446Strhodes 410135446Strhodes cleanup_interface: 411135446Strhodes ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link); 412135446Strhodes ns_interface_detach(&ifp); 413135446Strhodes return (result); 414135446Strhodes} 415135446Strhodes 416135446Strhodesvoid 417135446Strhodesns_interface_shutdown(ns_interface_t *ifp) { 418135446Strhodes if (ifp->clientmgr != NULL) 419135446Strhodes ns_clientmgr_destroy(&ifp->clientmgr); 420135446Strhodes} 421135446Strhodes 422135446Strhodesstatic void 423135446Strhodesns_interface_destroy(ns_interface_t *ifp) { 424135446Strhodes isc_mem_t *mctx = ifp->mgr->mctx; 425254897Serwin int disp; 426254897Serwin 427135446Strhodes REQUIRE(NS_INTERFACE_VALID(ifp)); 428135446Strhodes 429135446Strhodes ns_interface_shutdown(ifp); 430135446Strhodes 431254897Serwin for (disp = 0; disp < ifp->nudpdispatch; disp++) 432254897Serwin if (ifp->udpdispatch[disp] != NULL) { 433254897Serwin dns_dispatch_changeattributes(ifp->udpdispatch[disp], 0, 434254897Serwin DNS_DISPATCHATTR_NOLISTEN); 435254897Serwin dns_dispatch_detach(&(ifp->udpdispatch[disp])); 436254897Serwin } 437254897Serwin 438135446Strhodes if (ifp->tcpsocket != NULL) 439135446Strhodes isc_socket_detach(&ifp->tcpsocket); 440135446Strhodes 441135446Strhodes DESTROYLOCK(&ifp->lock); 442135446Strhodes 443135446Strhodes ns_interfacemgr_detach(&ifp->mgr); 444135446Strhodes 445135446Strhodes ifp->magic = 0; 446135446Strhodes isc_mem_put(mctx, ifp, sizeof(*ifp)); 447135446Strhodes} 448135446Strhodes 449135446Strhodesvoid 450135446Strhodesns_interface_attach(ns_interface_t *source, ns_interface_t **target) { 451135446Strhodes REQUIRE(NS_INTERFACE_VALID(source)); 452135446Strhodes LOCK(&source->lock); 453135446Strhodes INSIST(source->references > 0); 454135446Strhodes source->references++; 455135446Strhodes UNLOCK(&source->lock); 456135446Strhodes *target = source; 457135446Strhodes} 458135446Strhodes 459135446Strhodesvoid 460135446Strhodesns_interface_detach(ns_interface_t **targetp) { 461135446Strhodes isc_result_t need_destroy = ISC_FALSE; 462135446Strhodes ns_interface_t *target = *targetp; 463135446Strhodes REQUIRE(target != NULL); 464135446Strhodes REQUIRE(NS_INTERFACE_VALID(target)); 465135446Strhodes LOCK(&target->lock); 466135446Strhodes REQUIRE(target->references > 0); 467135446Strhodes target->references--; 468135446Strhodes if (target->references == 0) 469135446Strhodes need_destroy = ISC_TRUE; 470135446Strhodes UNLOCK(&target->lock); 471135446Strhodes if (need_destroy) 472135446Strhodes ns_interface_destroy(target); 473135446Strhodes *targetp = NULL; 474135446Strhodes} 475135446Strhodes 476170222Sdougb/*% 477135446Strhodes * Search the interface list for an interface whose address and port 478135446Strhodes * both match those of 'addr'. Return a pointer to it, or NULL if not found. 479135446Strhodes */ 480135446Strhodesstatic ns_interface_t * 481135446Strhodesfind_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) { 482135446Strhodes ns_interface_t *ifp; 483135446Strhodes for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; 484135446Strhodes ifp = ISC_LIST_NEXT(ifp, link)) { 485135446Strhodes if (isc_sockaddr_equal(&ifp->addr, addr)) 486135446Strhodes break; 487135446Strhodes } 488135446Strhodes return (ifp); 489135446Strhodes} 490135446Strhodes 491170222Sdougb/*% 492135446Strhodes * Remove any interfaces whose generation number is not the current one. 493135446Strhodes */ 494135446Strhodesstatic void 495135446Strhodespurge_old_interfaces(ns_interfacemgr_t *mgr) { 496135446Strhodes ns_interface_t *ifp, *next; 497135446Strhodes for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) { 498135446Strhodes INSIST(NS_INTERFACE_VALID(ifp)); 499135446Strhodes next = ISC_LIST_NEXT(ifp, link); 500135446Strhodes if (ifp->generation != mgr->generation) { 501135446Strhodes char sabuf[256]; 502135446Strhodes ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link); 503135446Strhodes isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf)); 504135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, 505135446Strhodes ISC_LOG_INFO, 506135446Strhodes "no longer listening on %s", sabuf); 507135446Strhodes ns_interface_shutdown(ifp); 508135446Strhodes ns_interface_detach(&ifp); 509135446Strhodes } 510135446Strhodes } 511135446Strhodes} 512135446Strhodes 513135446Strhodesstatic isc_result_t 514135446Strhodesclearacl(isc_mem_t *mctx, dns_acl_t **aclp) { 515135446Strhodes dns_acl_t *newacl = NULL; 516135446Strhodes isc_result_t result; 517193149Sdougb result = dns_acl_create(mctx, 0, &newacl); 518135446Strhodes if (result != ISC_R_SUCCESS) 519135446Strhodes return (result); 520135446Strhodes dns_acl_detach(aclp); 521135446Strhodes dns_acl_attach(newacl, aclp); 522135446Strhodes dns_acl_detach(&newacl); 523135446Strhodes return (ISC_R_SUCCESS); 524135446Strhodes} 525135446Strhodes 526135446Strhodesstatic isc_boolean_t 527135446Strhodeslistenon_is_ip6_any(ns_listenelt_t *elt) { 528193149Sdougb REQUIRE(elt && elt->acl); 529193149Sdougb return dns_acl_isany(elt->acl); 530135446Strhodes} 531135446Strhodes 532135446Strhodesstatic isc_result_t 533135446Strhodessetup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) { 534135446Strhodes isc_result_t result; 535135446Strhodes unsigned int prefixlen; 536193149Sdougb isc_netaddr_t *netaddr; 537135446Strhodes 538193149Sdougb netaddr = &interface->address; 539186462Sdougb 540193149Sdougb /* First add localhost address */ 541193149Sdougb prefixlen = (netaddr->family == AF_INET) ? 32 : 128; 542193149Sdougb result = dns_iptable_addprefix(mgr->aclenv.localhost->iptable, 543193149Sdougb netaddr, prefixlen, ISC_TRUE); 544135446Strhodes if (result != ISC_R_SUCCESS) 545135446Strhodes return (result); 546135446Strhodes 547193149Sdougb /* Then add localnets prefix */ 548135446Strhodes result = isc_netaddr_masktoprefixlen(&interface->netmask, 549135446Strhodes &prefixlen); 550135446Strhodes 551193149Sdougb /* Non contiguous netmasks not allowed by IPv6 arch. */ 552193149Sdougb if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6) 553135446Strhodes return (result); 554135446Strhodes 555135446Strhodes if (result != ISC_R_SUCCESS) { 556262706Serwin isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING, 557135446Strhodes "omitting IPv4 interface %s from " 558262706Serwin "localnets ACL: %s", interface->name, 559135446Strhodes isc_result_totext(result)); 560193149Sdougb return (ISC_R_SUCCESS); 561135446Strhodes } 562135446Strhodes 563262706Serwin if (prefixlen == 0U) { 564262706Serwin isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING, 565262706Serwin "omitting %s interface %s from localnets ACL: " 566262706Serwin "zero prefix length detected", 567262706Serwin (netaddr->family == AF_INET) ? "IPv4" : "IPv6", 568262706Serwin interface->name); 569262706Serwin return (ISC_R_SUCCESS); 570262706Serwin } 571262706Serwin 572193149Sdougb result = dns_iptable_addprefix(mgr->aclenv.localnets->iptable, 573193149Sdougb netaddr, prefixlen, ISC_TRUE); 574193149Sdougb if (result != ISC_R_SUCCESS) 575193149Sdougb return (result); 576193149Sdougb 577135446Strhodes return (ISC_R_SUCCESS); 578135446Strhodes} 579135446Strhodes 580170222Sdougbstatic void 581170222Sdougbsetup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface, 582170222Sdougb in_port_t port) 583186462Sdougb{ 584170222Sdougb isc_sockaddr_t *addr; 585170222Sdougb isc_sockaddr_t *old; 586170222Sdougb 587170222Sdougb addr = isc_mem_get(mgr->mctx, sizeof(*addr)); 588170222Sdougb if (addr == NULL) 589170222Sdougb return; 590170222Sdougb 591170222Sdougb isc_sockaddr_fromnetaddr(addr, &interface->address, port); 592170222Sdougb 593170222Sdougb for (old = ISC_LIST_HEAD(mgr->listenon); 594170222Sdougb old != NULL; 595170222Sdougb old = ISC_LIST_NEXT(old, link)) 596170222Sdougb if (isc_sockaddr_equal(addr, old)) 597186462Sdougb break; 598170222Sdougb 599170222Sdougb if (old != NULL) 600170222Sdougb isc_mem_put(mgr->mctx, addr, sizeof(*addr)); 601170222Sdougb else 602170222Sdougb ISC_LIST_APPEND(mgr->listenon, addr, link); 603170222Sdougb} 604170222Sdougb 605170222Sdougbstatic void 606170222Sdougbclearlistenon(ns_interfacemgr_t *mgr) { 607170222Sdougb isc_sockaddr_t *old; 608170222Sdougb 609170222Sdougb old = ISC_LIST_HEAD(mgr->listenon); 610170222Sdougb while (old != NULL) { 611170222Sdougb ISC_LIST_UNLINK(mgr->listenon, old, link); 612170222Sdougb isc_mem_put(mgr->mctx, old, sizeof(*old)); 613170222Sdougb old = ISC_LIST_HEAD(mgr->listenon); 614170222Sdougb } 615170222Sdougb} 616170222Sdougb 617135446Strhodesstatic isc_result_t 618135446Strhodesdo_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, 619135446Strhodes isc_boolean_t verbose) 620135446Strhodes{ 621135446Strhodes isc_interfaceiter_t *iter = NULL; 622135446Strhodes isc_boolean_t scan_ipv4 = ISC_FALSE; 623135446Strhodes isc_boolean_t scan_ipv6 = ISC_FALSE; 624135446Strhodes isc_boolean_t adjusting = ISC_FALSE; 625135446Strhodes isc_boolean_t ipv6only = ISC_TRUE; 626135446Strhodes isc_boolean_t ipv6pktinfo = ISC_TRUE; 627135446Strhodes isc_result_t result; 628135446Strhodes isc_netaddr_t zero_address, zero_address6; 629135446Strhodes ns_listenelt_t *le; 630135446Strhodes isc_sockaddr_t listen_addr; 631135446Strhodes ns_interface_t *ifp; 632135446Strhodes isc_boolean_t log_explicit = ISC_FALSE; 633170222Sdougb isc_boolean_t dolistenon; 634135446Strhodes 635135446Strhodes if (ext_listen != NULL) 636135446Strhodes adjusting = ISC_TRUE; 637135446Strhodes 638135446Strhodes if (isc_net_probeipv6() == ISC_R_SUCCESS) 639135446Strhodes scan_ipv6 = ISC_TRUE; 640135446Strhodes#ifdef WANT_IPV6 641135446Strhodes else 642135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, 643135446Strhodes verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), 644135446Strhodes "no IPv6 interfaces found"); 645135446Strhodes#endif 646135446Strhodes 647135446Strhodes if (isc_net_probeipv4() == ISC_R_SUCCESS) 648135446Strhodes scan_ipv4 = ISC_TRUE; 649135446Strhodes else 650135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, 651135446Strhodes verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1), 652135446Strhodes "no IPv4 interfaces found"); 653135446Strhodes 654135446Strhodes /* 655135446Strhodes * A special, but typical case; listen-on-v6 { any; }. 656135446Strhodes * When we can make the socket IPv6-only, open a single wildcard 657135446Strhodes * socket for IPv6 communication. Otherwise, make separate socket 658135446Strhodes * for each IPv6 address in order to avoid accepting IPv4 packets 659135446Strhodes * as the form of mapped addresses unintentionally unless explicitly 660135446Strhodes * allowed. 661135446Strhodes */ 662135446Strhodes#ifndef ISC_ALLOW_MAPPED 663135446Strhodes if (scan_ipv6 == ISC_TRUE && 664135446Strhodes isc_net_probe_ipv6only() != ISC_R_SUCCESS) { 665135446Strhodes ipv6only = ISC_FALSE; 666135446Strhodes log_explicit = ISC_TRUE; 667135446Strhodes } 668135446Strhodes#endif 669135446Strhodes if (scan_ipv6 == ISC_TRUE && 670135446Strhodes isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) { 671135446Strhodes ipv6pktinfo = ISC_FALSE; 672135446Strhodes log_explicit = ISC_TRUE; 673135446Strhodes } 674135446Strhodes if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) { 675135446Strhodes for (le = ISC_LIST_HEAD(mgr->listenon6->elts); 676135446Strhodes le != NULL; 677135446Strhodes le = ISC_LIST_NEXT(le, link)) { 678135446Strhodes struct in6_addr in6a; 679135446Strhodes 680135446Strhodes if (!listenon_is_ip6_any(le)) 681135446Strhodes continue; 682135446Strhodes 683135446Strhodes in6a = in6addr_any; 684135446Strhodes isc_sockaddr_fromin6(&listen_addr, &in6a, le->port); 685135446Strhodes 686135446Strhodes ifp = find_matching_interface(mgr, &listen_addr); 687135446Strhodes if (ifp != NULL) { 688135446Strhodes ifp->generation = mgr->generation; 689135446Strhodes } else { 690135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, 691135446Strhodes ISC_LOG_INFO, 692135446Strhodes "listening on IPv6 " 693135446Strhodes "interfaces, port %u", 694135446Strhodes le->port); 695135446Strhodes result = ns_interface_setup(mgr, &listen_addr, 696135446Strhodes "<any>", &ifp, 697135446Strhodes ISC_TRUE); 698135446Strhodes if (result == ISC_R_SUCCESS) 699135446Strhodes ifp->flags |= NS_INTERFACEFLAG_ANYADDR; 700135446Strhodes else 701135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, 702135446Strhodes ISC_LOG_ERROR, 703135446Strhodes "listening on all IPv6 " 704135446Strhodes "interfaces failed"); 705135446Strhodes /* Continue. */ 706135446Strhodes } 707135446Strhodes } 708135446Strhodes } 709135446Strhodes 710135446Strhodes isc_netaddr_any(&zero_address); 711135446Strhodes isc_netaddr_any6(&zero_address6); 712135446Strhodes 713135446Strhodes result = isc_interfaceiter_create(mgr->mctx, &iter); 714135446Strhodes if (result != ISC_R_SUCCESS) 715135446Strhodes return (result); 716135446Strhodes 717135446Strhodes if (adjusting == ISC_FALSE) { 718135446Strhodes result = clearacl(mgr->mctx, &mgr->aclenv.localhost); 719135446Strhodes if (result != ISC_R_SUCCESS) 720135446Strhodes goto cleanup_iter; 721135446Strhodes result = clearacl(mgr->mctx, &mgr->aclenv.localnets); 722135446Strhodes if (result != ISC_R_SUCCESS) 723135446Strhodes goto cleanup_iter; 724170222Sdougb clearlistenon(mgr); 725135446Strhodes } 726135446Strhodes 727135446Strhodes for (result = isc_interfaceiter_first(iter); 728135446Strhodes result == ISC_R_SUCCESS; 729135446Strhodes result = isc_interfaceiter_next(iter)) 730135446Strhodes { 731135446Strhodes isc_interface_t interface; 732135446Strhodes ns_listenlist_t *ll; 733186462Sdougb unsigned int family; 734135446Strhodes 735135446Strhodes result = isc_interfaceiter_current(iter, &interface); 736135446Strhodes if (result != ISC_R_SUCCESS) 737135446Strhodes break; 738135446Strhodes 739135446Strhodes family = interface.address.family; 740135446Strhodes if (family != AF_INET && family != AF_INET6) 741135446Strhodes continue; 742135446Strhodes if (scan_ipv4 == ISC_FALSE && family == AF_INET) 743135446Strhodes continue; 744135446Strhodes if (scan_ipv6 == ISC_FALSE && family == AF_INET6) 745135446Strhodes continue; 746135446Strhodes 747135446Strhodes /* 748135446Strhodes * Test for the address being nonzero rather than testing 749135446Strhodes * INTERFACE_F_UP, because on some systems the latter 750135446Strhodes * follows the media state and we could end up ignoring 751135446Strhodes * the interface for an entire rescan interval due to 752135446Strhodes * a temporary media glitch at rescan time. 753135446Strhodes */ 754135446Strhodes if (family == AF_INET && 755135446Strhodes isc_netaddr_equal(&interface.address, &zero_address)) { 756135446Strhodes continue; 757135446Strhodes } 758135446Strhodes if (family == AF_INET6 && 759135446Strhodes isc_netaddr_equal(&interface.address, &zero_address6)) { 760135446Strhodes continue; 761135446Strhodes } 762135446Strhodes 763135446Strhodes if (adjusting == ISC_FALSE) { 764135446Strhodes result = setup_locals(mgr, &interface); 765135446Strhodes if (result != ISC_R_SUCCESS) 766135446Strhodes goto ignore_interface; 767135446Strhodes } 768135446Strhodes 769135446Strhodes ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6; 770170222Sdougb dolistenon = ISC_TRUE; 771135446Strhodes for (le = ISC_LIST_HEAD(ll->elts); 772135446Strhodes le != NULL; 773135446Strhodes le = ISC_LIST_NEXT(le, link)) 774135446Strhodes { 775135446Strhodes int match; 776135446Strhodes isc_boolean_t ipv6_wildcard = ISC_FALSE; 777135446Strhodes isc_netaddr_t listen_netaddr; 778135446Strhodes isc_sockaddr_t listen_sockaddr; 779135446Strhodes 780135446Strhodes /* 781135446Strhodes * Construct a socket address for this IP/port 782135446Strhodes * combination. 783135446Strhodes */ 784135446Strhodes if (family == AF_INET) { 785135446Strhodes isc_netaddr_fromin(&listen_netaddr, 786135446Strhodes &interface.address.type.in); 787135446Strhodes } else { 788135446Strhodes isc_netaddr_fromin6(&listen_netaddr, 789135446Strhodes &interface.address.type.in6); 790135446Strhodes isc_netaddr_setzone(&listen_netaddr, 791135446Strhodes interface.address.zone); 792135446Strhodes } 793135446Strhodes isc_sockaddr_fromnetaddr(&listen_sockaddr, 794135446Strhodes &listen_netaddr, 795135446Strhodes le->port); 796135446Strhodes 797135446Strhodes /* 798135446Strhodes * See if the address matches the listen-on statement; 799135446Strhodes * if not, ignore the interface. 800135446Strhodes */ 801165071Sdougb (void)dns_acl_match(&listen_netaddr, NULL, le->acl, 802165071Sdougb &mgr->aclenv, &match, NULL); 803135446Strhodes if (match <= 0) 804135446Strhodes continue; 805135446Strhodes 806170222Sdougb if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) { 807170222Sdougb setup_listenon(mgr, &interface, le->port); 808170222Sdougb dolistenon = ISC_FALSE; 809170222Sdougb } 810170222Sdougb 811135446Strhodes /* 812135446Strhodes * The case of "any" IPv6 address will require 813135446Strhodes * special considerations later, so remember it. 814135446Strhodes */ 815135446Strhodes if (family == AF_INET6 && ipv6only && ipv6pktinfo && 816135446Strhodes listenon_is_ip6_any(le)) 817135446Strhodes ipv6_wildcard = ISC_TRUE; 818135446Strhodes 819135446Strhodes /* 820135446Strhodes * When adjusting interfaces with extra a listening 821135446Strhodes * list, see if the address matches the extra list. 822135446Strhodes * If it does, and is also covered by a wildcard 823135446Strhodes * interface, we need to listen on the address 824135446Strhodes * explicitly. 825135446Strhodes */ 826135446Strhodes if (adjusting == ISC_TRUE) { 827135446Strhodes ns_listenelt_t *ele; 828135446Strhodes 829135446Strhodes match = 0; 830135446Strhodes for (ele = ISC_LIST_HEAD(ext_listen->elts); 831135446Strhodes ele != NULL; 832135446Strhodes ele = ISC_LIST_NEXT(ele, link)) { 833165071Sdougb (void)dns_acl_match(&listen_netaddr, 834165071Sdougb NULL, ele->acl, 835165071Sdougb NULL, &match, NULL); 836193149Sdougb if (match > 0 && 837193149Sdougb (ele->port == le->port || 838193149Sdougb ele->port == 0)) 839135446Strhodes break; 840135446Strhodes else 841135446Strhodes match = 0; 842135446Strhodes } 843135446Strhodes if (ipv6_wildcard == ISC_TRUE && match == 0) 844135446Strhodes continue; 845135446Strhodes } 846135446Strhodes 847135446Strhodes ifp = find_matching_interface(mgr, &listen_sockaddr); 848135446Strhodes if (ifp != NULL) { 849135446Strhodes ifp->generation = mgr->generation; 850135446Strhodes } else { 851135446Strhodes char sabuf[ISC_SOCKADDR_FORMATSIZE]; 852135446Strhodes 853135446Strhodes if (adjusting == ISC_FALSE && 854135446Strhodes ipv6_wildcard == ISC_TRUE) 855135446Strhodes continue; 856135446Strhodes 857135446Strhodes if (log_explicit && family == AF_INET6 && 858135446Strhodes !adjusting && listenon_is_ip6_any(le)) { 859135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, 860135446Strhodes verbose ? ISC_LOG_INFO : 861135446Strhodes ISC_LOG_DEBUG(1), 862135446Strhodes "IPv6 socket API is " 863135446Strhodes "incomplete; explicitly " 864135446Strhodes "binding to each IPv6 " 865135446Strhodes "address separately"); 866135446Strhodes log_explicit = ISC_FALSE; 867135446Strhodes } 868135446Strhodes isc_sockaddr_format(&listen_sockaddr, 869135446Strhodes sabuf, sizeof(sabuf)); 870135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, 871135446Strhodes ISC_LOG_INFO, 872135446Strhodes "%s" 873135446Strhodes "listening on %s interface " 874135446Strhodes "%s, %s", 875135446Strhodes (adjusting == ISC_TRUE) ? 876135446Strhodes "additionally " : "", 877135446Strhodes (family == AF_INET) ? 878135446Strhodes "IPv4" : "IPv6", 879135446Strhodes interface.name, sabuf); 880135446Strhodes 881135446Strhodes result = ns_interface_setup(mgr, 882135446Strhodes &listen_sockaddr, 883135446Strhodes interface.name, 884135446Strhodes &ifp, 885135446Strhodes (adjusting == ISC_TRUE) ? 886135446Strhodes ISC_FALSE : 887135446Strhodes ISC_TRUE); 888135446Strhodes 889135446Strhodes if (result != ISC_R_SUCCESS) { 890135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, 891135446Strhodes ISC_LOG_ERROR, 892135446Strhodes "creating %s interface " 893135446Strhodes "%s failed; interface " 894135446Strhodes "ignored", 895135446Strhodes (family == AF_INET) ? 896135446Strhodes "IPv4" : "IPv6", 897135446Strhodes interface.name); 898135446Strhodes } 899135446Strhodes /* Continue. */ 900135446Strhodes } 901135446Strhodes 902135446Strhodes } 903135446Strhodes continue; 904135446Strhodes 905135446Strhodes ignore_interface: 906135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, 907135446Strhodes ISC_LOG_ERROR, 908135446Strhodes "ignoring %s interface %s: %s", 909135446Strhodes (family == AF_INET) ? "IPv4" : "IPv6", 910135446Strhodes interface.name, isc_result_totext(result)); 911135446Strhodes continue; 912135446Strhodes } 913135446Strhodes if (result != ISC_R_NOMORE) 914135446Strhodes UNEXPECTED_ERROR(__FILE__, __LINE__, 915135446Strhodes "interface iteration failed: %s", 916135446Strhodes isc_result_totext(result)); 917186462Sdougb else 918135446Strhodes result = ISC_R_SUCCESS; 919135446Strhodes cleanup_iter: 920135446Strhodes isc_interfaceiter_destroy(&iter); 921135446Strhodes return (result); 922135446Strhodes} 923135446Strhodes 924135446Strhodesstatic void 925135446Strhodesns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen, 926135446Strhodes isc_boolean_t verbose) 927135446Strhodes{ 928135446Strhodes isc_boolean_t purge = ISC_TRUE; 929135446Strhodes 930135446Strhodes REQUIRE(NS_INTERFACEMGR_VALID(mgr)); 931135446Strhodes 932135446Strhodes mgr->generation++; /* Increment the generation count. */ 933135446Strhodes 934135446Strhodes if (do_scan(mgr, ext_listen, verbose) != ISC_R_SUCCESS) 935135446Strhodes purge = ISC_FALSE; 936135446Strhodes 937135446Strhodes /* 938135446Strhodes * Now go through the interface list and delete anything that 939135446Strhodes * does not have the current generation number. This is 940135446Strhodes * how we catch interfaces that go away or change their 941135446Strhodes * addresses. 942135446Strhodes */ 943135446Strhodes if (purge) 944135446Strhodes purge_old_interfaces(mgr); 945135446Strhodes 946135446Strhodes /* 947135446Strhodes * Warn if we are not listening on any interface, unless 948186462Sdougb * we're in lwresd-only mode, in which case that is to 949135446Strhodes * be expected. 950135446Strhodes */ 951135446Strhodes if (ext_listen == NULL && 952135446Strhodes ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) { 953135446Strhodes isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING, 954135446Strhodes "not listening on any interfaces"); 955135446Strhodes } 956135446Strhodes} 957135446Strhodes 958135446Strhodesvoid 959135446Strhodesns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) { 960135446Strhodes ns_interfacemgr_scan0(mgr, NULL, verbose); 961135446Strhodes} 962135446Strhodes 963135446Strhodesvoid 964135446Strhodesns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list, 965135446Strhodes isc_boolean_t verbose) 966135446Strhodes{ 967135446Strhodes ns_interfacemgr_scan0(mgr, list, verbose); 968135446Strhodes} 969135446Strhodes 970135446Strhodesvoid 971135446Strhodesns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) { 972135446Strhodes LOCK(&mgr->lock); 973135446Strhodes ns_listenlist_detach(&mgr->listenon4); 974135446Strhodes ns_listenlist_attach(value, &mgr->listenon4); 975135446Strhodes UNLOCK(&mgr->lock); 976135446Strhodes} 977135446Strhodes 978135446Strhodesvoid 979135446Strhodesns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) { 980135446Strhodes LOCK(&mgr->lock); 981135446Strhodes ns_listenlist_detach(&mgr->listenon6); 982135446Strhodes ns_listenlist_attach(value, &mgr->listenon6); 983135446Strhodes UNLOCK(&mgr->lock); 984135446Strhodes} 985135446Strhodes 986135446Strhodesvoid 987135446Strhodesns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) { 988135446Strhodes ns_interface_t *interface; 989135446Strhodes 990135446Strhodes LOCK(&mgr->lock); 991135446Strhodes interface = ISC_LIST_HEAD(mgr->interfaces); 992135446Strhodes while (interface != NULL) { 993135446Strhodes if (interface->clientmgr != NULL) 994135446Strhodes ns_client_dumprecursing(f, interface->clientmgr); 995135446Strhodes interface = ISC_LIST_NEXT(interface, link); 996135446Strhodes } 997135446Strhodes UNLOCK(&mgr->lock); 998135446Strhodes} 999170222Sdougb 1000170222Sdougbisc_boolean_t 1001170222Sdougbns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) { 1002170222Sdougb isc_sockaddr_t *old; 1003170222Sdougb 1004170222Sdougb for (old = ISC_LIST_HEAD(mgr->listenon); 1005170222Sdougb old != NULL; 1006170222Sdougb old = ISC_LIST_NEXT(old, link)) 1007170222Sdougb if (isc_sockaddr_equal(old, addr)) 1008170222Sdougb return (ISC_TRUE); 1009170222Sdougb return (ISC_FALSE); 1010170222Sdougb} 1011