Logo Search packages:      
Sourcecode: whois version File versions  Download package

whois.c

/* Copyright 1999-2008 by Marco d'Itri <md@linux.it>.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 */

/* for AI_IDN */
#define _GNU_SOURCE

/* System library */
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include "config.h"
#include <string.h>
#include <ctype.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <signal.h>
#ifdef HAVE_GETOPT_LONG
#include <getopt.h>
#endif
#ifdef HAVE_REGEXEC
#include <regex.h>
#endif
#ifdef HAVE_LIBIDN
#include <idna.h>
#endif

/* Application-specific */
#include "data.h"
#include "whois.h"
#include "utils.h"

/* hack */
#define malloc(s) NOFAIL(malloc(s))
#define realloc(p, s) NOFAIL(realloc(p, s))

/* Global variables */
int sockfd, verb = 0;

#ifdef ALWAYS_HIDE_DISCL
int hide_discl = HIDE_UNSTARTED;
#else
int hide_discl = HIDE_DISABLED;
#endif

const char *client_tag = (char *)IDSTRING;

#ifdef HAVE_GETOPT_LONG
static const struct option longopts[] = {
    {"help",      no_argument,            NULL, 0  },
    {"version",   no_argument,            NULL, 1  },
    {"verbose",   no_argument,            NULL, 2  },
    {"server",    required_argument,      NULL, 'h'},
    {"host",      required_argument,      NULL, 'h'},
    {"port",      required_argument,      NULL, 'p'},
    {NULL,  0,                NULL, 0  }
};
#else
extern char *optarg;
extern int optind;
#endif

int main(int argc, char *argv[])
{
    int ch, nopar = 0;
    const char *server = NULL, *port = NULL;
    char *p, *qstring, fstring[64] = "\0";

#ifdef ENABLE_NLS
    setlocale(LC_ALL, "");
    bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
    textdomain(NLS_CAT_NAME);
#endif

    /* prepend options from environment */
    argv = merge_args(getenv("WHOIS_OPTIONS"), argv, &argc);

    while ((ch = GETOPT_LONGISH(argc, argv,
            "abBcdFg:Gh:Hi:KlLmMp:q:rRs:St:T:v:V:x", longopts, 0)) > 0) {
      /* RIPE flags */
      if (strchr(ripeflags, ch)) {
          for (p = fstring; *p; p++);
          sprintf(p--, "-%c ", ch);
          continue;
      }
      if (strchr(ripeflagsp, ch)) {
          for (p = fstring; *p; p++);
          snprintf(p--, sizeof(fstring), "-%c %s ", ch, optarg);
          if (ch == 't' || ch == 'v' || ch == 'q')
            nopar = 1;
          continue;
      }
      /* program flags */
      switch (ch) {
      case 'h':
          server = strdup(optarg);
          break;
      case 'V':
          client_tag = optarg;
      case 'H':
          hide_discl = HIDE_UNSTARTED;    /* enable disclaimers hiding */
          break;
      case 'p':
          port = strdup(optarg);
          break;
      case 2:
          verb = 1;
          break;
      case 1:
          fprintf(stderr, _("Version %s.\n\nReport bugs to %s.\n"),
                VERSION, "<md+whois@linux.it>");
          exit(0);
      default:
          usage();
      }
    }
    argc -= optind;
    argv += optind;

    if (argc == 0 && !nopar)  /* there is no parameter */
      usage();

    /* On some systems realloc only works on non-NULL buffers */
    qstring = malloc(64);
    *qstring = '\0';

    /* parse other parameters, if any */
    if (!nopar) {
      int qslen = 0;

      while (1) {
          qslen += strlen(*argv) + 1 + 1;
          qstring = realloc(qstring, qslen);
          strcat(qstring, *argv++);
          if (argc == 1)
            break;
          strcat(qstring, " ");
          argc--;
      }
    }

    signal(SIGTERM, sighandler);
    signal(SIGINT, sighandler);
    signal(SIGALRM, alarm_handler);

    if (getenv("WHOIS_HIDE"))
      hide_discl = HIDE_UNSTARTED;

    /* -v or -t has been used */
    if (!server && !*qstring)
      server = strdup("whois.ripe.net");

#ifdef CONFIG_FILE
    if (!server) {
      server = match_config_file(qstring);
      if (verb && server)
          printf(_("Using server %s.\n"), server);
    }
#endif

    if (!server) {
      char *tmp;

      tmp = normalize_domain(qstring);
      free(qstring);
      qstring = tmp;
      server = whichwhois(qstring);
    }

    handle_query(server, port, qstring, fstring);

    exit(0);
}

