[or-cvs] r9080: More DNS server hacking: everything except testing, and retr (in tor/trunk: . doc src/or)

nickm at seul.org nickm at seul.org
Tue Dec 12 02:56:20 UTC 2006


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 at 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



More information about the tor-commits mailing list