BIND 10 master, updated. 54cc81d718e60a3e095fecefe502cdca9dad1776 [master] Update git version in ChangeLog entry
BIND 10 source code commits
bind10-changes at lists.isc.org
Fri Apr 15 10:58:40 UTC 2011
The branch, master has been updated
via 54cc81d718e60a3e095fecefe502cdca9dad1776 (commit)
via 1b666838b6c0fe265522b30971e878d9f0d21fde (commit)
via 20607bda887846e2745bac1d275c51874885f917 (commit)
via 17106327efdf114e15b21cf8079f9191ab073648 (commit)
via 06c4fa64bb59638af953e9b3961d23e173eab49f (commit)
via 3b42967a83f4e15e1b1d07a159a600cb67628039 (commit)
via 3c348815b0ddc70deed6e5ffcdb3b6828edae961 (commit)
via 2c8303354db6a7d41b4c2e90181b5fcd5db40aee (commit)
via 96b5b4c186fffb2a52891209bd8c95e92e45573e (commit)
via 6f91ee90cd428b0e7eecd4cb99eefc0201f4360e (commit)
via bc88971bdb67728a22d029504bf18e778af26591 (commit)
via 3999bb246ea782310611471d3ff28cdd85bf4a0d (commit)
via 10b62db1ae170eed2fb897335037d50c399b37e9 (commit)
via f155c3edec68515cccb5f5c4da611af08770ae4e (commit)
via 4e9bf13057eba0ccff7052f1859ab49b0a27c777 (commit)
via 6ce4dde0aeb2a0aa3457f0037be5d549b3e9b966 (commit)
via cdf229b32e2138c7d451eead64d7fdc2d69e94b7 (commit)
via c3a18648a3d7f96325a529f87ed5824183fa0ce5 (commit)
via 30872fc580a3cb357bdd34765eaecc1d61820b16 (commit)
via f2de716ada3aa2c0862f3d7d21ef10d28db90219 (commit)
from 921ca1236dbf64fa1f73a03a6903b5a2fa82f84d (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 54cc81d718e60a3e095fecefe502cdca9dad1776
Author: Stephen Morris <stephen at isc.org>
Date: Fri Apr 15 11:58:13 2011 +0100
[master] Update git version in ChangeLog entry
-----------------------------------------------------------------------
Summary of changes:
ChangeLog | 11 +-
configure.ac | 7 +-
src/lib/asiodns/io_fetch.cc | 72 +++--
src/lib/asiodns/io_fetch.h | 30 ++-
tests/Makefile.am | 2 +-
tests/tools/Makefile.am | 1 +
tests/tools/badpacket/Makefile.am | 28 ++
tests/tools/badpacket/README | 53 +++
tests/tools/badpacket/badpacket.cc | 62 ++++
tests/tools/badpacket/command_options.cc | 333 ++++++++++++++++++++
tests/tools/badpacket/command_options.h | 162 ++++++++++
tests/tools/badpacket/header_flags.h | 102 ++++++
tests/tools/badpacket/option_info.cc | 114 +++++++
tests/tools/badpacket/option_info.h | 174 ++++++++++
tests/tools/badpacket/scan.cc | 309 ++++++++++++++++++
tests/tools/badpacket/scan.h | 198 ++++++++++++
tests/tools/badpacket/tests/Makefile.am | 31 ++
.../badpacket/tests/command_options_unittest.cc | 300 ++++++++++++++++++
.../tools/badpacket/tests/header_flags_unittest.cc | 141 +++++++++
.../tools/badpacket/tests/option_info_unittest.cc | 161 ++++++++++
.../tools/badpacket}/tests/run_unittests.cc | 3 +
.../tools/badpacket/version.h | 14 +-
22 files changed, 2267 insertions(+), 41 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/option_info.cc
create mode 100644 tests/tools/badpacket/option_info.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
create mode 100644 tests/tools/badpacket/tests/option_info_unittest.cc
copy {src/lib/config => tests/tools/badpacket}/tests/run_unittests.cc (97%)
copy src/lib/log/message_exception.cc => tests/tools/badpacket/version.h (83%)
-----------------------------------------------------------------------
diff --git a/ChangeLog b/ChangeLog
index 87a05c9..c6b8337 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,12 @@
+220. [func] stephen
+ Added the 'badpacket' program for testing; it sends a set of
+ (potentially) bad packets to a nameserver and prints the responses.
+ (Trac #703, git 1b666838b6c0fe265522b30971e878d9f0d21fde)
+
219. [func] ocean
- src/lib: move some dns related code out of asiolink library to
- asiodns library
- (Trac #751, git 262ac6c6fc61224d54705ed4c700dadb606fcb1c)
+ src/lib: move some dns related code out of asiolink library to
+ asiodns library
+ (Trac #751, git 262ac6c6fc61224d54705ed4c700dadb606fcb1c)
218. [func] jinmei
src/lib/dns: added support for RP RDATA.
diff --git a/configure.ac b/configure.ac
index 8e30987..63bd985 100644
--- a/configure.ac
+++ b/configure.ac
@@ -694,12 +694,15 @@ AC_CONFIG_FILES([Makefile
src/lib/cache/tests/Makefile
src/lib/server_common/Makefile
src/lib/server_common/tests/Makefile
- tests/Makefile
- tests/system/Makefile
src/lib/util/Makefile
src/lib/util/io/Makefile
src/lib/util/io/tests/Makefile
src/lib/util/unittests/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/asiodns/io_fetch.cc b/src/lib/asiodns/io_fetch.cc
index 7a5cf2d..f543ce2 100644
--- a/src/lib/asiodns/io_fetch.cc
+++ b/src/lib/asiodns/io_fetch.cc
@@ -14,23 +14,18 @@
#include <config.h>
-#include <unistd.h> // for some IPC/network system calls
-#include <sys/socket.h>
#include <netinet/in.h>
+#include <stdint.h>
+#include <sys/socket.h>
+#include <unistd.h> // for some IPC/network system calls
#include <boost/bind.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/date_time/posix_time/posix_time_types.hpp>
-#include <dns/message.h>
-#include <dns/messagerenderer.h>
-#include <dns/opcode.h>
-#include <dns/rcode.h>
-#include <log/logger.h>
#include <asio.hpp>
#include <asio/deadline_timer.hpp>
-#include <asiodns/qid_gen.h>
-#include <asiodns/asiodef.h>
+
#include <asiolink/io_address.h>
#include <asiolink/io_asio_socket.h>
#include <asiolink/io_endpoint.h>
@@ -40,9 +35,16 @@
#include <asiolink/udp_endpoint.h>
#include <asiolink/udp_socket.h>
-#include "io_fetch.h"
+#include <dns/message.h>
+#include <dns/messagerenderer.h>
+#include <dns/opcode.h>
+#include <dns/rcode.h>
+#include <log/logger.h>
+
+#include <asiodns/asiodef.h>
+#include <asiodns/io_fetch.h>
+#include <asiodns/qid_gen.h>
-#include <stdint.h>
using namespace asio;
using namespace isc::asiolink;
@@ -55,7 +57,7 @@ namespace asiodns {
/// Use the ASIO logger
-isc::log::Logger logger("asiodns");
+isc::log::Logger logger("asiolink");
/// \brief IOFetch Data
///
@@ -85,6 +87,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
@@ -136,7 +139,6 @@ struct IOFetchData {
question(query),
msgbuf(new isc::dns::OutputBuffer(512)),
received(buff),
-
callback(cb),
timer(service.get_io_service()),
protocol(proto),
@@ -145,6 +147,7 @@ struct IOFetchData {
offset(0),
stopped(false),
timeout(wait),
+ packet(false),
origin(ASIODNS_UNKORIGIN),
staging(),
qid(QidGenerator::getInstance().generateQid())
@@ -174,6 +177,19 @@ 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
@@ -200,14 +216,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
@@ -234,7 +258,7 @@ IOFetch::operator()(asio::error_code ec, size_t length) {
data_->origin = ASIODNS_SENDSOCK;
CORO_YIELD data_->socket->asyncSend(data_->msgbuf->getData(),
data_->msgbuf->getLength(), data_->remote_snd.get(), *this);
-
+
// Now receive the response. Since TCP may not receive the entire
// message in one operation, we need to loop until we have received
// it. (This can't be done within the asyncReceive() method because
@@ -253,7 +277,7 @@ IOFetch::operator()(asio::error_code ec, size_t length) {
// the expected amount of data. Then we need to loop until we have
// received all the data before copying it back to the user's buffer.
// And we want to minimise the amount of copying...
-
+
data_->origin = ASIODNS_RECVSOCK;
data_->cumulative = 0; // No data yet received
data_->offset = 0; // First data into start of buffer
@@ -376,5 +400,5 @@ void IOFetch::logIOFailure(asio::error_code ec) {
}
} // namespace asiodns
-} // namespace isc
+} // namespace isc {
diff --git a/src/lib/asiodns/io_fetch.h b/src/lib/asiodns/io_fetch.h
index 0a11fb7..9c34acf 100644
--- a/src/lib/asiodns/io_fetch.h
+++ b/src/lib/asiodns/io_fetch.h
@@ -24,8 +24,8 @@
#include <coroutine.h>
#include <asio/error_code.hpp>
-#include <asiolink/io_service.h>
#include <asiolink/io_address.h>
+#include <asiolink/io_service.h>
#include <dns/buffer.h>
#include <dns/question.h>
@@ -117,12 +117,34 @@ 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.
+ /// \param question DNS question to send to the upstream server.
+ /// \param address IP address of upstream server
+ /// \param port Port to which to connect on 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 wait Timeout for the fetch (in ms). The default value of
+ /// -1 indicates no timeout.
+ IOFetch(Protocol protocol, isc::asiolink::IOService& service,
+ const isc::dns::Question& question,
+ const isc::asiolink::IOAddress& address,
+ uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb,
+ int wait = -1);
+
+ /// \brief Constructor.
+ ///
+ /// Creates the object that will handle the upstream fetch.
///
/// \param protocol Fetch protocol, either IOFetch::TCP or IOFetch::UDP
/// \param service I/O Service object to handle the asynchronous
/// operations.
- /// \param question DNS question to send to the upstream server.
+ /// \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
@@ -134,7 +156,7 @@ public:
/// \param wait Timeout for the fetch (in ms). The default value of
/// -1 indicates no timeout.
IOFetch(Protocol protocol, isc::asiolink::IOService& service,
- const isc::dns::Question& question,
+ isc::dns::OutputBufferPtr& outpkt,
const isc::asiolink::IOAddress& address,
uint16_t port, isc::dns::OutputBufferPtr& buff, Callback* cb,
int wait = -1);
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..b249f0e
--- /dev/null
+++ b/tests/tools/badpacket/Makefile.am
@@ -0,0 +1,28 @@
+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 += option_info.cc option_info.h
+badpacket_SOURCES += scan.cc scan.h
+badpacket_SOURCES += version.h
+
+badpacket_LDADD = $(top_builddir)/src/lib/asiodns/libasiodns.la
+badpacket_LDADD += $(top_builddir)/src/lib/dns/libdns++.la
+badpacket_LDADD += $(top_builddir)/src/lib/asiolink/libasiolink.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..3f5e801
--- /dev/null
+++ b/tests/tools/badpacket/README
@@ -0,0 +1,53 @@
+"badpacket" is a tool intended to test that a nameserver can cope with
+incorrectly-formatted DNS messages.
+
+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:
+
+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 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
+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 ...
+ (qr:1 op:0 aa:0 tc:0 rd:0 ra:1 ...
+
+(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:
+* Setting values in the flags field.
+* Setting section counts to arbitrary values.
+* Extending or truncating the DNS message size.
+
+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).
diff --git a/tests/tools/badpacket/badpacket.cc b/tests/tools/badpacket/badpacket.cc
new file mode 100644
index 0000000..86bbc47
--- /dev/null
+++ b/tests/tools/badpacket/badpacket.cc
@@ -0,0 +1,62 @@
+// 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 <iostream>
+
+#include <config.h>
+
+#include <exceptions/exceptions.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:
+/// - 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.
+///
+/// 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;
+
+/// \brief Main Program
+int main(int argc, char* argv[]) {
+
+ try {
+ // Parse command
+ CommandOptions options;
+ options.parse(argc, argv);
+
+ // Send the sequence of messages
+ Scan scanner;
+ scanner.scan(options);
+ } catch (isc::Exception& e) {
+ std::cout << "ERROR: " << e.what() << "\n";
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/tests/tools/badpacket/command_options.cc b/tests/tools/badpacket/command_options.cc
new file mode 100644
index 0000000..03eeb75
--- /dev/null
+++ b/tests/tools/badpacket/command_options.cc
@@ -0,0 +1,333 @@
+// 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 "option_info.h"
+#include "version.h"
+
+using namespace std;
+using namespace isc;
+
+namespace isc {
+namespace badpacket {
+
+// 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 "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*").
+
+ // General options.
+ char HELP[] = {"help"};
+ char VERSION[] = {"version"};
+ char ADDRESS[] = {"address"};
+ char PORT[] = {"port"};
+ char TIMEOUT[] = {"timeout"};
+
+ // Settings for options in the flags field.
+ char QR[] = {"qr"};
+ char OP[] = {"op"};
+ char AA[] = {"aa"};
+ char TC[] = {"tc"};
+ char RD[] = {"rd"};
+ char RA[] = {"ra"};
+ char Z[] = {"z"};
+ char AD[] = {"ad"};
+ char CD[] = {"cd"};
+ char RC[] = {"rc"};
+
+ // Settings for the count fields
+ char QC[] = {"qc"};
+ char AC[] = {"ac"};
+ 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
+ {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
+ {QC, 1, NULL, 'Y'}, // querY section count
+ {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:M:";
+
+
+ // Set record of options 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)
+ case 'O': // --op (operation code)
+ case 'A': // --aa (authoritative answer)
+ case 'T': // --tc (truncated)
+ case 'D': // --rd (recursion desired)
+ case 'R': // --ra (recursion available)
+ case 'Z': // --z (zero: reserved bit)
+ case 'U': // --ad (authenticated data)
+ case 'C': // --cd (checking disabled)
+ case 'E': // --rc (result code)
+ case 'Y': // --qc (query count)
+ case 'W': // --ac (answer count)
+ case 'H': // --uc (authority count)
+ case 'I': // --dc (additional count)
+ case 'M': // --ms (message size)
+ processOptionValue(c, optarg);
+ break;
+
+ default:
+ isc_throw(isc::InvalidParameter,
+ "unknown option given on the command line");
+ }
+ }
+
+ // 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");
+ }
+}
+
+// Print usage information.
+void
+CommandOptions::usage() {
+ cout << "Usage: badpacket [options] query\n"
+ "\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"
+ "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"
+ "\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"
+ "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"
+ "--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"
+ "\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> [-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"
+ "\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"
+ "--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. 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"
+ ;
+}
+
+// Print version information,
+void
+CommandOptions::version() {
+ cout << BADPACKET_VERSION << "\n";
+}
+
+// Process single flag that can be stored in the options_ member.
+void
+CommandOptions::processOptionValue(int c, const char* value) {
+
+ // 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.
+ 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 <<
+ "': it must be in the form 'int' or 'int1-int2'");
+ }
+
+ // Convert to uint32.
+ try {
+ 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 (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) &&
+ ((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 (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 (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;
+}
+
+// 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 (options_[index].minimum);
+}
+
+uint32_t
+CommandOptions::maximum(int index) const {
+ OptionInfo::checkIndex(index);
+ return (options_[index].maximum);
+}
+
+bool
+CommandOptions::present(int index) const {
+ OptionInfo::checkIndex(index);
+ return (options_[index].present);
+}
+
+} // 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..fc819e9
--- /dev/null
+++ b/tests/tools/badpacket/command_options.h
@@ -0,0 +1,162 @@
+// 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 "option_info.h"
+
+namespace isc {
+namespace badpacket {
+
+/// \brief Command Options
+///
+/// This class is responsible for parsing the command-line and storing the
+/// specified options.
+///
+/// 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 and can be
+/// returned on request.
+///
+/// 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 Default Constructor
+ ///
+ /// Set values to defaults.
+ CommandOptions() {
+ reset();
+ }
+
+ /// \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
+ /// the option was not specified on the command line).
+ uint32_t minimum(int index) const;
+
+ /// \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 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
+ 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
+ ///
+ /// Resets the CommandOptions object to default values.
+ void reset();
+
+ /// \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 and exit program
+ void usage();
+
+ /// \brief Print version information and exit program
+ void version();
+
+private:
+ /// \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 c Short form option character from the command line
+ /// \param value Value of the option read from the command line
+ void processOptionValue(int c, const char* value);
+
+ // Member variables
+
+ 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
+ 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..5d74e75
--- /dev/null
+++ b/tests/tools/badpacket/header_flags.h
@@ -0,0 +1,102 @@
+// 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
+
+#include <exceptions/exceptions.h>
+#include "option_info.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:
+
+ /// \brief Constructor
+ HeaderFlags() {
+ reset();
+ }
+
+ /// \brief Reset values to zero
+ ///
+ /// Clears all flags.
+ void reset() {
+ setValue(0);
+ }
+
+ /// \brief Get header flags as 16-bit value
+ uint16_t getValue() const {
+ return (flags_);
+ }
+
+ /// \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;
+ }
+
+ /// \brief Get field
+ ///
+ /// Return the value of a bit field in the flags word.
+ ///
+ /// \param int Index of the bit field in the OptionInfo data structure
+ ///
+ /// \return Value of the field.
+ uint16_t get(int index) const {
+ OptionInfo::checkIndex(index);
+ return ((flags_ & OptionInfo::mask(index)) >> OptionInfo::offset(index));
+ }
+
+ /// \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, a BadValue exception is thrown.
+ void set(int index, uint16_t value) {
+
+ // 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
+ // should not really be needed, as the command line parsing should have
+ // checked the limits. But be safe.)
+ if ((value < o.minval(index)) || (value > o.maxval(index))) {
+ isc_throw(isc::BadValue, "value of index " << index << " is out of range");
+ }
+
+ // Clear the field then set it with the value.
+ flags_ &= ~o.mask(index);
+ flags_ |= (value << o.offset(index));
+ }
+
+private:
+ uint16_t flags_; ///< Variable holding field values
+};
+
+} // namespace badpacket
+} // namespace isc
+
+#endif // __HEADER_FLAGS_H
diff --git a/tests/tools/badpacket/option_info.cc b/tests/tools/badpacket/option_info.cc
new file mode 100644
index 0000000..e1c1f78
--- /dev/null
+++ b/tests/tools/badpacket/option_info.cc
@@ -0,0 +1,114 @@
+// 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 "option_info.h"
+
+namespace {
+
+// Define the various options for the command switches. This includes both the
+// long form and short form of the switch. Unfortunately this means that the
+// 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},
+ {'O', "op", 2, 0x7800, 11, 0, 0, 15},
+ {'A', "aa", 2, 0x0400, 10, 0, 0, 1},
+ {'T', "tc", 2, 0x0200, 9, 0, 0, 1},
+ {'D', "rd", 2, 0x0100, 8, 0, 0, 1},
+ {'R', "ra", 2, 0x0080, 7, 0, 0, 1},
+ {'Z', "z", 2, 0x0040, 6, 0, 0, 1},
+ {'U', "ad", 2, 0x0020, 5, 0, 0, 1},
+ {'C', "cd", 2, 0x0010, 4, 0, 0, 1},
+ {'E', "rc", 2, 0x000F, 0, 0, 0, 15},
+ {'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},
+ {'M', "ms", 0, 0, 0, 0, 1, 65536}
+};
+
+} // Anonymous namespace
+
+namespace isc {
+namespace badpacket {
+
+// Locate the index of the information in the array from the short switch.
+int
+OptionInfo::getIndex(int c) {
+ for (int i = 0; i < SIZE; ++i) {
+ if (option_information[i].short_form == c) {
+ return (i);
+ }
+ }
+ isc_throw(isc::BadValue, "unknown option: " << c);
+}
+
+// Methods to return values from the array
+
+const char*
+OptionInfo::name(int i) {
+ checkIndex(i);
+ return (option_information[i].long_form);
+}
+
+uint16_t
+OptionInfo::mask(int i) {
+ checkIndex(i);
+ return (option_information[i].mask);
+}
+
+int
+OptionInfo::word(int i) {
+ checkIndex(i);
+ return (option_information[i].word);
+}
+
+int
+OptionInfo::offset(int i) {
+ checkIndex(i);
+ return (option_information[i].offset);
+}
+
+uint32_t
+OptionInfo::minval(int i) {
+ checkIndex(i);
+ return (option_information[i].minval);
+}
+
+uint32_t
+OptionInfo::defval(int i) {
+ checkIndex(i);
+ return (option_information[i].defval);
+}
+
+uint32_t
+OptionInfo::maxval(int i) {
+ checkIndex(i);
+ return (option_information[i].maxval);
+}
+
+} // namespace badpacket
+} // namespace isc
diff --git a/tests/tools/badpacket/option_info.h b/tests/tools/badpacket/option_info.h
new file mode 100644
index 0000000..a340c1d
--- /dev/null
+++ b/tests/tools/badpacket/option_info.h
@@ -0,0 +1,174 @@
+// 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 __OPTION_INFO_H
+#define __OPTION_INFO_H
+
+#include <stdint.h>
+#include "exceptions/exceptions.h"
+
+namespace isc {
+namespace badpacket {
+
+/// \brief Option Information
+///
+/// Holds details about the options that can be specified on the command line
+/// that require values and which control data put in the DNS message sent to
+/// the remote system.
+///
+/// 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 the available options.
+
+class OptionInfo {
+public:
+
+ /// \brief Array Indexes
+ ///
+ /// 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 {
+ 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
+ ///
+ /// Defines a structure that holds information associated with each of the
+ /// 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 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
+ uint32_t minval; // Minimum valid value for this field
+ uint32_t maxval; // Maximum valid value for this field
+ };
+
+ /// \brief Return index for command option
+ ///
+ /// 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 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.
+ static int getIndex(int c);
+
+ /// \brief Return long form of command switch for this field
+ ///
+ /// \param index A valid index (one of the values in the 'Index' enum).
+ ///
+ /// \return The long option name (e.q. "qr" for the Query/Response field).
+ static const char* name(int index);
+
+ /// \brief Return header word offset
+ ///
+ /// Returns the byte offset in the DNS message header of the two-byte word
+ /// holding the data in question.
+ ///
+ /// \param index A valid index (one of the values in the 'Index' enum).
+ ///
+ /// \return The offset in the header for this datum.
+ static int word(int index);
+
+ /// \brief Return mask associated with switch field
+ ///
+ /// \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
+ /// 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 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. 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 an option
+ ///
+ /// \param index A valid index (one of the values in the 'Index' enum).
+ ///
+ /// \return Minimum allowed value for this option.
+ static uint32_t minval(int index);
+
+ /// \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 an option
+ ///
+ /// \param index A valid index (one of the values in the 'Index' enum).
+ ///
+ /// \return Maximum allowed value for this option. If the option is a bit
+ /// in the flags field of the DNS message hearder, this will be 1.
+ static uint32_t maxval(int index);
+
+ /// \brief Check Array Index
+ ///
+ /// Checks the passed field index and throws an exception if it does not
+ /// 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 "
+ "0 to " << SIZE);
+ }
+ }
+};
+
+} // namespace badpacket
+} // namespace isc
+
+#endif // __OPTION_INFO_H
diff --git a/tests/tools/badpacket/scan.cc b/tests/tools/badpacket/scan.cc
new file mode 100644
index 0000000..7b843b4
--- /dev/null
+++ b/tests/tools/badpacket/scan.cc
@@ -0,0 +1,309 @@
+// 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 <stdlib.h>
+
+#include <asio.hpp>
+
+#include <asiolink/io_address.h>
+#include <asiodns/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 isc::asiolink;
+using namespace isc::asiodns;
+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);
+
+ iterateFlagsStart(msgbuf, options);
+}
+
+// Iterate through the various settings in the flags fields.
+void
+Scan::iterateFlagsStart(OutputBufferPtr& msgbuf, const CommandOptions& options) {
+ HeaderFlags flags;
+ 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::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);
+ }
+}
+
+// Alter the message size.
+void
+Scan::sizeMessage(OutputBufferPtr& msgbuf, const CommandOptions& options) {
+
+ if (options.present(OptionInfo::MS)) {
+
+ // Iterate over the range of message sizes
+ for (size_t i = options.minimum(OptionInfo::MS);
+ i <= options.maximum(OptionInfo::MS); ++i) {
+
+ // 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 outgoing message.
+ string fields = string("(") + getFields(msgbuf) + string(")");
+
+ // 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 = string("(") + getFields(replybuf) + string(")");
+ 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.
+std::string
+Scan::getFields(isc::dns::OutputBufferPtr& msgbuf) {
+
+ // 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.
+ inbuf.setPosition(OptionInfo::word(OptionInfo::QC));
+ os << std::dec << std::uppercase <<
+ " QC:" << inbuf.readUint16();
+
+ inbuf.setPosition(OptionInfo::word(OptionInfo::AC));
+ os << std::dec << std::uppercase <<
+ " AC:" << inbuf.readUint16();
+
+ inbuf.setPosition(OptionInfo::word(OptionInfo::UC));
+ os << std::dec << std::uppercase <<
+ " UC:" << inbuf.readUint16();
+
+ inbuf.setPosition(OptionInfo::word(OptionInfo::DC));
+ 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 to the nameserver.
+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 exchange. 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 completes 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..956bf29
--- /dev/null
+++ b/tests/tools/badpacket/scan.h
@@ -0,0 +1,198 @@
+// 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_service.h>
+#include <asiodns/io_fetch.h>
+#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
+/// messages. For each packet exchange, a summary is written to stdout.
+
+class Scan : public isc::asiodns::IOFetch::Callback {
+public:
+
+ /// \brief Constructor
+ Scan() : service_(), result_()
+ {}
+
+ /// \brief Run Scan
+ ///
+ /// Actually performs the scan for the combination of options.
+ ///
+ /// \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()(isc::asiodns::IOFetch::Result result);
+
+private:
+ /// \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.
+ ///
+ /// 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).
+ /// \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 Iterate over count fields
+ ///
+ /// 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.
+ ///
+ /// \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 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 messages 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 fields in a DNS message and converts them to a brief
+ /// textual 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<isc::asiolink::IOService> service_;
+ ///< Service to run the scan
+ isc::asiodns::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..7cde4aa
--- /dev/null
+++ b/tests/tools/badpacket/tests/Makefile.am
@@ -0,0 +1,31 @@
+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 += option_info_unittest.cc
+run_unittests_SOURCES += header_flags_unittest.cc
+run_unittests_SOURCES += $(top_builddir)/tests/tools/badpacket/command_options.cc
+run_unittests_SOURCES += $(top_builddir)/tests/tools/badpacket/option_info.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..014618e
--- /dev/null
+++ b/tests/tools/badpacket/tests/command_options_unittest.cc
@@ -0,0 +1,300 @@
+// 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;
+
+
+/// \brief Test Fixture Class
+
+class CommandOptionsTest : public virtual ::testing::Test,
+ public virtual CommandOptions
+{
+public:
+
+ /// \brief Default Constructor
+ CommandOptionsTest()
+ {}
+
+ /// \brief Check Non-Limit Options
+ ///
+ /// 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) {
+ EXPECT_EQ(minimum(index), minval);
+ EXPECT_EQ(maximum(index), maxval);
+ }
+
+ /// \brief Checks that all options are at default values
+ ///
+ /// Checks that all options have both their maximum and minimum set to the
+ /// default values.
+ ///
+ /// \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 valid command option
+ ///
+ /// 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 non-message 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());
+ checkDefaultLimitsValues();
+}
+
+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());
+ checkDefaultLimitsValues();
+}
+
+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());
+ checkDefaultLimitsValues();
+}
+
+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());
+ checkDefaultLimitsValues();
+}
+
+// Test options representing the flags fields.
+
+TEST_F(CommandOptionsTest, qr) {
+ checkOneBitField(OptionInfo::QR, "--qr");
+}
+
+TEST_F(CommandOptionsTest, op) {
+ checkFourBitField(OptionInfo::OP, "--op");
+}
+
+TEST_F(CommandOptionsTest, aa) {
+ checkOneBitField(OptionInfo::AA, "--aa");
+}
+
+TEST_F(CommandOptionsTest, tc) {
+ checkOneBitField(OptionInfo::TC, "--tc");
+}
+
+TEST_F(CommandOptionsTest, z) {
+ checkOneBitField(OptionInfo::Z, "--z");
+}
+
+TEST_F(CommandOptionsTest, ad) {
+ checkOneBitField(OptionInfo::AD, "--ad");
+}
+
+TEST_F(CommandOptionsTest, cd) {
+ checkOneBitField(OptionInfo::CD, "--cd");
+}
+
+TEST_F(CommandOptionsTest, rc) {
+ checkFourBitField(OptionInfo::RC, "--rc");
+}
+
+// Section count options
+
+TEST_F(CommandOptionsTest, qc) {
+ checkSixteenBitField(OptionInfo::QC, "--qc");
+}
+
+TEST_F(CommandOptionsTest, ac) {
+ checkSixteenBitField(OptionInfo::AC, "--ac");
+}
+
+TEST_F(CommandOptionsTest, uc) {
+ checkSixteenBitField(OptionInfo::UC, "--uc");
+}
+
+TEST_F(CommandOptionsTest, dc) {
+ checkSixteenBitField(OptionInfo::DC, "--dc");
+}
+
+// ... 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
new file mode 100644
index 0000000..5a7a722
--- /dev/null
+++ b/tests/tools/badpacket/tests/header_flags_unittest.cc
@@ -0,0 +1,141 @@
+// 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 "../option_info.h"
+#include "../header_flags.h"
+
+using namespace isc::badpacket;
+
+// Test fixture class
+
+class HeaderFlagsTest : public ::testing::Test {
+public:
+ HeaderFlagsTest() {}
+
+
+ /// \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, 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
+
+TEST_F(HeaderFlagsTest, bitValues) {
+ HeaderFlags flags;
+ checkZero(flags);
+
+ flags.set(OptionInfo::QR, 1);
+ EXPECT_EQ(0x8000, flags.getValue());
+
+ flags.set(OptionInfo::QR, 0);
+ flags.set(OptionInfo::OP, 15);
+ EXPECT_EQ(0x7800, flags.getValue());
+
+ flags.set(OptionInfo::OP, 0);
+ flags.set(OptionInfo::AA, 1);
+ EXPECT_EQ(0x0400, flags.getValue());
+
+ flags.set(OptionInfo::AA, 0);
+ flags.set(OptionInfo::TC, 1);
+ EXPECT_EQ(0x0200, flags.getValue());
+
+ flags.set(OptionInfo::TC, 0);
+ flags.set(OptionInfo::RD, 1);
+ EXPECT_EQ(0x0100, flags.getValue());
+
+ flags.set(OptionInfo::RD, 0);
+ flags.set(OptionInfo::RA, 1);
+ EXPECT_EQ(0x0080, flags.getValue());
+
+ flags.set(OptionInfo::RA, 0);
+ flags.set(OptionInfo::Z, 1);
+ EXPECT_EQ(0x0040, flags.getValue());
+
+ flags.set(OptionInfo::Z, 0);
+ flags.set(OptionInfo::AD, 1);
+ EXPECT_EQ(0x0020, flags.getValue());
+
+ flags.set(OptionInfo::AD, 0);
+ flags.set(OptionInfo::CD, 1);
+ EXPECT_EQ(0x0010, flags.getValue());
+
+ flags.set(OptionInfo::CD, 0);
+ flags.set(OptionInfo::RC, 15);
+ EXPECT_EQ(0x000F, flags.getValue());
+}
diff --git a/tests/tools/badpacket/tests/option_info_unittest.cc b/tests/tools/badpacket/tests/option_info_unittest.cc
new file mode 100644
index 0000000..8c061de
--- /dev/null
+++ b/tests/tools/badpacket/tests/option_info_unittest.cc
@@ -0,0 +1,161 @@
+// 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 "../option_info.h"
+
+using namespace isc::badpacket;
+
+
+// Test fixture class
+
+class OptionInfoTest : public ::testing::Test {
+public:
+ OptionInfoTest() {}
+};
+
+
+// Check the values are as expected
+
+TEST_F(OptionInfoTest, FlagValues) {
+ EXPECT_STREQ("qr", OptionInfo::name(OptionInfo::QR));
+ EXPECT_STREQ("qr", OptionInfo::name(OptionInfo::getIndex('Q')));
+ EXPECT_EQ(2, OptionInfo::word(OptionInfo::QR));
+ EXPECT_EQ(0x8000, OptionInfo::mask(OptionInfo::QR));
+ EXPECT_EQ(15, OptionInfo::offset(OptionInfo::QR));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::QR));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::QR));
+ EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::QR));
+
+ EXPECT_STREQ("op", OptionInfo::name(OptionInfo::OP));
+ EXPECT_STREQ("op", OptionInfo::name(OptionInfo::getIndex('O')));
+ EXPECT_EQ(2, OptionInfo::word(OptionInfo::OP));
+ EXPECT_EQ(0x7800, OptionInfo::mask(OptionInfo::OP));
+ EXPECT_EQ(11, OptionInfo::offset(OptionInfo::OP));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::OP));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::OP));
+ EXPECT_EQ(15, OptionInfo::maxval(OptionInfo::OP));
+
+ EXPECT_STREQ("aa", OptionInfo::name(OptionInfo::AA));
+ EXPECT_STREQ("aa", OptionInfo::name(OptionInfo::getIndex('A')));
+ EXPECT_EQ(2, OptionInfo::word(OptionInfo::AA));
+ EXPECT_EQ(0x0400, OptionInfo::mask(OptionInfo::AA));
+ EXPECT_EQ(10, OptionInfo::offset(OptionInfo::AA));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::AA));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::AA));
+ EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::AA));
+
+ EXPECT_STREQ("tc", OptionInfo::name(OptionInfo::TC));
+ EXPECT_STREQ("tc", OptionInfo::name(OptionInfo::getIndex('T')));
+ EXPECT_EQ(2, OptionInfo::word(OptionInfo::TC));
+ EXPECT_EQ(0x0200, OptionInfo::mask(OptionInfo::TC));
+ EXPECT_EQ(9, OptionInfo::offset(OptionInfo::TC));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::TC));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::TC));
+ EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::TC));
+
+ EXPECT_STREQ("rd", OptionInfo::name(OptionInfo::RD));
+ EXPECT_STREQ("rd", OptionInfo::name(OptionInfo::getIndex('D')));
+ EXPECT_EQ(2, OptionInfo::word(OptionInfo::RD));
+ EXPECT_EQ(0x0100, OptionInfo::mask(OptionInfo::RD));
+ EXPECT_EQ(8, OptionInfo::offset(OptionInfo::RD));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::RD));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::RD));
+ EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::RD));
+
+ EXPECT_STREQ("ra", OptionInfo::name(OptionInfo::RA));
+ EXPECT_STREQ("ra", OptionInfo::name(OptionInfo::getIndex('R')));
+ EXPECT_EQ(2, OptionInfo::word(OptionInfo::RA));
+ EXPECT_EQ(0x0080, OptionInfo::mask(OptionInfo::RA));
+ EXPECT_EQ(7, OptionInfo::offset(OptionInfo::RA));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::RA));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::RA));
+ EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::RA));
+
+ EXPECT_STREQ("z", OptionInfo::name(OptionInfo::Z));
+ EXPECT_STREQ("z", OptionInfo::name(OptionInfo::getIndex('Z')));
+ EXPECT_EQ(2, OptionInfo::word(OptionInfo::Z));
+ EXPECT_EQ(0x0040, OptionInfo::mask(OptionInfo::Z));
+ EXPECT_EQ(6, OptionInfo::offset(OptionInfo::Z));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::Z));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::Z));
+ EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::Z));
+
+ EXPECT_STREQ("ad", OptionInfo::name(OptionInfo::AD));
+ EXPECT_STREQ("ad", OptionInfo::name(OptionInfo::getIndex('U')));
+ EXPECT_EQ(2, OptionInfo::word(OptionInfo::AD));
+ EXPECT_EQ(0x0020, OptionInfo::mask(OptionInfo::AD));
+ EXPECT_EQ(5, OptionInfo::offset(OptionInfo::AD));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::AD));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::AD));
+ EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::AD));
+
+ EXPECT_STREQ("cd", OptionInfo::name(OptionInfo::CD));
+ EXPECT_STREQ("cd", OptionInfo::name(OptionInfo::getIndex('C')));
+ EXPECT_EQ(2, OptionInfo::word(OptionInfo::CD));
+ EXPECT_EQ(0x0010, OptionInfo::mask(OptionInfo::CD));
+ EXPECT_EQ(4, OptionInfo::offset(OptionInfo::CD));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::CD));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::CD));
+ EXPECT_EQ(1, OptionInfo::maxval(OptionInfo::CD));
+
+ EXPECT_STREQ("rc", OptionInfo::name(OptionInfo::RC));
+ EXPECT_STREQ("rc", OptionInfo::name(OptionInfo::getIndex('E')));
+ EXPECT_EQ(2, OptionInfo::word(OptionInfo::RC));
+ EXPECT_EQ(0x000F, OptionInfo::mask(OptionInfo::RC));
+ EXPECT_EQ(0, OptionInfo::offset(OptionInfo::RC));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::RC));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::RC));
+ EXPECT_EQ(15, OptionInfo::maxval(OptionInfo::RC));
+}
+
+TEST_F(OptionInfoTest, CountValues) {
+ EXPECT_STREQ("qc", OptionInfo::name(OptionInfo::QC));
+ EXPECT_STREQ("qc", OptionInfo::name(OptionInfo::getIndex('Y')));
+ EXPECT_EQ(4, OptionInfo::word(OptionInfo::QC));
+ EXPECT_EQ(1, OptionInfo::defval(OptionInfo::QC));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::QC));
+ EXPECT_EQ(0xFFFF, OptionInfo::maxval(OptionInfo::QC));
+
+ EXPECT_STREQ("ac", OptionInfo::name(OptionInfo::AC));
+ EXPECT_STREQ("ac", OptionInfo::name(OptionInfo::getIndex('W')));
+ EXPECT_EQ(6, OptionInfo::word(OptionInfo::AC));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::AC));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::AC));
+ EXPECT_EQ(0xFFFF, OptionInfo::maxval(OptionInfo::AC));
+
+ EXPECT_STREQ("uc", OptionInfo::name(OptionInfo::UC));
+ EXPECT_STREQ("uc", OptionInfo::name(OptionInfo::getIndex('H')));
+ EXPECT_EQ(8, OptionInfo::word(OptionInfo::UC));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::UC));
+ EXPECT_EQ(0, OptionInfo::minval(OptionInfo::UC));
+ EXPECT_EQ(0xFFFF, OptionInfo::maxval(OptionInfo::UC));
+
+ EXPECT_STREQ("dc", OptionInfo::name(OptionInfo::DC));
+ EXPECT_STREQ("dc", OptionInfo::name(OptionInfo::getIndex('I')));
+ EXPECT_EQ(10, OptionInfo::word(OptionInfo::DC));
+ EXPECT_EQ(0, OptionInfo::defval(OptionInfo::DC));
+ 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));
+}
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