scan.cc 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  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. // Now loop through the flags setting data. This is quite deep nesting,
  53. // but we will continue to indent so as to make things clear (for those
  54. // readers lucky enough to have a wide screen).
  55. CommandOptions::FlagValues values = options.getFlagValues();
  56. HeaderFlags flags;
  57. for (uint16_t qr = values.qr[0]; qr <= values.qr[1]; ++qr) {
  58. flags.setQR(qr);
  59. for (uint16_t op = values.op[0]; op <= values.op[1]; ++op) {
  60. flags.setOP(op);
  61. for (uint16_t aa = values.aa[0]; aa <= values.aa[1]; ++aa) {
  62. flags.setAA(aa);
  63. for (uint16_t tc = values.tc[0]; tc <= values.tc[1]; ++tc) {
  64. flags.setTC(tc);
  65. for (uint16_t rd = values.rd[0]; rd <= values.rd[1]; ++rd) {
  66. flags.setRD(rd);
  67. for (uint16_t ra = values.ra[0]; ra <= values.ra[1]; ++ra) {
  68. flags.setRA(ra);
  69. for (uint16_t z = values.z[0]; z <= values.z[1]; ++z) {
  70. flags.setZ(z);
  71. for (uint16_t ad = values.ad[0]; ad <= values.ad[1]; ++ad) {
  72. flags.setAD(ad);
  73. for (uint16_t cd = values.cd[0]; cd <= values.cd[1]; ++cd) {
  74. flags.setCD(cd);
  75. for (uint16_t rc = values.rc[0]; rc <= values.rc[1]; ++rc) {
  76. flags.setRC(rc);
  77. // Set the flags in the message and do the I/O.
  78. msgbuf->writeUint16At(flags.getValue(), 2);
  79. scanOne(msgbuf, options);
  80. }
  81. }
  82. }
  83. }
  84. }
  85. }
  86. }
  87. }
  88. }
  89. }
  90. }
  91. // Perform the message exchange for a single combination of flags.
  92. void
  93. Scan::scanOne(isc::dns::OutputBufferPtr& msgbuf, const CommandOptions& options) {
  94. // Store the interpretation of the flags field.
  95. string fields = getFields(msgbuf);
  96. // Do the I/O, waiting for a reply
  97. OutputBufferPtr replybuf(new OutputBuffer(512));
  98. performIO(msgbuf, replybuf, options);
  99. string status = "";
  100. string returned = "";
  101. switch (result_) {
  102. case IOFetch::SUCCESS:
  103. {
  104. status = "SUCCESS";
  105. // Parse the reply and get the fields
  106. returned = getFields(replybuf);
  107. lowercase(returned);
  108. }
  109. break;
  110. case IOFetch::TIME_OUT:
  111. status = "TIMEOUT";
  112. break;
  113. case IOFetch::STOPPED:
  114. status = "STOPPED";
  115. break;
  116. default:
  117. status = "UNKNOWN";
  118. }
  119. // ... and output the result
  120. cout << status << ": (" << fields << ") (" << returned << ")\n";
  121. }
  122. // Get interpretation of the message fields.
  123. //
  124. // This takes the second and third bytes of the passed buffer and interprets
  125. // the values. A summary string listing them is returned.
  126. std::string
  127. Scan::getFields(isc::dns::OutputBufferPtr& msgbuf) {
  128. HeaderFlags flags;
  129. // Extract the flags field from the buffer
  130. InputBuffer inbuf(msgbuf->getData(), msgbuf->getLength());
  131. inbuf.setPosition(2);
  132. flags.setValue(inbuf.readUint16());
  133. std::ostringstream os;
  134. os << std::hex << std::uppercase <<
  135. "QR:" << flags.getQR() << " " <<
  136. "OP:" << flags.getOP() << " " <<
  137. "AA:" << flags.getAA() << " " <<
  138. "TC:" << flags.getTC() << " " <<
  139. "RD:" << flags.getRD() << " " <<
  140. "RA:" << flags.getRA() << " " <<
  141. "Z:" << flags.getZ() << " " <<
  142. "AD:" << flags.getAD() << " " <<
  143. "CD:" << flags.getCD() << " " <<
  144. "RC:" << flags.getRC();
  145. return (os.str());
  146. }
  147. // Perform the I/O.
  148. void
  149. Scan::performIO(OutputBufferPtr& sendbuf, OutputBufferPtr& recvbuf,
  150. const CommandOptions& options)
  151. {
  152. // Set up an I/O service for the I/O. This needs to be initialized before
  153. // every call as the callback called when the I/O completes stops it.
  154. service_.reset(new IOService());
  155. // The object that will do the I/O
  156. IOFetch fetch(IOFetch::UDP, *service_, sendbuf,
  157. IOAddress(options.getAddress()), options.getPort(), recvbuf,
  158. this, options.getTimeout());
  159. // Execute the message exhange. The call to run() will return when a
  160. // response is received or when the I/O times out.
  161. (service_->get_io_service()).post(fetch);
  162. service_->run();
  163. }
  164. // I/O Callback. Called when the message exchange compltes or times out.
  165. void
  166. Scan::operator()(IOFetch::Result result) {
  167. // Record the result. This is accessed when deciding what was returned
  168. // (if a timeout, nothing was returned).
  169. result_ = result;
  170. // Stop the I/O service. This will cause the call to run() to return.
  171. service_->stop();
  172. }
  173. } // namespace test
  174. } // namespace isc