BIND 10 trac703, updated. f2de716ada3aa2c0862f3d7d21ef10d28db90219 [trac703] Bad Packet Tool
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Apr 8 10:31:50 UTC 2011
The branch, trac703 has been updated
via f2de716ada3aa2c0862f3d7d21ef10d28db90219 (commit)
from 583d7973d8f49c061dee13a14c89cf0846f84721 (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 f2de716ada3aa2c0862f3d7d21ef10d28db90219
Author: Stephen Morris <stephen at isc.org>
Date: Fri Apr 8 11:30:02 2011 +0100
[trac703] Bad Packet Tool
Sends packets with a mangled flags field to DNS servers and examines
the responses.
-----------------------------------------------------------------------
Summary of changes:
configure.ac | 3 +
src/lib/asiolink/io_fetch.cc | 38 ++-
src/lib/asiolink/io_fetch.h | 26 +
tests/Makefile.am | 2 +-
tests/tools/Makefile.am | 1 +
tests/tools/badpacket/Makefile.am | 26 +
tests/tools/badpacket/README | 51 ++
tests/tools/badpacket/badpacket.cc | 52 ++
tests/tools/badpacket/command_options.cc | 221 ++++++++
tests/tools/badpacket/command_options.h | 183 +++++++
tests/tools/badpacket/header_flags.h | 211 ++++++++
tests/tools/badpacket/scan.cc | 207 ++++++++
tests/tools/badpacket/scan.h | 107 ++++
tests/tools/badpacket/tests/Makefile.am | 29 +
.../badpacket/tests/command_options_unittest.cc | 545 ++++++++++++++++++++
.../tools/badpacket/tests/header_flags_unittest.cc | 306 +++++++++++
.../tools/badpacket}/tests/run_unittests.cc | 3 +
.../tools/badpacket/version.h | 14 +-
18 files changed, 2009 insertions(+), 16 deletions(-)
create mode 100644 tests/tools/Makefile.am
create mode 100644 tests/tools/badpacket/Makefile.am
create mode 100644 tests/tools/badpacket/README
create mode 100644 tests/tools/badpacket/badpacket.cc
create mode 100644 tests/tools/badpacket/command_options.cc
create mode 100644 tests/tools/badpacket/command_options.h
create mode 100644 tests/tools/badpacket/header_flags.h
create mode 100644 tests/tools/badpacket/scan.cc
create mode 100644 tests/tools/badpacket/scan.h
create mode 100644 tests/tools/badpacket/tests/Makefile.am
create mode 100644 tests/tools/badpacket/tests/command_options_unittest.cc
create mode 100644 tests/tools/badpacket/tests/header_flags_unittest.cc
copy {src/lib/exceptions => tests/tools/badpacket}/tests/run_unittests.cc (97%)
copy src/lib/log/message_exception.cc => tests/tools/badpacket/version.h (83%)
-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 1c063c4..6fd41ba 100644
--- a/configure.ac
+++ b/configure.ac
@@ -692,6 +692,9 @@ AC_CONFIG_FILES([Makefile
src/lib/server_common/tests/Makefile
tests/Makefile
tests/system/Makefile
+ tests/tools/Makefile
+ tests/tools/badpacket/Makefile
+ tests/tools/badpacket/tests/Makefile
])
AC_OUTPUT([doc/version.ent
src/bin/cfgmgr/b10-cfgmgr.py
diff --git a/src/lib/asiolink/io_fetch.cc b/src/lib/asiolink/io_fetch.cc
index fdc1f2e..a00a0ef 100644
--- a/src/lib/asiolink/io_fetch.cc
+++ b/src/lib/asiolink/io_fetch.cc
@@ -86,6 +86,7 @@ struct IOFetchData {
size_t offset; ///< Offset to receive data
bool stopped; ///< Have we stopped running?
int timeout; ///< Timeout in ms
+ bool packet; ///< true if packet was supplied
// In case we need to log an error, the origin of the last asynchronous
// I/O is recorded. To save time and simplify the code, this is recorded
@@ -146,6 +147,7 @@ struct IOFetchData {
offset(0),
stopped(false),
timeout(wait),
+ packet(false),
origin(ASIO_UNKORIGIN),
staging(),
qid(QidGenerator::getInstance().generateQid())
@@ -175,6 +177,18 @@ IOFetch::IOFetch(Protocol protocol, IOService& service,
{
}
+IOFetch::IOFetch(Protocol protocol, IOService& service,
+ OutputBufferPtr& outpkt, const IOAddress& address, uint16_t port,
+ OutputBufferPtr& buff, Callback* cb, int wait)
+ :
+ data_(new IOFetchData(protocol, service,
+ isc::dns::Question(isc::dns::Name("dummy.example.org"), isc::dns::RRClass::IN(), isc::dns::RRType::A()),
+ address, port, buff, cb, wait))
+{
+ data_->msgbuf = outpkt;
+ data_->packet = true;
+}
+
// Return protocol in use.
IOFetch::Protocol
@@ -201,14 +215,22 @@ IOFetch::operator()(asio::error_code ec, size_t length) {
/// This is done in a different scope to allow inline variable
/// declarations.
{
- Message msg(Message::RENDER);
- msg.setQid(data_->qid);
- msg.setOpcode(Opcode::QUERY());
- msg.setRcode(Rcode::NOERROR());
- msg.setHeaderFlag(Message::HEADERFLAG_RD);
- msg.addQuestion(data_->question);
- MessageRenderer renderer(*data_->msgbuf);
- msg.toWire(renderer);
+ if (data_->packet) {
+ // A packet was given, overwrite the QID (which is in the
+ // first two bytes of the packet).
+ data_->msgbuf->writeUint16At(data_->qid, 0);
+
+ } else {
+ // A question was given, construct the packet
+ Message msg(Message::RENDER);
+ msg.setQid(data_->qid);
+ msg.setOpcode(Opcode::QUERY());
+ msg.setRcode(Rcode::NOERROR());
+ msg.setHeaderFlag(Message::HEADERFLAG_RD);
+ msg.addQuestion(data_->question);
+ MessageRenderer renderer(*data_->msgbuf);
+ msg.toWire(renderer);
+ }
}
// If we timeout, we stop, which will can cancel outstanding I/Os and
diff --git a/src/lib/asiolink/io_fetch.h b/src/lib/asiolink/io_fetch.h
index 0723777..56cee87 100644
--- a/src/lib/asiolink/io_fetch.h
+++ b/src/lib/asiolink/io_fetch.h
@@ -137,6 +137,32 @@ public:
uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb,
int wait = -1);
+ /// \brief Constructor.
+ ///
+ /// 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.
+ /// \param outpkt Packet to send to upstream server. Note that the
+ /// QID (first two bytes of the packet) may be altered in the sending.
+ /// \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 wait Timeout for the fetch (in ms). The default value of
+ /// -1 indicates no timeout.
+ IOFetch(Protocol protocol, IOService& service,
+ isc::dns::OutputBufferPtr& outpkt, const IOAddress& address,
+ uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb,
+ int wait = -1);
+
/// \brief Return Current Protocol
///
/// \return Protocol associated with this IOFetch object.
diff --git a/tests/Makefile.am b/tests/Makefile.am
index d4008c0..570c0e2 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -1 +1 @@
-SUBDIRS = system
+SUBDIRS = system tools
diff --git a/tests/tools/Makefile.am b/tests/tools/Makefile.am
new file mode 100644
index 0000000..2f07494
--- /dev/null
+++ b/tests/tools/Makefile.am
@@ -0,0 +1 @@
+SUBDIRS = badpacket
diff --git a/tests/tools/badpacket/Makefile.am b/tests/tools/badpacket/Makefile.am
new file mode 100644
index 0000000..90d8871
--- /dev/null
+++ b/tests/tools/badpacket/Makefile.am
@@ -0,0 +1,26 @@
+SUBDIRS = . tests
+
+AM_CPPFLAGS = -I$(top_srcdir)/src/lib -I$(top_builddir)/src/lib
+AM_CPPFLAGS += -I$(top_srcdir)/src/lib/log -I$(top_builddir)/src/lib/log
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+noinst_PROGRAMS = badpacket
+badpacket_SOURCES = badpacket.cc
+badpacket_SOURCES += command_options.cc command_options.h
+badpacket_SOURCES += header_flags.h
+badpacket_SOURCES += scan.cc scan.h
+badpacket_SOURCES += version.h
+
+badpacket_LDADD = $(top_builddir)/src/lib/asiolink/libasiolink.la
+badpacket_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+badpacket_LDADD += $(top_builddir)/src/lib/log/liblog.la
+badpacket_LDADD += $(top_builddir)/src/lib/exceptions/libexceptions.la
+
diff --git a/tests/tools/badpacket/README b/tests/tools/badpacket/README
new file mode 100644
index 0000000..4d90dd0
--- /dev/null
+++ b/tests/tools/badpacket/README
@@ -0,0 +1,51 @@
+"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.
+
+To illustrate this, consider the following command:
+
+badpacket --address 192.0.2.21 --port 5301 --aa 0-1 --cd 1
+ --rc 0-2 ftp.example.com
+
+(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:
+
+AA RCODE CD Rest
+0 0 1 0
+0 1 1 0
+0 2 1 0
+1 0 1 0
+1 1 1 0
+1 2 1 0
+
+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)
+
+(Again the text has been split across two lines for clarity.)
+
+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:
+
+* Flasify the values in the various count fields
+* 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
diff --git a/tests/tools/badpacket/badpacket.cc b/tests/tools/badpacket/badpacket.cc
new file mode 100644
index 0000000..ecfdc0d
--- /dev/null
+++ b/tests/tools/badpacket/badpacket.cc
@@ -0,0 +1,52 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <unistd.h>
+
+#include <config.h>
+
+#include "command_options.h"
+#include "scan.h"
+
+/// \brief Perform Bad Packet Scan
+///
+/// Scans the server by sending a sequence of (potentially) bad packets and
+/// 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.
+///
+/// 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.
+
+using namespace isc::badpacket;
+
+/// \brief Main Program
+int main(int argc, char* argv[]) {
+
+ CommandOptions command_line;
+ command_line.parse(argc, argv);
+
+ // Construct the scan object and perform the scan.
+ Scan scanner;
+ scanner.scan(command_line);
+
+ return 0;
+}
diff --git a/tests/tools/badpacket/command_options.cc b/tests/tools/badpacket/command_options.cc
new file mode 100644
index 0000000..a1cdd2a
--- /dev/null
+++ b/tests/tools/badpacket/command_options.cc
@@ -0,0 +1,221 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <algorithm>
+#include <iostream>
+#include <string>
+#include <vector>
+
+#include <boost/lexical_cast.hpp>
+#include <getopt.h>
+
+#include "exceptions/exceptions.h"
+#include "log/strutil.h"
+
+#include "command_options.h"
+#include "version.h"
+
+using namespace std;
+using namespace isc;
+namespace po = boost::program_options;
+
+namespace isc {
+namespace badpacket {
+
+/// Parses the command-line options and returns the results in an Options
+/// structure. If the
+void
+CommandOptions::parse(int argc, char* const argv[]) {
+
+ // Set up options for processing
+ const struct option longopts[] = {
+ {"help", 0, NULL, 'h'}, // Print usage message and exit
+ {"version", 0, NULL, 'v'}, // Print program version and exit
+ {"address", 1, NULL, 'a'}, // Specify target server address
+ {"port", 1, NULL, 'p'}, // Specify target port
+ {"timeout", 1, NULL, 't'}, // Time to wait before timing out (ms)
+ {"qr", 1, NULL, 'Q'}, // Query/response flag
+ {"op", 1, NULL, 'O'}, // Opcode
+ {"aa", 1, NULL, 'A'}, // Authoritative answer
+ {"tc", 1, NULL, 'T'}, // Truncated
+ {"rd", 1, NULL, 'D'}, // recursion Desired
+ {"ra", 1, NULL, 'R'}, // Recursion available
+ {"z", 1, NULL, 'Z'}, // Must be Zero (reserved bit)
+ {"ad", 1, NULL, 'U'}, // aUthenticated data
+ {"cd", 1, NULL, 'C'}, // Checking disabled
+ {"rc", 1, NULL, 'E'}, // rEsult code
+ {NULL, 0, NULL, 0 }
+ };
+ const char* shortopts = "hva:p:t:Q:O:A:T:D:R:Z:U:C:E:";
+
+
+ // Set variables to defaults before parsing
+ reset();
+
+ // Process command line
+ int c; // Option being processed
+ optind = 0; // Reset parsing
+ while ((c = getopt_long(argc, argv, shortopts, longopts, NULL)) != -1) {
+ switch (c) {
+ case 'h': // --help
+ usage();
+ exit(0);
+
+ case 'v': // --version
+ version();
+ exit(0);
+
+ case 'a': // --address
+ address_ = optarg;
+ break;
+
+ case 'p': // --port
+ port_ = boost::lexical_cast<uint16_t>(string(optarg));
+ break;
+
+ case 't': // --timeout
+ timeout_ = boost::lexical_cast<int>(string(optarg));
+ break;
+
+ case 'Q': // --qr (query/response)
+ processOptionValue(optarg, values_.qr, 0, 1);
+ break;
+
+ case 'O': // --op (operation code)
+ processOptionValue(optarg, values_.op, 0, 15);
+ break;
+
+ case 'A': // --aa (authoritative answer)
+ processOptionValue(optarg, values_.aa, 0, 1);
+ break;
+
+ case 'T': // --tc (truncated)
+ processOptionValue(optarg, values_.tc, 0, 1);
+ break;
+
+ case 'D': // --rd (recursion desired)
+ processOptionValue(optarg, values_.rd, 0, 1);
+ break;
+
+ case 'R': // --ra (recursion available)
+ processOptionValue(optarg, values_.ra, 0, 1);
+ break;
+
+ case 'Z': // --z (zero: reserved bit)
+ processOptionValue(optarg, values_.z, 0, 1);
+ break;
+
+ case 'U': // --ad (authenticated data)
+ processOptionValue(optarg, values_.ad, 0, 1);
+ break;
+
+ case 'C': // --cd (checking disabled)
+ processOptionValue(optarg, values_.cd, 0, 1);
+ break;
+
+ case 'E': // --rc (result code)
+ processOptionValue(optarg, values_.rc, 0, 15);
+ break;
+
+ default:
+ isc_throw(isc::InvalidParameter, "Unknown switch");
+ }
+ }
+
+ // Pick up a parameter if there is one (and ignore excess parameters).
+ if (optind < argc) {
+ qname_ = argv[optind++];
+ }
+}
+
+/// \brief 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"
+ "\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"
+ "specifying:\n"
+ "\n"
+ "--tc 0-1 --op 1-4 --aa 1 --rd 0-1\n"
+ "\n"
+ "... would send a total of 16 packets which would have all combinations of the\n"
+ "the tc bit set to 0 and 1, the rd bit set to 0 and 1, and the opcode set to all\n"
+ "values between 1 and 4. All other flags fields would be zero except for the aa\n"
+ "bit which would always be 1.\n"
+ "\n"
+ "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"
+ "--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"
+ "--port <port> [-p] Port to which to send query. Defaults to 53.\n"
+ "--timeout <value> [-t] Timeout value for the query. Specified in ms, it\n"
+ " defaults to 500ms.\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"
+ "--z <range> [-Z] Set zero (reserved) bit. Valid <range> is 0-1\n"
+ "--ad <range> [-U] Set authentiacted 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"
+ "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"
+ ;
+}
+
+/// \brief Print version information
+void
+CommandOptions::version() {
+ cout << BADPACKET_VERSION << "\n";
+}
+
+// Process single flag
+void
+CommandOptions::processOptionValue(const char* arg, uint32_t* where, uint32_t minval,
+ uint32_t maxval)
+{
+ // Split the string up into one or two tokens
+ vector<string> values = isc::strutil::tokens(string(arg), "-");
+ if ((values.size() < 1) || (values.size() > 2)) {
+ isc_throw(isc::BadValue, "command argument is '" << arg << "': it must "
+ "be in the form 'int' or 'int1-int2'");
+ }
+
+ // Convert to uint32.
+ uint32_t start = boost::lexical_cast<uint32_t>(values[0]);
+ uint32_t end = start;
+ if (values.size() == 2) {
+ end = boost::lexical_cast<uint32_t>(values[1]);
+ }
+ if (start > end) {
+ swap(start, end);
+ }
+
+ // Coerce values into the desired range
+ where[0] = max(minval, min(start, maxval));
+ where[1] = min(maxval, max(end, minval));
+}
+
+} // namespace badpacket
+} // namespace isc
diff --git a/tests/tools/badpacket/command_options.h b/tests/tools/badpacket/command_options.h
new file mode 100644
index 0000000..a1132b9
--- /dev/null
+++ b/tests/tools/badpacket/command_options.h
@@ -0,0 +1,183 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __COMMAND_OPTIONS_H
+#define __COMMAND_OPTIONS_H
+
+#include <cstdlib>
+#include <stdint.h>
+#include <utility>
+
+#include <boost/program_options.hpp>
+
+namespace isc {
+namespace badpacket {
+
+/// \brief Command Options
+///
+/// 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:
+///
+/// - \c --option value
+/// - \c --option value1-value2
+///
+/// Either way, two values are extracted the low value and the high value (in
+/// the former case, bost are the same). The values are stored in a
+/// "FlagValues" structure, which can be returned on request.
+///
+/// For simplicity, the class also 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 Flags Word Values
+ ///
+ /// Structure holding the values for the flag settings. Each variable in
+ /// the structure corresponds to one of the fields in the flags word. The
+ /// variables are two-ewlement arrays: element 0 of the array holds the low
+ /// value in the range given, and element 1 the high value. If only a
+ /// single value is given, both elements hold the same value.
+
+ struct FlagValues {
+ uint32_t qr[2]; // QR bit
+ uint32_t op[2]; // OPCODE field
+ uint32_t aa[2]; // AA bit
+ uint32_t tc[2]; // TC bit
+ uint32_t rd[2]; // RD bit
+ uint32_t ra[2]; // RA bit
+ uint32_t z[2]; // Z bit (reserved bit)
+ uint32_t ad[2]; // AD bit
+ uint32_t cd[2]; // CD bit
+ uint32_t rc[2]; // RCODE field
+
+ /// \brief Default Constructor
+ ///
+ /// Sets everything to zero.
+ FlagValues() {
+ reset();
+ }
+
+ /// \brief Reset All Values to Zero
+ void reset() {
+ qr[0] = qr[1] = 0;
+ op[0] = op[1] = 0;
+ aa[0] = aa[1] = 0;
+ tc[0] = tc[1] = 0;
+ rd[0] = rd[1] = 0;
+ ra[0] = ra[1] = 0;
+ z[0] = z[1] = 0;
+ ad[0] = ad[1] = 0;
+ cd[0] = cd[1] = 0;
+ rc[0] = rc[1] = 0;
+ }
+ };
+
+ /// \brief CommandOptions Constructor
+ ///
+ /// Set values to defaults.
+ CommandOptions() {
+ reset();
+ }
+
+ /// \brief Return Flags Word Values
+ ///
+ /// Returns a copy of the flags word structure for use by the caller. This
+ /// structure holds the flags field settings specified on the command line.
+ ///
+ /// \return Copy of the values specified on the command line.
+ FlagValues getFlagValues() const {
+ return values_;
+ }
+
+ /// \brief Return Target Address
+ std::string getAddress() const {
+ return address_;
+ }
+
+ /// \brief Return Target Port
+ uint16_t getPort() const {
+ return port_;
+ }
+
+ /// \brief Return Timeout
+ int getTimeout() const {
+ return timeout_;
+ }
+
+ /// \brief Return qname
+ std::string getQname() const {
+ return qname_;
+ }
+
+ /// \brief Reset To Defaults
+ void reset() {
+ values_.reset();
+ address_ = "127.0.0.1";
+ port_ = 53;
+ timeout_ = 500;
+ qname_ = "www.example.com";
+ }
+
+ /// \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
+ /// some text to be printed to stdout, after which exit() is called to
+ /// terminate the program.
+ ///
+ /// \param argc Argument count passed to main().
+ /// \param argv Argument value array passed to main().
+ void parse(int argc, char* const argv[]);
+
+ /// \brief Print Usage Information
+ void usage();
+
+ /// \brief Print Version Information
+ void version();
+
+ // The following are protected to aid testing
+
+protected:
+ /// \brief Process Option Value
+ ///
+ /// Processes a specific command-line option, interpreting the value and
+ /// placing it in the appropriate location. On error a BadValue exception
+ /// is thrown.
+ ///
+ /// \param arg flag argument read from the command line
+ /// \param where Two-element uint32_t array into which the data is put
+ /// \param minval Minimum allowed value
+ /// \param maxval Maximum allowed value
+ void processOptionValue(const char* arg, uint32_t* where, uint32_t minval,
+ uint32_t maxval);
+
+ // Member variables
+
+private:
+ FlagValues values_; ///< Values read from command line
+ std::string address_; ///< Address to where query is sent
+ uint16_t port_; ///< Target port
+ int timeout_; ///< Timeout for query
+ std::string qname_; ///< Query to make
+};
+
+} // namespace badpacket
+} // namespace isc
+
+#endif // __COMMAND_OPTIONS_H
diff --git a/tests/tools/badpacket/header_flags.h b/tests/tools/badpacket/header_flags.h
new file mode 100644
index 0000000..546a016
--- /dev/null
+++ b/tests/tools/badpacket/header_flags.h
@@ -0,0 +1,211 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __HEADER_FLAGS_H
+#define __HEADER_FLAGS_H
+
+namespace isc {
+namespace badpacket {
+
+/// \brief Header Flags
+///
+/// Simple class providing easy conversion between the header flags in a DNS
+/// message and a 16-bit value.
+
+class HeaderFlags {
+public:
+
+ // The following declaration describes the various fields in the DNS
+ // packet header.
+ struct Flags {
+ unsigned int rc : 4;
+ unsigned int cd : 1;
+ unsigned int ad : 1;
+ unsigned int z : 1; // Reserved
+ unsigned int ra : 1;
+ unsigned int rd : 1;
+ unsigned int tc : 1;
+ unsigned int aa : 1;
+ unsigned int op : 4;
+ unsigned int qr : 1;
+ };
+
+ /// \brief Constructor
+ HeaderFlags() {
+ reset();
+ }
+
+ /// \brief Reset Values to Zero
+ ///
+ /// Clears all flags.
+ void reset() {
+ setValue(0);
+ }
+
+ /// \brief Set Header Flags as 16-Bit Value
+ ///
+ /// \param value 16-bit value to put into object as representing the
+ /// header flags.
+ void setValue(uint16_t value) {
+ flags_.value = value;
+ }
+
+ /// \brief Get Header Flags as 16-bit Value
+ uint16_t getValue() const {
+ return flags_.value;
+ }
+
+ /// \brief Get QR Bit
+ uint16_t getQR() const {
+ return flags_.fields.qr;
+ }
+
+ /// \brief Set QR Bit
+ ///
+ /// \param value New value of the field, which must be 0 or 1: values
+ /// outside that range are coerced to the nearest boundary.
+ void setQR(uint16_t value) {
+ flags_.fields.qr = (value > 1) ? 1 : value;
+ }
+
+ /// \brief Get OP Value
+ uint16_t getOP() const {
+ return flags_.fields.op;
+ }
+
+ /// \brief Set OP Value
+ ///
+ /// \param value New value of the field, which must in the range 0 to 15:
+ /// values outside that range are coerced to the nearest boundary.
+ void setOP(uint16_t value) {
+ flags_.fields.op = (value > 15) ? 15 : value;
+ }
+
+ /// \brief Get AA Bit
+ uint16_t getAA() const {
+ return flags_.fields.aa;
+ }
+
+ /// \brief Set AA Bit
+ ///
+ /// \param value New value of the field, which must be 0 or 1: values
+ /// outside that range are coerced to the nearest boundary.
+ void setAA(uint16_t value) {
+ flags_.fields.aa = (value > 1) ? 1 : value;
+ }
+
+ /// \brief Get TC Bit
+ uint16_t getTC() const {
+ return flags_.fields.tc;
+ }
+
+ /// \brief Set TC Bit
+ ///
+ /// \param value New value of the field, which must be 0 or 1: values
+ /// outside that range are coerced to the nearest boundary.
+ void setTC(uint16_t value) {
+ flags_.fields.tc = (value > 1) ? 1 : value;
+ }
+
+ /// \brief Get RD Bit
+ uint16_t getRD() const {
+ return flags_.fields.rd;
+ }
+
+ /// \brief Set RD Bit
+ ///
+ /// \param value New value of the field, which must be 0 or 1: values
+ /// outside that range are coerced to the nearest boundary.
+ void setRD(uint16_t value) {
+ flags_.fields.rd = (value > 1) ? 1 : value;
+ }
+
+ /// \brief Get RA Bit
+ uint16_t getRA() const {
+ return flags_.fields.ra;
+ }
+
+ /// \brief Set RA Bit
+ ///
+ /// \param value New value of the field, which must be 0 or 1: values
+ /// outside that range are coerced to the nearest boundary.
+ void setRA(uint16_t value) {
+ flags_.fields.ra = (value > 1) ? 1 : value;
+ }
+
+ /// \brief Get Z Bit
+ uint16_t getZ() const {
+ return flags_.fields.z;
+ }
+
+ /// \brief Set Z Bit
+ ///
+ /// \param value New value of the field, which must be 0 or 1: values
+ /// outside that range are coerced to the nearest boundary.
+ void setZ(uint16_t value) {
+ flags_.fields.z = (value > 1) ? 1 : value;
+ }
+
+ /// \brief Get AD Bit
+ uint16_t getAD() const {
+ return flags_.fields.ad;
+ }
+
+ /// \brief Set AD Bit
+ ///
+ /// \param value New value of the field, which must be 0 or 1: values
+ /// outside that range are coerced to the nearest boundary.
+ void setAD(uint16_t value) {
+ flags_.fields.ad = (value > 1) ? 1 : value;
+ }
+
+ /// \brief Get CD Bit
+ uint16_t getCD() const {
+ return flags_.fields.cd;
+ }
+
+ /// \brief Set CD Bit
+ ///
+ /// \param value New value of the field, which must be 0 or 1: values
+ /// outside that range are coerced to the nearest boundary.
+ void setCD(uint16_t value) {
+ flags_.fields.cd = (value > 1) ? 1 : value;
+ }
+
+ /// \brief Get RC Value
+ uint16_t getRC() const {
+ return flags_.fields.rc;
+ }
+
+ /// \brief Set RC Value
+ ///
+ /// \param value New value of the field, which must be in the range 0 to 15:
+ /// values outside that range are coerced to the nearest boundary.
+ void setRC(uint16_t value) {
+ flags_.fields.rc = (value > 15) ? 15 : value;
+ }
+
+private:
+
+ // The variable that performs the conversion
+ union {
+ uint16_t value;
+ Flags fields;
+ } flags_;
+};
+
+} // namespace badpacket
+} // namespace isc
+
+#endif // __HEADER_FLAGS_H
diff --git a/tests/tools/badpacket/scan.cc b/tests/tools/badpacket/scan.cc
new file mode 100644
index 0000000..2059ba5
--- /dev/null
+++ b/tests/tools/badpacket/scan.cc
@@ -0,0 +1,207 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <iostream>
+#include <iomanip>
+#include <sstream>
+#include <string>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <asio.hpp>
+
+#include <asiolink/io_address.h>
+#include <asiolink/io_fetch.h>
+#include <dns/buffer.h>
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/opcode.h>
+#include <dns/question.h>
+#include <dns/rcode.h>
+#include <dns/rrclass.h>
+#include <dns/rrtype.h>
+#include <log/strutil.h>
+
+#include "command_options.h"
+#include "header_flags.h"
+#include "scan.h"
+
+using namespace std;
+using namespace asiolink;
+using namespace isc::dns;
+using namespace isc::strutil;
+
+namespace isc {
+namespace badpacket {
+
+// Perform the scan from start to end on a single question.
+void
+Scan::scan(const CommandOptions& options) {
+
+ // Create the message buffer to use
+ Message message(Message::RENDER);
+ message.setOpcode(Opcode::QUERY());
+ message.setRcode(Rcode::NOERROR());
+ message.addQuestion(Question(Name(options.getQname()), RRClass::IN(),
+ RRType::A()));
+
+ OutputBufferPtr msgbuf(new OutputBuffer(512));
+ MessageRenderer renderer(*msgbuf);
+ message.toWire(renderer);
+
+ // Now 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).
+ CommandOptions::FlagValues values = options.getFlagValues();
+ HeaderFlags flags;
+ for (uint16_t qr = values.qr[0]; qr <= values.qr[1]; ++qr) {
+ flags.setQR(qr);
+ for (uint16_t op = values.op[0]; op <= values.op[1]; ++op) {
+ flags.setOP(op);
+ for (uint16_t aa = values.aa[0]; aa <= values.aa[1]; ++aa) {
+ flags.setAA(aa);
+ for (uint16_t tc = values.tc[0]; tc <= values.tc[1]; ++tc) {
+ flags.setTC(tc);
+ for (uint16_t rd = values.rd[0]; rd <= values.rd[1]; ++rd) {
+ flags.setRD(rd);
+ for (uint16_t ra = values.ra[0]; ra <= values.ra[1]; ++ra) {
+ flags.setRA(ra);
+ for (uint16_t z = values.z[0]; z <= values.z[1]; ++z) {
+ flags.setZ(z);
+ for (uint16_t ad = values.ad[0]; ad <= values.ad[1]; ++ad) {
+ flags.setAD(ad);
+ for (uint16_t cd = values.cd[0]; cd <= values.cd[1]; ++cd) {
+ flags.setCD(cd);
+ for (uint16_t rc = values.rc[0]; rc <= values.rc[1]; ++rc) {
+ flags.setRC(rc);
+
+ // Set the flags in the message and do the I/O.
+ msgbuf->writeUint16At(flags.getValue(), 2);
+ scanOne(msgbuf, options);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+// Perform the message exchange for a single combination of flags.
+void
+Scan::scanOne(isc::dns::OutputBufferPtr& msgbuf, const CommandOptions& options) {
+
+ // Store the interpretation of the flags field.
+ string fields = getFields(msgbuf);
+
+ // Do the I/O, waiting for a reply
+ OutputBufferPtr replybuf(new OutputBuffer(512));
+ performIO(msgbuf, replybuf, options);
+
+ string status = "";
+ string returned = "";
+ switch (result_) {
+ case IOFetch::SUCCESS:
+ {
+ status = "SUCCESS";
+
+ // Parse the reply and get the fields
+ returned = getFields(replybuf);
+ lowercase(returned);
+ }
+ break;
+
+ case IOFetch::TIME_OUT:
+ status = "TIMEOUT";
+ break;
+
+ case IOFetch::STOPPED:
+ status = "STOPPED";
+ break;
+
+ default:
+ status = "UNKNOWN";
+ }
+
+ // ... and output the result
+ 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
+ InputBuffer inbuf(msgbuf->getData(), msgbuf->getLength());
+ inbuf.setPosition(2);
+ flags.setValue(inbuf.readUint16());
+
+ std::ostringstream os;
+ os << std::hex << std::uppercase <<
+ "QR:" << flags.getQR() << " " <<
+ "OP:" << flags.getOP() << " " <<
+ "AA:" << flags.getAA() << " " <<
+ "TC:" << flags.getTC() << " " <<
+ "RD:" << flags.getRD() << " " <<
+ "RA:" << flags.getRA() << " " <<
+ "Z:" << flags.getZ() << " " <<
+ "AD:" << flags.getAD() << " " <<
+ "CD:" << flags.getCD() << " " <<
+ "RC:" << flags.getRC();
+ return (os.str());
+}
+
+// Perform the I/O.
+void
+Scan::performIO(OutputBufferPtr& sendbuf, OutputBufferPtr& recvbuf,
+ const CommandOptions& options)
+{
+ // Set up an I/O service for the I/O. This needs to be initialized before
+ // every call as the callback called when the I/O completes stops it.
+ service_.reset(new IOService());
+
+ // The object that will do the I/O
+ IOFetch fetch(IOFetch::UDP, *service_, sendbuf,
+ IOAddress(options.getAddress()), options.getPort(), recvbuf,
+ this, options.getTimeout());
+
+ // Execute the message exhange. The call to run() will return when a
+ // response is received or when the I/O times out.
+ (service_->get_io_service()).post(fetch);
+ service_->run();
+}
+
+// I/O Callback. Called when the message exchange compltes or times out.
+void
+Scan::operator()(IOFetch::Result result) {
+
+ // Record the result. This is accessed when deciding what was returned
+ // (if a timeout, nothing was returned).
+ result_ = result;
+
+ // Stop the I/O service. This will cause the call to run() to return.
+ service_->stop();
+}
+
+
+
+} // namespace test
+} // namespace isc
diff --git a/tests/tools/badpacket/scan.h b/tests/tools/badpacket/scan.h
new file mode 100644
index 0000000..04b80ad
--- /dev/null
+++ b/tests/tools/badpacket/scan.h
@@ -0,0 +1,107 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __SCAN_H
+#define __SCAN_H
+
+#include <stdint.h>
+
+#include <boost/scoped_ptr.hpp>
+
+#include <config.h>
+
+#include <asiolink/io_fetch.h>
+#include <asiolink/io_service.h>
+#include <dns/buffer.h>
+
+#include "command_options.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.
+
+class Scan : public asiolink::IOFetch::Callback {
+public:
+
+ /// \brief Constructor
+ Scan() : service_(), result_()
+ {}
+
+ /// \brief Run Scan
+ ///
+ /// \param options Command-line options
+ void scan(const CommandOptions& options);
+
+ /// \brief Callback
+ ///
+ /// This class is derived from the IOFetch::Callback class as it acts as the
+ /// callback object. When an asynchronous I/I has completed, this method
+ /// will be called.
+ ///
+ /// \param result Result of the asynchronous I/O. Zero implies success.
+ virtual void operator()(asiolink::IOFetch::Result result);
+
+private:
+ /// \brief Scan One Value
+ ///
+ /// Performs one exchange of packets with the remote nameserver, sending
+ /// the specified message.
+ ///
+ /// \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 scanOne(isc::dns::OutputBufferPtr& msgbuf,
+ const CommandOptions& options);
+
+ /// \brief Perform I/O
+ ///
+ /// Performs a single query to the nameserver and reads the response. It
+ /// outputs a summary of the result.
+ ///
+ /// \param sendbuf Buffer sent to the nameserver
+ /// \param recvbuf Buffer to hold reply from the nameserver
+ /// \param options Command-line options
+ void performIO(isc::dns::OutputBufferPtr& sendbuf,
+ isc::dns::OutputBufferPtr& recvbuf,
+ const CommandOptions& options);
+
+ /// \brief Get Fields
+ ///
+ /// Interprets the flags fields in a DNS message and converts them to a
+ /// terxtual format.
+ ///
+ /// \param msg Message for which the header is value
+ ///
+ /// \return A string that holds a textual interpretation of all the fields
+ /// in the header.
+ std::string getFields(isc::dns::OutputBufferPtr& msgbuf);
+
+ // Member variables
+
+ boost::scoped_ptr<asiolink::IOService> service_;///< Service to run the scan
+ asiolink::IOFetch::Result result_; ///< Result of the I/O
+};
+
+} // namespace test
+} // namespace isc
+
+#endif // __SCAN_H
diff --git a/tests/tools/badpacket/tests/Makefile.am b/tests/tools/badpacket/tests/Makefile.am
new file mode 100644
index 0000000..3f38be9
--- /dev/null
+++ b/tests/tools/badpacket/tests/Makefile.am
@@ -0,0 +1,29 @@
+SUBDIRS = .
+
+AM_CPPFLAGS = -I$(top_builddir)/src/lib -I$(top_srcdir)/src/lib
+AM_CPPFLAGS += $(BOOST_INCLUDES)
+AM_CXXFLAGS = $(B10_CXXFLAGS)
+
+if USE_STATIC_LINK
+AM_LDFLAGS = -static
+endif
+
+CLEANFILES = *.gcno *.gcda
+
+TESTS =
+if HAVE_GTEST
+TESTS += run_unittests
+run_unittests_SOURCES = run_unittests.cc
+run_unittests_SOURCES += command_options_unittest.cc
+run_unittests_SOURCES += header_flags_unittest.cc
+run_unittests_SOURCES += $(top_builddir)/tests/tools/badpacket/command_options.cc
+
+run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
+run_unittests_LDFLAGS = $(AM_LDFLAGS) $(GTEST_LDFLAGS)
+run_unittests_LDFLAGS += $(top_builddir)/src/lib/log/liblog.la
+run_unittests_LDFLAGS += $(top_builddir)/src/lib/exceptions/libexceptions.la
+
+run_unittests_LDADD = $(GTEST_LDADD)
+endif
+
+noinst_PROGRAMS = $(TESTS)
diff --git a/tests/tools/badpacket/tests/command_options_unittest.cc b/tests/tools/badpacket/tests/command_options_unittest.cc
new file mode 100644
index 0000000..fe7ceb0
--- /dev/null
+++ b/tests/tools/badpacket/tests/command_options_unittest.cc
@@ -0,0 +1,545 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cstddef>
+#include <string>
+#include <gtest/gtest.h>
+
+#include "../command_options.h"
+
+#include "exceptions/exceptions.h"
+
+using namespace std;
+using namespace isc;
+using namespace isc::badpacket;
+
+
+// Test fixture class
+
+class CommandOptionsTest : public virtual ::testing::Test,
+ public virtual CommandOptions
+{
+public:
+ CommandOptionsTest() {}
+};
+
+// Check that the getRange() method works
+
+TEST_F(CommandOptionsTest, processOptionValue) {
+
+ uint32_t result[2];
+
+ // Check valid data
+ processOptionValue("1", result, 0, 1);
+ EXPECT_EQ(1, result[0]);
+ EXPECT_EQ(1, result[1]);
+
+ processOptionValue("0-2", result, 0, 5);
+ EXPECT_EQ(0, result[0]);
+ EXPECT_EQ(2, result[1]);
+
+ processOptionValue("4-8", result, 0, 10);
+ EXPECT_EQ(4, result[0]);
+ EXPECT_EQ(8, result[1]);
+
+ processOptionValue("172-103", result, 0, 200);
+ EXPECT_EQ(103, result[0]);
+ EXPECT_EQ(172, result[1]);
+
+ // Check coercion is as expected
+ processOptionValue("1", result, 3, 4); // Single value below range
+ EXPECT_EQ(3, result[0]);
+ EXPECT_EQ(3, result[1]);
+
+ processOptionValue("7", result, 3, 6); // Single value above range
+ EXPECT_EQ(6, result[0]);
+ EXPECT_EQ(6, result[1]);
+
+ processOptionValue("2-6", result, 5, 10); // Range overlaps valid range on low side
+ EXPECT_EQ(5, result[0]);
+ EXPECT_EQ(6, result[1]);
+
+ processOptionValue("4-7", result, 5, 9); // Range overlaps valid range on high side
+ EXPECT_EQ(5, result[0]);
+ EXPECT_EQ(7, result[1]);
+
+ processOptionValue("9-1", result, 4, 8); // Range overlaps valid range
+ EXPECT_EQ(4, result[0]);
+ EXPECT_EQ(8, result[1]);
+
+ processOptionValue("4-8", result, 1, 9); // Range inside valid range
+ EXPECT_EQ(4, result[0]);
+ EXPECT_EQ(8, result[1]);
+
+ // Now the invalid ones.
+ EXPECT_ANY_THROW(processOptionValue("", result, 0, 1));
+ EXPECT_ANY_THROW(processOptionValue(" ", result, 0, 1));
+ EXPECT_ANY_THROW(processOptionValue("abc", result, 0, 1));
+ EXPECT_ANY_THROW(processOptionValue("xyz-def", result, 0, 1));
+ EXPECT_ANY_THROW(processOptionValue("0.7", result, 0, 1));
+ EXPECT_ANY_THROW(processOptionValue("0.7-2.3", result, 0, 1));
+}
+
+
+// Checks the minimum and maximum values specified for a flag
+void
+checkValuePair(const uint32_t value[2], uint32_t minval = 0,
+ uint32_t maxval = 0)
+{
+ EXPECT_EQ(minval, value[0]);
+ EXPECT_EQ(maxval, value[1]);
+}
+
+// Checks that all flag values in the command values are zero
+void
+checkDefaultFlagValues(const CommandOptions::FlagValues& values) {
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+}
+
+// Checks non-flag options are set to defaults.
+void
+checkDefaultOtherValues(CommandOptions& options) {
+ EXPECT_EQ("127.0.0.1", options.getAddress());
+ EXPECT_EQ(53, options.getPort());
+ EXPECT_EQ(500, options.getTimeout());
+ EXPECT_EQ("www.example.com", options.getQname());
+}
+
+// Check that each of the options will be recognised
+
+TEST_F(CommandOptionsTest, address) {
+ const char* argv[] = {"badpacket", "--address", "192.0.2.1"};
+ int argc = sizeof(argv) / sizeof(const char*);
+
+ // The conversion is ugly but it simplifies the process of entering the
+ // string constant. The cast throws away the "const"ness of the pointed-to
+ // strings in order to conform to the function signature; however, the
+ // called functions all treat the strings as const.
+ parse(argc, const_cast<char**>(argv));
+ EXPECT_EQ("192.0.2.1", getAddress());
+ EXPECT_EQ(53, getPort());
+ EXPECT_EQ(500, getTimeout());
+ EXPECT_EQ("www.example.com", getQname());
+ checkDefaultFlagValues(getFlagValues());
+}
+
+TEST_F(CommandOptionsTest, port) {
+ const char* argv[] = {"badpacket", "--port", "153"};
+ int argc = sizeof(argv) / sizeof(const char*);
+
+ parse(argc, const_cast<char**>(argv));
+ EXPECT_EQ("127.0.0.1", getAddress());
+ EXPECT_EQ(153, getPort());
+ EXPECT_EQ(500, getTimeout());
+ EXPECT_EQ("www.example.com", getQname());
+ checkDefaultFlagValues(getFlagValues());
+}
+
+TEST_F(CommandOptionsTest, timeout) {
+ const char* argv[] = {"badpacket", "--timeout", "250"};
+ int argc = sizeof(argv) / sizeof(const char*);
+
+ parse(argc, const_cast<char**>(argv));
+ EXPECT_EQ("127.0.0.1", getAddress());
+ EXPECT_EQ(53, getPort());
+ EXPECT_EQ(250, getTimeout());
+ EXPECT_EQ("www.example.com", getQname());
+ checkDefaultFlagValues(getFlagValues());
+}
+
+TEST_F(CommandOptionsTest, parameter) {
+ const char* argv[] = {"badpacket", "ftp.example.net"};
+ int argc = sizeof(argv) / sizeof(const char*);
+
+ parse(argc, const_cast<char**>(argv));
+ EXPECT_EQ("127.0.0.1", getAddress());
+ EXPECT_EQ(53, getPort());
+ EXPECT_EQ(500, getTimeout());
+ EXPECT_EQ("ftp.example.net", getQname());
+ checkDefaultFlagValues(getFlagValues());
+}
+
+// The various tests of the different flags
+TEST_F(CommandOptionsTest, qr) {
+
+ // Specifying a value of zero, we expect all flag values to be zero
+ const char* argv1[] = {"badpacket", "--qr", "0"};
+ int argc1 = sizeof(argv1) / sizeof(const char*);
+
+ parse(argc1, const_cast<char**>(argv1));
+ checkDefaultOtherValues(*this);
+ FlagValues values = getFlagValues();
+ checkDefaultFlagValues(values);
+
+ // 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(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr, 1, 1);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.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(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr, 0, 1);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+}
+
+// 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 values and
+// variables.)
+
+TEST_F(CommandOptionsTest, op) {
+
+ // Specifying a value of zero, we expect all flag values to be zero
+ const char* argv1[] = {"badpacket", "--op", "0"};
+ int argc1 = sizeof(argv1) / sizeof(const char*);
+
+ parse(argc1, const_cast<char**>(argv1));
+ checkDefaultOtherValues(*this);
+ FlagValues values = getFlagValues();
+ checkDefaultFlagValues(values);
+
+ // 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(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op, 8, 8);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+
+ // Check that a range is accepted (in this case, specified backwards and
+ // outside the range - so it should be truncated).
+ const char* argv3[] = {"badpacket", "--op", "21-0"};
+ int argc3 = sizeof(argv3) / sizeof(const char*);
+
+ parse(argc3, const_cast<char**>(argv3));
+ checkDefaultOtherValues(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op, 0, 15);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+}
+
+TEST_F(CommandOptionsTest, aa) {
+
+ // Specifying a value of zero, we expect all flag values to be zero
+ const char* argv1[] = {"badpacket", "--aa", "0"};
+ int argc1 = sizeof(argv1) / sizeof(const char*);
+
+ parse(argc1, const_cast<char**>(argv1));
+ checkDefaultOtherValues(*this);
+ FlagValues values = getFlagValues();
+ checkDefaultFlagValues(values);
+
+ // 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(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa, 1, 1);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+
+ // Check that a range is accepted (in this case, specified backwards and
+ // outside the range - so it should be truncated).
+ const char* argv3[] = {"badpacket", "--aa", "21-0"};
+ int argc3 = sizeof(argv3) / sizeof(const char*);
+
+ parse(argc3, const_cast<char**>(argv3));
+ checkDefaultOtherValues(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa, 0, 1);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+}
+
+TEST_F(CommandOptionsTest, tc) {
+
+ // Specifying a value of zero, we expect all flag values to be zero
+ const char* argv1[] = {"badpacket", "--tc", "0"};
+ int argc1 = sizeof(argv1) / sizeof(const char*);
+
+ parse(argc1, const_cast<char**>(argv1));
+ checkDefaultOtherValues(*this);
+ FlagValues values = getFlagValues();
+ checkDefaultFlagValues(values);
+
+ // 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(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc, 1, 1);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+
+ // Check that a range is accepted (in this case, specified backwards and
+ // outside the range - so it should be truncated).
+ const char* argv3[] = {"badpacket", "--tc", "21-0"};
+ int argc3 = sizeof(argv3) / sizeof(const char*);
+
+ parse(argc3, const_cast<char**>(argv3));
+ checkDefaultOtherValues(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc, 0, 1);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+}
+
+TEST_F(CommandOptionsTest, z) {
+
+ // Specifying a value of zero, we expect all flag values to be zero
+ const char* argv1[] = {"badpacket", "--z", "0"};
+ int argc1 = sizeof(argv1) / sizeof(const char*);
+
+ parse(argc1, const_cast<char**>(argv1));
+ checkDefaultOtherValues(*this);
+ FlagValues values = getFlagValues();
+ checkDefaultFlagValues(values);
+
+ // 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(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z, 1, 1);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+
+ // Check that a range is accepted (in this case, specified backwards and
+ // outside the range - so it should be truncated).
+ const char* argv3[] = {"badpacket", "--z", "21-0"};
+ int argc3 = sizeof(argv3) / sizeof(const char*);
+
+ parse(argc3, const_cast<char**>(argv3));
+ checkDefaultOtherValues(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z, 0, 1);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+}
+
+TEST_F(CommandOptionsTest, ad) {
+
+ // Specifying a value of zero, we expect all flag values to be zero
+ const char* argv1[] = {"badpacket", "--ad", "0"};
+ int argc1 = sizeof(argv1) / sizeof(const char*);
+
+ parse(argc1, const_cast<char**>(argv1));
+ checkDefaultOtherValues(*this);
+ FlagValues values = getFlagValues();
+ checkDefaultFlagValues(values);
+
+ // 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(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad, 1, 1);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+
+ // Check that a range is accepted (in this case, specified backwards and
+ // outside the range - so it should be truncated).
+ const char* argv3[] = {"badpacket", "--ad", "21-0"};
+ int argc3 = sizeof(argv3) / sizeof(const char*);
+
+ parse(argc3, const_cast<char**>(argv3));
+ checkDefaultOtherValues(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad, 0, 1);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc);
+}
+
+TEST_F(CommandOptionsTest, cd) {
+
+ // Specifying a value of zero, we expect all flag values to be zero
+ const char* argv1[] = {"badpacket", "--cd", "0"};
+ int argc1 = sizeof(argv1) / sizeof(const char*);
+
+ parse(argc1, const_cast<char**>(argv1));
+ checkDefaultOtherValues(*this);
+ FlagValues values = getFlagValues();
+ checkDefaultFlagValues(values);
+
+ // 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(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd, 1, 1);
+ checkValuePair(values.rc);
+
+ // Check that a range is accepted (in this case, specified backwards and
+ // outside the range - so it should be truncated).
+ const char* argv3[] = {"badpacket", "--cd", "21-0"};
+ int argc3 = sizeof(argv3) / sizeof(const char*);
+
+ parse(argc3, const_cast<char**>(argv3));
+ checkDefaultOtherValues(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd, 0, 1);
+ checkValuePair(values.rc);
+}
+
+TEST_F(CommandOptionsTest, rc) {
+
+ // Specifying a value of zero, we expect all flag values to be zero
+ const char* argv1[] = {"badpacket", "--rc", "0"};
+ int argc1 = sizeof(argv1) / sizeof(const char*);
+
+ parse(argc1, const_cast<char**>(argv1));
+ checkDefaultOtherValues(*this);
+ FlagValues values = getFlagValues();
+ checkDefaultFlagValues(values);
+
+ // Check that a value of 1 is accepted
+ const char* argv2[] = {"badpacket", "--rc", "21"};
+ int argc2 = sizeof(argv2) / sizeof(const char*);
+
+ parse(argc2, const_cast<char**>(argv2));
+ checkDefaultOtherValues(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.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", "21-0"};
+ int argc3 = sizeof(argv3) / sizeof(const char*);
+
+ parse(argc3, const_cast<char**>(argv3));
+ checkDefaultOtherValues(*this);
+ values = getFlagValues();
+ checkValuePair(values.qr);
+ checkValuePair(values.op);
+ checkValuePair(values.aa);
+ checkValuePair(values.tc);
+ checkValuePair(values.z);
+ checkValuePair(values.ad);
+ checkValuePair(values.cd);
+ checkValuePair(values.rc, 0, 15);
+}
+
+
+// Check that the other flags work
diff --git a/tests/tools/badpacket/tests/header_flags_unittest.cc b/tests/tools/badpacket/tests/header_flags_unittest.cc
new file mode 100644
index 0000000..dce4dc9
--- /dev/null
+++ b/tests/tools/badpacket/tests/header_flags_unittest.cc
@@ -0,0 +1,306 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <cstddef>
+#include <stdint.h>
+#include <gtest/gtest.h>
+
+#include "../header_flags.h"
+
+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.getQR());
+ EXPECT_EQ(0, flags.getOP());
+ EXPECT_EQ(0, flags.getAA());
+ EXPECT_EQ(0, flags.getTC());
+ EXPECT_EQ(0, flags.getRD());
+ EXPECT_EQ(0, flags.getRA());
+ EXPECT_EQ(0, flags.getZ());
+ EXPECT_EQ(0, flags.getAD());
+ EXPECT_EQ(0, flags.getCD());
+ EXPECT_EQ(0, flags.getRC());
+
+ EXPECT_EQ(0, flags.getValue());
+}
+
+
+// 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.setQR(1);
+ EXPECT_EQ(1, flags.getQR());
+ EXPECT_EQ(0, flags.getOP());
+ EXPECT_EQ(0, flags.getAA());
+ EXPECT_EQ(0, flags.getTC());
+ EXPECT_EQ(0, flags.getRD());
+ EXPECT_EQ(0, flags.getRA());
+ EXPECT_EQ(0, flags.getZ());
+ EXPECT_EQ(0, flags.getAD());
+ EXPECT_EQ(0, flags.getCD());
+ EXPECT_EQ(0, flags.getRC());
+ EXPECT_NE(0, flags.getValue());
+
+ flags.setQR(0);
+ checkZero(flags);
+}
+
+TEST_F(HeaderFlagsTest, OPfield) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.setOP(15);
+ EXPECT_EQ(0, flags.getQR());
+ EXPECT_EQ(15, flags.getOP());
+ EXPECT_EQ(0, flags.getAA());
+ EXPECT_EQ(0, flags.getTC());
+ EXPECT_EQ(0, flags.getRD());
+ EXPECT_EQ(0, flags.getRA());
+ EXPECT_EQ(0, flags.getZ());
+ EXPECT_EQ(0, flags.getAD());
+ EXPECT_EQ(0, flags.getCD());
+ EXPECT_EQ(0, flags.getRC());
+ EXPECT_NE(0, flags.getValue());
+
+ flags.setOP(0);
+ checkZero(flags);
+}
+
+TEST_F(HeaderFlagsTest, AAfield) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.setAA(1);
+ EXPECT_EQ(0, flags.getQR());
+ EXPECT_EQ(0, flags.getOP());
+ EXPECT_EQ(1, flags.getAA());
+ EXPECT_EQ(0, flags.getTC());
+ EXPECT_EQ(0, flags.getRD());
+ EXPECT_EQ(0, flags.getRA());
+ EXPECT_EQ(0, flags.getZ());
+ EXPECT_EQ(0, flags.getAD());
+ EXPECT_EQ(0, flags.getCD());
+ EXPECT_EQ(0, flags.getRC());
+ EXPECT_NE(0, flags.getValue());
+
+ flags.setAA(0);
+ checkZero(flags);
+}
+
+TEST_F(HeaderFlagsTest, TCfield) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.setTC(1);
+ EXPECT_EQ(0, flags.getQR());
+ EXPECT_EQ(0, flags.getOP());
+ EXPECT_EQ(0, flags.getAA());
+ EXPECT_EQ(1, flags.getTC());
+ EXPECT_EQ(0, flags.getRD());
+ EXPECT_EQ(0, flags.getRA());
+ EXPECT_EQ(0, flags.getZ());
+ EXPECT_EQ(0, flags.getAD());
+ EXPECT_EQ(0, flags.getCD());
+ EXPECT_EQ(0, flags.getRC());
+ EXPECT_NE(0, flags.getValue());
+
+ flags.setTC(0);
+ checkZero(flags);
+}
+
+TEST_F(HeaderFlagsTest, RDfield) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.setRD(1);
+ EXPECT_EQ(0, flags.getQR());
+ EXPECT_EQ(0, flags.getOP());
+ EXPECT_EQ(0, flags.getAA());
+ EXPECT_EQ(0, flags.getTC());
+ EXPECT_EQ(1, flags.getRD());
+ EXPECT_EQ(0, flags.getRA());
+ EXPECT_EQ(0, flags.getZ());
+ EXPECT_EQ(0, flags.getAD());
+ EXPECT_EQ(0, flags.getCD());
+ EXPECT_EQ(0, flags.getRC());
+ EXPECT_NE(0, flags.getValue());
+
+ flags.setRD(0);
+ checkZero(flags);
+}
+
+TEST_F(HeaderFlagsTest, RAfield) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.setRA(1);
+ EXPECT_EQ(0, flags.getQR());
+ EXPECT_EQ(0, flags.getOP());
+ EXPECT_EQ(0, flags.getAA());
+ EXPECT_EQ(0, flags.getTC());
+ EXPECT_EQ(0, flags.getRD());
+ EXPECT_EQ(1, flags.getRA());
+ EXPECT_EQ(0, flags.getZ());
+ EXPECT_EQ(0, flags.getAD());
+ EXPECT_EQ(0, flags.getCD());
+ EXPECT_EQ(0, flags.getRC());
+ EXPECT_NE(0, flags.getValue());
+
+ flags.setRA(0);
+ checkZero(flags);
+}
+
+TEST_F(HeaderFlagsTest, Zfield) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.setZ(1);
+ EXPECT_EQ(0, flags.getQR());
+ EXPECT_EQ(0, flags.getOP());
+ EXPECT_EQ(0, flags.getAA());
+ EXPECT_EQ(0, flags.getTC());
+ EXPECT_EQ(0, flags.getRD());
+ EXPECT_EQ(0, flags.getRA());
+ EXPECT_EQ(1, flags.getZ());
+ EXPECT_EQ(0, flags.getAD());
+ EXPECT_EQ(0, flags.getCD());
+ EXPECT_EQ(0, flags.getRC());
+ EXPECT_NE(0, flags.getValue());
+
+ flags.setZ(0);
+ checkZero(flags);
+}
+
+TEST_F(HeaderFlagsTest, ADfield) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.setAD(1);
+ EXPECT_EQ(0, flags.getQR());
+ EXPECT_EQ(0, flags.getOP());
+ EXPECT_EQ(0, flags.getAA());
+ EXPECT_EQ(0, flags.getTC());
+ EXPECT_EQ(0, flags.getRD());
+ EXPECT_EQ(0, flags.getRA());
+ EXPECT_EQ(0, flags.getZ());
+ EXPECT_EQ(1, flags.getAD());
+ EXPECT_EQ(0, flags.getCD());
+ EXPECT_EQ(0, flags.getRC());
+ EXPECT_NE(0, flags.getValue());
+
+ flags.setAD(0);
+ checkZero(flags);
+}
+
+TEST_F(HeaderFlagsTest, CDfield) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.setCD(1);
+ EXPECT_EQ(0, flags.getQR());
+ EXPECT_EQ(0, flags.getOP());
+ EXPECT_EQ(0, flags.getAA());
+ EXPECT_EQ(0, flags.getTC());
+ EXPECT_EQ(0, flags.getRD());
+ EXPECT_EQ(0, flags.getRA());
+ EXPECT_EQ(0, flags.getZ());
+ EXPECT_EQ(0, flags.getAD());
+ EXPECT_EQ(1, flags.getCD());
+ EXPECT_EQ(0, flags.getRC());
+ EXPECT_NE(0, flags.getValue());
+
+ flags.setCD(0);
+ checkZero(flags);
+}
+
+TEST_F(HeaderFlagsTest, RCfield) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.setRC(7);
+ EXPECT_EQ(0, flags.getQR());
+ EXPECT_EQ(0, flags.getOP());
+ EXPECT_EQ(0, flags.getAA());
+ EXPECT_EQ(0, flags.getTC());
+ EXPECT_EQ(0, flags.getRD());
+ EXPECT_EQ(0, flags.getRA());
+ EXPECT_EQ(0, flags.getZ());
+ EXPECT_EQ(0, flags.getAD());
+ EXPECT_EQ(0, flags.getCD());
+ EXPECT_EQ(7, flags.getRC());
+ EXPECT_NE(0, flags.getValue());
+
+ flags.setRC(0);
+ checkZero(flags);
+}
+
+// Check that the correct bits are set
+
+TEST_F(HeaderFlagsTest, bitValues) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.setQR(1);
+ EXPECT_EQ(0x8000, flags.getValue());
+
+ flags.setQR(0);
+ flags.setOP(15);
+ EXPECT_EQ(0x7800, flags.getValue());
+
+ flags.setOP(0);
+ flags.setAA(1);
+ EXPECT_EQ(0x0400, flags.getValue());
+
+ flags.setAA(0);
+ flags.setTC(1);
+ EXPECT_EQ(0x0200, flags.getValue());
+
+ flags.setTC(0);
+ flags.setRD(1);
+ EXPECT_EQ(0x0100, flags.getValue());
+
+ flags.setRD(0);
+ flags.setRA(1);
+ EXPECT_EQ(0x0080, flags.getValue());
+
+ flags.setRA(0);
+ flags.setZ(1);
+ EXPECT_EQ(0x0040, flags.getValue());
+
+ flags.setZ(0);
+ flags.setAD(1);
+ EXPECT_EQ(0x0020, flags.getValue());
+
+ flags.setAD(0);
+ flags.setCD(1);
+ EXPECT_EQ(0x0010, flags.getValue());
+
+ flags.setCD(0);
+ flags.setRC(15);
+ EXPECT_EQ(0x000F, flags.getValue());
+}
diff --git a/tests/tools/badpacket/tests/run_unittests.cc b/tests/tools/badpacket/tests/run_unittests.cc
new file mode 100644
index 0000000..624cf6f
--- /dev/null
+++ b/tests/tools/badpacket/tests/run_unittests.cc
@@ -0,0 +1,24 @@
+// Copyright (C) 2009 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#include <config.h>
+
+#include <gtest/gtest.h>
+
+int
+main(int argc, char* argv[]) {
+ ::testing::InitGoogleTest(&argc, argv);
+
+ return (RUN_ALL_TESTS());
+}
diff --git a/tests/tools/badpacket/version.h b/tests/tools/badpacket/version.h
new file mode 100644
index 0000000..dc59b11
--- /dev/null
+++ b/tests/tools/badpacket/version.h
@@ -0,0 +1,26 @@
+// Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef __VERSION_H
+#define __VERSION_H
+
+namespace isc {
+namespace badpacket {
+
+static const char* BADPACKET_VERSION = "1.0-1";
+
+} // namespace badpacket
+} // namespace isc
+
+#endif // __VERSION_H
More information about the bind10-changes
mailing list