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