2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-02 15:45:25 +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/server.h>
#include <named/update.h> #include <named/update.h>
#include <named/notify.h> #include <named/notify.h>
#include <named/interfacemgr.h>
#define NS_CLIENT_TRACE #define NS_CLIENT_TRACE
#ifdef NS_CLIENT_TRACE #ifdef NS_CLIENT_TRACE
@@ -131,6 +132,8 @@ maybe_free(ns_client_t *client) {
} }
/* We have received our last event. */ /* We have received our last event. */
ns_interface_detach(&client->interface);
ns_query_free(client); ns_query_free(client);
isc_mempool_destroy(&client->sendbufs); isc_mempool_destroy(&client->sendbufs);
isc_timer_detach(&client->timer); isc_timer_detach(&client->timer);
@@ -175,6 +178,12 @@ maybe_free(ns_client_t *client) {
UNLOCK(&manager->lock); UNLOCK(&manager->lock);
} }
if (client->quota != NULL) {
isc_quota_release(client->quota);
client->quota = NULL;
}
CTRACE("free"); CTRACE("free");
client->magic = 0; client->magic = 0;
isc_mem_put(client->mctx, client, sizeof *client); 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; client->udpsize = 512;
dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE); dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
if (client->quota != NULL) {
if (client->oneshot) { 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. */ /* XXX should put in "idle client pool" instead. */
isc_task_shutdown(client->task); isc_task_shutdown(client->task);
return; return;
} }
}
if (client->dispevent != NULL) { 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, dns_dispatch_freeevent(client->dispatch, client->dispentry,
&client->dispevent); &client->dispevent);
} else if (TCP_CLIENT(client)) { } else if (TCP_CLIENT(client)) {
if (result == ISC_R_SUCCESS) if (result == ISC_R_SUCCESS) {
client_read(client); 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) { if (client->tcpsocket != NULL) {
/* /*
* There should be no outstanding read * There should be no outstanding read
@@ -688,9 +733,6 @@ client_request(isc_task_t *task, isc_event_t *event) {
if (ra == ISC_TRUE) if (ra == ISC_TRUE)
client->attributes |= NS_CLIENTATTR_RA; client->attributes |= NS_CLIENTATTR_RA;
/* XXX conditionally */
(void) ns_client_replace(client);
/* /*
* Dispatch the request. * Dispatch the request.
*/ */
@@ -737,7 +779,7 @@ client_timeout(isc_task_t *task, isc_event_t *event) {
static isc_result_t static isc_result_t
client_create(ns_clientmgr_t *manager, ns_clienttype_t type, 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; ns_client_t *client;
isc_result_t result; isc_result_t result;
@@ -809,7 +851,9 @@ client_create(ns_clientmgr_t *manager, ns_clienttype_t type,
client->udpsize = 512; client->udpsize = 512;
client->next = NULL; client->next = NULL;
dns_name_init(&client->signername, 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); ISC_LINK_INIT(client, link);
/* /*
@@ -821,6 +865,8 @@ client_create(ns_clientmgr_t *manager, ns_clienttype_t type,
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
goto cleanup_sendbufs; goto cleanup_sendbufs;
ns_interface_attach(ifp, &client->interface);
CTRACE("create"); CTRACE("create");
*clientp = client; *clientp = client;
@@ -865,6 +911,7 @@ static void
client_newconn(isc_task_t *task, isc_event_t *event) { client_newconn(isc_task_t *task, isc_event_t *event) {
ns_client_t *client = event->arg; ns_client_t *client = event->arg;
isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event; isc_socket_newconnev_t *nevent = (isc_socket_newconnev_t *)event;
isc_result_t result;
REQUIRE(event->type == ISC_SOCKEVENT_NEWCONN); REQUIRE(event->type == ISC_SOCKEVENT_NEWCONN);
REQUIRE(NS_CLIENT_VALID(client)); REQUIRE(NS_CLIENT_VALID(client));
@@ -875,6 +922,11 @@ client_newconn(isc_task_t *task, isc_event_t *event) {
INSIST(client->naccepts == 1); INSIST(client->naccepts == 1);
client->naccepts--; client->naccepts--;
LOCK(&client->interface->lock);
INSIST(client->interface->ntcpcurrent > 0);
client->interface->ntcpcurrent--;
UNLOCK(&client->interface->lock);
if (client->shuttingdown) { if (client->shuttingdown) {
maybe_free(client); maybe_free(client);
} else if (nevent->result == ISC_R_SUCCESS) { } 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 * telnetting to port 35 (once per CPU) will
* deny service to legititmate TCP clients. * 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); client_read(client);
} else { } else {
/* /*
@@ -931,6 +988,9 @@ client_accept(ns_client_t *client) {
} }
INSIST(client->naccepts == 0); INSIST(client->naccepts == 0);
client->naccepts++; client->naccepts++;
LOCK(&client->interface->lock);
client->interface->ntcpcurrent++;
UNLOCK(&client->interface->lock);
} }
void void
@@ -953,25 +1013,52 @@ ns_client_unwait(ns_client_t *client) {
isc_result_t 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; isc_result_t result;
CTRACE("replace"); CTRACE("replace");
if (quota != NULL) {
/* XXX Check quota here. */ result = ns_client_getquota(client, quota);
if (result != DNS_R_SUCCESS)
return (result);
}
if (TCP_CLIENT(client)) { if (TCP_CLIENT(client)) {
result = ns_clientmgr_accepttcp(client->manager, client->tcplistener, 1); result = ns_clientmgr_accepttcp(client->manager,
1, client->interface);
} else { } else {
result = ns_clientmgr_addtodispatch(client->manager, 1, client->dispatch); result = ns_clientmgr_addtodispatch(client->manager,
1, client->interface);
} }
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
return (result); return (result);
/* /*
* The new client is ready to listen for new requests, so we * The new client is ready to listen for new requests, therefore we
* should refrain from doing so. * 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); return (ISC_R_SUCCESS);
} }
@@ -1060,7 +1147,7 @@ ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
isc_result_t isc_result_t
ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n, 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; isc_result_t result = ISC_R_SUCCESS;
unsigned int i; unsigned int i;
@@ -1082,11 +1169,12 @@ ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n,
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
client = NULL; client = NULL;
result = client_create(manager, ns_clienttype_basic, result = client_create(manager, ns_clienttype_basic,
&client); ifp, &client);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
break; break;
dns_dispatch_attach(dispatch, &client->dispatch); dns_dispatch_attach(ifp->udpdispatch, &client->dispatch);
result = dns_dispatch_addrequest(dispatch, client->task, result = dns_dispatch_addrequest(client->dispatch,
client->task,
client_request, client_request,
client, &client->dispentry); client, &client->dispentry);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
@@ -1112,8 +1200,8 @@ ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n,
} }
isc_result_t isc_result_t
ns_clientmgr_accepttcp(ns_clientmgr_t *manager, isc_socket_t *socket, ns_clientmgr_accepttcp(ns_clientmgr_t *manager, unsigned int n,
unsigned int n) ns_interface_t *ifp)
{ {
isc_result_t result = ISC_R_SUCCESS; isc_result_t result = ISC_R_SUCCESS;
unsigned int i; unsigned int i;
@@ -1145,11 +1233,12 @@ ns_clientmgr_accepttcp(ns_clientmgr_t *manager, isc_socket_t *socket,
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
client = NULL; client = NULL;
result = client_create(manager, ns_clienttype_tcp, &client); result = client_create(manager, ns_clienttype_tcp,
ifp, &client);
if (result != ISC_R_SUCCESS) if (result != ISC_R_SUCCESS)
break; break;
client->attributes |= NS_CLIENTATTR_TCP; client->attributes |= NS_CLIENTATTR_TCP;
isc_socket_attach(socket, &client->tcplistener); isc_socket_attach(ifp->tcpsocket, &client->tcplistener);
client_accept(client); client_accept(client);
client->manager = manager; client->manager = manager;
ISC_LIST_APPEND(manager->clients, client, link); ISC_LIST_APPEND(manager->clients, client, link);

View File

@@ -21,6 +21,7 @@
#include <isc/types.h> #include <isc/types.h>
#include <isc/stdtime.h> #include <isc/stdtime.h>
#include <isc/buffer.h> #include <isc/buffer.h>
#include <isc/quota.h>
#include <dns/name.h> #include <dns/name.h>
#include <dns/types.h> #include <dns/types.h>
@@ -69,7 +70,9 @@ struct ns_client {
isc_stdtime_t now; isc_stdtime_t now;
dns_name_t signername; /* [T]SIG key name */ dns_name_t signername; /* [T]SIG key name */
dns_name_t * signer; /* NULL if not valid sig */ 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; ISC_LINK(struct ns_client) link;
}; };
@@ -118,7 +121,11 @@ ns_client_unwait(ns_client_t *client);
*/ */
isc_result_t 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 * Try to replace the current client with a new one, so that the
* current one can go off and do some lengthy work without * 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 isc_result_t
ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, unsigned int n, 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 isc_result_t
ns_clientmgr_accepttcp(ns_clientmgr_t *manager, isc_socket_t *socket, ns_clientmgr_accepttcp(ns_clientmgr_t *manager, unsigned int n,
unsigned int n); ns_interface_t *ifp);
/*
* Create up to 'n' TCP clients accepting requests on the
* socket of interface 'ifp'.
*/
isc_sockaddr_t * isc_sockaddr_t *
ns_client_getsockaddr(ns_client_t *client); ns_client_getsockaddr(ns_client_t *client);

View File

@@ -56,15 +56,49 @@
#include <named/types.h> #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 *** Functions
***/ ***/
isc_result_t isc_result_t
ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_socketmgr_t *socketmgr, ns_clientmgr_t *clientmgr, isc_socketmgr_t *socketmgr, ns_clientmgr_t *clientmgr,
ns_interfacemgr_t **mgrp); 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 void
ns_interfacemgr_scan(ns_interfacemgr_t *mgr); ns_interfacemgr_scan(ns_interfacemgr_t *mgr);
/* /*
@@ -79,10 +113,12 @@ ns_interfacemgr_scan(ns_interfacemgr_t *mgr);
* in named.conf. * in named.conf.
*/ */
void void
ns_interfacemgr_destroy(ns_interfacemgr_t **mgrp); ns_interface_attach(ns_interface_t *source,
/* ns_interface_t **target);
* Destroy the interface manager.
*/ void
ns_interface_detach(ns_interface_t **targetp);
#endif /* NS_INTERFACEMGR_H */ #endif /* NS_INTERFACEMGR_H */

View File

@@ -18,8 +18,9 @@
#ifndef NS_SERVER_H #ifndef NS_SERVER_H
#define NS_SERVER_H 1 #define NS_SERVER_H 1
#include <isc/types.h>
#include <isc/log.h> #include <isc/log.h>
#include <isc/types.h>
#include <isc/quota.h>
#include <dns/types.h> #include <dns/types.h>
@@ -37,6 +38,9 @@ struct ns_server {
dns_acl_t * queryacl; dns_acl_t * queryacl;
dns_acl_t * recursionacl; dns_acl_t * recursionacl;
dns_acl_t * transferacl; dns_acl_t * transferacl;
isc_quota_t xfroutquota;
isc_quota_t tcpquota;
isc_quota_t recursionquota;
/* Server data structures. */ /* Server data structures. */
dns_viewlist_t viewlist; 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_clientmgr ns_clientmgr_t;
typedef struct ns_query ns_query_t; typedef struct ns_query ns_query_t;
typedef struct ns_server ns_server_t; typedef struct ns_server ns_server_t;
typedef struct ns_interface ns_interface_t;
typedef struct ns_interfacemgr ns_interfacemgr_t; typedef struct ns_interfacemgr ns_interfacemgr_t;
#endif /* NS_TYPES_H */ #endif /* NS_TYPES_H */

View File

@@ -31,6 +31,7 @@
#include <isc/types.h> #include <isc/types.h>
#include <isc/net.h> #include <isc/net.h>
#include <isc/interfaceiter.h> #include <isc/interfaceiter.h>
#include <isc/util.h>
#include <dns/dispatch.h> #include <dns/dispatch.h>
@@ -39,13 +40,13 @@
#include <named/log.h> #include <named/log.h>
#include <named/interfacemgr.h> #include <named/interfacemgr.h>
typedef struct ns_interface ns_interface_t;
#define IFMGR_MAGIC 0x49464D47U /* IFMG. */ #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 { struct ns_interfacemgr {
unsigned int magic; /* Magic number. */ unsigned int magic; /* Magic number. */
int references;
isc_mutex_t lock;
isc_mem_t * mctx; /* Memory context. */ isc_mem_t * mctx; /* Memory context. */
isc_taskmgr_t * taskmgr; /* Task manager. */ isc_taskmgr_t * taskmgr; /* Task manager. */
isc_socketmgr_t * socketmgr; /* Socket manager. */ isc_socketmgr_t * socketmgr; /* Socket manager. */
@@ -54,26 +55,14 @@ struct ns_interfacemgr {
ISC_LIST(ns_interface_t) interfaces; /* List of interfaces. */ ISC_LIST(ns_interface_t) interfaces; /* List of interfaces. */
}; };
#define IFACE_MAGIC 0x493A2D29U /* I:-). */ static void purge_old_interfaces(ns_interfacemgr_t *mgr);
#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;
};
isc_result_t isc_result_t
ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr, ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
isc_socketmgr_t *socketmgr, ns_clientmgr_t *clientmgr, isc_socketmgr_t *socketmgr, ns_clientmgr_t *clientmgr,
ns_interfacemgr_t **mgrp) ns_interfacemgr_t **mgrp)
{ {
isc_result_t result;
ns_interfacemgr_t *mgr; ns_interfacemgr_t *mgr;
REQUIRE(mctx != NULL); REQUIRE(mctx != NULL);
@@ -84,6 +73,12 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
if (mgr == NULL) if (mgr == NULL)
return (DNS_R_NOMEMORY); 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->mctx = mctx;
mgr->taskmgr = taskmgr; mgr->taskmgr = taskmgr;
mgr->socketmgr = socketmgr; mgr->socketmgr = socketmgr;
@@ -91,25 +86,88 @@ ns_interfacemgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
mgr->generation = 1; mgr->generation = 1;
ISC_LIST_INIT(mgr->interfaces); ISC_LIST_INIT(mgr->interfaces);
mgr->references = 1;
mgr->magic = IFMGR_MAGIC; mgr->magic = IFMGR_MAGIC;
*mgrp = mgr; *mgrp = mgr;
return (DNS_R_SUCCESS); 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 static isc_result_t
ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr, 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; ns_interface_t *ifp;
isc_result_t result; isc_result_t result;
REQUIRE(VALID_IFMGR(mgr)); REQUIRE(NS_INTERFACEMGR_VALID(mgr));
ifp = isc_mem_get(mgr->mctx, sizeof(*ifp)); ifp = isc_mem_get(mgr->mctx, sizeof(*ifp));
if (ifp == NULL) if (ifp == NULL)
return (DNS_R_NOMEMORY); return (DNS_R_NOMEMORY);
ifp->mgr = mgr; ifp->mgr = NULL;
ifp->generation = mgr->generation; ifp->generation = mgr->generation;
ifp->addr = *addr; ifp->addr = *addr;
result = isc_mutex_init(&ifp->lock);
if (result != ISC_R_SUCCESS)
goto lock_create_failure;
/* /*
* Create a task. * Create a task.
*/ */
@@ -122,12 +180,42 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
goto task_create_failure; 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. * Open a UDP socket.
*/ */
ifp->udpsocket = NULL; result = isc_socket_create(ifp->mgr->socketmgr,
result = isc_socket_create(mgr->socketmgr, isc_sockaddr_pf(&ifp->addr),
isc_sockaddr_pf(addr),
isc_sockettype_udp, isc_sockettype_udp,
&ifp->udpsocket); &ifp->udpsocket);
if (result != ISC_R_SUCCESS) { 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 * 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. * need to set the hashsize to be be something bigger than 17.
*/ */
ifp->udpdispatch = NULL; result = dns_dispatch_create(ifp->mgr->mctx, ifp->udpsocket, ifp->task,
result = dns_dispatch_create(mgr->mctx, ifp->udpsocket, ifp->task,
4096, 50, 50, 17, 19, NULL, 4096, 50, 50, 17, 19, NULL,
&ifp->udpdispatch); &ifp->udpdispatch);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
@@ -158,22 +245,34 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
isc_result_totext(result)); isc_result_totext(result));
goto udp_dispatch_failure; 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) { if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"UDP ns_clientmgr_addtodispatch(): %s", "UDP ns_clientmgr_addtodispatch(): %s",
isc_result_totext(result)); isc_result_totext(result));
goto addtodispatch_failure; 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. * Open a TCP socket.
*/ */
result = isc_socket_create(mgr->socketmgr, result = isc_socket_create(ifp->mgr->socketmgr,
isc_sockaddr_pf(addr), isc_sockaddr_pf(&ifp->addr),
isc_sockettype_tcp, isc_sockettype_tcp,
&ifp->tcpsocket); &ifp->tcpsocket);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
@@ -196,75 +295,112 @@ ns_interface_create(ns_interfacemgr_t *mgr, isc_sockaddr_t *addr,
isc_result_totext(result)); isc_result_totext(result));
goto tcp_listen_failure; goto tcp_listen_failure;
} }
result = ns_clientmgr_accepttcp(mgr->clientmgr, ifp->tcpsocket, result = ns_clientmgr_accepttcp(ifp->mgr->clientmgr,
ns_g_cpus); ifp->ntcptarget, ifp);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"TCP ns_clientmgr_accepttcp(): %s", "TCP ns_clientmgr_accepttcp(): %s",
isc_result_totext(result)); isc_result_totext(result));
goto accepttcp_failure; goto accepttcp_failure;
} }
} return (ISC_R_SUCCESS);
ISC_LIST_APPEND(mgr->interfaces, ifp, link);
ifp->magic = IFACE_MAGIC;
*ifpret = ifp;
return (DNS_R_SUCCESS);
accepttcp_failure: accepttcp_failure:
tcp_listen_failure: tcp_listen_failure:
tcp_bind_failure: tcp_bind_failure:
isc_socket_detach(&ifp->tcpsocket); isc_socket_detach(&ifp->tcpsocket);
tcp_socket_failure: 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 * XXXRTH We don't currently have a way to easily stop dispatch
* service, so we return currently return DNS_R_SUCCESS (the UDP * service, so we return currently return DNS_R_SUCCESS (the UDP
* stuff will work even if TCP creation failed). This will be fixed * stuff will work even if TCP creation failed). This will be fixed
* later. * later.
*/ */
return (DNS_R_SUCCESS); result = ISC_R_SUCCESS;
}
*ifpret = ifp;
return (ISC_R_SUCCESS);
addtodispatch_failure: cleanup_interface:
dns_dispatch_detach(&ifp->udpdispatch); ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
udp_dispatch_failure: ns_interface_detach(&ifp);
udp_bind_failure: return (result);
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);
} }
static isc_result_t static void
ns_interface_destroy(ns_interface_t **ifpret) { ns_interface_destroy(ns_interface_t *ifp) {
ns_interface_t *ifp; isc_mem_t *mctx = ifp->mgr->mctx;
REQUIRE(ifpret != NULL); REQUIRE(NS_INTERFACE_VALID(ifp));
REQUIRE(VALID_IFACE(*ifpret));
ifp = *ifpret;
ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
if (ifp->udpdispatch != NULL)
dns_dispatch_detach(&ifp->udpdispatch); dns_dispatch_detach(&ifp->udpdispatch);
if (ifp->udpsocket != NULL) {
isc_socket_cancel(ifp->udpsocket, NULL, ISC_SOCKCANCEL_ALL); isc_socket_cancel(ifp->udpsocket, NULL, ISC_SOCKCANCEL_ALL);
isc_socket_detach(&ifp->udpsocket); isc_socket_detach(&ifp->udpsocket);
}
if (ifp->tcpsocket != NULL) { if (ifp->tcpsocket != NULL) {
isc_socket_cancel(ifp->tcpsocket, NULL, ISC_SOCKCANCEL_ALL); isc_socket_cancel(ifp->tcpsocket, NULL, ISC_SOCKCANCEL_ALL);
isc_socket_detach(&ifp->tcpsocket); isc_socket_detach(&ifp->tcpsocket);
} }
isc_task_detach(&ifp->task); isc_task_detach(&ifp->task);
isc_mutex_destroy(&ifp->lock);
ns_interfacemgr_detach(&ifp->mgr);
ifp->magic = 0; ifp->magic = 0;
isc_mem_put(ifp->mgr->mctx, ifp, sizeof(*ifp)); isc_mem_put(mctx, ifp, sizeof(*ifp));
}
*ifpret = NULL; void
return (DNS_R_SUCCESS); 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) { purge_old_interfaces(ns_interfacemgr_t *mgr) {
ns_interface_t *ifp, *next; ns_interface_t *ifp, *next;
for (ifp = ISC_LIST_HEAD(mgr->interfaces); ifp != NULL; 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); next = ISC_LIST_NEXT(ifp, link);
if (ifp->generation != mgr->generation) { if (ifp->generation != mgr->generation) {
isc_result_t result = ns_interface_destroy(&ifp); ISC_LIST_UNLINK(ifp->mgr->interfaces, ifp, link);
RUNTIME_CHECK(result == DNS_R_SUCCESS); ns_interface_detach(&ifp);
} }
} }
} }
static void 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_interfaceiter_t *iter = NULL;
isc_result_t result; isc_result_t result;
@@ -346,14 +482,15 @@ do_ipv4(ns_interfacemgr_t *mgr, isc_boolean_t udp_only) {
interface.name, addrstr, interface.name, addrstr,
ntohs(listen_addr.type.sin.sin_port)); ntohs(listen_addr.type.sin.sin_port));
result = ns_interface_create(mgr, &listen_addr, result = ns_interface_setup(mgr, &listen_addr, &ifp);
udp_only, &ifp);
if (result != DNS_R_SUCCESS) { if (result != DNS_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"listening on IPv4 interface %s" "creating IPv4 interface %s "
" failed; interface ignored", "failed; interface ignored",
interface.name); interface.name);
/* Continue. */
} }
} }
result = isc_interfaceiter_next(iter); result = isc_interfaceiter_next(iter);
} }
@@ -383,31 +520,30 @@ do_ipv6(ns_interfacemgr_t *mgr) {
NS_LOGMODULE_INTERFACEMGR, ISC_LOG_INFO, NS_LOGMODULE_INTERFACEMGR, ISC_LOG_INFO,
"listening on IPv6 interfaces, port %u", "listening on IPv6 interfaces, port %u",
ns_g_port); ns_g_port);
result = ns_interface_create(mgr, &listen_addr, ISC_FALSE, result = ns_interface_setup(mgr, &listen_addr, &ifp);
&ifp); if (result != DNS_R_SUCCESS) {
if (result != DNS_R_SUCCESS)
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"listening on IPv6 interfaces failed"); "listening on IPv6 interfaces failed");
/* Continue. */
}
} }
} }
void void
ns_interfacemgr_scan(ns_interfacemgr_t *mgr) { 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. */ mgr->generation++; /* Increment the generation count. */
if (isc_net_probeipv6() == ISC_R_SUCCESS) { if (isc_net_probeipv6() == ISC_R_SUCCESS) {
do_ipv6(mgr); do_ipv6(mgr);
udp_only = ISC_TRUE;
} else } else
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_NETWORK, isc_log_write(ns_g_lctx, NS_LOGCATEGORY_NETWORK,
NS_LOGMODULE_INTERFACEMGR, ISC_LOG_INFO, NS_LOGMODULE_INTERFACEMGR, ISC_LOG_INFO,
"no IPv6 interfaces found"); "no IPv6 interfaces found");
if (isc_net_probeipv4() == ISC_R_SUCCESS) if (isc_net_probeipv4() == ISC_R_SUCCESS)
do_ipv4(mgr, udp_only); do_ipv4(mgr);
else else
isc_log_write(ns_g_lctx, NS_LOGCATEGORY_NETWORK, isc_log_write(ns_g_lctx, NS_LOGCATEGORY_NETWORK,
NS_LOGMODULE_INTERFACEMGR, ISC_LOG_INFO, 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; dns_rdataset_t *rdataset, *sigrdataset;
unsigned int options = 0; 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. * Invoke the resolver.
*/ */
REQUIRE(nameservers->type == dns_rdatatype_ns); REQUIRE(nameservers->type == dns_rdatatype_ns);
REQUIRE(client->query.fetch == NULL); 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->recursionacl = NULL;
server->transferacl = 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. */ /* Initialize server data structures. */
ISC_LIST_INIT(server->viewlist); ISC_LIST_INIT(server->viewlist);
result = isc_rwlock_init(&server->viewlock, 0, 0); RUNTIME_CHECK(isc_rwlock_init(&server->viewlock, 0, 0) == ISC_R_SUCCESS);
if (result != ISC_R_SUCCESS)
return (result);
server->interfacemgr = NULL; server->interfacemgr = NULL;
result = ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr, 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); &server->interfacemgr);
if (result != ISC_R_SUCCESS) { if (result != ISC_R_SUCCESS) {
UNEXPECTED_ERROR(__FILE__, __LINE__, UNEXPECTED_ERROR(__FILE__, __LINE__,
"ns_interfacemgr_create() failed: %s\n", "ns_interfacemgr_create() failed: %s",
isc_result_totext(result)); isc_result_totext(result));
/* XXX cleanup */
return (ISC_R_UNEXPECTED); 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 * The interface manager owns tasks, so we have to destroy it before
* we destroy the task manager. * 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)); INSIST(ISC_LIST_EMPTY(server->viewlist));
isc_rwlock_destroy(&server->viewlock); isc_rwlock_destroy(&server->viewlock);
@@ -689,6 +694,10 @@ ns_server_destroy(ns_server_t **serverp) {
if (server->transferacl != NULL) if (server->transferacl != NULL)
dns_acl_detach(&server->transferacl); dns_acl_detach(&server->transferacl);
isc_quota_destroy(&server->recursionquota);
isc_quota_destroy(&server->tcpquota);
isc_quota_destroy(&server->xfroutquota);
server->magic = 0; server->magic = 0;
isc_mem_put(server->mctx, server, sizeof(*server)); isc_mem_put(server->mctx, server, sizeof(*server));
} }

View File

@@ -15,7 +15,7 @@
* SOFTWARE. * 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> #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); 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. * Interpret the question section.
*/ */