You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

ntkresolv.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667
  1. /* This file is part of Netsukuku
  2. *
  3. * This source code is free software; you can redistribute it and/or
  4. * modify it under the terms of the GNU General Public License as published
  5. * by the Free Software Foundation; either version 2 of the License,
  6. * or (at your option) any later version.
  7. *
  8. * This source code is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. * Please refer to the GNU Public License for more details.
  12. *
  13. * You should have received a copy of the GNU Public License along with
  14. * this source code; if not, write to:
  15. * Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  16. *
  17. */
  18. #include <netinet/in.h>
  19. #include "includes.h"
  20. #include "ntkresolv.h"
  21. #include "andns_net.h"
  22. #include "snsd_cache.h"
  23. #include "crypto.h"
  24. #include "common.h"
  25. static ntkresolv_opts globopts;
  26. static struct timeval time_start, time_stop;
  27. uint8_t mode_compute_hash = 0;
  28. uint8_t mode_parsable_output = 0;
  29. void
  30. version(void)
  31. {
  32. say("ntk-resolv version %s (Netsukuku tools)\n\n"
  33. "Copyright (C) 2006.\n"
  34. "This is free software. You may redistribute copies of it under the terms of\n"
  35. "the GNU General Public License <http://www.gnu.org/licenses/gpl.html>.\n"
  36. "There is NO WARRANTY, to the extent permitted by law.\n\n"
  37. "Report bugs and ideas to <%s>.\n", VERSION, NTK_RESOLV_MAIL_BUGS);
  38. ntkresolv_safe_exit(1);
  39. }
  40. void
  41. usage(void)
  42. {
  43. say("Usage:\n"
  44. "\tntk-resolv [OPTIONS] host\n"
  45. "\tntk-resolv -H host\n\n"
  46. " -v --version print version, then exit.\n"
  47. " -n --nameserver=ns use nameserver `ns' instead of localhost.\n"
  48. " -P --port=port nameserver port, default 53.\n"
  49. " -t --query-type=qt query type (`-t help' shows more info).\n"
  50. " -r --realm=realm realm to scan (`-r help' shows more info).\n"
  51. " -s --service=service SNSD service (`-s help' shows more info).\n"
  52. " -p --protocolo=proto SNSD protocol (`-p help' shows more info).\n"
  53. " -S --silent ntk-resolv will be not loquacious.\n"
  54. " -b --block-recursion set recursion OFF.\n"
  55. " -m --md5-hash hostname specified is hash-ed.\n"
  56. " -H --compute-hash print the hash'ed hostname.\n"
  57. " -l --parsable-output print answers in a synthetic way.\n"
  58. " -h --help display this help, then exit.\n\n"
  59. "Report bugs and ideas to <%s>.\n", NTK_RESOLV_MAIL_BUGS);
  60. ntkresolv_safe_exit(1);
  61. }
  62. void
  63. qt_usage(char *arg)
  64. {
  65. if (arg)
  66. say("Bad Query Type %s\n\n", arg);
  67. else
  68. say("ntk-resolv Query Type Help.\n\n");
  69. say("Valid query types are:\n"
  70. " * snsd\t\thost:port -> ip\n"
  71. " ptr\t\tip -> host\n"
  72. " global\thostname -> all services ip\n"
  73. " mx\t\thostname MX -> ip\n\n"
  74. "(you can also use univoque abbreviation)\n"
  75. "Note: mx query is equivalent to --query-type="
  76. "snsd AND --service=25\n\n");
  77. ntkresolv_safe_exit(1);
  78. }
  79. void
  80. realm_usage(char *arg)
  81. {
  82. if (arg)
  83. say("Bad Realm %s\n\n", arg);
  84. else
  85. say("ntk-resolv Realm Help.\n\n");
  86. say("Valid realms are:\n"
  87. " * ntk\tnetsukuku realm\n"
  88. " inet\tinternet realm\n\n"
  89. "(you can also use univoque abbreviation)\n\n");
  90. ntkresolv_safe_exit(1);
  91. }
  92. void
  93. proto_usage(char *arg)
  94. {
  95. if (arg)
  96. say("Bad Protocol %s\n\n", arg);
  97. else
  98. say("ntk-resolv Protocol Help.\n\n");
  99. say("Valid protocols are:\n"
  100. " * tcp\n"
  101. " udp\n"
  102. "(you can also use univoque abbreviation)\n"
  103. "Note: you can also specify the protocol with option `-s'.\n"
  104. "To know more, type:\n" "\tntk-resolv -s help\n\n");
  105. ntkresolv_safe_exit(1);
  106. }
  107. void
  108. service_and_proto_usage(char *arg)
  109. {
  110. if (arg)
  111. say("Bad service/proto %s\n\n"
  112. "Use `ntk-resolv -s help` for more info on"
  113. " service and proto.\n", arg);
  114. else
  115. say("ntk-resolv Service and Proto Help.\n\n"
  116. "The form to specify a service and a protocol are:\n"
  117. " ntk-resolv -s service/proto\n"
  118. " ntk-resolv -s service -p proto\n\n"
  119. "Valid protocols are:\n"
  120. " * tcp\n"
  121. " udp\n\n"
  122. "Valid services are expressed in /etc/services.\n"
  123. "You can use numeric form too.\n\n"
  124. "As example, the next commands are equivalent and\n"
  125. "will return the IP of the hostname that offers\n"
  126. "webpages for the hostname \"some_hostname\":\n\n"
  127. " ntk-resolv -s http -p tcp some_hostname\n"
  128. " ntk-resolv -s http/tcp some_hostname\n"
  129. " ntk-resolv -s 80/tcp some_hostname\n"
  130. " ntk-resolv -s 80 some_hostname\n\n");
  131. ntkresolv_safe_exit(1);
  132. }
  133. double
  134. diff_time(struct timeval a, struct timeval b)
  135. {
  136. double res;
  137. res = (double) (b.tv_sec - a.tv_sec);
  138. if (res < 0.9 || b.tv_usec >= a.tv_usec)
  139. res += (b.tv_usec - a.tv_usec) / TIME_SCALE;
  140. else {
  141. res -= 1.0;
  142. res += (TIME_SCALE + b.tv_usec - a.tv_usec) / TIME_SCALE;
  143. }
  144. return res;
  145. }
  146. void
  147. opts_init(void)
  148. {
  149. memset(&GOP, 0, NTKRESOLV_OPTS_SZ);
  150. strcpy(GOP.nsserver, LOCALHOST);
  151. GOP.port = NTKRESOLV_PORT;
  152. GQT = create_andns_pkt();
  153. GQT->nk = REALM_NTK;
  154. GQT->p = SNSD_PROTO_DEFAULT;
  155. GQT->service = SNSD_SERVICE_DEFAULT;
  156. GQT->r = 1;
  157. xsrand();
  158. }
  159. void
  160. opts_set_silent(void)
  161. {
  162. GOP.silent = 1;
  163. }
  164. void
  165. opts_set_port(char *arg)
  166. {
  167. int res;
  168. uint16_t port;
  169. res = atoi(arg);
  170. port = (uint16_t) res;
  171. if (port != res) {
  172. say("Bad port %s.", arg);
  173. ntkresolv_safe_exit(1);
  174. }
  175. GOP.port = port;
  176. }
  177. void
  178. opts_set_ns(char *arg)
  179. {
  180. int slen;
  181. slen = strlen(arg);
  182. if (slen >= MAX_HOSTNAME_LEN) {
  183. say("Server hostname too long.");
  184. ntkresolv_safe_exit(1);
  185. }
  186. strcpy(GOP.nsserver, arg);
  187. GOP.nsserver[slen] = 0;
  188. }
  189. void
  190. opts_set_qt(char *arg)
  191. {
  192. int res;
  193. if (!strcmp(arg, HELP_STR))
  194. qt_usage(NULL);
  195. res = QTFROMPREF(arg);
  196. if (res == -1)
  197. qt_usage(arg);
  198. if (res == QTYPE_MX) {
  199. GQT->qtype = QTYPE_A;
  200. GQT->service = 25;
  201. GQT->p = SNSD_PROTO_TCP;
  202. } else
  203. GQT->qtype = res;
  204. }
  205. void
  206. opts_set_realm(char *arg)
  207. {
  208. uint8_t res;
  209. if (!strcmp(arg, HELP_STR))
  210. realm_usage(NULL);
  211. res = REALMFROMPREF(arg);
  212. if (!res)
  213. realm_usage(arg);
  214. GQT->nk = res;
  215. }
  216. void
  217. opts_set_service_and_proto(char *arg)
  218. {
  219. int ret;
  220. if (!strcmp(arg, HELP_STR))
  221. service_and_proto_usage(NULL);
  222. ret = str_to_snsd_service(arg, (int *) &GQT->service, &GQT->p);
  223. /* if(ret == -1)
  224. say("Bad service %s.",arg);
  225. else if(ret == -2)
  226. proto_usage(arg);*/
  227. if (ret < 0)
  228. service_and_proto_usage(arg);
  229. GQT->p -= 1;
  230. }
  231. void
  232. opts_set_proto(char *arg)
  233. {
  234. int ret;
  235. if (!strcmp(arg, HELP_STR))
  236. proto_usage(NULL);
  237. ret = PROTOFROMPREF(arg);
  238. if (ret < 0)
  239. proto_usage(arg);
  240. GQT->p = ret;
  241. }
  242. /* This is a complex set of function. */
  243. void
  244. opts_set_recursion(void)
  245. {
  246. GQT->r = 0;
  247. }
  248. void
  249. opts_set_hash(void)
  250. {
  251. GOP.hash = 1;
  252. }
  253. void
  254. opts_set_compute_hash(void)
  255. {
  256. mode_compute_hash = 1;
  257. }
  258. void
  259. opts_set_parsable_output(void)
  260. {
  261. mode_parsable_output = 1;
  262. AMISILENT = 1;
  263. }
  264. void
  265. opts_set_question(char *arg)
  266. {
  267. struct in_addr ia;
  268. struct in6_addr i6a;
  269. int res;
  270. strcpy(GOP.obj, arg);
  271. res = strlen(arg);
  272. switch (GQT->qtype) {
  273. case QTYPE_A:
  274. if (GQT->nk == REALM_NTK) {
  275. G_ALIGN(ANDNS_HASH_H);
  276. if (GOP.hash) {
  277. if (res != 2 * ANDNS_HASH_H) {
  278. say("Malformed Hostname hash `%s'.\n", arg);
  279. ntkresolv_safe_exit(1);
  280. }
  281. NTK_RESOLV_STR_HASH(arg, GQT->qstdata);
  282. } else
  283. hash_md5((unsigned char *) arg, res,
  284. (unsigned char *) GQT->qstdata);
  285. } else {
  286. if (res > 255) {
  287. say("Hostname %s is too long for DNS standard.", arg);
  288. ntkresolv_safe_exit(1);
  289. }
  290. G_ALIGN(res);
  291. strcpy(GQT->qstdata, arg);
  292. }
  293. return;
  294. case QTYPE_PTR:
  295. res = inet_pton(AF_INET, arg, &ia);
  296. if (res) {
  297. G_ALIGN(ANDNS_HASH_H);
  298. memcpy(GQT->qstdata, &ia.s_addr, 4);
  299. return;
  300. }
  301. res = inet_pton(AF_INET6, arg, &i6a);
  302. if (!res) {
  303. say("Bad address `%s'\n", arg);
  304. ntkresolv_safe_exit(1);
  305. }
  306. G_ALIGN(16);
  307. memcpy(GQT->qstdata, &i6a.s6_addr16, 16);
  308. GQT->ipv = ANDNS_IPV6;
  309. return;
  310. case QTYPE_G:
  311. if (GQT->nk != REALM_NTK) {
  312. say("Global query type is valid only for the Ntk realm.");
  313. ntkresolv_safe_exit(1);
  314. }
  315. G_ALIGN(ANDNS_HASH_H);
  316. if (GOP.hash)
  317. NTK_RESOLV_STR_HASH(arg, GQT->qstdata);
  318. else
  319. hash_md5((unsigned char *) arg, res,
  320. (unsigned char *) GQT->qstdata);
  321. return;
  322. default:
  323. say("Unknow Query Type.\n");
  324. return;
  325. }
  326. }
  327. void
  328. opts_finish(char *arg)
  329. {
  330. int r;
  331. r = strlen(arg);
  332. if (r > NTKRESOLV_MAX_OBJ_LEN) {
  333. say("Object requested is too long: %s", arg);
  334. ntkresolv_safe_exit(1);
  335. }
  336. if (mode_compute_hash) { /* Do command here and exit */
  337. G_ALIGN(ANDNS_HASH_H);
  338. hash_md5((unsigned char *) arg, r, (unsigned char *) GQT->qstdata);
  339. NTK_RESOLV_HASH_STR(GQT->qstdata, GOP.obj);
  340. say("%s\n", GOP.obj);
  341. ntkresolv_safe_exit(0);
  342. }
  343. if (GOP.hash && GQT->qtype == AT_PTR) {
  344. say("Option `-m' is not usable with inverse queries.\n");
  345. ntkresolv_safe_exit(1);
  346. }
  347. r = rand();
  348. GQT->id = r >> 16;
  349. opts_set_question(arg);
  350. }
  351. void
  352. print_headers()
  353. {
  354. andns_pkt *ap = GQT;
  355. say("\n - Headers Section:\n"
  356. "\tid ~ %6d\tqr ~ %4d\tqtype ~ %7s\n"
  357. "\tan ~ %6d\tipv ~ %s\trealm ~ %7s\n"
  358. "\tsv ~ %6s\tprt ~ %4s\trCode ~ %s\n"
  359. "\trc ~ %6d\n",
  360. ap->id, ap->qr, QTYPE_STR(ap),
  361. ap->ancount, IPV_STR(ap), NK_STR(ap),
  362. SERVICE_STR(ap), PROTO_STR(ap), RCODE_STR(ap), ap->r);
  363. }
  364. void
  365. print_question()
  366. {
  367. say("\n - Question Section:\n" "\tObj ~ %s\n", GOP.obj);
  368. }
  369. void
  370. ip_bin_to_str(void *data, char *dst)
  371. {
  372. int family;
  373. struct in_addr ia;
  374. struct in6_addr i6a;
  375. const void *via;
  376. const char *crow;
  377. family = GQT->ipv == ANDNS_IPV4 ? AF_INET : AF_INET6;
  378. switch (family) {
  379. case AF_INET:
  380. memcpy(&(ia.s_addr), data, 4);
  381. via = (void *) (&ia);
  382. break;
  383. case AF_INET6:
  384. memcpy(&(i6a.s6_addr16), data, 16);
  385. via = (void *) (&i6a);
  386. break;
  387. default:
  388. strcpy(dst, "Unprintable Object");
  389. return;
  390. }
  391. crow = inet_ntop(family, via, dst, NTKRESOLV_MAX_OBJ_LEN);
  392. if (!crow)
  393. strcpy(dst, "Unprintable Object");
  394. }
  395. void
  396. answer_data_to_str(andns_pkt_data * apd, char *dst)
  397. {
  398. if (GQT->qtype == AT_PTR)
  399. strcpy(dst, apd->rdata);
  400. else if (GQT->qtype == AT_G || GQT->qtype == AT_A) {
  401. if (apd->m & APD_IP)
  402. ip_bin_to_str(apd->rdata, dst);
  403. else
  404. NTK_RESOLV_HASH_STR(apd->rdata, dst);
  405. } else
  406. strcpy(dst, "Unprintable Object");
  407. }
  408. void
  409. print_answers()
  410. {
  411. int i = 0;
  412. int ancount = GQT->ancount;
  413. andns_pkt_data *apd;
  414. if (!ancount)
  415. return;
  416. say("\n - Answers Section:\n");
  417. apd = GQT->pkt_answ;
  418. while (apd) {
  419. i++;
  420. if (i > ancount)
  421. say("Answer not declared in Headers Packet.\n");
  422. answer_data_to_str(apd, GOP.obj);
  423. say("\t ~ %s", GOP.obj);
  424. if (apd->m & APD_MAIN_IP)
  425. say(" *");
  426. else if (GQT->qtype != AT_PTR && !(apd->m & APD_IP) && GQT->r)
  427. say("\t + Recursion Failed");
  428. say("\n");
  429. if (GQT->qtype == AT_A || GQT->qtype == AT_G)
  430. say("\t\tPrio ~ %d Weigth ~ %d\n", apd->prio, apd->wg);
  431. if (GQT->qtype == AT_G)
  432. say("\t\tService ~ %d Proto ~ %s\n",
  433. apd->service, apd->m & APD_UDP ? "udp" : "tcp");
  434. say("\n");
  435. apd = apd->next;
  436. }
  437. }
  438. void
  439. print_parsable_answers(void)
  440. {
  441. int i = 0;
  442. int ancount = GQT->ancount;
  443. andns_pkt_data *apd;
  444. if (!ancount)
  445. return;
  446. apd = GQT->pkt_answ;
  447. while (apd) {
  448. i++;
  449. if (i > ancount)
  450. say("Answer not declared in Headers Packet.\n");
  451. answer_data_to_str(apd, GOP.obj);
  452. if (GQT->qtype == AT_PTR || (GQT->qtype == AT_A && !GQT->service))
  453. say("%s %s\n", NTK_RESOLV_SYMBOL(apd), GOP.obj);
  454. else if (GQT->qtype == AT_A)
  455. say("%s %s %d %d\n", NTK_RESOLV_SYMBOL(apd),
  456. GOP.obj, apd->prio, apd->wg);
  457. else
  458. say("%s %s %d %s %d %d\n", NTK_RESOLV_SYMBOL(apd),
  459. GOP.obj, apd->service,
  460. apd->m & APD_UDP ? "udp" : "tcp", apd->prio, apd->wg);
  461. apd = apd->next;
  462. }
  463. }
  464. void
  465. print_results(void)
  466. {
  467. if (!AMISILENT) {
  468. print_headers();
  469. print_question();
  470. }
  471. if (mode_parsable_output)
  472. print_parsable_answers();
  473. else
  474. print_answers();
  475. }
  476. void
  477. do_command(void)
  478. {
  479. char buf[ANDNS_MAX_SZ];
  480. char answer[ANDNS_MAX_PK_LEN];
  481. int res;
  482. memset(buf, 0, ANDNS_MAX_SZ);
  483. GOP.id = GQT->id;
  484. res = a_p(GQT, buf);
  485. if (res == -1) {
  486. say("Error building question.\n");
  487. ntkresolv_exit(1);
  488. }
  489. res = hn_send_recv_close(GOP.nsserver, GOP.port,
  490. SOCK_DGRAM, buf, res, answer,
  491. ANDNS_MAX_PK_LEN, 0, NTK_RESOLV_TIMEOUT);
  492. if (res == -1) {
  493. say("Communication failed with %s.\n", GOP.nsserver);
  494. ntkresolv_exit(1);
  495. }
  496. if (res == -2) {
  497. say("Unable to send() to %s.\n", GOP.nsserver);
  498. ntkresolv_exit(1);
  499. }
  500. if (res == -3) {
  501. say("Unable to recv() from %s.\n", GOP.nsserver);
  502. ntkresolv_exit(1);
  503. }
  504. res = a_u(answer, res, &GQT);
  505. if (res <= 0) {
  506. say("Error interpreting server answer.\n");
  507. ntkresolv_exit(1);
  508. }
  509. if (GQT->id != GOP.id)
  510. say("Warning: ID query (%d) is mismatching ID answer (%d)!\n",
  511. GOP.id, GQT->id);
  512. print_results();
  513. destroy_andns_pkt(GQT);
  514. }
  515. void
  516. ntkresolv_exit(int i)
  517. {
  518. exit(i);
  519. }
  520. void
  521. ntkresolv_safe_exit(int i)
  522. {
  523. destroy_andns_pkt(GQT);
  524. ntkresolv_exit(i);
  525. }
  526. int
  527. main(int argc, char **argv)
  528. {
  529. int c;
  530. extern int optind, opterr, optopt;
  531. extern char *optarg;
  532. log_init("", 0, 1);
  533. gettimeofday(&time_start, NULL);
  534. opts_init();
  535. struct option longopts[] = {
  536. {"version", 0, 0, 'v'},
  537. {"nameserver", 1, 0, 'n'},
  538. {"port", 1, 0, 'P'},
  539. {"query-type", 1, 0, 't'},
  540. {"realm", 1, 0, 'r'},
  541. {"service", 1, 0, 's'},
  542. {"proto", 1, 0, 'p'},
  543. {"silent", 0, 0, 'S'},
  544. {"block-recursion", 0, 0, 'b'},
  545. {"md5-hash", 0, 0, 'm'},
  546. {"compute-hash", 0, 0, 'H'},
  547. {"parsable-output", 0, 0, 'l'},
  548. {"help", 0, 0, 'h'},
  549. {0, 0, 0, 0}
  550. };
  551. while (1) {
  552. int oindex = 0;
  553. c = getopt_long(argc, argv,
  554. "vn:P:t:r:s:p:ShbmHl", longopts, &oindex);
  555. if (c == -1)
  556. break;
  557. switch (c) {
  558. case 'v':
  559. version();
  560. case 'n':
  561. opts_set_ns(optarg);
  562. break;
  563. case 'P':
  564. opts_set_port(optarg);
  565. break;
  566. case 't':
  567. opts_set_qt(optarg);
  568. break;
  569. case 'r':
  570. opts_set_realm(optarg);
  571. break;
  572. case 's':
  573. opts_set_service_and_proto(optarg);
  574. break;
  575. case 'p':
  576. opts_set_proto(optarg);
  577. break;
  578. case 'h':
  579. usage();
  580. case 'S':
  581. opts_set_silent();
  582. break;
  583. case 'b':
  584. opts_set_recursion();
  585. break;
  586. case 'm':
  587. opts_set_hash();
  588. break;
  589. case 'H':
  590. opts_set_compute_hash();
  591. break;
  592. case 'l':
  593. opts_set_parsable_output();
  594. break;
  595. default:
  596. usage();
  597. }
  598. }
  599. if (optind == argc)
  600. usage();
  601. opts_finish(argv[optind]);
  602. do_command();
  603. time_report;
  604. bye;
  605. return 0;
  606. }