bin/158125: whois takes too long to move to next address. [patch]
Mark Andrews
marka at isc.org
Tue Jun 21 14:20:10 UTC 2011
>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 marka at 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:
More information about the freebsd-bugs
mailing list