// zwhois.cpp : (c) 2004 by Erik Aronesty of ZoneEdit, Inc. // Attribution-ShareAlike 2.0 License. // Permission to copy granted with attribution to the author included. // Full source-code must be included with every copy. // If you alter, transform, or build upon this work, you may distribute the resulting work only under a license identical to this one. // Full legal terms here: http://creativecommons.org/licenses/by-sa/2.0/ // // 2004-10-21 version 1.0 (EA) initial release // 2004-10-22 version 1.0.1 (EA) added more error handling, license URL // 2004-10-23 version 1.1 (EA) added bind option // 2004-10-24 version 1.1.1 (EA) double buffer code now works // 2004-10-25 version 1.1.2 (EA) logic change for internic (todo: base it on hostent's server name?) // 2004-10-27 version 1.1.3 (EA) made linux strlwr readable #ifdef WIN32 # ifdef _DEBUG # define new DEBUG_NEW # endif #endif #include #include #include #ifdef WIN32 # include # pragma comment(lib, "wsock32.lib") #else # include # include # include # include # include # include #endif #define META_WHOIS_ZONE "tld-whois.zoneedit.com" char* sock_geterror(); int whois_lookup(char *domain, char *server); char *valid_ip4(char *s); char *valid_net4(char *s); #ifndef WIN32 char *strlwr(char *s); # define SOCKET int # define SOCKET_ERROR -1 #endif #define MAX_BUF 1024 bool opt_norec = false, opt_onlyrec = false, opt_verbose = false; char *opt_server = NULL; char *opt_bind = NULL; #ifndef WIN32 # define stricmp strcasecmp # define strnicmp strncasecmp #endif int main(int argc, char* argv[]) { #ifdef WIN32 WSADATA wsaData; int iResult = WSAStartup( MAKEWORD(2,2), &wsaData ); if ( iResult != NO_ERROR ) { fprintf(stderr, "error: windows sockets failed to load\n"); return 4; } #endif /* crappy argument handling */ while (argc > 2) { if (!stricmp(argv[1],"-n")) {opt_norec = true; ++argv; --argc;} else if (!stricmp(argv[1],"--nofollow")) {opt_norec = true; ++argv; --argc;} else if (!stricmp(argv[1],"-o")) {opt_onlyrec = true; ++argv; --argc;} else if (!stricmp(argv[1],"--onlyfollow")) {opt_onlyrec = true; ++argv; --argc;} else if (!stricmp(argv[1],"-v")) {opt_verbose = true; ++argv; --argc;} else if (!stricmp(argv[1],"--verbose")) {opt_verbose = true; ++argv; --argc;} else if (!stricmp(argv[1],"-s") && argc > 3) {opt_server = argv[2]; argv+=2; argc-=2;} else if (!stricmp(argv[1],"--server") && argc > 3) {opt_server = argv[2]; argv+=2; argc-=2;} else if (!stricmp(argv[1],"-b") && argc > 3) {opt_bind = argv[2]; argv+=2; argc-=2;} else if (!stricmp(argv[1],"--bind") && argc > 3) {opt_bind = argv[2]; argv+=2; argc-=2;} else break; } if (argc != 2) { fprintf(stderr, "zwhois 1.1.3 (C) 2004: ZoneEdit, Inc. - CC Attribution-ShareAlike 2.0 License\n\ \n\ Usage: zwhois [OPTIONS] \n\ -s, --server SERVER use the specified whois server\n\ -b, --bind IP bind to this outgoing ip\n\ -n, --nofollow don't follow redirects\n\ -o, --onlyfollow only output final redirects\n\ -v, --verbose debug/verbose output\n\ \n\ Looks up domain, ip or ARIN net-handle ownership. Uses heuristics plus\n\ .tld-whois.zoneedit.com to autodetermine the correct whois server.\n\ \n\ "); return 2; } char *domain = argv[1]; if (!opt_server && valid_ip4(domain) || valid_net4(domain)) { return whois_lookup(domain, "whois.arin.net"); } else { return whois_lookup(domain, opt_server); } } int whois_lookup(char *domain, char *server) { if (strlen(domain) > (MAX_BUF - 10)) { fprintf(stderr, "error: domain greater than %d bytes, '%s'\n", (MAX_BUF - 10), domain); return 3; } /* todo, support alternative character-set tlds, if they ever get going */ char *tld = strrchr(domain, '.'); if (tld) ++tld; if (!tld) tld = ""; bool rec_netsol = !server && (!stricmp(tld, "com")||!stricmp(tld, "net")||!stricmp(tld, "org")); bool rec_arin = server && !stricmp(server, "whois.arin.net"); bool needs_output = server || !opt_onlyrec; if (!server) { if (!tld || !*tld || !isalpha(*tld)) { fprintf(stderr, "error: invalid domain/ip\n"); return 3; } static char meta_domain[MAX_BUF] = ""; strcat(meta_domain,tld); strcat(meta_domain,"."); strcat(meta_domain,META_WHOIS_ZONE); server = meta_domain; } if (opt_verbose) printf("status: looking up %s\n", server); SOCKET s = socket(AF_INET,SOCK_STREAM,0); if (opt_bind) { struct hostent * bind_hostent = gethostbyname(opt_bind); if (!bind_hostent) { fprintf(stderr, "error: failed to validate address %s\n%s", opt_bind, sock_geterror()); return 5; } in_addr *addr1 = (in_addr *) bind_hostent->h_addr_list[0]; if (addr1) { sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = 0; addr.sin_addr = *addr1; memset(&(addr.sin_zero), 0, 8); if (bind(s, (sockaddr *) &addr, sizeof(addr))) { fprintf(stderr, "error: failed to bind to address %s\n%s", opt_bind, sock_geterror()); return 5; } } } struct hostent * server_hostent = gethostbyname(server); if (!server_hostent) { fprintf(stderr, "error: failed to find address %s\n%s", server, sock_geterror()); return 5; } in_addr *addr1 = (in_addr *) server_hostent->h_addr_list[0]; sockaddr_in addr; addr.sin_family = AF_INET; addr.sin_port = htons(43); addr.sin_addr = *addr1; memset(&(addr.sin_zero), 0, 8); if (opt_verbose) printf("status: connecting to %s (%s)\n", server_hostent->h_name, inet_ntoa(*addr1)); if (connect(s, (sockaddr *) &addr, sizeof(sockaddr))) { fprintf(stderr, "error: failed to connect to %s\n%s", server_hostent->h_name, sock_geterror()); return 6; } size_t n; char buf[MAX_BUF+1] = ""; if (rec_netsol && !strchr(domain, ' ')) { strcat(buf, "domain "); } strcat(buf, domain); strcat(buf, "\n"); n = send(s, buf, (int) strlen(buf), 0); char *refer = NULL; char combined_buf[MAX_BUF*2+1]; size_t combined_n = 0; while (n = recv(s, buf, MAX_BUF, 0)) { if (n == SOCKET_ERROR) { fprintf(stderr, "error: error during data\n%s", sock_geterror()); return 6; } buf[n] = '\0'; if (needs_output) fputs(buf, stdout); if (!opt_norec && !refer) { strlwr(buf); if (n + combined_n > MAX_BUF*2) { memmove(combined_buf, combined_buf+combined_n-(n + combined_n - MAX_BUF*2), (n + combined_n - MAX_BUF*2)); combined_n = combined_n - (n + combined_n - MAX_BUF*2); } memcpy(combined_buf+combined_n, buf, n); combined_n += n; combined_buf[combined_n] = '\0'; if (rec_netsol) { refer = strstr(combined_buf, "whois server:"); if (refer) { char *eol = strchr(refer, '\n'); if (eol) { *eol = '\0'; refer += 13; while (isspace(*refer)) ++refer; } } } if (rec_arin) { if (strstr(combined_buf, "refer to the apnic")) { refer = "whois.apnic.net"; } else if (strstr(combined_buf, "whois.ripe.net")) { refer = "whois.ripe.net"; } else { char * net = strstr(combined_buf, " (net-"); if (net) { net+=2; char *p = net+4; char *e = NULL; if (strtol(p, &e, 10) && *e == '-') { p = e + 1; if (strtol(p, &e, 10) && *e == '-') { p = e + 1; e = strchr(p, ')'); *e = '\0'; domain = net; refer = "whois.arin.net"; } } } } } } } if (refer && !opt_norec) { if (opt_verbose) printf("status: referred to %s\n", refer); whois_lookup(domain, refer); } return 0; } static char retString[MAX_BUF]; char* sock_geterror() { #ifndef _WINSOCKAPI_ return strerror(errno); #else long err; char* tmp; err = WSAGetLastError(); sprintf(retString, "Error code %ld: ", err); FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, /* Default language */ (LPTSTR) &tmp, 0, NULL); /* append the message text after the error code and ensure a terminating character ends the string */ strncpy(retString + strlen(retString), tmp, sizeof(retString) - strlen(retString) - 1); retString[sizeof(retString) - 1] = '\0'; return retString; #endif } char *valid_ip4(char *s) { if (!s) return NULL; char *e; long ip = strtol(s, &e, 0); if ((*e != '.') || ip < 0 || ip > 255) return NULL; s = e+1; ip = strtol(s, &e, 0); if ((*e != '.') || ip < 0 || ip > 255) return NULL; s = e+1; ip = strtol(s, &e, 0); if ((*e != '.') || ip < 0 || ip > 255) return NULL; s = e+1; ip = strtol(s, &e, 0); if (ip < 0 || ip > 255) return NULL; return e; } char *valid_net4(char *s) { if (!s) return NULL; if (strnicmp(s, "net-", 4)) return NULL; s+=4; char *e; long ip = strtol(s, &e, 0); if ((*e != '-') || ip < 0 || ip > 255) return NULL; s = e+1; ip = strtol(s, &e, 0); if ((*e != '-') || ip < 0 || ip > 255) return NULL; s = e+1; ip = strtol(s, &e, 0); if ((*e != '-') || ip < 0 || ip > 255) return NULL; s = e+1; ip = strtol(s, &e, 0); if (ip < 0 || ip > 255) return NULL; return e; } #ifndef WIN32 char *strlwr(char *s) { if (!s) return NULL; while ( *s ) { *s = (char) tolower( *s ); ++s; } return s; } #endif