httpd: do not set alarm() timeout if we read cached header
[oweals/busybox.git] / networking / whois.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * whois - tiny client for the whois directory service
4  *
5  * Copyright (c) 2011 Pere Orga <gotrunks@gmail.com>
6  * Licensed under GPLv2 or later, see file LICENSE in this source tree.
7  */
8 /* TODO
9  * Add ipv6 support
10  * Add proxy support
11  */
12 //config:config WHOIS
13 //config:       bool "whois (6.3 kb)"
14 //config:       default y
15 //config:       help
16 //config:       whois is a client for the whois directory service
17
18 //applet:IF_WHOIS(APPLET(whois, BB_DIR_USR_BIN, BB_SUID_DROP))
19
20 //kbuild:lib-$(CONFIG_WHOIS) += whois.o
21
22 //usage:#define whois_trivial_usage
23 //usage:       "[-i] [-h SERVER] [-p PORT] NAME..."
24 //usage:#define whois_full_usage "\n\n"
25 //usage:       "Query WHOIS info about NAME\n"
26 //usage:     "\n        -i      Show redirect results too"
27 //usage:     "\n        -h,-p   Server to query"
28
29 #include "libbb.h"
30
31 enum {
32         OPT_i = (1 << 0),
33 };
34
35 static char *query(const char *host, int port, const char *domain)
36 {
37         int fd;
38         FILE *fp;
39         bool success;
40         char *redir = NULL;
41         const char *pfx = "";
42         /* some .io domains reported to have very long strings in whois
43          * responses, 1k was not enough:
44          */
45         char linebuf[2 * 1024];
46         char *buf = NULL;
47         unsigned bufpos = 0;
48
49  again:
50         printf("[Querying %s:%d '%s%s']\n", host, port, pfx, domain);
51         fd = create_and_connect_stream_or_die(host, port);
52         fdprintf(fd, "%s%s\r\n", pfx, domain);
53         fp = xfdopen_for_read(fd);
54
55         success = 0;
56         while (fgets(linebuf, sizeof(linebuf)-1, fp)) {
57                 unsigned len;
58
59                 len = strcspn(linebuf, "\r\n");
60                 linebuf[len++] = '\n';
61                 linebuf[len] = '\0';
62
63                 buf = xrealloc(buf, bufpos + len + 1);
64                 memcpy(buf + bufpos, linebuf, len);
65                 bufpos += len;
66                 buf[bufpos] = '\0';
67
68                 if (!redir || !success) {
69                         trim(linebuf);
70                         str_tolower(linebuf);
71                         if (!success) {
72                                 success = is_prefixed_with(linebuf, "domain:")
73                                        || is_prefixed_with(linebuf, "domain name:");
74                         }
75                         else if (!redir) {
76                                 char *p = is_prefixed_with(linebuf, "whois server:");
77                                 if (!p)
78                                         p = is_prefixed_with(linebuf, "whois:");
79                                 if (p)
80                                         redir = xstrdup(skip_whitespace(p));
81                         }
82                 }
83         }
84         fclose(fp); /* closes fd too */
85         if (!success && !pfx[0]) {
86                 /*
87                  * Looking at /etc/jwhois.conf, some whois servers use
88                  * "domain = DOMAIN", "DOMAIN ID <DOMAIN>"
89                  * and "domain=DOMAIN_WITHOUT_LAST_COMPONENT"
90                  * formats, but those are rare.
91                  * (There are a few even more contrived ones.)
92                  * We are trying only "domain DOMAIN", the typical one.
93                  */
94                 pfx = "domain ";
95                 bufpos = 0;
96                 goto again;
97         }
98
99         /* Success */
100         if (redir && strcmp(redir, host) == 0) {
101                 /* Redirect to self does not count */
102                 free(redir);
103                 redir = NULL;
104         }
105         if (!redir || (option_mask32 & OPT_i)) {
106                 /* Output saved text */
107                 printf("[%s]\n%s", host, buf ? buf : "");
108         }
109         free(buf);
110         return redir;
111 }
112
113 static void recursive_query(const char *host, int port, const char *domain)
114 {
115         char *free_me = NULL;
116         char *redir;
117  again:
118         redir = query(host, port, domain);
119         free(free_me);
120         if (redir) {
121                 printf("[Redirected to %s]\n", redir);
122                 host = free_me = redir;
123                 port = 43;
124                 goto again;
125         }
126 }
127
128 /* One of "big" whois implementations has these options:
129  *
130  * $ whois --help
131  * jwhois version 4.0, Copyright (C) 1999-2007  Free Software Foundation, Inc.
132  * -v, --verbose              verbose debug output
133  * -c FILE, --config=FILE     use FILE as configuration file
134  * -h HOST, --host=HOST       explicitly query HOST
135  * -n, --no-redirect          disable content redirection
136  * -s, --no-whoisservers      disable whois-servers.net service support
137  * -a, --raw                  disable reformatting of the query
138  * -i, --display-redirections display all redirects instead of hiding them
139  * -p PORT, --port=PORT       use port number PORT (in conjunction with HOST)
140  * -r, --rwhois               force an rwhois query to be made
141  * --rwhois-display=DISPLAY   sets the display option in rwhois queries
142  * --rwhois-limit=LIMIT       sets the maximum number of matches to return
143  *
144  * Example of its output:
145  * $ whois cnn.com
146  * [Querying whois.verisign-grs.com]
147  * [Redirected to whois.corporatedomains.com]
148  * [Querying whois.corporatedomains.com]
149  * [whois.corporatedomains.com]
150  * ...text of the reply...
151  *
152  * With -i, reply from each server is printed, after all redirects are done:
153  * [Querying whois.verisign-grs.com]
154  * [Redirected to whois.corporatedomains.com]
155  * [Querying whois.corporatedomains.com]
156  * [whois.verisign-grs.com]
157  * ...text of the reply...
158  * [whois.corporatedomains.com]
159  * ...text of the reply...
160  *
161  * With -a, no "DOMAIN" -> "domain DOMAIN" transformation is attempted.
162
163  * With -n, the first reply is shown, redirects are not followed:
164  * [Querying whois.verisign-grs.com]
165  * [whois.verisign-grs.com]
166  * ...text of the reply...
167  */
168
169 int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
170 int whois_main(int argc UNUSED_PARAM, char **argv)
171 {
172         int port = 43;
173         const char *host = "whois.iana.org";
174
175         getopt32(argv, "^" "ih:p:+" "\0" "-1", &host, &port);
176         argv += optind;
177
178         do {
179                 recursive_query(host, port, *argv);
180         }
181         while (*++argv);
182
183         return EXIT_SUCCESS;
184 }