Index: third_party/libevent/evdns.c |
diff --git a/third_party/libevent/evdns.c b/third_party/libevent/evdns.c |
index 6861161cfca8c215cd87d0e114825c70f81255a9..f07ecc98a140bafc499012d5c26872c411c50ea5 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) |