From: bert hubert Date: Thu, 26 Jun 2014 10:49:17 +0000 (+0200) Subject: teach dnsscope --servfail-tree which emits nodes in DNS that cause servfails, plus... X-Git-Tag: auth-3.4.0-rc1~119 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=9ad511a7445d75f3def159cb27dda2083386cf98;p=thirdparty%2Fpdns.git teach dnsscope --servfail-tree which emits nodes in DNS that cause servfails, plus IP addresses doing queries within those trees --- diff --git a/pdns/dnsscope.cc b/pdns/dnsscope.cc index 540a09aae2..4a6ed57cf4 100644 --- a/pdns/dnsscope.cc +++ b/pdns/dnsscope.cc @@ -14,6 +14,7 @@ #include #include "arguments.hh" #include "namespaces.hh" +#include namespace po = boost::program_options; po::variables_map g_vm; @@ -25,6 +26,172 @@ ArgvMap& arg() } StatBag S; +struct comboCompare +{ + bool operator()(const ComboAddress& a, const ComboAddress& b) const + { + return ntohl(a.sin4.sin_addr.s_addr) < ntohl(b.sin4.sin_addr.s_addr); + } +}; + + +class StatNode +{ +public: + void submit(const std::string& domain, int rcode, const ComboAddress& remote); + void submit(deque& labels, const std::string& domain, int rcode, const ComboAddress& remote); + + string name; + string fullname; + struct Stat + { + Stat() : queries(0), noerrors(0), nxdomains(0), servfails(0), drops(0){} + int queries, noerrors, nxdomains, servfails, drops; + + Stat& operator+=(const Stat& rhs) { + queries+=rhs.queries; + noerrors+=rhs.noerrors; + nxdomains+=rhs.nxdomains; + servfails+=rhs.servfails; + drops+=rhs.drops; + + BOOST_FOREACH(const remotes_t::value_type& rem, rhs.remotes) { + remotes[rem.first]+=rem.second; + } + return *this; + } + typedef map remotes_t; + remotes_t remotes; + }; + + Stat s; + Stat print(int depth=0, Stat newstat=Stat(), bool silent=false) const; + typedef boost::function visitor_t; + void visit(visitor_t visitor, Stat& newstat, int depth=0) const; + typedef map children_t; + children_t children; + +}; + +StatNode::Stat StatNode::print(int depth, Stat newstat, bool silent) const +{ + if(!silent) { + cout<1024 && !silent) { + cout<1024); + } + if(!silent || children.size()>1) + cout< parts; + stringtok(parts, domain, "."); + if(parts.empty()) + return; + children[parts.back()].submit(parts, "", rcode, remote); +} + +/* www.powerdns.com. -> + . <- fullnames + com. + powerdns.com + www.powerdns.com. +*/ + +void StatNode::submit(deque& labels, const std::string& domain, int rcode, const ComboAddress& remote) +{ + if(labels.empty()) + return; + // cerr<<"Submit called for domain='"< 0.8 && node->children.size()>100) { + cout<fullname<<", servfails: "<children.size()<fullname<<" "<(), "If set to true, only process RD packets, to false only non-RD, unset: both") ("ipv4", po::value()->default_value(true), "Process IPv4 packets") ("ipv6", po::value()->default_value(true), "Process IPv6 packets") + ("servfail-tree", "Figure out subtrees that generate servfails") ("load-stats,l", po::value()->default_value(""), "if set, emit per-second load statistics (questions, answers, outstanding)") ("write-failures,w", po::value()->default_value(""), "if set, write weird packets to this PCAP file") ("verbose,v", "be verbose"); @@ -115,6 +276,8 @@ try exit(1); } + StatNode root; + bool verbose = g_vm.count("verbose"); bool haveRDFilter=0, rdFilter=0; @@ -128,6 +291,7 @@ try bool doIPv4 = g_vm["ipv4"].as(); bool doIPv6 = g_vm["ipv6"].as(); + bool doServFailTree = g_vm.count("servfail-tree"); PcapPacketReader pr(files[0]); PcapPacketWriter* pw=0; @@ -245,6 +409,11 @@ try if(mdp.d_header.rcode != 0 && mdp.d_header.rcode!=3) errorresult++; + ComboAddress rem = pr.getDest(); + rem.sin4.sin_port=0; + + if(doServFailTree) + root.submit(mdp.d_qname, mdp.d_header.rcode, rem); } if(!qd.d_qcount || qd.d_qcount == qd.d_answercount) @@ -389,7 +558,12 @@ try BOOST_FOREACH(const ComboAddress& rem, rdnonra) { rdnonrafs<