Loading doc/TODO +6 −5 Original line number Diff line number Diff line Loading @@ -92,20 +92,21 @@ N - DNS improvements . 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? Loading src/or/eventdns.c +272 −73 Original line number Diff line number Diff line Loading @@ -383,19 +383,25 @@ struct nameserver { 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 { Loading @@ -403,15 +409,22 @@ struct server_request { 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 server_request_item *answer; struct server_request_item *authority; struct server_request_item *additional; struct evdns_request base; char *response; size_t response_len; struct evdns_server_request base; }; #define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0)) Loading @@ -419,7 +432,8 @@ struct server_request { ((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; Loading Loading @@ -449,6 +463,7 @@ const char *const evdns_error_strings[] = {"no error", "The name server was unab 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); Loading Loading @@ -907,7 +922,7 @@ name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) { return 0; } // parses a raw request from the wire // parses a raw request from a nameserver. static int reply_parse(u8 *packet, int length) { Loading Loading @@ -1029,7 +1044,7 @@ reply_parse(u8 *packet, int length) #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 Loading Loading @@ -1061,20 +1076,20 @@ request_parse(u8 *packet, int length, struct server_port *port, struct sockaddr 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; Loading Loading @@ -1205,7 +1220,7 @@ nameserver_read(struct nameserver *ns) { } 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; Loading @@ -1225,6 +1240,13 @@ server_port_read(struct server_port *s) { } } 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. Loading Loading @@ -1261,6 +1283,22 @@ nameserver_ready_callback(int fd, short events, void *arg) { } } // 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 Loading Loading @@ -1431,84 +1469,215 @@ evdns_request_data_build(const char *const name, const int name_len, const u16 t return (int)j; } // 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)))) while (*itemp) { itemp = &((*itemp)->next); } item = malloc(sizeof(struct server_request_item)); if (!item) return -1; item->next = NULL; if (!(item->name = strdup(name))) { free(item); return -1; memset(*secp, 0, sizeof(struct server_request_section)); } 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->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; } APPEND16(type); APPEND16(class); APPEND32(ttl); APPEND16(datalen); if ((size_t)(j + datalen) > buf_len) item->datalen = -1; } else { if (!(item->data = malloc(datalen))) { free(item->name); free(item); return -1; memcpy(buf + j, data, datalen); j += datalen; (*secp)->j = j; (*secp)->n_items++; } item->datalen = datalen; memcpy(item->data, data, datalen); } } *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, 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, n*4, addrs); 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; // XXXX make a response and store it somewhere. Where? Oops; structs // may be wrong. if (!req->response) { if ((r = evdns_request_response_format(req, flags))<0) return r; } 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); Loading @@ -1529,27 +1698,44 @@ eventdns_request_respond(struct evdns_request *_req, int err, int flags) } // 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_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) { struct server_request *req = TO_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) Loading @@ -1560,6 +1746,11 @@ evdns_request_free(struct evdns_request *_req) --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; Loading @@ -1568,10 +1759,18 @@ evdns_request_free(struct evdns_request *_req) 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 Loading src/or/eventdns.h +15 −10 Original line number Diff line number Diff line Loading @@ -75,25 +75,30 @@ void evdns_set_log_fn(evdns_debug_log_fn_type fn); #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 Loading
doc/TODO +6 −5 Original line number Diff line number Diff line Loading @@ -92,20 +92,21 @@ N - DNS improvements . 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? Loading
src/or/eventdns.c +272 −73 Original line number Diff line number Diff line Loading @@ -383,19 +383,25 @@ struct nameserver { 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 { Loading @@ -403,15 +409,22 @@ struct server_request { 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 server_request_item *answer; struct server_request_item *authority; struct server_request_item *additional; struct evdns_request base; char *response; size_t response_len; struct evdns_server_request base; }; #define OFFSET_OF(st, member) ((off_t) (((char*)&((st*)0)->member)-(char*)0)) Loading @@ -419,7 +432,8 @@ struct server_request { ((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; Loading Loading @@ -449,6 +463,7 @@ const char *const evdns_error_strings[] = {"no error", "The name server was unab 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); Loading Loading @@ -907,7 +922,7 @@ name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) { return 0; } // parses a raw request from the wire // parses a raw request from a nameserver. static int reply_parse(u8 *packet, int length) { Loading Loading @@ -1029,7 +1044,7 @@ reply_parse(u8 *packet, int length) #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 Loading Loading @@ -1061,20 +1076,20 @@ request_parse(u8 *packet, int length, struct server_port *port, struct sockaddr 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; Loading Loading @@ -1205,7 +1220,7 @@ nameserver_read(struct nameserver *ns) { } 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; Loading @@ -1225,6 +1240,13 @@ server_port_read(struct server_port *s) { } } 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. Loading Loading @@ -1261,6 +1283,22 @@ nameserver_ready_callback(int fd, short events, void *arg) { } } // 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 Loading Loading @@ -1431,84 +1469,215 @@ evdns_request_data_build(const char *const name, const int name_len, const u16 t return (int)j; } // 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)))) while (*itemp) { itemp = &((*itemp)->next); } item = malloc(sizeof(struct server_request_item)); if (!item) return -1; item->next = NULL; if (!(item->name = strdup(name))) { free(item); return -1; memset(*secp, 0, sizeof(struct server_request_section)); } 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->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; } APPEND16(type); APPEND16(class); APPEND32(ttl); APPEND16(datalen); if ((size_t)(j + datalen) > buf_len) item->datalen = -1; } else { if (!(item->data = malloc(datalen))) { free(item->name); free(item); return -1; memcpy(buf + j, data, datalen); j += datalen; (*secp)->j = j; (*secp)->n_items++; } item->datalen = datalen; memcpy(item->data, data, datalen); } } *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, 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, n*4, addrs); 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; // XXXX make a response and store it somewhere. Where? Oops; structs // may be wrong. if (!req->response) { if ((r = evdns_request_response_format(req, flags))<0) return r; } 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); Loading @@ -1529,27 +1698,44 @@ eventdns_request_respond(struct evdns_request *_req, int err, int flags) } // 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_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) { struct server_request *req = TO_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) Loading @@ -1560,6 +1746,11 @@ evdns_request_free(struct evdns_request *_req) --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; Loading @@ -1568,10 +1759,18 @@ evdns_request_free(struct evdns_request *_req) 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 Loading
src/or/eventdns.h +15 −10 Original line number Diff line number Diff line Loading @@ -75,25 +75,30 @@ void evdns_set_log_fn(evdns_debug_log_fn_type fn); #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