interfacemgr.c revision 55670a1e5517e9587171e9f41dc8f3e40b6fcfef
/*
* Copyright (C) 2004-2009, 2011 Internet Systems Consortium, Inc. ("ISC")
* Copyright (C) 1999-2002 Internet Software Consortium.
*
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
* REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
* AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
* INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
* LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
* OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
* PERFORMANCE OF THIS SOFTWARE.
*/
/* $Id: interfacemgr.c,v 1.101 2011/11/09 18:44:03 each Exp $ */
/*! \file */
#include <config.h>
#include <isc/interfaceiter.h>
#include <dns/dispatch.h>
#include <named/interfacemgr.h>
#define IFMGR_COMMON_LOGARGS \
/*% nameserver interface manager structure */
struct ns_interfacemgr {
unsigned int magic; /*%< Magic number. */
int references;
unsigned int generation; /*%< Current generation no. */
};
static void
static void
{
return (ISC_R_NOMEMORY);
if (result != ISC_R_SUCCESS)
goto cleanup_mem;
/*
* The listen-on lists are initially empty.
*/
if (result != ISC_R_SUCCESS)
goto cleanup_mem;
if (result != ISC_R_SUCCESS)
goto cleanup_listenon;
return (ISC_R_SUCCESS);
return (result);
}
static void
}
}
void
source->references++;
}
void
target->references--;
if (target->references == 0)
if (need_destroy)
}
void
/*%
* Shut down and detach all interfaces.
* By incrementing the generation count, we make purge_old_interfaces()
* consider all interfaces "old".
*/
mgr->generation++;
}
static isc_result_t
{
int disp;
return (ISC_R_NOMEMORY);
if (result != ISC_R_SUCCESS)
goto lock_create_failure;
if (result != ISC_R_SUCCESS) {
"ns_clientmgr_create() failed: %s",
goto clientmgr_create_failure;
}
/*
* Create a single TCP client object. It will replace itself
* with a new one as soon as it gets a connection, so the actual
* connections will be handled in parallel even though there is
* only one client initially.
*/
ifp->ntcpcurrent = 0;
ifp->nudpdispatch = 0;
return (ISC_R_SUCCESS);
return (ISC_R_UNEXPECTED);
}
static isc_result_t
unsigned int attrs;
unsigned int attrmask;
int disp, i;
attrs = 0;
else
attrmask = 0;
4096, 1000, 32768, 8219, 8237,
disp == 0
? NULL
: ifp->udpdispatch[0]);
if (result != ISC_R_SUCCESS) {
"could not listen on UDP socket: %s",
goto udp_dispatch_failure;
}
}
if (result != ISC_R_SUCCESS) {
"UDP ns_clientmgr_createclients(): %s",
goto addtodispatch_failure;
}
return (ISC_R_SUCCESS);
for (i = disp - 1; i <= 0; i--) {
}
ifp->nudpdispatch = 0;
return (result);
}
static isc_result_t
/*
* Open a TCP socket.
*/
if (result != ISC_R_SUCCESS) {
"creating TCP socket: %s",
goto tcp_socket_failure;
}
#ifndef ISC_ALLOW_MAPPED
#endif
if (result != ISC_R_SUCCESS) {
"binding TCP socket: %s",
goto tcp_bind_failure;
}
if (result != ISC_R_SUCCESS) {
"listening on TCP socket: %s",
goto tcp_listen_failure;
}
/*
* result.
*/
ISC_TRUE);
if (result != ISC_R_SUCCESS) {
"TCP ns_clientmgr_createclients(): %s",
goto accepttcp_failure;
}
return (ISC_R_SUCCESS);
return (ISC_R_SUCCESS);
}
static isc_result_t
{
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
goto cleanup_interface;
if (accept_tcp == ISC_TRUE) {
if (result != ISC_R_SUCCESS) {
/*
* 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.
*/
}
}
return (result);
return (result);
}
void
}
static void
int disp;
}
}
void
source->references++;
}
void
target->references--;
if (target->references == 0)
if (need_destroy)
}
/*%
* 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 *
break;
}
return (ifp);
}
/*%
* Remove any interfaces whose generation number is not the current one.
*/
static void
char sabuf[256];
"no longer listening on %s", sabuf);
}
}
}
static isc_result_t
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
static isc_boolean_t
}
static isc_result_t
unsigned int prefixlen;
/* First add localhost address */
if (result != ISC_R_SUCCESS)
return (result);
/* Then add localnets prefix */
&prefixlen);
/* Non contiguous netmasks not allowed by IPv6 arch. */
return (result);
if (result != ISC_R_SUCCESS) {
"omitting IPv4 interface %s from "
"localnets ACL: %s",
return (ISC_R_SUCCESS);
}
if (result != ISC_R_SUCCESS)
return (result);
return (ISC_R_SUCCESS);
}
static void
{
return;
break;
else
}
static void
}
}
static isc_result_t
{
if (ext_listen != NULL)
if (isc_net_probeipv6() == ISC_R_SUCCESS)
#ifdef WANT_IPV6
else
"no IPv6 interfaces found");
#endif
if (isc_net_probeipv4() == ISC_R_SUCCESS)
else
"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
isc_net_probe_ipv6only() != ISC_R_SUCCESS) {
}
#endif
}
if (!listenon_is_ip6_any(le))
continue;
in6a = in6addr_any;
} else {
"listening on IPv6 "
"interfaces, port %u",
"<any>", &ifp,
ISC_TRUE);
if (result == ISC_R_SUCCESS)
else
"listening on all IPv6 "
"interfaces failed");
/* Continue. */
}
}
}
if (result != ISC_R_SUCCESS)
return (result);
if (result != ISC_R_SUCCESS)
goto cleanup_iter;
if (result != ISC_R_SUCCESS)
goto cleanup_iter;
}
result == ISC_R_SUCCESS;
{
unsigned int family;
if (result != ISC_R_SUCCESS)
break;
continue;
continue;
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.
*/
continue;
}
continue;
}
if (result != ISC_R_SUCCESS)
goto ignore_interface;
}
{
int match;
/*
* combination.
*/
} else {
}
/*
* See if the address matches the listen-on statement;
* if not, ignore the interface.
*/
if (match <= 0)
continue;
}
/*
* The case of "any" IPv6 address will require
* special considerations later, so remember it.
*/
/*
* 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.
*/
match = 0;
(void)dns_acl_match(&listen_netaddr,
if (match > 0 &&
break;
else
match = 0;
}
continue;
}
} else {
char sabuf[ISC_SOCKADDR_FORMATSIZE];
continue;
verbose ? ISC_LOG_INFO :
ISC_LOG_DEBUG(1),
"IPv6 socket API is "
"incomplete; explicitly "
"binding to each IPv6 "
"address separately");
}
"%s"
"listening on %s interface "
"%s, %s",
"additionally " : "",
"IPv4" : "IPv6",
&ifp,
ISC_TRUE);
if (result != ISC_R_SUCCESS) {
"creating %s interface "
"%s failed; interface "
"ignored",
"IPv4" : "IPv6",
}
/* Continue. */
}
}
continue;
"ignoring %s interface %s: %s",
continue;
}
if (result != ISC_R_NOMORE)
"interface iteration failed: %s",
else
return (result);
}
static void
{
/*
* 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)
/*
* 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 &&
"not listening on any interfaces");
}
}
void
}
void
{
}
void
}
void
}
void
}
}
return (ISC_TRUE);
return (ISC_FALSE);
}