/* server may be a server name from the command line, a server name got
 * from whichwhois or an encoded command/message from whichwhois.
 * server and port are allocated with malloc.
 */
const char *handle_query(const char *hserver, const char *hport,
      const char *qstring, const char *fstring)
{
    const char *server = NULL, *port = NULL;
    char *p;

    if (hport) {
      server = strdup(hserver);
      port = strdup(hport);
    } else if (hserver[0] < ' ')
      server = strdup(hserver);
    else
      split_server_port(hserver, &server, &port);

    switch (server[0]) {
      case 0:
          if (!(server = getenv("WHOIS_SERVER")))
            server = DEFAULTSERVER;
          break;
      case 1:
          puts(_("This TLD has no whois server, but you can access the "
                  "whois database at"));
          puts(server + 1);
          return NULL;
      case 2:
          puts(server + 1);
          return NULL;
      case 3:
          puts(_("This TLD has no whois server."));
          return NULL;
      case 5:
          puts(_("No whois server is known for this kind of object."));
          return NULL;
      case 6:
          puts(_("Unknown AS number or IP network. Please upgrade this program."));
          return NULL;
      case 4:
          if (verb)
            printf(_("Using server %s.\n"), "whois.crsnic.net");
          sockfd = openconn("whois.crsnic.net", NULL);
          server = query_crsnic(sockfd, qstring);
          break;
      case 7:
          if (verb)
            printf(_("Using server %s.\n"),
                  "whois.publicinterestregistry.net");
          sockfd = openconn("whois.publicinterestregistry.net", NULL);
          server = query_pir(sockfd, qstring);
          break;
      case 8:
          if (verb)
            printf(_("Using server %s.\n"), "whois.afilias-grs.info");
          sockfd = openconn("whois.afilias-grs.info", NULL);
          server = query_afilias(sockfd, qstring);
          break;
      case 9:
          if (verb)
            printf(_("Using server %s.\n"), "whois.nic.cc");
          sockfd = openconn("whois.nic.cc", NULL);
          server = query_crsnic(sockfd, qstring);
          break;
      case 0x0A:
          p = convert_6to4(qstring);
          /* XXX should fail if p = 0.0.0.0 */
          printf(_("\nQuerying for the IPv4 endpoint %s of a 6to4 IPv6 address.\n\n"), p);
          server = whichwhois(p);
          /* XXX should fail if server[0] < ' ' */
          qstring = p;              /* XXX leak */
          break;
      case 0x0B:
          p = convert_teredo(qstring);
          printf(_("\nQuerying for the IPv4 endpoint %s of a Teredo IPv6 address.\n\n"), p);
          server = whichwhois(p);
          qstring = p ;
          break;
      default:
          break;
    }

    if (!server)
      return NULL;

    p = queryformat(server, fstring, qstring);
    if (verb) {
      printf(_("Using server %s.\n"), server);
      printf(_("Query string: \"%s\"\n\n"), p);
    }

    sockfd = openconn(server, port);

    strcat(p, "\r\n");
    server = do_query(sockfd, p);

    /* recursion is fun */
    if (server) {
      printf(_("\n\nFound a referral to %s.\n\n"), server);
      handle_query(server, NULL, qstring, fstring);
    }

    return NULL;
}

