2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-01 15:05:23 +00:00

client quotas; added reference counting to ns_interface_t

and ns_interfacemgr_t so that they can safely hold quota information
This commit is contained in:
Andreas Gustafsson
2000-01-11 21:18:22 +00:00
parent 5f2d1b96ac
commit 559b10cc8f
9 changed files with 487 additions and 196 deletions

View File

@@ -42,6 +42,7 @@
#include <named/server.h>
#include <named/update.h>
#include <named/notify.h>
#include <named/interfacemgr.h>
#define NS_CLIENT_TRACE
#ifdef NS_CLIENT_TRACE
@@ -131,6 +132,8 @@ maybe_free(ns_client_t *client) {
}
/* We have received our last event. */
ns_interface_detach(&client->interface);
ns_query_free(client);
isc_mempool_destroy(&client->sendbufs);
isc_timer_detach(&client->timer);
@@ -175,6 +178,12 @@ maybe_free(ns_client_t *client) {
UNLOCK(&manager->lock);
}
if (client->quota != NULL) {
isc_quota_release(client->quota);
client->quota = NULL;
}
CTRACE("free");
client->magic = 0;
isc_mem_put(client->mctx, client, sizeof *client);
@@ -234,20 +243,56 @@ ns_client_next(ns_client_t *client, isc_result_t result) {
client->udpsize = 512;
dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
if (client->oneshot) {
if (client->quota != NULL) {
isc_quota_release(client->quota);
client->quota = NULL;
}
if (client->mortal) {
/*
* This client object is supposed to die now, but if we
* have fewer client objects than planned due to
* quota exhaustion, don't.
*/
isc_boolean_t need_another_client = ISC_FALSE;
if (TCP_CLIENT(client)) {
LOCK(&client->interface->lock);
if (client->interface->ntcpcurrent <
client->interface->ntcptarget)
need_another_client = ISC_TRUE;
UNLOCK(&client->interface->lock);
} else {
/*
* The UDP client quota is enforced by making
* requests fail rather than by not listening
* for new ones. Therefore, there is always a
* full set of UDP clients listening.
*/
}
if (! need_another_client) {
/* XXX should put in "idle client pool" instead. */
isc_task_shutdown(client->task);
return;
}
}
if (client->dispevent != NULL) {
/*
* Give the processed dispatch event back to the dispatch.
* This tells the dispatch that we are ready to receive
* the next event.
*/
dns_dispatch_freeevent(client->dispatch, client->dispentry,
&client->dispevent);
} else if (TCP_CLIENT(client)) {
if (result == ISC_R_SUCCESS)
if (result == ISC_R_SUCCESS) {
client_read(client);
else {
} else {
/*
* There was an error processing a TCP request.
* It may have have left the connection out of
* sync. Close the connection and listen for a
* new one.
*/
if (client->tcpsocket != NULL) {
/*
* There should be no outstanding read
@@ -688,9 +733,6 @@ client_request(isc_task_t *task, isc_event_t *event) {
if (ra == ISC_TRUE)
client->attributes |= NS_CLIENTATTR_RA;
/* XXX conditionally */
(void) ns_client_replace(client);
/*
* Dispatch the request.
*/
@@ -737,7 +779,7 @@ client_timeout(isc_task_t *task, isc_event_t *event) {
static isc_result_t
client_create(ns_clientmgr_t *manager, ns_clienttype_t type,
ns_client_t **clientp)
ns_interface_t *ifp, ns_client_t **clientp)
{
ns_client_t *client;
isc_result_t result;
@@ -809,7 +851,9 @@ client_create(ns_clientmgr_t *manager, ns_clienttype_t type,
client->udpsize = 512;
client->next = NULL;
dns_name_init(&client->signername, NULL);
client->oneshot = ISC_FALSE;
client->mortal = ISC_FALSE;
client->quota = NULL;
client->interface = NULL;
ISC_LINK_INIT(client, link);
/*
@@ -821,6 +865,8 @@ client_create(ns_clientmgr_t *manager, ns_clienttype_t type,
if (result != ISC_R_SUCCESS)
goto cleanup_sendbufs;
ns_interface_attach(ifp, &client->interface);
CTRACE("create");
*clientp = client;
@@ -865,6 +911,7 @@ static void
client_newconn(isc_task_t *task, isc_event_t *event) {
ns_client_t *client = event->arg;
isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
isc_result_t result;
REQUIRE(event->type == ISC_SOCKEVENT_NEWCONN);
REQUIRE(NS_CLIENT_VALID(client));
@@ -875,6 +922,11 @@ client_newconn(isc_task_t *task, isc_event_t *event) {
INSIST(client->naccepts == 1);
client->naccepts--;
LOCK(&client->interface->lock);
INSIST(client->interface->ntcpcurrent > 0);
client->interface->ntcpcurrent--;
UNLOCK(&client->interface->lock);
if (client->shuttingdown) {
maybe_free(client);
} else if (nevent->result == ISC_R_SUCCESS) {
@@ -890,8 +942,13 @@ client_newconn(isc_task_t *task, isc_event_t *event) {
* telnetting to port 35 (once per CPU) will
* deny service to legititmate TCP clients.
*/
(void) ns_client_replace(client);
result = ns_client_replace(client, &ns_g_server->tcpquota);
if (result != ISC_R_SUCCESS) {
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_CLIENT, ISC_LOG_WARNING,
"no more TCP clients: %s",
isc_result_totext(result));
}
client_read(client);
} else {
/*
@@ -931,6 +988,9 @@ client_accept(ns_client_t *client) {
}
INSIST(client->naccepts == 0);
client->naccepts++;
LOCK(&client->interface->lock);
client->interface->ntcpcurrent++;
UNLOCK(&client->interface->lock);
}
void
@@ -953,25 +1013,52 @@ ns_client_unwait(ns_client_t *client) {
isc_result_t
ns_client_replace(ns_client_t *client) {
ns_client_getquota(ns_client_t *client, isc_quota_t *quota) {
isc_result_t result;
/*
* A client can only use one quota at a time.
* If we are already using a quota, release it.
*/
if (client->quota != NULL) {
isc_quota_release(client->quota);
client->quota = NULL;
}
result = isc_quota_reserve(quota);
if (result == ISC_R_SUCCESS) {
client->quota = quota;
} else {
return (result);
}
return (ISC_R_SUCCESS);
}
isc_result_t
ns_client_replace(ns_client_t *client, isc_quota_t *quota) {
isc_result_t result;
CTRACE("replace");
/* XXX Check quota here. */
if (quota != NULL) {
result = ns_client_getquota(client, quota);
if (result != DNS_R_SUCCESS)
return (result);
}
if (TCP_CLIENT(client)) {
result = ns_clientmgr_accepttcp(client->manager, client->tcplistener, 1);
result = ns_clientmgr_accepttcp(client->manager,
1, client->interface);
} else {
result = ns_clientmgr_addtodispatch(client->manager, 1, client->dispatch);
result = ns_clientmgr_addtodispatch(client->manager,
1, client->interface);
}
if (result != ISC_R_SUCCESS)
return (result);
/*
* The new client is ready to listen for new requests, so we
* should refrain from doing so.
* The new client is ready to listen for new requests, therefore we
* should refrain from listening from any more requests when we are
* done with this one.
*/
client->oneshot = ISC_TRUE;
client->mortal = ISC_TRUE;
return (ISC_R_SUCCESS);
}
@@ -1060,7 +1147,7 @@ ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
isc_result_t
ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n,
dns_dispatch_t *dispatch)
ns_interface_t *ifp)
{
isc_result_t result = ISC_R_SUCCESS;
unsigned int i;
@@ -1082,11 +1169,12 @@ ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n,
for (i = 0; i < n; i++) {
client = NULL;
result = client_create(manager, ns_clienttype_basic,
&client);
ifp, &client);
if (result != ISC_R_SUCCESS)
break;
dns_dispatch_attach(dispatch, &client->dispatch);
result = dns_dispatch_addrequest(dispatch, client->task,
dns_dispatch_attach(ifp->udpdispatch, &client->dispatch);
result = dns_dispatch_addrequest(client->dispatch,
client->task,
client_request,
client, &client->dispentry);
if (result != ISC_R_SUCCESS) {
@@ -1112,8 +1200,8 @@ ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n,
}
isc_result_t
ns_clientmgr_accepttcp(ns_clientmgr_t *manager, isc_socket_t *socket,
unsigned int n)
ns_clientmgr_accepttcp(ns_clientmgr_t *manager, unsigned int n,
ns_interface_t *ifp)
{
isc_result_t result = ISC_R_SUCCESS;
unsigned int i;
@@ -1145,11 +1233,12 @@ ns_clientmgr_accepttcp(ns_clientmgr_t *manager, isc_socket_t *socket,
for (i = 0; i < n; i++) {
client = NULL;
result = client_create(manager, ns_clienttype_tcp, &client);
result = client_create(manager, ns_clienttype_tcp,
ifp, &client);
if (result != ISC_R_SUCCESS)
break;
client->attributes |= NS_CLIENTATTR_TCP;
isc_socket_attach(socket, &client->tcplistener);
isc_socket_attach(ifp->tcpsocket, &client->tcplistener);
client_accept(client);
client->manager = manager;
ISC_LIST_APPEND(manager->clients, client, link);

View File

@@ -21,6 +21,7 @@
#include <isc/types.h>
#include <isc/stdtime.h>
#include <isc/buffer.h>
#include <isc/quota.h>
#include <dns/name.h>
#include <dns/types.h>
@@ -69,7 +70,9 @@ struct ns_client {
isc_stdtime_t now;
dns_name_t signername; /* [T]SIG key name */
dns_name_t * signer; /* NULL if not valid sig */
isc_boolean_t oneshot;
isc_boolean_t mortal; /* Die after handling request. */
isc_quota_t *quota;
ns_interface_t *interface;
ISC_LINK(struct ns_client) link;
};
@@ -118,7 +121,11 @@ ns_client_unwait(ns_client_t *client);
*/
isc_result_t
ns_client_replace(ns_client_t *client);
ns_client_getquota(ns_client_t *client, isc_quota_t *quota);
isc_result_t
ns_client_replace(ns_client_t *client, isc_quota_t *quota);
/*
* Try to replace the current client with a new one, so that the
* current one can go off and do some lengthy work without
@@ -136,11 +143,19 @@ ns_clientmgr_destroy(ns_clientmgr_t **managerp);
isc_result_t
ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n,
dns_dispatch_t *dispatch);
ns_interface_t *ifp);
/*
* Create up to 'n' UDP clients listening for requests through the
* dispatch of interface 'ifp'.
*/
isc_result_t
ns_clientmgr_accepttcp(ns_clientmgr_t *manager, isc_socket_t *socket,
unsigned int n);
ns_clientmgr_accepttcp(ns_clientmgr_t *manager, unsigned int n,
ns_interface_t *ifp);
/*
* Create up to 'n' TCP clients accepting requests on the
* socket of interface 'ifp'.
*/
isc_sockaddr_t *
ns_client_getsockaddr(ns_client_t *client);

View File

@@ -56,15 +56,49 @@
#include <named/types.h>
/***
*** Types
***/
#define IFACE_MAGIC 0x493A2D29U /* I:-). */
#define NS_INTERFACE_VALID(t) ((t) != NULL && (t)->magic == IFACE_MAGIC)
struct ns_interface {
unsigned int magic; /* Magic number. */
ns_interfacemgr_t * mgr; /* Interface manager. */
isc_mutex_t lock;
int references; /* Locked */
unsigned int generation; /* Generation number. */
isc_sockaddr_t addr; /* Address and port. */
isc_socket_t * udpsocket; /* UDP socket. */
dns_dispatch_t * udpdispatch; /* UDP dispatcher. */
isc_socket_t * tcpsocket; /* TCP socket. */
isc_task_t * task;
int ntcptarget; /* Desired # of TCP accepts */
int ntcpcurrent; /* Current ditto, locked */
ISC_LINK(ns_interface_t) link;
};
/***
*** Functions
***/
isc_result_t
ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_socketmgr_t *socketmgr, ns_clientmgr_t *clientmgr,
ns_interfacemgr_t **mgrp);
void
ns_interfacemgr_attach(ns_interfacemgr_t *source,
ns_interfacemgr_t **target);
void
ns_interfacemgr_detach(ns_interfacemgr_t **targetp);
void
ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr);
void
ns_interfacemgr_scan(ns_interfacemgr_t *mgr);
/*
@@ -79,10 +113,12 @@ ns_interfacemgr_scan(ns_interfacemgr_t *mgr);
* in named.conf.
*/
void
ns_interfacemgr_destroy(ns_interfacemgr_t **mgrp);
/*
* Destroy the interface manager.
*/
ns_interface_attach(ns_interface_t *source,
ns_interface_t **target);
void
ns_interface_detach(ns_interface_t **targetp);
#endif /* NS_INTERFACEMGR_H */

View File

@@ -18,8 +18,9 @@
#ifndef NS_SERVER_H
#define NS_SERVER_H 1
#include <isc/types.h>
#include <isc/log.h>
#include <isc/types.h>
#include <isc/quota.h>
#include <dns/types.h>
@@ -37,6 +38,9 @@ struct ns_server {
dns_acl_t * queryacl;
dns_acl_t * recursionacl;
dns_acl_t * transferacl;
isc_quota_t xfroutquota;
isc_quota_t tcpquota;
isc_quota_t recursionquota;
/* Server data structures. */
dns_viewlist_t viewlist;

View File

@@ -26,6 +26,7 @@ typedef struct ns_client ns_client_t;
typedef struct ns_clientmgr ns_clientmgr_t;
typedef struct ns_query ns_query_t;
typedef struct ns_server ns_server_t;
typedef struct ns_interface ns_interface_t;
typedef struct ns_interfacemgr ns_interfacemgr_t;
#endif /* NS_TYPES_H */

View File

@@ -31,6 +31,7 @@
#include <isc/types.h>
#include <isc/net.h>
#include <isc/interfaceiter.h>
#include <isc/util.h>
#include <dns/dispatch.h>
@@ -39,13 +40,13 @@
#include <named/log.h>
#include <named/interfacemgr.h>
typedef struct ns_interface ns_interface_t;
#define IFMGR_MAGIC 0x49464D47U /* IFMG. */
#define VALID_IFMGR(t) ((t) != NULL && (t)->magic == IFMGR_MAGIC)
#define NS_INTERFACEMGR_VALID(t) ((t) != NULL && (t)->magic == IFMGR_MAGIC)
struct ns_interfacemgr {
unsigned int magic; /* Magic number. */
int references;
isc_mutex_t lock;
isc_mem_t * mctx; /* Memory context. */
isc_taskmgr_t * taskmgr; /* Task manager. */
isc_socketmgr_t * socketmgr; /* Socket manager. */
@@ -54,26 +55,14 @@ struct ns_interfacemgr {
ISC_LIST(ns_interface_t) interfaces; /* List of interfaces. */
};
#define IFACE_MAGIC 0x493A2D29U /* I:-). */
#define VALID_IFACE(t) ((t) != NULL && (t)->magic == IFACE_MAGIC)
struct ns_interface {
unsigned int magic; /* Magic number. */
ns_interfacemgr_t * mgr; /* Interface manager. */
unsigned int generation; /* Generation number. */
isc_sockaddr_t addr; /* Address and port. */
isc_socket_t * udpsocket; /* UDP socket. */
dns_dispatch_t * udpdispatch; /* UDP dispatcher. */
isc_socket_t * tcpsocket; /* TCP socket. */
isc_task_t * task;
ISC_LINK(ns_interface_t) link;
};
static void purge_old_interfaces(ns_interfacemgr_t *mgr);
isc_result_t
ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_socketmgr_t *socketmgr, ns_clientmgr_t *clientmgr,
ns_interfacemgr_t **mgrp)
{
isc_result_t result;
ns_interfacemgr_t *mgr;
REQUIRE(mctx != NULL);
@@ -84,6 +73,12 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
if (mgr == NULL)
return (DNS_R_NOMEMORY);
result = isc_mutex_init(&mgr->lock);
if (result != ISC_R_SUCCESS) {
isc_mem_put(mctx, mgr, sizeof(*mgr));
return (result);
}
mgr->mctx = mctx;
mgr->taskmgr = taskmgr;
mgr->socketmgr = socketmgr;
@@ -91,25 +86,88 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
mgr->generation = 1;
ISC_LIST_INIT(mgr->interfaces);
mgr->references = 1;
mgr->magic = IFMGR_MAGIC;
*mgrp = mgr;
return (DNS_R_SUCCESS);
}
static void
ns_interfacemgr_destroy(ns_interfacemgr_t *mgr)
{
REQUIRE(NS_INTERFACEMGR_VALID(mgr));
isc_mutex_destroy(&mgr->lock);
mgr->magic = 0;
isc_mem_put(mgr->mctx, mgr, sizeof *mgr);
}
void
ns_interfacemgr_attach(ns_interfacemgr_t *source,
ns_interfacemgr_t **target)
{
REQUIRE(NS_INTERFACEMGR_VALID(source));
LOCK(&source->lock);
INSIST(source->references > 0);
source->references++;
UNLOCK(&source->lock);
*target = source;
}
void
ns_interfacemgr_detach(ns_interfacemgr_t **targetp)
{
isc_result_t need_destroy = ISC_FALSE;
ns_interfacemgr_t *target = *targetp;
REQUIRE(target != NULL);
REQUIRE(NS_INTERFACEMGR_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_interfacemgr_destroy(target);
*targetp = NULL;
}
void
ns_interfacemgr_shutdown(ns_interfacemgr_t *mgr)
{
REQUIRE(NS_INTERFACEMGR_VALID(mgr));
LOCK(&mgr->lock);
/*
* Shut down and detach all interfaces.
* By incrementing the generation count, we make purge_old_interfaces()
* consider all interfaces "old".
*/
mgr->generation++;
purge_old_interfaces(mgr);
INSIST(ISC_LIST_EMPTY(mgr->interfaces));
UNLOCK(&mgr->lock);
}
static isc_result_t
ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
isc_boolean_t udp_only, ns_interface_t **ifpret) {
ns_interface_t **ifpret)
{
ns_interface_t *ifp;
isc_result_t result;
REQUIRE(VALID_IFMGR(mgr));
REQUIRE(NS_INTERFACEMGR_VALID(mgr));
ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
if (ifp == NULL)
return (DNS_R_NOMEMORY);
ifp->mgr = mgr;
ifp->mgr = NULL;
ifp->generation = mgr->generation;
ifp->addr = *addr;
result = isc_mutex_init(&ifp->lock);
if (result != ISC_R_SUCCESS)
goto lock_create_failure;
/*
* Create a task.
*/
@@ -122,12 +180,42 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
goto task_create_failure;
}
ifp->udpsocket = NULL;
ifp->udpdispatch = NULL;
ifp->tcpsocket = NULL;
ifp->ntcptarget = ns_g_cpus;
ifp->ntcpcurrent = 0;
ns_interfacemgr_attach(mgr, &ifp->mgr);
ISC_LIST_APPEND(mgr->interfaces, ifp, link);
ifp->references = 1;
ifp->magic = IFACE_MAGIC;
*ifpret = ifp;
return (DNS_R_SUCCESS);
isc_task_detach(&ifp->task);
task_create_failure:
isc_mutex_destroy(&ifp->lock);
lock_create_failure:
ifp->magic = 0;
isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
return (DNS_R_UNEXPECTED);
}
static isc_result_t
ns_interface_listenudp(ns_interface_t *ifp) {
isc_result_t result;
/*
* Open a UDP socket.
*/
ifp->udpsocket = NULL;
result = isc_socket_create(mgr->socketmgr,
isc_sockaddr_pf(addr),
result = isc_socket_create(ifp->mgr->socketmgr,
isc_sockaddr_pf(&ifp->addr),
isc_sockettype_udp,
&ifp->udpsocket);
if (result != ISC_R_SUCCESS) {
@@ -148,8 +236,7 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
* this UDP socket will be shared with the resolver, and if so, we
* need to set the hashsize to be be something bigger than 17.
*/
ifp->udpdispatch = NULL;
result = dns_dispatch_create(mgr->mctx, ifp->udpsocket, ifp->task,
result = dns_dispatch_create(ifp->mgr->mctx, ifp->udpsocket, ifp->task,
4096, 50, 50, 17, 19, NULL,
&ifp->udpdispatch);
if (result != ISC_R_SUCCESS) {
@@ -158,22 +245,34 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
isc_result_totext(result));
goto udp_dispatch_failure;
}
result = ns_clientmgr_addtodispatch(mgr->clientmgr, ns_g_cpus,
ifp->udpdispatch);
result = ns_clientmgr_addtodispatch(ifp->mgr->clientmgr, ns_g_cpus, ifp);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"UDP ns_clientmgr_addtodispatch(): %s",
isc_result_totext(result));
goto addtodispatch_failure;
}
return (ISC_R_SUCCESS);
addtodispatch_failure:
dns_dispatch_detach(&ifp->udpdispatch);
udp_dispatch_failure:
udp_bind_failure:
isc_socket_detach(&ifp->udpsocket);
udp_socket_failure:
return (result);
}
static isc_result_t
ns_interface_accepttcp(ns_interface_t *ifp) {
isc_result_t result;
ifp->tcpsocket = NULL;
if (!udp_only) {
/*
* Open a TCP socket.
*/
result = isc_socket_create(mgr->socketmgr,
isc_sockaddr_pf(addr),
result = isc_socket_create(ifp->mgr->socketmgr,
isc_sockaddr_pf(&ifp->addr),
isc_sockettype_tcp,
&ifp->tcpsocket);
if (result != ISC_R_SUCCESS) {
@@ -196,75 +295,112 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
isc_result_totext(result));
goto tcp_listen_failure;
}
result = ns_clientmgr_accepttcp(mgr->clientmgr, ifp->tcpsocket,
ns_g_cpus);
result = ns_clientmgr_accepttcp(ifp->mgr->clientmgr,
ifp->ntcptarget, ifp);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"TCP ns_clientmgr_accepttcp(): %s",
isc_result_totext(result));
goto accepttcp_failure;
}
}
ISC_LIST_APPEND(mgr->interfaces, ifp, link);
ifp->magic = IFACE_MAGIC;
*ifpret = ifp;
return (DNS_R_SUCCESS);
return (ISC_R_SUCCESS);
accepttcp_failure:
tcp_listen_failure:
tcp_bind_failure:
isc_socket_detach(&ifp->tcpsocket);
tcp_socket_failure:
return (DNS_R_SUCCESS);
}
static isc_result_t
ns_interface_setup(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
ns_interface_t **ifpret)
{
isc_result_t result;
ns_interface_t *ifp = NULL;
REQUIRE(ifpret != NULL && *ifpret == NULL);
result = ns_interface_create(mgr, addr, &ifp);
if (result != DNS_R_SUCCESS)
return (result);
result = ns_interface_listenudp(ifp);
if (result != DNS_R_SUCCESS)
goto cleanup_interface;
result = ns_interface_accepttcp(ifp);
if (result != DNS_R_SUCCESS) {
/*
* XXXRTH We don't currently have a way to easily stop dispatch
* service, so we return currently return DNS_R_SUCCESS (the UDP
* stuff will work even if TCP creation failed). This will be fixed
* later.
*/
return (DNS_R_SUCCESS);
result = ISC_R_SUCCESS;
}
*ifpret = ifp;
return (ISC_R_SUCCESS);
addtodispatch_failure:
dns_dispatch_detach(&ifp->udpdispatch);
udp_dispatch_failure:
udp_bind_failure:
isc_socket_detach(&ifp->udpsocket);
udp_socket_failure:
isc_task_detach(&ifp->task);
task_create_failure:
ifp->magic = 0;
isc_mem_put(mgr->mctx, ifp, sizeof(*ifp));
return (DNS_R_UNEXPECTED);
cleanup_interface:
ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
ns_interface_detach(&ifp);
return (result);
}
static isc_result_t
ns_interface_destroy(ns_interface_t **ifpret) {
ns_interface_t *ifp;
REQUIRE(ifpret != NULL);
REQUIRE(VALID_IFACE(*ifpret));
ifp = *ifpret;
ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
static void
ns_interface_destroy(ns_interface_t *ifp) {
isc_mem_t *mctx = ifp->mgr->mctx;
REQUIRE(NS_INTERFACE_VALID(ifp));
if (ifp->udpdispatch != NULL)
dns_dispatch_detach(&ifp->udpdispatch);
if (ifp->udpsocket != NULL) {
isc_socket_cancel(ifp->udpsocket, NULL, ISC_SOCKCANCEL_ALL);
isc_socket_detach(&ifp->udpsocket);
}
if (ifp->tcpsocket != NULL) {
isc_socket_cancel(ifp->tcpsocket, NULL, ISC_SOCKCANCEL_ALL);
isc_socket_detach(&ifp->tcpsocket);
}
isc_task_detach(&ifp->task);
isc_mutex_destroy(&ifp->lock);
ns_interfacemgr_detach(&ifp->mgr);
ifp->magic = 0;
isc_mem_put(ifp->mgr->mctx, ifp, sizeof(*ifp));
isc_mem_put(mctx, ifp, sizeof(*ifp));
}
*ifpret = NULL;
return (DNS_R_SUCCESS);
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;
}
/*
@@ -289,17 +425,17 @@ 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(VALID_IFACE(ifp));
INSIST(NS_INTERFACE_VALID(ifp));
next = ISC_LIST_NEXT(ifp, link);
if (ifp->generation != mgr->generation) {
isc_result_t result = ns_interface_destroy(&ifp);
RUNTIME_CHECK(result == DNS_R_SUCCESS);
ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
ns_interface_detach(&ifp);
}
}
}
static void
do_ipv4(ns_interfacemgr_t *mgr, isc_boolean_t udp_only) {
do_ipv4(ns_interfacemgr_t *mgr) {
isc_interfaceiter_t *iter = NULL;
isc_result_t result;
@@ -346,14 +482,15 @@ do_ipv4(ns_interfacemgr_t *mgr, isc_boolean_t udp_only) {
interface.name, addrstr,
ntohs(listen_addr.type.sin.sin_port));
result = ns_interface_create(mgr, &listen_addr,
udp_only, &ifp);
result = ns_interface_setup(mgr, &listen_addr, &ifp);
if (result != DNS_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"listening on IPv4 interface %s"
" failed; interface ignored",
"creating IPv4 interface %s "
"failed; interface ignored",
interface.name);
/* Continue. */
}
}
result = isc_interfaceiter_next(iter);
}
@@ -383,31 +520,30 @@ do_ipv6(ns_interfacemgr_t *mgr) {
NS_LOGMODULE_INTERFACEMGR, ISC_LOG_INFO,
"listening on IPv6 interfaces, port %u",
ns_g_port);
result = ns_interface_create(mgr, &listen_addr, ISC_FALSE,
&ifp);
if (result != DNS_R_SUCCESS)
result = ns_interface_setup(mgr, &listen_addr, &ifp);
if (result != DNS_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"listening on IPv6 interfaces failed");
/* Continue. */
}
}
}
void
ns_interfacemgr_scan(ns_interfacemgr_t *mgr) {
isc_boolean_t udp_only = ISC_FALSE;
REQUIRE(VALID_IFMGR(mgr));
REQUIRE(NS_INTERFACEMGR_VALID(mgr));
mgr->generation++; /* Increment the generation count. */
if (isc_net_probeipv6() == ISC_R_SUCCESS) {
do_ipv6(mgr);
udp_only = ISC_TRUE;
} else
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_NETWORK,
NS_LOGMODULE_INTERFACEMGR, ISC_LOG_INFO,
"no IPv6 interfaces found");
if (isc_net_probeipv4() == ISC_R_SUCCESS)
do_ipv4(mgr, udp_only);
do_ipv4(mgr);
else
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_NETWORK,
NS_LOGMODULE_INTERFACEMGR, ISC_LOG_INFO,
@@ -430,26 +566,3 @@ ns_interfacemgr_scan(ns_interfacemgr_t *mgr) {
*/
}
}
void
ns_interfacemgr_destroy(ns_interfacemgr_t **mgrp)
{
ns_interfacemgr_t *mgr;
REQUIRE(mgrp != NULL);
mgr = *mgrp;
REQUIRE(VALID_IFMGR(mgr));
/*
* Destroy all interfaces. By incrementing the generation count,
* we make purge_old_interfaces() consider all interfaces "old"
* and destroy all of them.
*/
mgr->generation++;
purge_old_interfaces(mgr);
INSIST(ISC_LIST_EMPTY(mgr->interfaces));
mgr->magic = 0;
isc_mem_put(mgr->mctx, mgr, sizeof *mgr);
*mgrp = NULL;
}

