"Fossies" - the Fresh Open Source Software Archive

Member "pdns-auth-4.2.0/pdns/dnsbulktest.cc" (27 Aug 2019, 12032 Bytes) of package /linux/misc/dns/pdns-auth-4.2.0.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "dnsbulktest.cc" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 4.1.13_vs_4.2.0.

    1 /*
    2  * This file is part of PowerDNS or dnsdist.
    3  * Copyright -- PowerDNS.COM B.V. and its contributors
    4  *
    5  * This program is free software; you can redistribute it and/or modify
    6  * it under the terms of version 2 of the GNU General Public License as
    7  * published by the Free Software Foundation.
    8  *
    9  * In addition, for the avoidance of any doubt, permission is granted to
   10  * link this program with OpenSSL and to (re)distribute the binaries
   11  * produced as the result of such linking.
   12  *
   13  * This program is distributed in the hope that it will be useful,
   14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
   15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   16  * GNU General Public License for more details.
   17  *
   18  * You should have received a copy of the GNU General Public License
   19  * along with this program; if not, write to the Free Software
   20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
   21  */
   22 #ifdef HAVE_CONFIG_H
   23 #include "config.h"
   24 #endif
   25 #include <boost/accumulators/accumulators.hpp>
   26 #include <boost/array.hpp>
   27 #include <boost/accumulators/statistics.hpp>
   28 #include <boost/program_options.hpp>
   29 #include "inflighter.cc"
   30 #include <deque>
   31 #include "namespaces.hh"
   32 #include "dnsparser.hh"
   33 #include "sstuff.hh"
   34 #include "misc.hh"
   35 #include "dnswriter.hh"
   36 #include "dnsrecords.hh"
   37 
   38 using namespace boost::accumulators;
   39 namespace po = boost::program_options;
   40 
   41 po::variables_map g_vm;
   42 
   43 StatBag S;
   44 
   45 bool g_quiet=false;
   46 bool g_envoutput=false;
   47 
   48 struct DNSResult
   49 {
   50   vector<ComboAddress> ips;
   51   int rcode;
   52   bool seenauthsoa;
   53 };
   54 
   55 struct TypedQuery
   56 {
   57   TypedQuery(const string& name_, uint16_t type_) : name(name_), type(type_){}
   58   DNSName name;
   59   uint16_t type;
   60 };
   61 
   62 struct SendReceive
   63 {
   64   typedef int Identifier;
   65   typedef DNSResult Answer; // ip 
   66   int d_socket;
   67   deque<uint16_t> d_idqueue;
   68     
   69   typedef accumulator_set<
   70         double
   71       , stats<boost::accumulators::tag::extended_p_square,
   72               boost::accumulators::tag::median(with_p_square_quantile),
   73               boost::accumulators::tag::mean(immediate)
   74               >
   75     > acc_t;
   76   acc_t* d_acc;
   77   
   78   boost::array<double, 11> d_probs;
   79   
   80   SendReceive(const std::string& remoteAddr, uint16_t port) : d_probs({{0.001,0.01, 0.025, 0.1, 0.25,0.5,0.75,0.9,0.975, 0.99,0.9999}})
   81   {
   82     d_acc = new acc_t(boost::accumulators::tag::extended_p_square::probabilities=d_probs);
   83     // 
   84     //d_acc = acc_t
   85     d_socket = socket(AF_INET, SOCK_DGRAM, 0);
   86     int val=1;
   87     setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
   88     
   89     ComboAddress remote(remoteAddr, port);
   90     connect(d_socket, (struct sockaddr*)&remote, remote.getSocklen());
   91     d_oks = d_errors = d_nodatas = d_nxdomains = d_unknowns = 0;
   92     d_receiveds = d_receiveerrors = d_senderrors = 0;
   93     for(unsigned int id =0 ; id < std::numeric_limits<uint16_t>::max(); ++id) 
   94       d_idqueue.push_back(id);
   95   }
   96   
   97   ~SendReceive()
   98   {
   99     close(d_socket);
  100   }
  101   
  102   Identifier send(TypedQuery& domain)
  103   {
  104     //cerr<<"Sending query for '"<<domain<<"'"<<endl;
  105     
  106     // send it, copy code from 'sdig'
  107     vector<uint8_t> packet;
  108   
  109     DNSPacketWriter pw(packet, domain.name, domain.type);
  110 
  111     if(d_idqueue.empty()) {
  112       cerr<<"Exhausted ids!"<<endl;
  113       exit(1);
  114     }    
  115     pw.getHeader()->id = d_idqueue.front();
  116     d_idqueue.pop_front();
  117     pw.getHeader()->rd = 1;
  118     pw.getHeader()->qr = 0;
  119     
  120     if(::send(d_socket, &*packet.begin(), packet.size(), 0) < 0)
  121       d_senderrors++;
  122     
  123     if(!g_quiet)
  124       cout<<"Sent out query for '"<<domain.name<<"' with id "<<pw.getHeader()->id<<endl;
  125     return pw.getHeader()->id;
  126   }
  127   
  128   bool receive(Identifier& id, DNSResult& dr)
  129   {
  130     if(waitForData(d_socket, 0, 500000) > 0) {
  131       char buf[512];
  132           
  133       int len = recv(d_socket, buf, sizeof(buf), 0);
  134       if(len < 0) {
  135         d_receiveerrors++;
  136         return 0;
  137       }
  138       else {
  139         d_receiveds++;
  140       }
  141       // parse packet, set 'id', fill out 'ip' 
  142       
  143       MOADNSParser mdp(false, string(buf, len));
  144       if(!g_quiet) {
  145         cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
  146         cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr;
  147         cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
  148       }
  149       dr.rcode = mdp.d_header.rcode;
  150       for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {          
  151         if(i->first.d_place == 1 && i->first.d_type == mdp.d_qtype)
  152           dr.ips.push_back(ComboAddress(i->first.d_content->getZoneRepresentation()));
  153         if(i->first.d_place == 2 && i->first.d_type == QType::SOA) {
  154           dr.seenauthsoa = 1;
  155         }
  156         if(!g_quiet)
  157         {
  158           cout<<i->first.d_place-1<<"\t"<<i->first.d_name<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
  159           cout<<"\t"<<i->first.d_ttl<<"\t"<< i->first.d_content->getZoneRepresentation()<<"\n";
  160         }
  161       }
  162       
  163       id = mdp.d_header.id;
  164       d_idqueue.push_back(id);
  165     
  166       return 1;
  167     }
  168     return 0;
  169   }
  170   
  171   void deliverTimeout(const Identifier& id)
  172   {
  173     if(!g_quiet) {
  174       cout<<"Timeout for id "<<id<<endl;
  175     }
  176     d_idqueue.push_back(id);
  177   }
  178   
  179   void deliverAnswer(TypedQuery& domain, const DNSResult& dr, unsigned int usec)
  180   {
  181     (*d_acc)(usec/1000.0);
  182 //    if(usec > 1000000)
  183   //    cerr<<"Slow: "<<domain<<" ("<<usec/1000.0<<" msec)\n";
  184     if(!g_quiet) {
  185       cout<<domain.name<<"|"<<DNSRecordContent::NumberToType(domain.type)<<": ("<<usec/1000.0<<"msec) rcode: "<<dr.rcode;
  186       for(const ComboAddress& ca :  dr.ips) {
  187         cout<<", "<<ca.toString();
  188       }
  189       cout<<endl;
  190     }
  191     if(dr.rcode == RCode::NXDomain) {
  192       d_nxdomains++;
  193     }
  194     else if(dr.rcode) {
  195       d_errors++;
  196     }
  197     else if(dr.ips.empty() && dr.seenauthsoa) 
  198       d_nodatas++;
  199     else if(!dr.ips.empty())
  200       d_oks++;
  201     else {
  202       if(!g_quiet) cout<<"UNKNOWN!! ^^"<<endl;
  203       d_unknowns++;
  204     }
  205   }
  206   unsigned int d_errors, d_nxdomains, d_nodatas, d_oks, d_unknowns;
  207   unsigned int d_receiveds, d_receiveerrors, d_senderrors;
  208 };
  209 
  210 void usage(po::options_description &desc) {
  211   cerr << "Usage: dnsbulktest [OPTION].. IPADDRESS PORTNUMBER [LIMIT]"<<endl;
  212   cerr << desc << "\n";
  213 }
  214 
  215 int main(int argc, char** argv)
  216 try
  217 {
  218   po::options_description desc("Allowed options");
  219   desc.add_options()
  220     ("help,h", "produce help message")
  221     ("quiet,q", "be quiet about individual queries")
  222     ("type,t",  po::value<string>()->default_value("A"), "What type to query for")
  223     ("envoutput,e", "write report in shell environment format")
  224     ("version", "show the version number")
  225     ("www", po::value<bool>()->default_value(true), "duplicate all queries with an additional 'www.' in front")
  226   ;
  227 
  228   po::options_description alloptions;
  229   po::options_description hidden("hidden options");
  230   hidden.add_options()
  231     ("ip-address", po::value<string>(), "ip-address")
  232     ("portnumber", po::value<uint16_t>(), "portnumber")
  233     ("limit", po::value<uint32_t>()->default_value(0), "limit");
  234 
  235   alloptions.add(desc).add(hidden);
  236   po::positional_options_description p;
  237   p.add("ip-address", 1);
  238   p.add("portnumber", 1);
  239   p.add("limit", 1);
  240 
  241   po::store(po::command_line_parser(argc, argv).options(alloptions).positional(p).run(), g_vm);
  242   po::notify(g_vm);
  243 
  244   if (g_vm.count("help")) {
  245     usage(desc);
  246     return EXIT_SUCCESS;
  247   }
  248 
  249   if (g_vm.count("version")) {
  250     cerr<<"dnsbulktest "<<VERSION<<endl;
  251     return EXIT_SUCCESS;
  252   }
  253 
  254   if(!g_vm.count("portnumber")) {
  255     cerr<<"Fatal, need to specify ip-address and portnumber"<<endl;
  256     usage(desc);
  257     return EXIT_FAILURE;
  258   }
  259 
  260   bool doWww = g_vm["www"].as<bool>();
  261   g_quiet = g_vm.count("quiet") > 0;
  262   g_envoutput = g_vm.count("envoutput") > 0;
  263   uint16_t qtype;
  264   reportAllTypes();
  265   try {
  266     qtype = DNSRecordContent::TypeToNumber(g_vm["type"].as<string>());
  267   }
  268   catch(std::exception& e) {
  269     cerr << e.what() << endl;
  270     return EXIT_FAILURE;
  271   }
  272 
  273   SendReceive sr(g_vm["ip-address"].as<string>(), g_vm["portnumber"].as<uint16_t>());
  274   unsigned int limit = g_vm["limit"].as<unsigned int>();
  275     
  276   vector<TypedQuery> domains;
  277     
  278   Inflighter<vector<TypedQuery>, SendReceive> inflighter(domains, sr);
  279   inflighter.d_maxInFlight = 1000;
  280   inflighter.d_timeoutSeconds = 3;
  281   inflighter.d_burst = 100;
  282   string line;
  283   
  284   pair<string, string> split;
  285   string::size_type pos;
  286   while(stringfgets(stdin, line)) {
  287     if(limit && domains.size() >= limit)
  288       break;
  289 
  290     trim_right(line);
  291     if(line.empty() || line[0] == '#')
  292       continue;
  293     split=splitField(line,',');
  294     if (split.second.empty())
  295       split=splitField(line,'\t');
  296     if(split.second.find('.') == 0) // skip 'Hidden profile' in quantcast list.
  297       continue;
  298     pos=split.second.find('/');
  299     if(pos != string::npos) // alexa has whole urls in the list now.
  300       split.second.resize(pos);
  301     if(find_if(split.second.begin(), split.second.end(), isalpha) == split.second.end())
  302     {
  303       continue; // this was an IP address
  304     }
  305     domains.push_back(TypedQuery(split.second, qtype));
  306     if(doWww)
  307       domains.push_back(TypedQuery("www."+split.second, qtype));
  308   }
  309   cerr<<"Read "<<domains.size()<<" domains!"<<endl;
  310   random_shuffle(domains.begin(), domains.end());
  311 
  312   boost::format datafmt("%s %|20t|%+15s  %|40t|%s %|60t|%+15s\n");
  313 
  314   for(;;) {
  315     try {
  316       inflighter.run();
  317       break;
  318     }
  319     catch(std::exception& e) {
  320       cerr<<"Caught exception: "<<e.what()<<endl;
  321     }
  322   }
  323 
  324   cerr<< datafmt % "Sending" % "" % "Receiving" % "";
  325   cerr<< datafmt % "  Queued " % domains.size() % "  Received" % sr.d_receiveds;
  326   cerr<< datafmt % "  Error -/-" % sr.d_senderrors %  "  Timeouts" % inflighter.getTimeouts();
  327   cerr<< datafmt % " " % "" %  "  Unexpected" % inflighter.getUnexpecteds();
  328   
  329   cerr<< datafmt % " Sent" % (domains.size() - sr.d_senderrors) %  " Total" % (sr.d_receiveds + inflighter.getTimeouts() + inflighter.getUnexpecteds());
  330   
  331   cerr<<endl;  
  332   cerr<< datafmt % "DNS Status" % ""       % "" % "";
  333   cerr<< datafmt % "  OK" % sr.d_oks       % "" % "";
  334   cerr<< datafmt % "  Error" % sr.d_errors       % "" % "";  
  335   cerr<< datafmt % "  No Data" % sr.d_nodatas       % "" % "";  
  336   cerr<< datafmt % "  NXDOMAIN" % sr.d_nxdomains      % "" % "";
  337   cerr<< datafmt % "  Unknowns" % sr.d_unknowns      % "" % "";  
  338   cerr<< datafmt % "Answers" % (sr.d_oks      +      sr.d_errors      +      sr.d_nodatas      + sr.d_nxdomains           +      sr.d_unknowns) % "" % "";
  339   cerr<< datafmt % "  Timeouts " % (inflighter.getTimeouts()) % "" % "";
  340   cerr<< datafmt % "Total " % (sr.d_oks      +      sr.d_errors      +      sr.d_nodatas      + sr.d_nxdomains           +      sr.d_unknowns + inflighter.getTimeouts()) % "" % "";
  341   
  342   cerr<<"\n";
  343   cerr<< "Mean response time: "<<mean(*sr.d_acc) << " msec"<<", median: "<<median(*sr.d_acc)<< " msec\n";
  344   
  345   boost::format statfmt("Time < %6.03f msec %|30t|%6.03f%% cumulative\n");
  346   
  347   for (unsigned int i = 0; i < sr.d_probs.size(); ++i) {
  348         cerr << statfmt % extended_p_square(*sr.d_acc)[i] % (100*sr.d_probs[i]);
  349     }
  350 
  351   if(g_envoutput) {
  352     cout<<"DBT_QUEUED="<<domains.size()<<endl;
  353     cout<<"DBT_SENDERRORS="<<sr.d_senderrors<<endl;
  354     cout<<"DBT_RECEIVED="<<sr.d_receiveds<<endl;
  355     cout<<"DBT_NXDOMAINS="<<sr.d_nxdomains<<endl;
  356     cout<<"DBT_NODATAS="<<sr.d_nodatas<<endl;
  357     cout<<"DBT_UNKNOWNS="<<sr.d_unknowns<<endl;
  358     cout<<"DBT_OKS="<<sr.d_oks<<endl;
  359     cout<<"DBT_ERRORS="<<sr.d_errors<<endl;
  360     cout<<"DBT_TIMEOUTS="<<inflighter.getTimeouts()<<endl;
  361     cout<<"DBT_UNEXPECTEDS="<<inflighter.getUnexpecteds()<<endl;
  362     cout<<"DBT_OKPERCENTAGE="<<((float)sr.d_oks/domains.size()*100)<<endl;
  363     cout<<"DBT_OKPERCENTAGEINT="<<(int)((float)sr.d_oks/domains.size()*100)<<endl;
  364   }
  365 }
  366 catch(PDNSException& pe)
  367 {
  368   cerr<<"Fatal error: "<<pe.reason<<endl;
  369   exit(EXIT_FAILURE);
  370 }