diff --git a/.gitmodules b/.gitmodules index b7f61ea..b9edf39 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "dnstap"] path = dnstap url = https://github.com/dnstap/dnstap.pb +[submodule "contrib/dns-stats-docker"] + path = contrib/dns-stats-docker + url = https://github.com/SeanBurford/dns-stats-docker.git diff --git a/ChangeLog.txt b/ChangeLog.txt index 9dc94c3..c1b88d4 100644 --- a/ChangeLog.txt +++ b/ChangeLog.txt @@ -6,6 +6,20 @@ # file, you can obtain one at https://mozilla.org/MPL/2.0/. # + +Version 1.2.1-rc1 - 2022-01-18 +-------------------------- + +* Modify the format output by the debug option `--debug-qr` to be more human + readable (`--debug-dns` output is left unchanged). +* Fix 2 minor bugs where an incorrect start time could be written to the CDNS + file, resulting in a negative file duration. +* Documentation: correct the dependency list. +* Fix build issue when using `configure --disable-pseudo-anonymisation`. Thanks + Sean Burford for reporting this. +* Add example docker image as a submodule in `contrib/dns-stats-docker`. Thanks + to Sean Burford for providing this. + Version 1.2.1-beta2 - 2021-09-23 -------------------------- * Bump the private version because schema extended with new stats. diff --git a/Makefile.am b/Makefile.am index 5669cb9..465a14c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -268,6 +268,7 @@ libcdns_a_SOURCES = \ src/ipaddress.cpp \ src/log.cpp \ src/pseudoanonymise.cpp \ + src/queryresponse.cpp \ src/rotatingfilename.cpp \ src/streamwriter.cpp \ src/util.cpp diff --git a/contrib/dns-stats-docker b/contrib/dns-stats-docker new file mode 160000 index 0000000..5a492d8 --- /dev/null +++ b/contrib/dns-stats-docker @@ -0,0 +1 @@ +Subproject commit 5a492d8afb66f4bc97ca5a6bc95dcc46636ae85e diff --git a/doc/user-guide/installation.adoc.in b/doc/user-guide/installation.adoc.in index 5511b9b..a8ca0a8 100644 --- a/doc/user-guide/installation.adoc.in +++ b/doc/user-guide/installation.adoc.in @@ -86,6 +86,8 @@ source, see the documentation for those items. {cpp}. Building them requires a {cpp} compiler and tool chain compatible with the 2011 ISO standard, otherwise {cpp}11. +| pkg-config | Used for dependency management. + | `boost-log` .5+| Several libraries from http://www.boost.org[Boost {cpp}] are required. Depending on your system, it may be possible to @@ -101,6 +103,8 @@ source, see the documentation for those items. | `boost-iostreams` +| `boost-filesystem` + | `liblzma`| The compression library from http://tukaani.org/xz/[XZ utils]. | `libpcap`| Library for capturing network traffic http://www.tcpdump.org/. diff --git a/src/blockcbordata.cpp b/src/blockcbordata.cpp index 0033c4c..1038576 100644 --- a/src/blockcbordata.cpp +++ b/src/blockcbordata.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 Internet Corporation for Assigned Names and Numbers. + * Copyright 2016-2022 Internet Corporation for Assigned Names and Numbers. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -1726,7 +1726,11 @@ namespace block_cbor { Timestamp end_ts(*end_time, ticks_per_second); end_ts.writeCbor(enc); } - if ( start_time ) + // There is a rare case where a 'live' capture is fed old data (e.g. + // via a DNSTAP socket) and in this case the start time can be later + // than the earliest data. Don't write the start time if this is the + // case + if ( start_time && start_time <= earliest_time ) { enc.write(start_time_index); Timestamp start_ts(*start_time, ticks_per_second); diff --git a/src/blockcborreader.cpp b/src/blockcborreader.cpp index de0dead..61eca56 100644 --- a/src/blockcborreader.cpp +++ b/src/blockcborreader.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 Internet Corporation for Assigned Names and Numbers. + * Copyright 2016-2022 Internet Corporation for Assigned Names and Numbers. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -888,8 +888,10 @@ void BlockCborReader::dump_times(std::ostream& os) const output_duration(os, std::chrono::duration_cast(*latest_time_ - *earliest_time_)); os << "\n"; } - - if ( start_time_ && end_time_ ) + // A bug allowed start_time_ to be set to later than end_time_ giving a + // negative file duration.... We need a sanity check here becuase this + // value is used to calculate average rates downstream. + if ( start_time_ && end_time_ && end_time_ > start_time_) { os << " File duration : "; output_duration(os, std::chrono::duration_cast(*end_time_ - *start_time_)); @@ -997,8 +999,8 @@ std::ostream& operator<<(std::ostream& output, const QueryResponseData& qr) { case 0: transport = "UDP"; break; case 1: transport = "TCP"; break; - case 2: transport = "TLS"; break; - case 3: transport = "DTLS"; break; + case 2: transport = "DoT"; break; + case 3: transport = "DoD"; break; case 4: transport = "DOH"; break; default: transport = "Unknown"; break; } @@ -1016,164 +1018,187 @@ std::ostream& operator<<(std::ostream& output, const QueryResponseData& qr) case block_cbor::UPDATE : transaction_type = "Update"; break; default: transaction_type = "Tool"; break; } - } + } + else + transaction_type = "Unknown"; - output << "Query/Response:\n"; - if ( qr.qr_flags & block_cbor::HAS_QUERY ) - { - output << "Query: "; - if ( qr.timestamp ) + bool query = qr.qr_flags & block_cbor::HAS_QUERY; + bool response = qr.qr_flags & block_cbor::HAS_RESPONSE; + + output << "-----------------------------------------------------------------------------------------------------------------------------------\n" ; + output << " Timestamp Client IP/port Server IP/port QNAME"; + if (query) { + output << "\nQuery "; + if (qr.timestamp) output_time_point(output, *qr.timestamp); + else + output << "No timestamp available "; if ( qr.client_address ) - output << "\n\tClient IP: " << *qr.client_address; + output << " " << *qr.client_address << ":"; + if ( qr.client_port ) + output << std::left << std::setw(5) << *qr.client_port; + else + output << " "; if ( qr.server_address ) - output << "\n\tServer IP: " << *qr.server_address; - if ( transport ) - output << "\n\tTransport: " << transport; - if ( transaction_type ) - output << "\n\tType: " << transaction_type; + output << " " << *qr.server_address << ":"; + if ( qr.server_port ) + output << std::left << std::setw(5) << *qr.server_port << " "; + else + output << " "; + output << (qr.qname ? CaptureDNS::decode_domain_name(*qr.qname): " no QNAME present"); + } + else + output << "\nQuery not present"; + if (response) { + output << "\nResponse "; + if ( qr.timestamp && qr.response_delay ) + output_time_point(output, *qr.timestamp + std::chrono::duration_cast(*qr.response_delay)); + else + output << "No timestamp available. "; + if ( qr.client_address ) + output << " " << *qr.client_address << ":"; if ( qr.client_port ) - output << "\n\tClient port: " << *qr.client_port; + output << std::left << std::setw(5) << *qr.client_port; + else + output << " "; + if ( qr.server_address ) + output << " " << *qr.server_address << ":"; if ( qr.server_port ) - output << "\n\tServer port: " << *qr.server_port; - if ( qr.client_hoplimit ) - output << "\n\tHop limit: " << +*qr.client_hoplimit; - output << "\n\tDNS QR: Query"; - if ( qr.id ) - output << "\n\tID: " << *qr.id; - if ( qr.query_opcode ) - output << "\n\tOpcode: " << static_cast(*qr.query_opcode); - if ( qr.query_rcode ) - output << "\n\tRcode: " << static_cast(*qr.query_rcode); + output << std::left << std::setw(5) << *qr.server_port << " "; + else + output << " "; + output << (qr.qname ? CaptureDNS::decode_domain_name(*qr.qname): " no QNAME present"); + } + else + output << "\nResponse not present"; + + output << "\n Transport Hop-limit MsgID QR OPCODE FLAGS(AA/TC/RD/RA/AD/CD) RCODE COUNTS(QD/AN/NS/AD) Query-type Class Trans-type\n"; + + if ( transport ) + output << " " << transport; + else + output << " "; + if ( qr.client_hoplimit ) + output << std::left << " " << std::setw(4) << +*qr.client_hoplimit; + else + output << " "; + if ( qr.id ) + output << " " << std::left << std::setw(5) << *qr.id; + else + output << " "; + if (query) { + output << " 0 "; + if ( qr.query_opcode ) + output << std::left << std::setw(6) << Configuration::find_opcode_string(*qr.query_opcode) << " " ; + else + output << " "; if ( qr.dns_flags ) { - output << "\n\tFlags: "; - if ( *qr.dns_flags & block_cbor::QUERY_AA ) - output << "AA "; - if ( *qr.dns_flags & block_cbor::QUERY_TC ) - output << "TC "; - if ( *qr.dns_flags & block_cbor::QUERY_RD ) - output << "RD "; - if ( *qr.dns_flags & block_cbor::QUERY_RA ) - output << "RA "; - if ( *qr.dns_flags & block_cbor::QUERY_AD ) - output << "AD "; - if ( *qr.dns_flags & block_cbor::QUERY_CD ) - output << "CD "; - } + output << ((*qr.dns_flags & block_cbor::QUERY_AA ) ? " 1 " : " 0 ") ; + output << ((*qr.dns_flags & block_cbor::QUERY_TC ) ? " 1 " : " 0 ") ; + output << ((*qr.dns_flags & block_cbor::QUERY_RD ) ? " 1 " : " 0 ") ; + output << ((*qr.dns_flags & block_cbor::QUERY_RA ) ? " 1 " : " 0 ") ; + output << ((*qr.dns_flags & block_cbor::QUERY_AD ) ? " 1 " : " 0 ") ; + output << ((*qr.dns_flags & block_cbor::QUERY_CD ) ? " 1 " : " 0 ") ; + } else + output << " "; + if ( qr.query_rcode ) + output << " " << std::left << std::setw(11) << Configuration::find_rcode_string(*qr.query_rcode) << " " ; + else + output << " "; count = (qr.query_questions) ? (*qr.query_questions).size() : 0; if ( !(qr.qr_flags & block_cbor::QUERY_HAS_NO_QUESTION) ) count += 1; - output << "\n\tQdCount: " << count; + output << std::right << std::setw(2) << count; count = ( qr.query_answers ) ? (*qr.query_answers).size() : 0; - output << "\n\tAnCount: " << count; + output << " " << std::right << std::setw(2) << count; count = ( qr.query_authorities ) ? (*qr.query_authorities).size() : 0; - output << "\n\tNsCount: " << count; + output << " " << std::right << std::setw(2) << count; count = ( qr.query_additionals ) ? (*qr.query_additionals).size() : 0; if ( qr.qr_flags & block_cbor::QUERY_HAS_OPT ) count += 1; - output << "\n\tArCount: " << count; + output << " " << std::right << std::setw(2) << count; - if ( qr.qname ) - output << "\n\tName: " << CaptureDNS::decode_domain_name(*qr.qname); if ( qr.query_type ) - output << "\n\tType: " << static_cast(*qr.query_type); + output << " " << std::setw(6) << Configuration::find_rrtype_string(*qr.query_type); + else + output << " "; if ( qr.query_class ) - output << "\n\tClass: " << static_cast(*qr.query_class); - - if ( qr.query_questions ) - for ( const auto& q : *qr.query_questions ) - { - if ( q.qname ) - output << "\n\tName: " << CaptureDNS::decode_domain_name(*q.qname); - if ( q.qtype ) - output << "\n\tType: " << static_cast(*q.qtype); - if ( q.qclass ) - output << "\n\tClass: " << static_cast(*q.qclass); - } - + output << " " << static_cast(*qr.query_class); + else + output << " "; + if ( transaction_type ) + output << " " << transaction_type; output << "\n"; } else - output << "No Query\n"; - - if ( qr.qr_flags & block_cbor::HAS_RESPONSE ) - { - output << "Response: "; - if ( qr.timestamp && qr.response_delay ) - output_time_point(output, *qr.timestamp + std::chrono::duration_cast(*qr.response_delay)); - if ( qr.client_address ) - output << "\n\tClient IP: " << *qr.client_address; - if ( qr.server_address ) - output << "\n\tServer IP: " << *qr.server_address; - if ( transport ) - output << "\n\tTransport: " << transport; - if ( transaction_type ) - output << "\n\tType: " << transaction_type; - if ( qr.client_port ) - output << "\n\tClient port: " << *qr.client_port; - if ( qr.server_port ) - output << "\n\tServer port: " << *qr.server_port; - if ( qr.server_hoplimit ) - output << "\n\tHop limit: " << +*qr.server_hoplimit; - output << "\n\tDNS QR: Response"; + output << "\n"; + if (response) { + output << " "; if ( qr.id ) - output << "\n\tID: " << *qr.id; - if ( qr.query_opcode ) - output << "\n\tOpcode: " << static_cast(*qr.query_opcode); - if ( qr.response_rcode ) - output << "\n\tRcode: " << static_cast(*qr.response_rcode); + output << " " << std::left << std::setw(5) << *qr.id; + output << " 1 "; + if ( qr.query_opcode ) + output << std::left << std::setw(6) << Configuration::find_opcode_string(*qr.query_opcode) << " " ; + else + output << " "; + if ( qr.dns_flags ) { - output << "\n\tFlags: "; - if ( *qr.dns_flags & block_cbor::RESPONSE_AA ) - output << "AA "; - if ( *qr.dns_flags & block_cbor::RESPONSE_TC ) - output << "TC "; - if ( *qr.dns_flags & block_cbor::RESPONSE_RD ) - output << "RD "; - if ( *qr.dns_flags & block_cbor::RESPONSE_RA ) - output << "RA "; - if ( *qr.dns_flags & block_cbor::RESPONSE_AD ) - output << "AD "; - if ( *qr.dns_flags & block_cbor::RESPONSE_CD ) - output << "CD "; + output << ((*qr.dns_flags & block_cbor::RESPONSE_AA ) ? " 1 " : " 0 ") ; + output << ((*qr.dns_flags & block_cbor::RESPONSE_TC ) ? " 1 " : " 0 ") ; + output << ((*qr.dns_flags & block_cbor::RESPONSE_RD ) ? " 1 " : " 0 ") ; + output << ((*qr.dns_flags & block_cbor::RESPONSE_RA ) ? " 1 " : " 0 ") ; + output << ((*qr.dns_flags & block_cbor::RESPONSE_AD ) ? " 1 " : " 0 ") ; + output << ((*qr.dns_flags & block_cbor::RESPONSE_CD ) ? " 1 " : " 0 ") ; } + if ( qr.response_rcode ) + output << " " << std::left << std::setw(11) << Configuration::find_rcode_string(*qr.response_rcode) << " " ; + else + output << " "; count = 0; if ( !(qr.qr_flags & block_cbor::QUERY_HAS_NO_QUESTION) ) count = 1; if ( qr.response_questions ) count += (*qr.response_questions).size(); - output << "\n\tQdCount: " << count; + output << std::right << std::setw(2) << count; count = ( qr.response_answers ) ? (*qr.response_answers).size() : 0; - output << "\n\tAnCount: " << count; + output << " " << std::right << std::setw(2) << count; count = ( qr.response_authorities ) ? (*qr.response_authorities).size() : 0; - output << "\n\tNsCount: " << count; + output << " " << std::right << std::setw(2) << count; count = ( qr.response_additionals ) ? (*qr.response_additionals).size() : 0; - output << "\n\tArCount: " << count; - - if ( qr.qname ) - output << "\n\tName: " << CaptureDNS::decode_domain_name(*qr.qname); + output << " " << std::right << std::setw(2) << count; if ( qr.query_type ) - output << "\n\tType: " << static_cast(*qr.query_type); + output << " " << std::setw(6) << Configuration::find_rrtype_string(*qr.query_type); + else + output << " "; if ( qr.query_class ) - output << "\n\tClass: " << static_cast(*qr.query_class); + output << " " << static_cast(*qr.query_class); + else + output << " "; + if ( transaction_type ) + output << " " << transaction_type; + output << "\n"; + } + else + output << "\n"; - if ( qr.response_questions ) - for ( const auto& q : *qr.response_questions ) + if (response) + { + if ( qr.response_answers ) { + output << " Response Answers: Type Class Name\n"; + for ( const auto& r : *qr.response_answers ) { - if ( q.qname ) - output << "\n\tName: " << CaptureDNS::decode_domain_name(*q.qname); - if ( q.qtype ) - output << "\n\tType: " << static_cast(*q.qtype); - if ( q.qclass ) - output << "\n\tClass: " << static_cast(*q.qclass); + if ( r.rtype ) + output << "\t\t " << std::right << std::setw(6) << Configuration::find_rrtype_string(*r.rtype); + if ( r.rclass ) + output << " "<< static_cast(*r.rclass); + if ( r.name ) + output << " " << CaptureDNS::decode_domain_name(*r.name) << "\n"; } + } - output << "\n"; } - else - output << "No Response\n"; - + output << "\n"; return output; } diff --git a/src/configuration.cpp b/src/configuration.cpp index f7d1474..4368ded 100644 --- a/src/configuration.cpp +++ b/src/configuration.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 Internet Corporation for Assigned Names and Numbers. + * Copyright 2016-2022 Internet Corporation for Assigned Names and Numbers. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -783,6 +783,48 @@ void Configuration::dump_output_option(std::ostream& os, bool query) const os << "\n"; } +const std::string Configuration::find_opcode_string(unsigned opcode) +{ + auto f = std::find_if(OPCODES.begin(), + OPCODES.end(), + [opcode](const std::pair& op) + { + return op.second == opcode; + }); + if ( f != std::end(OPCODES) ) + return f->first; + else + return std::to_string(opcode); +} + +const std::string Configuration::find_rcode_string(unsigned rcode) +{ + auto f = std::find_if(RCODES.begin(), + RCODES.end(), + [rcode](const std::pair& r) + { + return r.second == rcode; + }); + if ( f != std::end(RCODES) ) + return f->first; + else + return std::to_string(rcode); +} + +const std::string Configuration::find_rrtype_string(unsigned rrtype) +{ + auto f = std::find_if(RR_TYPES.begin(), + RR_TYPES.end(), + [rrtype](const std::pair& rr) + { + return rr.second == rrtype; + }); + if ( f != std::end(RR_TYPES) ) + return f->first; + else + return std::to_string(rrtype); +} + void Configuration::dump_OPCODEs(std::ostream& os, bool accept) const { const std::vector& opcodes = accept ? accept_opcodes : ignore_opcodes; @@ -795,16 +837,8 @@ void Configuration::dump_OPCODEs(std::ostream& os, bool accept) const else os << ", "; - auto f = std::find_if(OPCODES.begin(), - OPCODES.end(), - [op_t](const std::pair& op) - { - return op.second == op_t; - }); - if ( f != std::end(OPCODES) ) - os << f->first; - else - os << std::to_string(op_t); + os << find_opcode_string(op_t); + } os << "\n"; } @@ -821,16 +855,7 @@ void Configuration::dump_RR_types(std::ostream& os, bool accept) const else os << ", "; - auto f = std::find_if(RR_TYPES.begin(), - RR_TYPES.end(), - [rr_t](const std::pair& rr) - { - return rr.second == rr_t; - }); - if ( f != std::end(RR_TYPES) ) - os << f->first; - else - os << std::to_string(rr_t); + os << find_rrtype_string(rr_t); } os << "\n"; } diff --git a/src/configuration.hpp b/src/configuration.hpp index df72c2e..a8d7ae7 100644 --- a/src/configuration.hpp +++ b/src/configuration.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2021 Internet Corporation for Assigned Names and Numbers. + * Copyright 2016-2022 Internet Corporation for Assigned Names and Numbers. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -1025,6 +1025,30 @@ class Configuration */ void set_from_block_parameters(const block_cbor::BlockParameters& bp); + /** + * \brief Return a string for OPCODE if found + * + * \param opcode OPCODE numeric value + * \returns a string with the OPCODE name if found or the value if not + */ + static const std::string find_opcode_string(unsigned opcode); + + /** + * \brief Return a string for RCODE if found + * + * \param opcode RCODE numeric value + * \returns a string with the RCODE name if found or the value if not + */ + static const std::string find_rcode_string(unsigned rcode); + + /** + * \brief Return a string for RRTYPE if found + * + * \param opcode RRTYPE numeric value + * \returns a string with the RRTYPE name if found or the value if not + */ + static const std::string find_rrtype_string(unsigned rrtype); + protected: /** * \brief Set configuration items that aren't directly set by Boost. diff --git a/src/dnsmessage.cpp b/src/dnsmessage.cpp index b4b8612..1a16095 100644 --- a/src/dnsmessage.cpp +++ b/src/dnsmessage.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2018, 2021 Internet Corporation for Assigned Names and Numbers. + * Copyright 2016-2018, 2021, 2022 Internet Corporation for Assigned Names and Numbers. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -83,7 +83,7 @@ std::ostream& operator<<(std::ostream& output, const DNSMessage& msg) { case TransportType::DOH: output << "DoH"; break; case TransportType::DOT: output << "DoT"; break; - case TransportType::DDOT: output << "DDoT"; break; + case TransportType::DDOT: output << "DoD"; break; case TransportType::TCP: output << "TCP"; break; case TransportType::UDP: output << "UDP"; break; } diff --git a/src/inspector.cpp b/src/inspector.cpp index af6ef96..bafba1c 100644 --- a/src/inspector.cpp +++ b/src/inspector.cpp @@ -330,7 +330,7 @@ int main(int ac, char *av[]) << "Run '" << PROGNAME << " -h' for help.\n"; return 1; } - +#if ENABLE_PSEUDOANONYMISATION if ( vm.count("pseudo-anonymisation-key") != 0 && vm.count("pseudo-anonymisation-passphrase") != 0 ) { @@ -339,7 +339,7 @@ int main(int ac, char *av[]) "or passphrase, but not both.\n"; return 1; } - +#endif po::notify(vm); if ( vm.count("output-format") != 0 ) @@ -382,7 +382,7 @@ int main(int ac, char *av[]) return 1; } } - +#if ENABLE_PSEUDOANONYMISATION if ( vm.count("pseudo-anonymisation-key") != 0 && pseudo_anon_key.size() != 16 ) { @@ -401,7 +401,7 @@ int main(int ac, char *av[]) " a passphrase or key.\n"; return 1; } - +#endif pcap_options.baseopts.gzip_output = ( vm.count("gzip-output") != 0 ); pcap_options.baseopts.xz_output = ( vm.count("xz-output") != 0 ); pcap_options.query_only = ( vm.count("query-only") != 0 ); diff --git a/src/queryresponse.cpp b/src/queryresponse.cpp new file mode 100644 index 0000000..46c3970 --- /dev/null +++ b/src/queryresponse.cpp @@ -0,0 +1,199 @@ +/* + * Copyright 2016-2017, 2021, 2022 Internet Corporation for Assigned Names and Numbers. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, you can obtain one at https://mozilla.org/MPL/2.0/. + */ + +/* + * Developed by Sinodun IT (www.sinodun.com) + */ + +#include +#include +#include +#include + +#include "queryresponse.hpp" +#include "configuration.hpp" + + +std::ostream& operator<<(std::ostream& output, const QueryResponse& qr) +{ + const char* transport = NULL; + const char* transaction_type = NULL; + bool query = false; + bool response = false; + + if (qr.query_ ) query = true; + if (qr.response_ ) response = true; + + if (query) { + switch ( qr.query_->transport_type ) + { + case TransportType::DOH: transport = "DoH"; break; + case TransportType::DOT: transport = "DoT"; break; + case TransportType::DDOT: transport = "DoD"; break; + case TransportType::TCP: transport = "TCP"; break; + case TransportType::UDP: transport = "UDP"; break; + default: transport = "Unknown"; break; + } + + if ( qr.query_->transaction_type != TransactionType::NONE ) + { + switch (qr.query_->transaction_type) + { + case TransactionType::AUTH_QUERY: transaction_type = "Auth query"; break; + case TransactionType::AUTH_RESPONSE: transaction_type = "Auth response"; break; + case TransactionType::RESOLVER_QUERY: transaction_type = "Resolver query"; break; + case TransactionType::RESOLVER_RESPONSE: transaction_type = "Resolver response"; break; + case TransactionType::CLIENT_QUERY: transaction_type = "Client query"; break; + case TransactionType::CLIENT_RESPONSE: transaction_type = "Client response"; break; + case TransactionType::FORWARDER_QUERY: transaction_type = "Forwarder query"; break; + case TransactionType::FORWARDER_RESPONSE: transaction_type = "Forwarder response"; break; + case TransactionType::STUB_QUERY: transaction_type = "Stub query"; break; + case TransactionType::STUB_RESPONSE: transaction_type = "Stub response"; break; + case TransactionType::TOOL_QUERY: transaction_type = "Tool query"; break; + case TransactionType::TOOL_RESPONSE: transaction_type = "Tool response"; break; + case TransactionType::UPDATE_QUERY: transaction_type = "Update query"; break; + case TransactionType::UPDATE_RESPONSE: transaction_type = "Update response"; break; + default: transaction_type = "Unknown"; break; + } + } else + transaction_type = "Unknown"; + } + + output << "-----------------------------------------------------------------------------------------------------------------------------------\n" ; + output << " Timestamp Client IP/port Server IP/port QNAME"; + + output << "\nQuery "; + if (query) { + std::time_t t = std::chrono::system_clock::to_time_t(qr.query_->timestamp); + std::tm tm = *std::gmtime(&t); + char buf[40]; + std::strftime(buf, sizeof(buf), "%Y-%m-%d %Hh%Mm%Ss", &tm); + double us = std::chrono::duration_cast(qr.query_->timestamp.time_since_epoch()).count() % 1000000; + output << buf << us << "us UTC"; + if ( qr.query_->clientIP ) + output << " " << *(qr.query_->clientIP) << ":"; + if ( qr.query_->clientPort ) + output << std::left << std::setw(5) << *(qr.query_->clientPort); + else + output << " "; + if ( qr.query_->serverIP ) + output << " " << *(qr.query_->serverIP) << ":"; + if ( qr.query_->serverPort ) + output << std::left << std::setw(5) << *(qr.query_->serverPort); + else + output << " "; + if (!qr.query_->dns.queries().empty()) { + const auto &q = qr.query_->dns.queries().begin(); + output << " " << CaptureDNS::decode_domain_name(q->dname()); + } + else + output << " no QNAME present"; + } else + output << "No query present"; + + output << "\nResponse "; + if (response) { + std::time_t t = std::chrono::system_clock::to_time_t(qr.response_->timestamp); + std::tm tm = *std::gmtime(&t); + char buf[40]; + std::strftime(buf, sizeof(buf), "%Y-%m-%d %Hh%Mm%Ss", &tm); + double us = std::chrono::duration_cast(qr.response_->timestamp.time_since_epoch()).count() % 1000000; + output << buf << us << "us UTC"; + if ( qr.response_->clientIP ) + output << " " << *(qr.response_->clientIP) << ":"; + if ( qr.response_->clientPort ) + output << std::left << std::setw(5) << *(qr.response_->clientPort); + else + output << " "; + if ( qr.response_->serverIP ) + output << " " << *(qr.response_->serverIP) << ":"; + if ( qr.response_->serverPort ) + output << std::left << std::setw(5) << *(qr.response_->serverPort); + else + output << " "; + if (!qr.response_->dns.queries().empty()) { + const auto &q = qr.response_->dns.queries().begin(); + output << " " << CaptureDNS::decode_domain_name(q->dname()); + } + else + output << " no QNAME present"; + } else + output << "No response present"; + + output << "\n Transport Hop-limit MsgID QR OPCODE FLAGS(AA/TC/RD/RA/AD/CD) RCODE COUNTS(QD/AN/NS/AD) Query-type Class Trans-type\n"; + + if ( transport ) + output << " " << transport; + else + output << " "; + if (query) { + if ( qr.query_->hoplimit ) + output << " " << std::left << std::setw(4) << +*(qr.query_->hoplimit); + else + output << " "; + output << " " << std::left << std::setw(5) << qr.query_->dns.id(); + output << " 0 "; + output << std::left << std::setw(6) << Configuration::find_opcode_string(qr.query_->dns.opcode()) << " " ; + output << (qr.query_->dns.authoritative_answer() ? " 1 " : " 0 ") ; + output << (qr.query_->dns.truncated() ? " 1 " : " 0 ") ; + output << (qr.query_->dns.recursion_desired() ? " 1 " : " 0 ") ; + output << (qr.query_->dns.recursion_available() ? " 1 " : " 0 ") ; + output << (qr.query_->dns.authenticated_data() ? " 1 " : " 0 ") ; + output << (qr.query_->dns.checking_disabled() ? " 1 " : " 0 ") ; + output << " " << std::left << std::setw(11) << Configuration::find_rcode_string(qr.query_->dns.rcode()) << " " ; + output << " " << std::right << std::setw(2) << qr.query_->dns.questions_count(); + output << " " << std::right << std::setw(2) << qr.query_->dns.answers_count(); + output << " " << std::right << std::setw(2) << qr.query_->dns.authority_count(); + output << " " << std::right << std::setw(2) << qr.query_->dns.additional_count(); + + if (!qr.query_->dns.queries().empty()) { + const auto &q = qr.query_->dns.queries().begin(); + output << " " << std::setw(6) << Configuration::find_rrtype_string(q->query_type()); + output << " " << static_cast(q->query_class()); + } + if ( transaction_type ) + output << " " << transaction_type; + output << "\n"; + } + else + output << "\n"; + + if (response) { + output << " "; + output << " " << std::left << std::setw(5) << qr.response_->dns.id(); + output << " 1 "; + output << std::left << std::setw(6) << Configuration::find_opcode_string(qr.response_->dns.opcode()) << " " ; + output << (qr.response_->dns.authoritative_answer() ? " 1 " : " 0 ") ; + output << (qr.response_->dns.truncated() ? " 1 " : " 0 ") ; + output << (qr.response_->dns.recursion_desired() ? " 1 " : " 0 ") ; + output << (qr.response_->dns.recursion_available() ? " 1 " : " 0 ") ; + output << (qr.response_->dns.authenticated_data() ? " 1 " : " 0 ") ; + output << (qr.response_->dns.checking_disabled() ? " 1 " : " 0 ") ; + output << " " << std::left << std::setw(11) << Configuration::find_rcode_string(qr.response_->dns.rcode()) << " " ; + output << " " << std::right << std::setw(2) << qr.response_->dns.questions_count(); + output << " " << std::right << std::setw(2) << qr.response_->dns.answers_count(); + output << " " << std::right << std::setw(2) << qr.response_->dns.authority_count(); + output << " " << std::right << std::setw(2) << qr.response_->dns.additional_count(); + + if (!qr.response_->dns.queries().empty()) { + const auto &q = qr.response_->dns.queries().begin(); + output << " " << std::setw(6) << Configuration::find_rrtype_string(q->query_type()); + output << " " << static_cast(q->query_class()); + } + if ( transaction_type ) + output << " " << transaction_type; + output << "\n"; + } + else + output << "\n"; + + output << "\n"; + return output; + + +} diff --git a/src/queryresponse.hpp b/src/queryresponse.hpp index 1c6b597..62da502 100644 --- a/src/queryresponse.hpp +++ b/src/queryresponse.hpp @@ -1,5 +1,5 @@ /* - * Copyright 2016-2017, 2021 Internet Corporation for Assigned Names and Numbers. + * Copyright 2016-2017, 2021, 2022 Internet Corporation for Assigned Names and Numbers. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this @@ -127,19 +127,7 @@ class QueryResponse * \param qr the pair. * \return the output stream. */ - friend std::ostream& operator<<(std::ostream& output, const QueryResponse& qr) - { - output << "Query/Response:\n"; - if ( qr.query_ ) - output << "Query: " << *(qr.query_); - else - output << "No Query\n"; - if ( qr.response_ ) - output << "Response: " << *(qr.response_); - else - output << "No Response\n"; - return output; - } + friend std::ostream& operator<<(std::ostream& output, const QueryResponse& qr); private: /** diff --git a/test-scripts/addressprefix.debugqr b/test-scripts/addressprefix.debugqr index 66147ed..e10df76 100644 --- a/test-scripts/addressprefix.debugqr +++ b/test-scripts/addressprefix.debugqr @@ -1,78 +1,16 @@ -Query/Response: -Query: 2016-04-05 19h33m24s561484us UTC - Client IP: 86.237.0.0 - Server IP: 211.79.123.0 - Transport: UDP - Client port: 51644 - Server port: 53 - Hop limit: 52 - DNS QR: Query - ID: 61888 - Opcode: 0 - Rcode: 0 - Flags: - QdCount: 1 - AnCount: 0 - NsCount: 0 - ArCount: 1 - Name: xtsskb5qon8sn._kerberos._tcp.TEVC._sites.dc._msdcs.172.20.222.38 - Type: 33 - Class: 1 -Response: 2016-04-05 19h33m24s561574us UTC - Client IP: 86.237.0.0 - Server IP: 211.79.123.0 - Transport: UDP - Client port: 51644 - Server port: 53 - Hop limit: 64 - DNS QR: Response - ID: 61888 - Opcode: 0 - Rcode: 3 - Flags: AA - QdCount: 1 - AnCount: 0 - NsCount: 4 - ArCount: 1 - Name: xtsskb5qon8sn._kerberos._tcp.TEVC._sites.dc._msdcs.172.20.222.38 - Type: 33 - Class: 1 -Query/Response: -Query: 2016-04-05 19h33m24s667820us UTC - Client IP: 3249:c000:: - Server IP: 3249:ec00:: - Transport: UDP - Client port: 47686 - Server port: 53 - Hop limit: 59 - DNS QR: Query - ID: 11414 - Opcode: 0 - Rcode: 0 - Flags: - QdCount: 1 - AnCount: 0 - NsCount: 0 - ArCount: 1 - Name: CO801M180191.azcorrections.local - Type: 6 - Class: 1 -Response: 2016-04-05 19h33m24s667916us UTC - Client IP: 3249:c000:: - Server IP: 3249:ec00:: - Transport: UDP - Client port: 47686 - Server port: 53 - Hop limit: 64 - DNS QR: Response - ID: 11414 - Opcode: 0 - Rcode: 3 - Flags: AA - QdCount: 1 - AnCount: 0 - NsCount: 6 - ArCount: 1 - Name: CO801M180191.azcorrections.local - Type: 6 - Class: 1 +----------------------------------------------------------------------------------------------------------------------------------- + Timestamp Client IP/port Server IP/port QNAME +Query 2016-04-05 19h33m24s561484us UTC 86.237.0.0:51644 211.79.123.0:53 xtsskb5qon8sn._kerberos._tcp.TEVC._sites.dc._msdcs.172.20.222.38 +Response 2016-04-05 19h33m24s561574us UTC 86.237.0.0:51644 211.79.123.0:53 xtsskb5qon8sn._kerberos._tcp.TEVC._sites.dc._msdcs.172.20.222.38 + Transport Hop-limit MsgID QR OPCODE FLAGS(AA/TC/RD/RA/AD/CD) RCODE COUNTS(QD/AN/NS/AD) Query-type Class Trans-type + UDP 52 61888 0 QUERY 0 0 0 0 0 0 NOERROR 1 0 0 1 SRV 1 Unknown + 61888 1 QUERY 1 0 0 0 0 0 NXDOMAIN 1 0 4 1 SRV 1 Unknown + +----------------------------------------------------------------------------------------------------------------------------------- + Timestamp Client IP/port Server IP/port QNAME +Query 2016-04-05 19h33m24s667820us UTC 3249:c000:::47686 3249:ec00:::53 CO801M180191.azcorrections.local +Response 2016-04-05 19h33m24s667916us UTC 3249:c000:::47686 3249:ec00:::53 CO801M180191.azcorrections.local + Transport Hop-limit MsgID QR OPCODE FLAGS(AA/TC/RD/RA/AD/CD) RCODE COUNTS(QD/AN/NS/AD) Query-type Class Trans-type + UDP 59 11414 0 QUERY 0 0 0 0 0 0 NOERROR 1 0 0 1 SOA 1 Unknown + 11414 1 QUERY 1 0 0 0 0 0 NXDOMAIN 1 0 6 1 SOA 1 Unknown + diff --git a/test-scripts/check-testcontent.sh b/test-scripts/check-testcontent.sh index b592ea7..fc47493 100755 --- a/test-scripts/check-testcontent.sh +++ b/test-scripts/check-testcontent.sh @@ -56,6 +56,6 @@ if [ $? -ne 0 ]; then cleanup 1 fi -cmp $tmpdir/out.debugqr $DATAQR && +diff -i $tmpdir/out.debugqr $DATAQR && diff -i $tmpdir/out.diag $DATADIAG cleanup $? diff --git a/test-scripts/same-qr-dump.sh b/test-scripts/same-qr-dump.sh index 8b9fefb..5ed4b8b 100755 --- a/test-scripts/same-qr-dump.sh +++ b/test-scripts/same-qr-dump.sh @@ -39,5 +39,5 @@ if [ $? -ne 0 ]; then cleanup 1 fi -cmp -s $tmpdir/compactor-qr.txt $tmpdir/inspector-qr.txt +diff -i $tmpdir/compactor-qr.txt $tmpdir/inspector-qr.txt cleanup $? diff --git a/test-scripts/testcontent.debugqr b/test-scripts/testcontent.debugqr index 9ba1beb..64a58fe 100644 --- a/test-scripts/testcontent.debugqr +++ b/test-scripts/testcontent.debugqr @@ -1,78 +1,16 @@ -Query/Response: -Query: 2016-04-05 19h33m24s561484us UTC - Client IP: 86.237.170.188 - Server IP: 211.79.123.239 - Transport: UDP - Client port: 51644 - Server port: 53 - Hop limit: 52 - DNS QR: Query - ID: 61888 - Opcode: 0 - Rcode: 0 - Flags: - QdCount: 1 - AnCount: 0 - NsCount: 0 - ArCount: 1 - Name: xtsskb5qon8sn._kerberos._tcp.TEVC._sites.dc._msdcs.172.20.222.38 - Type: 33 - Class: 1 -Response: 2016-04-05 19h33m24s561574us UTC - Client IP: 86.237.170.188 - Server IP: 211.79.123.239 - Transport: UDP - Client port: 51644 - Server port: 53 - Hop limit: 64 - DNS QR: Response - ID: 61888 - Opcode: 0 - Rcode: 3 - Flags: AA - QdCount: 1 - AnCount: 0 - NsCount: 4 - ArCount: 1 - Name: xtsskb5qon8sn._kerberos._tcp.TEVC._sites.dc._msdcs.172.20.222.38 - Type: 33 - Class: 1 -Query/Response: -Query: 2016-04-05 19h33m24s667820us UTC - Client IP: 3249:ed7d:124b:f9c3:1248:e8c5:12ef:e8c5 - Server IP: 3249:edc5:124b:e8c5:1248:e8c5:1248:e847 - Transport: UDP - Client port: 47686 - Server port: 53 - Hop limit: 59 - DNS QR: Query - ID: 11414 - Opcode: 0 - Rcode: 0 - Flags: - QdCount: 1 - AnCount: 0 - NsCount: 0 - ArCount: 1 - Name: CO801M180191.azcorrections.local - Type: 6 - Class: 1 -Response: 2016-04-05 19h33m24s667916us UTC - Client IP: 3249:ed7d:124b:f9c3:1248:e8c5:12ef:e8c5 - Server IP: 3249:edc5:124b:e8c5:1248:e8c5:1248:e847 - Transport: UDP - Client port: 47686 - Server port: 53 - Hop limit: 64 - DNS QR: Response - ID: 11414 - Opcode: 0 - Rcode: 3 - Flags: AA - QdCount: 1 - AnCount: 0 - NsCount: 6 - ArCount: 1 - Name: CO801M180191.azcorrections.local - Type: 6 - Class: 1 +----------------------------------------------------------------------------------------------------------------------------------- + Timestamp Client IP/port Server IP/port QNAME +Query 2016-04-05 19h33m24s561484us UTC 86.237.170.188:51644 211.79.123.239:53 xtsskb5qon8sn._kerberos._tcp.TEVC._sites.dc._msdcs.172.20.222.38 +Response 2016-04-05 19h33m24s561574us UTC 86.237.170.188:51644 211.79.123.239:53 xtsskb5qon8sn._kerberos._tcp.TEVC._sites.dc._msdcs.172.20.222.38 + Transport Hop-limit MsgID QR OPCODE FLAGS(AA/TC/RD/RA/AD/CD) RCODE COUNTS(QD/AN/NS/AD) Query-type Class Trans-type + UDP 52 61888 0 QUERY 0 0 0 0 0 0 NOERROR 1 0 0 1 SRV 1 Unknown + 61888 1 QUERY 1 0 0 0 0 0 NXDOMAIN 1 0 4 1 SRV 1 Unknown + +----------------------------------------------------------------------------------------------------------------------------------- + Timestamp Client IP/port Server IP/port QNAME +Query 2016-04-05 19h33m24s667820us UTC 3249:ed7d:124b:f9c3:1248:e8c5:12ef:e8c5:47686 3249:edc5:124b:e8c5:1248:e8c5:1248:e847:53 CO801M180191.azcorrections.local +Response 2016-04-05 19h33m24s667916us UTC 3249:ed7d:124b:f9c3:1248:e8c5:12ef:e8c5:47686 3249:edc5:124b:e8c5:1248:e8c5:1248:e847:53 CO801M180191.azcorrections.local + Transport Hop-limit MsgID QR OPCODE FLAGS(AA/TC/RD/RA/AD/CD) RCODE COUNTS(QD/AN/NS/AD) Query-type Class Trans-type + UDP 59 11414 0 QUERY 0 0 0 0 0 0 NOERROR 1 0 0 1 SOA 1 Unknown + 11414 1 QUERY 1 0 0 0 0 0 NXDOMAIN 1 0 6 1 SOA 1 Unknown +