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 (bufpos < 32*1024 /* paranoia */
  57         && fgets(linebuf, sizeof(linebuf)-1, fp)
  58        ) {
  59                unsigned len;
  60
  61                len = strcspn(linebuf, "\r\n");
  62                linebuf[len++] = '\n';
  63                linebuf[len] = '\0';
  64
  65                buf = xrealloc(buf, bufpos + len + 1);
  66                memcpy(buf + bufpos, linebuf, len);
  67                bufpos += len;
  68                buf[bufpos] = '\0';
  69
  70                if (!redir || !success) {
  71                        trim(linebuf);
  72                        str_tolower(linebuf);
  73                        if (!success) {
  74                                success = is_prefixed_with(linebuf, "domain:")
  75                                       || is_prefixed_with(linebuf, "domain name:");
  76                        }
  77                        else if (!redir) {
  78                                char *p = is_prefixed_with(linebuf, "whois server:");
  79                                if (!p)
  80                                        p = is_prefixed_with(linebuf, "whois:");
  81                                if (p)
  82                                        redir = xstrdup(skip_whitespace(p));
  83                        }
  84                }
  85        }
  86        fclose(fp); /* closes fd too */
  87        if (!success && !pfx[0]) {
  88                /*
  89                 * Looking at /etc/jwhois.conf, some whois servers use
  90                 * "domain = DOMAIN", "DOMAIN ID <DOMAIN>"
  91                 * and "domain=DOMAIN_WITHOUT_LAST_COMPONENT"
  92                 * formats, but those are rare.
  93                 * (There are a few even more contrived ones.)
  94                 * We are trying only "domain DOMAIN", the typical one.
  95                 */
  96                pfx = "domain ";
  97                bufpos = 0;
  98                goto again;
  99        }
 100
 101        /* Success */
 102        if (redir && strcmp(redir, host) == 0) {
 103                /* Redirect to self does not count */
 104                free(redir);
 105                redir = NULL;
 106        }
 107        if (!redir || (option_mask32 & OPT_i)) {
 108                /* Output saved text */
 109                printf("[%s]\n%s", host, buf ? buf : "");
 110        }
 111        free(buf);
 112        return redir;
 113}
 114
 115static void recursive_query(const char *host, int port, const char *domain)
 116{
 117        char *free_me = NULL;
 118        char *redir;
 119 again:
 120        redir = query(host, port, domain);
 121        free(free_me);
 122        if (redir) {
 123                printf("[Redirected to %s]\n", redir);
 124                host = free_me = redir;
 125                port = 43;
 126                goto again;
 127        }
 128}
 129
 130/* One of "big" whois implementations has these options:
 131 *
 132 * $ whois --help
 133 * jwhois version 4.0, Copyright (C) 1999-2007  Free Software Foundation, Inc.
 134 * -v, --verbose              verbose debug output
 135 * -c FILE, --config=FILE     use FILE as configuration file
 136 * -h HOST, --host=HOST       explicitly query HOST
 137 * -n, --no-redirect          disable content redirection
 138 * -s, --no-whoisservers      disable whois-servers.net service support
 139 * -a, --raw                  disable reformatting of the query
 140 * -i, --display-redirections display all redirects instead of hiding them
 141 * -p PORT, --port=PORT       use port number PORT (in conjunction with HOST)
 142 * -r, --rwhois               force an rwhois query to be made
 143 * --rwhois-display=DISPLAY   sets the display option in rwhois queries
 144 * --rwhois-limit=LIMIT       sets the maximum number of matches to return
 145 *
 146 * Example of its output:
 147 * $ whois cnn.com
 148 * [Querying whois.verisign-grs.com]
 149 * [Redirected to whois.corporatedomains.com]
 150 * [Querying whois.corporatedomains.com]
 151 * [whois.corporatedomains.com]
 152 * ...text of the reply...
 153 *
 154 * With -i, reply from each server is printed, after all redirects are done:
 155 * [Querying whois.verisign-grs.com]
 156 * [Redirected to whois.corporatedomains.com]
 157 * [Querying whois.corporatedomains.com]
 158 * [whois.verisign-grs.com]
 159 * ...text of the reply...
 160 * [whois.corporatedomains.com]
 161 * ...text of the reply...
 162 *
 163 * With -a, no "DOMAIN" -> "domain DOMAIN" transformation is attempted.
 164
 165 * With -n, the first reply is shown, redirects are not followed:
 166 * [Querying whois.verisign-grs.com]
 167 * [whois.verisign-grs.com]
 168 * ...text of the reply...
 169 */
 170
 171int whois_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 172int whois_main(int argc UNUSED_PARAM, char **argv)
 173{
 174        int port = 43;
 175        const char *host = "whois.iana.org";
 176
 177        getopt32(argv, "^" "ih:p:+" "\0" "-1", &host, &port);
 178        argv += optind;
 179
 180        do {
 181                recursive_query(host, port, *argv);
 182        }
 183        while (*++argv);
 184
 185        return EXIT_SUCCESS;
 186}
 187