4 #include <boost/accumulators/accumulators.hpp>
5 #include <boost/array.hpp>
6 #include <boost/accumulators/statistics.hpp>
7 #include <boost/program_options.hpp>
8 #include "inflighter.cc"
10 #include "namespaces.hh"
11 #include "dnsparser.hh"
14 #include "dnswriter.hh"
15 #include "dnsrecords.hh"
17 using namespace boost::accumulators
;
18 namespace po
= boost::program_options
;
20 po::variables_map g_vm
;
25 bool g_envoutput
=false;
29 vector
<ComboAddress
> ips
;
36 TypedQuery(const string
& name_
, uint16_t type_
) : name(name_
), type(type_
){}
43 typedef int Identifier
;
44 typedef DNSResult Answer
; // ip
46 deque
<uint16_t> d_idqueue
;
48 typedef accumulator_set
<
50 , stats
<boost::accumulators::tag::extended_p_square
,
51 boost::accumulators::tag::median(with_p_square_quantile
),
52 boost::accumulators::tag::mean(immediate
)
57 boost::array
<double, 11> d_probs
;
59 SendReceive(const std::string
& remoteAddr
, uint16_t port
)
61 boost::array
<double, 11> tmp
={{0.001,0.01, 0.025, 0.1, 0.25,0.5,0.75,0.9,0.975, 0.99,0.9999}};
63 d_acc
= new acc_t(boost::accumulators::tag::extended_p_square::probabilities
=d_probs
);
66 d_socket
= socket(AF_INET
, SOCK_DGRAM
, 0);
68 setsockopt(d_socket
, SOL_SOCKET
, SO_REUSEADDR
, &val
, sizeof(val
));
70 ComboAddress
remote(remoteAddr
, port
);
71 connect(d_socket
, (struct sockaddr
*)&remote
, remote
.getSocklen());
72 d_oks
= d_errors
= d_nodatas
= d_nxdomains
= d_unknowns
= 0;
73 d_receiveds
= d_receiveerrors
= d_senderrors
= 0;
74 for(unsigned int id
=0 ; id
< std::numeric_limits
<uint16_t>::max(); ++id
)
75 d_idqueue
.push_back(id
);
83 Identifier
send(TypedQuery
& domain
)
85 //cerr<<"Sending query for '"<<domain<<"'"<<endl;
87 // send it, copy code from 'sdig'
88 vector
<uint8_t> packet
;
90 DNSPacketWriter
pw(packet
, domain
.name
, domain
.type
);
92 if(d_idqueue
.empty()) {
93 cerr
<<"Exhausted ids!"<<endl
;
96 pw
.getHeader()->id
= d_idqueue
.front();
97 d_idqueue
.pop_front();
98 pw
.getHeader()->rd
= 1;
99 pw
.getHeader()->qr
= 0;
101 if(::send(d_socket
, &*packet
.begin(), packet
.size(), 0) < 0)
105 cout
<<"Sent out query for '"<<domain
.name
<<"' with id "<<pw
.getHeader()->id
<<endl
;
106 return pw
.getHeader()->id
;
109 bool receive(Identifier
& id
, DNSResult
& dr
)
111 if(waitForData(d_socket
, 0, 500000) > 0) {
114 int len
= recv(d_socket
, buf
, sizeof(buf
), 0);
122 // parse packet, set 'id', fill out 'ip'
124 MOADNSParser
mdp(string(buf
, len
));
126 cout
<<"Reply to question for qname='"<<mdp
.d_qname
.toString()<<"', qtype="<<DNSRecordContent::NumberToType(mdp
.d_qtype
)<<endl
;
127 cout
<<"Rcode: "<<mdp
.d_header
.rcode
<<", RD: "<<mdp
.d_header
.rd
<<", QR: "<<mdp
.d_header
.qr
;
128 cout
<<", TC: "<<mdp
.d_header
.tc
<<", AA: "<<mdp
.d_header
.aa
<<", opcode: "<<mdp
.d_header
.opcode
<<endl
;
130 dr
.rcode
= mdp
.d_header
.rcode
;
131 for(MOADNSParser::answers_t::const_iterator i
=mdp
.d_answers
.begin(); i
!=mdp
.d_answers
.end(); ++i
) {
132 if(i
->first
.d_place
== 1 && i
->first
.d_type
== mdp
.d_qtype
)
133 dr
.ips
.push_back(ComboAddress(i
->first
.d_content
->getZoneRepresentation()));
134 if(i
->first
.d_place
== 2 && i
->first
.d_type
== QType::SOA
) {
139 cout
<<i
->first
.d_place
-1<<"\t"<<i
->first
.d_name
.toString()<<"\tIN\t"<<DNSRecordContent::NumberToType(i
->first
.d_type
);
140 cout
<<"\t"<<i
->first
.d_ttl
<<"\t"<< i
->first
.d_content
->getZoneRepresentation()<<"\n";
144 id
= mdp
.d_header
.id
;
145 d_idqueue
.push_back(id
);
152 void deliverTimeout(const Identifier
& id
)
155 cout
<<"Timeout for id "<<id
<<endl
;
157 d_idqueue
.push_back(id
);
160 void deliverAnswer(TypedQuery
& domain
, const DNSResult
& dr
, unsigned int usec
)
162 (*d_acc
)(usec
/1000.0);
163 // if(usec > 1000000)
164 // cerr<<"Slow: "<<domain<<" ("<<usec/1000.0<<" msec)\n";
166 cout
<<domain
.name
<<"|"<<DNSRecordContent::NumberToType(domain
.type
)<<": ("<<usec
/1000.0<<"msec) rcode: "<<dr
.rcode
;
167 for(const ComboAddress
& ca
: dr
.ips
) {
168 cout
<<", "<<ca
.toString();
172 if(dr
.rcode
== RCode::NXDomain
) {
178 else if(dr
.ips
.empty() && dr
.seenauthsoa
)
180 else if(!dr
.ips
.empty())
183 if(!g_quiet
) cout
<<"UNKNOWN!! ^^"<<endl
;
187 unsigned int d_errors
, d_nxdomains
, d_nodatas
, d_oks
, d_unknowns
;
188 unsigned int d_receiveds
, d_receiveerrors
, d_senderrors
;
191 void usage(po::options_description
&desc
) {
192 cerr
<< "Usage: dnsbulktest [OPTION].. IPADDRESS PORTNUMBER [LIMIT]"<<endl
;
193 cerr
<< desc
<< "\n";
196 int main(int argc
, char** argv
)
199 po::options_description
desc("Allowed options");
201 ("help,h", "produce help message")
202 ("quiet,q", "be quiet about individual queries")
203 ("type,t", po::value
<string
>()->default_value("A"), "What type to query for")
204 ("envoutput,e", "write report in shell environment format")
205 ("version", "show the version number")
208 po::options_description alloptions
;
209 po::options_description
hidden("hidden options");
211 ("ip-address", po::value
<string
>(), "ip-address")
212 ("portnumber", po::value
<uint16_t>(), "portnumber")
213 ("limit", po::value
<uint32_t>()->default_value(0), "limit");
215 alloptions
.add(desc
).add(hidden
);
216 po::positional_options_description p
;
217 p
.add("ip-address", 1);
218 p
.add("portnumber", 1);
221 po::store(po::command_line_parser(argc
, argv
).options(alloptions
).positional(p
).run(), g_vm
);
224 if (g_vm
.count("help")) {
229 if (g_vm
.count("version")) {
230 cerr
<<"dnsbulktest "<<VERSION
<<endl
;
234 if(!g_vm
.count("portnumber")) {
235 cerr
<<"Fatal, need to specify ip-address and portnumber"<<endl
;
240 g_quiet
= g_vm
.count("quiet") > 0;
241 g_envoutput
= g_vm
.count("envoutput") > 0;
245 qtype
= DNSRecordContent::TypeToNumber(g_vm
["type"].as
<string
>());
247 catch(std::exception
& e
) {
248 cerr
<< e
.what() << endl
;
252 SendReceive
sr(g_vm
["ip-address"].as
<string
>(), g_vm
["portnumber"].as
<uint16_t>());
253 unsigned int limit
= g_vm
["limit"].as
<unsigned int>();
255 vector
<TypedQuery
> domains
;
257 Inflighter
<vector
<TypedQuery
>, SendReceive
> inflighter(domains
, sr
);
258 inflighter
.d_maxInFlight
= 1000;
259 inflighter
.d_timeoutSeconds
= 3;
260 inflighter
.d_burst
= 100;
263 pair
<string
, string
> split
;
264 string::size_type pos
;
265 while(stringfgets(stdin
, line
)) {
266 if(limit
&& domains
.size() >= limit
)
270 if(line
.empty() || line
[0] == '#')
272 split
=splitField(line
,',');
273 if (split
.second
.empty())
274 split
=splitField(line
,'\t');
275 if(!split
.second
.find('.')) // skip 'Hidden profile' in quantcast list.
277 pos
=split
.second
.find('/');
278 if(pos
!= string::npos
) // alexa has whole urls in the list now.
279 split
.second
.resize(pos
);
280 if(find_if(split
.second
.begin(), split
.second
.end(), isalpha
) == split
.second
.end())
282 continue; // this was an IP address
284 domains
.push_back(TypedQuery(split
.second
, qtype
));
285 domains
.push_back(TypedQuery("www."+split
.second
, qtype
));
287 cerr
<<"Read "<<domains
.size()<<" domains!"<<endl
;
288 random_shuffle(domains
.begin(), domains
.end());
290 boost::format
datafmt("%s %|20t|%+15s %|40t|%s %|60t|%+15s\n");
297 catch(std::exception
& e
) {
298 cerr
<<"Caught exception: "<<e
.what()<<endl
;
302 cerr
<< datafmt
% "Sending" % "" % "Receiving" % "";
303 cerr
<< datafmt
% " Queued " % domains
.size() % " Received" % sr
.d_receiveds
;
304 cerr
<< datafmt
% " Error -/-" % sr
.d_senderrors
% " Timeouts" % inflighter
.getTimeouts();
305 cerr
<< datafmt
% " " % "" % " Unexpected" % inflighter
.getUnexpecteds();
307 cerr
<< datafmt
% " Sent" % (domains
.size() - sr
.d_senderrors
) % " Total" % (sr
.d_receiveds
+ inflighter
.getTimeouts() + inflighter
.getUnexpecteds());
310 cerr
<< datafmt
% "DNS Status" % "" % "" % "";
311 cerr
<< datafmt
% " OK" % sr
.d_oks
% "" % "";
312 cerr
<< datafmt
% " Error" % sr
.d_errors
% "" % "";
313 cerr
<< datafmt
% " No Data" % sr
.d_nodatas
% "" % "";
314 cerr
<< datafmt
% " NXDOMAIN" % sr
.d_nxdomains
% "" % "";
315 cerr
<< datafmt
% " Unknowns" % sr
.d_unknowns
% "" % "";
316 cerr
<< datafmt
% "Answers" % (sr
.d_oks
+ sr
.d_errors
+ sr
.d_nodatas
+ sr
.d_nxdomains
+ sr
.d_unknowns
) % "" % "";
317 cerr
<< datafmt
% " Timeouts " % (inflighter
.getTimeouts()) % "" % "";
318 cerr
<< datafmt
% "Total " % (sr
.d_oks
+ sr
.d_errors
+ sr
.d_nodatas
+ sr
.d_nxdomains
+ sr
.d_unknowns
+ inflighter
.getTimeouts()) % "" % "";
321 cerr
<< "Mean response time: "<<mean(*sr
.d_acc
) << " msec"<<", median: "<<median(*sr
.d_acc
)<< " msec\n";
323 boost::format
statfmt("Time < %6.03f msec %|30t|%6.03f%% cumulative\n");
325 for (unsigned int i
= 0; i
< sr
.d_probs
.size(); ++i
) {
326 cerr
<< statfmt
% extended_p_square(*sr
.d_acc
)[i
] % (100*sr
.d_probs
[i
]);
330 cout
<<"DBT_QUEUED="<<domains
.size()<<endl
;
331 cout
<<"DBT_SENDERRORS="<<sr
.d_senderrors
<<endl
;
332 cout
<<"DBT_RECEIVED="<<sr
.d_receiveds
<<endl
;
333 cout
<<"DBT_TIMEOUTS="<<inflighter
.getTimeouts()<<endl
;
334 cout
<<"DBT_UNEXPECTEDS="<<inflighter
.getUnexpecteds()<<endl
;
335 cout
<<"DBT_OKPERCENTAGE="<<((float)sr
.d_oks
/domains
.size()*100)<<endl
;
336 cout
<<"DBT_OKPERCENTAGEINT="<<(int)((float)sr
.d_oks
/domains
.size()*100)<<endl
;
339 catch(PDNSException
& pe
)
341 cerr
<<"Fatal error: "<<pe
.reason
<<endl
;