#ifdef CONFIG_FILE
const char *match_config_file(const char *s)
{
    FILE *fp;
    char buf[512];
    static const char delim[] = " \t";

    if ((fp = fopen(CONFIG_FILE, "r")) == NULL) {
      if (errno != ENOENT)
          err_sys("Cannot open " CONFIG_FILE);
      return NULL;
    }

    while (fgets(buf, sizeof(buf), fp) != NULL) {
      char *p;
      const char *pattern, *server;
#ifdef HAVE_REGEXEC
      int i;
      regex_t re;
#endif

      for (p = buf; *p; p++)
          if (*p == '\n')
            *p = '\0';

      p = buf;
      while (*p == ' ' || *p == '\t')     /* eat leading blanks */
          p++;
      if (!*p)
          continue;           /* skip empty lines */
      if (*p == '#')
          continue;           /* skip comments */

      pattern = strtok(p, delim);
      server = strtok(NULL, delim);
      if (!pattern || !server)
          err_quit(_("Cannot parse this line: %s"), p);
      p = strtok(NULL, delim);
      if (p)
          err_quit(_("Cannot parse this line: %s"), p);

#ifdef HAVE_REGEXEC
      i = regcomp(&re, pattern, REG_EXTENDED|REG_ICASE|REG_NOSUB);
      if (i != 0) {
          char m[1024];
          regerror(i, &re, m, sizeof(m));
          err_quit("Invalid regular expression '%s': %s", pattern, m);
      }

      i = regexec(&re, s, 0, NULL, 0);
      if (i == 0) {
          regfree(&re);
          return strdup(server);
      }
      if (i != REG_NOMATCH) {
          char m[1024];
          regerror(i, &re, m, sizeof(m));
          err_quit("regexec: %s",  m);
      }
      regfree(&re);
#else
      if (domcmp(s, pattern))
          return strdup(server);
#endif
    }
    return NULL;
}
#endif

/* Parses an user-supplied string and tries to guess the right whois server.
 * Returns a statically allocated buffer.
 */
const char *whichwhois(const char *s)
{
    unsigned long ip, as32;
    unsigned int i;
    const char *colon;

    /* IPv6 address */
    if ((colon = strchr(s, ':'))) {
      unsigned long v6prefix, v6net;

      /* RPSL hierarchical objects */
      if (strncaseeq(s, "as", 2)) {
          if (isasciidigit(s[2]))
            return whereas(atoi(s + 2));
          else
            return "";
      }

      v6prefix = strtol(s, NULL, 16);

      if (v6prefix == 0)
          return "\x05";                  /* unknown */

      v6net = (v6prefix << 16) + strtol(colon + 1, NULL, 16);/* second u16 */

      for (i = 0; ip6_assign[i].serv; i++) {
          if ((v6net & (~0UL << (32 - ip6_assign[i].masklen)))
                == ip6_assign[i].net)
            return ip6_assign[i].serv;
      }

      return "\x06";                /* unknown allocation */
    }

    /* email address */
    if (strchr(s, '@'))
      return "\x05";

    /* no dot and no hyphen means it's a NSI NIC handle or ASN (?) */
    if (!strpbrk(s, ".-")) {
      if (strncaseeq(s, "as", 2) &&       /* it's an AS */
            (isasciidigit(s[2]) || s[2] == ' '))
          return whereas(atoi(s + 2));
      if (*s == '!')    /* NSI NIC handle */
          return "whois.networksolutions.com";
      else
          return "\x05";      /* probably a unknown kind of nic handle */
    }

    /* ASN32? */
    if (strncaseeq(s, "as", 2) && s[2] && (as32 = asn32_to_long(s + 2)) != 0)
      return whereas32(as32);

    /* smells like an IP? */
    if ((ip = myinet_aton(s))) {
      for (i = 0; ip_assign[i].serv; i++)
          if ((ip & ip_assign[i].mask) == ip_assign[i].net)
            return ip_assign[i].serv;
      return "\x05";                /* not in the unicast IPv4 space */
    }

    /* check the TLDs list */
    for (i = 0; tld_serv[i]; i += 2)
      if (domcmp(s, tld_serv[i]))
          return tld_serv[i + 1];

    /* no dot but hyphen */
    if (!strchr(s, '.')) {
      /* search for strings at the start of the word */
      for (i = 0; nic_handles[i]; i += 2)
          if (strncaseeq(s, nic_handles[i], strlen(nic_handles[i])))
            return nic_handles[i + 1];
      /* it's probably a network name */
      return "";
    }

    /* has dot and maybe a hyphen and it's not in tld_serv[], WTF is it? */
    /* either a TLD or a NIC handle we don't know about yet */
    return "\x05";
}

