📄 whois.c
字号:
/* Copyright 1999 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. */#ifdef HAVE_CONFIG_H# include <config.h>#endif/* System library */#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <getopt.h>#include <unistd.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>/* Application-specific */#include <data.h>#include <whois.h>/* Global variables */int sockfd, verb = 0;#ifdef ALWAYS_HIDE_DISCLint hide_discl = 0;#elseint hide_discl = 2;#endifstatic struct option longopts[] = { {"help", no_argument, NULL, 0 }, {"version", no_argument, NULL, 1 }, {"verbose", no_argument, NULL, 'V'}, {"server", required_argument, NULL, 'h'}, {"host", required_argument, NULL, 'h'}, {0, 0, 0, 0}};int main(int argc, char *argv[]){ int ch, nopar = 0; const char *server = NULL, *port = NULL; char *p, *q, *qstring, fstring[64] = "\0"; extern char *optarg; extern int optind;#ifdef ENABLE_NLS setlocale(LC_MESSAGES, ""); bindtextdomain(NLS_CAT_NAME, LOCALEDIR); textdomain(NLS_CAT_NAME);#endif while ((ch = getopt_long(argc, argv, "acFg:h:Hi:lLmMp:q:rRs:St:T:v:Vx", longopts, 0)) > 0) { /* RIPE flags */ if (strchr(ripeflags, ch)) { for (p = fstring; *p != '\0'; p++); sprintf(p--, "-%c ", ch); continue; } if (strchr(ripeflagsp, ch)) { for (p = fstring; *p != '\0'; p++); sprintf(p--, "-%c %s ", ch, optarg); if (ch == 't' || ch == 'v' || ch == 'q') nopar = 1; continue; } /* program flags */ switch (ch) { case 'h': server = q = malloc(strlen(optarg) + 1); for (p = optarg; *p != '\0' && *p != ':'; *q++ = tolower(*p++)); if (*p == ':') port = p + 1; *q = '\0'; break; case 'H': hide_discl = 0; /* enable disclaimers hiding */ break; case 'p': port = optarg; break; case 'V': 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", PACKAGE_NAME, PACKAGE_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(1); *qstring = '\0'; /* parse other parameters, if any */ if (!nopar) { int qslen = 0; while (1) { qslen += strlen(*argv) + 1; qstring = realloc(qstring, qslen); strcat(qstring, *argv++); if (argc == 1) break; strcat(qstring, " "); argc--; } } if (!server && domfind(qstring, gtlds)) { if (verb) puts(_("Connecting to whois.internic.net.")); sockfd = openconn("whois.internic.net", NULL); server = query_crsnic(sockfd, qstring); closeconn(sockfd); if (!server) exit(0); printf(_("\nFound InterNIC referral to %s.\n\n"), server); } if (!server) { server = whichwhois(qstring); switch (server[0]) { case 0: if (!(server = getenv("WHOIS_SERVER"))) server = DEFAULTSERVER; if (verb) printf(_("Using default server %s.\n"), server); break; case 1: puts(_("This TLD has no whois server, but you can access the " "whois database at")); case 2: puts(server + 1); exit(0); case 3: puts(_("This TLD has no whois server.")); exit(0); default: if (verb) printf(_("Using server %s.\n"), server); } } if (getenv("WHOIS_HIDE")) hide_discl = 0; p = queryformat(server, fstring, qstring); if (verb) printf(_("Query string: \"%s\"\n\n"), p); strcat(p, "\r\n"); signal(SIGTERM, sighandler); signal(SIGINT, sighandler); sockfd = openconn(server, port); do_query(sockfd, p); closeconn(sockfd); exit(0);}const char *whichwhois(const char *s){ unsigned long ip; unsigned int i; /* -v or -t has been used */ if (*s == '\0') return "whois.ripe.net"; /* IPv6 address */ if (strchr(s, ':')) { if (strncasecmp(s, "2001:2", 6) == 0) /* XXX ugly hack! */ return "whois.apnic.net"; if (strncasecmp(s, "2001:4", 6) == 0) return "whois.arin.net"; if (strncasecmp(s, "2001:6", 6) == 0) return "whois.ripe.net"; /* if (strncasecmp(s, "3ffe", 4) == 0) */ return "whois.6bone.net"; } /* email address */ if (strchr(s, '@')) return ""; /* no dot and no hyphen means it's a NSI NIC handle or ASN (?) */ if (!strpbrk(s, ".-")) { const char *p; for (p = s; *p != '\0'; p++); /* go to the end of s */ if (strncasecmp(s, "as", 2) == 0 && /* it's an AS */ ((s[2] >= '0' && s[2] <= '9') || s[2] == ' ')) return whereas(atoi(s + 2), as_assign); else if (strncasecmp(p - 2, "jp", 2) == 0) /* JP NIC handle */ return "whois.nic.ad.jp"; if (*p == '!') /* NSI NIC handle */ return "whois.networksolutions.com"; else /* it's a NSI NIC handle or something we don't know about */ return ""; } /* 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; if (verb) puts(_("I don't know where this IP has been delegated.\n" "I'll try ARIN and hope for the best...")); return "whois.arin.net"; } /* check TLD 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 (strncasecmp(s, nic_handles[i], strlen(nic_handles[i])) == 0) return nic_handles[i + 1]; if (verb) puts(_("I guess it's a netblock name but I don't know where to" " look it up.")); return "whois.arin.net"; } /* has dot and hypen and it's not in tld_serv[], WTF is it? */ if (verb) puts(_("I guess it's a domain but I don't know where to look it" " up.")); return "";}const char *whereas(int asn, struct as_del aslist[]){ int i; if (asn > 16383) puts(_("Unknown AS number. Please upgrade this program.")); for (i = 0; aslist[i].serv; i++) if (asn >= aslist[i].first && asn <= aslist[i].last) return aslist[i].serv; return "whois.arin.net";}char *queryformat(const char *server, const char *flags, const char *query){ char *buf; int i, isripe = 0; /* +10 for CORE; +2 for \r\n; +1 for NULL */ buf = malloc(strlen(flags) + strlen(query) + 10 + 2 + 1); *buf = '\0'; for (i = 0; ripe_servers[i]; i++) if (strcmp(server, ripe_servers[i]) == 0) { strcat(buf, "-V " IDSTRING " "); isripe = 1; break; } if (!isripe) for (i = 0; ripe_servers_old[i]; i++) if (strcmp(server, ripe_servers_old[i]) == 0) { strcat(buf, "-V" IDSTRING " "); isripe = 1; break; } if (*flags != '\0') { if (!isripe && strcmp(server, "whois.corenic.net") != 0) puts(_("Warning: RIPE flags ignored for a traditional server.")); else strcat(buf, flags); } if (!isripe && (strcmp(server, "whois.arin.net") == 0 || strcmp(server, "whois.nic.mil") == 0) && strncasecmp(query, "AS", 2) == 0 && query[2] >= '0' && query[2] <= '9') sprintf(buf, "AS %s", query + 2); /* fix query for ARIN */ else if (!isripe && strcmp(server, "whois.corenic.net") == 0) sprintf(buf, "--machine %s", query); /* machine readable output */ else if (!isripe && strcmp(server, "whois.ncst.ernet.in") == 0 && !strchr(query, ' ')) sprintf(buf, "domain %s", query); /* ask for a domain */ else if (!isripe && strcmp(server, "whois.nic.ad.jp") == 0) { char *lang = getenv("LANG"); /* not a perfect check, but... */ if (!lang || (strncmp(lang, "ja", 2) != 0)) sprintf(buf, "%s/e", query); /* ask for english text */ else strcat(buf, query); } else strcat(buf, query); return buf;}void do_query(const int sock, const char *query){ char buf[200], *p; FILE *fi; int i = 0, hide = hide_discl; fi = fdopen(sock, "r"); if (write(sock, query, strlen(query)) < 0) err_sys("write"); if (shutdown(sock, 1) < 0) err_sys("shutdown"); while (fgets(buf, 200, fi)) { /* XXX errors? */ if (hide == 1) { if (strncmp(buf, hide_strings[i+1], strlen(hide_strings[i+1]))==0) hide = 2; /* stop hiding */ continue; /* hide this line */ } if (hide == 0) { for (i = 0; hide_strings[i] != NULL; i += 2) { if (strncmp(buf, hide_strings[i], strlen(hide_strings[i]))==0){ hide = 1; /* start hiding */ break; } } if (hide == 1) continue; /* hide the first line */ }#ifdef EXT_6BONE /* % referto: whois -h whois.arin.net -p 43 as 1 */ if (strncmp(buf, "% referto:", 10) == 0) { char nh[256], np[16], nq[1024]; if (sscanf(buf, REFERTO_FORMAT, nh, np, nq) == 3) { int fd; if (verb) printf(_("Detected referral to %s on %s.\n"), nq, nh); strcat(nq, "\r\n"); fd = openconn(nh, np); do_query(fd, nq); closeconn(fd); continue; } }#endif for (p = buf; *p && *p != '\r' && *p != '\n'; p++); *p = '\0'; fprintf(stdout, "%s\n", buf); } if (ferror(fi)) err_sys("fgets"); if (hide == 1) err_quit(_("Catastrophic error: disclaimer text has been changed.\n" "Please upgrade this program.\n"));}const char *query_crsnic(const int sock, const char *query){ char *temp, buf[100], *ret = NULL; FILE *fi; 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, 100, fi)) { /* If there are multiple matches only the server of the first record is queried */ if (strncmp(buf, " Whois Server:", 16) == 0 && !ret) { 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'; *q++ = *p++); /*copy data*/ *q = '\0'; } fputs(buf, stdout); } if (ferror(fi)) err_sys("fgets"); free(temp); return ret;}int openconn(const char *server, const char *port){ int fd;#ifdef HAVE_GETADDRINFO int i; struct addrinfo hints, *res, *ressave;#else struct hostent *hostinfo; struct servent *servinfo; struct sockaddr_in saddr;#endif#ifdef HAVE_GETADDRINFO memset(&hints, 0, sizeof(struct addrinfo)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; if ((i = getaddrinfo(server, port ? port : "whois", &hints, &res)) != 0) err_quit("getaddrinfo: %s", gai_strerror(i)); for (ressave = res; res; res = res->ai_next) { if ((fd = socket(res->ai_family, res->ai_socktype, res->ai_protocol))<0) continue; /* ignore */ if (connect(fd, res->ai_addr, res->ai_addrlen) == 0) break; /* success */ close(fd); } if (!res) err_sys("connect"); freeaddrinfo(ressave);#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, &saddr, sizeof(saddr)) < 0) err_sys("connect");#endif return (fd);}void closeconn(const int fd){ close(fd);}void sighandler(int signum){ closeconn(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 != '\0'; p++); p--; /* move to the last char */ for (q = tld; *q != '\0'; 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;}/* check if dom ends with an element of tldlist[] */int domfind(const char *dom, const char *tldlist[]){ int i; for (i = 0; tldlist[i]; i++) if (domcmp(dom, tldlist[i])) return 1; return 0;}unsigned long myinet_aton(const char *s){ int a, b, c, d; if (!s) return 0; if (sscanf(s, "%d.%d.%d.%d", &a, &b, &c, &d) != 4) return 0; return (a << 24) + (b << 16) + (c << 8) + d;}void usage(void){ fprintf(stderr, _("Usage: whois [OPTION]... OBJECT...\n\n""-a search all databases\n""-F fast raw output (implies -r)\n""-g SOURCE:FIRST-LAST find updates from SOURCE from serial FIRST to LAST\n""-h HOST connect to server HOST\n""-H hide legal disclaimers\n""-i ATTR[,ATTR]... do an inverse lookup for specified ATTRibutes\n""-l one level less specific lookup (RPSL only)\n""-L find all Less specific matches\n""-M find all More specific matches\n""-m find first level more specific matches\n""-r turn off recursive lookups\n""-p PORT connect to PORT\n""-R force to show local copy of the domain object even\n"" if it contains referral\n""-S tell server to leave out syntactic sugar\n""-s SOURCE[,SOURCE]... search the database from SOURCE\n""-T TYPE[,TYPE]... only look for objects of TYPE\n""-q [version|sources] query specified server info (RPSL only)\n""-t TYPE requests template for object of TYPE ('all' for a list)\n""-v TYPE requests verbose template for object of TYPE\n""-x exact match only (RPSL only)\n""-V --verbose explain what is being done\n"" --help display this help and exit\n"" --version output version information and exit\n")); exit(0);}/* Error routines */void err_sys(const char *fmt, ...){ va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fprintf(stderr, ": %s\n", strerror(errno)); va_end(ap); exit(2);}void err_quit(const char *fmt, ...){ va_list ap; va_start(ap, fmt); vfprintf(stderr, fmt, ap); fputs("\n", stderr); va_end(ap); exit(2);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -