]> git.ipfire.org Git - thirdparty/pdns.git/commitdiff
rename tcpbench to dnstcpbench, add documentation, add command line parsing
authorbert hubert <bert.hubert@netherlabs.nl>
Tue, 11 Jun 2013 14:01:08 +0000 (16:01 +0200)
committerbert hubert <bert.hubert@netherlabs.nl>
Tue, 11 Jun 2013 14:09:47 +0000 (16:09 +0200)
pdns/Makefile.am
pdns/dnstcpbench.cc [moved from pdns/tcpbench.cc with 56% similarity]
pdns/docs/dnstcpbench.1.txt [new file with mode: 0644]

index 6d50bbd860a6e25898be0c3456caab3c15a8e22c..2c538a552d15c84666a513691ec00467b8c5ab37 100644 (file)
@@ -39,7 +39,7 @@ sbin_PROGRAMS = pdns_server
 bin_PROGRAMS = pdns_control pdnssec dnsreplay
 endif
 
-EXTRA_PROGRAMS=pdns_recursor sdig tcpbench tsig-tests speedtest pdns_control dnsscope dnsgram \
+EXTRA_PROGRAMS=pdns_recursor sdig dnstcpbench tsig-tests speedtest pdns_control dnsscope dnsgram \
 testrunner \
 toysdig dnsdemog dnswasher dnsscan nproxy notify pdnssec dnsbulktest nsec3dig # dnslabel # tcptorture
 
@@ -142,10 +142,11 @@ sdig_SOURCES=sdig.cc sstuff.hh dnsparser.cc dnsparser.hh dnsrecords.cc dnswriter
        misc.cc misc.hh rcpgenerator.cc rcpgenerator.hh base64.cc base64.hh unix_utility.cc \
        logger.cc statbag.cc qtype.cc sillyrecords.cc nsecrecords.cc base32.cc
 
-tcpbench_SOURCES=tcpbench.cc sstuff.hh dnsparser.cc dnsparser.hh dnsrecords.cc dnswriter.cc dnslabeltext.cc dnswriter.hh \
+dnstcpbench_SOURCES=dnstcpbench.cc sstuff.hh dnsparser.cc dnsparser.hh dnsrecords.cc dnswriter.cc dnslabeltext.cc dnswriter.hh \
        misc.cc misc.hh rcpgenerator.cc rcpgenerator.hh base64.cc base64.hh unix_utility.cc \
        logger.cc statbag.cc qtype.cc sillyrecords.cc nsecrecords.cc base32.cc
