Commit 51c0bc9e authored by Michael Graff's avatar Michael Graff
Browse files

Actually answers queries!

parent d65db529
......@@ -38,6 +38,7 @@
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/compress.h>
#include <dns/db.h>
#include <sys/types.h>
#include <sys/socket.h>
......@@ -52,6 +53,38 @@
isc_mem_t *mctx = NULL;
dns_db_t *db;
/*
* For debugging only... XXX
*/
void dump_packet(char *buf, u_int len);
static void
makename(isc_mem_t *mctx, char *text, dns_name_t *name, dns_name_t *origin) {
char b[255];
isc_buffer_t source, target;
size_t len;
isc_region_t r1, r2;
dns_result_t result;
if (origin == NULL)
origin = dns_rootname;
dns_name_init(name, NULL);
len = strlen(text);
isc_buffer_init(&source, text, len, ISC_BUFFERTYPE_TEXT);
isc_buffer_add(&source, len);
isc_buffer_init(&target, b, sizeof b, ISC_BUFFERTYPE_BINARY);
result = dns_name_fromtext(name, &source, origin, ISC_FALSE, &target);
RUNTIME_CHECK(result == DNS_R_SUCCESS);
dns_name_toregion(name, &r1);
r2.base = isc_mem_get(mctx, r1.length);
RUNTIME_CHECK(r2.base != NULL);
r2.length = r1.length;
memcpy(r2.base, r1.base, r1.length);
dns_name_fromregion(name, &r2);
}
/*
* Process the wire format message given in r, and return a new packet to
* transmit.
......@@ -64,28 +97,50 @@ isc_mem_t *mctx = NULL;
static dns_result_t
dispatch(isc_mem_t *mctx, isc_region_t *rxr, unsigned int reslen)
{
char t[5000];
isc_buffer_t source;
isc_buffer_t target;
dns_result_t result;
isc_region_t txr;
unsigned char *cp;
dump_packet(rxr->base, rxr->length);
/*
* Set up the temporary output buffer.
*/
isc_buffer_init(&target, t, sizeof(t), ISC_BUFFERTYPE_BINARY);
isc_buffer_add(&target, reslen);
/*
* Set up the input buffer from the contents of the region passed
* to us.
*/
isc_buffer_init(&source, rxr->base, rxr->length,
ISC_BUFFERTYPE_BINARY);
isc_buffer_add(&source, rxr->length);
result = resolve_packet(db, &source, &target);
if (result != DNS_R_SUCCESS)
return (result);
/*
* XXX for now, just SERVFAIL everything.
* Copy the reply out
*/
txr.length = rxr->length + reslen;
isc_buffer_used(&target, &txr);
txr.length += reslen;
txr.base = isc_mem_get(mctx, txr.length);
if (txr.base == NULL)
return (DNS_R_NOMEMORY);
memcpy(txr.base + reslen, rxr->base, rxr->length);
cp = txr.base + reslen;
cp += 2;
*cp |= 0x80; /* set QR to response */
*cp++ &= 0xf9; /* clear AA, TC */
*cp++ = 2; /* SERVFAIL */
memcpy(txr.base + reslen, t + reslen, txr.length - reslen);
rxr->base = txr.base;
rxr->length = txr.length;
printf("Base == %p, length == %u\n", txr.base, txr.length);
fflush(stdout);
dump_packet(txr.base + reslen, txr.length - reslen);
isc_mem_stats(mctx, stdout);
return (DNS_R_SUCCESS);
......@@ -105,15 +160,40 @@ main(int argc, char *argv[])
tcp_listener_t *ltcp;
isc_cfgctx_t *configctx = NULL;
const char *conffile = "/etc/named.conf"; /* XXX hardwired */
dns_name_t base, *origin;
int ch;
char basetext[1000];
dns_rdatatype_t type = 2;
dns_result_t result;
/*+ XXX */
strcpy(basetext, "");
while ((ch = getopt(argc, argv, "z:t:")) != -1) {
switch (ch) {
case 'z':
strcpy(basetext, optarg);
break;
case 't':
type = atoi(optarg);
break;
}
}
argc -= optind;
argv += optind;
if (argc < 1) {
fprintf(stderr, "usage: named filename\n");
exit(1);
}
/*- XXX */
memset(&sockaddr, 0, sizeof(sockaddr));
sockaddr.type.sin.sin_port = htons(5544);
addrlen = sizeof(struct sockaddr_in);
if (argc > 1)
workers = atoi(argv[1]);
else
workers = 2;
workers = 2;
printf("%d workers\n", workers);
RUNTIME_CHECK(isc_mem_create(0, 0, &mctx) == ISC_R_SUCCESS);
......@@ -122,10 +202,35 @@ main(int argc, char *argv[])
isc_parser_init();
isc_parse_configuration(conffile, mctx, &configctx);
#endif
/*+ XXX */
if (strcmp(basetext, "") == 0)
strcpy(basetext, "vix.com.");
makename(mctx, basetext, &base, NULL);
db = NULL;
result = dns_db_create(mctx, "rbt", &base, ISC_FALSE, 1, 0, NULL,
&db);
RUNTIME_CHECK(result == DNS_R_SUCCESS);
origin = &base;
printf("loading %s\n", argv[0]);
result = dns_db_load(db, argv[0]);
if (result != DNS_R_SUCCESS) {
printf("couldn't load master file: %s\n",
dns_result_totext(result));
exit(1);
}
/*- XXX */
RUNTIME_CHECK(isc_taskmgr_create(mctx, workers, 0, &manager) ==
ISC_R_SUCCESS);
/*
* Open up a database.
*/
socketmgr = NULL;
RUNTIME_CHECK(isc_socketmgr_create(mctx, &socketmgr) == ISC_R_SUCCESS);
......
......@@ -36,11 +36,6 @@
#include "tcpclient.h"
/*
* For debugging only... XXX
*/
void dump_packet(char *buf, u_int len);
static tcp_cctx_t *tcp_cctx_allocate(isc_mem_t *mctx);
static void tcp_cctx_free(tcp_cctx_t *ctx);
......@@ -81,7 +76,9 @@ tcp_cctx_free(tcp_cctx_t *ctx)
static void
tcp_restart(isc_task_t *task, tcp_cctx_t *ctx)
{
#ifdef NOISY
printf("Restarting listen on %u\n", ctx->slot);
#endif
if (ctx->buf != NULL)
isc_mem_put(ctx->mctx, ctx->buf, ctx->buflen);
......@@ -107,8 +104,6 @@ tcp_shutdown(isc_task_t *task, isc_event_t *event)
ctx = (tcp_cctx_t *)(event->arg);
l = ctx->parent;
printf("Parent: %p\n", l);
LOCK(&l->lock);
if (ctx->csock != NULL)
......@@ -129,7 +124,9 @@ tcp_shutdown(isc_task_t *task, isc_event_t *event)
UNLOCK(&l->lock);
#ifdef NOISY
printf("Final shutdown slot %u\n", ctx->slot);
#endif
tcp_cctx_free(ctx);
isc_event_free(&event);
......@@ -147,6 +144,7 @@ tcp_recv_len(isc_task_t *task, isc_event_t *event)
dev = (isc_socketevent_t *)event;
ctx = (tcp_cctx_t *)(event->arg);
#ifdef NOISY
printf("len Task %u (sock %p, base %p, length %d, n %d, result %d)\n",
ctx->slot, sock,
dev->region.base, dev->region.length,
......@@ -154,6 +152,7 @@ tcp_recv_len(isc_task_t *task, isc_event_t *event)
printf("\tFrom: %s port %d\n",
inet_ntoa(dev->address.type.sin.sin_addr),
ntohs(dev->address.type.sin.sin_port));
#endif
if (dev->result == ISC_R_CANCELED) {
isc_task_shutdown(task);
......@@ -184,8 +183,6 @@ tcp_recv_len(isc_task_t *task, isc_event_t *event)
return;
}
printf("Length of buffer: %u\n", ctx->buflen);
region.base = ctx->buf;
region.length = ctx->buflen;
......@@ -210,6 +207,7 @@ tcp_recv_req(isc_task_t *task, isc_event_t *event)
dev = (isc_socketevent_t *)event;
ctx = (tcp_cctx_t *)(event->arg);
#ifdef NOISY
printf("req Task %u (sock %p, base %p, length %d, n %d, result %d)\n",
ctx->slot, sock,
dev->region.base, dev->region.length,
......@@ -217,6 +215,7 @@ tcp_recv_req(isc_task_t *task, isc_event_t *event)
printf("\tFrom: %s port %d\n",
inet_ntoa(dev->address.type.sin.sin_addr),
ntohs(dev->address.type.sin.sin_port));
#endif
if (dev->result == ISC_R_CANCELED) {
isc_task_shutdown(task);
......@@ -233,11 +232,6 @@ tcp_recv_req(isc_task_t *task, isc_event_t *event)
return;
}
/*
* Call the dump routine to print this baby out
*/
dump_packet(ctx->buf, dev->n);
/*
* Call the dispatch() function to actually process this packet.
* If it returns ISC_R_SUCCESS, we have a packet to transmit.
......@@ -246,8 +240,11 @@ tcp_recv_req(isc_task_t *task, isc_event_t *event)
region.base = ctx->buf;
region.length = dev->n;
result = ctx->parent->dispatch(ctx->mctx, &region, 2);
isc_mem_put(ctx->mctx, ctx->buf, ctx->buflen); /* clean up request */
ctx->buf = NULL;
if (ctx->buf != region.base) { /* clean up request */
isc_mem_put(ctx->mctx, ctx->buf, ctx->buflen);
ctx->buf = NULL;
}
/*
* Failure. Close TCP client.
......@@ -286,8 +283,6 @@ tcp_accept(isc_task_t *task, isc_event_t *event)
dev = (isc_socket_newconnev_t *)event;
ctx = (tcp_cctx_t *)(event->arg);
printf("tcp_accept: task %u\n", ctx->slot);
/*
* If we get an error, close the socket. This routine will actually
* close the socket and restart a listen on the parent socket for
......@@ -337,9 +332,11 @@ tcp_send(isc_task_t *task, isc_event_t *event)
dev = (isc_socketevent_t *)event;
ctx = (tcp_cctx_t *)(event->arg);
#ifdef NOISY
printf("tcp_send: task %u\n\t(base %p, length %d, n %d, result %d)\n",
ctx->slot, dev->region.base, dev->region.length,
dev->n, dev->result);
#endif
/*
* release memory regardless of outcome.
......@@ -440,7 +437,5 @@ tcp_listener_start(tcp_listener_t *l,
UNLOCK(&l->lock);
printf("Parent: %p\n", l);
return (ISC_R_SUCCESS);
}
......@@ -30,11 +30,6 @@
#include "udpclient.h"
/*
* For debugging only... XXX
*/
void dump_packet(char *buf, u_int len);
static udp_cctx_t *udp_cctx_allocate(isc_mem_t *mctx);
static void udp_cctx_free(udp_cctx_t *ctx);
......@@ -101,7 +96,9 @@ udp_shutdown(isc_task_t *task, isc_event_t *event)
UNLOCK(&l->lock);
#ifdef NOISY
printf("Final shutdown slot %u\n", ctx->slot);
#endif
udp_cctx_free(ctx);
isc_event_free(&event);
......@@ -120,6 +117,7 @@ udp_recv(isc_task_t *task, isc_event_t *event)
dev = (isc_socketevent_t *)event;
ctx = (udp_cctx_t *)(event->arg);
#ifdef NOISY
printf("Task %u (sock %p, base %p, length %d, n %d, result %d)\n",
ctx->slot, sock,
dev->region.base, dev->region.length,
......@@ -127,6 +125,7 @@ udp_recv(isc_task_t *task, isc_event_t *event)
printf("\tFrom: %s port %d\n",
inet_ntoa(dev->address.type.sin.sin_addr),
ntohs(dev->address.type.sin.sin_port));
#endif
if (dev->result != ISC_R_SUCCESS) {
isc_task_shutdown(task);
......@@ -136,11 +135,6 @@ udp_recv(isc_task_t *task, isc_event_t *event)
return;
}
/*
* Call the dump routine to print this baby out
*/
dump_packet(ctx->buf, dev->n);
region.base = ctx->buf;
region.length = dev->n;
result = ctx->parent->dispatch(ctx->mctx, &region, 0);
......@@ -165,11 +159,14 @@ udp_send(isc_task_t *task, isc_event_t *event)
dev = (isc_socketevent_t *)event;
ctx = (udp_cctx_t *)(event->arg);
#ifdef NOISY
printf("udp_send: task %u\n\t(base %p, length %d, n %d, result %d)\n",
ctx->slot, dev->region.base, dev->region.length,
dev->n, dev->result);
#endif
isc_mem_put(ctx->mctx, dev->region.base, dev->region.length);
if (ctx->buf != dev->region.base)
isc_mem_put(ctx->mctx, dev->region.base, dev->region.length);
if (dev->result != ISC_R_SUCCESS) {
isc_task_shutdown(task);
......
......@@ -24,7 +24,17 @@
#include <dns/rdatalist.h>
#include <dns/rdataset.h>
#include <dns/compress.h>
#include <dns/db.h>
#define DNS_FLAG_QR 0x8000U
#define DNS_FLAG_AA 0x0400U
#define DNS_FLAG_TC 0x0200U
#define DNS_FLAG_RD 0x0100U
#define DNS_FLAG_RA 0x0080U
#define DNS_OPCODE_MASK 0x7000U
#define DNS_OPCODE_SHIFT 11
#define DNS_RCODE_MASK 0x000FU
/*
* XXX All of the following is for debugging only, and will eventually
......@@ -77,3 +87,146 @@ dump_packet(char *buf, u_int len)
printf("printmessage() failed: %s\n",
dns_result_totext(result));
}
static isc_uint16_t
getshort(isc_buffer_t *buffer) {
isc_region_t r;
isc_buffer_remaining(buffer, &r);
if (r.length < 2) {
printf("not enough input\n");
exit(5);
}
return (isc_buffer_getuint16(buffer));
}
dns_result_t
resolve_packet(dns_db_t *db, isc_buffer_t *source, isc_buffer_t *target)
{
dns_decompress_t dctx;
dns_compress_t cctx;
dns_result_t result;
unsigned int count;
dns_message_t message;
dns_name_t name;
isc_uint16_t qtype;
isc_uint16_t qclass;
unsigned char t[256];
isc_buffer_t tbuf;
isc_uint16_t status;
dns_dbnode_t *node;
dns_rdataset_t rdataset;
count = 0;
status = 0;
message.id = getshort(source);
message.flags = getshort(source);
message.qcount = getshort(source);
message.ancount = getshort(source);
message.aucount = getshort(source);
message.adcount = getshort(source);
INSIST(message.qcount == 1);
INSIST(message.ancount == 0);
INSIST(message.aucount == 0);
INSIST(message.adcount == 0);
dctx.allowed = DNS_COMPRESS_GLOBAL14;
dns_name_init(&dctx.owner_name, NULL);
cctx.allowed = DNS_COMPRESS_GLOBAL14;
dns_name_init(&cctx.owner_name, NULL);
/*
* Expand the name requested into buffer (tbuf)
*/
isc_buffer_init(&tbuf, t, sizeof(t), ISC_BUFFERTYPE_BINARY);
dns_name_init(&name, NULL);
result = dns_name_fromwire(&name, source, &dctx, ISC_FALSE, &tbuf);
qtype = getshort(source);
qclass = getshort(source);
/*
* Look it up in the database. XXX Uses many hard coded bits.
*/
node = NULL;
result = dns_db_findnode(db, &name, ISC_FALSE, &node);
if (result == DNS_R_NOTFOUND) {
status = 3; /* NXDOMAIN */
goto out;
}
if (result != DNS_R_SUCCESS) {
status = 2; /* SERVFAIL */
goto out;
}
dns_rdataset_init(&rdataset);
result = dns_db_findrdataset(db, node, NULL, qtype, &rdataset);
dns_db_detachnode(db, &node);
if (result == DNS_R_NOTFOUND) {
status = 3; /* NXDOMAIN */
goto out;
}
if (result != DNS_R_SUCCESS) {
status = 2; /* SERVFAIL */
goto out;
}
out:
/*
* XXX This should really use the buffer functions correctly, but...
*/
/*
* Write the header.
*/
isc_buffer_putuint16(target, message.id);
message.flags |= DNS_FLAG_QR;
message.flags &= ~(DNS_FLAG_AA | DNS_FLAG_TC | DNS_FLAG_RA);
message.flags &= ~(DNS_RCODE_MASK);
message.flags |= status;
isc_buffer_putuint16(target, message.flags);
isc_buffer_putuint16(target, message.qcount);
isc_buffer_putuint16(target, message.ancount); /* XXX fix up later */
isc_buffer_putuint16(target, message.aucount);
isc_buffer_putuint16(target, message.adcount);
/*
* Write the question. Note that we reconstruct it...
*/
dns_name_towire(&name, &cctx, target);
isc_buffer_putuint16(target, qtype);
isc_buffer_putuint16(target, qclass);
/*
* Now, scribble out the answer. If this works we will update the
* answer count. If it fails, we will update the status instead.
*/
if (status == 0) {
unsigned int oldused;
count = 0;
result = dns_rdataset_towire(&rdataset, &name, &cctx,
target, &count);
if (result != DNS_R_SUCCESS) { /* Should just return fail? */
oldused = target->used;
target->used = 2; /* Hack! XXX */
message.flags &= ~(DNS_RCODE_MASK);
message.flags |= 2; /* SERVFAIL */
isc_buffer_putuint16(target, message.flags);
target->used = oldused;
} else {
oldused = target->used;
target->used = 6; /* Another hack! XXX */
isc_buffer_putuint16(target, count);
target->used = oldused;
}
}
return (DNS_R_SUCCESS);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment