scan.cc 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  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 <stdlib.h>
  19. #include <config.h>
  20. // on sunstudio, asio.hpp needs unistd.h for pipe() to be defined
  21. #ifdef HAVE_UNISTD_H
  22. #include <unistd.h>
  23. #endif
  24. #include <asio.hpp>
  25. #include <asiolink/io_address.h>
  26. #include <asiodns/io_fetch.h>
  27. #include <util/buffer.h>
  28. #include <dns/message.h>
  29. #include <dns/messagerenderer.h>
  30. #include <dns/opcode.h>
  31. #include <dns/question.h>
  32. #include <dns/rcode.h>
  33. #include <dns/rrclass.h>
  34. #include <dns/rrtype.h>
  35. #include <util/strutil.h>
  36. #include "command_options.h"
  37. #include "header_flags.h"
  38. #include "scan.h"
  39. using namespace std;
  40. using namespace isc::asiolink;
  41. using namespace isc::asiodns;
  42. using namespace isc::dns;
  43. using namespace isc::util;
  44. using namespace isc::util::str;
  45. namespace isc {
  46. namespace badpacket {
  47. // Perform the scan from start to end on a single question.
  48. void
  49. Scan::scan(const CommandOptions& options) {
  50. // Create the message buffer to use
  51. Message message(Message::RENDER);
  52. message.setOpcode(Opcode::QUERY());
  53. message.setRcode(Rcode::NOERROR());
  54. message.addQuestion(Question(Name(options.getQname()), RRClass::IN(),
  55. RRType::A()));
  56. OutputBufferPtr msgbuf(new OutputBuffer(512));
  57. MessageRenderer renderer(*msgbuf);
  58. message.toWire(renderer);
  59. iterateFlagsStart(msgbuf, options);
  60. }
  61. // Iterate through the various settings in the flags fields.
  62. void
  63. Scan::iterateFlagsStart(OutputBufferPtr& msgbuf, const CommandOptions& options) {
  64. HeaderFlags flags;
  65. iterateFlags(msgbuf, options, flags, OptionInfo::FLAGS_START,
  66. OptionInfo::FLAGS_END);
  67. }
  68. void
  69. Scan::iterateFlags(OutputBufferPtr& msgbuf, const CommandOptions& options,
  70. HeaderFlags& flags, int index, int maxindex)
  71. {
  72. // Is the index valid?
  73. if (index <= maxindex) {
  74. // Index is valid, did the command line specify a range of values for
  75. // this field?
  76. if (options.present(index)) {
  77. // It did, so loop between minimum and maximum values given.
  78. for (uint32_t i = options.minimum(index);
  79. i <= options.maximum(index); ++i) {
  80. flags.set(index, i);
  81. // Recurse to set the next option.
  82. iterateFlags(msgbuf, options, flags, (index + 1), maxindex);
  83. }
  84. } else {
  85. // Not specified on command line, so set the default value in the
  86. // flags and process the next index.
  87. flags.set(index, OptionInfo::defval(index));
  88. iterateFlags(msgbuf, options, flags, (index + 1), maxindex);
  89. }
  90. } else {
  91. // Index is not valid, so we have recursed enough to process all the
  92. // flags fields. Set the value in the message header and call the next
  93. // stage in the processing.
  94. //
  95. // (In the next statement, the "word" offset of in the header is the
  96. // same for all flags options, so the value for an arbitrary field
  97. // (QR) has been used.)
  98. msgbuf->writeUint16At(flags.getValue(),
  99. OptionInfo::word(OptionInfo::QR));
  100. iterateCountStart(msgbuf, options);
  101. }
  102. }
  103. // Iterate through the various count fields
  104. void
  105. Scan::iterateCountStart(OutputBufferPtr& msgbuf, const CommandOptions& options)
  106. {
  107. iterateCount(msgbuf, options, OptionInfo::COUNT_START,
  108. OptionInfo::COUNT_END);
  109. }
  110. void
  111. Scan::iterateCount(OutputBufferPtr& msgbuf, const CommandOptions& options,
  112. int index, int maxindex)
  113. {
  114. // If the index is valid, process the iteration over the range for this
  115. // flags field.
  116. if (index <= maxindex) {
  117. // Index is valid, did the command line specify a range of values for
  118. // this field?
  119. if (options.present(index)) {
  120. // It did, so loop between minimum and maximum values given.
  121. for (uint32_t i = options.minimum(index);
  122. i <= options.maximum(index); ++i) {
  123. // Set the value in the message buffer header and recurse to
  124. // the next option.
  125. msgbuf->writeUint16At(i, OptionInfo::word(index));
  126. iterateCount(msgbuf, options, (index + 1), maxindex);
  127. }
  128. } else {
  129. // Not specified on command line, so do change anything and process
  130. // the next index.
  131. iterateCount(msgbuf, options, (index + 1), maxindex);
  132. }
  133. } else {
  134. // Index is not valid, so we have recursed enough to process all the
  135. // flags fields. Do the next stage of the processing.
  136. sizeMessage(msgbuf, options);
  137. }
  138. }
  139. // Alter the message size.
  140. void
  141. Scan::sizeMessage(OutputBufferPtr& msgbuf, const CommandOptions& options) {
  142. if (options.present(OptionInfo::MS)) {
  143. // Iterate over the range of message sizes
  144. for (size_t i = options.minimum(OptionInfo::MS);
  145. i <= options.maximum(OptionInfo::MS); ++i) {
  146. // Copy the data into a new buffer.
  147. OutputBufferPtr newbuf(new OutputBuffer(i));
  148. newbuf->writeData(msgbuf->getData(), min(msgbuf->getLength(), i));
  149. // Pad with junk (actually pseudo-random data) if the new buffer is
  150. // longer than the old.
  151. for (size_t j = newbuf->getLength(); j < i; ++j) {
  152. newbuf->writeUint8(static_cast<uint8_t>(rand() & 0xFFU));
  153. }
  154. // ... and process.
  155. scanOne(newbuf, options);
  156. }
  157. } else {
  158. // No packet size given, just process the message as it.
  159. scanOne(msgbuf, options);
  160. }
  161. }
  162. // Perform the message exchange for a single combination command options.
  163. void
  164. Scan::scanOne(isc::util::OutputBufferPtr& msgbuf, const CommandOptions& options) {
  165. // Store the interpretation of outgoing message.
  166. string fields = string("(") + getFields(msgbuf) + string(")");
  167. // Do the I/O, waiting for a reply
  168. OutputBufferPtr replybuf(new OutputBuffer(512));
  169. performIO(msgbuf, replybuf, options);
  170. string status = "";
  171. string returned = "";
  172. switch (result_) {
  173. case IOFetch::SUCCESS:
  174. {
  175. status = "SUCCESS";
  176. // Parse the reply and get the fields
  177. returned = string("(") + getFields(replybuf) + string(")");
  178. lowercase(returned);
  179. }
  180. break;
  181. case IOFetch::TIME_OUT:
  182. status = "TIMEOUT";
  183. break;
  184. case IOFetch::STOPPED:
  185. status = "STOPPED";
  186. break;
  187. default:
  188. status = "UNKNOWN";
  189. }
  190. // ... and output the result
  191. cout << status << ": " << fields << " " << returned << "\n";
  192. }
  193. // Get interpretation of the message fields.
  194. std::string
  195. Scan::getFields(isc::util::OutputBufferPtr& msgbuf) {
  196. // Header flags. (Note that all come from the same word in the message, so
  197. // using the word offset for the QR flag as the position in the buffer from
  198. // which to extract the values is valid.)
  199. HeaderFlags flags;
  200. InputBuffer inbuf(msgbuf->getData(), msgbuf->getLength());
  201. inbuf.setPosition(OptionInfo::word(OptionInfo::QR));
  202. flags.setValue(inbuf.readUint16());
  203. std::ostringstream os;
  204. os << std::hex << std::uppercase <<
  205. "QR:" << flags.get(OptionInfo::QR) <<
  206. " OP:" << flags.get(OptionInfo::OP) <<
  207. " AA:" << flags.get(OptionInfo::AA) <<
  208. " TC:" << flags.get(OptionInfo::TC) <<
  209. " RD:" << flags.get(OptionInfo::RD) <<
  210. " RA:" << flags.get(OptionInfo::RA) <<
  211. " Z:" << flags.get(OptionInfo::Z) <<
  212. " AD:" << flags.get(OptionInfo::AD) <<
  213. " CD:" << flags.get(OptionInfo::CD) <<
  214. " RC:" << flags.get(OptionInfo::RC);
  215. // Section count fields.
  216. inbuf.setPosition(OptionInfo::word(OptionInfo::QC));
  217. os << std::dec << std::uppercase <<
  218. " QC:" << inbuf.readUint16();
  219. inbuf.setPosition(OptionInfo::word(OptionInfo::AC));
  220. os << std::dec << std::uppercase <<
  221. " AC:" << inbuf.readUint16();
  222. inbuf.setPosition(OptionInfo::word(OptionInfo::UC));
  223. os << std::dec << std::uppercase <<
  224. " UC:" << inbuf.readUint16();
  225. inbuf.setPosition(OptionInfo::word(OptionInfo::DC));
  226. os << std::dec << std::uppercase <<
  227. " DC:" << inbuf.readUint16();
  228. // ... and message size.
  229. os << std::dec << std::uppercase <<
  230. " MS:" << msgbuf->getLength();
  231. return (os.str());
  232. }
  233. // Perform the I/O to the nameserver.
  234. void
  235. Scan::performIO(OutputBufferPtr& sendbuf, OutputBufferPtr& recvbuf,
  236. const CommandOptions& options)
  237. {
  238. // Set up an I/O service for the I/O. This needs to be initialized before
  239. // every call as the callback called when the I/O completes stops it.
  240. service_.reset(new IOService());
  241. // The object that will do the I/O
  242. IOFetch fetch(IOFetch::UDP, *service_, sendbuf,
  243. IOAddress(options.getAddress()), options.getPort(), recvbuf,
  244. this, options.getTimeout());
  245. // Execute the message exchange. The call to run() will return when a
  246. // response is received or when the I/O times out.
  247. (service_->get_io_service()).post(fetch);
  248. service_->run();
  249. }
  250. // I/O Callback. Called when the message exchange completes or times out.
  251. void
  252. Scan::operator()(IOFetch::Result result) {
  253. // Record the result. This is accessed when deciding what was returned
  254. // (if a timeout, nothing was returned).
  255. result_ = result;
  256. // Stop the I/O service. This will cause the call to run() to return.
  257. service_->stop();
  258. }
  259. } // namespace test
  260. } // namespace isc