123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283 |
- // Copyright (C) 2011 Internet Systems Consortium, Inc. ("ISC")
- //
- // Permission to use, copy, modify, and/or distribute this software for any
- // purpose with or without fee is hereby granted, provided that the above
- // copyright notice and this permission notice appear in all copies.
- //
- // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
- // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
- // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
- // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
- // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
- // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
- // PERFORMANCE OF THIS SOFTWARE.
- #include <iostream>
- #include <iomanip>
- #include <sstream>
- #include <string>
- #include <boost/scoped_ptr.hpp>
- #include <asio.hpp>
- #include <asiolink/io_address.h>
- #include <asiolink/io_fetch.h>
- #include <dns/buffer.h>
- #include <dns/message.h>
- #include <dns/messagerenderer.h>
- #include <dns/opcode.h>
- #include <dns/question.h>
- #include <dns/rcode.h>
- #include <dns/rrclass.h>
- #include <dns/rrtype.h>
- #include <log/strutil.h>
- #include "command_options.h"
- #include "header_flags.h"
- #include "scan.h"
- using namespace std;
- using namespace asiolink;
- using namespace isc::dns;
- using namespace isc::strutil;
- namespace isc {
- namespace badpacket {
- // Perform the scan from start to end on a single question.
- void
- Scan::scan(const CommandOptions& options) {
- // Create the message buffer to use
- Message message(Message::RENDER);
- message.setOpcode(Opcode::QUERY());
- message.setRcode(Rcode::NOERROR());
- message.addQuestion(Question(Name(options.getQname()), RRClass::IN(),
- RRType::A()));
- OutputBufferPtr msgbuf(new OutputBuffer(512));
- MessageRenderer renderer(*msgbuf);
- message.toWire(renderer);
- iterateFlagsFields(msgbuf, options);
- }
- // Iterate through the various settings in the flags fields
- void
- Scan::iterateFlagsFields(OutputBufferPtr& msgbuf, const CommandOptions& options) {
- // Loop through the flags setting data. This is quite deep nesting,
- // but we will continue to indent so as to make things clear (for those
- // readers lucky enough to have a wide screen).
- HeaderFlags flags;
- for (uint32_t qr = options.minimum(OptionInfo::QR);
- qr <= options.maximum(OptionInfo::QR); ++qr) {
- flags.set(OptionInfo::QR, qr);
- for (uint32_t op = options.minimum(OptionInfo::OP);
- op <= options.maximum(OptionInfo::OP); ++op) {
- flags.set(OptionInfo::OP, op);
- for (uint32_t aa = options.minimum(OptionInfo::AA);
- aa <= options.maximum(OptionInfo::AA); ++aa) {
- flags.set(OptionInfo::AA, aa);
- for (uint32_t tc = options.minimum(OptionInfo::TC);
- tc <= options.maximum(OptionInfo::TC); ++tc) {
- flags.set(OptionInfo::TC, tc);
- for (uint32_t rd = options.minimum(OptionInfo::RD);
- rd <= options.maximum(OptionInfo::RD); ++rd) {
- flags.set(OptionInfo::RD, rd);
- for (uint32_t ra = options.minimum(OptionInfo::RA);
- ra <= options.maximum(OptionInfo::RA); ++ra) {
- flags.set(OptionInfo::RA, ra);
- for (uint32_t z = options.minimum(OptionInfo::Z);
- z <= options.maximum(OptionInfo::Z); ++z) {
- flags.set(OptionInfo::Z, z);
- for (uint32_t ad = options.minimum(OptionInfo::AD);
- ad <= options.maximum(OptionInfo::AD); ++ad) {
- flags.set(OptionInfo::AD, ad);
- for (uint32_t cd = options.minimum(OptionInfo::CD);
- cd <= options.maximum(OptionInfo::CD); ++cd) {
- flags.set(OptionInfo::CD, cd);
- for (uint32_t rc = options.minimum(OptionInfo::RC);
- rc <= options.maximum(OptionInfo::RC); ++rc) {
- flags.set(OptionInfo::RC, rc);
- // Set the flags in the message.
- msgbuf->writeUint16At(flags.getValue(), 2);
- // And for this flag combination, iterate over the section
- // count fields.
- iterateCountFields(msgbuf, options);
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- }
- // Iterate through the various count fields
- void
- Scan::iterateCountFields(OutputBufferPtr& msgbuf, const CommandOptions& options) {
- for (uint32_t qc = options.minimum(OptionInfo::QC);
- qc <= options.maximum(OptionInfo::QC); ++qc) {
- msgbuf->writeUint16At(qc, OptionInfo::word(OptionInfo::QC));
- for (uint32_t ac = options.minimum(OptionInfo::AC);
- ac <= options.maximum(OptionInfo::AC); ++ac) {
- msgbuf->writeUint16At(ac, OptionInfo::word(OptionInfo::AC));
- for (uint32_t uc = options.minimum(OptionInfo::UC);
- uc <= options.maximum(OptionInfo::UC); ++uc) {
- msgbuf->writeUint16At(uc, OptionInfo::word(OptionInfo::UC));
- for (uint32_t dc = options.minimum(OptionInfo::DC);
- dc <= options.maximum(OptionInfo::DC); ++dc) {
- msgbuf->writeUint16At(dc, OptionInfo::word(OptionInfo::DC));
- // Do the I/O.
- scanOne(msgbuf, options);
- }
- }
- }
- }
- }
- // Perform the message exchange for a single combination command options.
- void
- Scan::scanOne(isc::dns::OutputBufferPtr& msgbuf, const CommandOptions& options) {
- // Store the interpretation of the flags field.
- string fields = getFields(msgbuf);
- // 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(OptionInfo::word(OptionInfo::QR));
- flags.setValue(inbuf.readUint16());
- std::ostringstream os;
- os << std::hex << std::uppercase <<
- "QR:" << flags.get(OptionInfo::QR) << " " <<
- "OP:" << flags.get(OptionInfo::OP) << " " <<
- "AA:" << flags.get(OptionInfo::AA) << " " <<
- "TC:" << flags.get(OptionInfo::TC) << " " <<
- "RD:" << flags.get(OptionInfo::RD) << " " <<
- "RA:" << flags.get(OptionInfo::RA) << " " <<
- "Z:" << flags.get(OptionInfo::Z) << " " <<
- "AD:" << flags.get(OptionInfo::AD) << " " <<
- "CD:" << flags.get(OptionInfo::CD) << " " <<
- "RC:" << flags.get(OptionInfo::RC);
- // Section count fields
- os << " ";
- inbuf.setPosition(OptionInfo::word(OptionInfo::QC));
- os << std::hex << std::uppercase <<
- "QC:" << inbuf.readUint16() << " ";
- inbuf.setPosition(OptionInfo::word(OptionInfo::AC));
- os << std::hex << std::uppercase <<
- "AC:" << inbuf.readUint16() << " ";
- inbuf.setPosition(OptionInfo::word(OptionInfo::UC));
- os << std::hex << std::uppercase <<
- "UC:" << inbuf.readUint16() << " ";
- inbuf.setPosition(OptionInfo::word(OptionInfo::DC));
- os << std::hex << std::uppercase <<
- "DC:" << inbuf.readUint16();
- 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
|