const char *whereas32(const unsigned long asn)
{
    int i;

    for (i = 0; as32_assign[i].serv; i++)
      if (asn >= as32_assign[i].first && asn <= as32_assign[i].last)
          return as32_assign[i].serv;
    return "\x06";
}

const char *whereas(const unsigned short asn)
{
    int i;

    for (i = 0; as_assign[i].serv; i++)
      if (asn >= as_assign[i].first && asn <= as_assign[i].last)
          return as_assign[i].serv;
    return "\x06";
}

char *queryformat(const char *server, const char *flags, const char *query)
{
    char *buf, *p;
    int i, isripe = 0;

    /* 64 bytes reserved for server-specific flags added later */
    buf = malloc(strlen(flags) + strlen(query) + strlen(client_tag) + 64);
    *buf = '\0';
    for (i = 0; ripe_servers[i]; i++)
      if (streq(server, ripe_servers[i])) {
          strcat(buf, "-V ");
          strcat(buf, client_tag);
          strcat(buf, " ");
          isripe = 1;
          break;
      }
    if (*flags) {
      if (!isripe && !streq(server, "whois.corenic.net"))
          puts(_("Warning: RIPE flags used with a traditional server."));
      strcat(buf, flags);
    }

#ifdef HAVE_LIBIDN
    /* why, oh why DENIC had to make whois "user friendly"?
     * Do this only if the user did not use any flag.
     */
    if (streq(server, "whois.denic.de") && domcmp(query, ".de")
          && !strchr(query, ' ') && !*flags)
      sprintf(buf, "-T dn,ace -C US-ASCII %s", query);
    else
    /* here we have another registrar who could not make things simple
     * -C sets the language for both input and output
     */
    if (!isripe && streq(server, "whois.cat") && domcmp(query, ".cat")
          && !strchr(query, ' '))
      sprintf(buf, "-C US-ASCII ace %s", query);
    else
#endif
    if (!isripe && (streq(server, "whois.nic.mil") ||
          streq(server, "whois.nic.ad.jp")) &&
          strncaseeq(query, "AS", 2) && isasciidigit(query[2]))
      /* FIXME: /e is not applied to .JP ASN */
      sprintf(buf, "AS %s", query + 2);   /* fix query for DDN */
    else if (!isripe && (streq(server, "whois.nic.ad.jp") ||
          streq(server, "whois.jprs.jp"))) {
      char *lang = getenv("LANG");  /* not a perfect check, but... */
      if (!lang || !strneq(lang, "ja", 2))
          sprintf(buf, "%s/e", query);    /* ask for english text */
      else
          strcat(buf, query);
    } else if (!isripe && streq(server, "whois.arin.net") &&
          (p = strrchr(query, '/'))) {
      strncat(buf, query, p - query);           /* strip CIDR */
    } else
      strcat(buf, query);
    return buf;
}

/* the first parameter contains the state of this simple state machine:
 * HIDE_DISABLED: hidden text finished
 * HIDE_UNSTARTED: hidden text not seen yet
 * >= 0: currently hiding message hide_strings[*hiding]
 */
