interfacemgr.c revision a98f70acc8d36bf73c000808ffed455ad8f15b02
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews/*
a7038d1a0513c8e804937ebc95fc9cb3a46c04f5Mark Andrews * Copyright (C) 2004-2009, 2011-2014 Internet Systems Consortium, Inc. ("ISC")
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * Copyright (C) 1999-2002 Internet Software Consortium.
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews *
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews * Permission to use, copy, modify, and/or distribute this software for any
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews * purpose with or without fee is hereby granted, provided that the above
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence * copyright notice and this permission notice appear in all copies.
15a44745412679c30a6d022733925af70a38b715David Lawrence *
15a44745412679c30a6d022733925af70a38b715David Lawrence * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
15a44745412679c30a6d022733925af70a38b715David Lawrence * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
15a44745412679c30a6d022733925af70a38b715David Lawrence * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
15a44745412679c30a6d022733925af70a38b715David Lawrence * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15a44745412679c30a6d022733925af70a38b715David Lawrence * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15a44745412679c30a6d022733925af70a38b715David Lawrence * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15a44745412679c30a6d022733925af70a38b715David Lawrence * PERFORMANCE OF THIS SOFTWARE.
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews */
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews/* $Id: interfacemgr.c,v 1.101 2011/11/09 18:44:03 each Exp $ */
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley/*! \file */
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley#include <config.h>
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley#include <isc/interfaceiter.h>
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#include <isc/os.h>
854d0238dbc2908490197984b3b9d558008a53dfMark Andrews#include <isc/string.h>
854d0238dbc2908490197984b3b9d558008a53dfMark Andrews#include <isc/task.h>
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#include <isc/util.h>
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff
6324997211a5e2d82528dcde98e8981190a35faeMichael Graff#include <dns/acl.h>
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff#include <dns/dispatch.h>
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#include <named/client.h>
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#include <named/log.h>
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#include <named/interfacemgr.h>
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#include <named/server.h>
63430de3450a99b7ae0cb05a95a26cff8cc66358David Lawrence
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#ifdef HAVE_NET_ROUTE_H
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#include <net/route.h>
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley#if defined(RTM_VERSION) && defined(RTM_NEWADDR) && defined(RTM_DELADDR)
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#define USE_ROUTE_SOCKET 1
ae114ded82e773a4d9058f833f964a17514712a8Brian Wellington#define ROUTE_SOCKET_PROTOCOL PF_ROUTE
ae114ded82e773a4d9058f833f964a17514712a8Brian Wellington#define MSGHDR rt_msghdr
bddfe77128b0f16af263ff149db40f0d885f43d0Mark Andrews#define MSGTYPE rtm_type
ae114ded82e773a4d9058f833f964a17514712a8Brian Wellington#endif
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#endif
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#if defined(HAVE_LINUX_NETLINK_H) && defined(HAVE_LINUX_RTNETLINK_H)
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington#include <linux/netlink.h>
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington#include <linux/rtnetlink.h>
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#if defined(RTM_NEWADDR) && defined(RTM_DELADDR)
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence#define USE_ROUTE_SOCKET 1
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#define ROUTE_SOCKET_PROTOCOL PF_NETLINK
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews#define MSGHDR nlmsghdr
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#define MSGTYPE nlmsg_type
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#endif
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#endif
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#ifdef TUNE_LARGE
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington#define UDPBUFFERS 32768
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington#else
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#define UDPBUFFERS 1000
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#endif /* TUNE_LARGE */
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#define IFMGR_MAGIC ISC_MAGIC('I', 'F', 'M', 'G')
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#define NS_INTERFACEMGR_VALID(t) ISC_MAGIC_VALID(t, IFMGR_MAGIC)
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington#define IFMGR_COMMON_LOGARGS \
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews ns_g_lctx, NS_LOGCATEGORY_NETWORK, NS_LOGMODULE_INTERFACEMGR
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence/*% nameserver interface manager structure */
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrencestruct ns_interfacemgr {
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence unsigned int magic; /*%< Magic number. */
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington int references;
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington isc_mutex_t lock;
5eb91bd90e3ad3426e5e3213031556a737cf3809Mark Andrews isc_mem_t * mctx; /*%< Memory context. */
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews isc_taskmgr_t * taskmgr; /*%< Task manager. */
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews isc_socketmgr_t * socketmgr; /*%< Socket manager. */
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews dns_dispatchmgr_t * dispatchmgr;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence unsigned int generation; /*%< Current generation no. */
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ns_listenlist_t * listenon4;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ns_listenlist_t * listenon6;
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington dns_aclenv_t aclenv; /*%< Localhost/localnets ACLs */
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington ISC_LIST(ns_interface_t) interfaces; /*%< List of interfaces. */
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington ISC_LIST(isc_sockaddr_t) listenon;
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#ifdef USE_ROUTE_SOCKET
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington isc_task_t * task;
c46f10e4a1702191b003cf8f8fc5059c15d29c48Mark Andrews isc_socket_t * route;
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews unsigned char buf[2048];
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews#endif
63430de3450a99b7ae0cb05a95a26cff8cc66358David Lawrence};
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews
63430de3450a99b7ae0cb05a95a26cff8cc66358David Lawrencestatic void
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrewspurge_old_interfaces(ns_interfacemgr_t *mgr);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrewsstatic void
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrenceclearlistenon(ns_interfacemgr_t *mgr);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#ifdef USE_ROUTE_SOCKET
add4043305ca411202ed9cf1929a4179016515ceBrian Wellingtonstatic void
add4043305ca411202ed9cf1929a4179016515ceBrian Wellingtonroute_event(isc_task_t *task, isc_event_t *event) {
5eb91bd90e3ad3426e5e3213031556a737cf3809Mark Andrews isc_socketevent_t *sevent = NULL;
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews ns_interfacemgr_t *mgr = NULL;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews isc_region_t r;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews isc_result_t result;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence struct MSGHDR *rtm;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence isc_boolean_t done = ISC_TRUE;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence UNUSED(task);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence REQUIRE(event->ev_type == ISC_SOCKEVENT_RECVDONE);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence mgr = event->ev_arg;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence sevent = (isc_socketevent_t *)event;
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington
add4043305ca411202ed9cf1929a4179016515ceBrian Wellington if (sevent->result != ISC_R_SUCCESS) {
5eb91bd90e3ad3426e5e3213031556a737cf3809Mark Andrews if (sevent->result != ISC_R_CANCELED)
9ac7076ebad044afb15e9e2687e3696868778538Mark Andrews isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews "automatic interface scanning "
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews "terminated: %s",
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence isc_result_totext(sevent->result));
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ns_interfacemgr_detach(&mgr);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence isc_event_free(&event);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence return;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews }
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff rtm = (struct MSGHDR *)mgr->buf;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence#ifdef RTM_VERSION
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley if (rtm->rtm_version != RTM_VERSION) {
91cd0f93ad34d23e8b09dca337120f64fbe8f0a1Andreas Gustafsson isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews "automatic interface rescanning disabled: "
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews "rtm->rtm_version mismatch (%u != %u) "
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews "recompile required", rtm->rtm_version,
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews RTM_VERSION);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews ns_interfacemgr_detach(&mgr);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews isc_event_free(&event);
b589e90689c6e87bf9608424ca8d99571c18bc61Mark Andrews return;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews }
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#endif
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence switch (rtm->MSGTYPE) {
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence case RTM_NEWADDR:
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence case RTM_DELADDR:
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews if (mgr->route != NULL && ns_g_server->interface_auto)
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews ns_server_scan_interfaces(ns_g_server);
5901928ef856543882f38b2318e8991ce2644d2bMark Andrews break;
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson default:
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews break;
2cd8a160b9e2c0c7a016b534652b5c909f36ed4aMark Andrews }
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews LOCK(&mgr->lock);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence if (mgr->route != NULL) {
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence /*
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence * Look for next route event.
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews */
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews r.base = mgr->buf;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews r.length = sizeof(mgr->buf);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews route_event, mgr);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence if (result == ISC_R_SUCCESS)
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence done = ISC_FALSE;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence }
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews UNLOCK(&mgr->lock);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews if (done)
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews ns_interfacemgr_detach(&mgr);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews isc_event_free(&event);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence return;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence}
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#endif
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrewsisc_result_t
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrewsns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews isc_socketmgr_t *socketmgr,
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews dns_dispatchmgr_t *dispatchmgr,
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence isc_task_t *task, ns_interfacemgr_t **mgrp)
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence{
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence isc_result_t result;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews ns_interfacemgr_t *mgr;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
5d83b561ad7eb84885a8ec63dee4c51b335f067aBrian Wellington#ifndef USE_ROUTE_SOCKET
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews UNUSED(task);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#endif
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews REQUIRE(mctx != NULL);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews REQUIRE(mgrp != NULL);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews REQUIRE(*mgrp == NULL);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence mgr = isc_mem_get(mctx, sizeof(*mgr));
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence if (mgr == NULL)
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews return (ISC_R_NOMEMORY);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
fad44a20eede1bbc66716241dede225500c91caaAndreas Gustafsson mgr->mctx = NULL;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews isc_mem_attach(mctx, &mgr->mctx);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence result = isc_mutex_init(&mgr->lock);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence if (result != ISC_R_SUCCESS)
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence goto cleanup_mem;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley mgr->taskmgr = taskmgr;
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley mgr->socketmgr = socketmgr;
fad44a20eede1bbc66716241dede225500c91caaAndreas Gustafsson mgr->dispatchmgr = dispatchmgr;
fad44a20eede1bbc66716241dede225500c91caaAndreas Gustafsson mgr->generation = 1;
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson mgr->listenon4 = NULL;
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley mgr->listenon6 = NULL;
5fc7ba3e1ac5d72239e9971e0f469dd5796738f9Andreas Gustafsson
fad44a20eede1bbc66716241dede225500c91caaAndreas Gustafsson ISC_LIST_INIT(mgr->interfaces);
fad44a20eede1bbc66716241dede225500c91caaAndreas Gustafsson ISC_LIST_INIT(mgr->listenon);
fad44a20eede1bbc66716241dede225500c91caaAndreas Gustafsson
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence /*
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews * The listen-on lists are initially empty.
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews */
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence result = ns_listenlist_create(mctx, &mgr->listenon4);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence if (result != ISC_R_SUCCESS)
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence goto cleanup_mem;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews ns_listenlist_attach(mgr->listenon4, &mgr->listenon6);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson result = dns_aclenv_init(mctx, &mgr->aclenv);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews if (result != ISC_R_SUCCESS)
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews goto cleanup_listenon;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#ifdef HAVE_GEOIP
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence mgr->aclenv.geoip = ns_g_geoip;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#endif
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley
5eb91bd90e3ad3426e5e3213031556a737cf3809Mark Andrews#ifdef USE_ROUTE_SOCKET
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson mgr->route = NULL;
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson result = isc_socket_create(mgr->socketmgr, ROUTE_SOCKET_PROTOCOL,
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson isc_sockettype_raw, &mgr->route);
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson switch (result) {
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson case ISC_R_NOPERM:
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson case ISC_R_SUCCESS:
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson case ISC_R_NOTIMPLEMENTED:
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson case ISC_R_FAMILYNOSUPPORT:
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson break;
a3c9e34301218c7092cd8b6add6eec0957ab5483Andreas Gustafsson default:
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley goto cleanup_aclenv;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews }
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff mgr->task = NULL;
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence if (mgr->route != NULL)
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews isc_task_attach(task, &mgr->task);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews mgr->references = (mgr->route != NULL) ? 2 : 1;
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#else
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews mgr->references = 1;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#endif
1ef8965366d91e02a4672c35a187d30aa4a4c72cMark Andrews mgr->magic = IFMGR_MAGIC;
ae114ded82e773a4d9058f833f964a17514712a8Brian Wellington *mgrp = mgr;
ae114ded82e773a4d9058f833f964a17514712a8Brian Wellington
ae114ded82e773a4d9058f833f964a17514712a8Brian Wellington#ifdef USE_ROUTE_SOCKET
94a08e09db3dc844b6ee4841c368a2d7074a9c3fAndreas Gustafsson if (mgr->route != NULL) {
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence isc_region_t r = { mgr->buf, sizeof(mgr->buf) };
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence result = isc_socket_recv(mgr->route, &r, 1, mgr->task,
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence route_event, mgr);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews if (result != ISC_R_SUCCESS) {
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews isc_task_detach(&mgr->task);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews isc_socket_detach(&mgr->route);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ns_interfacemgr_detach(&mgr);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews }
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews }
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#endif
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews return (ISC_R_SUCCESS);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
6e49e91bd08778d7eae45a2229dcf41ed97cc636David Lawrence#ifdef USE_ROUTE_SOCKET
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews cleanup_aclenv:
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff dns_aclenv_destroy(&mgr->aclenv);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#endif
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews cleanup_listenon:
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews ns_listenlist_detach(&mgr->listenon4);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews ns_listenlist_detach(&mgr->listenon6);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence cleanup_mem:
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence return (result);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews}
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrewsstatic void
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrewsns_interfacemgr_destroy(ns_interfacemgr_t *mgr) {
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff REQUIRE(NS_INTERFACEMGR_VALID(mgr));
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#ifdef USE_ROUTE_SOCKET
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews if (mgr->route != NULL)
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews isc_socket_detach(&mgr->route);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence if (mgr->task != NULL)
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence isc_task_detach(&mgr->task);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence#endif
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews dns_aclenv_destroy(&mgr->aclenv);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff ns_listenlist_detach(&mgr->listenon4);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews ns_listenlist_detach(&mgr->listenon6);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews clearlistenon(mgr);
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff DESTROYLOCK(&mgr->lock);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews mgr->magic = 0;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews isc_mem_putanddetach(&mgr->mctx, mgr, sizeof(*mgr));
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews}
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graffdns_aclenv_t *
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrencens_interfacemgr_getaclenv(ns_interfacemgr_t *mgr) {
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews return (&mgr->aclenv);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews}
cdc50af0bff41accc02c613b9c6d8cd41b171ffeBrian Wellington
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrewsvoid
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrewsns_interfacemgr_attach(ns_interfacemgr_t *source, ns_interfacemgr_t **target) {
b589e90689c6e87bf9608424ca8d99571c18bc61Mark Andrews REQUIRE(NS_INTERFACEMGR_VALID(source));
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews LOCK(&source->lock);
94a08e09db3dc844b6ee4841c368a2d7074a9c3fAndreas Gustafsson INSIST(source->references > 0);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence source->references++;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence UNLOCK(&source->lock);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence *target = source;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews}
cdc50af0bff41accc02c613b9c6d8cd41b171ffeBrian Wellington
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrewsvoid
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrewsns_interfacemgr_detach(ns_interfacemgr_t **targetp) {
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews isc_result_t need_destroy = ISC_FALSE;
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews ns_interfacemgr_t *target = *targetp;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews REQUIRE(target != NULL);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews REQUIRE(NS_INTERFACEMGR_VALID(target));
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews LOCK(&target->lock);
4529cdaedaf1a0a5f8ff89aeca510b7a4475446cBob Halley REQUIRE(target->references > 0);
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence target->references--;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews if (target->references == 0)
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews need_destroy = ISC_TRUE;
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews UNLOCK(&target->lock);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews if (need_destroy)
41aad56b6cc458cbf7b8483576d990a77ae9bac2Andreas Gustafsson ns_interfacemgr_destroy(target);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews *targetp = NULL;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews}
d981ca645597116d227a48bf37cc5edc061c854dBob Halley
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrewsvoid
b589e90689c6e87bf9608424ca8d99571c18bc61Mark Andrewsns_interfacemgr_shutdown(ns_interfacemgr_t *mgr) {
b589e90689c6e87bf9608424ca8d99571c18bc61Mark Andrews REQUIRE(NS_INTERFACEMGR_VALID(mgr));
40f53fa8d9c6a4fc38c0014495e7a42b08f52481David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence /*%
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence * Shut down and detach all interfaces.
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence * By incrementing the generation count, we make purge_old_interfaces()
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews * consider all interfaces "old".
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews */
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews mgr->generation++;
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews#ifdef USE_ROUTE_SOCKET
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews LOCK(&mgr->lock);
5901928ef856543882f38b2318e8991ce2644d2bMark Andrews if (mgr->route != NULL) {
41aad56b6cc458cbf7b8483576d990a77ae9bac2Andreas Gustafsson isc_socket_cancel(mgr->route, mgr->task, ISC_SOCKCANCEL_RECV);
41aad56b6cc458cbf7b8483576d990a77ae9bac2Andreas Gustafsson isc_socket_detach(&mgr->route);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews isc_task_detach(&mgr->task);
8d3e74b1683f714a484bbcf73249e8ee470e36d7Mark Andrews }
90e303b114e56db5809fdd19805243457fa43cd9Olafur Gudmundsson UNLOCK(&mgr->lock);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews#endif
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews purge_old_interfaces(mgr);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff}
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence
373ce67419680a398ba3dc51a14a486caaf0afb0Mark Andrews
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halleystatic isc_result_t
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrewsns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
373ce67419680a398ba3dc51a14a486caaf0afb0Mark Andrews const char *name, ns_interface_t **ifpret)
373ce67419680a398ba3dc51a14a486caaf0afb0Mark Andrews{
373ce67419680a398ba3dc51a14a486caaf0afb0Mark Andrews ns_interface_t *ifp;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington isc_result_t result;
ae114ded82e773a4d9058f833f964a17514712a8Brian Wellington int disp;
63cef8bde8b92aeb30ccdcf21d4e44c9be9cc6e3Andreas Gustafsson
63cef8bde8b92aeb30ccdcf21d4e44c9be9cc6e3Andreas Gustafsson REQUIRE(NS_INTERFACEMGR_VALID(mgr));
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence if (ifp == NULL)
5466ce3f279d9fa83ce826bcdc9482bc591152aeAndreas Gustafsson return (ISC_R_NOMEMORY);
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ifp->mgr = NULL;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ifp->generation = mgr->generation;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ifp->addr = *addr;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ifp->flags = 0;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington strncpy(ifp->name, name, sizeof(ifp->name));
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ifp->name[sizeof(ifp->name)-1] = '\0';
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ifp->clientmgr = NULL;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington result = isc_mutex_init(&ifp->lock);
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington if (result != ISC_R_SUCCESS)
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence goto lock_create_failure;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence result = ns_clientmgr_create(mgr->mctx, mgr->taskmgr,
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ns_g_timermgr,
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington &ifp->clientmgr);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence if (result != ISC_R_SUCCESS) {
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence "ns_clientmgr_create() failed: %s",
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington isc_result_totext(result));
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington goto clientmgr_create_failure;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence }
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence for (disp = 0; disp < MAX_UDP_DISPATCH; disp++)
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ifp->udpdispatch[disp] = NULL;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ifp->tcpsocket = NULL;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence /*
373ce67419680a398ba3dc51a14a486caaf0afb0Mark Andrews * Create a single TCP client object. It will replace itself
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington * with a new one as soon as it gets a connection, so the actual
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence * connections will be handled in parallel even though there is
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence * only one client initially.
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence */
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ifp->ntcptarget = 1;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ifp->ntcpcurrent = 0;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ifp->nudpdispatch = 0;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ifp->dscp = -1;
373ce67419680a398ba3dc51a14a486caaf0afb0Mark Andrews
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews ISC_LINK_INIT(ifp, link);
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff ns_interfacemgr_attach(mgr, &ifp->mgr);
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence ISC_LIST_APPEND(mgr->interfaces, ifp, link);
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ifp->references = 1;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ifp->magic = IFACE_MAGIC;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews *ifpret = ifp;
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews return (ISC_R_SUCCESS);
b589e90689c6e87bf9608424ca8d99571c18bc61Mark Andrews
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington clientmgr_create_failure:
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington DESTROYLOCK(&ifp->lock);
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington lock_create_failure:
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews ifp->magic = 0;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence return (ISC_R_UNEXPECTED);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence}
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellingtonstatic isc_result_t
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellingtonns_interface_listenudp(ns_interface_t *ifp) {
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington isc_result_t result;
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews unsigned int attrs;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington unsigned int attrmask;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington int disp, i;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence attrs = 0;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence attrs |= DNS_DISPATCHATTR_UDP;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington if (isc_sockaddr_pf(&ifp->addr) == AF_INET)
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington attrs |= DNS_DISPATCHATTR_IPV4;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington else
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence attrs |= DNS_DISPATCHATTR_IPV6;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence attrs |= DNS_DISPATCHATTR_NOLISTEN;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence attrmask = 0;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington attrmask |= DNS_DISPATCHATTR_UDP | DNS_DISPATCHATTR_TCP;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington attrmask |= DNS_DISPATCHATTR_IPV4 | DNS_DISPATCHATTR_IPV6;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence ifp->nudpdispatch = ISC_MIN(ns_g_udpdisp, MAX_UDP_DISPATCH);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence for (disp = 0; disp < ifp->nudpdispatch; disp++) {
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence result = dns_dispatch_getudp_dup(ifp->mgr->dispatchmgr,
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ns_g_socketmgr,
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ns_g_taskmgr, &ifp->addr,
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington 4096, UDPBUFFERS,
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence 32768, 8219, 8237,
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence attrs, attrmask,
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence &ifp->udpdispatch[disp],
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington disp == 0
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ? NULL
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington : ifp->udpdispatch[0]);
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence if (result != ISC_R_SUCCESS) {
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence "could not listen on UDP socket: %s",
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington isc_result_totext(result));
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington goto udp_dispatch_failure;
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington }
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence }
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence
85bdc128fcda11c89ec1d76ea4221f4fa8e4fc24Mark Andrews result = ns_clientmgr_createclients(ifp->clientmgr, ifp->nudpdispatch,
85bdc128fcda11c89ec1d76ea4221f4fa8e4fc24Mark Andrews ifp, ISC_FALSE);
85bdc128fcda11c89ec1d76ea4221f4fa8e4fc24Mark Andrews if (result != ISC_R_SUCCESS) {
85bdc128fcda11c89ec1d76ea4221f4fa8e4fc24Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington "UDP ns_clientmgr_createclients(): %s",
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence isc_result_totext(result));
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence goto addtodispatch_failure;
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence }
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington return (ISC_R_SUCCESS);
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence addtodispatch_failure:
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence for (i = disp - 1; i <= 0; i--) {
652c80435a97ca558a47e2f320047b73b3626cd1David Lawrence dns_dispatch_changeattributes(ifp->udpdispatch[i], 0,
85bdc128fcda11c89ec1d76ea4221f4fa8e4fc24Mark Andrews DNS_DISPATCHATTR_NOLISTEN);
85bdc128fcda11c89ec1d76ea4221f4fa8e4fc24Mark Andrews dns_dispatch_detach(&(ifp->udpdispatch[i]));
85bdc128fcda11c89ec1d76ea4221f4fa8e4fc24Mark Andrews }
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington ifp->nudpdispatch = 0;
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff udp_dispatch_failure:
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews return (result);
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews}
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews
9281e7aa775026dc47c01745fdcc438645146877Mark Andrewsstatic isc_result_t
9281e7aa775026dc47c01745fdcc438645146877Mark Andrewsns_interface_accepttcp(ns_interface_t *ifp) {
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews isc_result_t result;
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews
f427e7850928d15ffc37b1f68c60588995c9b318Mark Andrews /*
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews * Open a TCP socket.
4529cdaedaf1a0a5f8ff89aeca510b7a4475446cBob Halley */
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence result = isc_socket_create(ifp->mgr->socketmgr,
b8dd48ecf83142f6ee7238cbd68fec455e527fc8Mark Andrews isc_sockaddr_pf(&ifp->addr),
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington isc_sockettype_tcp,
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews &ifp->tcpsocket);
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington if (result != ISC_R_SUCCESS) {
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews "creating TCP socket: %s",
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews isc_result_totext(result));
cf3f14106d082e4676431c10c54b60b9a0e9b127Brian Wellington goto tcp_socket_failure;
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley }
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews isc_socket_setname(ifp->tcpsocket, "dispatcher", NULL);
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley#ifndef ISC_ALLOW_MAPPED
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews isc_socket_ipv6only(ifp->tcpsocket, ISC_TRUE);
9281e7aa775026dc47c01745fdcc438645146877Mark Andrews#endif
94a3bcd132e515b4baa0884ba9dd0f361d2e17bcMark Andrews result = isc_socket_bind(ifp->tcpsocket, &ifp->addr,
d981ca645597116d227a48bf37cc5edc061c854dBob Halley ISC_SOCKET_REUSEADDRESS);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff if (result != ISC_R_SUCCESS) {
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
82ca33427bdd4f3bc4ed3431e86bd810fe751674Andreas Gustafsson "binding TCP socket: %s",
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley isc_result_totext(result));
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley goto tcp_bind_failure;
d981ca645597116d227a48bf37cc5edc061c854dBob Halley }
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley
d981ca645597116d227a48bf37cc5edc061c854dBob Halley if (ifp->dscp != -1)
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff isc_socket_dscp(ifp->tcpsocket, ifp->dscp);
d981ca645597116d227a48bf37cc5edc061c854dBob Halley
d981ca645597116d227a48bf37cc5edc061c854dBob Halley result = isc_socket_listen(ifp->tcpsocket, ns_g_listen);
3ddd814a97de1d152ba0913c592d6e6dc83d38a6Michael Graff if (result != ISC_R_SUCCESS) {
6d12fdf96621801e80f3f4c2a8a569fe48766a20David Lawrence isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_ERROR,
82ca33427bdd4f3bc4ed3431e86bd810fe751674Andreas Gustafsson "listening on TCP socket: %s",
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley isc_result_totext(result));
d10099d8663f4a4b21219f0c4bcc4f2b1ca1d877Bob Halley goto tcp_listen_failure;
e27a69f8bd9538e08f775265167ba6cc5f47c587Bob Halley }
e27a69f8bd9538e08f775265167ba6cc5f47c587Bob Halley
e27a69f8bd9538e08f775265167ba6cc5f47c587Bob Halley /*
419590499823ce15b5d2ad4fe71eaf04bd5a86c0Michael Graff * If/when there a multiple filters listen to the
e27a69f8bd9538e08f775265167ba6cc5f47c587Bob Halley * result.
e27a69f8bd9538e08f775265167ba6cc5f47c587Bob Halley */
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews (void)isc_socket_filter(ifp->tcpsocket, "dataready");
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews result = ns_clientmgr_createclients(ifp->clientmgr,
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews ifp->ntcptarget, ifp,
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews ISC_TRUE);
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews if (result != ISC_R_SUCCESS) {
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews UNEXPECTED_ERROR(__FILE__, __LINE__,
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews "TCP ns_clientmgr_createclients(): %s",
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews isc_result_totext(result));
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews goto accepttcp_failure;
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews }
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews return (ISC_R_SUCCESS);
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews accepttcp_failure:
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews tcp_listen_failure:
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews tcp_bind_failure:
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews isc_socket_detach(&ifp->tcpsocket);
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews tcp_socket_failure:
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews return (result);
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews}
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrewsstatic isc_result_t
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrewsns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews const char *name, ns_interface_t **ifpret,
2047977ce2dfcfe3a0fa2d638c3242841310fad3Mark Andrews isc_boolean_t accept_tcp, isc_dscp_t dscp,
854d0238dbc2908490197984b3b9d558008a53dfMark Andrews isc_boolean_t *addr_in_use)
{
isc_result_t result;
ns_interface_t *ifp = NULL;
REQUIRE(ifpret != NULL && *ifpret == NULL);
REQUIRE(addr_in_use == NULL || *addr_in_use == ISC_FALSE);
result = ns_interface_create(mgr, addr, name, &ifp);
if (result != ISC_R_SUCCESS)
return (result);
ifp->dscp = dscp;
result = ns_interface_listenudp(ifp);
if (result != ISC_R_SUCCESS) {
if ((result == ISC_R_ADDRINUSE) && (addr_in_use != NULL))
*addr_in_use = ISC_TRUE;
goto cleanup_interface;
}
if (!ns_g_notcp && accept_tcp == ISC_TRUE) {
result = ns_interface_accepttcp(ifp);
if (result != ISC_R_SUCCESS) {
if ((result == ISC_R_ADDRINUSE) &&
(addr_in_use != NULL))
*addr_in_use = ISC_TRUE;
/*
* XXXRTH We don't currently have a way to easily stop
* dispatch service, so we currently return
* ISC_R_SUCCESS (the UDP stuff will work even if TCP
* creation failed). This will be fixed later.
*/
result = ISC_R_SUCCESS;
}
}
*ifpret = ifp;
return (result);
cleanup_interface:
ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
ns_interface_detach(&ifp);
return (result);
}
void
ns_interface_shutdown(ns_interface_t *ifp) {
if (ifp->clientmgr != NULL)
ns_clientmgr_destroy(&ifp->clientmgr);
}
static void
ns_interface_destroy(ns_interface_t *ifp) {
isc_mem_t *mctx = ifp->mgr->mctx;
int disp;
REQUIRE(NS_INTERFACE_VALID(ifp));
ns_interface_shutdown(ifp);
for (disp = 0; disp < ifp->nudpdispatch; disp++)
if (ifp->udpdispatch[disp] != NULL) {
dns_dispatch_changeattributes(ifp->udpdispatch[disp], 0,
DNS_DISPATCHATTR_NOLISTEN);
dns_dispatch_detach(&(ifp->udpdispatch[disp]));
}
if (ifp->tcpsocket != NULL)
isc_socket_detach(&ifp->tcpsocket);
DESTROYLOCK(&ifp->lock);
ns_interfacemgr_detach(&ifp->mgr);
ifp->magic = 0;
isc_mem_put(mctx, ifp, sizeof(*ifp));
}
void
ns_interface_attach(ns_interface_t *source, ns_interface_t **target) {
REQUIRE(NS_INTERFACE_VALID(source));
LOCK(&source->lock);
INSIST(source->references > 0);
source->references++;
UNLOCK(&source->lock);
*target = source;
}
void
ns_interface_detach(ns_interface_t **targetp) {
isc_result_t need_destroy = ISC_FALSE;
ns_interface_t *target = *targetp;
REQUIRE(target != NULL);
REQUIRE(NS_INTERFACE_VALID(target));
LOCK(&target->lock);
REQUIRE(target->references > 0);
target->references--;
if (target->references == 0)
need_destroy = ISC_TRUE;
UNLOCK(&target->lock);
if (need_destroy)
ns_interface_destroy(target);
*targetp = NULL;
}
/*%
* Search the interface list for an interface whose address and port
* both match those of 'addr'. Return a pointer to it, or NULL if not found.
*/
static ns_interface_t *
find_matching_interface(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
ns_interface_t *ifp;
for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL;
ifp = ISC_LIST_NEXT(ifp, link)) {
if (isc_sockaddr_equal(&ifp->addr, addr))
break;
}
return (ifp);
}
/*%
* Remove any interfaces whose generation number is not the current one.
*/
static void
purge_old_interfaces(ns_interfacemgr_t *mgr) {
ns_interface_t *ifp, *next;
for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; ifp = next) {
INSIST(NS_INTERFACE_VALID(ifp));
next = ISC_LIST_NEXT(ifp, link);
if (ifp->generation != mgr->generation) {
char sabuf[256];
ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
isc_sockaddr_format(&ifp->addr, sabuf, sizeof(sabuf));
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_INFO,
"no longer listening on %s", sabuf);
ns_interface_shutdown(ifp);
ns_interface_detach(&ifp);
}
}
}
static isc_result_t
clearacl(isc_mem_t *mctx, dns_acl_t **aclp) {
dns_acl_t *newacl = NULL;
isc_result_t result;
result = dns_acl_create(mctx, 0, &newacl);
if (result != ISC_R_SUCCESS)
return (result);
dns_acl_detach(aclp);
dns_acl_attach(newacl, aclp);
dns_acl_detach(&newacl);
return (ISC_R_SUCCESS);
}
static isc_boolean_t
listenon_is_ip6_any(ns_listenelt_t *elt) {
REQUIRE(elt && elt->acl);
return dns_acl_isany(elt->acl);
}
static isc_result_t
setup_locals(ns_interfacemgr_t *mgr, isc_interface_t *interface) {
isc_result_t result;
unsigned int prefixlen;
isc_netaddr_t *netaddr;
netaddr = &interface->address;
/* First add localhost address */
prefixlen = (netaddr->family == AF_INET) ? 32 : 128;
result = dns_iptable_addprefix(mgr->aclenv.localhost->iptable,
netaddr, prefixlen, ISC_TRUE);
if (result != ISC_R_SUCCESS)
return (result);
/* Then add localnets prefix */
result = isc_netaddr_masktoprefixlen(&interface->netmask,
&prefixlen);
/* Non contiguous netmasks not allowed by IPv6 arch. */
if (result != ISC_R_SUCCESS && netaddr->family == AF_INET6)
return (result);
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
"omitting IPv4 interface %s from "
"localnets ACL: %s", interface->name,
isc_result_totext(result));
return (ISC_R_SUCCESS);
}
if (prefixlen == 0U) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
"omitting %s interface %s from localnets ACL: "
"zero prefix length detected",
(netaddr->family == AF_INET) ? "IPv4" : "IPv6",
interface->name);
return (ISC_R_SUCCESS);
}
result = dns_iptable_addprefix(mgr->aclenv.localnets->iptable,
netaddr, prefixlen, ISC_TRUE);
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
static void
setup_listenon(ns_interfacemgr_t *mgr, isc_interface_t *interface,
in_port_t port)
{
isc_sockaddr_t *addr;
isc_sockaddr_t *old;
addr = isc_mem_get(mgr->mctx, sizeof(*addr));
if (addr == NULL)
return;
isc_sockaddr_fromnetaddr(addr, &interface->address, port);
for (old = ISC_LIST_HEAD(mgr->listenon);
old != NULL;
old = ISC_LIST_NEXT(old, link))
if (isc_sockaddr_equal(addr, old))
break;
if (old != NULL)
isc_mem_put(mgr->mctx, addr, sizeof(*addr));
else
ISC_LIST_APPEND(mgr->listenon, addr, link);
}
static void
clearlistenon(ns_interfacemgr_t *mgr) {
isc_sockaddr_t *old;
old = ISC_LIST_HEAD(mgr->listenon);
while (old != NULL) {
ISC_LIST_UNLINK(mgr->listenon, old, link);
isc_mem_put(mgr->mctx, old, sizeof(*old));
old = ISC_LIST_HEAD(mgr->listenon);
}
}
static isc_result_t
do_scan(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
isc_boolean_t verbose)
{
isc_interfaceiter_t *iter = NULL;
isc_boolean_t scan_ipv4 = ISC_FALSE;
isc_boolean_t scan_ipv6 = ISC_FALSE;
isc_boolean_t adjusting = ISC_FALSE;
isc_boolean_t ipv6only = ISC_TRUE;
isc_boolean_t ipv6pktinfo = ISC_TRUE;
isc_result_t result;
isc_netaddr_t zero_address, zero_address6;
ns_listenelt_t *le;
isc_sockaddr_t listen_addr;
ns_interface_t *ifp;
isc_boolean_t log_explicit = ISC_FALSE;
isc_boolean_t dolistenon;
char sabuf[ISC_SOCKADDR_FORMATSIZE];
isc_boolean_t tried_listening;
isc_boolean_t all_addresses_in_use;
if (ext_listen != NULL)
adjusting = ISC_TRUE;
if (isc_net_probeipv6() == ISC_R_SUCCESS)
scan_ipv6 = ISC_TRUE;
#ifdef WANT_IPV6
else if (!ns_g_disable6)
isc_log_write(IFMGR_COMMON_LOGARGS,
verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
"no IPv6 interfaces found");
#endif
if (isc_net_probeipv4() == ISC_R_SUCCESS)
scan_ipv4 = ISC_TRUE;
else if (!ns_g_disable4)
isc_log_write(IFMGR_COMMON_LOGARGS,
verbose ? ISC_LOG_INFO : ISC_LOG_DEBUG(1),
"no IPv4 interfaces found");
/*
* A special, but typical case; listen-on-v6 { any; }.
* When we can make the socket IPv6-only, open a single wildcard
* socket for IPv6 communication. Otherwise, make separate socket
* for each IPv6 address in order to avoid accepting IPv4 packets
* as the form of mapped addresses unintentionally unless explicitly
* allowed.
*/
#ifndef ISC_ALLOW_MAPPED
if (scan_ipv6 == ISC_TRUE &&
isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
ipv6only = ISC_FALSE;
log_explicit = ISC_TRUE;
}
#endif
if (scan_ipv6 == ISC_TRUE &&
isc_net_probe_ipv6pktinfo() != ISC_R_SUCCESS) {
ipv6pktinfo = ISC_FALSE;
log_explicit = ISC_TRUE;
}
if (scan_ipv6 == ISC_TRUE && ipv6only && ipv6pktinfo) {
for (le = ISC_LIST_HEAD(mgr->listenon6->elts);
le != NULL;
le = ISC_LIST_NEXT(le, link)) {
struct in6_addr in6a;
if (!listenon_is_ip6_any(le))
continue;
in6a = in6addr_any;
isc_sockaddr_fromin6(&listen_addr, &in6a, le->port);
ifp = find_matching_interface(mgr, &listen_addr);
if (ifp != NULL) {
ifp->generation = mgr->generation;
if (le->dscp != -1 && ifp->dscp == -1)
ifp->dscp = le->dscp;
else if (le->dscp != ifp->dscp) {
isc_sockaddr_format(&listen_addr,
sabuf,
sizeof(sabuf));
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_WARNING,
"%s: conflicting DSCP "
"values, using %d",
sabuf, ifp->dscp);
}
} else {
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_INFO,
"listening on IPv6 "
"interfaces, port %u",
le->port);
result = ns_interface_setup(mgr, &listen_addr,
"<any>", &ifp,
ISC_TRUE,
le->dscp,
NULL);
if (result == ISC_R_SUCCESS)
ifp->flags |= NS_INTERFACEFLAG_ANYADDR;
else
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_ERROR,
"listening on all IPv6 "
"interfaces failed");
/* Continue. */
}
}
}
isc_netaddr_any(&zero_address);
isc_netaddr_any6(&zero_address6);
result = isc_interfaceiter_create(mgr->mctx, &iter);
if (result != ISC_R_SUCCESS)
return (result);
if (adjusting == ISC_FALSE) {
result = clearacl(mgr->mctx, &mgr->aclenv.localhost);
if (result != ISC_R_SUCCESS)
goto cleanup_iter;
result = clearacl(mgr->mctx, &mgr->aclenv.localnets);
if (result != ISC_R_SUCCESS)
goto cleanup_iter;
clearlistenon(mgr);
}
tried_listening = ISC_FALSE;
all_addresses_in_use = ISC_TRUE;
for (result = isc_interfaceiter_first(iter);
result == ISC_R_SUCCESS;
result = isc_interfaceiter_next(iter))
{
isc_interface_t interface;
ns_listenlist_t *ll;
unsigned int family;
result = isc_interfaceiter_current(iter, &interface);
if (result != ISC_R_SUCCESS)
break;
family = interface.address.family;
if (family != AF_INET && family != AF_INET6)
continue;
if (scan_ipv4 == ISC_FALSE && family == AF_INET)
continue;
if (scan_ipv6 == ISC_FALSE && family == AF_INET6)
continue;
/*
* Test for the address being nonzero rather than testing
* INTERFACE_F_UP, because on some systems the latter
* follows the media state and we could end up ignoring
* the interface for an entire rescan interval due to
* a temporary media glitch at rescan time.
*/
if (family == AF_INET &&
isc_netaddr_equal(&interface.address, &zero_address)) {
continue;
}
if (family == AF_INET6 &&
isc_netaddr_equal(&interface.address, &zero_address6)) {
continue;
}
if (adjusting == ISC_FALSE) {
result = setup_locals(mgr, &interface);
if (result != ISC_R_SUCCESS)
goto ignore_interface;
}
ll = (family == AF_INET) ? mgr->listenon4 : mgr->listenon6;
dolistenon = ISC_TRUE;
for (le = ISC_LIST_HEAD(ll->elts);
le != NULL;
le = ISC_LIST_NEXT(le, link))
{
int match;
isc_boolean_t ipv6_wildcard = ISC_FALSE;
isc_netaddr_t listen_netaddr;
isc_sockaddr_t listen_sockaddr;
/*
* Construct a socket address for this IP/port
* combination.
*/
if (family == AF_INET) {
isc_netaddr_fromin(&listen_netaddr,
&interface.address.type.in);
} else {
isc_netaddr_fromin6(&listen_netaddr,
&interface.address.type.in6);
isc_netaddr_setzone(&listen_netaddr,
interface.address.zone);
}
isc_sockaddr_fromnetaddr(&listen_sockaddr,
&listen_netaddr,
le->port);
/*
* See if the address matches the listen-on statement;
* if not, ignore the interface.
*/
(void)dns_acl_match(&listen_netaddr, NULL, le->acl,
&mgr->aclenv, &match, NULL);
if (match <= 0)
continue;
if (adjusting == ISC_FALSE && dolistenon == ISC_TRUE) {
setup_listenon(mgr, &interface, le->port);
dolistenon = ISC_FALSE;
}
/*
* The case of "any" IPv6 address will require
* special considerations later, so remember it.
*/
if (family == AF_INET6 && ipv6only && ipv6pktinfo &&
listenon_is_ip6_any(le))
ipv6_wildcard = ISC_TRUE;
/*
* When adjusting interfaces with extra a listening
* list, see if the address matches the extra list.
* If it does, and is also covered by a wildcard
* interface, we need to listen on the address
* explicitly.
*/
if (adjusting == ISC_TRUE) {
ns_listenelt_t *ele;
match = 0;
for (ele = ISC_LIST_HEAD(ext_listen->elts);
ele != NULL;
ele = ISC_LIST_NEXT(ele, link)) {
(void)dns_acl_match(&listen_netaddr,
NULL, ele->acl,
NULL, &match, NULL);
if (match > 0 &&
(ele->port == le->port ||
ele->port == 0))
break;
else
match = 0;
}
if (ipv6_wildcard == ISC_TRUE && match == 0)
continue;
}
ifp = find_matching_interface(mgr, &listen_sockaddr);
if (ifp != NULL) {
ifp->generation = mgr->generation;
if (le->dscp != -1 && ifp->dscp == -1)
ifp->dscp = le->dscp;
else if (le->dscp != ifp->dscp) {
isc_sockaddr_format(&listen_sockaddr,
sabuf,
sizeof(sabuf));
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_WARNING,
"%s: conflicting DSCP "
"values, using %d",
sabuf, ifp->dscp);
}
} else {
isc_boolean_t addr_in_use = ISC_FALSE;
if (adjusting == ISC_FALSE &&
ipv6_wildcard == ISC_TRUE)
continue;
if (log_explicit && family == AF_INET6 &&
!adjusting && listenon_is_ip6_any(le)) {
isc_log_write(IFMGR_COMMON_LOGARGS,
verbose ? ISC_LOG_INFO :
ISC_LOG_DEBUG(1),
"IPv6 socket API is "
"incomplete; explicitly "
"binding to each IPv6 "
"address separately");
log_explicit = ISC_FALSE;
}
isc_sockaddr_format(&listen_sockaddr,
sabuf, sizeof(sabuf));
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_INFO,
"%s"
"listening on %s interface "
"%s, %s",
(adjusting == ISC_TRUE) ?
"additionally " : "",
(family == AF_INET) ?
"IPv4" : "IPv6",
interface.name, sabuf);
result = ns_interface_setup(mgr,
&listen_sockaddr,
interface.name,
&ifp,
(adjusting == ISC_TRUE) ?
ISC_FALSE : ISC_TRUE,
le->dscp,
&addr_in_use);
tried_listening = ISC_TRUE;
if (!addr_in_use)
all_addresses_in_use = ISC_FALSE;
if (result != ISC_R_SUCCESS) {
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_ERROR,
"creating %s interface "
"%s failed; interface "
"ignored",
(family == AF_INET) ?
"IPv4" : "IPv6",
interface.name);
}
/* Continue. */
}
}
continue;
ignore_interface:
isc_log_write(IFMGR_COMMON_LOGARGS,
ISC_LOG_ERROR,
"ignoring %s interface %s: %s",
(family == AF_INET) ? "IPv4" : "IPv6",
interface.name, isc_result_totext(result));
continue;
}
if (result != ISC_R_NOMORE)
UNEXPECTED_ERROR(__FILE__, __LINE__,
"interface iteration failed: %s",
isc_result_totext(result));
else
result = ((tried_listening && all_addresses_in_use) ?
ISC_R_ADDRINUSE : ISC_R_SUCCESS);
cleanup_iter:
isc_interfaceiter_destroy(&iter);
return (result);
}
static isc_result_t
ns_interfacemgr_scan0(ns_interfacemgr_t *mgr, ns_listenlist_t *ext_listen,
isc_boolean_t verbose)
{
isc_result_t result;
isc_boolean_t purge = ISC_TRUE;
REQUIRE(NS_INTERFACEMGR_VALID(mgr));
mgr->generation++; /* Increment the generation count. */
result = do_scan(mgr, ext_listen, verbose);
if ((result != ISC_R_SUCCESS) && (result != ISC_R_ADDRINUSE))
purge = ISC_FALSE;
/*
* Now go through the interface list and delete anything that
* does not have the current generation number. This is
* how we catch interfaces that go away or change their
* addresses.
*/
if (purge)
purge_old_interfaces(mgr);
/*
* Warn if we are not listening on any interface, unless
* we're in lwresd-only mode, in which case that is to
* be expected.
*/
if (ext_listen == NULL &&
ISC_LIST_EMPTY(mgr->interfaces) && ! ns_g_lwresdonly) {
isc_log_write(IFMGR_COMMON_LOGARGS, ISC_LOG_WARNING,
"not listening on any interfaces");
}
return (result);
}
isc_boolean_t
ns_interfacemgr_islistening(ns_interfacemgr_t *mgr) {
REQUIRE(NS_INTERFACEMGR_VALID(mgr));
return (ISC_LIST_EMPTY(mgr->interfaces) ? ISC_FALSE : ISC_TRUE);
}
isc_result_t
ns_interfacemgr_scan(ns_interfacemgr_t *mgr, isc_boolean_t verbose) {
return (ns_interfacemgr_scan0(mgr, NULL, verbose));
}
isc_result_t
ns_interfacemgr_adjust(ns_interfacemgr_t *mgr, ns_listenlist_t *list,
isc_boolean_t verbose)
{
return (ns_interfacemgr_scan0(mgr, list, verbose));
}
void
ns_interfacemgr_setlistenon4(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
LOCK(&mgr->lock);
ns_listenlist_detach(&mgr->listenon4);
ns_listenlist_attach(value, &mgr->listenon4);
UNLOCK(&mgr->lock);
}
void
ns_interfacemgr_setlistenon6(ns_interfacemgr_t *mgr, ns_listenlist_t *value) {
LOCK(&mgr->lock);
ns_listenlist_detach(&mgr->listenon6);
ns_listenlist_attach(value, &mgr->listenon6);
UNLOCK(&mgr->lock);
}
void
ns_interfacemgr_dumprecursing(FILE *f, ns_interfacemgr_t *mgr) {
ns_interface_t *interface;
LOCK(&mgr->lock);
interface = ISC_LIST_HEAD(mgr->interfaces);
while (interface != NULL) {
if (interface->clientmgr != NULL)
ns_client_dumprecursing(f, interface->clientmgr);
interface = ISC_LIST_NEXT(interface, link);
}
UNLOCK(&mgr->lock);
}
isc_boolean_t
ns_interfacemgr_listeningon(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr) {
isc_sockaddr_t *old;
for (old = ISC_LIST_HEAD(mgr->listenon);
old != NULL;
old = ISC_LIST_NEXT(old, link))
if (isc_sockaddr_equal(old, addr))
return (ISC_TRUE);
return (ISC_FALSE);
}