mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-08-31 14:35:26 +00:00
add
This commit is contained in:
568
bin/named/client.c
Normal file
568
bin/named/client.c
Normal file
@@ -0,0 +1,568 @@
|
||||
/*
|
||||
* Copyright (C) 1999 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <isc/assertions.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/task.h>
|
||||
#include <isc/timer.h>
|
||||
|
||||
#include <dns/dispatch.h>
|
||||
#include <dns/events.h>
|
||||
#include <dns/message.h>
|
||||
|
||||
#include <named/client.h>
|
||||
#include <named/query.h>
|
||||
|
||||
#include "../../isc/util.h" /* XXX */
|
||||
|
||||
#define NS_CLIENT_TRACE
|
||||
#ifdef NS_CLIENT_TRACE
|
||||
#include <stdio.h>
|
||||
#define CTRACE(m) printf("client %p: %s\n", client, (m))
|
||||
#define MTRACE(m) printf("clientmgr %p: %s\n", manager, (m))
|
||||
#else
|
||||
#define CTRACE(m)
|
||||
#define MTRACE(m)
|
||||
#endif
|
||||
|
||||
#define SEND_BUFFER_SIZE 512
|
||||
|
||||
struct ns_clientmgr {
|
||||
/* Unlocked. */
|
||||
unsigned int magic;
|
||||
isc_mem_t * mctx;
|
||||
isc_taskmgr_t * taskmgr;
|
||||
isc_timermgr_t * timermgr;
|
||||
isc_mutex_t lock;
|
||||
/* Locked by lock. */
|
||||
isc_boolean_t exiting;
|
||||
unsigned int nclients;
|
||||
ISC_LIST(ns_client_t) clients;
|
||||
};
|
||||
|
||||
#define MANAGER_MAGIC 0x4E53436DU /* NSCm */
|
||||
#define VALID_MANAGER(m) ((m) != NULL && \
|
||||
(m)->magic == MANAGER_MAGIC)
|
||||
|
||||
|
||||
static void clientmgr_destroy(ns_clientmgr_t *manager);
|
||||
|
||||
|
||||
/***
|
||||
*** Client
|
||||
***/
|
||||
|
||||
/*
|
||||
* Important note!
|
||||
*
|
||||
* All client state changes, other than that from idle to listening, occur
|
||||
* as a result of events. This guarantees serialization and avoids the
|
||||
* need for locking.
|
||||
*
|
||||
* If a routine is ever created that allows someone other than the client's
|
||||
* task to change the client, then the client will have to be locked.
|
||||
*/
|
||||
|
||||
static inline void
|
||||
client_free(ns_client_t *client) {
|
||||
dns_dispatchevent_t **deventp;
|
||||
|
||||
CTRACE("free");
|
||||
|
||||
isc_mempool_destroy(&client->sendbufs);
|
||||
dns_message_destroy(&client->message);
|
||||
isc_timer_detach(&client->timer);
|
||||
if (client->dispentry != NULL) {
|
||||
if (client->dispevent != NULL)
|
||||
deventp = &client->dispevent;
|
||||
else
|
||||
deventp = NULL;
|
||||
dns_dispatch_removerequest(client->dispatch,
|
||||
&client->dispentry,
|
||||
deventp);
|
||||
}
|
||||
if (client->dispatch != NULL)
|
||||
dns_dispatch_detach(&client->dispatch);
|
||||
isc_task_detach(&client->task);
|
||||
client->magic = 0;
|
||||
|
||||
isc_mem_put(client->manager->mctx, client, sizeof *client);
|
||||
}
|
||||
|
||||
void
|
||||
ns_client_destroy(ns_client_t *client) {
|
||||
ns_clientmgr_t *manager;
|
||||
isc_boolean_t need_clientmgr_destroy = ISC_FALSE;
|
||||
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
|
||||
CTRACE("destroy");
|
||||
|
||||
manager = client->manager;
|
||||
|
||||
LOCK(&manager->lock);
|
||||
|
||||
INSIST(manager->nclients > 0);
|
||||
manager->nclients--;
|
||||
if (manager->nclients == 0 && manager->exiting)
|
||||
need_clientmgr_destroy = ISC_TRUE;
|
||||
ISC_LIST_UNLINK(manager->clients, client, link);
|
||||
|
||||
UNLOCK(&manager->lock);
|
||||
|
||||
client_free(client);
|
||||
|
||||
if (need_clientmgr_destroy)
|
||||
clientmgr_destroy(manager);
|
||||
}
|
||||
|
||||
static void
|
||||
client_shutdown(isc_task_t *task, isc_event_t *event) {
|
||||
ns_client_t *client;
|
||||
|
||||
REQUIRE(event != NULL);
|
||||
REQUIRE(event->type == ISC_TASKEVENT_SHUTDOWN);
|
||||
client = event->arg;
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
REQUIRE(task == client->task);
|
||||
|
||||
CTRACE("shutdown");
|
||||
|
||||
ns_client_destroy(client);
|
||||
|
||||
isc_event_free(&event);
|
||||
}
|
||||
|
||||
void
|
||||
ns_client_next(ns_client_t *client, isc_result_t result) {
|
||||
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
REQUIRE(client->state == ns_clientstate_listening ||
|
||||
client->state == ns_clientstate_working);
|
||||
|
||||
CTRACE("next");
|
||||
|
||||
/*
|
||||
* XXXRTH If result != ISC_R_SUCCESS:
|
||||
* Log result if there is interest in doing so.
|
||||
* If this is a TCP client, close the connection.
|
||||
*/
|
||||
(void)result;
|
||||
|
||||
dns_message_reset(client->message, DNS_MESSAGE_INTENTPARSE);
|
||||
if (client->dispevent != NULL) {
|
||||
dns_dispatch_freeevent(client->dispatch, client->dispentry,
|
||||
&client->dispevent);
|
||||
client->state = ns_clientstate_listening;
|
||||
}
|
||||
}
|
||||
|
||||
static void client_send(ns_client_t *client);
|
||||
|
||||
static void
|
||||
client_senddone(isc_task_t *task, isc_event_t *event) {
|
||||
ns_client_t *client;
|
||||
isc_socketevent_t *sevent = (isc_socketevent_t *)event;
|
||||
|
||||
REQUIRE(sevent != NULL);
|
||||
REQUIRE(sevent->common.type == ISC_SOCKEVENT_SENDDONE);
|
||||
client = sevent->common.arg;
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
REQUIRE(task == client->task);
|
||||
|
||||
CTRACE("senddone");
|
||||
|
||||
client->nsends--;
|
||||
isc_mempool_put(client->sendbufs, sevent->region.base);
|
||||
|
||||
isc_event_free(&event);
|
||||
|
||||
/*
|
||||
* If all of its sendbufs buffers were busy, the client might be
|
||||
* waiting for one to become available.
|
||||
*/
|
||||
if (client->state == ns_clientstate_waiting) {
|
||||
client->state = ns_clientstate_working;
|
||||
client_send(client);
|
||||
return;
|
||||
}
|
||||
/* XXXRTH need to add exit draining mode. */
|
||||
}
|
||||
|
||||
static void
|
||||
client_send(ns_client_t *client) {
|
||||
isc_result_t result;
|
||||
unsigned char *data;
|
||||
isc_buffer_t buffer;
|
||||
isc_region_t r;
|
||||
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
|
||||
CTRACE("send");
|
||||
|
||||
data = isc_mempool_get(client->sendbufs);
|
||||
if (data == NULL) {
|
||||
CTRACE("no buffers available");
|
||||
if (client->nsends > 0) {
|
||||
/*
|
||||
* We couldn't get memory, but there is at least one
|
||||
* send outstanding. We arrange to be restarted when a
|
||||
* send completes.
|
||||
*/
|
||||
CTRACE("waiting");
|
||||
INSIST(client->state == ns_clientstate_working);
|
||||
client->state = ns_clientstate_waiting;
|
||||
} else
|
||||
ns_client_next(client, ISC_R_NOMEMORY);
|
||||
return;
|
||||
}
|
||||
|
||||
isc_buffer_init(&buffer, data, SEND_BUFFER_SIZE,
|
||||
ISC_BUFFERTYPE_BINARY);
|
||||
result = dns_message_renderbegin(client->message, &buffer);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto done;
|
||||
result = dns_message_rendersection(client->message,
|
||||
DNS_SECTION_QUESTION, 0, 0);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto done;
|
||||
result = dns_message_renderend(client->message);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto done;
|
||||
isc_buffer_used(&buffer, &r);
|
||||
/* XXXRTH this only works for UDP clients. */
|
||||
CTRACE("sendto");
|
||||
result = isc_socket_sendto(dns_dispatch_getsocket(client->dispatch),
|
||||
&r, client->task, client_senddone, client,
|
||||
&client->dispevent->addr);
|
||||
if (result == ISC_R_SUCCESS)
|
||||
client->nsends++;
|
||||
|
||||
done:
|
||||
if (result != ISC_R_SUCCESS)
|
||||
isc_mempool_put(client->sendbufs, data);
|
||||
|
||||
ns_client_next(client, result);
|
||||
}
|
||||
|
||||
void
|
||||
ns_client_error(ns_client_t *client, isc_result_t result) {
|
||||
dns_rcode_t rcode;
|
||||
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
|
||||
CTRACE("error");
|
||||
|
||||
rcode = dns_result_torcode(result);
|
||||
|
||||
result = dns_message_reply(client->message, ISC_TRUE);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ns_client_next(client, result);
|
||||
return;
|
||||
}
|
||||
client->message->rcode = rcode;
|
||||
client_send(client);
|
||||
}
|
||||
|
||||
static void
|
||||
client_recv(isc_task_t *task, isc_event_t *event) {
|
||||
ns_client_t *client;
|
||||
dns_dispatchevent_t *devent = (dns_dispatchevent_t *)event;
|
||||
isc_result_t result;
|
||||
|
||||
REQUIRE(devent != NULL);
|
||||
REQUIRE(devent->type == DNS_EVENT_DISPATCH);
|
||||
client = devent->arg;
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
REQUIRE(task == client->task);
|
||||
REQUIRE(client->dispentry != NULL);
|
||||
|
||||
CTRACE("recv");
|
||||
|
||||
client->dispevent = devent;
|
||||
if (devent->result != ISC_R_SUCCESS) {
|
||||
ns_client_destroy(client);
|
||||
return;
|
||||
}
|
||||
|
||||
client->state = ns_clientstate_working;
|
||||
result = dns_message_parse(client->message, &devent->buffer);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
ns_client_error(client, result);
|
||||
return;
|
||||
}
|
||||
INSIST((client->message->flags & DNS_MESSAGEFLAG_QR) == 0);
|
||||
|
||||
/*
|
||||
* Dispatch the request.
|
||||
*/
|
||||
switch (client->message->opcode) {
|
||||
#if 0
|
||||
case dns_opcode_query:
|
||||
CTRACE("query");
|
||||
ns_query_start(client);
|
||||
break;
|
||||
#endif
|
||||
case dns_opcode_iquery:
|
||||
CTRACE("iquery");
|
||||
ns_client_error(client, DNS_R_REFUSED);
|
||||
default:
|
||||
CTRACE("unknown opcode");
|
||||
ns_client_error(client, DNS_R_NOTIMP);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
client_timeout(isc_task_t *task, isc_event_t *event) {
|
||||
ns_client_t *client;
|
||||
|
||||
REQUIRE(event != NULL);
|
||||
REQUIRE(event->type == ISC_TIMEREVENT_LIFE ||
|
||||
event->type == ISC_TIMEREVENT_IDLE);
|
||||
client = event->arg;
|
||||
REQUIRE(NS_CLIENT_VALID(client));
|
||||
REQUIRE(task == client->task);
|
||||
REQUIRE(client->timer != NULL);
|
||||
|
||||
CTRACE("timeout");
|
||||
|
||||
isc_event_free(&event);
|
||||
|
||||
ns_client_next(client, ISC_R_TIMEDOUT);
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
client_create(ns_clientmgr_t *manager, ns_clienttype_t type,
|
||||
ns_client_t **clientp)
|
||||
{
|
||||
ns_client_t *client;
|
||||
isc_result_t result;
|
||||
|
||||
/*
|
||||
* Caller must be holding the manager lock.
|
||||
*
|
||||
* Note: creating a client does not add the client to the manager's
|
||||
* client list. The caller is responsible for that.
|
||||
*/
|
||||
|
||||
REQUIRE(clientp != NULL && *clientp == NULL);
|
||||
|
||||
client = isc_mem_get(manager->mctx, sizeof *client);
|
||||
if (client == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
|
||||
client->task = NULL;
|
||||
result = isc_task_create(manager->taskmgr, manager->mctx, 0,
|
||||
&client->task);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup_client;
|
||||
result = isc_task_onshutdown(client->task, client_shutdown, client);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup_task;
|
||||
|
||||
client->timer = NULL;
|
||||
result = isc_timer_create(manager->timermgr, isc_timertype_inactive,
|
||||
NULL, NULL, client->task, client_timeout,
|
||||
client, &client->timer);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup_task;
|
||||
|
||||
client->message = NULL;
|
||||
result = dns_message_create(manager->mctx, DNS_MESSAGE_INTENTPARSE,
|
||||
&client->message);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup_timer;
|
||||
|
||||
/* XXXRTH Hardwired constants */
|
||||
client->sendbufs = NULL;
|
||||
result = isc_mempool_create(manager->mctx, SEND_BUFFER_SIZE,
|
||||
&client->sendbufs);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup_message;
|
||||
isc_mempool_setfreemax(client->sendbufs, 3);
|
||||
isc_mempool_setmaxalloc(client->sendbufs, 3);
|
||||
|
||||
client->manager = manager;
|
||||
client->type = type;
|
||||
client->state = ns_clientstate_idle;
|
||||
client->attributes = 0;
|
||||
client->dispatch = NULL;
|
||||
client->dispentry = NULL;
|
||||
client->dispevent = NULL;
|
||||
client->nsends = 0;
|
||||
ISC_LINK_INIT(client, link);
|
||||
client->magic = NS_CLIENT_MAGIC;
|
||||
|
||||
CTRACE("create");
|
||||
|
||||
*clientp = client;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup_message:
|
||||
dns_message_destroy(&client->message);
|
||||
|
||||
cleanup_timer:
|
||||
isc_timer_detach(&client->timer);
|
||||
|
||||
cleanup_task:
|
||||
isc_task_detach(&client->task);
|
||||
|
||||
cleanup_client:
|
||||
isc_mem_put(manager->mctx, client, sizeof *client);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
|
||||
/***
|
||||
*** Client Manager
|
||||
***/
|
||||
|
||||
static void
|
||||
clientmgr_destroy(ns_clientmgr_t *manager) {
|
||||
REQUIRE(manager->nclients == 0);
|
||||
REQUIRE(ISC_LIST_EMPTY(manager->clients));
|
||||
|
||||
MTRACE("clientmgr_destroy");
|
||||
|
||||
manager->magic = 0;
|
||||
isc_mem_put(manager->mctx, manager, sizeof *manager);
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
isc_timermgr_t *timermgr, ns_clientmgr_t **managerp)
|
||||
{
|
||||
ns_clientmgr_t *manager;
|
||||
isc_result_t result;
|
||||
|
||||
manager = isc_mem_get(mctx, sizeof *manager);
|
||||
if (manager == NULL)
|
||||
return (ISC_R_NOMEMORY);
|
||||
|
||||
result = isc_mutex_init(&manager->lock);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
goto cleanup_manager;
|
||||
|
||||
manager->mctx = mctx;
|
||||
manager->taskmgr = taskmgr;
|
||||
manager->timermgr = timermgr;
|
||||
manager->exiting = ISC_FALSE;
|
||||
manager->nclients = 0;
|
||||
ISC_LIST_INIT(manager->clients);
|
||||
manager->magic = MANAGER_MAGIC;
|
||||
|
||||
MTRACE("create");
|
||||
|
||||
*managerp = manager;
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
|
||||
cleanup_manager:
|
||||
isc_mem_put(manager->mctx, manager, sizeof *manager);
|
||||
|
||||
return (result);
|
||||
}
|
||||
|
||||
void
|
||||
ns_clientmgr_destroy(ns_clientmgr_t **managerp) {
|
||||
ns_clientmgr_t *manager;
|
||||
ns_client_t *client;
|
||||
isc_boolean_t need_destroy = ISC_FALSE;
|
||||
|
||||
REQUIRE(managerp != NULL);
|
||||
manager = *managerp;
|
||||
REQUIRE(VALID_MANAGER(manager));
|
||||
|
||||
MTRACE("destroy");
|
||||
|
||||
LOCK(&manager->lock);
|
||||
|
||||
manager->exiting = ISC_TRUE;
|
||||
|
||||
for (client = ISC_LIST_HEAD(manager->clients);
|
||||
client != NULL;
|
||||
client = ISC_LIST_NEXT(client, link))
|
||||
isc_task_shutdown(client->task);
|
||||
|
||||
if (ISC_LIST_EMPTY(manager->clients))
|
||||
need_destroy = ISC_TRUE;
|
||||
|
||||
UNLOCK(&manager->lock);
|
||||
|
||||
if (need_destroy)
|
||||
clientmgr_destroy(manager);
|
||||
|
||||
*managerp = NULL;
|
||||
}
|
||||
|
||||
isc_result_t
|
||||
ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, ns_clienttype_t type,
|
||||
unsigned int n,
|
||||
dns_dispatch_t *dispatch)
|
||||
{
|
||||
isc_result_t result = ISC_R_SUCCESS;
|
||||
unsigned int i;
|
||||
ns_client_t *client;
|
||||
|
||||
REQUIRE(VALID_MANAGER(manager));
|
||||
REQUIRE(n > 0);
|
||||
|
||||
MTRACE("addtodispatch");
|
||||
|
||||
/*
|
||||
* We MUST lock the manager lock for the entire client creation
|
||||
* process. If we didn't do this, then a client could get a
|
||||
* shutdown event and disappear out from under us.
|
||||
*/
|
||||
|
||||
LOCK(&manager->lock);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
client = NULL;
|
||||
result = client_create(manager, type, &client);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
break;
|
||||
dns_dispatch_attach(dispatch, &client->dispatch);
|
||||
result = dns_dispatch_addrequest(dispatch, client->task,
|
||||
client_recv,
|
||||
client, &client->dispentry);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
client_free(client);
|
||||
break;
|
||||
}
|
||||
client->state = ns_clientstate_listening;
|
||||
manager->nclients++;
|
||||
ISC_LIST_APPEND(manager->clients, client, link);
|
||||
}
|
||||
if (i != 0) {
|
||||
/*
|
||||
* We managed to create at least one client, so we
|
||||
* declare victory.
|
||||
*/
|
||||
result = ISC_R_SUCCESS;
|
||||
}
|
||||
|
||||
UNLOCK(&manager->lock);
|
||||
|
||||
return (result);
|
||||
}
|
88
bin/named/include/named/client.h
Normal file
88
bin/named/include/named/client.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 1999 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef NS_CLIENT_H
|
||||
#define NS_CLIENT_H 1
|
||||
|
||||
#include <isc/types.h>
|
||||
#include <isc/buffer.h>
|
||||
|
||||
#include <dns/types.h>
|
||||
|
||||
#include <named/types.h>
|
||||
|
||||
typedef enum ns_clienttype {
|
||||
ns_clienttype_basic = 0,
|
||||
ns_clienttype_recursive,
|
||||
ns_clienttype_axfr,
|
||||
ns_clienttype_ixfr
|
||||
} ns_clienttype_t;
|
||||
|
||||
typedef enum {
|
||||
ns_clientstate_idle = 0,
|
||||
ns_clientstate_listening,
|
||||
ns_clientstate_working,
|
||||
ns_clientstate_waiting
|
||||
} ns_clientstate_t;
|
||||
|
||||
struct ns_client {
|
||||
unsigned int magic;
|
||||
ns_clientmgr_t * manager;
|
||||
ns_clienttype_t type;
|
||||
ns_clientstate_t state;
|
||||
unsigned int attributes;
|
||||
isc_task_t * task;
|
||||
dns_dispatch_t * dispatch;
|
||||
dns_dispentry_t * dispentry;
|
||||
dns_dispatchevent_t * dispevent;
|
||||
isc_timer_t * timer;
|
||||
dns_message_t * message;
|
||||
unsigned int nsends;
|
||||
isc_mempool_t * sendbufs;
|
||||
ISC_LINK(struct ns_client) link;
|
||||
};
|
||||
|
||||
#define NS_CLIENT_MAGIC 0x4E534363U /* NSCc */
|
||||
#define NS_CLIENT_VALID(c) ((c) != NULL && \
|
||||
(c)->magic == NS_CLIENT_MAGIC)
|
||||
|
||||
/*
|
||||
* Note! These ns_client_ routines MUST be called ONLY from the client's
|
||||
* task in order to ensure synchronization.
|
||||
*/
|
||||
void
|
||||
ns_client_error(ns_client_t *client, isc_result_t result);
|
||||
|
||||
void
|
||||
ns_client_next(ns_client_t *client, isc_result_t result);
|
||||
|
||||
void
|
||||
ns_client_destroy(ns_client_t *client);
|
||||
|
||||
isc_result_t
|
||||
ns_clientmgr_create(isc_mem_t *mctx, isc_taskmgr_t *taskmgr,
|
||||
isc_timermgr_t *timermgr, ns_clientmgr_t **managerp);
|
||||
|
||||
void
|
||||
ns_clientmgr_destroy(ns_clientmgr_t **managerp);
|
||||
|
||||
isc_result_t
|
||||
ns_clientmgr_addtodispatch(ns_clientmgr_t *manager, ns_clienttype_t type,
|
||||
unsigned int n,
|
||||
dns_dispatch_t *dispatch);
|
||||
|
||||
#endif /* NS_CLIENT_H */
|
62
bin/named/include/named/globals.h
Normal file
62
bin/named/include/named/globals.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Copyright (C) 1999 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef NS_GLOBALS_H
|
||||
#define NS_GLOBALS_H 1
|
||||
|
||||
#include <isc/types.h>
|
||||
#include <isc/rwlock.h>
|
||||
|
||||
#include <dns/types.h>
|
||||
|
||||
#include <named/types.h>
|
||||
#include <named/interfacemgr.h>
|
||||
|
||||
#undef EXTERN
|
||||
#undef INIT
|
||||
#ifdef NS_MAIN
|
||||
#define EXTERN
|
||||
#define INIT(v) = (v)
|
||||
#else
|
||||
#define EXTERN extern
|
||||
#define INIT(v)
|
||||
#endif
|
||||
|
||||
EXTERN isc_mem_t * ns_g_mctx INIT(NULL);
|
||||
EXTERN unsigned int ns_g_cpus INIT(1);
|
||||
EXTERN isc_taskmgr_t * ns_g_taskmgr INIT(NULL);
|
||||
/*
|
||||
* XXXRTH We're going to want multiple timer managers eventually. One
|
||||
* for really short timers, another for client timers, and one
|
||||
* for zone timers.
|
||||
*/
|
||||
EXTERN isc_timermgr_t * ns_g_timermgr INIT(NULL);
|
||||
EXTERN isc_socketmgr_t * ns_g_socketmgr INIT(NULL);
|
||||
EXTERN ns_interfacemgr_t * ns_g_interfacemgr INIT(NULL);
|
||||
EXTERN ns_clientmgr_t * ns_g_clientmgr INIT(NULL);
|
||||
EXTERN char * ns_g_version INIT(VERSION);
|
||||
|
||||
EXTERN isc_rwlock_t ns_g_viewlock;
|
||||
EXTERN dns_viewlist_t ns_g_views;
|
||||
|
||||
/* XXXRTH This next one is temporary. */
|
||||
EXTERN ns_dbinfolist_t ns_g_dbs;
|
||||
|
||||
#undef EXTERN
|
||||
#undef INIT
|
||||
|
||||
#endif /* NS_GLOBALS_H */
|
25
bin/named/include/named/query.h
Normal file
25
bin/named/include/named/query.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 1999 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef NS_QUERY_H
|
||||
#define NS_QUERY_H 1
|
||||
|
||||
#include <named/types.h>
|
||||
|
||||
void ns_query_start(ns_client_t *client);
|
||||
|
||||
#endif /* NS_QUERY_H */
|
25
bin/named/include/named/server.h
Normal file
25
bin/named/include/named/server.h
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 1999 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef NS_SERVER_H
|
||||
#define NS_SERVER_H 1
|
||||
|
||||
#include <isc/types.h>
|
||||
|
||||
isc_result_t ns_server_init(void);
|
||||
|
||||
#endif /* NS_SERVER_H */
|
47
bin/named/include/named/types.h
Normal file
47
bin/named/include/named/types.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 1999 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef NS_TYPES_H
|
||||
#define NS_TYPES_H 1
|
||||
|
||||
#include <isc/list.h>
|
||||
|
||||
#include <dns/types.h>
|
||||
|
||||
typedef struct ns_client ns_client_t;
|
||||
typedef struct ns_clientmgr ns_clientmgr_t;
|
||||
|
||||
/*
|
||||
* XXXRTH This stuff is temporary. As soon as we have zone and config
|
||||
* support, it will go away.
|
||||
*/
|
||||
|
||||
typedef struct ns_dbinfo {
|
||||
char * path;
|
||||
char * origin;
|
||||
isc_boolean_t iscache;
|
||||
dns_db_t * db;
|
||||
ISC_LINK(struct ns_dbinfo) link;
|
||||
} ns_dbinfo_t;
|
||||
|
||||
typedef ISC_LIST(ns_dbinfo_t) ns_dbinfolist_t;
|
||||
|
||||
/*
|
||||
* XXXRTH End of temporary stuff.
|
||||
*/
|
||||
|
||||
#endif /* NS_TYPES_H */
|
263
bin/named/main.c
Normal file
263
bin/named/main.c
Normal file
@@ -0,0 +1,263 @@
|
||||
/*
|
||||
* Copyright (C) 1999 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h> /* XXXRTH Naughty. Needed for getopt(). */
|
||||
|
||||
#include <isc/app.h>
|
||||
#include <isc/error.h>
|
||||
#include <isc/boolean.h>
|
||||
#include <isc/task.h>
|
||||
#include <isc/timer.h>
|
||||
|
||||
#include <dns/dbtable.h>
|
||||
#include <dns/result.h>
|
||||
|
||||
#include <dst/result.h>
|
||||
|
||||
#define NS_MAIN 1
|
||||
|
||||
#include <named/globals.h>
|
||||
#include <named/client.h>
|
||||
#include <named/interfacemgr.h>
|
||||
#include <named/server.h>
|
||||
|
||||
static isc_boolean_t want_stats = ISC_FALSE;
|
||||
|
||||
static void
|
||||
early_fatal(char *format, ...) {
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
fprintf(stderr, "\n");
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static void
|
||||
usage(void) {
|
||||
fprintf(stderr,
|
||||
"usage: named [[-c cachefile] ...] [[-z zonefile] ...]\n");
|
||||
fprintf(stderr,
|
||||
" [-s] [-N number of cpus]\n");
|
||||
}
|
||||
|
||||
static void
|
||||
parse_command_line(int argc, char *argv[]) {
|
||||
char *origintext;
|
||||
int ch;
|
||||
ns_dbinfo_t *dbi;
|
||||
|
||||
/*+ XXXRTH we need a veneered getopt() */
|
||||
while ((ch = getopt(argc, argv, "c:N:sz:")) != -1) {
|
||||
switch (ch) {
|
||||
case 'c':
|
||||
/* XXXRTH temporary syntax */
|
||||
dbi = isc_mem_get(ns_g_mctx, sizeof *dbi);
|
||||
if (dbi == NULL)
|
||||
early_fatal("creating cache info failed");
|
||||
dbi->path = optarg;
|
||||
dbi->origin = ".";
|
||||
dbi->iscache = ISC_TRUE;
|
||||
dbi->db = NULL;
|
||||
ISC_LINK_INIT(dbi, link);
|
||||
ISC_LIST_APPEND(ns_g_dbs, dbi, link);
|
||||
break;
|
||||
case 'N':
|
||||
ns_g_cpus = atoi(optarg);
|
||||
if (ns_g_cpus == 0)
|
||||
ns_g_cpus = 1;
|
||||
break;
|
||||
case 's':
|
||||
/* XXXRTH temporary syntax */
|
||||
want_stats = ISC_TRUE;
|
||||
break;
|
||||
case 'z':
|
||||
/* XXXRTH temporary syntax */
|
||||
origintext = strrchr(optarg, '/');
|
||||
if (origintext == NULL)
|
||||
origintext = optarg;
|
||||
else
|
||||
origintext++; /* Skip '/'. */
|
||||
dbi = isc_mem_get(ns_g_mctx, sizeof *dbi);
|
||||
if (dbi == NULL)
|
||||
early_fatal("creating zone info failed");
|
||||
dbi->path = optarg;
|
||||
dbi->origin = origintext;
|
||||
dbi->iscache = ISC_FALSE;
|
||||
dbi->db = NULL;
|
||||
ISC_LINK_INIT(dbi, link);
|
||||
ISC_LIST_APPEND(ns_g_dbs, dbi, link);
|
||||
break;
|
||||
case '?':
|
||||
usage();
|
||||
early_fatal("unknown command line argument");
|
||||
break;
|
||||
default:
|
||||
early_fatal("getopt() returned %d", ch);
|
||||
}
|
||||
}
|
||||
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
if (argc > 1) {
|
||||
usage();
|
||||
early_fatal("extra command line arguments");
|
||||
}
|
||||
}
|
||||
|
||||
static isc_result_t
|
||||
create_managers() {
|
||||
isc_result_t result;
|
||||
|
||||
result = isc_taskmgr_create(ns_g_mctx, ns_g_cpus, 0, &ns_g_taskmgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"ns_taskmgr_create() failed: %s\n",
|
||||
isc_result_totext(result));
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
result = isc_timermgr_create(ns_g_mctx, &ns_g_timermgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"ns_timermgr_create() failed: %s\n",
|
||||
isc_result_totext(result));
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
result = isc_socketmgr_create(ns_g_mctx, &ns_g_socketmgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"isc_socketmgr_create() failed: %s\n",
|
||||
isc_result_totext(result));
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
result = ns_clientmgr_create(ns_g_mctx, ns_g_taskmgr, ns_g_timermgr,
|
||||
&ns_g_clientmgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"ns_clientmgr_create() failed: %s\n",
|
||||
isc_result_totext(result));
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
result = ns_interfacemgr_create(ns_g_mctx, ns_g_taskmgr,
|
||||
ns_g_socketmgr, ns_g_clientmgr,
|
||||
&ns_g_interfacemgr);
|
||||
if (result != ISC_R_SUCCESS) {
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__,
|
||||
"ns_interfacemgr_create() failed: %s\n",
|
||||
isc_result_totext(result));
|
||||
return (ISC_R_UNEXPECTED);
|
||||
}
|
||||
|
||||
return (ISC_R_SUCCESS);
|
||||
}
|
||||
|
||||
static void
|
||||
destroy_managers(void) {
|
||||
/*
|
||||
* The interface manager owns tasks, so we have to destroy it before
|
||||
* we destroy the task manager.
|
||||
*/
|
||||
ns_interfacemgr_destroy(&ns_g_interfacemgr);
|
||||
/*
|
||||
* isc_taskmgr_destroy() will block until all tasks have exited,
|
||||
*/
|
||||
isc_taskmgr_destroy(&ns_g_taskmgr);
|
||||
isc_timermgr_destroy(&ns_g_timermgr);
|
||||
isc_socketmgr_destroy(&ns_g_socketmgr);
|
||||
ns_clientmgr_destroy(&ns_g_clientmgr);
|
||||
}
|
||||
|
||||
static void
|
||||
setup() {
|
||||
isc_result_t result;
|
||||
|
||||
ISC_LIST_INIT(ns_g_views);
|
||||
|
||||
result = isc_rwlock_init(&ns_g_viewlock, 0, 0);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
early_fatal("isc_rwlock_init() failed: %s",
|
||||
isc_result_totext(result));
|
||||
|
||||
result = create_managers();
|
||||
if (result != ISC_R_SUCCESS)
|
||||
early_fatal("create_managers() failed: %s",
|
||||
isc_result_totext(result));
|
||||
|
||||
result = ns_server_init();
|
||||
if (result != ISC_R_SUCCESS)
|
||||
early_fatal("ns_server_init() failed: %s",
|
||||
isc_result_totext(result));
|
||||
}
|
||||
|
||||
static void
|
||||
cleanup() {
|
||||
destroy_managers();
|
||||
isc_rwlock_destroy(&ns_g_viewlock);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
isc_result_t result;
|
||||
|
||||
result = isc_app_start();
|
||||
if (result != ISC_R_SUCCESS)
|
||||
early_fatal("isc_app_start() failed: %s",
|
||||
isc_result_totext(result));
|
||||
|
||||
result = isc_mem_create(0, 0, &ns_g_mctx);
|
||||
if (result != ISC_R_SUCCESS)
|
||||
early_fatal("isc_mem_create() failed: %s",
|
||||
isc_result_totext(result));
|
||||
|
||||
dns_result_register();
|
||||
dst_result_register();
|
||||
|
||||
parse_command_line(argc, argv);
|
||||
|
||||
setup();
|
||||
|
||||
/*
|
||||
* Start things running and then wait for a shutdown request.
|
||||
*/
|
||||
result = isc_app_run();
|
||||
if (result != ISC_R_SUCCESS)
|
||||
UNEXPECTED_ERROR(__FILE__, __LINE__, "isc_app_run(): %s",
|
||||
isc_result_totext(result));
|
||||
|
||||
cleanup();
|
||||
|
||||
if (want_stats)
|
||||
isc_mem_stats(ns_g_mctx, stdout);
|
||||
isc_mem_destroy(&ns_g_mctx);
|
||||
|
||||
isc_app_finish();
|
||||
|
||||
return (0);
|
||||
}
|
209
bin/named/query.c
Normal file
209
bin/named/query.c
Normal file
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (C) 1999 Internet Software Consortium.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
|
||||
* ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
|
||||
* CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
|
||||
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
|
||||
* PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
|
||||
* ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
|
||||
* SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <isc/assertions.h>
|
||||
#include <isc/mem.h>
|
||||
#include <isc/mutex.h>
|
||||
#include <isc/result.h>
|
||||
#include <isc/task.h>
|
||||
#include <isc/timer.h>
|
||||
|
||||
#include <dns/dispatch.h>
|
||||
#include <dns/events.h>
|
||||
|
||||
#include <named/client.h>
|
||||
|
||||
#include "../../isc/util.h" /* XXX */
|
||||
|
||||
static dns_result_t
|
||||
resolve_packet(isc_mem_t *mctx, dns_message_t *query, isc_buffer_t *target) {
|
||||
dns_message_t *message;
|
||||
dns_result_t result, dbresult;
|
||||
dns_name_t *qname, *fname, *rqname;
|
||||
dns_fixedname_t foundname, frqname;
|
||||
dns_rdataset_t *rds, *rdataset, rqrds, rdatasets[MAX_RDATASETS];
|
||||
unsigned int nrdatasets = 0;
|
||||
dns_dbnode_t *node;
|
||||
dns_db_t *db;
|
||||
dns_rdatasetiter_t *rdsiter;
|
||||
dns_rdatatype_t type;
|
||||
isc_boolean_t possibly_auth = ISC_FALSE;
|
||||
|
||||
message = NULL;
|
||||
result = dns_message_create(mctx, &message, DNS_MESSAGE_INTENTRENDER);
|
||||
CHECKRESULT(result, "dns_message_create failed");
|
||||
|
||||
message->id = query->id;
|
||||
message->rcode = dns_rcode_noerror;
|
||||
message->flags = query->flags;
|
||||
message->flags |= DNS_MESSAGEFLAG_QR;
|
||||
|
||||
result = dns_message_firstname(query, DNS_SECTION_QUESTION);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
return (result);
|
||||
qname = NULL;
|
||||
dns_fixedname_init(&frqname);
|
||||
rqname = dns_fixedname_name(&frqname);
|
||||
dns_message_currentname(query, DNS_SECTION_QUESTION, &qname);
|
||||
result = dns_name_concatenate(qname, NULL, rqname, NULL);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
return (DNS_R_UNEXPECTED);
|
||||
rds = ISC_LIST_HEAD(qname->list);
|
||||
if (rds == NULL)
|
||||
return (DNS_R_UNEXPECTED);
|
||||
type = rds->type;
|
||||
dns_rdataset_init(&rqrds);
|
||||
dns_rdataset_makequestion(&rqrds, rds->rdclass, rds->type);
|
||||
ISC_LIST_APPEND(rqname->list, &rqrds, link);
|
||||
|
||||
dns_message_addname(message, rqname, DNS_SECTION_QUESTION);
|
||||
|
||||
result = printmessage(message);
|
||||
INSIST(result == DNS_R_SUCCESS); /* XXX not in a real server */
|
||||
|
||||
/*
|
||||
* Find a database to answer the query from.
|
||||
*/
|
||||
db = NULL;
|
||||
result = dns_dbtable_find(dbtable, qname, &db);
|
||||
if (result != DNS_R_SUCCESS && result != DNS_R_PARTIALMATCH) {
|
||||
printf("could not find a dbtable: %s\n",
|
||||
dns_result_totext(result));
|
||||
message->rcode = dns_rcode_servfail;
|
||||
goto render;
|
||||
}
|
||||
|
||||
/*
|
||||
* Now look for an answer in the database.
|
||||
*/
|
||||
dns_fixedname_init(&foundname);
|
||||
fname = dns_fixedname_name(&foundname);
|
||||
rdataset = &rdatasets[nrdatasets++];
|
||||
dns_rdataset_init(rdataset);
|
||||
node = NULL;
|
||||
dbresult = dns_db_find(db, qname, NULL, type, 0, 0, &node, fname,
|
||||
rdataset);
|
||||
switch (dbresult) {
|
||||
case DNS_R_SUCCESS:
|
||||
case DNS_R_DNAME:
|
||||
case DNS_R_CNAME:
|
||||
possibly_auth = ISC_TRUE;
|
||||
break;
|
||||
case DNS_R_GLUE:
|
||||
case DNS_R_ZONECUT:
|
||||
case DNS_R_DELEGATION:
|
||||
break;
|
||||
case DNS_R_NXRDATASET:
|
||||
if (dns_db_iszone(db))
|
||||
message->flags |= DNS_MESSAGEFLAG_AA;
|
||||
dns_db_detachnode(db, &node);
|
||||
dns_db_detach(&db);
|
||||
goto render;
|
||||
case DNS_R_NXDOMAIN:
|
||||
if (dns_db_iszone(db))
|
||||
message->flags |= DNS_MESSAGEFLAG_AA;
|
||||
dns_db_detach(&db);
|
||||
message->rcode = dns_rcode_nxdomain;
|
||||
goto render;
|
||||
default:
|
||||
printf("%s\n", dns_result_totext(result));
|
||||
dns_db_detach(&db);
|
||||
message->rcode = dns_rcode_servfail;
|
||||
goto render;
|
||||
}
|
||||
|
||||
if (dbresult == DNS_R_DELEGATION) {
|
||||
ISC_LIST_APPEND(fname->list, rdataset, link);
|
||||
dns_message_addname(message, fname, DNS_SECTION_AUTHORITY);
|
||||
} else if (type == dns_rdatatype_any) {
|
||||
rdsiter = NULL;
|
||||
result = dns_db_allrdatasets(db, node, NULL, 0, &rdsiter);
|
||||
if (result == DNS_R_SUCCESS)
|
||||
result = dns_rdatasetiter_first(rdsiter);
|
||||
while (result == DNS_R_SUCCESS) {
|
||||
dns_rdatasetiter_current(rdsiter, rdataset);
|
||||
ISC_LIST_APPEND(fname->list, rdataset, link);
|
||||
if (nrdatasets == MAX_RDATASETS) {
|
||||
result = DNS_R_NOSPACE;
|
||||
} else {
|
||||
rdataset = &rdatasets[nrdatasets++];
|
||||
dns_rdataset_init(rdataset);
|
||||
result = dns_rdatasetiter_next(rdsiter);
|
||||
}
|
||||
}
|
||||
if (result != DNS_R_NOMORE) {
|
||||
dns_db_detachnode(db, &node);
|
||||
dns_db_detach(&db);
|
||||
message->rcode = dns_rcode_servfail;
|
||||
goto render;
|
||||
}
|
||||
dns_message_addname(message, fname, DNS_SECTION_ANSWER);
|
||||
} else {
|
||||
ISC_LIST_APPEND(fname->list, rdataset, link);
|
||||
dns_message_addname(message, fname, DNS_SECTION_ANSWER);
|
||||
}
|
||||
|
||||
if (dns_db_iszone(db) && possibly_auth)
|
||||
message->flags |= DNS_MESSAGEFLAG_AA;
|
||||
|
||||
dns_db_detachnode(db, &node);
|
||||
dns_db_detach(&db);
|
||||
|
||||
render:
|
||||
|
||||
result = dns_message_renderbegin(message, target);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
result = dns_message_rendersection(message, DNS_SECTION_QUESTION,
|
||||
0, 0);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
result = dns_message_rendersection(message, DNS_SECTION_ANSWER,
|
||||
0, 0);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
result = dns_message_rendersection(message, DNS_SECTION_AUTHORITY,
|
||||
0, 0);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
result = dns_message_rendersection(message, DNS_SECTION_ADDITIONAL,
|
||||
0, 0);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
result = dns_message_rendersection(message, DNS_SECTION_TSIG,
|
||||
0, 0);
|
||||
if (result != DNS_R_SUCCESS)
|
||||
return (result);
|
||||
|
||||
result = dns_message_renderend(message);
|
||||
|
||||
dns_message_destroy(&message);
|
||||
|
||||
return (DNS_R_SUCCESS);
|
||||
}
|
||||
|
||||
void
|
||||
ns_query_start(ns_client_t *client) {
|
||||
|
||||
}
|
1011
doc/rfc/rfc1876.txt
Normal file
1011
doc/rfc/rfc1876.txt
Normal file
File diff suppressed because it is too large
Load Diff
1123
doc/rfc/rfc2168.txt
Normal file
1123
doc/rfc/rfc2168.txt
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user