View File

@@ -1693,10 +1693,23 @@ query_recurse(ns_client_t *client, dns_rdatatype_t qtype, dns_name_t *qdomain,
dns_rdataset_t *rdataset, *sigrdataset;
unsigned int options = 0;
/*
* Set up a new client object to handle incoming queries while
* this one is being resolved.
*/
result = ns_client_replace(client, &ns_g_server->recursionquota);
if (result != ISC_R_SUCCESS) {
/* Most likely the quota was full. */
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_CLIENT,
NS_LOGMODULE_QUERY, ISC_LOG_WARNING,
"no more recursive clients: %s",
isc_result_totext(result));
return (result);
}
/*
* Invoke the resolver.
*/
REQUIRE(nameservers->type == dns_rdatatype_ns);
REQUIRE(client->query.fetch == NULL);

View File

@@ -646,11 +646,14 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
server->recursionacl = NULL;
server->transferacl = NULL;
/* XXX these values are for debugging only */
RUNTIME_CHECK(isc_quota_init(&server->xfroutquota, 1) == ISC_R_SUCCESS);
RUNTIME_CHECK(isc_quota_init(&server->tcpquota, 3) == ISC_R_SUCCESS);
RUNTIME_CHECK(isc_quota_init(&server->recursionquota, 1) == ISC_R_SUCCESS);
/* Initialize server data structures. */
ISC_LIST_INIT(server->viewlist);
result = isc_rwlock_init(&server->viewlock, 0, 0);
if (result != ISC_R_SUCCESS)
return (result);
RUNTIME_CHECK(isc_rwlock_init(&server->viewlock, 0, 0) == ISC_R_SUCCESS);
server->interfacemgr = NULL;
result = ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
@@ -658,8 +661,9 @@ ns_server_create(isc_mem_t *mctx, ns_server_t **serverp) {
&server->interfacemgr);
if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__,
"ns_interfacemgr_create() failed: %s\n",
"ns_interfacemgr_create() failed: %s",
isc_result_totext(result));
/* XXX cleanup */
return (ISC_R_UNEXPECTED);
}
@@ -677,7 +681,8 @@ ns_server_destroy(ns_server_t **serverp) {
* The interface manager owns tasks, so we have to destroy it before
* we destroy the task manager.
*/
ns_interfacemgr_destroy(&server->interfacemgr);
ns_interfacemgr_shutdown(server->interfacemgr);
ns_interfacemgr_detach(&server->interfacemgr);
INSIST(ISC_LIST_EMPTY(server->viewlist));
isc_rwlock_destroy(&server->viewlock);
@@ -689,6 +694,10 @@ ns_server_destroy(ns_server_t **serverp) {
if (server->transferacl != NULL)
dns_acl_detach(&server->transferacl);
isc_quota_destroy(&server->recursionquota);
isc_quota_destroy(&server->tcpquota);
isc_quota_destroy(&server->xfroutquota);
server->magic = 0;
isc_mem_put(server->mctx, server, sizeof(*server));
}

View File

@@ -15,7 +15,7 @@
* SOFTWARE.
*/
/* $Id: xfrout.c,v 1.33 1999/12/23 00:08:23 explorer Exp $ */
/* $Id: xfrout.c,v 1.34 2000/01/11 21:18:21 gson Exp $ */
#include <config.h>
@@ -805,6 +805,17 @@ ns_xfr_start(ns_client_t *client, dns_rdatatype_t reqtype)
isc_log_write(XFROUT_DEBUG_LOGARGS(6), "got %s request", mnemonic);
/*
* Apply quotas.
*/
result = ns_client_getquota(client, &ns_g_server->xfroutquota);
if (result != DNS_R_SUCCESS) {
isc_log_write(XFROUT_COMMON_LOGARGS, ISC_LOG_WARNING,
"zone transfer request denied: %s",
isc_result_totext(result));
goto failure;
}
/*
* Interpret the question section.
*/