[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]
[or-cvs] r9080: More DNS server hacking: everything except testing, and retr (in tor/trunk: . doc src/or)
- To: or-cvs@xxxxxxxxxxxxx
- Subject: [or-cvs] r9080: More DNS server hacking: everything except testing, and retr (in tor/trunk: . doc src/or)
- From: nickm@xxxxxxxx
- Date: Mon, 11 Dec 2006 21:56:20 -0500 (EST)
- Delivered-to: archiver@seul.org
- Delivered-to: or-cvs-outgoing@seul.org
- Delivered-to: or-cvs@seul.org
- Delivery-date: Mon, 11 Dec 2006 21:56:29 -0500
- Reply-to: or-talk@xxxxxxxxxxxxx
- Sender: owner-or-cvs@xxxxxxxxxxxxx
Author: nickm
Date: 2006-12-11 21:56:20 -0500 (Mon, 11 Dec 2006)
New Revision: 9080
Modified:
tor/trunk/
tor/trunk/doc/TODO
tor/trunk/src/or/eventdns.c
tor/trunk/src/or/eventdns.h
Log:
r11491@Kushana: nickm | 2006-12-11 12:12:57 -0500
More DNS server hacking: everything except testing, and retries, and documentation, and Tor integration.
Property changes on: tor/trunk
___________________________________________________________________
svk:merge ticket from /tor/branches/eventdns [r11491] on c95137ef-5f19-0410-b913-86e773d04f59
Modified: tor/trunk/doc/TODO
===================================================================
--- tor/trunk/doc/TODO 2006-12-12 02:56:17 UTC (rev 9079)
+++ tor/trunk/doc/TODO 2006-12-12 02:56:20 UTC (rev 9080)
@@ -92,20 +92,21 @@
. Asynchronous DNS
o Document and rename SearchDomains, ResolvConf options
D Make API closer to getaddrinfo()
- - Teach it to be able to listen for requests to be processed.
+ - Teach evdns to be able to listen for requests to be processed.
. Design interface.
- Rename stuff; current names suck.
. Design backend.
- Implement
. Listen for questions
o Parse questions, tell user code
- . Let user code tell us the answer
- - Generate responses
+ o Let user code tell us the answer
+ o Generate responses
o Send responses to client
o Queue responses when we see EAGAIN
- Retry responses after a while
- - Be efficient about labels.
- - Be more memory-efficient
+ o Be efficient about labels.
+ - Test
+d - Be more memory-efficient
- Add some kind of general question/response API so libevent can be
flexible here.
d - Add option to use /etc/hosts?
Modified: tor/trunk/src/or/eventdns.c
===================================================================
--- tor/trunk/src/or/eventdns.c 2006-12-12 02:56:17 UTC (rev 9079)
+++ tor/trunk/src/or/eventdns.c 2006-12-12 02:56:20 UTC (rev 9080)
@@ -383,19 +383,25 @@
static struct request *req_head = NULL, *req_waiting_head = NULL;
static struct nameserver *server_head = NULL;
-struct server_port {
+struct evdns_server_port {
int socket;
int refcnt;
char choaked;
- evdns_request_callback_type user_callback;
+ evdns_request_callback_fn_type user_callback;
void *user_data;
+ struct event event;
struct server_request *pending_replies;
};
-struct server_request_section {
- int n_items;
- int j;
- u8 buf[512];
+struct server_request_item {
+ struct server_request_item *next;
+ char *name;
+ unsigned int type : 16;
+ unsigned int class : 16;
+ int ttl;
+ unsigned is_name : 1;
+ int datalen : 31;
+ void *data;
};
struct server_request {
@@ -403,15 +409,22 @@
struct server_request *prev_pending;
u16 trans_id;
- struct server_port *port;
+ struct evdns_server_port *port;
struct sockaddr_storage addr;
socklen_t addrlen;
- struct server_request_section *answer;
- struct server_request_section *authority;
- struct server_request_section *additional;
+ int n_answer;
+ int n_authority;
+ int n_additional;
- struct evdns_request base;
+ struct server_request_item *answer;
+ struct server_request_item *authority;
+ struct server_request_item *additional;
+
+ char *response;
+ size_t response_len;
+
+ struct evdns_server_request base;
};
#define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0))
@@ -419,7 +432,8 @@
((struct server_request*) \
(((char*)(base_ptr) - OFFSET_OF(struct server_request, base))))
-static void evdns_request_free(struct evdns_request *_req);
+static void evdns_server_request_free(struct server_request *req);
+static void evdns_server_request_free_answers(struct server_request *req);
// The number of good nameservers that we have
static int global_good_nameservers = 0;
@@ -449,6 +463,7 @@
static struct nameserver *nameserver_pick(void);
static void evdns_request_insert(struct request *req, struct request **head);
static void nameserver_ready_callback(int fd, short events, void *arg);
+static void server_port_ready_callback(int fd, short events, void *arg);
static int evdns_transmit(void);
static int evdns_request_transmit(struct request *req);
static void nameserver_send_probe(struct nameserver *const ns);
@@ -907,7 +922,7 @@
return 0;
}
-// parses a raw request from the wire
+// parses a raw request from a nameserver.
static int
reply_parse(u8 *packet, int length)
{
@@ -1029,7 +1044,7 @@
#undef GET8
static int
-request_parse(u8 *packet, int length, struct server_port *port, struct sockaddr *addr, socklen_t addrlen)
+request_parse(u8 *packet, int length, struct evdns_server_port *port, struct sockaddr *addr, socklen_t addrlen)
{
int j = 0; // index into packet
u16 _t; // used by the macros
@@ -1061,20 +1076,20 @@
server_req->base.flags = flags;
server_req->base.nquestions = 0;
- server_req->base.questions = malloc(sizeof(struct evdns_question *) * questions);
+ server_req->base.questions = malloc(sizeof(struct evdns_server_question *) * questions);
if (server_req->base.questions == NULL)
goto err;
for (i = 0; i < questions; ++i) {
u16 type, class;
- struct evdns_question *q;
+ struct evdns_server_question *q;
int namelen;
if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)
goto err;
GET16(type);
GET16(class);
namelen = strlen(tmp_name);
- q = malloc(sizeof(struct evdns_question) + namelen);
+ q = malloc(sizeof(struct evdns_server_question) + namelen);
if (!q)
goto err;
q->type = type;
@@ -1205,7 +1220,7 @@
}
static void
-server_port_read(struct server_port *s) {
+server_port_read(struct evdns_server_port *s) {
u8 packet[1500];
struct sockaddr_storage addr;
socklen_t addrlen;
@@ -1225,6 +1240,13 @@
}
}
+static void
+server_port_flush(struct evdns_server_port *port)
+{
+ // XXXX Writeme.
+ (void)port;
+}
+
// set if we are waiting for the ability to write to this server.
// if waiting is true then we ask libevent for EV_WRITE events, otherwise
// we stop these events.
@@ -1261,6 +1283,22 @@
}
}
+// a callback function. Called by libevent when the kernel says that
+// a server socket is ready for writing or reading.
+static void
+server_port_ready_callback(int fd, short events, void *arg) {
+ struct evdns_server_port *port = (struct evdns_server_port *) arg;
+ (void) fd;
+
+ if (events & EV_WRITE) {
+ port->choaked = 0;
+ server_port_flush(port);
+ }
+ if (events & EV_READ) {
+ server_port_read(port);
+ }
+}
+
/* This is an inefficient representation; only use it via the dnslabel_table_*
* functions. */
#define MAX_LABELS 128
@@ -1432,83 +1470,214 @@
}
// exported function
+struct evdns_server_port *
+evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type cb, void *user_data)
+{
+ struct evdns_server_port *port;
+ if (!(port = malloc(sizeof(struct evdns_server_port))))
+ return NULL;
+
+ assert(!is_tcp); // TCP sockets not yet implemented
+ port->socket = socket;
+ port->refcnt = 1;
+ port->choaked = 0;
+ port->user_callback = cb;
+ port->user_data = user_data;
+ port->pending_replies = NULL;
+ event_set(&port->event, port->socket, EV_READ | EV_PERSIST,
+ server_port_ready_callback, port);
+ event_add(&port->event, NULL); // check return.
+ return port;
+}
+
+// exported function
int
-evdns_request_add_reply(struct evdns_request *_req, int section, const char *name, int type, int class, int ttl, int datalen, const char *data)
+evdns_request_add_reply(struct evdns_server_request *_req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data)
{
struct server_request *req = TO_SERVER_REQUEST(_req);
- struct server_request_section **secp;
- int j;
- u8 *buf;
- int buf_len;
- u16 _t; // used by the macros
- u32 _t32; // used by the macros
+ struct server_request_item **itemp, *item;
+ int *countp;
+ if (req->response) /* have we already answered? */
+ return -1;
+
switch (section) {
case EVDNS_ANSWER_SECTION:
- secp = &req->answer;
+ itemp = &req->answer;
+ countp = &req->n_answer;
break;
case EVDNS_AUTHORITY_SECTION:
- secp = &req->authority;
+ itemp = &req->authority;
+ countp = &req->n_authority;
break;
case EVDNS_ADDITIONAL_SECTION:
- secp = &req->additional;
+ itemp = &req->additional;
+ countp = &req->n_additional;
break;
default:
return -1;
}
- if (!*secp) {
- if (!(*secp = malloc(sizeof(struct server_request_section))))
- return -1;
- memset(*secp, 0, sizeof(struct server_request_section));
+ while (*itemp) {
+ itemp = &((*itemp)->next);
}
- buf = (*secp)->buf;
- buf_len = sizeof((*secp)->buf);
- j = (*secp)->j;
-
- // format is <label:name><u16:type><u16:class><u32:ttl><u16:len><data...>
-
- j = dnsname_to_labels(buf, buf_len, j, name, strlen(name), NULL);
- if (j < 0) {
- return j;
+ item = malloc(sizeof(struct server_request_item));
+ if (!item)
+ return -1;
+ item->next = NULL;
+ if (!(item->name = strdup(name))) {
+ free(item);
+ return -1;
}
+ item->type = type;
+ item->class = class;
+ item->ttl = ttl;
+ item->is_name = is_name != 0;
+ item->datalen = 0;
+ item->data = NULL;
+ if (data) {
+ if (item->is_name) {
+ if (!(item->data = strdup(data))) {
+ free(item->name);
+ free(item);
+ return -1;
+ }
+ item->datalen = -1;
+ } else {
+ if (!(item->data = malloc(datalen))) {
+ free(item->name);
+ free(item);
+ return -1;
+ }
+ item->datalen = datalen;
+ memcpy(item->data, data, datalen);
+ }
+ }
- APPEND16(type);
- APPEND16(class);
- APPEND32(ttl);
- APPEND16(datalen);
- if ((size_t)(j + datalen) > buf_len)
- return -1;
- memcpy(buf + j, data, datalen);
- j += datalen;
-
- (*secp)->j = j;
- (*secp)->n_items++;
-
+ *itemp = item;
+ ++(*countp);
return 0;
}
// exported function
int
-evdns_request_add_a_reply(struct evdns_request *req, const char *name, int n, void *addrs, int ttl)
+evdns_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
{
return evdns_request_add_reply(
req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
- ttl, n*4, addrs);
+ ttl, n*4, 0, addrs);
}
+int
+evdns_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl)
+{
+ return evdns_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, name, TYPE_AAAA, CLASS_INET,
+ ttl, n*16, 0, addrs);
+}
+
+int
+evdns_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *name, int ttl)
+{
+ u32 a;
+ char buf[32];
+ assert(in);
+ a = ntohl(in->s_addr);
+ sprintf(buf, "%d.%d.%d.%d.in-addr.arpa",
+ (int)(u8)((a )&0xff),
+ (int)(u8)((a>>8 )&0xff),
+ (int)(u8)((a>>16)&0xff),
+ (int)(u8)((a>>24)&0xff));
+ return evdns_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, buf, TYPE_PTR, CLASS_INET,
+ ttl, -1, 1, name);
+}
+
+int
+evdns_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl)
+{
+ return evdns_request_add_reply(
+ req, EVDNS_ANSWER_SECTION, name, TYPE_A, CLASS_INET,
+ ttl, -1, 1, cname);
+}
+
+static int
+evdns_request_response_format(struct server_request *req, int flags)
+{
+ unsigned char buf[1500];
+ size_t buf_len = sizeof(buf);
+ off_t j = 0;
+ u16 _t;
+ u32 _t32;
+ int i;
+ struct dnslabel_table table;
+
+ dnslabel_table_init(&table); // XXXX need to call dnslable_table_clear.
+ APPEND16(req->trans_id);
+ APPEND16(flags);
+ APPEND16(0); /* questions */
+ APPEND16(req->n_answer);
+ APPEND16(req->n_authority);
+ APPEND16(req->n_additional);
+
+ /* Add questions : none. */
+ for (i=0; i<3; ++i) {
+ struct server_request_item *item;
+ if (i==0)
+ item = req->answer;
+ else if (i==1)
+ item = req->authority;
+ else
+ item = req->additional;
+ while (item) {
+ j = dnsname_to_labels(buf, buf_len, j, item->name, strlen(item->name), &table);
+ if (j < 0)
+ return (int) j;
+
+ APPEND16(item->type);
+ APPEND16(item->class);
+ APPEND32(item->ttl);
+ if (item->is_name) {
+ off_t len_idx = j, name_start;
+ j += 2;
+ name_start = j;
+ j = dnsname_to_labels(buf, buf_len, j, item->data, strlen(item->data), &table);
+ if (j < 0)
+ return (int) j;
+ _t = htons( (j-name_start) );
+ memcpy(buf+len_idx, &_t, 2);
+ } else {
+ APPEND16(item->datalen);
+ if (j+item->datalen > (off_t)buf_len)
+ return -1;
+ memcpy(buf+j, item->data, item->datalen);
+ j += item->datalen;
+ }
+ item = item->next;
+ }
+ }
+
+ req->response_len = j;
+ if (!(req->response = malloc(req->response_len)))
+ return -1;
+ memcpy(req->response, buf, req->response_len);
+
+ evdns_server_request_free_answers(req);
+ dnslabel_clear(&table);
+ return 0;
+}
+
// exported function
int
-eventdns_request_respond(struct evdns_request *_req, int err, int flags)
+evdns_request_respond(struct evdns_server_request *_req, int flags)
{
struct server_request *req = TO_SERVER_REQUEST(_req);
int r;
- char response[1500];
- size_t responselen = 10;
+ if (!req->response) {
+ if ((r = evdns_request_response_format(req, flags))<0)
+ return r;
+ }
- // XXXX make a response and store it somewhere. Where? Oops; structs
- // may be wrong.
-
- r = sendto(req->port->socket, response, responselen, 0,
+ r = sendto(req->port->socket, req->response, req->response_len, 0,
(struct sockaddr*) &req->addr, req->addrlen);
if (r<0) {
int err = last_error(req->port->socket);
@@ -1529,27 +1698,44 @@
}
// XXXX process pending replies.
- evdns_request_free(_req);
+ evdns_server_request_free(req);
return 0;
}
static void
-evdns_request_free(struct evdns_request *_req)
+evdns_server_request_free_answers(struct server_request *req)
{
- struct server_request *req = TO_SERVER_REQUEST(_req);
+ struct server_request_item *victim, *next, **list;
int i;
+ for (i = 0; i < 3; ++i) {
+ if (i==0)
+ list = &req->answer;
+ else if (i==1)
+ list = &req->authority;
+ else
+ list = &req->additional;
+
+ victim = *list;
+ while (victim) {
+ next = victim->next;
+ free(victim->name);
+ if (victim->data)
+ free(victim->data);
+ victim = next;
+ }
+ *list = NULL;
+ }
+}
+
+static void
+evdns_server_request_free(struct server_request *req)
+{
+ int i;
if (req->base.questions) {
for (i = 0; i < req->base.nquestions; ++i)
free(req->base.questions[i]);
}
- if (req->answer)
- free(req->answer);
- if (req->answer)
- free(req->authority);
- if (req->answer)
- free(req->additional);
-
if (req->port) {
if (req->port->pending_replies == req) {
if (req->next_pending)
@@ -1560,6 +1746,11 @@
--req->port->refcnt; /* release? XXXX NM*/
}
+ if (req->response)
+ free(req->response);
+
+ evdns_server_request_free_answers(req);
+
if (req->next_pending && req->next_pending != req) {
req->next_pending->prev_pending = req->prev_pending;
req->prev_pending->next_pending = req->next_pending;
@@ -1568,10 +1759,18 @@
free(req);
}
+// exported function
+int
+evdns_request_drop(struct evdns_server_request *_req)
+{
+ struct server_request *req = TO_SERVER_REQUEST(_req);
+ evdns_server_request_free(req);
+ return 0;
+}
+
#undef APPEND16
#undef APPEND32
-
// this is a libevent callback function which is called when a request
// has timed out.
static void
Modified: tor/trunk/src/or/eventdns.h
===================================================================
--- tor/trunk/src/or/eventdns.h 2006-12-12 02:56:17 UTC (rev 9079)
+++ tor/trunk/src/or/eventdns.h 2006-12-12 02:56:20 UTC (rev 9080)
@@ -75,25 +75,30 @@
#define DNS_NO_SEARCH 1
-struct evdns_request {
+struct evdns_server_request {
int flags;
int nquestions;
- struct evdns_question **questions;
+ struct evdns_server_question **questions;
};
-struct evdns_question {
+struct evdns_server_question {
int type;
int class;
char name[1];
};
-typedef void (*evdns_request_callback_type)(struct evdns_request *, void *);
+typedef void (*evdns_request_callback_fn_type)(struct evdns_server_request *, void *);
#define EVDNS_ANSWER_SECTION 0
#define EVDNS_AUTHORITY_SECTION 1
#define EVDNS_ADDITIONAL_SECTION 2
-int evdns_request_add_reply(struct evdns_request *req, int section, const char *name, int type, int class, int ttl, int datalen, const char *data);
-int evdns_request_add_a_reply(struct evdns_request *req, const char *name, int n, void *addrs, int ttl);
-int evdns_request_add_ptr_reply(struct evdns_request *req, struct in_addr *in, const char *name, int ttl);
-int evdns_request_add_cname_reply(struct evdns_request *req, const char *name, const char *cname, int ttl);
-int evdns_request_respond(struct evdns_request *req, int err, int flags);
-int evdns_request_drop(struct evdns_request *req);
+struct evdns_server_port *evdns_add_server_port(int socket, int is_tcp, evdns_request_callback_fn_type callback, void *user_data);
+void evdns_close_server_port(struct evdns_server_port *port);
+int evdns_request_add_reply(struct evdns_server_request *req, int section, const char *name, int type, int class, int ttl, int datalen, int is_name, const char *data);
+int evdns_request_add_a_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
+int evdns_request_add_aaaa_reply(struct evdns_server_request *req, const char *name, int n, void *addrs, int ttl);
+int evdns_request_add_ptr_reply(struct evdns_server_request *req, struct in_addr *in, const char *name, int ttl);
+int evdns_request_add_cname_reply(struct evdns_server_request *req, const char *name, const char *cname, int ttl);
+
+int evdns_request_respond(struct evdns_server_request *req, int flags);
+int evdns_request_drop(struct evdns_server_request *req);
+
#endif // !EVENTDNS_H