PageRenderTime 53ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 1ms

/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
  1. /* Copyright 1999-2008 by Marco d'Itri <md@linux.it>.
  2. *
  3. * This program is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License version 2 as
  5. * published by the Free Software Foundation.
  6. */
  7. /* for AI_IDN */
  8. #define _GNU_SOURCE
  9. /* System library */
  10. #include <stdio.h>
  11. #include <stdlib.h>
  12. #include <stdarg.h>
  13. #include <unistd.h>
  14. #include "config.h"
  15. #include <string.h>
  16. #include <ctype.h>
  17. #include <sys/types.h>
  18. #include <sys/socket.h>
  19. #include <netinet/in.h>
  20. #include <netdb.h>
  21. #include <errno.h>
  22. #include <signal.h>
  23. #ifdef HAVE_GETOPT_LONG
  24. #include <getopt.h>
  25. #endif
  26. #ifdef HAVE_REGEXEC
  27. #include <regex.h>
  28. #endif
  29. #ifdef HAVE_LIBIDN
  30. #include <idna.h>
  31. #endif
  32. /* Application-specific */
  33. #include "data.h"
  34. #include "whois.h"
  35. #include "utils.h"
  36. /* hack */
  37. #define malloc(s) NOFAIL(malloc(s))
  38. #define realloc(p, s) NOFAIL(realloc(p, s))
  39. /* Global variables */
  40. int sockfd, verb = 0;
  41. #ifdef ALWAYS_HIDE_DISCL
  42. int hide_discl = HIDE_UNSTARTED;
  43. #else
  44. int hide_discl = HIDE_DISABLED;
  45. #endif
  46. const char *client_tag = (char *)IDSTRING;
  47. #ifdef HAVE_GETOPT_LONG
  48. static const struct option longopts[] = {
  49. {"help", no_argument, NULL, 0 },
  50. {"version", no_argument, NULL, 1 },
  51. {"verbose", no_argument, NULL, 2 },
  52. {"server", required_argument, NULL, 'h'},
  53. {"host", required_argument, NULL, 'h'},
  54. {"port", required_argument, NULL, 'p'},
  55. {NULL, 0, NULL, 0 }
  56. };
  57. #else
  58. extern char *optarg;
  59. extern int optind;
  60. #endif
  61. int main(int argc, char *argv[])
  62. {
  63. int ch, nopar = 0;
  64. const char *server = NULL, *port = NULL;
  65. char *p, *qstring, fstring[64] = "\0";
  66. #ifdef ENABLE_NLS
  67. setlocale(LC_ALL, "");
  68. bindtextdomain(NLS_CAT_NAME, LOCALEDIR);
  69. textdomain(NLS_CAT_NAME);
  70. #endif
  71. /* prepend options from environment */
  72. argv = merge_args(getenv("WHOIS_OPTIONS"), argv, &argc);
  73. while ((ch = GETOPT_LONGISH(argc, argv,
  74. "abBcdFg:Gh:Hi:KlLmMp:q:rRs:St:T:v:V:x", longopts, 0)) > 0) {
  75. /* RIPE flags */
  76. if (strchr(ripeflags, ch)) {
  77. for (p = fstring; *p; p++);
  78. sprintf(p--, "-%c ", ch);
  79. continue;
  80. }
  81. if (strchr(ripeflagsp, ch)) {
  82. for (p = fstring; *p; p++);
  83. snprintf(p--, sizeof(fstring), "-%c %s ", ch, optarg);
  84. if (ch == 't' || ch == 'v' || ch == 'q')
  85. nopar = 1;
  86. continue;
  87. }
  88. /* program flags */
  89. switch (ch) {
  90. case 'h':
  91. server = strdup(optarg);
  92. break;
  93. case 'V':
  94. client_tag = optarg;
  95. case 'H':
  96. hide_discl = HIDE_UNSTARTED; /* enable disclaimers hiding */
  97. break;
  98. case 'p':
  99. port = strdup(optarg);
  100. break;
  101. case 2:
  102. verb = 1;
  103. break;
  104. case 1:
  105. #ifdef VERSION
  106. fprintf(stderr, _("Version %s.\n\nReport bugs to %s.\n"),
  107. VERSION, "<md+whois@linux.it>");
  108. #else
  109. fprintf(stderr, "%s %s\n", inetutils_package, inetutils_version);
  110. #endif
  111. exit(0);
  112. default:
  113. usage();
  114. }
  115. }
  116. argc -= optind;
  117. argv += optind;
  118. if (argc == 0 && !nopar) /* there is no parameter */
  119. usage();
  120. /* On some systems realloc only works on non-NULL buffers */
  121. qstring = malloc(64);
  122. *qstring = '\0';
  123. /* parse other parameters, if any */
  124. if (!nopar) {
  125. int qslen = 0;
  126. while (1) {
  127. qslen += strlen(*argv) + 1 + 1;
  128. qstring = realloc(qstring, qslen);
  129. strcat(qstring, *argv++);
  130. if (argc == 1)
  131. break;
  132. strcat(qstring, " ");
  133. argc--;
  134. }
  135. }
  136. signal(SIGTERM, sighandler);
  137. signal(SIGINT, sighandler);
  138. signal(SIGALRM, alarm_handler);
  139. if (getenv("WHOIS_HIDE"))
  140. hide_discl = HIDE_UNSTARTED;
  141. /* -v or -t has been used */
  142. if (!server && !*qstring)
  143. server = strdup("whois.ripe.net");
  144. #ifdef CONFIG_FILE
  145. if (!server) {
  146. server = match_config_file(qstring);
  147. if (verb && server)
  148. printf(_("Using server %s.\n"), server);
  149. }
  150. #endif
  151. if (!server) {
  152. char *tmp;
  153. tmp = normalize_domain(qstring);
  154. free(qstring);
  155. qstring = tmp;
  156. server = whichwhois(qstring);
  157. }
  158. handle_query(server, port, qstring, fstring);
  159. exit(0);
  160. }
  161. /* server may be a server name from the command line, a server name got
  162. * from whichwhois or an encoded command/message from whichwhois.
  163. * server and port are allocated with malloc.
  164. */
  165. const char *handle_query(const char *hserver, const char *hport,
  166. const char *qstring, const char *fstring)
  167. {
  168. const char *server = NULL, *port = NULL;
  169. char *p;
  170. if (hport) {
  171. server = strdup(hserver);
  172. port = strdup(hport);
  173. } else if (hserver[0] < ' ')
  174. server = strdup(hserver);
  175. else
  176. split_server_port(hserver, &server, &port);
  177. switch (server[0]) {
  178. case 0:
  179. if (!(server = getenv("WHOIS_SERVER")))
  180. server = DEFAULTSERVER;
  181. break;
  182. case 1:
  183. puts(_("This TLD has no whois server, but you can access the "
  184. "whois database at"));
  185. puts(server + 1);
  186. return NULL;
  187. case 2:
  188. puts(server + 1);
  189. return NULL;
  190. case 3:
  191. puts(_("This TLD has no whois server."));
  192. return NULL;
  193. case 5:
  194. puts(_("No whois server is known for this kind of object."));
  195. return NULL;
  196. case 6:
  197. puts(_("Unknown AS number or IP network. Please upgrade this program."));
  198. return NULL;
  199. case 4:
  200. if (verb)
  201. printf(_("Using server %s.\n"), "whois.crsnic.net");
  202. sockfd = openconn("whois.crsnic.net", NULL);
  203. server = query_crsnic(sockfd, qstring);
  204. break;
  205. case 7:
  206. if (verb)
  207. printf(_("Using server %s.\n"),
  208. "whois.publicinterestregistry.net");
  209. sockfd = openconn("whois.publicinterestregistry.net", NULL);
  210. server = query_pir(sockfd, qstring);
  211. break;
  212. case 8:
  213. if (verb)
  214. printf(_("Using server %s.\n"), "whois.afilias-grs.info");
  215. sockfd = openconn("whois.afilias-grs.info", NULL);
  216. server = query_afilias(sockfd, qstring);
  217. break;
  218. case 9:
  219. if (verb)
  220. printf(_("Using server %s.\n"), "whois.nic.cc");
  221. sockfd = openconn("whois.nic.cc", NULL);
  222. server = query_crsnic(sockfd, qstring);
  223. break;
  224. case 0x0A:
  225. p = convert_6to4(qstring);
  226. /* XXX should fail if p = 0.0.0.0 */
  227. printf(_("\nQuerying for the IPv4 endpoint %s of a 6to4 IPv6 address.\n\n"), p);
  228. server = whichwhois(p);
  229. /* XXX should fail if server[0] < ' ' */
  230. qstring = p; /* XXX leak */
  231. break;
  232. case 0x0B:
  233. p = convert_teredo(qstring);
  234. printf(_("\nQuerying for the IPv4 endpoint %s of a Teredo IPv6 address.\n\n"), p);
  235. server = whichwhois(p);
  236. qstring = p ;
  237. break;
  238. default:
  239. break;
  240. }
  241. if (!server)
  242. return NULL;
  243. p = queryformat(server, fstring, qstring);
  244. if (verb) {
  245. printf(_("Using server %s.\n"), server);
  246. printf(_("Query string: \"%s\"\n\n"), p);
  247. }
  248. sockfd = openconn(server, port);
  249. strcat(p, "\r\n");
  250. server = do_query(sockfd, p);
  251. /* recursion is fun */
  252. if (server) {
  253. printf(_("\n\nFound a referral to %s.\n\n"), server);
  254. handle_query(server, NULL, qstring, fstring);
  255. }
  256. return NULL;
  257. }
  258. #ifdef CONFIG_FILE
  259. const char *match_config_file(const char *s)
  260. {
  261. FILE *fp;
  262. char buf[512];
  263. static const char delim[] = " \t";
  264. if ((fp = fopen(CONFIG_FILE, "r")) == NULL) {
  265. if (errno != ENOENT)
  266. err_sys("Cannot open " CONFIG_FILE);
  267. return NULL;
  268. }
  269. while (fgets(buf, sizeof(buf), fp) != NULL) {
  270. char *p;
  271. const char *pattern, *server;
  272. #ifdef HAVE_REGEXEC
  273. int i;
  274. regex_t re;
  275. #endif
  276. for (p = buf; *p; p++)
  277. if (*p == '\n')
  278. *p = '\0';
  279. p = buf;
  280. while (*p == ' ' || *p == '\t') /* eat leading blanks */
  281. p++;
  282. if (!*p)
  283. continue; /* skip empty lines */
  284. if (*p == '#')
  285. continue; /* skip comments */
  286. pattern = strtok(p, delim);
  287. server = strtok(NULL, delim);
  288. if (!pattern || !server)
  289. err_quit(_("Cannot parse this line: %s"), p);
  290. p = strtok(NULL, delim);
  291. if (p)
  292. err_quit(_("Cannot parse this line: %s"), p);
  293. #ifdef HAVE_REGEXEC
  294. i = regcomp(&re, pattern, REG_EXTENDED|REG_ICASE|REG_NOSUB);
  295. if (i != 0) {
  296. char m[1024];
  297. regerror(i, &re, m, sizeof(m));
  298. err_quit("Invalid regular expression '%s': %s", pattern, m);
  299. }
  300. i = regexec(&re, s, 0, NULL, 0);
  301. if (i == 0) {
  302. regfree(&re);
  303. return strdup(server);
  304. }
  305. if (i != REG_NOMATCH) {
  306. char m[1024];
  307. regerror(i, &re, m, sizeof(m));
  308. err_quit("regexec: %s", m);
  309. }
  310. regfree(&re);
  311. #else
  312. if (domcmp(s, pattern))
  313. return strdup(server);
  314. #endif
  315. }
  316. return NULL;
  317. }
  318. #endif
  319. /* Parses an user-supplied string and tries to guess the right whois server.
  320. * Returns a statically allocated buffer.
  321. */
  322. const char *whichwhois(const char *s)
  323. {
  324. unsigned long ip, as32;
  325. unsigned int i;
  326. const char *colon;
  327. /* IPv6 address */
  328. if ((colon = strchr(s, ':'))) {
  329. unsigned long v6prefix, v6net;
  330. /* RPSL hierarchical objects */
  331. if (strncaseeq(s, "as", 2)) {
  332. if (isasciidigit(s[2]))
  333. return whereas(atoi(s + 2));
  334. else
  335. return "";
  336. }
  337. v6prefix = strtol(s, NULL, 16);
  338. if (v6prefix == 0)
  339. return "\x05"; /* unknown */
  340. v6net = (v6prefix << 16) + strtol(colon + 1, NULL, 16);/* second u16 */
  341. for (i = 0; ip6_assign[i].serv; i++) {
  342. if ((v6net & (~0UL << (32 - ip6_assign[i].masklen)))
  343. == ip6_assign[i].net)
  344. return ip6_assign[i].serv;
  345. }
  346. return "\x06"; /* unknown allocation */
  347. }
  348. /* email address */
  349. if (strchr(s, '@'))
  350. return "\x05";
  351. /* no dot and no hyphen means it's a NSI NIC handle or ASN (?) */
  352. if (!strpbrk(s, ".-")) {
  353. if (strncaseeq(s, "as", 2) && /* it's an AS */
  354. (isasciidigit(s[2]) || s[2] == ' '))
  355. return whereas(atoi(s + 2));
  356. if (*s == '!') /* NSI NIC handle */
  357. return "whois.networksolutions.com";
  358. else
  359. return "\x05"; /* probably a unknown kind of nic handle */
  360. }
  361. /* ASN32? */
  362. if (strncaseeq(s, "as", 2) && s[2] && (as32 = asn32_to_long(s + 2)) != 0)
  363. return whereas32(as32);
  364. /* smells like an IP? */
  365. if ((ip = myinet_aton(s))) {
  366. for (i = 0; ip_assign[i].serv; i++)
  367. if ((ip & ip_assign[i].mask) == ip_assign[i].net)
  368. return ip_assign[i].serv;
  369. return "\x05"; /* not in the unicast IPv4 space */
  370. }
  371. /* check the TLDs list */
  372. for (i = 0; tld_serv[i]; i += 2)
  373. if (domcmp(s, tld_serv[i]))
  374. return tld_serv[i + 1];
  375. /* no dot but hyphen */
  376. if (!strchr(s, '.')) {
  377. /* search for strings at the start of the word */
  378. for (i = 0; nic_handles[i]; i += 2)
  379. if (strncaseeq(s, nic_handles[i], strlen(nic_handles[i])))
  380. return nic_handles[i + 1];
  381. /* it's probably a network name */
  382. return "";
  383. }
  384. /* has dot and maybe a hyphen and it's not in tld_serv[], WTF is it? */
  385. /* either a TLD or a NIC handle we don't know about yet */
  386. return "\x05";
  387. }
  388. const char *whereas32(const unsigned long asn)
  389. {
  390. int i;
  391. for (i = 0; as32_assign[i].serv; i++)
  392. if (asn >= as32_assign[i].first && asn <= as32_assign[i].last)
  393. return as32_assign[i].serv;
  394. return "\x06";
  395. }
  396. const char *whereas(const unsigned short asn)
  397. {
  398. int i;
  399. for (i = 0; as_assign[i].serv; i++)
  400. if (asn >= as_assign[i].first && asn <= as_assign[i].last)
  401. return as_assign[i].serv;
  402. return "\x06";
  403. }
  404. char *queryformat(const char *server, const char *flags, const char *query)
  405. {
  406. char *buf, *p;
  407. int i, isripe = 0;
  408. /* 64 bytes reserved for server-specific flags added later */
  409. buf = malloc(strlen(flags) + strlen(query) + strlen(client_tag) + 64);
  410. *buf = '\0';
  411. for (i = 0; ripe_servers[i]; i++)
  412. if (streq(server, ripe_servers[i])) {
  413. strcat(buf, "-V ");
  414. strcat(buf, client_tag);
  415. strcat(buf, " ");
  416. isripe = 1;
  417. break;
  418. }
  419. if (*flags) {
  420. if (!isripe && !streq(server, "whois.corenic.net"))
  421. puts(_("Warning: RIPE flags used with a traditional server."));
  422. strcat(buf, flags);
  423. }
  424. #ifdef HAVE_LIBIDN
  425. /* why, oh why DENIC had to make whois "user friendly"?
  426. * Do this only if the user did not use any flag.
  427. */
  428. if (streq(server, "whois.denic.de") && domcmp(query, ".de")
  429. && !strchr(query, ' ') && !*flags)
  430. sprintf(buf, "-T dn,ace -C US-ASCII %s", query);
  431. else
  432. /* here we have another registrar who could not make things simple
  433. * -C sets the language for both input and output
  434. */
  435. if (!isripe && streq(server, "whois.cat") && domcmp(query, ".cat")
  436. && !strchr(query, ' '))
  437. sprintf(buf, "-C US-ASCII ace %s", query);
  438. else
  439. #endif
  440. if (!isripe && (streq(server, "whois.nic.mil") ||
  441. streq(server, "whois.nic.ad.jp")) &&
  442. strncaseeq(query, "AS", 2) && isasciidigit(query[2]))
  443. /* FIXME: /e is not applied to .JP ASN */
  444. sprintf(buf, "AS %s", query + 2); /* fix query for DDN */
  445. else if (!isripe && (streq(server, "whois.nic.ad.jp") ||
  446. streq(server, "whois.jprs.jp"))) {
  447. char *lang = getenv("LANG"); /* not a perfect check, but... */
  448. if (!lang || !strneq(lang, "ja", 2))
  449. sprintf(buf, "%s/e", query); /* ask for english text */
  450. else
  451. strcat(buf, query);
  452. } else if (!isripe && streq(server, "whois.arin.net") &&
  453. (p = strrchr(query, '/'))) {
  454. strncat(buf, query, p - query); /* strip CIDR */
  455. } else
  456. strcat(buf, query);
  457. return buf;
  458. }
  459. /* the first parameter contains the state of this simple state machine:
  460. * HIDE_DISABLED: hidden text finished
  461. * HIDE_UNSTARTED: hidden text not seen yet
  462. * >= 0: currently hiding message hide_strings[*hiding]
  463. */
  464. int hide_line(int *hiding, const char *const line)
  465. {
  466. int i;
  467. if (*hiding == HIDE_DISABLED) {
  468. return 0;
  469. } else if (*hiding == HIDE_UNSTARTED) { /* looking for smtng to hide */
  470. for (i = 0; hide_strings[i] != NULL; i += 2) {
  471. if (strneq(line, hide_strings[i], strlen(hide_strings[i]))) {
  472. *hiding = i; /* start hiding */
  473. return 1; /* and hide this line */
  474. }
  475. }
  476. return 0; /* don't hide this line */
  477. } else if (*hiding > HIDE_UNSTARTED) { /* hiding something */
  478. if (*hide_strings[*hiding + 1] == '\0') { /*look for a blank line?*/
  479. if (*line == '\n' || *line == '\r' || *line == '\0') {
  480. *hiding = HIDE_DISABLED; /* stop hiding */
  481. return 0; /* but do not hide the blank line */
  482. }
  483. } else { /*look for a matching string*/
  484. if (strneq(line, hide_strings[*hiding + 1],
  485. strlen(hide_strings[*hiding + 1]))) {
  486. *hiding = HIDE_DISABLED; /* stop hiding */
  487. return 1; /* but hide the last line */
  488. }
  489. }
  490. return 1; /* we are hiding, so do it */
  491. } else
  492. return 0;
  493. }
  494. /* returns a string which should be freed by the caller, or NULL */
  495. const char *do_query(const int sock, const char *query)
  496. {
  497. char buf[2000], *p;
  498. FILE *fi;
  499. int hide = hide_discl;
  500. char *referral_server = NULL;
  501. fi = fdopen(sock, "r");
  502. if (write(sock, query, strlen(query)) < 0)
  503. err_sys("write");
  504. /* Using shutdown used to break the buggy RIPE server. Would this work now?
  505. if (shutdown(sock, 1) < 0)
  506. err_sys("shutdown");
  507. */
  508. while (fgets(buf, sizeof(buf), fi)) {
  509. /* 6bone-style referral:
  510. * % referto: whois -h whois.arin.net -p 43 as 1
  511. */
  512. if (!referral_server && strneq(buf, "% referto:", 10)) {
  513. char nh[256], np[16], nq[1024];
  514. if (sscanf(buf, REFERTO_FORMAT, nh, np, nq) == 3) {
  515. /* XXX we are ignoring the new query string */
  516. referral_server = malloc(300);
  517. sprintf(referral_server, "%s:%s", nh, np);
  518. }
  519. }
  520. /* ARIN referrals:
  521. * ReferralServer: rwhois://rwhois.fuse.net:4321/
  522. * ReferralServer: whois://whois.ripe.net
  523. */
  524. if (!referral_server && strneq(buf, "ReferralServer:", 15)) {
  525. char *q;
  526. q = strstr(buf, "rwhois://");
  527. if ((q = strstr(buf, "rwhois://")))
  528. referral_server = strdup(q + 9);
  529. else if ((q = strstr(buf, "whois://")))
  530. referral_server = strdup(q + 8);
  531. if (referral_server) {
  532. if ((q = strchr(referral_server, '/'))
  533. || (q = strchr(referral_server, '\n')))
  534. *q = '\0';
  535. }
  536. }
  537. if (hide_line(&hide, buf))
  538. continue;
  539. for (p = buf; *p && *p != '\r' && *p != '\n'; p++);
  540. *p = '\0';
  541. fprintf(stdout, "%s\n", buf);
  542. }
  543. if (ferror(fi))
  544. err_sys("fgets");
  545. fclose(fi);
  546. if (hide > HIDE_UNSTARTED)
  547. err_quit(_("Catastrophic error: disclaimer text has been changed.\n"
  548. "Please upgrade this program.\n"));
  549. return referral_server;
  550. }
  551. const char *query_crsnic(const int sock, const char *query)
  552. {
  553. char *temp, buf[2000], *ret = NULL;
  554. FILE *fi;
  555. int hide = hide_discl;
  556. int state = 0;
  557. temp = malloc(strlen(query) + 1 + 2 + 1);
  558. *temp = '=';
  559. strcpy(temp + 1, query);
  560. strcat(temp, "\r\n");
  561. fi = fdopen(sock, "r");
  562. if (write(sock, temp, strlen(temp)) < 0)
  563. err_sys("write");
  564. while (fgets(buf, sizeof(buf), fi)) {
  565. /* If there are multiple matches only the server of the first record
  566. is queried */
  567. if (state == 0 && strneq(buf, " Domain Name:", 15))
  568. state = 1;
  569. if (state == 1 && strneq(buf, " Whois Server:", 16)) {
  570. char *p, *q;
  571. for (p = buf; *p != ':'; p++); /* skip until colon */
  572. for (p++; *p == ' '; p++); /* skip colon and spaces */
  573. ret = malloc(strlen(p) + 1);
  574. for (q = ret; *p != '\n' && *p != '\r' && *p != ' '; *q++ = *p++)
  575. ; /*copy data*/
  576. *q = '\0';
  577. state = 2;
  578. }
  579. /* the output must not be hidden or no data will be shown for
  580. host records and not-existing domains */
  581. if (!hide_line(&hide, buf))
  582. fputs(buf, stdout);
  583. }
  584. if (ferror(fi))
  585. err_sys("fgets");
  586. free(temp);
  587. return ret;
  588. }
  589. const char *query_pir(const int sock, const char *query)
  590. {
  591. char *temp, buf[2000], *ret = NULL;
  592. FILE *fi;
  593. int hide = hide_discl;
  594. int state = 0;
  595. temp = malloc(strlen(query) + 5 + 2 + 1);
  596. strcpy(temp, "FULL ");
  597. strcat(temp, query);
  598. strcat(temp, "\r\n");
  599. fi = fdopen(sock, "r");
  600. if (write(sock, temp, strlen(temp)) < 0)
  601. err_sys("write");
  602. while (fgets(buf, sizeof(buf), fi)) {
  603. /* If there are multiple matches only the server of the first record
  604. is queried */
  605. if (state == 0 &&
  606. strneq(buf, "Registrant Name:SEE SPONSORING REGISTRAR", 40))
  607. state = 1;
  608. if (state == 1 &&
  609. strneq(buf, "Registrant Street1:Whois Server:", 32)) {
  610. char *p, *q;
  611. for (p = buf; *p != ':'; p++); /* skip until colon */
  612. for (p++; *p != ':'; p++); /* skip until 2nd colon */
  613. for (p++; *p == ' '; p++); /* skip colon and spaces */
  614. ret = malloc(strlen(p) + 1);
  615. for (q = ret; *p != '\n' && *p != '\r'; *q++ = *p++); /*copy data*/
  616. *q = '\0';
  617. state = 2;
  618. }
  619. if (!hide_line(&hide, buf))
  620. fputs(buf, stdout);
  621. }
  622. if (ferror(fi))
  623. err_sys("fgets");
  624. free(temp);
  625. return ret;
  626. }
  627. const char *query_afilias(const int sock, const char *query)
  628. {
  629. char *temp, buf[2000], *ret = NULL;
  630. FILE *fi;
  631. int hide = hide_discl;
  632. int state = 0;
  633. temp = malloc(strlen(query) + 2 + 1);
  634. strcpy(temp, query);
  635. strcat(temp, "\r\n");
  636. fi = fdopen(sock, "r");
  637. if (write(sock, temp, strlen(temp)) < 0)
  638. err_sys("write");
  639. while (fgets(buf, sizeof(buf), fi)) {
  640. if (state == 0 && strneq(buf, "Domain Name:", 12))
  641. state = 1;
  642. if (state == 1 && strneq(buf, "Whois Server:", 13)) {
  643. char *p, *q;
  644. for (p = buf; *p != ':'; p++); /* skip until colon */
  645. for (p++; *p == ' '; p++); /* skip colon and spaces */
  646. ret = malloc(strlen(p) + 1);
  647. for (q = ret; *p != '\n' && *p != '\r' && *p != ' '; *q++ = *p++)
  648. ; /*copy data*/
  649. *q = '\0';
  650. }
  651. if (!hide_line(&hide, buf)) {
  652. char *p;
  653. for (p = buf; *p && *p != '\r' && *p != '\n'; p++)
  654. ;
  655. *p = '\0';
  656. fprintf(stdout, "%s\n", buf);
  657. }
  658. }
  659. if (ferror(fi))
  660. err_sys("fgets");
  661. fclose(fi);
  662. if (hide > HIDE_UNSTARTED)
  663. err_quit(_("Catastrophic error: disclaimer text has been changed.\n"
  664. "Please upgrade this program.\n"));
  665. return ret;
  666. }
  667. int openconn(const char *server, const char *port)
  668. {
  669. int fd = -1;
  670. #ifdef HAVE_GETADDRINFO
  671. int err;
  672. struct addrinfo hints, *res, *ai;
  673. #else
  674. struct hostent *hostinfo;
  675. struct servent *servinfo;
  676. struct sockaddr_in saddr;
  677. #endif
  678. alarm(60);
  679. #ifdef HAVE_GETADDRINFO
  680. memset(&hints, 0, sizeof(struct addrinfo));
  681. hints.ai_family = AF_UNSPEC;
  682. hints.ai_socktype = SOCK_STREAM;
  683. hints.ai_flags = AI_IDN;
  684. if ((err = getaddrinfo(server, port ? port : "nicname", &hints, &res)) != 0)
  685. err_quit("getaddrinfo(%s): %s", server, gai_strerror(err));
  686. for (ai = res; ai; ai = ai->ai_next) {
  687. if ((fd = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)
  688. continue; /* ignore */
  689. if (connect(fd, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == 0)
  690. break; /* success */
  691. close(fd);
  692. }
  693. freeaddrinfo(res);
  694. if (!ai)
  695. err_sys("connect");
  696. #else
  697. if ((hostinfo = gethostbyname(server)) == NULL)
  698. err_quit(_("Host %s not found."), server);
  699. if ((fd = socket(PF_INET, SOCK_STREAM, IPPROTO_IP)) < 0)
  700. err_sys("socket");
  701. memset(&saddr, 0, sizeof(saddr));
  702. saddr.sin_addr = *(struct in_addr *) hostinfo->h_addr;
  703. saddr.sin_family = AF_INET;
  704. if (!port) {
  705. saddr.sin_port = htons(43);
  706. } else if ((saddr.sin_port = htons(atoi(port))) == 0) {
  707. if ((servinfo = getservbyname(port, "tcp")) == NULL)
  708. err_quit(_("%s/tcp: unknown service"), port);
  709. saddr.sin_port = servinfo->s_port;
  710. }
  711. if (connect(fd, (struct sockaddr *)&saddr, sizeof(saddr)) < 0)
  712. err_sys("connect");
  713. #endif
  714. /*
  715. * Now we are connected and the query is supposed to complete quickly.
  716. * This will help people who run whois ... | less
  717. */
  718. alarm(0);
  719. return fd;
  720. }
  721. void alarm_handler(int signum)
  722. {
  723. close(sockfd);
  724. err_quit(_("Timeout."));
  725. }
  726. void sighandler(int signum)
  727. {
  728. close(sockfd);
  729. err_quit(_("Interrupted by signal %d..."), signum);
  730. }
  731. /* check if dom ends with tld */
  732. int domcmp(const char *dom, const char *tld)
  733. {
  734. const char *p, *q;
  735. for (p = dom; *p; p++); p--; /* move to the last char */
  736. for (q = tld; *q; q++); q--;
  737. while (p >= dom && q >= tld && tolower(*p) == *q) { /* compare backwards */
  738. if (q == tld) /* start of the second word? */
  739. return 1;
  740. p--; q--;
  741. }
  742. return 0;
  743. }
  744. char *normalize_domain(const char *dom)
  745. {
  746. char *p, *ret;
  747. char *domain_start = NULL;
  748. ret = strdup(dom);
  749. for (p = ret; *p; p++); p--; /* move to the last char */
  750. /* eat trailing dots and blanks */
  751. for (; *p == '.' || *p == ' ' || *p == '\t' || p == ret; p--)
  752. *p = '\0';
  753. #ifdef HAVE_LIBIDN
  754. /* find the start of the last word if there are spaces in the query */
  755. for (p = ret; *p; p++)
  756. if (*p == ' ')
  757. domain_start = p + 1;
  758. if (domain_start) {
  759. char *q, *r;
  760. int prefix_len;
  761. if (idna_to_ascii_lz(domain_start, &q, 0) != IDNA_SUCCESS)
  762. return ret;
  763. /* reassemble the original query in a new buffer */
  764. prefix_len = domain_start - ret;
  765. r = malloc(prefix_len + strlen(q) + 1);
  766. strncpy(r, ret, prefix_len);
  767. r[prefix_len] = '\0';
  768. strcat(r, q);
  769. free(q);
  770. free(ret);
  771. return r;
  772. } else {
  773. char *q;
  774. if (idna_to_ascii_lz(ret, &q, 0) != IDNA_SUCCESS)
  775. return ret;
  776. free(ret);
  777. return q;
  778. }
  779. #else
  780. return ret;
  781. #endif
  782. }
  783. /* server and port have to be freed by the caller */
  784. void split_server_port(const char *const input,
  785. const char **server, const char **port) {
  786. char *p;
  787. if (*input == '[' && (p = strchr(input, ']'))) { /* IPv6 */
  788. char *s;
  789. int len = p - input - 1;
  790. *server = s = malloc(len + 1);
  791. memcpy(s, input + 1, len);
  792. *(s + len) = '\0';
  793. p = strchr(p, ':');
  794. if (p && *(p + 1) != '\0')
  795. *port = strdup(p + 1); /* IPv6 + port */
  796. } else if ((p = strchr(input, ':')) && /* IPv6, no port */
  797. strchr(p + 1, ':')) { /* and no brackets */
  798. *server = strdup(input);
  799. } else if ((p = strchr(input, ':'))) { /* IPv4 + port */
  800. char *s;
  801. int len = p - input;
  802. *server = s = malloc(len + 1);
  803. memcpy(s, input, len);
  804. *(s + len) = '\0';
  805. p++;
  806. if (*p != '\0')
  807. *port = strdup(p);
  808. } else { /* IPv4, no port */
  809. *server = strdup(input);
  810. }
  811. /* change the server name to lower case */
  812. for (p = (char *) *server; *p && *p != '\0'; p++)
  813. *p = tolower(*p);
  814. }
  815. char *convert_6to4(const char *s)
  816. {
  817. char *new = malloc(sizeof("255.255.255.255"));
  818. unsigned int a, b;
  819. if (sscanf(s, "2002:%x:%x:", &a, &b) != 2)
  820. return (char *) "0.0.0.0";
  821. sprintf(new, "%d.%d.%d.%d", a >> 8, a & 0xff, b >> 8, b & 0xff);
  822. return new;
  823. }
  824. char *convert_teredo(const char *s)
  825. {
  826. char *new = malloc(sizeof("255.255.255.255"));
  827. unsigned int a, b;
  828. if (sscanf(s, "2001:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%*[^:]:%x:%x", &a, &b) != 2)
  829. return (char *) "0.0.0.0";
  830. a ^= 0xffff;
  831. b ^= 0xffff;
  832. sprintf(new, "%d.%d.%d.%d", a >> 8, a & 0xff, b >> 8, b & 0xff);
  833. return new;
  834. }
  835. unsigned long myinet_aton(const char *s)
  836. {
  837. unsigned long a, b, c, d;
  838. int elements;
  839. char junk;
  840. if (!s)
  841. return 0;
  842. elements = sscanf(s, "%lu.%lu.%lu.%lu%c", &a, &b, &c, &d, &junk);
  843. if (!(elements == 4 || (elements == 5 && junk == '/')))
  844. return 0;
  845. if (a > 255 || b > 255 || c > 255 || d > 255)
  846. return 0;
  847. return (a << 24) + (b << 16) + (c << 8) + d;
  848. }
  849. unsigned long asn32_to_long(const char *s)
  850. {
  851. unsigned long a, b;
  852. char junk;
  853. if (!s)
  854. return 0;
  855. if (sscanf(s, "%lu.%lu%c", &a, &b, &junk) != 2)
  856. return 0;
  857. if (a > 65535 || b > 65535)
  858. return 0;
  859. return (a << 16) + b;
  860. }
  861. int isasciidigit(const char c) {
  862. return (c >= '0' && c <= '9') ? 1 : 0;
  863. }
  864. /* http://www.ripe.net/ripe/docs/databaseref-manual.html */
  865. void usage(void)
  866. {
  867. fprintf(stderr, _(
  868. "Usage: whois [OPTION]... OBJECT...\n\n"
  869. "-l one level less specific lookup [RPSL only]\n"
  870. "-L find all Less specific matches\n"
  871. "-m find first level more specific matches\n"
  872. "-M find all More specific matches\n"
  873. "-c find the smallest match containing a mnt-irt attribute\n"
  874. "-x exact match [RPSL only]\n"
  875. "-d return DNS reverse delegation objects too [RPSL only]\n"
  876. "-i ATTR[,ATTR]... do an inverse lookup for specified ATTRibutes\n"
  877. "-T TYPE[,TYPE]... only look for objects of TYPE\n"
  878. "-K only primary keys are returned [RPSL only]\n"
  879. "-r turn off recursive lookups for contact information\n"
  880. "-R force to show local copy of the domain object even\n"
  881. " if it contains referral\n"
  882. "-a search all databases\n"
  883. "-s SOURCE[,SOURCE]... search the database from SOURCE\n"
  884. "-g SOURCE:FIRST-LAST find updates from SOURCE from serial FIRST to LAST\n"
  885. "-t TYPE request template for object of TYPE ('all' for a list)\n"
  886. "-v TYPE request verbose template for object of TYPE\n"
  887. "-q [version|sources|types] query specified server info [RPSL only]\n"
  888. "-F fast raw output (implies -r)\n"
  889. "-h HOST connect to server HOST\n"
  890. "-p PORT connect to PORT\n"
  891. "-H hide legal disclaimers\n"
  892. " --verbose explain what is being done\n"
  893. " --help display this help and exit\n"
  894. " --version output version information and exit\n"
  895. ));
  896. exit(0);
  897. }