command_options.cc 11 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 <algorithm>
  15. #include <iostream>
  16. #include <string>
  17. #include <vector>
  18. #include <boost/lexical_cast.hpp>
  19. #include <getopt.h>
  20. #include "exceptions/exceptions.h"
  21. #include "log/strutil.h"
  22. #include "command_options.h"
  23. #include "option_info.h"
  24. #include "version.h"
  25. using namespace std;
  26. using namespace isc;
  27. namespace isc {
  28. namespace badpacket {
  29. /// Parses the command-line options and returns the results in an Options
  30. /// structure. If the
  31. void
  32. CommandOptions::parse(int argc, char* const argv[]) {
  33. // Set up options for processing. The declaration of the string constants
  34. // as mutable arrays and putting the string variable into the "option"
  35. // structure (as opposed to just putting a string literal there) is
  36. // occasioned by a version of solaris which declares the first field
  37. // as "char*" (instead of the correct "const char*").
  38. char HELP[] = {"help"};
  39. char VERSION[] = {"version"};
  40. char ADDRESS[] = {"address"};
  41. char PORT[] = {"port"};
  42. char TIMEOUT[] = {"timeout"};
  43. // Settings for options in the flags field
  44. char QR[] = {"qr"};
  45. char OP[] = {"op"};
  46. char AA[] = {"aa"};
  47. char TC[] = {"tc"};
  48. char RD[] = {"rd"};
  49. char RA[] = {"ra"};
  50. char Z[] = {"z"};
  51. char AD[] = {"ad"};
  52. char CD[] = {"cd"};
  53. char RC[] = {"rc"};
  54. // Settings for the count fields
  55. char QC[] = {"qc"};
  56. char AC[] = {"ac"};
  57. char UC[] = {"uc"};
  58. char DC[] = {"dc"};
  59. const struct option longopts[] = {
  60. {HELP, 0, NULL, 'h'}, // Print usage message and exit
  61. {VERSION, 0, NULL, 'v'}, // Print program version and exit
  62. {ADDRESS, 1, NULL, 'a'}, // Specify target server address
  63. {PORT, 1, NULL, 'p'}, // Specify target port
  64. {TIMEOUT, 1, NULL, 't'}, // Time to wait before timing out (ms)
  65. {QR, 1, NULL, 'Q'}, // Query/response flag
  66. {OP, 1, NULL, 'O'}, // Opcode
  67. {AA, 1, NULL, 'A'}, // Authoritative answer
  68. {TC, 1, NULL, 'T'}, // Truncated
  69. {RD, 1, NULL, 'D'}, // recursion Desired
  70. {RA, 1, NULL, 'R'}, // Recursion available
  71. {Z, 1, NULL, 'Z'}, // must be Zero (reserved bit)
  72. {AD, 1, NULL, 'U'}, // aUthenticated data
  73. {CD, 1, NULL, 'C'}, // Checking disabled
  74. {RC, 1, NULL, 'E'}, // rEsult code
  75. {QC, 1, NULL, 'Y'}, // querY section count
  76. {AC, 1, NULL, 'W'}, // ansWer section count
  77. {UC, 1, NULL, 'H'}, // autHority section count
  78. {DC, 1, NULL, 'I'}, // addItional section count
  79. {NULL, 0, NULL, 0 }
  80. };
  81. const char* shortopts = "hva:p:t:Q:O:A:T:D:R:Z:U:C:E:Y:W:H:I:";
  82. // Set variables to defaults before parsing
  83. reset();
  84. // Process command line
  85. int c; // Option being processed
  86. optind = 0; // Reset parsing
  87. while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
  88. switch (c) {
  89. case 'h': // --help
  90. usage();
  91. exit(0);
  92. case 'v': // --version
  93. version();
  94. exit(0);
  95. case 'a': // --address
  96. address_ = optarg;
  97. break;
  98. case 'p': // --port
  99. port_ = boost::lexical_cast<uint16_t>(string(optarg));
  100. break;
  101. case 't': // --timeout
  102. timeout_ = boost::lexical_cast<int>(string(optarg));
  103. break;
  104. case 'Q': // --qr (query/response)
  105. case 'O': // --op (operation code)
  106. case 'A': // --aa (authoritative answer)
  107. case 'T': // --tc (truncated)
  108. case 'D': // --rd (recursion desired)
  109. case 'R': // --ra (recursion available)
  110. case 'Z': // --z (zero: reserved bit)
  111. case 'U': // --ad (authenticated data)
  112. case 'C': // --cd (checking disabled)
  113. case 'E': // --rc (result code)
  114. case 'Y': // --qc (query count)
  115. case 'W': // --ac (answer count)
  116. case 'H': // --uc (authority count)
  117. case 'I': // --dc (additional count)
  118. processOptionValue(c, optarg);
  119. break;
  120. default:
  121. isc_throw(isc::InvalidParameter,
  122. "unknown option '" << argv[optind] << "' given on the command line");
  123. }
  124. }
  125. // Pick up a parameter if there is one (and ignore excess parameters).
  126. if (optind < argc) {
  127. qname_ = argv[optind++];
  128. }
  129. }
  130. /// \brief Print usage information
  131. void
  132. CommandOptions::usage() {
  133. cout << "Usage: badpacket [options] query\n"
  134. "\n"
  135. "Sends a sequence of packets to the specified nameserver and prints the results.\n"
  136. "The packets are valid query packets but the flags field (third and fourth bytes\n"
  137. "of the packet) can be set to arbitrary values using the command-line switches.\n"
  138. "\n"
  139. "In the following list of command-line switches, '<range>' indicates a range of\n"
  140. "values specified as either <integer> or <integer1>-<integer2> (e.g. both '42'\n"
  141. "and '0-1' would be valid values for range). The program sends a sequence of\n"
  142. "packets that contain all combinations of the flag values. For example,\n"
  143. "specifying:\n"
  144. "\n"
  145. "--tc 0-1 --op 1-4 --aa 1 --rd 0-1\n"
  146. "\n"
  147. "... would send a total of 16 packets which would have all combinations of the\n"
  148. "the tc bit set to 0 and 1, the rd bit set to 0 and 1, and the opcode set to all\n"
  149. "values between 1 and 4. All other flags fields would be zero except for the aa\n"
  150. "bit which would always be 1.\n"
  151. "\n"
  152. "The long form of the option is given. It can also be specified as a single-\n"
  153. "character short-form, which is listed in sqare brackets in the description.\n"
  154. "\n"
  155. "--help [-h] Prints this message and exits.\n"
  156. "--version [-v] Prints the program version number.\n"
  157. "--address <address> [-a] Address of nameserver, which defaults to 127.0.0.1\n"
  158. "--port <port> [-p] Port to which to send query. Defaults to 53.\n"
  159. "--timeout <value> [-t] Timeout value for the query. Specified in ms, it\n"
  160. " defaults to 500ms.\n"
  161. "\n"
  162. "The following options set fields in the outgoing DNS message flags word\n"
  163. "\n"
  164. "--qr <range> [-Q] Set query/response bit. Valid <range> is 0-1.\n"
  165. "--op <range> [-O] Set opcode. Valid <range> is 0-15.\n"
  166. "--aa <range> [-A] Set authoritative answer bit. Valid <range> is 0-1.\n"
  167. "--tc <range> [-T] Set truncated bit. Valid <range> is 0-1.\n"
  168. "--rd <range> [-T] Set recursion desired bit. Valid <range> is 0-1.\n"
  169. "--ra <range> [-T] Set recursion available bit. Valid <range> is 0-1.\n"
  170. "--z <range> [-Z] Set zero (reserved) bit. Valid <range> is 0-1.\n"
  171. "--ad <range> [-U] Set authenticated data bit. Valid <range> is 0-1.\n"
  172. "--cd <range> [-C] Set checking disabled bit. Valid <range> is 0-1.\n"
  173. "--rc <range> [-E] Set rcode value. Valid <range> is 0-15\n"
  174. "\n"
  175. "The following options set the various section counts (independent of what is\n"
  176. "actually in the section)\n"
  177. "\n"
  178. "--qc <range> [-Q] Set the query count. Valid range is 0-65535.\n"
  179. "--ac <range> [-Q] Set the answer count. Valid range is 0-65535.\n"
  180. "--uc <range> [-Q] Set the authority count. Valid range is 0-65535.\n"
  181. "--dc <range> [-Q] Set the additional count. Valid range is 0-65535.\n"
  182. "\n"
  183. "query Name to query for. The query is for an 'IN' A record.\n"
  184. " If not given, the name 'www.example.com' is used.\n"
  185. ;
  186. }
  187. /// \brief Print version information
  188. void
  189. CommandOptions::version() {
  190. cout << BADPACKET_VERSION << "\n";
  191. }
  192. // Process single flag
  193. void
  194. CommandOptions::processOptionValue(int c, const char* value) {
  195. // Get values for this option
  196. int index = OptionInfo::getIndex(c);
  197. const char* name = OptionInfo::name(index);
  198. uint32_t minval = OptionInfo::minval(index);
  199. uint32_t maxval = OptionInfo::maxval(index);
  200. // Split the string up into one or two tokens
  201. vector<string> tokens = isc::strutil::tokens(string(value), "-");
  202. if ((tokens.size() < 1) || (tokens.size() > 2)) {
  203. isc_throw(isc::BadValue, "value given for " << name << " is '" << value <<
  204. "': it must be in the form 'int' or 'int1-int2'");
  205. }
  206. // Convert to uint32.
  207. int i = 0;
  208. try {
  209. do {
  210. limits_[index][i] = boost::lexical_cast<uint32_t>(tokens[i]);
  211. ++i;
  212. } while (i < tokens.size());
  213. } catch (boost::bad_lexical_cast) {
  214. isc_throw(isc::BadValue, "value given for " << name << " is '" << value <<
  215. "': it must be in the form 'int' or 'int1-int2'");
  216. }
  217. // Set the limits in the correct order.
  218. if (tokens.size() == 1) {
  219. limits_[index][1] = limits_[index][0];
  220. } else if (limits_[index][0] > limits_[index][1]) {
  221. swap(limits_[index][0], limits_[index][1]);
  222. }
  223. // Check that tokens lie inside the allowed ranges
  224. if ((tokens.size() == 1) &&
  225. ((limits_[index][0] < OptionInfo::minval(index)) || (limits_[index][0] > maxval))) {
  226. isc_throw(isc::BadValue, "the tokens of " << limits_[index][0] <<
  227. " given for " << name << " is outside the range of " <<
  228. minval << " to " << maxval);
  229. } else if (limits_[index][0] < minval) {
  230. isc_throw(isc::BadValue, "the lower limit of " << limits_[index][0] <<
  231. " given for " << name << " is below the minimum permitted"
  232. " value of " << minval);
  233. } else if (limits_[index][1] > maxval) {
  234. isc_throw(isc::BadValue, "the upper limit of " << limits_[index][1] <<
  235. " given for " << name << " is above the maximum permitted"
  236. " value of " << maxval);
  237. }
  238. }
  239. // Minimum and maximum value of the flag
  240. uint32_t
  241. CommandOptions::minimum(int index) const {
  242. OptionInfo::checkIndex(index);
  243. return (limits_[index][0]);
  244. }
  245. uint32_t
  246. CommandOptions::maximum(int index) const {
  247. OptionInfo::checkIndex(index);
  248. return (limits_[index][1]);
  249. }
  250. } // namespace badpacket
  251. } // namespace isc