]> git.ipfire.org Git - thirdparty/pdns.git/blame - pdns/dnsbulktest.cc
Fix warnings about dup/missing prototypes
[thirdparty/pdns.git] / pdns / dnsbulktest.cc
CommitLineData
12471842
PL
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 */
870a0fe4
AT
22#ifdef HAVE_CONFIG_H
23#include "config.h"
24#endif
830515d8
BH
25#include <boost/accumulators/accumulators.hpp>
26#include <boost/array.hpp>
27#include <boost/accumulators/statistics.hpp>
b3bd2e75 28#include <boost/program_options.hpp>
4dd35bb1 29#include "inflighter.cc"
a4382ef3 30#include <deque>
4dd35bb1
BH
31#include "namespaces.hh"
32#include "dnsparser.hh"
33#include "sstuff.hh"
34#include "misc.hh"
35#include "dnswriter.hh"
36#include "dnsrecords.hh"
d720eb8a
OM
37#include "dns_random.hh"
38#include "arguments.hh"
4dd35bb1 39
830515d8 40using namespace boost::accumulators;
b3bd2e75 41namespace po = boost::program_options;
de43ec0f 42
b3bd2e75 43po::variables_map g_vm;
830515d8 44
4dd35bb1
BH
45StatBag S;
46
d720eb8a
OM
47ArgvMap &arg()
48{
49 static ArgvMap theArg;
50 return theArg;
51}
52
b3bd2e75
PD
53bool g_quiet=false;
54bool g_envoutput=false;
55
4dd35bb1
BH
56struct DNSResult
57{
58 vector<ComboAddress> ips;
59 int rcode;
d712a557 60 bool seenauthsoa;
4dd35bb1
BH
61};
62
62921444
BH
63struct TypedQuery
64{
65 TypedQuery(const string& name_, uint16_t type_) : name(name_), type(type_){}
a9456e80 66 DNSName name;
62921444
BH
67 uint16_t type;
68};
830515d8 69
4dd35bb1
BH
70struct SendReceive
71{
72 typedef int Identifier;
73 typedef DNSResult Answer; // ip
74 int d_socket;
a4382ef3 75 deque<uint16_t> d_idqueue;
62921444 76
830515d8
BH
77 typedef accumulator_set<
78 double
79 , stats<boost::accumulators::tag::extended_p_square,
232f0877 80 boost::accumulators::tag::median(with_p_square_quantile),
830515d8 81 boost::accumulators::tag::mean(immediate)
232f0877 82 >
830515d8
BH
83 > acc_t;
84 acc_t* d_acc;
85
86 boost::array<double, 11> d_probs;
87
8a70e507 88 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}})
4dd35bb1 89 {
830515d8
BH
90 d_acc = new acc_t(boost::accumulators::tag::extended_p_square::probabilities=d_probs);
91 //
92 //d_acc = acc_t
4dd35bb1
BH
93 d_socket = socket(AF_INET, SOCK_DGRAM, 0);
94 int val=1;
95 setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
96
910d27bb 97 ComboAddress remote(remoteAddr, port);
4dd35bb1 98 connect(d_socket, (struct sockaddr*)&remote, remote.getSocklen());
9cb47734 99 d_oks = d_errors = d_nodatas = d_nxdomains = d_unknowns = 0;
bf2aaa52 100 d_receiveds = d_receiveerrors = d_senderrors = 0;
04bbeaa0 101 for(unsigned int id =0 ; id < std::numeric_limits<uint16_t>::max(); ++id)
a4382ef3 102 d_idqueue.push_back(id);
4dd35bb1
BH
103 }
104
105 ~SendReceive()
106 {
107 close(d_socket);
108 }
109
62921444 110 Identifier send(TypedQuery& domain)
4dd35bb1
BH
111 {
112 //cerr<<"Sending query for '"<<domain<<"'"<<endl;
113
114 // send it, copy code from 'sdig'
115 vector<uint8_t> packet;
116
62921444 117 DNSPacketWriter pw(packet, domain.name, domain.type);
bf2aaa52
BH
118
119 if(d_idqueue.empty()) {
120 cerr<<"Exhausted ids!"<<endl;
121 exit(1);
122 }
a4382ef3
BH
123 pw.getHeader()->id = d_idqueue.front();
124 d_idqueue.pop_front();
4dd35bb1
BH
125 pw.getHeader()->rd = 1;
126 pw.getHeader()->qr = 0;
127
bf2aaa52
BH
128 if(::send(d_socket, &*packet.begin(), packet.size(), 0) < 0)
129 d_senderrors++;
4dd35bb1 130
a9456e80 131 if(!g_quiet)
132 cout<<"Sent out query for '"<<domain.name<<"' with id "<<pw.getHeader()->id<<endl;
4dd35bb1
BH
133 return pw.getHeader()->id;
134 }
135
136 bool receive(Identifier& id, DNSResult& dr)
137 {
138 if(waitForData(d_socket, 0, 500000) > 0) {
139 char buf[512];
9cb47734 140
4dd35bb1 141 int len = recv(d_socket, buf, sizeof(buf), 0);
9cb47734
BH
142 if(len < 0) {
143 d_receiveerrors++;
4dd35bb1 144 return 0;
9cb47734
BH
145 }
146 else {
147 d_receiveds++;
148 }
4dd35bb1
BH
149 // parse packet, set 'id', fill out 'ip'
150
27c0050c 151 MOADNSParser mdp(false, string(buf, len));
b3bd2e75 152 if(!g_quiet) {
c48816ca 153 cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
b3bd2e75
PD
154 cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr;
155 cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
156 }
4dd35bb1
BH
157 dr.rcode = mdp.d_header.rcode;
158 for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
62921444 159 if(i->first.d_place == 1 && i->first.d_type == mdp.d_qtype)
4dd35bb1 160 dr.ips.push_back(ComboAddress(i->first.d_content->getZoneRepresentation()));
9cb47734 161 if(i->first.d_place == 2 && i->first.d_type == QType::SOA) {
d712a557
BH
162 dr.seenauthsoa = 1;
163 }
b3bd2e75
PD
164 if(!g_quiet)
165 {
c48816ca 166 cout<<i->first.d_place-1<<"\t"<<i->first.d_name<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
b3bd2e75
PD
167 cout<<"\t"<<i->first.d_ttl<<"\t"<< i->first.d_content->getZoneRepresentation()<<"\n";
168 }
4dd35bb1 169 }
d712a557 170
4dd35bb1 171 id = mdp.d_header.id;
bf2aaa52 172 d_idqueue.push_back(id);
d712a557 173
4dd35bb1
BH
174 return 1;
175 }
176 return 0;
177 }
178
a4382ef3
BH
179 void deliverTimeout(const Identifier& id)
180 {
a9456e80 181 if(!g_quiet) {
182 cout<<"Timeout for id "<<id<<endl;
183 }
a4382ef3
BH
184 d_idqueue.push_back(id);
185 }
186
62921444 187 void deliverAnswer(TypedQuery& domain, const DNSResult& dr, unsigned int usec)
4dd35bb1 188 {
830515d8
BH
189 (*d_acc)(usec/1000.0);
190// if(usec > 1000000)
191 // cerr<<"Slow: "<<domain<<" ("<<usec/1000.0<<" msec)\n";
b3bd2e75 192 if(!g_quiet) {
62921444 193 cout<<domain.name<<"|"<<DNSRecordContent::NumberToType(domain.type)<<": ("<<usec/1000.0<<"msec) rcode: "<<dr.rcode;
ef7cd021 194 for(const ComboAddress& ca : dr.ips) {
b3bd2e75
PD
195 cout<<", "<<ca.toString();
196 }
197 cout<<endl;
4dd35bb1 198 }
d712a557
BH
199 if(dr.rcode == RCode::NXDomain) {
200 d_nxdomains++;
201 }
202 else if(dr.rcode) {
910d27bb 203 d_errors++;
d712a557
BH
204 }
205 else if(dr.ips.empty() && dr.seenauthsoa)
206 d_nodatas++;
910d27bb
BH
207 else if(!dr.ips.empty())
208 d_oks++;
9cb47734 209 else {
b3bd2e75 210 if(!g_quiet) cout<<"UNKNOWN!! ^^"<<endl;
9cb47734
BH
211 d_unknowns++;
212 }
4dd35bb1 213 }
9cb47734 214 unsigned int d_errors, d_nxdomains, d_nodatas, d_oks, d_unknowns;
bf2aaa52 215 unsigned int d_receiveds, d_receiveerrors, d_senderrors;
4dd35bb1
BH
216};
217
050e6877 218static void usage(po::options_description &desc) {
d2c701a0
PL
219 cerr << "Usage: dnsbulktest [OPTION].. IPADDRESS PORTNUMBER [LIMIT]"<<endl;
220 cerr << desc << "\n";
221}
222
910d27bb 223int main(int argc, char** argv)
fc9152ee 224try
4dd35bb1 225{
b3bd2e75
PD
226 po::options_description desc("Allowed options");
227 desc.add_options()
228 ("help,h", "produce help message")
229 ("quiet,q", "be quiet about individual queries")
62921444 230 ("type,t", po::value<string>()->default_value("A"), "What type to query for")
b3bd2e75 231 ("envoutput,e", "write report in shell environment format")
d2c701a0 232 ("version", "show the version number")
503c33df 233 ("www", po::value<bool>()->default_value(true), "duplicate all queries with an additional 'www.' in front")
b3bd2e75
PD
234 ;
235
236 po::options_description alloptions;
237 po::options_description hidden("hidden options");
238 hidden.add_options()
239 ("ip-address", po::value<string>(), "ip-address")
240 ("portnumber", po::value<uint16_t>(), "portnumber")
241 ("limit", po::value<uint32_t>()->default_value(0), "limit");
242
243 alloptions.add(desc).add(hidden);
244 po::positional_options_description p;
245 p.add("ip-address", 1);
246 p.add("portnumber", 1);
247 p.add("limit", 1);
248
249 po::store(po::command_line_parser(argc, argv).options(alloptions).positional(p).run(), g_vm);
250 po::notify(g_vm);
251
252 if (g_vm.count("help")) {
d2c701a0 253 usage(desc);
b3bd2e75 254 return EXIT_SUCCESS;
ac379ae2 255 }
d2c701a0
PL
256
257 if (g_vm.count("version")) {
258 cerr<<"dnsbulktest "<<VERSION<<endl;
259 return EXIT_SUCCESS;
260 }
261
b3bd2e75
PD
262 if(!g_vm.count("portnumber")) {
263 cerr<<"Fatal, need to specify ip-address and portnumber"<<endl;
d2c701a0 264 usage(desc);
b3bd2e75
PD
265 return EXIT_FAILURE;
266 }
267
faf7fa43 268 bool doWww = g_vm["www"].as<bool>();
62921444
BH
269 g_quiet = g_vm.count("quiet") > 0;
270 g_envoutput = g_vm.count("envoutput") > 0;
271 uint16_t qtype;
272 reportAllTypes();
273 try {
274 qtype = DNSRecordContent::TypeToNumber(g_vm["type"].as<string>());
275 }
276 catch(std::exception& e) {
277 cerr << e.what() << endl;
278 return EXIT_FAILURE;
279 }
b3bd2e75
PD
280
281 SendReceive sr(g_vm["ip-address"].as<string>(), g_vm["portnumber"].as<uint16_t>());
282 unsigned int limit = g_vm["limit"].as<unsigned int>();
910d27bb 283
62921444 284 vector<TypedQuery> domains;
4dd35bb1 285
62921444 286 Inflighter<vector<TypedQuery>, SendReceive> inflighter(domains, sr);
0eafd0fe 287 inflighter.d_maxInFlight = 1000;
bf2aaa52 288 inflighter.d_timeoutSeconds = 3;
0eafd0fe 289 inflighter.d_burst = 100;
4dd35bb1
BH
290 string line;
291
292 pair<string, string> split;
013f96e9 293 string::size_type pos;
4dd35bb1 294 while(stringfgets(stdin, line)) {
910d27bb
BH
295 if(limit && domains.size() >= limit)
296 break;
246ccf7b 297
4dd35bb1 298 trim_right(line);
246ccf7b
KM
299 if(line.empty() || line[0] == '#')
300 continue;
4dd35bb1 301 split=splitField(line,',');
246ccf7b
KM
302 if (split.second.empty())
303 split=splitField(line,'\t');
1ee9e847 304 if(split.second.find('.') == 0) // skip 'Hidden profile' in quantcast list.
246ccf7b 305 continue;
013f96e9 306 pos=split.second.find('/');
246ccf7b 307 if(pos != string::npos) // alexa has whole urls in the list now.
013f96e9 308 split.second.resize(pos);
6fc9c5ea
BH
309 if(find_if(split.second.begin(), split.second.end(), isalpha) == split.second.end())
310 {
311 continue; // this was an IP address
312 }
62921444 313 domains.push_back(TypedQuery(split.second, qtype));
faf7fa43 314 if(doWww)
315 domains.push_back(TypedQuery("www."+split.second, qtype));
4dd35bb1
BH
316 }
317 cerr<<"Read "<<domains.size()<<" domains!"<<endl;
d720eb8a 318 shuffle(domains.begin(), domains.end(), pdns::dns_random_engine());
4dd35bb1 319
bf2aaa52
BH
320 boost::format datafmt("%s %|20t|%+15s %|40t|%s %|60t|%+15s\n");
321
4dd35bb1
BH
322 for(;;) {
323 try {
324 inflighter.run();
325 break;
326 }
830515d8 327 catch(std::exception& e) {
4dd35bb1
BH
328 cerr<<"Caught exception: "<<e.what()<<endl;
329 }
330 }
9cb47734 331
bf2aaa52
BH
332 cerr<< datafmt % "Sending" % "" % "Receiving" % "";
333 cerr<< datafmt % " Queued " % domains.size() % " Received" % sr.d_receiveds;
334 cerr<< datafmt % " Error -/-" % sr.d_senderrors % " Timeouts" % inflighter.getTimeouts();
335 cerr<< datafmt % " " % "" % " Unexpected" % inflighter.getUnexpecteds();
336
337 cerr<< datafmt % " Sent" % (domains.size() - sr.d_senderrors) % " Total" % (sr.d_receiveds + inflighter.getTimeouts() + inflighter.getUnexpecteds());
338
339 cerr<<endl;
340 cerr<< datafmt % "DNS Status" % "" % "" % "";
341 cerr<< datafmt % " OK" % sr.d_oks % "" % "";
342 cerr<< datafmt % " Error" % sr.d_errors % "" % "";
343 cerr<< datafmt % " No Data" % sr.d_nodatas % "" % "";
344 cerr<< datafmt % " NXDOMAIN" % sr.d_nxdomains % "" % "";
345 cerr<< datafmt % " Unknowns" % sr.d_unknowns % "" % "";
346 cerr<< datafmt % "Answers" % (sr.d_oks + sr.d_errors + sr.d_nodatas + sr.d_nxdomains + sr.d_unknowns) % "" % "";
347 cerr<< datafmt % " Timeouts " % (inflighter.getTimeouts()) % "" % "";
348 cerr<< datafmt % "Total " % (sr.d_oks + sr.d_errors + sr.d_nodatas + sr.d_nxdomains + sr.d_unknowns + inflighter.getTimeouts()) % "" % "";
830515d8
BH
349
350 cerr<<"\n";
351 cerr<< "Mean response time: "<<mean(*sr.d_acc) << " msec"<<", median: "<<median(*sr.d_acc)<< " msec\n";
830515d8 352
d497340c 353 boost::format statfmt("Time < %6.03f msec %|30t|%6.03f%% cumulative\n");
830515d8
BH
354
355 for (unsigned int i = 0; i < sr.d_probs.size(); ++i) {
356 cerr << statfmt % extended_p_square(*sr.d_acc)[i] % (100*sr.d_probs[i]);
357 }
358
b3bd2e75
PD
359 if(g_envoutput) {
360 cout<<"DBT_QUEUED="<<domains.size()<<endl;
361 cout<<"DBT_SENDERRORS="<<sr.d_senderrors<<endl;
362 cout<<"DBT_RECEIVED="<<sr.d_receiveds<<endl;
aa395172 363 cout<<"DBT_NXDOMAINS="<<sr.d_nxdomains<<endl;
364 cout<<"DBT_NODATAS="<<sr.d_nodatas<<endl;
365 cout<<"DBT_UNKNOWNS="<<sr.d_unknowns<<endl;
366 cout<<"DBT_OKS="<<sr.d_oks<<endl;
367 cout<<"DBT_ERRORS="<<sr.d_errors<<endl;
b3bd2e75
PD
368 cout<<"DBT_TIMEOUTS="<<inflighter.getTimeouts()<<endl;
369 cout<<"DBT_UNEXPECTEDS="<<inflighter.getUnexpecteds()<<endl;
bbb6ce1f 370 cout<<"DBT_OKPERCENTAGE="<<((float)sr.d_oks/domains.size()*100)<<endl;
dfddcdaf 371 cout<<"DBT_OKPERCENTAGEINT="<<(int)((float)sr.d_oks/domains.size()*100)<<endl;
b3bd2e75 372 }
4dd35bb1 373}
fc9152ee 374catch(PDNSException& pe)
375{
376 cerr<<"Fatal error: "<<pe.reason<<endl;
377 exit(EXIT_FAILURE);
378}