int hide_line(int *hiding, const char *const line)
{
    int i;

    if (*hiding == HIDE_DISABLED) {
      return 0;
    } else if (*hiding == HIDE_UNSTARTED) {     /* looking for smtng to hide */
      for (i = 0; hide_strings[i] != NULL; i += 2) {
          if (strneq(line, hide_strings[i], strlen(hide_strings[i]))) {
            *hiding = i;                  /* start hiding */
            return 1;               /* and hide this line */
          }
      }
      return 0;                     /* don't hide this line */
    } else if (*hiding > HIDE_UNSTARTED) {      /* hiding something */
      if (*hide_strings[*hiding + 1] == '\0')   { /*look for a blank line?*/
          if (*line == '\n' || *line == '\r' || *line == '\0') {
            *hiding = HIDE_DISABLED;      /* stop hiding */
            return 0;         /* but do not hide the blank line */
          }
      } else {                      /*look for a matching string*/
          if (strneq(line, hide_strings[*hiding + 1],
                  strlen(hide_strings[*hiding + 1]))) {
            *hiding = HIDE_DISABLED;      /* stop hiding */
            return 1;               /* but hide the last line */
          }
      }
      return 1;                     /* we are hiding, so do it */
    } else
      return 0;
}

/* returns a string which should be freed by the caller, or NULL */
const char *do_query(const int sock, const char *query)
{
    char buf[2000], *p;
    FILE *fi;
    int hide = hide_discl;
    char *referral_server = NULL;

    fi = fdopen(sock, "r");
    if (write(sock, query, strlen(query)) < 0)
      err_sys("write");
/* Using shutdown used to break the buggy RIPE server. Would this work now?
    if (shutdown(sock, 1) < 0)
      err_sys("shutdown");
*/

    while (fgets(buf, sizeof(buf), fi)) {
      /* 6bone-style referral:
       * % referto: whois -h whois.arin.net -p 43 as 1
       */
      if (!referral_server && strneq(buf, "% referto:", 10)) {
          char nh[256], np[16], nq[1024];

          if (sscanf(buf, REFERTO_FORMAT, nh, np, nq) == 3) {
            /* XXX we are ignoring the new query string */
            referral_server = malloc(300);
            sprintf(referral_server, "%s:%s", nh, np);
          }
      }

      /* ARIN referrals:
       * ReferralServer: rwhois://rwhois.fuse.net:4321/
       * ReferralServer: whois://whois.ripe.net
       */
      if (!referral_server && strneq(buf, "ReferralServer:", 15)) {
          char *q;

          q = strstr(buf, "rwhois://");
          if ((q = strstr(buf, "rwhois://")))
            referral_server = strdup(q + 9);
          else if ((q = strstr(buf, "whois://")))
            referral_server = strdup(q + 8);
          if (referral_server) {
            if ((q = strchr(referral_server, '/'))
                  || (q = strchr(referral_server, '\n')))
                *q = '\0';
          }
      }

      if (hide_line(&hide, buf))
          continue;

      for (p = buf; *p && *p != '\r' && *p != '\n'; p++);
      *p = '\0';
      fprintf(stdout, "%s\n", buf);
    }
    if (ferror(fi))
      err_sys("fgets");
    fclose(fi);

    if (hide > HIDE_UNSTARTED)
      err_quit(_("Catastrophic error: disclaimer text has been changed.\n"
               "Please upgrade this program.\n"));

    return referral_server;
}

const char *query_crsnic(const int sock, const char *query)
{
    char *temp, buf[2000], *ret = NULL;
    FILE *fi;
    int hide = hide_discl;
    int state = 0;

    temp = malloc(strlen(query) + 1 + 2 + 1);
    *temp = '=';
    strcpy(temp + 1, query);
    strcat(temp, "\r\n");

    fi = fdopen(sock, "r");
    if (write(sock, temp, strlen(temp)) < 0)
      err_sys("write");
    while (fgets(buf, sizeof(buf), fi)) {
      /* If there are multiple matches only the server of the first record
         is queried */
      if (state == 0 && strneq(buf, "   Domain Name:", 15))
          state = 1;
      if (state == 1 && strneq(buf, "   Whois Server:", 16)) {
          char *p, *q;

          for (p = buf; *p != ':'; p++);  /* skip until colon */
          for (p++; *p == ' '; p++);            /* skip colon and spaces */
          ret = malloc(strlen(p) + 1);
          for (q = ret; *p != '\n' && *p != '\r' && *p != ' '; *q++ = *p++)
            ; /*copy data*/
          *q = '\0';
          state = 2;
      }
      /* the output must not be hidden or no data will be shown for
         host records and not-existing domains */
      if (!hide_line(&hide, buf))
          fputs(buf, stdout);
    }
    if (ferror(fi))
      err_sys("fgets");

    free(temp);
    return ret;
}

