diff options
Diffstat (limited to 'third_party/libevent/evdns.c')
-rw-r--r-- | third_party/libevent/evdns.c | 104 |
1 files changed, 73 insertions, 31 deletions
diff --git a/third_party/libevent/evdns.c b/third_party/libevent/evdns.c index 6861161..f07ecc9 100644 --- a/third_party/libevent/evdns.c +++ b/third_party/libevent/evdns.c @@ -74,7 +74,9 @@ #include <openssl/rand.h> #endif +#ifndef _FORTIFY_SOURCE #define _FORTIFY_SOURCE 3 +#endif #include <string.h> #include <fcntl.h> @@ -209,6 +211,7 @@ struct reply { struct nameserver { int socket; /* a connected UDP socket */ u32 address; + u16 port; int failed_times; /* number of times which we have given this server a chance */ int timedout; /* number of times in a row a request has timed out */ struct event event; @@ -469,7 +472,6 @@ nameserver_probe_failed(struct nameserver *const ns) { global_nameserver_timeouts_length - 1)]; ns->failed_times++; - evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns); if (evtimer_add(&ns->timeout_event, (struct timeval *) timeout) < 0) { log(EVDNS_LOG_WARN, "Error from libevent when adding timer event for %s", @@ -498,7 +500,6 @@ nameserver_failed(struct nameserver *const ns, const char *msg) { ns->state = 0; ns->failed_times = 1; - evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns); if (evtimer_add(&ns->timeout_event, (struct timeval *) &global_nameserver_timeouts[0]) < 0) { log(EVDNS_LOG_WARN, "Error from libevent when adding timer event for %s", @@ -680,7 +681,10 @@ reply_callback(struct request *const req, u32 ttl, u32 err, struct reply *reply) static void reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) { int error; - static const int error_codes[] = {DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST, DNS_ERR_NOTIMPL, DNS_ERR_REFUSED}; + static const int error_codes[] = { + DNS_ERR_FORMAT, DNS_ERR_SERVERFAILED, DNS_ERR_NOTEXIST, + DNS_ERR_NOTIMPL, DNS_ERR_REFUSED + }; if (flags & 0x020f || !reply || !reply->have_answer) { /* there was an error */ @@ -709,9 +713,10 @@ reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) } break; case DNS_ERR_SERVERFAILED: - /* rcode 2 (servfailed) sometimes means "we are broken" and - * sometimes (with some binds) means "that request was very - * confusing." Treat this as a timeout, not a failure. + /* rcode 2 (servfailed) sometimes means "we + * are broken" and sometimes (with some binds) + * means "that request was very confusing." + * Treat this as a timeout, not a failure. */ log(EVDNS_LOG_DEBUG, "Got a SERVERFAILED from nameserver %s; " "will allow the request to time out.", @@ -723,10 +728,13 @@ reply_handle(struct request *const req, u16 flags, u32 ttl, struct reply *reply) } if (req->search_state && req->request_type != TYPE_PTR) { - /* if we have a list of domains to search in, try the next one */ + /* if we have a list of domains to search in, + * try the next one */ if (!search_try_next(req)) { - /* a new request was issued so this request is finished and */ - /* the user callback will be made when that request (or a */ + /* a new request was issued so this + * request is finished and */ + /* the user callback will be made when + * that request (or a */ /* child of it) finishes. */ request_finished(req, &req_head); return; @@ -803,10 +811,10 @@ name_parse(u8 *packet, int length, int *idx, char *name_out, int name_out_len) { /* parses a raw request from a nameserver */ static int reply_parse(u8 *packet, int length) { - int j = 0; /* index into packet */ + int j = 0, k = 0; /* index into packet */ u16 _t; /* used by the macros */ u32 _t32; /* used by the macros */ - char tmp_name[256]; /* used by the macros */ + char tmp_name[256], cmp_name[256]; /* used by the macros */ u16 trans_id, questions, answers, authority, additional, datalength; u16 flags = 0; @@ -839,10 +847,21 @@ reply_parse(u8 *packet, int length) { /* This macro skips a name in the DNS reply. */ #define SKIP_NAME \ - do { tmp_name[0] = '\0'; \ - if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0) \ - goto err; \ - } while(0); + do { tmp_name[0] = '\0'; \ + if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\ + goto err; \ + } while(0) +#define TEST_NAME \ + do { tmp_name[0] = '\0'; \ + cmp_name[0] = '\0'; \ + k = j; \ + if (name_parse(packet, length, &j, tmp_name, sizeof(tmp_name))<0)\ + goto err; \ + if (name_parse(req->request, req->request_len, &k, cmp_name, sizeof(cmp_name))<0) \ + goto err; \ + if (memcmp(tmp_name, cmp_name, strlen (tmp_name)) != 0) \ + return (-1); /* we ignore mismatching names */ \ + } while(0) reply.type = req->request_type; @@ -851,7 +870,7 @@ reply_parse(u8 *packet, int length) { /* the question looks like * <label:name><u16:type><u16:class> */ - SKIP_NAME; + TEST_NAME; j += 4; if (j > length) goto err; } @@ -1134,19 +1153,38 @@ nameserver_pick(void) { } } +static int +address_is_correct(struct nameserver *ns, struct sockaddr *sa, socklen_t slen) +{ + struct sockaddr_in *sin = (struct sockaddr_in*) sa; + if (sa->sa_family != AF_INET || slen != sizeof(struct sockaddr_in)) + return 0; + if (sin->sin_addr.s_addr != ns->address) + return 0; + return 1; +} + /* this is called when a namesever socket is ready for reading */ static void nameserver_read(struct nameserver *ns) { u8 packet[1500]; + struct sockaddr_storage ss; + socklen_t addrlen = sizeof(ss); for (;;) { - const int r = recv(ns->socket, packet, sizeof(packet), 0); + const int r = recvfrom(ns->socket, packet, sizeof(packet), 0, + (struct sockaddr*)&ss, &addrlen); if (r < 0) { int err = last_error(ns->socket); if (error_is_eagain(err)) return; nameserver_failed(ns, strerror(err)); return; } + if (!address_is_correct(ns, (struct sockaddr*)&ss, addrlen)) { + log(EVDNS_LOG_WARN, "Address mismatch on received " + "DNS packet."); + return; + } ns->timedout = 0; reply_parse(packet, r); } @@ -1667,7 +1705,7 @@ evdns_server_request_format_response(struct server_request *req, int err) if (j > 512) { overflow: j = 512; - buf[3] |= 0x02; /* set the truncated bit. */ + buf[2] |= 0x02; /* set the truncated bit. */ } req->response_len = j; @@ -1874,7 +1912,15 @@ evdns_request_timeout_callback(int fd, short events, void *arg) { /* 2 other failure */ static int evdns_request_transmit_to(struct request *req, struct nameserver *server) { - const int r = send(server->socket, req->request, req->request_len, 0); + struct sockaddr_in sin; + int r; + memset(&sin, 0, sizeof(sin)); + sin.sin_addr.s_addr = req->ns->address; + sin.sin_port = req->ns->port; + sin.sin_family = AF_INET; + + r = sendto(server->socket, req->request, req->request_len, 0, + (struct sockaddr*)&sin, sizeof(sin)); if (r < 0) { int err = last_error(server->socket); if (error_is_eagain(err)) return 1; @@ -1923,7 +1969,6 @@ evdns_request_transmit(struct request *req) { /* all ok */ log(EVDNS_LOG_DEBUG, "Setting timeout for request %lx", (unsigned long) req); - evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req); if (evtimer_add(&req->timeout_event, &global_timeout) < 0) { log(EVDNS_LOG_WARN, "Error from libevent when adding timer for request %lx", @@ -2070,7 +2115,6 @@ _evdns_nameserver_add_impl(unsigned long int address, int port) { const struct nameserver *server = server_head, *const started_at = server_head; struct nameserver *ns; - struct sockaddr_in sin; int err = 0; if (server) { do { @@ -2084,18 +2128,14 @@ _evdns_nameserver_add_impl(unsigned long int address, int port) { memset(ns, 0, sizeof(struct nameserver)); + evtimer_set(&ns->timeout_event, nameserver_prod_callback, ns); + ns->socket = socket(PF_INET, SOCK_DGRAM, 0); if (ns->socket < 0) { err = 1; goto out1; } evutil_make_socket_nonblocking(ns->socket); - sin.sin_addr.s_addr = address; - sin.sin_port = htons(port); - sin.sin_family = AF_INET; - if (connect(ns->socket, (struct sockaddr *) &sin, sizeof(sin)) != 0) { - err = 2; - goto out2; - } ns->address = address; + ns->port = htons(port); ns->state = 1; event_set(&ns->event, ns->socket, EV_READ | EV_PERSIST, nameserver_ready_callback, ns); if (event_add(&ns->event, NULL) < 0) { @@ -2208,6 +2248,8 @@ request_new(int type, const char *name, int flags, if (!req) return NULL; memset(req, 0, sizeof(struct request)); + evtimer_set(&req->timeout_event, evdns_request_timeout_callback, req); + /* request data lives just after the header */ req->request = ((u8 *) req) + sizeof(struct request); /* denotes that the request data shouldn't be free()ed */ @@ -2277,7 +2319,7 @@ int evdns_resolve_ipv6(const char *name, int flags, } } -int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) { +int evdns_resolve_reverse(const struct in_addr *in, int flags, evdns_callback_type callback, void *ptr) { char buf[32]; struct request *req; u32 a; @@ -2295,7 +2337,7 @@ int evdns_resolve_reverse(struct in_addr *in, int flags, evdns_callback_type cal return 0; } -int evdns_resolve_reverse_ipv6(struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) { +int evdns_resolve_reverse_ipv6(const struct in6_addr *in, int flags, evdns_callback_type callback, void *ptr) { /* 32 nybbles, 32 periods, "ip6.arpa", NUL. */ char buf[73]; char *cp; @@ -2947,7 +2989,7 @@ load_nameservers_from_registry(void) #undef TRY } -static int +int evdns_config_windows_nameservers(void) { if (load_nameservers_with_getnetworkparams() == 0) |