BIND 10 trac703, updated. 6f91ee90cd428b0e7eecd4cb99eefc0201f4360e [trac703] Update document and comments
BIND 10 source code commits
bind10-changes at lists.isc.org
Wed Apr 13 14:14:38 UTC 2011
The branch, trac703 has been updated
via 6f91ee90cd428b0e7eecd4cb99eefc0201f4360e (commit)
via bc88971bdb67728a22d029504bf18e778af26591 (commit)
from 3999bb246ea782310611471d3ff28cdd85bf4a0d (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 6f91ee90cd428b0e7eecd4cb99eefc0201f4360e
Author: Stephen Morris <stephen at isc.org>
Date: Wed Apr 13 15:14:12 2011 +0100
[trac703] Update document and comments
commit bc88971bdb67728a22d029504bf18e778af26591
Author: Stephen Morris <stephen at isc.org>
Date: Wed Apr 13 13:09:11 2011 +0100
[trac703] Added ability to set the packet size
-----------------------------------------------------------------------
Summary of changes:
src/lib/asiolink/io_fetch.h | 19 +-
tests/tools/badpacket/README | 38 +-
tests/tools/badpacket/badpacket.cc | 23 +-
tests/tools/badpacket/command_options.cc | 146 ++++--
tests/tools/badpacket/command_options.h | 72 ++--
tests/tools/badpacket/header_flags.h | 18 +-
tests/tools/badpacket/option_info.cc | 15 +-
tests/tools/badpacket/option_info.h | 89 ++--
tests/tools/badpacket/scan.cc | 251 ++++++-----
tests/tools/badpacket/scan.h | 100 +++-
.../badpacket/tests/command_options_unittest.cc | 515 +++++++-------------
.../tools/badpacket/tests/header_flags_unittest.cc | 286 +++---------
.../tools/badpacket/tests/option_info_unittest.cc | 7 +
13 files changed, 704 insertions(+), 875 deletions(-)
-----------------------------------------------------------------------
diff --git a/src/lib/asiolink/io_fetch.h b/src/lib/asiolink/io_fetch.h
index 56cee87..179fdd9 100644
--- a/src/lib/asiolink/io_fetch.h
+++ b/src/lib/asiolink/io_fetch.h
@@ -116,22 +116,19 @@ public:
///
/// Creates the object that will handle the upstream fetch.
///
- /// TODO: Need to randomise the source port
- ///
/// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
/// \param service I/O Service object to handle the asynchronous
- /// operations.
+ /// operations.
/// \param question DNS question to send to the upstream server.
- /// \param buff Output buffer into which the response (in wire format)
- /// is written (if a response is received).
- /// \param cb Callback object containing the callback to be called
- /// when we terminate. The caller is responsible for managing this
- /// object and deleting it if necessary.
/// \param address IP address of upstream server
/// \param port Port to which to connect on the upstream server
- /// (default = 53)
+ /// \param buff Output buffer into which the response (in wire format)
+ /// is written (if a response is received).
+ /// \param cb Callback object containing the callback to be called when we
+ /// terminate. The caller is responsible for managing this object
+ /// and deleting it if necessary.
/// \param wait Timeout for the fetch (in ms). The default value of
- /// -1 indicates no timeout.
+ /// - 1 indicates no timeout.
IOFetch(Protocol protocol, IOService& service,
const isc::dns::Question& question, const IOAddress& address,
uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb,
@@ -141,8 +138,6 @@ public:
///
/// Creates the object that will handle the upstream fetch.
///
- /// TODO: Need to randomise the source port
- ///
/// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
/// \param service I/O Service object to handle the asynchronous
/// operations.
diff --git a/tests/tools/badpacket/README b/tests/tools/badpacket/README
index 4d90dd0..3f5e801 100644
--- a/tests/tools/badpacket/README
+++ b/tests/tools/badpacket/README
@@ -1,12 +1,11 @@
"badpacket" is a tool intended to test that a nameserver can cope with
incorrectly-formatted DNS messages.
-This particular incarnation of the tool allows the flags field of a DNS message
-(the third and fourth bytes) to be set to any bit combination (including ones
-that invalid in a query). As well as setting the bits to a particular
-combination, it is possible to specify ranges for bit/field values; when this
-is done, the tool will send a set of packets so that each combination of flag
-bits is checked.
+This particular incarnation of the tool allows various fields in the DNS
+message to be set to any value (including to values that invalidate the query).
+As well as setting individual values, it is possible to specify ranges; when
+this is done, the tool will send a set of packets so that each combination
+of values is checked.
To illustrate this, consider the following command:
@@ -15,11 +14,11 @@ badpacket --address 192.0.2.21 --port 5301 --aa 0-1 --cd 1
(The command has been split across two lines for clarity.)
-The address and port flags are self-evident. The other flags specify settings
-for the AA bit (0 and 1), CD bit (always 1) and the RCODE field (0, 1, 2). (The
-remaining fields are not specified, so will always be zero.) There are six
-combinations of these values, so six packets will sent to the remote server with
-the following settings:
+The address and port flags are self-evident. The other flags specify
+settings for the AA bit (0 and 1), CD bit (always 1) and the RCODE field
+(0, 1, 2). (The remaining fields in the flags word are not specified, so
+will always be zero.) There are six combinations of these values, so six
+packets will sent to the remote server with the following settings:
AA RCODE CD Rest
0 0 1 0
@@ -32,20 +31,23 @@ AA RCODE CD Rest
Each packet will cause a line to be output to stdout, which will have the
following form:
-SUCCESS: (QR:0 OP:0 AA:0 TC:0 RD:0 RA:0 Z:0 AD:0 CD:1 RC:0)
- (qr:1 op:0 aa:0 tc:0 rd:0 ra:1 z:0 ad:0 cd:1 rc:0)
+SUCCESS: (QR:0 OP:0 AA:0 TC:0 RD:0 RA:0 ...
+ (qr:1 op:0 aa:0 tc:0 rd:0 ra:1 ...
-(Again the text has been split across two lines for clarity.)
+(Again the text has been split across two lines for clarity. Also, the full
+list of fields has been truncated.)
Each lines contains a status (SUCCESS indicates that a response was received,
regardless of the contents of the response), the state of the fields in the
flags word of the packet sent (in upper-case letters) and the state of the
fields in the flags word of the response (in lower-case letters).
-TODO: At the moment the tool is limited to just alerting the flags field.
-Future work should extend the program to other bad packets. Ideas are:
+TODO: At the moment the tool is limited to:
+* Setting values in the flags field.
+* Setting section counts to arbitrary values.
+* Extending or truncating the DNS message size.
-* Flasify the values in the various count fields
+Additional options needed are:
* Add data to sections that should be empty.
* Deliberately mangle the names placed in the message sections (e.g. by altering
- the label count fields).
\ No newline at end of file
+ the label count fields).
diff --git a/tests/tools/badpacket/badpacket.cc b/tests/tools/badpacket/badpacket.cc
index 894b72f..86bbc47 100644
--- a/tests/tools/badpacket/badpacket.cc
+++ b/tests/tools/badpacket/badpacket.cc
@@ -27,16 +27,18 @@
/// printing the packet settings and the response received. The principle
/// raison d'etre for this is to check if a bad packet will cause a crash.
///
-/// This particular version of the code allows a set of ranges to be set for
-/// each field in the "flags" word (the third and fourth bytes) of a DNS
-/// message. (Most of the flags are single-bit values, so the range is just 0-1.
-/// The OPCODE and RCODE are both four bits wide, so the range is 0-15.) The
-/// program then sends packets containing each combination of values.
+/// This particular version of the code allows a set of ranges to be set for:
+/// - The flags fields in the message.
+/// - The section count fields, regardless of what is in the section.
+/// - The message size: the message can be truncated or extended.
///
-/// TODO: Extend the program to other bad values.
-/// Examples of this would be to make the count fields invalid, to add data
-/// to sections that should be empty, and to deliberately mangle the names in
-/// these sections.
+/// The program then sends a set of packets corresponding to all combinations
+/// of values in the ranges selected.
+
+// TODO: Extend to cover:
+// - Mangling the QNAME
+// - Adding names to the message sections
+// - Adding EDNS0 RR and magling the fields there
using namespace isc::badpacket;
@@ -44,10 +46,11 @@ using namespace isc::badpacket;
int main(int argc, char* argv[]) {
try {
+ // Parse command
CommandOptions options;
options.parse(argc, argv);
- // Construct the scan object and perform the scan.
+ // Send the sequence of messages
Scan scanner;
scanner.scan(options);
} catch (isc::Exception& e) {
diff --git a/tests/tools/badpacket/command_options.cc b/tests/tools/badpacket/command_options.cc
index 8eda345..a8bde6e 100644
--- a/tests/tools/badpacket/command_options.cc
+++ b/tests/tools/badpacket/command_options.cc
@@ -33,23 +33,39 @@ using namespace isc;
namespace isc {
namespace badpacket {
-/// Parses the command-line options and returns the results in an Options
-/// structure. If the
+// Reset stored values to the defaults.
+void
+CommandOptions::reset() {
+ address_ = "127.0.0.1";
+ port_ = 53;
+ timeout_ = 500;
+ qname_ = "www.example.com";
+
+ for (int i = 0; i < OptionInfo::SIZE; ++i) {
+ options_[i].minimum = OptionInfo::defval(i);
+ options_[i].maximum = OptionInfo::defval(i);
+ options_[i].present = false;
+ }
+}
+
+/// Parses the command-line options and records the results.
void
CommandOptions::parse(int argc, char* const argv[]) {
// Set up options for processing. The declaration of the string constants
- // as mutable arrays and putting the string variable into the "option"
+ // as mutable arrays and putting the string variable into the "longopts"
// structure (as opposed to just putting a string literal there) is
- // occasioned by a version of solaris which declares the first field
- // as "char*" (instead of the correct "const char*").
+ // occasioned by a version of solaris which declares the first field as
+ // "char*" (instead of the correct "const char*").
+
+ // General options.
char HELP[] = {"help"};
char VERSION[] = {"version"};
char ADDRESS[] = {"address"};
char PORT[] = {"port"};
char TIMEOUT[] = {"timeout"};
- // Settings for options in the flags field
+ // Settings for options in the flags field.
char QR[] = {"qr"};
char OP[] = {"op"};
char AA[] = {"aa"};
@@ -67,6 +83,9 @@ CommandOptions::parse(int argc, char* const argv[]) {
char UC[] = {"uc"};
char DC[] = {"dc"};
+ // Message size
+ char MS[] = {"ms"};
+
const struct option longopts[] = {
{HELP, 0, NULL, 'h'}, // Print usage message and exit
{VERSION, 0, NULL, 'v'}, // Print program version and exit
@@ -87,12 +106,13 @@ CommandOptions::parse(int argc, char* const argv[]) {
{AC, 1, NULL, 'W'}, // ansWer section count
{UC, 1, NULL, 'H'}, // autHority section count
{DC, 1, NULL, 'I'}, // addItional section count
+ {MS, 1, NULL, 'M'}, // Message size
{NULL, 0, NULL, 0 }
};
- const char* shortopts = "hva:p:t:Q:O:A:T:D:R:Z:U:C:E:Y:W:H:I:";
+ const char* shortopts = "hva:p:t:Q:O:A:T:D:R:Z:U:C:E:Y:W:H:I:M:";
- // Set variables to defaults before parsing
+ // Set record of options to defaults before parsing
reset();
// Process command line
@@ -134,6 +154,7 @@ CommandOptions::parse(int argc, char* const argv[]) {
case 'W': // --ac (answer count)
case 'H': // --uc (authority count)
case 'I': // --dc (additional count)
+ case 'M': // --ms (message size)
processOptionValue(c, optarg);
break;
@@ -143,25 +164,31 @@ CommandOptions::parse(int argc, char* const argv[]) {
}
}
- // Pick up a parameter if there is one (and ignore excess parameters).
+ // Pick up a parameter if there is one (and report excess).
if (optind < argc) {
qname_ = argv[optind++];
}
+
+ if (optind < argc) {
+ isc_throw(isc::InvalidParameter,
+ "only a single (optional) parameter may be specified on the command line");
+ }
}
-/// \brief Print usage information
+// Print usage information.
void
CommandOptions::usage() {
cout << "Usage: badpacket [options] query\n"
"\n"
- "Sends a sequence of packets to the specified nameserver and prints the results.\n"
- "The packets are valid query packets but the flags field (third and fourth bytes\n"
- "of the packet) can be set to arbitrary values using the command-line switches.\n"
+ "Sends a sequence of DNS messages to the specified nameserver and prints the\n"
+ " results. The packets are valid query packets but certain aspects of the\n"
+ " packets (such as the flags fields, section count fields and message size) can\n"
+ "be set to arbitrary values using the command-line switches.\n"
"\n"
"In the following list of command-line switches, '<range>' indicates a range of\n"
"values specified as either <integer> or <integer1>-<integer2> (e.g. both '42'\n"
"and '0-1' would be valid values for range). The program sends a sequence of\n"
- "packets that contain all combinations of the flag values. For example,\n"
+ "messages that contain all combinations of the flag values. For example,\n"
"specifying:\n"
"\n"
"--tc 0-1 --op 1-4 --aa 1 --rd 0-1\n"
@@ -174,6 +201,8 @@ CommandOptions::usage() {
"The long form of the option is given. It can also be specified as a single-\n"
"character short-form, which is listed in sqare brackets in the description.\n"
"\n"
+ "General options are:\n"
+ "\n"
"--help [-h] Prints this message and exits.\n"
"--version [-v] Prints the program version number.\n"
"--address <address> [-a] Address of nameserver, which defaults to 127.0.0.1\n"
@@ -181,49 +210,60 @@ CommandOptions::usage() {
"--timeout <value> [-t] Timeout value for the query. Specified in ms, it\n"
" defaults to 500ms.\n"
"\n"
- "The following options set fields in the outgoing DNS message flags word\n"
+ "The following options set fields in the outgoing DNS message flags word:\n"
"\n"
"--qr <range> [-Q] Set query/response bit. Valid <range> is 0-1.\n"
"--op <range> [-O] Set opcode. Valid <range> is 0-15.\n"
"--aa <range> [-A] Set authoritative answer bit. Valid <range> is 0-1.\n"
"--tc <range> [-T] Set truncated bit. Valid <range> is 0-1.\n"
- "--rd <range> [-T] Set recursion desired bit. Valid <range> is 0-1.\n"
- "--ra <range> [-T] Set recursion available bit. Valid <range> is 0-1.\n"
+ "--rd <range> [-D] Set recursion desired bit. Valid <range> is 0-1.\n"
+ "--ra <range> [-D] Set recursion available bit. Valid <range> is 0-1.\n"
"--z <range> [-Z] Set zero (reserved) bit. Valid <range> is 0-1.\n"
"--ad <range> [-U] Set authenticated data bit. Valid <range> is 0-1.\n"
"--cd <range> [-C] Set checking disabled bit. Valid <range> is 0-1.\n"
"--rc <range> [-E] Set rcode value. Valid <range> is 0-15\n"
"\n"
"The following options set the various section counts (independent of what is\n"
- "actually in the section)\n"
+ "actually in the section):\n"
+ "\n"
+ "--qc <range> [-Y] Set the query count. Valid range is 0-65535.\n"
+ "--ac <range> [-W] Set the answer count. Valid range is 0-65535.\n"
+ "--uc <range> [-H] Set the authority count. Valid range is 0-65535.\n"
+ "--dc <range> [-I] Set the additional count. Valid range is 0-65535.\n"
+ "\n"
+ "Other options are:\n"
"\n"
- "--qc <range> [-Q] Set the query count. Valid range is 0-65535.\n"
- "--ac <range> [-Q] Set the answer count. Valid range is 0-65535.\n"
- "--uc <range> [-Q] Set the authority count. Valid range is 0-65535.\n"
- "--dc <range> [-Q] Set the additional count. Valid range is 0-65535.\n"
+ "--ms <range> [-M] Set the size of the message. If the specified size\n"
+ " smaller than the natural message size, it is truncated.\n"
+ " If longer, the packet is extended with random values.\n"
+ " Valid range is 2 to 65536\n"
"\n"
- "query Name to query for. The query is for an 'IN' A record.\n"
- " If not given, the name 'www.example.com' is used.\n"
+ "query Name to query for. The query is for an 'IN' A record. If\n"
+ " not given, the name 'www.example.com' is used.\n"
+ "\n"
+ "The output is a single (very long) line containing the settings of the various\n"
+ "fields. The settings for the outgoing packet are reported in uppercase letters\n"
+ "and that of the returned packet in lowercase.\n"
;
}
-/// \brief Print version information
+// Print version information,
void
CommandOptions::version() {
cout << BADPACKET_VERSION << "\n";
}
-// Process single flag
+// Process single flag that can be stored in the options_ member.
void
CommandOptions::processOptionValue(int c, const char* value) {
- // Get values for this option
+ // Get values for this option.
int index = OptionInfo::getIndex(c);
const char* name = OptionInfo::name(index);
uint32_t minval = OptionInfo::minval(index);
uint32_t maxval = OptionInfo::maxval(index);
- // Split the string up into one or two tokens
+ // Split the string up into one or two tokens.
vector<string> tokens = isc::strutil::tokens(string(value), "-");
if ((tokens.size() < 1) || (tokens.size() > 2)) {
isc_throw(isc::BadValue, "value given for " << name << " is '" << value <<
@@ -231,52 +271,62 @@ CommandOptions::processOptionValue(int c, const char* value) {
}
// Convert to uint32.
- int i = 0;
try {
- do {
- limits_[index][i] = boost::lexical_cast<uint32_t>(tokens[i]);
- ++i;
- } while (i < tokens.size());
+ options_[index].minimum = boost::lexical_cast<uint32_t>(tokens[0]);
+ if (tokens.size() == 2) {
+ options_[index].maximum = boost::lexical_cast<uint32_t>(tokens[1]);
+ } else {
+ options_[index].maximum = options_[index].minimum;
+ }
} catch (boost::bad_lexical_cast) {
isc_throw(isc::BadValue, "value given for " << name << " is '" << value <<
"': it must be in the form 'int' or 'int1-int2'");
}
// Set the limits in the correct order.
- if (tokens.size() == 1) {
- limits_[index][1] = limits_[index][0];
- } else if (limits_[index][0] > limits_[index][1]) {
- swap(limits_[index][0], limits_[index][1]);
+ if (options_[index].minimum > options_[index].maximum) {
+ swap(options_[index].minimum, options_[index].maximum);
}
- // Check that tokens lie inside the allowed ranges
- if ((tokens.size() == 1) &&
- ((limits_[index][0] < OptionInfo::minval(index)) || (limits_[index][0] > maxval))) {
- isc_throw(isc::BadValue, "the value of " << limits_[index][0] <<
+ // Check that tokens lie inside the allowed ranges.
+ if ((tokens.size() == 2) &&
+ ((options_[index].minimum < OptionInfo::minval(index)) || (options_[index].maximum > maxval))) {
+ isc_throw(isc::BadValue, "the value of " << options_[index].minimum <<
" given for " << name << " is outside the range of " <<
minval << " to " << maxval);
- } else if (limits_[index][0] < minval) {
- isc_throw(isc::BadValue, "the lower limit of " << limits_[index][0] <<
+ } else if (options_[index].minimum < minval) {
+ isc_throw(isc::BadValue, "the lower limit of " << options_[index].minimum <<
" given for " << name << " is below the minimum permitted"
" value of " << minval);
- } else if (limits_[index][1] > maxval) {
- isc_throw(isc::BadValue, "the upper limit of " << limits_[index][1] <<
+ } else if (options_[index].maximum > maxval) {
+ isc_throw(isc::BadValue, "the upper limit of " << options_[index].maximum <<
" given for " << name << " is above the maximum permitted"
" value of " << maxval);
}
+
+ // And finally note that the option was specified on the command line
+ options_[index].present = true;
}
-// Minimum and maximum value of the flag
+// Return information about the option - minimum and maximum values and whether
+// it was actually specified. (Note that if it wasn't, the maximum and minimum
+// values will have been set to the default recorded in the OptionInfo class.)
uint32_t
CommandOptions::minimum(int index) const {
OptionInfo::checkIndex(index);
- return (limits_[index][0]);
+ return (options_[index].minimum);
}
uint32_t
CommandOptions::maximum(int index) const {
OptionInfo::checkIndex(index);
- return (limits_[index][1]);
+ return (options_[index].maximum);
+}
+
+bool
+CommandOptions::present(int index) const {
+ OptionInfo::checkIndex(index);
+ return (options_[index].present);
}
} // namespace badpacket
diff --git a/tests/tools/badpacket/command_options.h b/tests/tools/badpacket/command_options.h
index 06ed0ab..fc819e9 100644
--- a/tests/tools/badpacket/command_options.h
+++ b/tests/tools/badpacket/command_options.h
@@ -29,24 +29,25 @@ namespace badpacket {
/// This class is responsible for parsing the command-line and storing the
/// specified options.
///
-/// Each option setting the state of one of the fields in the flags word in the
-/// DNS packet can be specified as either:
+/// Some of the options perform general control (like setting the address of the
+/// nameserver under test, while the rest set values in the DNS message being
+/// sent. Each of the latter options can be specified as either:
///
/// - \c --option value
/// - \c --option value1-value2
///
/// Either way, two values are extracted the low value and the high value (in
-/// the former case, both are the same). The values are stored in an array
-/// and can be returned on request.
+/// the former case, both are the same). The values are stored and can be
+/// returned on request.
///
-/// For simplicity, the class also takes care of the --help and --version flags,
+/// For simplicity, the class takes care of the --help and --version flags,
/// each of which will cause a message to be printed to stdout and the program
/// to terminate.
class CommandOptions {
public:
- /// \brief CommandOptions Constructor
+ /// \brief Default Constructor
///
/// Set values to defaults.
CommandOptions() {
@@ -55,6 +56,12 @@ public:
/// \brief Return minimum value for option
///
+ /// Applicable only to an option affecting a field in the message, this
+ /// method returns the minimum value that was given on the command line.
+ /// (If only a single value was given, it will be that value returned.)
+ /// If the option was not specified on the command line, the default value
+ /// set in the OptionsInfo class will be returned.
+ ///
/// \param index Index of the command-line option.
///
/// \return uint32_t holding the minimum value given (or the default if
@@ -63,23 +70,37 @@ public:
/// \brief Return maximum value for option
///
+ /// Applicable only to an option affecting a field in the message, this
+ /// method returns the maximum value that was given on the command line.
+ /// (If only a single value was given, it will be that value returned.)
+ /// If the option was not specified on the command line, the default value
+ /// set in the OptionsInfo class will be returned.
+ ///
/// \param index Index of the command-line option.
///
/// \return uint32_t holding the maximum value given (or the default if
/// the option was not specified on the command line).
uint32_t maximum(int index) const;
- /// \brief Return Target Address
+ /// \brief Reports if option was given on command line
+ ///
+ /// \param index Index of the command-line option.
+ ///
+ /// \return true if the option was present, false if not.
+ bool present(int index) const;
+
+
+ /// \brief Return target address
std::string getAddress() const {
return address_;
}
- /// \brief Return Target Port
+ /// \brief Return target port
uint16_t getPort() const {
return port_;
}
- /// \brief Return Timeout
+ /// \brief Return timeout
int getTimeout() const {
return timeout_;
}
@@ -89,19 +110,12 @@ public:
return qname_;
}
- /// \brief Reset To Defaults
- void reset() {
- address_ = "127.0.0.1";
- port_ = 53;
- timeout_ = 500;
- qname_ = "www.example.com";
-
- for (int i = 0; i < OptionInfo::SIZE; ++i) {
- limits_[i][0] = limits_[i][1] = OptionInfo::defval(i);
- }
- }
+ /// \brief Reset to defaults
+ ///
+ /// Resets the CommandOptions object to default values.
+ void reset();
- /// \brief Parse Command Line
+ /// \brief Parse command line
///
/// Parses the command line and stores the selected options. The parsing
/// also handles the --help and --version commands: both of these will cause
@@ -112,15 +126,13 @@ public:
/// \param argv Argument value array passed to main().
void parse(int argc, char* const argv[]);
- /// \brief Print Usage Information And Exit Program
+ /// \brief Print usage information and exit program
void usage();
- /// \brief Print Version Information And Exit Program
+ /// \brief Print version information and exit program
void version();
- // The following are protected to aid testing
-
-protected:
+private:
/// \brief Process Option Value
///
/// Processes a specific command-line option, interpreting the value and
@@ -133,9 +145,11 @@ protected:
// Member variables
-private:
- uint32_t limits_[OptionInfo::SIZE][2];
- ///< Value of options (minimum and maximum)
+ struct {
+ uint32_t minimum; ///< Minimum value specified
+ uint32_t maximum; ///< Maximum value specified
+ bool present; ///< true if specified on command line
+ } options_[OptionInfo::SIZE]; ///< Information about command options
std::string address_; ///< Address to where query is sent
uint16_t port_; ///< Target port
int timeout_; ///< Timeout for query
diff --git a/tests/tools/badpacket/header_flags.h b/tests/tools/badpacket/header_flags.h
index 3c84439..5d74e75 100644
--- a/tests/tools/badpacket/header_flags.h
+++ b/tests/tools/badpacket/header_flags.h
@@ -34,19 +34,19 @@ public:
reset();
}
- /// \brief Reset Values to Zero
+ /// \brief Reset values to zero
///
/// Clears all flags.
void reset() {
setValue(0);
}
- /// \brief Get Header Flags as 16-bit Value
+ /// \brief Get header flags as 16-bit value
uint16_t getValue() const {
return (flags_);
}
- /// \brief Set Header Flags as 16-Bit Value
+ /// \brief Set header flags as 16-bit value
///
/// \param value 16-bit value to put into object as representing the
/// header flags.
@@ -54,7 +54,7 @@ public:
flags_ = value;
}
- /// \brief Get Field
+ /// \brief Get field
///
/// Return the value of a bit field in the flags word.
///
@@ -66,18 +66,18 @@ public:
return ((flags_ & OptionInfo::mask(index)) >> OptionInfo::offset(index));
}
- /// \brief Set Field
+ /// \brief Set field
///
/// Sets the value of a bit field.
///
/// \param int Index of the bit field in the OptionInfo data structure
/// \param value Value to set. If the value is more than the field can
- /// hold, it is set to the maximum.
+ /// hold, a BadValue exception is thrown.
void set(int index, uint16_t value) {
- // Declare an OptionInfo object for brevity
- OptionInfo o;
- // Ensure in range
+ // Declare an OptionInfo object for brevity and check the index is
+ // valid.
+ OptionInfo o;
o.checkIndex(index);
// Ensure the value is within limits and throw an exception if not. (This
diff --git a/tests/tools/badpacket/option_info.cc b/tests/tools/badpacket/option_info.cc
index ccb44c4..e1c1f78 100644
--- a/tests/tools/badpacket/option_info.cc
+++ b/tests/tools/badpacket/option_info.cc
@@ -21,6 +21,16 @@ namespace {
// information is duplicated here and where the long options are specified for
// getopt_long, but this inconvenience is outweighed by the simplified command
// processing.
+//
+// Fields are:
+// * Short option name
+// * Long option name
+// * Offset of 16-bit word holding datum in DNS message (if applicable)
+// * Bit mask for the data (if applicable)
+// * Offset of the bit field in the word (if applicable)
+// * Default value (this can be ignored if applicable)
+// * Minimum value specified on command line
+// * Maximum value specified on command line
isc::badpacket::OptionInfo::Parameter option_information[] = {
{'Q', "qr", 2, 0x8000, 15, 0, 0, 1},
@@ -36,7 +46,8 @@ isc::badpacket::OptionInfo::Parameter option_information[] = {
{'Y', "qc", 4, 0, 0, 1, 0, 0xFFFF},
{'W', "ac", 6, 0, 0, 0, 0, 0xFFFF},
{'H', "uc", 8, 0, 0, 0, 0, 0xFFFF},
- {'I', "dc", 10, 0, 0, 0, 0, 0xFFFF}
+ {'I', "dc", 10, 0, 0, 0, 0, 0xFFFF},
+ {'M', "ms", 0, 0, 0, 0, 1, 65536}
};
} // Anonymous namespace
@@ -48,7 +59,7 @@ namespace badpacket {
int
OptionInfo::getIndex(int c) {
for (int i = 0; i < SIZE; ++i) {
- if (c == option_information[i].short_form) {
+ if (option_information[i].short_form == c) {
return (i);
}
}
diff --git a/tests/tools/badpacket/option_info.h b/tests/tools/badpacket/option_info.h
index 8b4e4b9..a340c1d 100644
--- a/tests/tools/badpacket/option_info.h
+++ b/tests/tools/badpacket/option_info.h
@@ -27,47 +27,56 @@ namespace badpacket {
/// that require values and which control data put in the DNS message sent to
/// the remote system.
///
-/// Currently all of these options correspond to fields in the flags word of the
-/// DNS message header, so the information includes details about the position
-/// of the fields and an appropriate bit mask.
+/// Some of the fields are no applicable to all options. For example, some of
+/// the options correspond to fields in the flags word of the DNS message
+/// header, so the information includes details about the position of the fields
+/// and an appropriate bit mask.
///
/// Note that the class does not hold values specified on the command line - it
-/// only holds information about command-line options.
+/// only holds information about the available options.
class OptionInfo {
public:
/// \brief Array Indexes
///
- /// The data for the flags options are held in an array. Although an enum,
- /// only the numeric values are used - they are indexes into arrays.
+ /// The data for the flags options are held in an array. Although declared
+ /// as an enum, only the numeric values are used as they are the indexes
+ /// into the array.
enum Index {
- QR = 0, // Query/response
- OP = 1, // Opcode
- AA = 2, // Authoritative answer
- TC = 3, // Truncated
- RD = 4, // Recursion desired
- RA = 5, // Recursion available
- Z = 6, // Zero (reserved)
- AD = 7, // Authenticated data
- CD = 8, // Checking disabled
- RC = 9, // Response code
- QC = 10, // Query count
- AC = 11, // Answer count
- UC = 12, // Authority count
- DC = 13, // Additional count
- SIZE = 14 // Number of index values
+ FLAGS_START = 0, // Start of flags field codes
+ QR = 0, // Query/response
+ OP = 1, // Opcode
+ AA = 2, // Authoritative answer
+ TC = 3, // Truncated
+ RD = 4, // Recursion desired
+ RA = 5, // Recursion available
+ Z = 6, // Zero (reserved)
+ AD = 7, // Authenticated data
+ CD = 8, // Checking disabled
+ RC = 9, // Response code
+ FLAGS_END = 9, // End of flags field codes
+ COUNT_START = 10, // Start of count fields
+ QC = 10, // Query count
+ AC = 11, // Answer count
+ UC = 12, // Authority count
+ DC = 13, // Additional count
+ COUNT_END = 13, // End of count fields
+ OTHER_START = 14, // Start of other fields
+ MS = 14, // Message size
+ OTHER_END = 14, // End of other fields
+ SIZE = 15 // Number of index values
};
- /// \brief Option Parameters
+ /// \brief Option parameters
///
/// Defines a structure that holds information associated with each of the
- /// flags field command options. Note all members of the structure are
- /// relevant to all options
+ /// flags field command options. Not all members of the structure are
+ /// relevant to all options.
struct Parameter {
const char short_form; // Short form of the command switch
const char* long_form; // Long form of the command switch
- int word; // Byte offset of word in the header
+ int word; // Byte offset of word in message header
uint16_t mask; // Bit mask of field in the flags word
int offset; // Offset of field in flags word
uint32_t defval; // Default value
@@ -77,14 +86,15 @@ public:
/// \brief Return index for command option
///
- /// Given the short form of a switch, return the index into the options
- /// array.
+ /// Given the short form of a command-line option, return the index in the
+ /// options array corresponding to that option.
///
/// \param c The character that is the short form of the command line option.
- /// An 'int' is used as the value passed will be the return vaue from
- /// 'getopt()' (or equivalent) which is an int.
+ /// An 'int' is used as the value passed will be the return value
+ /// from 'getopt()' (or equivalent) which is an int. If the
+ /// character is not found, an exception will be thrown.
///
- /// \return A valid index value (else an exception is thrown).
+ /// \return A valid index value.
static int getIndex(int c);
/// \brief Return long form of command switch for this field
@@ -101,7 +111,7 @@ public:
///
/// \param index A valid index (one of the values in the 'Index' enum).
///
- /// \return The offset in the header foe this datum.
+ /// \return The offset in the header for this datum.
static int word(int index);
/// \brief Return mask associated with switch field
@@ -109,32 +119,34 @@ public:
/// \param index A valid index (one of the values in the 'Index' enum).
///
/// \return The mask for this particular option in the DNS message flags
- /// field.
+ /// word. The returned value is only valid for options that
+ /// correspond to fields in the flags word.
static uint16_t mask(int index);
- /// \brief Return offset associated with switch field
+ /// \brief Return offset associated with option field
///
/// \param index A valid index (one of the values in the 'Index' enum).
///
/// \return The offset of the field corresponding to this option in the DNS
- /// message flags field.
+ /// message flags field. The returned value is only valid for
+ /// options that correpond to fields in the flags word.
static int offset(int index);
- /// \brief Return minimum allowed value of field
+ /// \brief Return minimum allowed value of an option
///
/// \param index A valid index (one of the values in the 'Index' enum).
///
- /// \return Minimum allowed value for this option. This is usually 0.
+ /// \return Minimum allowed value for this option.
static uint32_t minval(int index);
- /// \brief Return default value of a field
+ /// \brief Return default value of an option
///
/// \param index A valid index (one of the values in the 'Index' enum).
///
/// \return Default value for this option
static uint32_t defval(int index);
- /// \brief Return maximum allowed value of field
+ /// \brief Return maximum allowed value of an option
///
/// \param index A valid index (one of the values in the 'Index' enum).
///
@@ -148,7 +160,6 @@ public:
/// correspond to one of the valid indexes in the 'Index' enum.
///
/// \param index An index value.
- ///
static void checkIndex(int i) {
if ((i < 0) || (i >= SIZE)) {
isc_throw(isc::OutOfRange, "option index must be in the range "
diff --git a/tests/tools/badpacket/scan.cc b/tests/tools/badpacket/scan.cc
index f8cee96..18924a9 100644
--- a/tests/tools/badpacket/scan.cc
+++ b/tests/tools/badpacket/scan.cc
@@ -17,7 +17,7 @@
#include <sstream>
#include <string>
-#include <boost/scoped_ptr.hpp>
+#include <stdlib.h>
#include <asio.hpp>
@@ -60,109 +60,135 @@ Scan::scan(const CommandOptions& options) {
MessageRenderer renderer(*msgbuf);
message.toWire(renderer);
- iterateFlagsFields(msgbuf, options);
+ iterateFlagsStart(msgbuf, options);
}
-// Iterate through the various settings in the flags fields
+// Iterate through the various settings in the flags fields.
void
-Scan::iterateFlagsFields(OutputBufferPtr& msgbuf, const CommandOptions& options) {
-
- // Loop through the flags setting data. This is quite deep nesting,
- // but we will continue to indent so as to make things clear (for those
- // readers lucky enough to have a wide screen).
+Scan::iterateFlagsStart(OutputBufferPtr& msgbuf, const CommandOptions& options) {
HeaderFlags flags;
- for (uint32_t qr = options.minimum(OptionInfo::QR);
- qr <= options.maximum(OptionInfo::QR); ++qr) {
- flags.set(OptionInfo::QR, qr);
-
- for (uint32_t op = options.minimum(OptionInfo::OP);
- op <= options.maximum(OptionInfo::OP); ++op) {
- flags.set(OptionInfo::OP, op);
-
- for (uint32_t aa = options.minimum(OptionInfo::AA);
- aa <= options.maximum(OptionInfo::AA); ++aa) {
- flags.set(OptionInfo::AA, aa);
-
- for (uint32_t tc = options.minimum(OptionInfo::TC);
- tc <= options.maximum(OptionInfo::TC); ++tc) {
- flags.set(OptionInfo::TC, tc);
-
- for (uint32_t rd = options.minimum(OptionInfo::RD);
- rd <= options.maximum(OptionInfo::RD); ++rd) {
- flags.set(OptionInfo::RD, rd);
-
- for (uint32_t ra = options.minimum(OptionInfo::RA);
- ra <= options.maximum(OptionInfo::RA); ++ra) {
- flags.set(OptionInfo::RA, ra);
-
- for (uint32_t z = options.minimum(OptionInfo::Z);
- z <= options.maximum(OptionInfo::Z); ++z) {
- flags.set(OptionInfo::Z, z);
-
- for (uint32_t ad = options.minimum(OptionInfo::AD);
- ad <= options.maximum(OptionInfo::AD); ++ad) {
- flags.set(OptionInfo::AD, ad);
-
- for (uint32_t cd = options.minimum(OptionInfo::CD);
- cd <= options.maximum(OptionInfo::CD); ++cd) {
- flags.set(OptionInfo::CD, cd);
-
- for (uint32_t rc = options.minimum(OptionInfo::RC);
- rc <= options.maximum(OptionInfo::RC); ++rc) {
- flags.set(OptionInfo::RC, rc);
-
- // Set the flags in the message.
- msgbuf->writeUint16At(flags.getValue(), 2);
-
- // And for this flag combination, iterate over the section
- // count fields.
- iterateCountFields(msgbuf, options);
- }
- }
- }
- }
- }
- }
- }
+ iterateFlags(msgbuf, options, flags, OptionInfo::FLAGS_START,
+ OptionInfo::FLAGS_END);
+}
+void
+Scan::iterateFlags(OutputBufferPtr& msgbuf, const CommandOptions& options,
+ HeaderFlags& flags, int index, int maxindex)
+{
+ // Is the index valid?
+ if (index <= maxindex) {
+
+ // Index is valid, did the command line specify a range of values for
+ // this field?
+ if (options.present(index)) {
+
+ // It did, so loop between minimum and maximum values given.
+ for (uint32_t i = options.minimum(index);
+ i <= options.maximum(index); ++i) {
+ flags.set(index, i);
+
+ // Recurse to set the next option.
+ iterateFlags(msgbuf, options, flags, (index + 1), maxindex);
}
+ } else {
+
+ // Not specified on command line, so set the default value in the
+ // flags and process the next index.
+ flags.set(index, OptionInfo::defval(index));
+ iterateFlags(msgbuf, options, flags, (index + 1), maxindex);
}
+ } else {
+
+ // Index is not valid, so we have recursed enough to process all the
+ // flags fields. Set the value in the message header and call the next
+ // stage in the processing.
+ //
+ // (In the next statement, the "word" offset of in the header is the
+ // same for all flags options, so the value for an arbitrary field
+ // (QR) has been used.)
+ msgbuf->writeUint16At(flags.getValue(),
+ OptionInfo::word(OptionInfo::QR));
+ iterateCountStart(msgbuf, options);
}
}
// Iterate through the various count fields
void
-Scan::iterateCountFields(OutputBufferPtr& msgbuf, const CommandOptions& options) {
- for (uint32_t qc = options.minimum(OptionInfo::QC);
- qc <= options.maximum(OptionInfo::QC); ++qc) {
- msgbuf->writeUint16At(qc, OptionInfo::word(OptionInfo::QC));
+Scan::iterateCountStart(OutputBufferPtr& msgbuf, const CommandOptions& options)
+{
+ iterateCount(msgbuf, options, OptionInfo::COUNT_START,
+ OptionInfo::COUNT_END);
+}
+
+void
+Scan::iterateCount(OutputBufferPtr& msgbuf, const CommandOptions& options,
+ int index, int maxindex)
+{
+ // If the index is valid, process the iteration over the range for this
+ // flags field.
+ if (index <= maxindex) {
+
+ // Index is valid, did the command line specify a range of values for
+ // this field?
+ if (options.present(index)) {
+
+ // It did, so loop between minimum and maximum values given.
+ for (uint32_t i = options.minimum(index);
+ i <= options.maximum(index); ++i) {
+
+ // Set the value in the message buffer header and recurse to
+ // the next option.
+ msgbuf->writeUint16At(i, OptionInfo::word(index));
+ iterateCount(msgbuf, options, (index + 1), maxindex);
+ }
+ } else {
+
+ // Not specified on command line, so do change anything and process
+ // the next index.
+ iterateCount(msgbuf, options, (index + 1), maxindex);
+ }
+ } else {
+
+ // Index is not valid, so we have recursed enough to process all the
+ // flags fields. Do the next stage of the processing.
+ sizeMessage(msgbuf, options);
+ }
+}
- for (uint32_t ac = options.minimum(OptionInfo::AC);
- ac <= options.maximum(OptionInfo::AC); ++ac) {
- msgbuf->writeUint16At(ac, OptionInfo::word(OptionInfo::AC));
+// Alter the message size.
+void
+Scan::sizeMessage(OutputBufferPtr& msgbuf, const CommandOptions& options) {
- for (uint32_t uc = options.minimum(OptionInfo::UC);
- uc <= options.maximum(OptionInfo::UC); ++uc) {
- msgbuf->writeUint16At(uc, OptionInfo::word(OptionInfo::UC));
+ if (options.present(OptionInfo::MS)) {
- for (uint32_t dc = options.minimum(OptionInfo::DC);
- dc <= options.maximum(OptionInfo::DC); ++dc) {
- msgbuf->writeUint16At(dc, OptionInfo::word(OptionInfo::DC));
+ // Iterate over the range of message sizes
+ for (size_t i = options.minimum(OptionInfo::MS);
+ i <= options.maximum(OptionInfo::MS); ++i) {
- // Do the I/O.
- scanOne(msgbuf, options);
+ // Copy the data into a new buffer.
+ OutputBufferPtr newbuf(new OutputBuffer(i));
+ newbuf->writeData(msgbuf->getData(), min(msgbuf->getLength(), i));
- }
+ // Pad with junk (actually pseudo-random data) if the new buffer is
+ // longer than the old.
+ for (size_t j = newbuf->getLength(); j < i; ++j) {
+ newbuf->writeUint8(static_cast<uint8_t>(rand() & 0xFFU));
}
+
+ // ... and process.
+ scanOne(newbuf, options);
}
+ } else {
+
+ // No packet size given, just process the message as it.
+ scanOne(msgbuf, options);
}
}
// Perform the message exchange for a single combination command options.
void
Scan::scanOne(isc::dns::OutputBufferPtr& msgbuf, const CommandOptions& options) {
-
- // Store the interpretation of the flags field.
- string fields = getFields(msgbuf);
+ // Store the interpretation of outgoing message.
+ string fields = string("(") + getFields(msgbuf) + string(")");
// Do the I/O, waiting for a reply
OutputBufferPtr replybuf(new OutputBuffer(512));
@@ -176,7 +202,7 @@ Scan::scanOne(isc::dns::OutputBufferPtr& msgbuf, const CommandOptions& options)
status = "SUCCESS";
// Parse the reply and get the fields
- returned = getFields(replybuf);
+ returned = string("(") + getFields(replybuf) + string(")");
lowercase(returned);
}
break;
@@ -194,58 +220,59 @@ Scan::scanOne(isc::dns::OutputBufferPtr& msgbuf, const CommandOptions& options)
}
// ... and output the result
- cout << status << ": (" << fields << ") (" << returned << ")\n";
+ cout << status << ": " << fields << " " << returned << "\n";
}
// Get interpretation of the message fields.
-//
-// This takes the second and third bytes of the passed buffer and interprets
-// the values. A summary string listing them is returned.
std::string
Scan::getFields(isc::dns::OutputBufferPtr& msgbuf) {
- HeaderFlags flags;
- // Extract the flags field from the buffer
+ // Header flags. (Note that all come from the same word in the message, so
+ // using the word offset for the QR flag as the position in the buffer from
+ // which to extract the values is valid.)
+ HeaderFlags flags;
InputBuffer inbuf(msgbuf->getData(), msgbuf->getLength());
inbuf.setPosition(OptionInfo::word(OptionInfo::QR));
flags.setValue(inbuf.readUint16());
std::ostringstream os;
os << std::hex << std::uppercase <<
- "QR:" << flags.get(OptionInfo::QR) << " " <<
- "OP:" << flags.get(OptionInfo::OP) << " " <<
- "AA:" << flags.get(OptionInfo::AA) << " " <<
- "TC:" << flags.get(OptionInfo::TC) << " " <<
- "RD:" << flags.get(OptionInfo::RD) << " " <<
- "RA:" << flags.get(OptionInfo::RA) << " " <<
- "Z:" << flags.get(OptionInfo::Z) << " " <<
- "AD:" << flags.get(OptionInfo::AD) << " " <<
- "CD:" << flags.get(OptionInfo::CD) << " " <<
- "RC:" << flags.get(OptionInfo::RC);
-
- // Section count fields
- os << " ";
-
+ "QR:" << flags.get(OptionInfo::QR) <<
+ " OP:" << flags.get(OptionInfo::OP) <<
+ " AA:" << flags.get(OptionInfo::AA) <<
+ " TC:" << flags.get(OptionInfo::TC) <<
+ " RD:" << flags.get(OptionInfo::RD) <<
+ " RA:" << flags.get(OptionInfo::RA) <<
+ " Z:" << flags.get(OptionInfo::Z) <<
+ " AD:" << flags.get(OptionInfo::AD) <<
+ " CD:" << flags.get(OptionInfo::CD) <<
+ " RC:" << flags.get(OptionInfo::RC);
+
+ // Section count fields.
inbuf.setPosition(OptionInfo::word(OptionInfo::QC));
- os << std::hex << std::uppercase <<
- "QC:" << inbuf.readUint16() << " ";
+ os << std::dec << std::uppercase <<
+ " QC:" << inbuf.readUint16();
inbuf.setPosition(OptionInfo::word(OptionInfo::AC));
- os << std::hex << std::uppercase <<
- "AC:" << inbuf.readUint16() << " ";
+ os << std::dec << std::uppercase <<
+ " AC:" << inbuf.readUint16();
inbuf.setPosition(OptionInfo::word(OptionInfo::UC));
- os << std::hex << std::uppercase <<
- "UC:" << inbuf.readUint16() << " ";
+ os << std::dec << std::uppercase <<
+ " UC:" << inbuf.readUint16();
inbuf.setPosition(OptionInfo::word(OptionInfo::DC));
- os << std::hex << std::uppercase <<
- "DC:" << inbuf.readUint16();
+ os << std::dec << std::uppercase <<
+ " DC:" << inbuf.readUint16();
+
+ // ... and message size.
+ os << std::dec << std::uppercase <<
+ " MS:" << msgbuf->getLength();
return (os.str());
}
-// Perform the I/O.
+// Perform the I/O to the nameserver.
void
Scan::performIO(OutputBufferPtr& sendbuf, OutputBufferPtr& recvbuf,
const CommandOptions& options)
@@ -265,7 +292,7 @@ Scan::performIO(OutputBufferPtr& sendbuf, OutputBufferPtr& recvbuf,
service_->run();
}
-// I/O Callback. Called when the message exchange compltes or times out.
+// I/O Callback. Called when the message exchange completes or times out.
void
Scan::operator()(IOFetch::Result result) {
@@ -277,7 +304,5 @@ Scan::operator()(IOFetch::Result result) {
service_->stop();
}
-
-
} // namespace test
} // namespace isc
diff --git a/tests/tools/badpacket/scan.h b/tests/tools/badpacket/scan.h
index 09eb544..65084e2 100644
--- a/tests/tools/badpacket/scan.h
+++ b/tests/tools/badpacket/scan.h
@@ -26,16 +26,16 @@
#include <dns/buffer.h>
#include "command_options.h"
+#include "header_flags.h"
namespace isc {
namespace badpacket {
/// \brief Field Scan
///
-/// This class implements a field scan. Given a CommandOptions object, it
-/// will cycle through combinations of the given options, sending and
-/// receiving packets. For each packet exchange, a summary is written to
-/// stdout.
+/// This class implements a field scan. Given a CommandOptions object, it will
+/// cycle through combinations of the given options, sending and receiving
+/// messages. For each packet exchange, a summary is written to stdout.
class Scan : public asiolink::IOFetch::Callback {
public:
@@ -46,6 +46,8 @@ public:
/// \brief Run Scan
///
+ /// Actually performs the scan for the combination of options.
+ ///
/// \param options Command-line options
void scan(const CommandOptions& options);
@@ -59,39 +61,97 @@ public:
virtual void operator()(asiolink::IOFetch::Result result);
private:
- /// \brief Set Flags Fields Options
+ /// \brief Iterate over flags fields options
+ ///
+ /// This method relies on the fact that data concerning the settings for
+ /// the fields in the flags word of the DNS message are held at adjacent
+ /// elements in the various data arrays and so can be accessed by a set
+ /// of contiguous index values.
///
- /// Iterates through all combinations of the DNS message flags fields specified
- /// on the command line and calls scanOne for each combination.
+ /// The method is passed an index value and the maximum valid index value.
+ /// If a set of values for the field at the given index was specified on
+ /// the command line, it loops through those values and sets the appropriate
+ /// value in the a copy of the DNS message header flags. It then calls
+ /// itself with an incremented index. If the value was not given, it just
+ /// sets a default value calls itself (with the incremented index). When
+ /// called with an index above the maximum valid index, the header flags
+ /// in the message buffer are set and the next stage of processing called.
+ ///
+ /// In this way, all fields can be cycled through without the need for a
+ /// single function to nest loops very deeply.
///
/// \param msgbuf Message that will be sent to the remote nameserver. The
/// QID given will be ignored - the value used will be determined by
/// the sending code
/// \param options Command-line options (the important ones being address,
/// port and timeout).
- void iterateFlagsFields(isc::dns::OutputBufferPtr& msgbuf,
- const CommandOptions& options);
+ /// \param flags Header flags
+ /// \param index Index of the current field to be processed.
+ /// \param maxindex Maximum valid index value
+ void iterateFlags(isc::dns::OutputBufferPtr& msgbuf,
+ const CommandOptions& options, HeaderFlags& flags,
+ int index, int maxindex);
+
+ /// \brief Start iterating over flags field options
+ ///
+ /// Kicks off the call to \c iterateFlags by calling it with the initial
+ /// index value.
+ ///
+ /// \param msgbuf Message that will be sent to the remote nameserver. The
+ /// QID given will be ignored - the value used will be determined by
+ /// the sending code
+ /// \param options Command-line options (the important ones being address,
+ /// port and timeout).
+ void iterateFlagsStart(isc::dns::OutputBufferPtr& msgbuf,
+ const CommandOptions& options);
- /// \brief Set Count Fields Options
+ /// \brief Iterate over count fields
///
- /// Iterates through all combinations of the count fields specified on the
- /// command line.
+ /// In a manner similar to iterateFlags, this iterates over all specified
+ /// values for each count field, recursively calling itself to process the
+ /// next field. When all fields have been processed, it chains to the
+ /// next stage of packet processing.
///
- /// The count fields are set by default to question count = 1, all the rest
- /// zero. Command-line options allow these values to be altered, although
- /// the actual contents of the sections are not changed.
+ /// \param msgbuf Message that will be sent to the remote nameserver. The
+ /// QID given will be ignored - the value used will be determined by
+ /// the sending code
+ /// \param options Command-line options (the important ones being address,
+ /// port and timeout).
+ /// \param index Index of the current field to be processed.
+ /// \param maxindex Maximum valid index value
+ void iterateCount(isc::dns::OutputBufferPtr& msgbuf,
+ const CommandOptions& options, int index, int maxindex);
+
+ /// \brief Start iterating over count fields
+ ///
+ /// Kicks off the call to \c iterateCount by calling it with the initial
+ /// index value.
///
/// \param msgbuf Message that will be sent to the remote nameserver. The
/// QID given will be ignored - the value used will be determined by
/// the sending code
/// \param options Command-line options (the important ones being address,
/// port and timeout).
- void iterateCountFields(isc::dns::OutputBufferPtr& msgbuf,
- const CommandOptions& options);
+ void iterateCountStart(isc::dns::OutputBufferPtr& msgbuf,
+ const CommandOptions& options);
+
+ /// \brief Iterate over message sizes
+ ///
+ /// If the message size option is given on the command line, the message
+ /// sent to the remote system is either truncated or extended (with zeroes)
+ /// before being set.
+ ///
+ /// \param msgbuf Message that will be sent to the remote nameserver. The
+ /// QID given will be ignored - the value used will be determined by
+ /// the sending code
+ /// \param options Command-line options (the important ones being address,
+ /// port and timeout).
+ void sizeMessage(isc::dns::OutputBufferPtr& msgbuf,
+ const CommandOptions& options);
/// \brief Scan One Value
///
- /// Performs one exchange of packets with the remote nameserver, sending
+ /// Performs one exchange of messages with the remote nameserver, sending
/// the specified message.
///
/// \param msgbuf Message that will be sent to the remote nameserver. The
@@ -116,8 +176,8 @@ private:
/// \brief Get Fields
///
- /// Interprets the flags fields in a DNS message and converts them to a
- /// terxtual format.
+ /// Interprets the fields in a DNS message and converts them to a brief
+ /// textual format.
///
/// \param msg Message for which the header is value
///
diff --git a/tests/tools/badpacket/tests/command_options_unittest.cc b/tests/tools/badpacket/tests/command_options_unittest.cc
index ec9ccf8..014618e 100644
--- a/tests/tools/badpacket/tests/command_options_unittest.cc
+++ b/tests/tools/badpacket/tests/command_options_unittest.cc
@@ -33,51 +33,151 @@ class CommandOptionsTest : public virtual ::testing::Test,
public:
/// \brief Default Constructor
- CommandOptionsTest() {}
+ CommandOptionsTest()
+ {}
- /// \brief Checks the minimum and maximum () specified for an option
+ /// \brief Check Non-Limit Options
///
- /// Checks the () for one of the options whose values are stored in the
- /// class's limits) array.
+ /// Checks that the options that are NOT related to the message are set to
+ /// their default values.
+ void checkDefaultOtherValues() {
+ EXPECT_EQ("127.0.0.1", getAddress());
+ EXPECT_EQ(53, getPort());
+ EXPECT_EQ(500, getTimeout());
+ EXPECT_EQ("www.example.com", getQname());
+ }
+
+ /// \brief Checks the minimum and maximum value specified for an option
+ ///
+ /// Checks the values for one of the options whose values are stored in the
+ /// class's options_ array.
///
/// \param index Index of the option in the limits_ array
/// \param minval Expected minimum value
/// \param maxval Expected maximum value
- void checkValuePair(int index, uint32_t minval = 0, uint32_t maxval = 0)
- {
+ void checkValuePair(int index, uint32_t minval = 0, uint32_t maxval = 0) {
EXPECT_EQ(minimum(index), minval);
EXPECT_EQ(maximum(index), maxval);
}
- /// \brief Checks that all options giving flags () are zero.
+ /// \brief Checks that all options are at default values
+ ///
+ /// Checks that all options have both their maximum and minimum set to the
+ /// default values.
///
- /// Checks that all options whose () are stored in the class's limits_
- /// array have both their maximum and minimum () set to zero.
- void checkDefaultLimitsValues() {
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
+ /// \param except Index not to check. (This allows options not being tested
+ /// to be checked to see that they are at the default value.) As all
+ /// index values are positive, a negative value means check
+ /// everything.
+ void checkDefaultLimitsValues(int except = -1) {
+ for (int i = 0; i < OptionInfo::SIZE; ++i) {
+ if (i != except) {
+ checkValuePair(i, OptionInfo::defval(i),
+ OptionInfo::defval(i));
+ }
+ }
}
- /// \brief Check Non-Limit Options
+ /// \brief Check valid command option
///
- /// Checks that the options whose () are NOT stored in the limits_
- /// array are set to their default ().
- void
- checkDefaultOtherValues() {
- EXPECT_EQ("127.0.0.1", getAddress());
- EXPECT_EQ(53, getPort());
- EXPECT_EQ(500, getTimeout());
- EXPECT_EQ("www.example.com", getQname());
+ /// Checks that the command line specification of one of the options taking
+ /// a value correctly processes the option.
+ ///
+ /// \param index Option index
+ /// \param optflag Option flag (in the form '--option')
+ /// \param optval Value to be passed to the option.
+ /// \param minval Expected minimum value
+ /// \param maxval Expected maximum value
+ void checkCommandValid(int index, const char* optflag, const char* optval,
+ uint32_t minval, uint32_t maxval) {
+
+ // Set up the command line and parse it.
+ const char* argv[] = {"badpacket", NULL, NULL};
+ argv[1] = optflag;
+ argv[2] = optval;
+ int argc = 3;
+ parse(argc, const_cast<char**>(argv));
+
+ // Check the results. Everything should be at the defaults except for
+ // the specified option, where the minimum and maximum should be as
+ // specified.
+ checkDefaultOtherValues();
+ checkDefaultLimitsValues(index);
+ checkValuePair(index, minval, maxval);
+ }
+
+ /// \brief Check invalid command option
+ ///
+ /// Passed a command with an invalid value, checks that the parsing throws
+ /// a BadValue exception.
+ ///
+ /// \param optflag Option flag (in the form '--option')
+ /// \param optval Value to be passed to the option.
+ void checkCommandInvalid(const char* optflag, const char* optval) {
+
+ // Set up the command line and parse it.
+ const char* argv[] = {"badpacket", NULL, NULL};
+ argv[1] = optflag;
+ argv[2] = optval;
+ int argc = 3;
+ EXPECT_THROW(parse(argc, const_cast<char**>(argv)), isc::BadValue);
+ }
+
+ /// \brief Check one-bit field
+ ///
+ /// Explicitly for those fields in the flags word that are one bit wide,
+ /// perform a series of tests to check that they accept valid values and
+ /// reject invalid ones.
+ ///
+ /// \param index Option index
+ /// \param optflag Option flag (in the form '--option')
+ void checkOneBitField(int index, const char* optflag) {
+ checkCommandValid(index, optflag, "0", 0, 0);
+ checkCommandValid(index, optflag, "1", 1, 1);
+ checkCommandValid(index, optflag, "0-1", 0, 1);
+ checkCommandValid(index, optflag, "1-0", 0, 1);
+ checkCommandInvalid(optflag, "0-3");
+ checkCommandInvalid(optflag, "4");
+ checkCommandInvalid(optflag, "xyz");
+ }
+
+ /// \brief Check four-bit field
+ ///
+ /// Explicitly for those fields in the flags word that are four bits wide,
+ /// perform a series of tests to check that they accept valid values and
+ /// reject invalid ones.
+ ///
+ /// \param index Option index
+ /// \param optflag Option flag (in the form '--option')
+ void checkFourBitField(int index, const char* optflag) {
+ checkCommandValid(index, optflag, "0", 0, 0);
+ checkCommandValid(index, optflag, "15", 15, 15);
+ checkCommandValid(index, optflag, "0-15", 0, 15);
+ checkCommandValid(index, optflag, "15-0", 0, 15);
+ checkCommandInvalid(optflag, "0-17");
+ checkCommandInvalid(optflag, "24");
+ checkCommandInvalid(optflag, "xyz");
+ }
+
+ /// \brief Check sixteen-bit field
+ ///
+ /// Explicitly test the parsing of the fields that can take a 16-bit
+ /// value ranging from 0 to 65535.
+ ///
+ /// \param index Option index
+ /// \param optflag Option flag (in the form '--option')
+ void checkSixteenBitField(int index, const char* optflag) {
+ checkCommandValid(index, optflag, "0", 0, 0);
+ checkCommandValid(index, optflag, "65535", 65535, 65535);
+ checkCommandValid(index, optflag, "0-65535", 0, 65535);
+ checkCommandValid(index, optflag, "65535-0", 0, 65535);
+ checkCommandInvalid(optflag, "0-65536");
+ checkCommandInvalid(optflag, "65537");
+ checkCommandInvalid(optflag, "xyz");
}
};
-// Check that each of the options will be recognised
+// Check that each of the non-message options will be recognised
TEST_F(CommandOptionsTest, address) {
const char* argv[] = {"badpacket", "--address", "192.0.2.1"};
@@ -131,353 +231,70 @@ TEST_F(CommandOptionsTest, parameter) {
checkDefaultLimitsValues();
}
-// The various tests of the different flags
-TEST_F(CommandOptionsTest, qr) {
-
- // Specifying a value of zero, we expect all flag () to be zero
- const char* argv1[] = {"badpacket", "--qr", "0"};
- int argc1 = sizeof(argv1) / sizeof(const char*);
+// Test options representing the flags fields.
- parse(argc1, const_cast<char**>(argv1));
- checkDefaultOtherValues();
- checkDefaultLimitsValues();
-
- // Check that a value of 1 is accepted
- const char* argv2[] = {"badpacket", "--qr", "1"};
- int argc2 = sizeof(argv2) / sizeof(const char*);
-
- parse(argc2, const_cast<char**>(argv2));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR, 1, 1);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
-
- // Check that a range is accepted (in this case, specified backwards)
- const char* argv3[] = {"badpacket", "--qr", "1-0"};
- int argc3 = sizeof(argv3) / sizeof(const char*);
-
- parse(argc3, const_cast<char**>(argv3));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR, 0, 1);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
+TEST_F(CommandOptionsTest, qr) {
+ checkOneBitField(OptionInfo::QR, "--qr");
}
-// The following are cut-and-pasted from the "qr" test. (It is awkward to put
-// the test into a general function because of differing string () and
-// variables.)
-
TEST_F(CommandOptionsTest, op) {
-
- // Specifying a value of zero, we expect all flag () to be zero
- const char* argv1[] = {"badpacket", "--op", "0"};
- int argc1 = sizeof(argv1) / sizeof(const char*);
-
- parse(argc1, const_cast<char**>(argv1));
- checkDefaultOtherValues();
- checkDefaultLimitsValues();
-
- // Check that a value of 1 is accepted
- const char* argv2[] = {"badpacket", "--op", "8"};
- int argc2 = sizeof(argv2) / sizeof(const char*);
-
- parse(argc2, const_cast<char**>(argv2));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP, 8, 8);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
-
- // Check that a range is accepted (in this case, specified backwards)
- const char* argv3[] = {"badpacket", "--op", "14-2"};
- int argc3 = sizeof(argv3) / sizeof(const char*);
-
- parse(argc3, const_cast<char**>(argv3));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP, 2, 14);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
+ checkFourBitField(OptionInfo::OP, "--op");
}
TEST_F(CommandOptionsTest, aa) {
-
- // Specifying a value of zero, we expect all flag () to be zero
- const char* argv1[] = {"badpacket", "--aa", "0"};
- int argc1 = sizeof(argv1) / sizeof(const char*);
-
- parse(argc1, const_cast<char**>(argv1));
- checkDefaultOtherValues();
- checkDefaultLimitsValues();
-
- // Check that a value of 1 is accepted
- const char* argv2[] = {"badpacket", "--aa", "1"};
- int argc2 = sizeof(argv2) / sizeof(const char*);
-
- parse(argc2, const_cast<char**>(argv2));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA, 1, 1);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
-
- // Check that a range is accepted.
- const char* argv3[] = {"badpacket", "--aa", "1-0"};
- int argc3 = sizeof(argv3) / sizeof(const char*);
-
- parse(argc3, const_cast<char**>(argv3));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA, 0, 1);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
+ checkOneBitField(OptionInfo::AA, "--aa");
}
TEST_F(CommandOptionsTest, tc) {
-
- // Specifying a value of zero, we expect all flag () to be zero
- const char* argv1[] = {"badpacket", "--tc", "0"};
- int argc1 = sizeof(argv1) / sizeof(const char*);
-
- parse(argc1, const_cast<char**>(argv1));
- checkDefaultOtherValues();
- checkDefaultLimitsValues();
-
- // Check that a value of 1 is accepted
- const char* argv2[] = {"badpacket", "--tc", "1"};
- int argc2 = sizeof(argv2) / sizeof(const char*);
-
- parse(argc2, const_cast<char**>(argv2));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC, 1, 1);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
-
- // Check that a range is accepted.
- const char* argv3[] = {"badpacket", "--tc", "1-0"};
- int argc3 = sizeof(argv3) / sizeof(const char*);
-
- parse(argc3, const_cast<char**>(argv3));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC, 0, 1);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
+ checkOneBitField(OptionInfo::TC, "--tc");
}
TEST_F(CommandOptionsTest, z) {
-
- // Specifying a value of zero, we expect all flag () to be zero
- const char* argv1[] = {"badpacket", "--z", "0"};
- int argc1 = sizeof(argv1) / sizeof(const char*);
-
- parse(argc1, const_cast<char**>(argv1));
- checkDefaultOtherValues();
- checkDefaultLimitsValues();
-
- // Check that a value of 1 is accepted
- const char* argv2[] = {"badpacket", "--z", "1"};
- int argc2 = sizeof(argv2) / sizeof(const char*);
-
- parse(argc2, const_cast<char**>(argv2));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z, 1, 1);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
-
- // Check that a range is accepted.
- const char* argv3[] = {"badpacket", "--z", "1-0"};
- int argc3 = sizeof(argv3) / sizeof(const char*);
-
- parse(argc3, const_cast<char**>(argv3));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z, 0, 1);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
+ checkOneBitField(OptionInfo::Z, "--z");
}
TEST_F(CommandOptionsTest, ad) {
-
- // Specifying a value of zero, we expect all flag () to be zero
- const char* argv1[] = {"badpacket", "--ad", "0"};
- int argc1 = sizeof(argv1) / sizeof(const char*);
-
- parse(argc1, const_cast<char**>(argv1));
- checkDefaultOtherValues();
- checkDefaultLimitsValues();
-
- // Check that a value of 1 is accepted
- const char* argv2[] = {"badpacket", "--ad", "1"};
- int argc2 = sizeof(argv2) / sizeof(const char*);
-
- parse(argc2, const_cast<char**>(argv2));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD, 1, 1);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
-
- // Check that a range is accepted.
- const char* argv3[] = {"badpacket", "--ad", "0-1"};
- int argc3 = sizeof(argv3) / sizeof(const char*);
-
- parse(argc3, const_cast<char**>(argv3));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD, 0, 1);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC);
+ checkOneBitField(OptionInfo::AD, "--ad");
}
TEST_F(CommandOptionsTest, cd) {
+ checkOneBitField(OptionInfo::CD, "--cd");
+}
- // Specifying a value of zero, we expect all flag () to be zero
- const char* argv1[] = {"badpacket", "--cd", "0"};
- int argc1 = sizeof(argv1) / sizeof(const char*);
+TEST_F(CommandOptionsTest, rc) {
+ checkFourBitField(OptionInfo::RC, "--rc");
+}
- parse(argc1, const_cast<char**>(argv1));
- checkDefaultOtherValues();
- checkDefaultLimitsValues();
+// Section count options
- // Check that a value of 1 is accepted
- const char* argv2[] = {"badpacket", "--cd", "1"};
- int argc2 = sizeof(argv2) / sizeof(const char*);
-
- parse(argc2, const_cast<char**>(argv2));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD, 1, 1);
- checkValuePair(OptionInfo::RC);
-
- // Check that a range is accepted.
- const char* argv3[] = {"badpacket", "--cd", "1-0"};
- int argc3 = sizeof(argv3) / sizeof(const char*);
-
- parse(argc3, const_cast<char**>(argv3));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD, 0, 1);
- checkValuePair(OptionInfo::RC);
+TEST_F(CommandOptionsTest, qc) {
+ checkSixteenBitField(OptionInfo::QC, "--qc");
}
-TEST_F(CommandOptionsTest, rc) {
-
- // Specifying a value of zero, we expect all flag () to be zero
- const char* argv1[] = {"badpacket", "--rc", "0"};
- int argc1 = sizeof(argv1) / sizeof(const char*);
+TEST_F(CommandOptionsTest, ac) {
+ checkSixteenBitField(OptionInfo::AC, "--ac");
+}
- parse(argc1, const_cast<char**>(argv1));
- checkDefaultOtherValues();
- checkDefaultLimitsValues();
+TEST_F(CommandOptionsTest, uc) {
+ checkSixteenBitField(OptionInfo::UC, "--uc");
+}
- // Check that a valid value is accepted.
- const char* argv2[] = {"badpacket", "--rc", "15"};
- int argc2 = sizeof(argv2) / sizeof(const char*);
-
- parse(argc2, const_cast<char**>(argv2));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC, 15, 15);
-
- // Check that a range is accepted (in this case, specified backwards and
- // outside the range - so it should be truncated).
- const char* argv3[] = {"badpacket", "--rc", "8-4"};
- int argc3 = sizeof(argv3) / sizeof(const char*);
-
- parse(argc3, const_cast<char**>(argv3));
- checkDefaultOtherValues();
- checkValuePair(OptionInfo::QR);
- checkValuePair(OptionInfo::OP);
- checkValuePair(OptionInfo::AA);
- checkValuePair(OptionInfo::TC);
- checkValuePair(OptionInfo::Z);
- checkValuePair(OptionInfo::AD);
- checkValuePair(OptionInfo::CD);
- checkValuePair(OptionInfo::RC, 4, 8);
+TEST_F(CommandOptionsTest, dc) {
+ checkSixteenBitField(OptionInfo::DC, "--dc");
}
-// Check that invalid () are caught.
-TEST_F(CommandOptionsTest, processOptionValue) {
-
- // Check out of range () cause a BadValue exception
- EXPECT_THROW(processOptionValue('Q', "2"), isc::BadValue); // Single value above range
- EXPECT_THROW(processOptionValue('O', "0-17"), isc::BadValue); // Range overlapping valid range
-
- // ... and that any invalid string does the same
- EXPECT_THROW(processOptionValue('O', ""), isc::BadValue);
- EXPECT_THROW(processOptionValue('O', " "), isc::BadValue);
- EXPECT_THROW(processOptionValue('O', "1-2-3"), isc::BadValue);
- EXPECT_THROW(processOptionValue('O', "abc"), isc::BadValue);
- EXPECT_THROW(processOptionValue('O', "abc-xyz"), isc::BadValue);
- EXPECT_THROW(processOptionValue('O', "0.7"), isc::BadValue);
- EXPECT_THROW(processOptionValue('O', "0.7-2.3"), isc::BadValue);
+// ... and the message size option
+
+TEST_F(CommandOptionsTest, ms) {
+ int index = OptionInfo::MS;
+ const char* optflag = "--ms";
+
+ checkCommandValid(index, optflag, "1", 1, 1);
+ checkCommandValid(index, optflag, "65536", 65536, 65536);
+ checkCommandValid(index, optflag, "1-65536", 1, 65536);
+ checkCommandValid(index, optflag, "65536-1", 1, 65536);
+ checkCommandInvalid(optflag, "0");
+ checkCommandInvalid(optflag, "1-65537");
+ checkCommandInvalid(optflag, "65538");
+ checkCommandInvalid(optflag, "xyz");
}
diff --git a/tests/tools/badpacket/tests/header_flags_unittest.cc b/tests/tools/badpacket/tests/header_flags_unittest.cc
index bc39b32..5a7a722 100644
--- a/tests/tools/badpacket/tests/header_flags_unittest.cc
+++ b/tests/tools/badpacket/tests/header_flags_unittest.cc
@@ -21,243 +21,77 @@
using namespace isc::badpacket;
-
// Test fixture class
class HeaderFlagsTest : public ::testing::Test {
public:
HeaderFlagsTest() {}
-};
-
-// Convenience function to check that all values are zero
-void
-checkZero(const HeaderFlags& flags) {
- EXPECT_EQ(0, flags.get(OptionInfo::QR));
- EXPECT_EQ(0, flags.get(OptionInfo::OP));
- EXPECT_EQ(0, flags.get(OptionInfo::AA));
- EXPECT_EQ(0, flags.get(OptionInfo::TC));
- EXPECT_EQ(0, flags.get(OptionInfo::RD));
- EXPECT_EQ(0, flags.get(OptionInfo::RA));
- EXPECT_EQ(0, flags.get(OptionInfo::Z));
- EXPECT_EQ(0, flags.get(OptionInfo::AD));
- EXPECT_EQ(0, flags.get(OptionInfo::CD));
- EXPECT_EQ(0, flags.get(OptionInfo::RC));
- EXPECT_EQ(0, flags.getValue());
-}
+ /// \brief Checks that all options are zero
+ ///
+ /// Checks that all flags options are set to zero.
+ ///
+ /// \param flags Flags structure to check.
+ /// \param except Index not to check. (This allows options not being tested
+ /// to be checked to see that they are at the default value.) As all
+ /// index values are positive, a negative value means check
+ /// everything.
+ void checkZero(const HeaderFlags& flags, int except = -1) {
+
+ // Check individual fields
+ for (int i = OptionInfo::FLAGS_START; i < OptionInfo::FLAGS_END; ++i) {
+ if (i != except) {
+ EXPECT_EQ(0, flags.get(i));
+ }
+ }
+
+ // ... and check the composite
+ if (except == -1) {
+ EXPECT_EQ(0, flags.getValue());
+ } else {
+ EXPECT_NE(0, flags.getValue());
+ }
+ }
+
+ /// \brief Check Option
+ ///
+ /// Checks that an option will only set the appropriate bits in the flags
+ /// field.
+ ///
+ /// \param index Index of the flags field to check.
+ /// \param maxval Maximum value of the header field.
+ void checkOption(int index, uint32_t maxval) {
+
+ // Create header flags and check initialized properly.
+ HeaderFlags flags;
+ checkZero(flags);
+
+ // Check we can set field to maximum.
+ flags.set(index, maxval);
+ EXPECT_EQ(maxval, flags.get(index));
+ checkZero(flags, index);
+
+ // Check we can reset it to zero.
+ flags.set(index, 0);
+ checkZero(flags);
+ }
+};
// Set of tests to check that setting a bit only sets that bit and nothing
// else.
-TEST_F(HeaderFlagsTest, QRfield) {
- HeaderFlags flags;
- checkZero(flags);
-
- flags.set(OptionInfo::QR, 1);
- EXPECT_EQ(1, flags.get(OptionInfo::QR));
- EXPECT_EQ(0, flags.get(OptionInfo::OP));
- EXPECT_EQ(0, flags.get(OptionInfo::AA));
- EXPECT_EQ(0, flags.get(OptionInfo::TC));
- EXPECT_EQ(0, flags.get(OptionInfo::RD));
- EXPECT_EQ(0, flags.get(OptionInfo::RA));
- EXPECT_EQ(0, flags.get(OptionInfo::Z));
- EXPECT_EQ(0, flags.get(OptionInfo::AD));
- EXPECT_EQ(0, flags.get(OptionInfo::CD));
- EXPECT_EQ(0, flags.get(OptionInfo::RC));
- EXPECT_NE(0, flags.getValue());
-
- flags.set(OptionInfo::QR, 0);
- checkZero(flags);
-}
-
-TEST_F(HeaderFlagsTest, OPfield) {
- HeaderFlags flags;
- checkZero(flags);
-
- flags.set(OptionInfo::OP, 15);
- EXPECT_EQ(0, flags.get(OptionInfo::QR));
- EXPECT_EQ(15, flags.get(OptionInfo::OP));
- EXPECT_EQ(0, flags.get(OptionInfo::AA));
- EXPECT_EQ(0, flags.get(OptionInfo::TC));
- EXPECT_EQ(0, flags.get(OptionInfo::RD));
- EXPECT_EQ(0, flags.get(OptionInfo::RA));
- EXPECT_EQ(0, flags.get(OptionInfo::Z));
- EXPECT_EQ(0, flags.get(OptionInfo::AD));
- EXPECT_EQ(0, flags.get(OptionInfo::CD));
- EXPECT_EQ(0, flags.get(OptionInfo::RC));
- EXPECT_NE(0, flags.getValue());
-
- flags.set(OptionInfo::OP, 0);
- checkZero(flags);
-}
-
-TEST_F(HeaderFlagsTest, AAfield) {
- HeaderFlags flags;
- checkZero(flags);
-
- flags.set(OptionInfo::AA, 1);
- EXPECT_EQ(0, flags.get(OptionInfo::QR));
- EXPECT_EQ(0, flags.get(OptionInfo::OP));
- EXPECT_EQ(1, flags.get(OptionInfo::AA));
- EXPECT_EQ(0, flags.get(OptionInfo::TC));
- EXPECT_EQ(0, flags.get(OptionInfo::RD));
- EXPECT_EQ(0, flags.get(OptionInfo::RA));
- EXPECT_EQ(0, flags.get(OptionInfo::Z));
- EXPECT_EQ(0, flags.get(OptionInfo::AD));
- EXPECT_EQ(0, flags.get(OptionInfo::CD));
- EXPECT_EQ(0, flags.get(OptionInfo::RC));
- EXPECT_NE(0, flags.getValue());
-
- flags.set(OptionInfo::AA, 0);
- checkZero(flags);
-}
-
-TEST_F(HeaderFlagsTest, TCfield) {
- HeaderFlags flags;
- checkZero(flags);
-
- flags.set(OptionInfo::TC, 1);
- EXPECT_EQ(0, flags.get(OptionInfo::QR));
- EXPECT_EQ(0, flags.get(OptionInfo::OP));
- EXPECT_EQ(0, flags.get(OptionInfo::AA));
- EXPECT_EQ(1, flags.get(OptionInfo::TC));
- EXPECT_EQ(0, flags.get(OptionInfo::RD));
- EXPECT_EQ(0, flags.get(OptionInfo::RA));
- EXPECT_EQ(0, flags.get(OptionInfo::Z));
- EXPECT_EQ(0, flags.get(OptionInfo::AD));
- EXPECT_EQ(0, flags.get(OptionInfo::CD));
- EXPECT_EQ(0, flags.get(OptionInfo::RC));
- EXPECT_NE(0, flags.getValue());
-
- flags.set(OptionInfo::TC, 0);
- checkZero(flags);
-}
-
-TEST_F(HeaderFlagsTest, RDfield) {
- HeaderFlags flags;
- checkZero(flags);
-
- flags.set(OptionInfo::RD, 1);
- EXPECT_EQ(0, flags.get(OptionInfo::QR));
- EXPECT_EQ(0, flags.get(OptionInfo::OP));
- EXPECT_EQ(0, flags.get(OptionInfo::AA));
- EXPECT_EQ(0, flags.get(OptionInfo::TC));
- EXPECT_EQ(1, flags.get(OptionInfo::RD));
- EXPECT_EQ(0, flags.get(OptionInfo::RA));
- EXPECT_EQ(0, flags.get(OptionInfo::Z));
- EXPECT_EQ(0, flags.get(OptionInfo::AD));
- EXPECT_EQ(0, flags.get(OptionInfo::CD));
- EXPECT_EQ(0, flags.get(OptionInfo::RC));
- EXPECT_NE(0, flags.getValue());
-
- flags.set(OptionInfo::RD, 0);
- checkZero(flags);
-}
-
-TEST_F(HeaderFlagsTest, RAfield) {
- HeaderFlags flags;
- checkZero(flags);
-
- flags.set(OptionInfo::RA, 1);
- EXPECT_EQ(0, flags.get(OptionInfo::QR));
- EXPECT_EQ(0, flags.get(OptionInfo::OP));
- EXPECT_EQ(0, flags.get(OptionInfo::AA));
- EXPECT_EQ(0, flags.get(OptionInfo::TC));
- EXPECT_EQ(0, flags.get(OptionInfo::RD));
- EXPECT_EQ(1, flags.get(OptionInfo::RA));
- EXPECT_EQ(0, flags.get(OptionInfo::Z));
- EXPECT_EQ(0, flags.get(OptionInfo::AD));
- EXPECT_EQ(0, flags.get(OptionInfo::CD));
- EXPECT_EQ(0, flags.get(OptionInfo::RC));
- EXPECT_NE(0, flags.getValue());
-
- flags.set(OptionInfo::RA, 0);
- checkZero(flags);
-}
-
-TEST_F(HeaderFlagsTest, Zfield) {
- HeaderFlags flags;
- checkZero(flags);
-
- flags.set(OptionInfo::Z, 1);
- EXPECT_EQ(0, flags.get(OptionInfo::QR));
- EXPECT_EQ(0, flags.get(OptionInfo::OP));
- EXPECT_EQ(0, flags.get(OptionInfo::AA));
- EXPECT_EQ(0, flags.get(OptionInfo::TC));
- EXPECT_EQ(0, flags.get(OptionInfo::RD));
- EXPECT_EQ(0, flags.get(OptionInfo::RA));
- EXPECT_EQ(1, flags.get(OptionInfo::Z));
- EXPECT_EQ(0, flags.get(OptionInfo::AD));
- EXPECT_EQ(0, flags.get(OptionInfo::CD));
- EXPECT_EQ(0, flags.get(OptionInfo::RC));
- EXPECT_NE(0, flags.getValue());
-
- flags.set(OptionInfo::Z, 0);
- checkZero(flags);
-}
-
-TEST_F(HeaderFlagsTest, ADfield) {
- HeaderFlags flags;
- checkZero(flags);
-
- flags.set(OptionInfo::AD, 1);
- EXPECT_EQ(0, flags.get(OptionInfo::QR));
- EXPECT_EQ(0, flags.get(OptionInfo::OP));
- EXPECT_EQ(0, flags.get(OptionInfo::AA));
- EXPECT_EQ(0, flags.get(OptionInfo::TC));
- EXPECT_EQ(0, flags.get(OptionInfo::RD));
- EXPECT_EQ(0, flags.get(OptionInfo::RA));
- EXPECT_EQ(0, flags.get(OptionInfo::Z));
- EXPECT_EQ(1, flags.get(OptionInfo::AD));
- EXPECT_EQ(0, flags.get(OptionInfo::CD));
- EXPECT_EQ(0, flags.get(OptionInfo::RC));
- EXPECT_NE(0, flags.getValue());
-
- flags.set(OptionInfo::AD, 0);
- checkZero(flags);
-}
-
-TEST_F(HeaderFlagsTest, CDfield) {
- HeaderFlags flags;
- checkZero(flags);
-
- flags.set(OptionInfo::CD, 1);
- EXPECT_EQ(0, flags.get(OptionInfo::QR));
- EXPECT_EQ(0, flags.get(OptionInfo::OP));
- EXPECT_EQ(0, flags.get(OptionInfo::AA));
- EXPECT_EQ(0, flags.get(OptionInfo::TC));
- EXPECT_EQ(0, flags.get(OptionInfo::RD));
- EXPECT_EQ(0, flags.get(OptionInfo::RA));
- EXPECT_EQ(0, flags.get(OptionInfo::Z));
- EXPECT_EQ(0, flags.get(OptionInfo::AD));
- EXPECT_EQ(1, flags.get(OptionInfo::CD));
- EXPECT_EQ(0, flags.get(OptionInfo::RC));
- EXPECT_NE(0, flags.getValue());
-
- flags.set(OptionInfo::CD, 0);
- checkZero(flags);
-}
-
-TEST_F(HeaderFlagsTest, RCfield) {
- HeaderFlags flags;
- checkZero(flags);
-
- flags.set(OptionInfo::RC, 15);
- EXPECT_EQ(0, flags.get(OptionInfo::QR));
- EXPECT_EQ(0, flags.get(OptionInfo::OP));
- EXPECT_EQ(0, flags.get(OptionInfo::AA));
- EXPECT_EQ(0, flags.get(OptionInfo::TC));
- EXPECT_EQ(0, flags.get(OptionInfo::RD));
- EXPECT_EQ(0, flags.get(OptionInfo::RA));
- EXPECT_EQ(0, flags.get(OptionInfo::Z));
- EXPECT_EQ(0, flags.get(OptionInfo::AD));
- EXPECT_EQ(0, flags.get(OptionInfo::CD));
- EXPECT_EQ(15, flags.get(OptionInfo::RC));
- EXPECT_NE(0, flags.getValue());
-
- flags.set(OptionInfo::RC, 0);
- checkZero(flags);
+TEST_F(HeaderFlagsTest, fields) {
+ checkOption(OptionInfo::QR, 1);
+ checkOption(OptionInfo::OP, 15);
+ checkOption(OptionInfo::AA, 1);
+ checkOption(OptionInfo::TC, 1);
+ checkOption(OptionInfo::RD, 1);
+ checkOption(OptionInfo::RA, 1);
+ checkOption(OptionInfo::Z, 1);
+ checkOption(OptionInfo::AD, 1);
+ checkOption(OptionInfo::CD, 1);
+ checkOption(OptionInfo::RC, 15);
}
// Check that the correct bits are set
diff --git a/tests/tools/badpacket/tests/option_info_unittest.cc b/tests/tools/badpacket/tests/option_info_unittest.cc
index cacb213..8c061de 100644
--- a/tests/tools/badpacket/tests/option_info_unittest.cc
+++ b/tests/tools/badpacket/tests/option_info_unittest.cc
@@ -152,3 +152,10 @@ TEST_F(OptionInfoTest, CountValues) {
EXPECT_EQ(0, OptionInfo::minval(OptionInfo::DC));
EXPECT_EQ(0xFFFF, OptionInfo::maxval(OptionInfo::DC));
}
+
+TEST_F(OptionInfoTest, OtherValues) {
+ EXPECT_STREQ("ms", OptionInfo::name(OptionInfo::MS));
+ EXPECT_STREQ("ms", OptionInfo::name(OptionInfo::getIndex('M')));
+ EXPECT_EQ(1, OptionInfo::minval(OptionInfo::MS));
+ EXPECT_EQ(65536, OptionInfo::maxval(OptionInfo::MS));
+}
More information about the bind10-changes
mailing list