Let evdns keep working when our IP changes. Fix by Christopher Davis; backported by nickm.

svn:r1328
This commit is contained in:
Nick Mathewson 2009-06-24 22:39:12 +00:00
parent b99254ac22
commit 763391947c
2 changed files with 32 additions and 10 deletions

View File

@ -4,6 +4,7 @@ Changes in 1.4.12-stable:
o Use __VA_ARGS__ syntax for varargs macros in event_rpcgen when compiler is not GCC.
o Activate fd events in a pseudorandom order with O(N) backends, so that we don't systematically favor low fds (select) or earlier-added fds (poll, win32).
o Fix another pair of fencepost bugs in epoll.c. [Patch from Adam Langley.]
o Do not break evdns connections to nameservers when our IP changes.
Changes in 1.4.11-stable:
o Fix a bug when removing a timeout from the heap. [Patch from Marko Kreen]

41
evdns.c
View File

@ -209,6 +209,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;
@ -1150,19 +1151,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);
}
@ -1890,7 +1910,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;
@ -2085,7 +2113,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 {
@ -2104,15 +2131,9 @@ _evdns_nameserver_add_impl(unsigned long int address, int port) {
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) {