host.cc 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // host rewritten in C++ using BIND 10 DNS library
  2. #include <arpa/inet.h>
  3. #include <netdb.h> // for getaddrinfo
  4. #include <sys/time.h> // for gettimeofday
  5. #include <sys/socket.h> // networking functions and definitions on FreeBSD
  6. #include <string>
  7. #include <iostream>
  8. #include "dns/buffer.h"
  9. #include "dns/name.h"
  10. #include "dns/message.h"
  11. #include "dns/messagerenderer.h"
  12. #include "dns/rrclass.h"
  13. #include "dns/rrtype.h"
  14. #include "dns/rrset.h"
  15. #include "dns/message.h"
  16. using namespace std;
  17. using namespace isc::dns;
  18. char* dns_type = NULL; // not set, so A, AAAA, MX
  19. std::string server = "127.0.0.1";
  20. int verbose = 0;
  21. int first_time = 1;
  22. bool recursive_bit = true;
  23. struct timeval before_time, after_time;
  24. int
  25. host_lookup(char* name, std::string type)
  26. {
  27. Message msg(Message::RENDER);
  28. msg.setQid(0); // does this matter?
  29. // TODO: add switch for this
  30. msg.setOpcode(Opcode::QUERY());
  31. msg.setRcode(Rcode::NOERROR());
  32. if (recursive_bit) {
  33. msg.setHeaderFlag(MessageFlag::RD()); // set recursive bit
  34. }
  35. msg.addQuestion(Question(Name(name),
  36. RRClass::IN(), // IN class only for now
  37. RRType(type))); // if NULL then:
  38. // terminate called after throwing an instance of 'std::logic_error'
  39. // what(): basic_string::_S_construct NULL not valid
  40. OutputBuffer obuffer(512);
  41. MessageRenderer renderer(obuffer);
  42. msg.toWire(renderer);
  43. struct addrinfo hints, *res;
  44. int e;
  45. memset(&hints, 0, sizeof(hints));
  46. hints.ai_family = AF_UNSPEC;
  47. hints.ai_socktype = SOCK_DGRAM;
  48. hints.ai_flags = 0; // not using AI_NUMERICHOST in case to bootstrap
  49. e = getaddrinfo(server.c_str(), "53", &hints, &res);
  50. if (verbose) {
  51. cout << "Trying \"" << name << "\"\n";
  52. }
  53. if (verbose && first_time) {
  54. // this is only output the first time
  55. first_time = 0;
  56. cout << "Using domain server:\n";
  57. cout << "Name: " << server << "\n";
  58. // TODO: I guess I have to do a lookup to get that address and aliases too
  59. // cout << "Address: " << address << "\n" ; // "#" << port << "\n";
  60. // cout << "Aliases: " << server << "\n";
  61. }
  62. int s = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
  63. if (s < 0) {
  64. cerr << "failed to open socket" << endl;
  65. return (1);
  66. }
  67. if (verbose) {
  68. gettimeofday(&before_time, NULL);
  69. }
  70. sendto(s, obuffer.getData(), obuffer.getLength(), 0, res->ai_addr,
  71. res->ai_addrlen);
  72. struct sockaddr_storage ss;
  73. struct sockaddr* sa;
  74. socklen_t sa_len;
  75. sa_len = sizeof(ss);
  76. sa = static_cast<struct sockaddr*>((void*)&ss);
  77. char recvbuf[4096];
  78. int cc;
  79. if ((cc = recvfrom(s, recvbuf, sizeof(recvbuf), 0, sa, &sa_len)) > 0) {
  80. try {
  81. Message rmsg(Message::PARSE);
  82. InputBuffer ibuffer(recvbuf, cc);
  83. rmsg.fromWire(ibuffer);
  84. if (!verbose) {
  85. for (RRsetIterator it = rmsg.beginSection(Section::ANSWER());
  86. it != rmsg.endSection(Section::ANSWER());
  87. ++it) {
  88. if ((*it)->getType() != RRType::A()) {
  89. continue;
  90. }
  91. RdataIteratorPtr rit = (*it)->getRdataIterator();
  92. for (rit->first(); !rit->isLast(); rit->next()) {
  93. // instead of using my name, maybe use returned label?
  94. cout << name << " has address " <<
  95. (*rit).getCurrent().toText() << endl;
  96. }
  97. }
  98. } else {
  99. gettimeofday(&after_time, NULL);
  100. // HEADER and QUESTION, ANSWER, AUTHORITY, and ADDITIONAL
  101. std::cout << rmsg.toText() << std::endl;
  102. if (before_time.tv_usec > after_time.tv_usec) {
  103. after_time.tv_usec += 1000000;
  104. --after_time.tv_sec;
  105. }
  106. int elapsed_time =
  107. (after_time.tv_sec - before_time.tv_sec)
  108. + ((after_time.tv_usec - before_time.tv_usec))/1000;
  109. // TODO: if NXDOMAIN, host(1) doesn't show HEADER
  110. // Host hsdjkfhksjhdfkj not found: 3(NXDOMAIN)
  111. // TODO: figure out the new libdns way to test if NXDOMAIN
  112. std::cout << "Received " << cc <<
  113. " bytes in " << elapsed_time << " ms\n";
  114. // TODO: " bytes from 127.0.0.1#53 in 0 ms
  115. } //verbose
  116. } catch (const exception& ex) {
  117. std::cerr << "parse failed for " <<
  118. string(name) << "/" << type << ": " << ex.what() << std::endl;
  119. } catch (...) {
  120. std::cerr << "parse failed for " << string(name) << "/" << type;
  121. }
  122. }
  123. freeaddrinfo(res);
  124. return (0);
  125. } // host_lookup()
  126. int
  127. main(int argc, char* argv[])
  128. {
  129. int c;
  130. while ((c = getopt(argc, argv, "rt:v")) != -1)
  131. switch (c) {
  132. case 'r':
  133. recursive_bit = false;
  134. break;
  135. case 't':
  136. dns_type = optarg;
  137. break;
  138. case 'v':
  139. verbose = 1;
  140. break;
  141. }
  142. argc -= optind;
  143. argv += optind;
  144. if (argc < 1) {
  145. cout << "Usage: host [-vr] [-t type] hostname [server]\n";
  146. exit(1);
  147. }
  148. if (argc >= 2) {
  149. server = argv[1];
  150. }
  151. if (!dns_type) {
  152. host_lookup(argv[0], "A");
  153. // TODO: don't do next if A doesn't exist
  154. host_lookup(argv[0], "AAAA");
  155. host_lookup(argv[0], "MX");
  156. } else {
  157. host_lookup(argv[0], dns_type);
  158. }
  159. return (0);
  160. }