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:
@@ -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);
|
||||
|
@@ -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);
|
||||
|
@@ -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 */
|
||||
|
@@ -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;
|
||||
|
@@ -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 */
|
||||
|
@@ -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"
|
||||
"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;
|
||||
}
|
||||
|
@@ -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);
|
||||
|
||||
|
@@ -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));
|
||||
}
|
||||
|
@@ -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.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user