host.cc 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. // Copyright (C) 2010 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. // host rewritten in C++ using BIND 10 DNS library
  15. #include <arpa/inet.h>
  16. #include <netdb.h> // for getaddrinfo
  17. #include <sys/time.h> // for gettimeofday
  18. #include <sys/socket.h> // networking functions and definitions on FreeBSD
  19. #include <unistd.h>
  20. #include <string>
  21. #include <iostream>
  22. #include <dns/buffer.h>
  23. #include <dns/name.h>
  24. #include <dns/message.h>
  25. #include <dns/messagerenderer.h>
  26. #include <dns/opcode.h>
  27. #include <dns/rcode.h>
  28. #include <dns/rrclass.h>
  29. #include <dns/rrtype.h>
  30. #include <dns/rrset.h>
  31. #include <dns/message.h>
  32. using namespace std;
  33. using namespace isc::dns;
  34. namespace {
  35. char* dns_type = NULL; // not set, so A, AAAA, MX
  36. const char* server = "127.0.0.1";
  37. const char* server_port = "53";
  38. int verbose = 0;
  39. int first_time = 1;
  40. bool recursive_bit = true;
  41. struct timeval before_time, after_time;
  42. int
  43. host_lookup(const char* const name, const char* const type) {
  44. Message msg(Message::RENDER);
  45. msg.setQid(0); // does this matter?
  46. // TODO: add switch for this
  47. msg.setOpcode(Opcode::QUERY());
  48. msg.setRcode(Rcode::NOERROR());
  49. if (recursive_bit) {
  50. msg.setHeaderFlag(Message::HEADERFLAG_RD); // set recursive bit
  51. }
  52. msg.addQuestion(Question(Name(name),
  53. RRClass::IN(), // IN class only for now
  54. RRType(type))); // if NULL then:
  55. OutputBuffer obuffer(512);
  56. MessageRenderer renderer(obuffer);
  57. msg.toWire(renderer);
  58. struct addrinfo hints, *res;
  59. int e;
  60. memset(&hints, 0, sizeof(hints));
  61. hints.ai_family = AF_UNSPEC;
  62. hints.ai_socktype = SOCK_DGRAM;
  63. hints.ai_flags = 0; // not using AI_NUMERICHOST in case to bootstrap
  64. e = getaddrinfo(server, server_port, &hints, &res);
  65. if (verbose) {
  66. cout << "Trying \"" << name << "\"\n";
  67. }
  68. if (verbose && first_time) {
  69. // this is only output the first time
  70. first_time = 0;
  71. cout << "Using domain server:\n";
  72. cout << "Name: " << server << "\n";
  73. // TODO: I guess I have to do a lookup to get that address and aliases
  74. // too
  75. //cout << "Address: " << address << "\n" ; // "#" << port << "\n";
  76. //cout << "Aliases: " << server << "\n";
  77. }
  78. int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  79. if (s < 0) {
  80. cerr << "failed to open socket" << endl;
  81. return (1);
  82. }
  83. if (verbose) {
  84. gettimeofday(&before_time, NULL);
  85. }
  86. sendto(s, obuffer.getData(), obuffer.getLength(), 0, res->ai_addr,
  87. res->ai_addrlen);
  88. struct sockaddr_storage ss;
  89. struct sockaddr* sa;
  90. socklen_t sa_len;
  91. sa_len = sizeof(ss);
  92. sa = static_cast<struct sockaddr*>((void*)&ss);
  93. char recvbuf[4096];
  94. int cc;
  95. if ((cc = recvfrom(s, recvbuf, sizeof(recvbuf), 0, sa, &sa_len)) > 0) {
  96. try {
  97. Message rmsg(Message::PARSE);
  98. InputBuffer ibuffer(recvbuf, cc);
  99. rmsg.fromWire(ibuffer);
  100. if (!verbose) {
  101. for (RRsetIterator it =
  102. rmsg.beginSection(Message::SECTION_ANSWER);
  103. it != rmsg.endSection(Message::SECTION_ANSWER);
  104. ++it) {
  105. if ((*it)->getType() != RRType::A()) {
  106. continue;
  107. }
  108. RdataIteratorPtr rit = (*it)->getRdataIterator();
  109. for (rit->first(); !rit->isLast(); rit->next()) {
  110. // instead of using my name, maybe use returned label?
  111. cout << name << " has address " <<
  112. (*rit).getCurrent().toText() << endl;
  113. }
  114. }
  115. } else {
  116. gettimeofday(&after_time, NULL);
  117. // HEADER and QUESTION, ANSWER, AUTHORITY, and ADDITIONAL
  118. std::cout << rmsg.toText() << std::endl;
  119. if (before_time.tv_usec > after_time.tv_usec) {
  120. after_time.tv_usec += 1000000;
  121. --after_time.tv_sec;
  122. }
  123. int elapsed_time =
  124. (after_time.tv_sec - before_time.tv_sec)
  125. + ((after_time.tv_usec - before_time.tv_usec))/1000;
  126. // TODO: if NXDOMAIN, host(1) doesn't show HEADER
  127. // Host hsdjkfhksjhdfkj not found: 3(NXDOMAIN)
  128. // TODO: figure out the new libdns way to test if NXDOMAIN
  129. std::cout << "Received " << cc <<
  130. " bytes in " << elapsed_time << " ms\n";
  131. // TODO: " bytes from 127.0.0.1#53 in 0 ms
  132. } //verbose
  133. } catch (const exception& ex) {
  134. std::cerr << "parse failed for " <<
  135. string(name) << "/" << type << ": " << ex.what() << std::endl;
  136. } catch (...) {
  137. std::cerr << "parse failed for " << string(name) << "/" << type;
  138. }
  139. }
  140. freeaddrinfo(res);
  141. return (0);
  142. } // host_lookup()
  143. }
  144. int
  145. main(int argc, char* argv[]) {
  146. int c;
  147. while ((c = getopt(argc, argv, "p:rt:v")) != -1)
  148. switch (c) {
  149. case 'r':
  150. recursive_bit = false;
  151. break;
  152. case 't':
  153. dns_type = optarg;
  154. break;
  155. case 'p':
  156. server_port = optarg;
  157. break;
  158. case 'v':
  159. verbose = 1;
  160. break;
  161. }
  162. argc -= optind;
  163. argv += optind;
  164. if (argc < 1) {
  165. cout << "Usage: host [-vr] [-t type] hostname [server]\n";
  166. exit(1);
  167. }
  168. if (argc >= 2) {
  169. server = argv[1];
  170. }
  171. if (dns_type == NULL) {
  172. host_lookup(argv[0], "A");
  173. // TODO: don't do next if A doesn't exist
  174. host_lookup(argv[0], "AAAA");
  175. host_lookup(argv[0], "MX");
  176. } else {
  177. host_lookup(argv[0], dns_type);
  178. }
  179. return (0);
  180. }