summaryrefslogtreecommitdiff
path: root/whois.c
diff options
context:
space:
mode:
Diffstat (limited to 'whois.c')
-rw-r--r--whois.c140
1 files changed, 123 insertions, 17 deletions
diff --git a/whois.c b/whois.c
index 44a1871..ed8f483 100644
--- a/whois.c
+++ b/whois.c
@@ -1,8 +1,10 @@
-/* Copyright 1999-2008 by Marco d'Itri <md@linux.it>.
+/*
+ * Copyright 1999-2009 by Marco d'Itri <md@linux.it>.
*
* This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
*/
/* for AI_IDN */
@@ -21,6 +23,7 @@
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
+#include <fcntl.h>
#include <signal.h>
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
@@ -258,6 +261,10 @@ const char *handle_query(const char *hserver, const char *hport,
server = whichwhois(p);
qstring = p ;
break;
+ case 0x0C:
+ p = convert_inaddr(qstring);
+ server = whichwhois(p);
+ break;
default:
break;
}
@@ -327,7 +334,7 @@ const char *match_config_file(const char *s)
err_quit(_("Cannot parse this line: %s"), p);
#ifdef HAVE_REGEXEC
- i = regcomp(&re, pattern, REG_EXTENDED|REG_ICASE|REG_NOSUB);
+ i = regcomp(&re, pattern, REG_EXTENDED | REG_ICASE | REG_NOSUB);
if (i != 0) {
char m[1024];
regerror(i, &re, m, sizeof(m));
@@ -761,6 +768,7 @@ const char *query_afilias(const int sock, const char *query)
int openconn(const char *server, const char *port)
{
int fd = -1;
+ int timeout = 10;
#ifdef HAVE_GETADDRINFO
int err;
struct addrinfo hints, *res, *ai;
@@ -776,14 +784,24 @@ int openconn(const char *server, const char *port)
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_IDN;
+ hints.ai_flags = AI_ADDRCONFIG | AI_IDN;
+
+ if ((err = getaddrinfo(server, port ? port : "nicname", &hints, &res))
+ != 0) {
+ if (err == EAI_SYSTEM)
+ err_sys("getaddrinfo(%s)", server);
+ else
+ err_quit("getaddrinfo(%s): %s", server, gai_strerror(err));
+ }
- if ((err = getaddrinfo(server, port ? port : "nicname", &hints, &res)) != 0)
- err_quit("getaddrinfo(%s): %s", server, gai_strerror(err));
for (ai = res; ai; ai = ai->ai_next) {
+ /* no timeout for the last address. is this a good idea? */
+ if (!ai->ai_next)
+ timeout = 0;
if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
continue; /* ignore */
- if (connect(fd, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == 0)
+ if (connect_with_timeout(fd, (struct sockaddr *)ai->ai_addr,
+ ai->ai_addrlen, timeout) == 0)
break; /* success */
close(fd);
}
@@ -806,21 +824,75 @@ int openconn(const char *server, const char *port)
err_quit(_("%s/tcp: unknown service"), port);
saddr.sin_port = servinfo->s_port;
}
- if (connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
+ if (connect_with_timeout(fd, (struct sockaddr *)&saddr, sizeof(saddr),
+ timeout) < 0)
err_sys("connect");
#endif
- /*
- * Now we are connected and the query is supposed to complete quickly.
- * This will help people who run whois ... | less
- */
- /* Disabled, because in the real world this is not true. :-(
- alarm(0);
- */
-
return fd;
}
+int connect_with_timeout(int fd, const struct sockaddr *addr,
+ socklen_t addrlen, int timeout)
+{
+ int savedflags, rc, connect_errno, opt;
+ fd_set fd_w;
+ struct timeval tv;
+ size_t len;
+
+ if (timeout <= 0)
+ return (connect(fd, addr, addrlen));
+
+ if ((savedflags = fcntl(fd, F_GETFL, 0)) < 0)
+ return -1;
+
+ /* set the socket non-blocking, so connect(2) will return immediately */
+ if (fcntl(fd, F_SETFL, savedflags | O_NONBLOCK) < 0)
+ return -1;
+
+ rc = connect(fd, addr, addrlen);
+
+ /* set the socket to block again */
+ connect_errno = errno;
+ if (fcntl(fd, F_SETFL, savedflags) < 0)
+ return -1;
+ errno = connect_errno;
+
+ if (rc == 0 || errno != EINPROGRESS)
+ return rc;
+
+ FD_ZERO(&fd_w);
+ FD_SET(fd, &fd_w);
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+
+ /* loop until an error or the timeout has expired */
+ do {
+ rc = select(fd + 1, NULL, &fd_w, NULL, &tv);
+ } while (rc == -1 && errno == EINTR);
+
+ if (rc == 0) { /* timed out */
+ errno = ETIMEDOUT;
+ return -1;
+ }
+
+ if (rc < 0 || rc > 1) /* select failed */
+ return rc;
+
+ /* rc == 1: success. check for errors */
+ len = sizeof(opt);
+ if (getsockopt(fd, SOL_SOCKET, SO_ERROR, &opt, &len) < 0)
+ return -1;
+
+ /* and report them */
+ if (opt != 0) {
+ errno = (int) &opt;
+ return -1;
+ }
+
+ return 0;
+}
+
void alarm_handler(int signum)
{
close(sockfd);
@@ -961,6 +1033,40 @@ char *convert_teredo(const char *s)
return new;
}
+char *convert_inaddr(const char *s)
+{
+ char *new = malloc(sizeof("255.255.255.255"));
+ char *endptr;
+ unsigned int a, b, c;
+
+ errno = 0;
+
+ a = strtol(s, &endptr, 10);
+ if (errno || a < 0 || a > 255 || *endptr != '.')
+ return (char *) "0.0.0.0";
+
+ if (domcmp(endptr + 1, ".in-addr.arpa")) {
+ b = strtol(endptr + 1, &endptr, 10); /* 1.2. */
+ if (errno || b < 0 || b > 255 || *endptr != '.')
+ return (char *) "0.0.0.0";
+
+ if (domcmp(endptr + 1, ".in-addr.arpa")) {
+ c = strtol(endptr + 1, &endptr, 10); /* 1.2.3. */
+ if (errno || c < 0 || c > 255 || *endptr != '.')
+ return (char *) "0.0.0.0";
+
+ if (domcmp(endptr + 1, ".in-addr.arpa"))
+ return (char *) "0.0.0.0";
+
+ sprintf(new, "%d.%d.%d.0", c, b, a);
+ } else
+ sprintf(new, "%d.%d.0.0", b, a);
+ } else
+ sprintf(new, "%d.0.0.0", a);
+
+ return new;
+}
+
unsigned long myinet_aton(const char *s)
{
unsigned long a, b, c, d;