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