>Number: 158125 >Category: bin >Synopsis: whois takes too long to move to next address. [patch] >Confidential: no >Severity: non-critical >Priority: low >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: sw-bug >Submitter-Id: current-users >Arrival-Date: Tue Jun 21 14:20:09 UTC 2011 >Closed-Date: >Last-Modified: >Originator: Mark Andrews >Release: FreeBSD 8.2-STABLE i386 >Organization: ISC >Environment: System: FreeBSD sex.dv.isc.org 8.2-STABLE FreeBSD 8.2-STABLE #10: Sat Feb 26 18:02:12 EST 2011 ma...@sex.dv.isc.org:/usr/obj/usr/src/sys/DEBUG i386
>Description: whois has a simple connect loop which has doesn't fallback to alternate address on connect failures in a timely manner. >How-To-Repeat: block connections to whois.ripe.net over IPv6 then try to lookup information in ripe's whois database from a dual stack server. >Fix: Attempt to connect to alternate addresses if the connect doesn't succeed in 100ms. Take the first connection to succeed and close the others. Reduce the wait between connection attempts by 2 on each connection attempt. --- /usr/src/usr.bin/whois/whois.c 2010-01-21 21:16:21.000000000 +1100 +++ whois.c 2011-06-22 00:01:47.000000000 +1000 @@ -48,6 +48,7 @@ #include <sys/types.h> #include <sys/socket.h> +#include <sys/poll.h> #include <netinet/in.h> #include <arpa/inet.h> #include <ctype.h> @@ -59,6 +60,8 @@ #include <string.h> #include <sysexits.h> #include <unistd.h> +#include <fcntl.h> +#include <errno.h> #define ABUSEHOST "whois.abuse.net" #define NICHOST "whois.crsnic.net" @@ -282,21 +285,96 @@ FILE *sfi, *sfo; struct addrinfo *hostres, *res; char *buf, *host, *nhost, *p; - int i, s; + int i, j, n, s, count; size_t c, len; + struct pollfd *fds; + int timeout = 100; s = -1; hostres = gethostinfo(hostname, 1); - for (res = hostres; res; res = res->ai_next) { + for (res = hostres, count = 0; res; res = res->ai_next) + count++; + + fds = calloc(count, sizeof(*fds)); + if (fds == NULL) + err(EX_OSERR, "calloc()"); + + for (res = hostres, i = 0, count = 0; res; res = res->ai_next) { s = socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (s < 0) + if (s < 0) { + if (res->ai_next != NULL) + continue; + } else if ((flags = fcntl(s, F_GETFL)) == -1) { + close(s); + } else if (fcntl(s, F_SETFL, flags | O_NONBLOCK) == -1) { + close(s); + } else if (connect(s, res->ai_addr, res->ai_addrlen) < 0) { + if (errno != EINPROGRESS) { + close(s); + } else { + fds[i].fd = s; + fds[i].events = POLLERR | POLLHUP | + POLLIN | POLLOUT; + count++; + i++; + } + } else + goto done; + + if (count == 0) continue; - if (connect(s, res->ai_addr, res->ai_addrlen) == 0) - break; - close(s); + + do { + if (res->ai_next == NULL) + timeout = -1; + n = poll(fds, i, timeout); + if (n == 0) { + timeout >> 1; + break; + } + if (n < 0 ) { + if (errno == EAGAIN || errno == EINTR) + continue; + s = -1; + goto done; + } + for (j = 0; j < i; j++) { + if (fds[j].fd == -1 || fds[j].events == 0 || + fds[j].revents == 0) + continue; + s = fds[j].fd; + if (fds[j].revents & POLLHUP) { + close(s); + fds[j].fd = -1; + fds[j].events = 0; + count--; + continue; + } + /* Connect succeeded. */ + goto done; + } + } while (timeout == -1 && count != 0); } + s = -1; + + done: + for (j = 0; j < i; j++) + if (fds[j].fd != s && fds[j].fd != -1) + close(fds[j].fd); + + if (s != -1) { + /* Restore default blocking behaviour. */ + if ((flags = fcntl(s, F_GETFL)) != -1) { + flags &= ~O_NONBLOCK; + if (fcntl(s, F_SETFL, flags) == -1) + err(EX_OSERR, "fcntl()"); + } else + err(EX_OSERR, "fcntl()"); + } + + free(fds); freeaddrinfo(hostres); - if (res == NULL) + if (s == -1) err(EX_OSERR, "connect()"); sfi = fdopen(s, "r"); >Release-Note: >Audit-Trail: >Unformatted: _______________________________________________ freebsd-bugs@freebsd.org mailing list http://lists.freebsd.org/mailman/listinfo/freebsd-bugs To unsubscribe, send any mail to "freebsd-bugs-unsubscr...@freebsd.org"