command_options.cc 10.0 KB

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