-
+dnstcpbench_LDFLAGS=$(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+dnstcpbench_LDADD=$(BOOST_PROGRAM_OPTIONS_LIBS)
 
 nsec3dig_SOURCES=nsec3dig.cc sstuff.hh dnsparser.cc dnsparser.hh dnsrecords.cc dnswriter.cc dnslabeltext.cc \
     dnswriter.hh dnssecinfra.cc \
similarity index 56%
rename from pdns/tcpbench.cc
rename to pdns/dnstcpbench.cc
index 0f4c047dacdc90b3135a7f5d33f54aa9f42a5658..ce0f7cd7b59b6fa6d4e29f0d4302522926deccaf 100644 (file)
@@ -5,20 +5,24 @@
 #include "dnsrecords.hh"
 #include "statbag.hh"
 #include <boost/array.hpp>
-StatBag S;
+#include <boost/program_options.hpp>
 
+StatBag S;
+namespace po = boost::program_options;
+po::variables_map g_vm;
+bool g_verbose;
 bool g_onlyTCP;
-AtomicCounter g_networkErrors, g_otherErrors, g_OK, g_truncates;
+unsigned int g_timeoutMsec;
+AtomicCounter g_networkErrors, g_otherErrors, g_OK, g_truncates, g_authAnswers, g_timeOuts;
 
 // echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle 
 
-
 void doQuery(const std::string& qname, uint16_t qtype, const ComboAddress& dest)
 try
 {
   vector<uint8_t> packet;
   DNSPacketWriter pw(packet, qname, qtype);
-
+  int res;
   string reply;
 
   if(!g_onlyTCP) {
@@ -26,6 +30,14 @@ try
     
     udpsock.sendTo(string((char*)&*packet.begin(), (char*)&*packet.end()), dest);
     ComboAddress origin;
+    res = waitForData(udpsock.getHandle(), 0, 1000 * g_timeoutMsec);
+    if(res < 0)
+      throw NetworkError("Error waiting for response");
+    if(!res) {
+      g_timeOuts++;
+      return;
+    }
+
     udpsock.recvFrom(reply, origin);
     MOADNSParser mdp(reply);
     if(!mdp.d_header.tc)
@@ -33,19 +45,25 @@ try
     g_truncates++;
   }
 
-
   Socket sock(InterNetwork, Stream);
   int tmp=1;
   if(setsockopt(sock.getHandle(),SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) 
     throw runtime_error("Unable to set socket reuse: "+string(strerror(errno)));
 
   sock.connect(dest);
-  uint16_t len;
-  len = htons(packet.size());
-  if(sock.write((char *) &len, 2) != 2)
-    throw AhuException("tcp write failed");
-  
-  sock.writen(string((char*)&*packet.begin(), (char*)&*packet.end()));
+  uint16_t len = htons(packet.size());
+  string tcppacket((char*)& len, 2);
+  tcppacket.append((char*)&*packet.begin(), (char*)&*packet.end());
+
+  sock.writen(tcppacket);
+
+  res = waitForData(sock.getHandle(), 0, 1000 * g_timeoutMsec);
+  if(res < 0)
+    throw NetworkError("Error waiting for response");
+  if(!res) {
+    g_timeOuts++;
+    return;
+  }
   
   if(sock.read((char *) &len, 2) != 2)
     throw AhuException("tcp read failed");
@@ -66,6 +84,8 @@ try
   
   MOADNSParser mdp(reply);
   //  cout<<"Had correct TCP/IP response, "<<mdp.d_answers.size()<<" answers, aabit="<<mdp.d_header.aa<<endl;
+  if(mdp.d_header.aa)
+    g_authAnswers++;
   g_OK++;
 }
 catch(NetworkError& ne)
@@ -77,7 +97,6 @@ catch(...)
 {
   g_otherErrors++;
 }
 
 /* read queries from stdin, put in vector
    launch n worker threads, each picks a query using AtomicCounter
@@ -108,24 +127,57 @@ void* worker(void*)
   return 0;
 }
 
-
 int main(int argc, char** argv)
 try
 {
+  po::options_description desc("Allowed options"), hidden, alloptions;
+  desc.add_options()
+    ("help,h", "produce help message")
+    ("verbose,v", "be verbose")
+    ("udp-first,u", "try UDP first")
+    ("timeout-msec", po::value<int>()->default_value(10), "wait for this amount of milliseconds for an answer")
+    ("workers", po::value<int>()->default_value(100), "number of parallel workers");
+
+  hidden.add_options()
+    ("remote-host", po::value<string>(), "remote-host")
+    ("remote-port", po::value<int>()->default_value(53), "remote-port");
+  alloptions.add(desc).add(hidden); 
+
+  po::positional_options_description p;
+  p.add("remote-host", 1);
+  p.add("remote-port", 1);
+
+  po::store(po::command_line_parser(argc, argv).options(alloptions).positional(p).run(), g_vm);
+  po::notify(g_vm);
+  
+  if(g_vm.count("help")) {
+    cout << desc<<endl;
+    exit(EXIT_SUCCESS);
+  }
+  g_onlyTCP = !g_vm.count("udp-first");
+  g_verbose = g_vm.count("verbose");
+  g_timeoutMsec = g_vm["timeout-msec"].as<int>();
+
   reportAllTypes();
-  g_onlyTCP=false;
 
-  uint16_t port=53;
-  if(argc < 2) {
+  if(g_vm["remote-host"].empty()) {
     cerr<<"Syntax: tcpbench remote [port] < queries"<<endl;
     cerr<<"Where queries is one query per line, format: qname qtype, just 1 space"<<endl;
+    cerr<<desc<<endl;
     exit(EXIT_FAILURE);
   }
-  if(argc > 2)
-    port = atoi(argv[2]);
 
-  g_dest = ComboAddress(argv[1], port);
-  unsigned int numworkers=100;
+  g_dest = ComboAddress(g_vm["remote-host"].as<string>().c_str(), g_vm["remote-port"].as<int>());
+
+  unsigned int numworkers=g_vm["workers"].as<int>();
+  
+  if(g_verbose) {
+    cout<<"Sending queries to: "<<g_dest.toStringWithPort()<<endl;
+    cout<<"Attempting UDP first: " << (g_onlyTCP ? "no" : "yes") <<endl;
+    cout<<"Timeout: "<< g_timeoutMsec<<"msec"<<endl;
+  }
+
+
   pthread_t workers[numworkers];
 
   FILE* fp=fdopen(0, "r");
@@ -146,7 +198,8 @@ try
     pthread_join(workers[n], &status);
   }
   cout<<"OK: "<<g_OK<<", network errors: "<<g_networkErrors<<", other errors: "<<g_otherErrors<<endl;
-  cout<<"Truncateds: "<<g_truncates<<endl;
+  cout<<"Timeouts: "<<g_timeOuts<<endl;
+  cout<<"Truncateds: "<<g_truncates<<", auth answers: "<<g_authAnswers<<endl;
 }
 catch(std::exception &e)
 {
diff --git a/pdns/docs/dnstcpbench.1.txt b/pdns/docs/dnstcpbench.1.txt
new file mode 100644 (file)
index 0000000..590b852
--- /dev/null
@@ -0,0 +1,64 @@
+DNSTCPBENCH(1)\r
+==============
+bert hubert <bert.hubert@netherlabs.nl>
+
+NAME
+----
+dnstcpbench - tool to perform TCP benchmarking of nameservers
+
+SYNOPSIS
+--------
+'dnstcpbench' [--help] [--verbose] [--udp-first, -u] [--workers] [--timeout-msec] remote-ip-address [remote-port]
+\r
+DESCRIPTION
+-----------
+dnstcpbench reads DNS queries from standard input and sends them out in\r
+parallel to a remote nameserver. By default TCP/IP is used, but optionally,\r
+UDP is tried first, which allows for the benchmarking of TCP/IP fallback.\r
+\r
+The input format is one query per line: qname single-space qtype. An\r
+example:\r
+       www.powerdns.com ANY\r
+       powerdns.com MX\r
+\r
+OPTIONS
+-------
+
+--verbose::
+       Be wordy on what the program is doing
+
+--udp-first, -u::
+       Attempt resolution via UDP first, only do TCP if truncated answer is\r
+       received
+\r
+--workers::\r
+       Number of parallel worker threads to use. \r
+\r
+--timeout-msec::\r
+       Number of milliseconds to wait for an answer    
+\r
+--help::\r
+       Provide a helpful message\r
+\r
+BUGS
+----
+Currently the timeout code does not actually perform non-blocking connects\r
+or writes.  So a slow connect or slow writes will still cause low\r
+performance and delays. \r
+\r
+Does not yet support IPv6 testing.\r
+
+AUTHOR
+------
+Written by PowerDNS.COM BV, bert hubert, <bert.hubert@netherlabs.nl>
+
+RESOURCES
+---------
+Website: http://www.powerdns.com
+
+COPYING
+-------
+Copyright (C) 2013 PowerDNS.COM BV. Free use of this software
+is granted under the terms of the GNU General Public License (GPL) version
+2.
+