/psad-2.1.7/deps/whois/whois.c
C | 1032 lines | 815 code | 135 blank | 82 comment | 308 complexity | 84ad4b6c182571b75189879e76927d18 MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.0
- /* 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:
- #ifdef VERSION
- fprintf(stderr, _("Version %s.\n\nReport bugs to %s.\n"),
- VERSION, "<md+whois@linux.it>");
- #else
- fprintf(stderr, "%s %s\n", inetutils_package, inetutils_version);
- #endif
- 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);
- }