const char *query_pir(const int sock, const char *query)
{
    char *temp, buf[2000], *ret = NULL;
    FILE *fi;
    int hide = hide_discl;
    int state = 0;

    temp = malloc(strlen(query) + 5 + 2 + 1);
    strcpy(temp, "FULL ");
    strcat(temp, query);
    strcat(temp, "\r\n");

    fi = fdopen(sock, "r");
    if (write(sock, temp, strlen(temp)) < 0)
      err_sys("write");
    while (fgets(buf, sizeof(buf), fi)) {
      /* If there are multiple matches only the server of the first record
         is queried */
      if (state == 0 &&
            strneq(buf, "Registrant Name:SEE SPONSORING REGISTRAR", 40))
          state = 1;
      if (state == 1 &&
            strneq(buf, "Registrant Street1:Whois Server:", 32)) {
          char *p, *q;

          for (p = buf; *p != ':'; p++);  /* skip until colon */
          for (p++; *p != ':'; p++);            /* skip until 2nd colon */
          for (p++; *p == ' '; p++);            /* skip colon and spaces */
          ret = malloc(strlen(p) + 1);
          for (q = ret; *p != '\n' && *p != '\r'; *q++ = *p++); /*copy data*/
          *q = '\0';
          state = 2;
      }
      if (!hide_line(&hide, buf))
          fputs(buf, stdout);
    }
    if (ferror(fi))
      err_sys("fgets");

    free(temp);
    return ret;
}

const char *query_afilias(const int sock, const char *query)
{
    char *temp, buf[2000], *ret = NULL;
    FILE *fi;
    int hide = hide_discl;
    int state = 0;

    temp = malloc(strlen(query) + 2 + 1);
    strcpy(temp, query);
    strcat(temp, "\r\n");

    fi = fdopen(sock, "r");
    if (write(sock, temp, strlen(temp)) < 0)
      err_sys("write");

    while (fgets(buf, sizeof(buf), fi)) {
      if (state == 0 && strneq(buf, "Domain Name:", 12))
          state = 1;
      if (state == 1 && strneq(buf, "Whois Server:", 13)) {
          char *p, *q;

          for (p = buf; *p != ':'; p++);  /* skip until colon */
          for (p++; *p == ' '; p++);            /* skip colon and spaces */
          ret = malloc(strlen(p) + 1);
          for (q = ret; *p != '\n' && *p != '\r' && *p != ' '; *q++ = *p++)
            ; /*copy data*/
          *q = '\0';
      }

      if (!hide_line(&hide, buf)) {
          char *p;

          for (p = buf; *p && *p != '\r' && *p != '\n'; p++)
            ;
          *p = '\0';
          fprintf(stdout, "%s\n", buf);
      }
    }
    if (ferror(fi))
      err_sys("fgets");
    fclose(fi);

    if (hide > HIDE_UNSTARTED)
      err_quit(_("Catastrophic error: disclaimer text has been changed.\n"
               "Please upgrade this program.\n"));

    return ret;
}

