scan.cc 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283
  1. // Copyright (C) 2011 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. #include <iostream>
  15. #include <iomanip>
  16. #include <sstream>
  17. #include <string>
  18. #include <boost/scoped_ptr.hpp>
  19. #include <asio.hpp>
  20. #include <asiolink/io_address.h>
  21. #include <asiolink/io_fetch.h>
  22. #include <dns/buffer.h>
  23. #include <dns/message.h>
  24. #include <dns/messagerenderer.h>
  25. #include <dns/opcode.h>
  26. #include <dns/question.h>
  27. #include <dns/rcode.h>
  28. #include <dns/rrclass.h>
  29. #include <dns/rrtype.h>
  30. #include <log/strutil.h>
  31. #include "command_options.h"
  32. #include "header_flags.h"
  33. #include "scan.h"
  34. using namespace std;
  35. using namespace asiolink;
  36. using namespace isc::dns;
  37. using namespace isc::strutil;
  38. namespace isc {
  39. namespace badpacket {
  40. // Perform the scan from start to end on a single question.
  41. void
  42. Scan::scan(const CommandOptions& options) {
  43. // Create the message buffer to use
  44. Message message(Message::RENDER);
  45. message.setOpcode(Opcode::QUERY());
  46. message.setRcode(Rcode::NOERROR());
  47. message.addQuestion(Question(Name(options.getQname()), RRClass::IN(),
  48. RRType::A()));
  49. OutputBufferPtr msgbuf(new OutputBuffer(512));
  50. MessageRenderer renderer(*msgbuf);
  51. message.toWire(renderer);
  52. iterateFlagsFields(msgbuf, options);
  53. }
  54. // Iterate through the various settings in the flags fields
  55. void
  56. Scan::iterateFlagsFields(OutputBufferPtr& msgbuf, const CommandOptions& options) {
  57. // Loop through the flags setting data. This is quite deep nesting,
  58. // but we will continue to indent so as to make things clear (for those
  59. // readers lucky enough to have a wide screen).
  60. HeaderFlags flags;
  61. for (uint32_t qr = options.minimum(OptionInfo::QR);
  62. qr <= options.maximum(OptionInfo::QR); ++qr) {
  63. flags.set(OptionInfo::QR, qr);
  64. for (uint32_t op = options.minimum(OptionInfo::OP);
  65. op <= options.maximum(OptionInfo::OP); ++op) {
  66. flags.set(OptionInfo::OP, op);
  67. for (uint32_t aa = options.minimum(OptionInfo::AA);
  68. aa <= options.maximum(OptionInfo::AA); ++aa) {
  69. flags.set(OptionInfo::AA, aa);
  70. for (uint32_t tc = options.minimum(OptionInfo::TC);
  71. tc <= options.maximum(OptionInfo::TC); ++tc) {
  72. flags.set(OptionInfo::TC, tc);
  73. for (uint32_t rd = options.minimum(OptionInfo::RD);
  74. rd <= options.maximum(OptionInfo::RD); ++rd) {
  75. flags.set(OptionInfo::RD, rd);
  76. for (uint32_t ra = options.minimum(OptionInfo::RA);
  77. ra <= options.maximum(OptionInfo::RA); ++ra) {
  78. flags.set(OptionInfo::RA, ra);
  79. for (uint32_t z = options.minimum(OptionInfo::Z);
  80. z <= options.maximum(OptionInfo::Z); ++z) {
  81. flags.set(OptionInfo::Z, z);
  82. for (uint32_t ad = options.minimum(OptionInfo::AD);
  83. ad <= options.maximum(OptionInfo::AD); ++ad) {
  84. flags.set(OptionInfo::AD, ad);
  85. for (uint32_t cd = options.minimum(OptionInfo::CD);
  86. cd <= options.maximum(OptionInfo::CD); ++cd) {
  87. flags.set(OptionInfo::CD, cd);
  88. for (uint32_t rc = options.minimum(OptionInfo::RC);
  89. rc <= options.maximum(OptionInfo::RC); ++rc) {
  90. flags.set(OptionInfo::RC, rc);
  91. // Set the flags in the message.
  92. msgbuf->writeUint16At(flags.getValue(), 2);
  93. // And for this flag combination, iterate over the section
  94. // count fields.
  95. iterateCountFields(msgbuf, options);
  96. }
  97. }
  98. }
  99. }
  100. }
  101. }
  102. }
  103. }
  104. }
  105. }
  106. }
  107. // Iterate through the various count fields
  108. void
  109. Scan::iterateCountFields(OutputBufferPtr& msgbuf, const CommandOptions& options) {
  110. for (uint32_t qc = options.minimum(OptionInfo::QC);
  111. qc <= options.maximum(OptionInfo::QC); ++qc) {
  112. msgbuf->writeUint16At(qc, OptionInfo::word(OptionInfo::QC));
  113. for (uint32_t ac = options.minimum(OptionInfo::AC);
  114. ac <= options.maximum(OptionInfo::AC); ++ac) {
  115. msgbuf->writeUint16At(ac, OptionInfo::word(OptionInfo::AC));
  116. for (uint32_t uc = options.minimum(OptionInfo::UC);
  117. uc <= options.maximum(OptionInfo::UC); ++uc) {
  118. msgbuf->writeUint16At(uc, OptionInfo::word(OptionInfo::UC));
  119. for (uint32_t dc = options.minimum(OptionInfo::DC);
  120. dc <= options.maximum(OptionInfo::DC); ++dc) {
  121. msgbuf->writeUint16At(dc, OptionInfo::word(OptionInfo::DC));
  122. // Do the I/O.
  123. scanOne(msgbuf, options);
  124. }
  125. }
  126. }
  127. }
  128. }
  129. // Perform the message exchange for a single combination command options.
  130. void
  131. Scan::scanOne(isc::dns::OutputBufferPtr& msgbuf, const CommandOptions& options) {
  132. // Store the interpretation of the flags field.
  133. string fields = getFields(msgbuf);
  134. // Do the I/O, waiting for a reply
  135. OutputBufferPtr replybuf(new OutputBuffer(512));
  136. performIO(msgbuf, replybuf, options);
  137. string status = "";
  138. string returned = "";
  139. switch (result_) {
  140. case IOFetch::SUCCESS:
  141. {
  142. status = "SUCCESS";
  143. // Parse the reply and get the fields
  144. returned = getFields(replybuf);
  145. lowercase(returned);
  146. }
  147. break;
  148. case IOFetch::TIME_OUT:
  149. status = "TIMEOUT";
  150. break;
  151. case IOFetch::STOPPED:
  152. status = "STOPPED";
  153. break;
  154. default:
  155. status = "UNKNOWN";
  156. }
  157. // ... and output the result
  158. cout << status << ": (" << fields << ") (" << returned << ")\n";
  159. }
  160. // Get interpretation of the message fields.
  161. //
  162. // This takes the second and third bytes of the passed buffer and interprets
  163. // the values. A summary string listing them is returned.
  164. std::string
  165. Scan::getFields(isc::dns::OutputBufferPtr& msgbuf) {
  166. HeaderFlags flags;
  167. // Extract the flags field from the buffer
  168. InputBuffer inbuf(msgbuf->getData(), msgbuf->getLength());
  169. inbuf.setPosition(OptionInfo::word(OptionInfo::QR));
  170. flags.setValue(inbuf.readUint16());
  171. std::ostringstream os;
  172. os << std::hex << std::uppercase <<
  173. "QR:" << flags.get(OptionInfo::QR) << " " <<
  174. "OP:" << flags.get(OptionInfo::OP) << " " <<
  175. "AA:" << flags.get(OptionInfo::AA) << " " <<
  176. "TC:" << flags.get(OptionInfo::TC) << " " <<
  177. "RD:" << flags.get(OptionInfo::RD) << " " <<
  178. "RA:" << flags.get(OptionInfo::RA) << " " <<
  179. "Z:" << flags.get(OptionInfo::Z) << " " <<
  180. "AD:" << flags.get(OptionInfo::AD) << " " <<
  181. "CD:" << flags.get(OptionInfo::CD) << " " <<
  182. "RC:" << flags.get(OptionInfo::RC);
  183. // Section count fields
  184. os << " ";
  185. inbuf.setPosition(OptionInfo::word(OptionInfo::QC));
  186. os << std::hex << std::uppercase <<
  187. "QC:" << inbuf.readUint16() << " ";
  188. inbuf.setPosition(OptionInfo::word(OptionInfo::AC));
  189. os << std::hex << std::uppercase <<
  190. "AC:" << inbuf.readUint16() << " ";
  191. inbuf.setPosition(OptionInfo::word(OptionInfo::UC));
  192. os << std::hex << std::uppercase <<
  193. "UC:" << inbuf.readUint16() << " ";
  194. inbuf.setPosition(OptionInfo::word(OptionInfo::DC));
  195. os << std::hex << std::uppercase <<
  196. "DC:" << inbuf.readUint16();
  197. return (os.str());
  198. }
  199. // Perform the I/O.
  200. void
  201. Scan::performIO(OutputBufferPtr& sendbuf, OutputBufferPtr& recvbuf,
  202. const CommandOptions& options)
  203. {
  204. // Set up an I/O service for the I/O. This needs to be initialized before
  205. // every call as the callback called when the I/O completes stops it.
  206. service_.reset(new IOService());
  207. // The object that will do the I/O
  208. IOFetch fetch(IOFetch::UDP, *service_, sendbuf,
  209. IOAddress(options.getAddress()), options.getPort(), recvbuf,
  210. this, options.getTimeout());
  211. // Execute the message exhange. The call to run() will return when a
  212. // response is received or when the I/O times out.
  213. (service_->get_io_service()).post(fetch);
  214. service_->run();
  215. }
  216. // I/O Callback. Called when the message exchange compltes or times out.
  217. void
  218. Scan::operator()(IOFetch::Result result) {
  219. // Record the result. This is accessed when deciding what was returned
  220. // (if a timeout, nothing was returned).
  221. result_ = result;
  222. // Stop the I/O service. This will cause the call to run() to return.
  223. service_->stop();
  224. }
  225. } // namespace test
  226. } // namespace isc