From f2de716ada3aa2c0862f3d7d21ef10d28db90219 Mon Sep 17 00:00:00 2001 From: Stephen Morris Date: Fri, 8 Apr 2011 11:30:02 +0100 Subject: [PATCH] [trac703] Bad Packet Tool Sends packets with a mangled flags field to DNS servers and examines the responses. --- 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 + .../tests/command_options_unittest.cc | 545 ++++++++++++++++++ .../badpacket/tests/header_flags_unittest.cc | 306 ++++++++++ tests/tools/badpacket/tests/run_unittests.cc | 24 + tests/tools/badpacket/version.h | 26 + 18 files changed, 2049 insertions(+), 9 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 create mode 100644 tests/tools/badpacket/tests/run_unittests.cc create mode 100644 tests/tools/badpacket/version.h diff --git a/configure.ac b/configure.ac index 1c063c489..6fd41baaa 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 fdc1f2e9b..a00a0ef78 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 0723777e1..56cee877a 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 d4008c0dd..570c0e22c 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 000000000..2f07494dc --- /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 000000000..90d88710c --- /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 000000000..4d90dd0b3 --- /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 000000000..ecfdc0d35 --- /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 + +#include + +#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 000000000..a1cdd2afc --- /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 +#include +#include +#include + +#include +#include + +#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(string(optarg)); + break; + + case 't': // --timeout + timeout_ = boost::lexical_cast(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, '' indicates a range of\n" + "values specified as either or - (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
[-a] Address of nameserver, which defaults to 127.0.0.1\n" + "--port [-p] Port to which to send query. Defaults to 53.\n" + "--timeout [-t] Timeout value for the query. Specified in ms, it\n" + " defaults to 500ms.\n" + "--qr [-Q] Set query/response bit. Valid is 0-1\n" + "--op [-O] Set opcode. Valid is 0-15\n" + "--aa [-A] Set authoritative answer bit. Valid is 0-1\n" + "--tc [-T] Set truncated bit. Valid is 0-1\n" + "--z [-Z] Set zero (reserved) bit. Valid is 0-1\n" + "--ad [-U] Set authentiacted data bit. Valid is 0-1\n" + "--cd [-C] Set checking disabled bit. Valid is 0-1\n" + "--rc [-E] Set rcode value. Valid 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 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(values[0]); + uint32_t end = start; + if (values.size() == 2) { + end = boost::lexical_cast(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 000000000..a1132b909 --- /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 +#include +#include + +#include + +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 000000000..546a0168f --- /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 000000000..2059ba5ce --- /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 +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 000000000..04b80ad20 --- /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 + +#include + +#include + +#include +#include +#include + +#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 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 000000000..3f38be932 --- /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 000000000..fe7ceb02e --- /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 +#include +#include + +#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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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(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 000000000..dce4dc9e0 --- /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 +#include +#include + +#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 000000000..624cf6fb6 --- /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 + +#include + +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 000000000..dc59b11f7 --- /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 -- GitLab