int openconn(const char *server, const char *port)
{
    int fd = -1;
#ifdef HAVE_GETADDRINFO
    int err;
    struct addrinfo hints, *res, *ai;
#else
    struct hostent *hostinfo;
    struct servent *servinfo;
    struct sockaddr_in saddr;
#endif

    alarm(60);

#ifdef HAVE_GETADDRINFO
    memset(&hints, 0, sizeof(struct addrinfo));
    hints.ai_family = AF_UNSPEC;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_flags = AI_IDN;

    if ((err = getaddrinfo(server, port ? port : "nicname", &hints, &res)) != 0)
      err_quit("getaddrinfo(%s): %s", server, gai_strerror(err));
    for (ai = res; ai; ai = ai->ai_next) {
      if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
          continue;           /* ignore */
      if (connect(fd, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == 0)
          break;        /* success */
      close(fd);
    }
    freeaddrinfo(res);

    if (!ai)
      err_sys("connect");
#else
    if ((hostinfo = gethostbyname(server)) == NULL)
      err_quit(_("Host %s not found."), server);
    if ((fd = socket(PF_INET, SOCK_STREAM, IPPROTO_IP)) < 0)
      err_sys("socket");
    memset(&saddr, 0, sizeof(saddr));
    saddr.sin_addr = *(struct in_addr *) hostinfo->h_addr;
    saddr.sin_family = AF_INET;
    if (!port) {
      saddr.sin_port = htons(43);
    } else if ((saddr.sin_port = htons(atoi(port))) == 0) {
      if ((servinfo = getservbyname(port, "tcp")) == NULL)
          err_quit(_("%s/tcp: unknown service"), port);
      saddr.sin_port = servinfo->s_port;
    }
    if (connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
      err_sys("connect");
#endif

    /*
     * Now we are connected and the query is supposed to complete quickly.
     * This will help people who run whois ... | less
     */
    alarm(0);

    return fd;
}

void alarm_handler(int signum)
{
    close(sockfd);
    err_quit(_("Timeout."));
}

void sighandler(int signum)
{
    close(sockfd);
    err_quit(_("Interrupted by signal %d..."), signum);
}

/* check if dom ends with tld */
int domcmp(const char *dom, const char *tld)
{
    const char *p, *q;

    for (p = dom; *p; p++); p--;    /* move to the last char */
    for (q = tld; *q; q++); q--;
    while (p >= dom && q >= tld && tolower(*p) == *q) {     /* compare backwards */
      if (q == tld)                 /* start of the second word? */
          return 1;
      p--; q--;
    }
    return 0;
}

char *normalize_domain(const char *dom)
{
    char *p, *ret;
    char *domain_start = NULL;

    ret = strdup(dom);
    for (p = ret; *p; p++); p--;    /* move to the last char */
    /* eat trailing dots and blanks */
    for (; *p == '.' || *p == ' ' || *p == '\t' || p == ret; p--)
      *p = '\0';

#ifdef HAVE_LIBIDN
    /* find the start of the last word if there are spaces in the query */
    for (p = ret; *p; p++)
      if (*p == ' ')
          domain_start = p + 1;

    if (domain_start) {
      char *q, *r;
      int prefix_len;

      if (idna_to_ascii_lz(domain_start, &q, 0) != IDNA_SUCCESS)
          return ret;

      /* reassemble the original query in a new buffer */
      prefix_len = domain_start - ret;
      r = malloc(prefix_len + strlen(q) + 1);
      strncpy(r, ret, prefix_len);
      r[prefix_len] = '\0';
      strcat(r, q);

      free(q);
      free(ret);
      return r;
    } else {
      char *q;

      if (idna_to_ascii_lz(ret, &q, 0) != IDNA_SUCCESS)
          return ret;

      free(ret);
      return q;
    }
#else
    return ret;
#endif
}

/* server and port have to be freed by the caller */
void split_server_port(const char *const input,
      const char **server, const char **port) {
    char *p;

    if (*input == '[' && (p = strchr(input, ']'))) {  /* IPv6 */
      char *s;
      int len = p - input - 1;

      *server = s = malloc(len + 1);
      memcpy(s, input + 1, len);
      *(s + len) = '\0';

      p = strchr(p, ':');
      if (p && *(p + 1) != '\0')
          *port = strdup(p + 1);                /* IPv6 + port */
    } else if ((p = strchr(input, ':')) &&            /* IPv6, no port */
          strchr(p + 1, ':')) {                 /*   and no brackets */
      *server = strdup(input);
    } else if ((p = strchr(input, ':'))) {            /* IPv4 + port */
      char *s;
      int len = p - input;

      *server = s = malloc(len + 1);
      memcpy(s, input, len);
      *(s + len) = '\0';

      p++;
      if (*p != '\0')
          *port = strdup(p);
    } else {                                    /* IPv4, no port */
      *server = strdup(input);
    }

    /* change the server name to lower case */
    for (p = (char *) *server; *p && *p != '\0'; p++)
      *p = tolower(*p);
}

char *convert_6to4(const char *s)
{
    char *new = malloc(sizeof("255.255.255.255"));
    unsigned int a, b;

    if (sscanf(s, "2002:%x:%x:", &a, &b) != 2)
      return (char *) "0.0.0.0";

    sprintf(new, "%d.%d.%d.%d", a >> 8, a & 0xff, b >> 8, b & 0xff);
    return new;
}

char *convert_teredo(const char *s)
{
    char *new = malloc(sizeof("255.255.255.255"));
    unsigned int a, b;

    if (sscanf(s, "2001:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%x:%x", &a, &b) != 2)
      return (char *) "0.0.0.0";

    a ^= 0xffff;
    b ^= 0xffff;
    sprintf(new, "%d.%d.%d.%d", a >> 8, a & 0xff, b >> 8, b & 0xff);
    return new;
}

unsigned long myinet_aton(const char *s)
{
    unsigned long a, b, c, d;
    int elements;
    char junk;

    if (!s)
      return 0;
    elements = sscanf(s, "%lu.%lu.%lu.%lu%c", &a, &b, &c, &d, &junk);
    if (!(elements == 4 || (elements == 5 && junk == '/')))
      return 0;
    if (a > 255 || b > 255 || c > 255 || d > 255)
      return 0;
    return (a << 24) + (b << 16) + (c << 8) + d;
}

unsigned long asn32_to_long(const char *s)
{
    unsigned long a, b;
    char junk;

    if (!s)
      return 0;
    if (sscanf(s, "%lu.%lu%c", &a, &b, &junk) != 2)
      return 0;
    if (a > 65535 || b > 65535)
      return 0;
    return (a << 16) + b;
}

int isasciidigit(const char c) {
    return (c >= '0' && c <= '9') ? 1 : 0;
}

/* http://www.ripe.net/ripe/docs/databaseref-manual.html */

void usage(void)
{
    fprintf(stderr, _(
"Usage: whois [OPTION]... OBJECT...\n\n"
"-l                     one level less specific lookup [RPSL only]\n"
"-L                     find all Less specific matches\n"
"-m                     find first level more specific matches\n"
"-M                     find all More specific matches\n"
"-c                     find the smallest match containing a mnt-irt attribute\n"
"-x                     exact match [RPSL only]\n"
"-d                     return DNS reverse delegation objects too [RPSL only]\n"
"-i ATTR[,ATTR]...      do an inverse lookup for specified ATTRibutes\n"
"-T TYPE[,TYPE]...      only look for objects of TYPE\n"
"-K                     only primary keys are returned [RPSL only]\n"
"-r                     turn off recursive lookups for contact information\n"
"-R                     force to show local copy of the domain object even\n"
"                       if it contains referral\n"
"-a                     search all databases\n"
"-s SOURCE[,SOURCE]...  search the database from SOURCE\n"
"-g SOURCE:FIRST-LAST   find updates from SOURCE from serial FIRST to LAST\n"
"-t TYPE                request template for object of TYPE ('all' for a list)\n"
"-v TYPE                request verbose template for object of TYPE\n"
"-q [version|sources|types]  query specified server info [RPSL only]\n"
"-F                     fast raw output (implies -r)\n"
"-h HOST                connect to server HOST\n"
"-p PORT                connect to PORT\n"
"-H                     hide legal disclaimers\n"
"      --verbose        explain what is being done\n"
"      --help           display this help and exit\n"
"      --version        output version information and exit\n"
));
    exit(0);
}


Generated by  Doxygen 1.6.0   Back to index