blob: f3da32b4e1461a9799b2c62b04aec9901709ad1e [file] [log] [blame]
Pere Orga251962f2011-02-27 23:38:52 +01001/* 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 */
Pere Orga251962f2011-02-27 23:38:52 +010012//config:config WHOIS
Denys Vlasenko4eed2c62017-07-18 22:01:24 +020013//config: bool "whois (6.6 kb)"
Pere Orga251962f2011-02-27 23:38:52 +010014//config: default y
15//config: help
Denys Vlasenko72089cf2017-07-21 09:50:55 +020016//config: whois is a client for the whois directory service
Pere Orga251962f2011-02-27 23:38:52 +010017
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
Denys Vlasenko0844b5a2016-07-06 17:16:27 +020023//usage: "[-i] [-h SERVER] [-p PORT] NAME..."
Pere Orga251962f2011-02-27 23:38:52 +010024//usage:#define whois_full_usage "\n\n"
25//usage: "Query WHOIS info about NAME\n"
Denys Vlasenko0844b5a2016-07-06 17:16:27 +020026//usage: "\n -i Show redirect results too"
Pere Orga251962f2011-02-27 23:38:52 +010027//usage: "\n -h,-p Server to query"
28
29#include "libbb.h"
30
Denys Vlasenko0844b5a2016-07-06 17:16:27 +020031enum {
32 OPT_i = (1 << 0),
33};
34
Denys Vlasenko1035c922016-07-06 15:45:41 +020035static char *query(const char *host, int port, const char *domain)
Pere Orga251962f2011-02-27 23:38:52 +010036{
Denys Vlasenko1035c922016-07-06 15:45:41 +020037 int fd;
Pere Orga251962f2011-02-27 23:38:52 +010038 FILE *fp;
Denys Vlasenko1035c922016-07-06 15:45:41 +020039 bool success;
40 char *redir = NULL;
41 const char *pfx = "";
Denys Vlasenko3d6f95e2018-09-04 14:48:00 +020042 /* some .io domains reported to have very long strings in whois
43 * responses, 1k was not enough:
44 */
45 char linebuf[2 * 1024];
Denys Vlasenko1035c922016-07-06 15:45:41 +020046 char *buf = NULL;
47 unsigned bufpos = 0;
Pere Orga251962f2011-02-27 23:38:52 +010048
Denys Vlasenko1035c922016-07-06 15:45:41 +020049 again:
50 printf("[Querying %s:%d '%s%s']\n", host, port, pfx, domain);
51 fd = create_and_connect_stream_or_die(host, port);
Denys Vlasenko1035c922016-07-06 15:45:41 +020052 fdprintf(fd, "%s%s\r\n", pfx, domain);
Pere Orga251962f2011-02-27 23:38:52 +010053 fp = xfdopen_for_read(fd);
Denys Vlasenko1035c922016-07-06 15:45:41 +020054
Denys Vlasenko3d6f95e2018-09-04 14:48:00 +020055 success = 0;
56 while (fgets(linebuf, sizeof(linebuf)-1, fp)) {
57 unsigned len;
58
59 len = strcspn(linebuf, "\r\n");
Denys Vlasenko1035c922016-07-06 15:45:41 +020060 linebuf[len++] = '\n';
Denys Vlasenko3d6f95e2018-09-04 14:48:00 +020061 linebuf[len] = '\0';
Denys Vlasenko1035c922016-07-06 15:45:41 +020062
63 buf = xrealloc(buf, bufpos + len + 1);
64 memcpy(buf + bufpos, linebuf, len);
65 bufpos += len;
Denys Vlasenko0844b5a2016-07-06 17:16:27 +020066 buf[bufpos] = '\0';
Denys Vlasenko1035c922016-07-06 15:45:41 +020067
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 /*
Denys Vlasenko0844b5a2016-07-06 17:16:27 +020087 * Looking at /etc/jwhois.conf, some whois servers use
Denys Vlasenko1035c922016-07-06 15:45:41 +020088 * "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;
Pere Orga251962f2011-02-27 23:38:52 +010097 }
98
Denys Vlasenko1035c922016-07-06 15:45:41 +020099 /* Success */
100 if (redir && strcmp(redir, host) == 0) {
101 /* Redirect to self does not count */
102 free(redir);
103 redir = NULL;
104 }
Denys Vlasenko0844b5a2016-07-06 17:16:27 +0200105 if (!redir || (option_mask32 & OPT_i)) {
Denys Vlasenko1035c922016-07-06 15:45:41 +0200106 /* Output saved text */
Denys Vlasenko0844b5a2016-07-06 17:16:27 +0200107 printf("[%s]\n%s", host, buf ? buf : "");
Denys Vlasenko1035c922016-07-06 15:45:41 +0200108 }
109 free(buf);
110 return redir;
Pere Orga251962f2011-02-27 23:38:52 +0100111}
112
Denys Vlasenko1035c922016-07-06 15:45:41 +0200113static 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
Pere Orga251962f2011-02-27 23:38:52 +0100169int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
170int whois_main(int argc UNUSED_PARAM, char **argv)
171{
172 int port = 43;
Denys Vlasenko1035c922016-07-06 15:45:41 +0200173 const char *host = "whois.iana.org";
Pere Orga251962f2011-02-27 23:38:52 +0100174
Denys Vlasenko22542ec2017-08-08 21:55:02 +0200175 getopt32(argv, "^" "ih:p:+" "\0" "-1", &host, &port);
Pere Orga251962f2011-02-27 23:38:52 +0100176 argv += optind;
Denys Vlasenko1035c922016-07-06 15:45:41 +0200177
Pere Orga251962f2011-02-27 23:38:52 +0100178 do {
Denys Vlasenko1035c922016-07-06 15:45:41 +0200179 recursive_query(host, port, *argv);
Pere Orga251962f2011-02-27 23:38:52 +0100180 }
181 while (*++argv);
182
183 return EXIT_SUCCESS;
184}