busybox/networking/whois.c
<<
>>
Prefs
   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
  31enum {
  32        OPT_i = (1 << 0),
  33};
  34
  35static 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
 113static 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
 169int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 170int 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}
 185