7 #include "dnsrecords.hh"
8 #include "dnsparser.hh"
9 #include <boost/tuple/tuple.hpp>
10 #include <boost/tuple/tuple_comparison.hpp>
17 #include "namespaces.hh"
18 #include "namespaces.hh"
22 struct tm
* pdns_localtime_r(const uint32_t* then
, struct tm
* tm
)
26 return localtime_r(&t
, tm
);
29 int32_t g_clientQuestions
, g_clientResponses
, g_serverQuestions
, g_serverResponses
, g_skipped
;
30 struct pdns_timeval g_lastanswerTime
, g_lastquestionTime
;
31 void makeReport(const struct pdns_timeval
& tv
)
33 int64_t clientdiff
= g_clientQuestions
- g_clientResponses
;
34 int64_t serverdiff
= g_serverQuestions
- g_serverResponses
;
36 if(clientdiff
> 1 && clientdiff
> 0.02*g_clientQuestions
) {
38 struct tm tm
=*pdns_localtime_r(&tv
.tv_sec
, &tm
);
39 strftime(tmp
, sizeof(tmp
) - 1, "%F %H:%M:%S", &tm
);
41 cout
<< tmp
<< ": Resolver dropped too many questions ("
42 << g_clientQuestions
<<" vs " << g_clientResponses
<< "), diff: " <<clientdiff
<<endl
;
44 tm
=*pdns_localtime_r(&g_lastanswerTime
.tv_sec
, &tm
);
45 strftime(tmp
, sizeof(tmp
) - 1, "%F %H:%M:%S", &tm
);
47 cout
<<"Last answer: "<<tmp
<<"."<<g_lastanswerTime
.tv_usec
/1000000.0<<endl
;
49 tm
=*pdns_localtime_r(&g_lastquestionTime
.tv_sec
, &tm
);
50 strftime(tmp
, sizeof(tmp
) - 1, "%F %H:%M:%S", &tm
);
52 cout
<<"Last question: "<<tmp
<<"."<<g_lastquestionTime
.tv_usec
/1000000.0<<endl
;
55 if(serverdiff
> 1 && serverdiff
> 0.02*g_serverQuestions
) {
57 struct tm tm
=*pdns_localtime_r(&tv
.tv_sec
, &tm
);
58 strftime(tmp
, sizeof(tmp
) - 1, "%F %H:%M:%S", &tm
);
60 cout
<< tmp
<< ": Auth server dropped too many questions ("
61 << g_serverQuestions
<<" vs " << g_serverResponses
<< "), diff: " <<serverdiff
<<endl
;
63 tm
=*pdns_localtime_r(&g_lastanswerTime
.tv_sec
, &tm
);
64 strftime(tmp
, sizeof(tmp
) - 1, "%F %H:%M:%S", &tm
);
66 cout
<<"Last answer: "<<tmp
<<"."<<g_lastanswerTime
.tv_usec
/1000000.0<<endl
;
68 tm
=*pdns_localtime_r(&g_lastquestionTime
.tv_sec
, &tm
);
69 strftime(tmp
, sizeof(tmp
) - 1, "%F %H:%M:%S", &tm
);
71 cout
<<"Last question: "<<tmp
<<"."<<g_lastquestionTime
.tv_usec
/1000000.0<<endl
;
73 // cout <<"Recursive questions: "<<g_clientQuestions<<", recursive responses: " << g_clientResponses<<
74 // ", server questions: "<<g_serverQuestions<<", server responses: "<<g_serverResponses<<endl;
77 // cerr << tv.tv_sec << " " <<g_clientQuestions<<" " << g_clientResponses<< " "<<g_serverQuestions<<" "<<g_serverResponses<<" "<<g_skipped<<endl;
78 g_clientQuestions
=g_clientResponses
=g_serverQuestions
=g_serverResponses
=0;
83 cerr
<<"syntax: dnsgram INFILE..."<<endl
;
86 int main(int argc
, char** argv
)
89 // Parse possible options
95 for(int n
=1 ; n
< argc
; ++n
) {
96 if ((string
) argv
[n
] == "--help") {
101 if ((string
) argv
[n
] == "--version") {
102 cerr
<<"dnsgram "<<VERSION
<<endl
;
108 for(int n
=1 ; n
< argc
; ++n
) {
110 unsigned int parseErrors
=0, totalQueries
=0, skipped
=0;
111 PcapPacketReader
pr(argv
[n
]);
112 // PcapPacketWriter pw(argv[n]+string(".out"), pr);
113 /* four sorts of packets:
114 "rd": question from a client pc
115 "rd qr": answer to a client pc
116 "": question from the resolver
117 "qr": answer to the resolver */
119 /* what are interesting events to note? */
120 /* we measure every 60 seconds, each interval with 10% less answers than questions is interesting */
123 struct pdns_timeval lastreport
;
125 typedef set
<pair
<DNSName
, uint16_t> > queries_t
;
126 queries_t questions
, answers
;
128 // unsigned int count = 50000;
130 map
<pair
<DNSName
, uint16_t>, int> counts
;
132 map
<double, int> rdqcounts
, rdacounts
;
134 while(pr
.getUDPPacket()) {
135 if((ntohs(pr
.d_udp
->uh_dport
)==5300 || ntohs(pr
.d_udp
->uh_sport
)==5300 ||
136 ntohs(pr
.d_udp
->uh_dport
)==53 || ntohs(pr
.d_udp
->uh_sport
)==53) &&
139 MOADNSParser
mdp((const char*)pr
.d_payload
, pr
.d_len
);
141 if(lastreport
.tv_sec
== 0) {
142 lastreport
= pr
.d_pheader
.ts
;
145 if(mdp
.d_header
.rd
&& !mdp
.d_header
.qr
) {
146 rdqcounts
[pr
.d_pheader
.ts
.tv_sec
+ 0.01*(pr
.d_pheader
.ts
.tv_usec
/10000)]++;
147 g_lastquestionTime
=pr
.d_pheader
.ts
;
150 counts
[make_pair(mdp
.d_qname
, mdp
.d_qtype
)]++;
151 questions
.insert(make_pair(mdp
.d_qname
, mdp
.d_qtype
));
153 else if(mdp
.d_header
.rd
&& mdp
.d_header
.qr
) {
154 rdacounts
[pr
.d_pheader
.ts
.tv_sec
+ 0.01*(pr
.d_pheader
.ts
.tv_usec
/10000)]++;
155 g_lastanswerTime
=pr
.d_pheader
.ts
;
157 answers
.insert(make_pair(mdp
.d_qname
, mdp
.d_qtype
));
159 else if(!mdp
.d_header
.rd
&& !mdp
.d_header
.qr
) {
160 g_lastquestionTime
=pr
.d_pheader
.ts
;
162 counts
[make_pair(mdp
.d_qname
, mdp
.d_qtype
)]++;
163 questions
.insert(make_pair(mdp
.d_qname
, mdp
.d_qtype
));
166 else if(!mdp
.d_header
.rd
&& mdp
.d_header
.qr
) {
167 answers
.insert(make_pair(mdp
.d_qname
, mdp
.d_qtype
));
171 if(pr
.d_pheader
.ts
.tv_sec
- lastreport
.tv_sec
>= 1) {
172 makeReport(pr
.d_pheader
.ts
);
173 lastreport
= pr
.d_pheader
.ts
;
176 catch(MOADNSException
& mde
) {
177 // cerr<<"error parsing packet: "<<mde.what()<<endl;
181 catch(std::exception
& e
) {
182 cerr
<< e
.what() << endl
;
188 map
<double, pair
<int, int>> splot
;
190 for(auto& a
: rdqcounts
) {
191 splot
[a
.first
].first
= a
.second
;
193 for(auto& a
: rdacounts
) {
194 splot
[a
.first
].second
= a
.second
;
197 cerr
<<"Writing out sub-second rd query/response stats to ./rdqaplot"<<endl
;
198 ofstream
plot("rdqaplot");
200 for(auto& a
: splot
) {
201 plot
<< a
.first
<<"\t"<<a
.second
.first
<<"\t"<<a
.second
.second
<<endl
;
203 cerr
<<"Parse errors: "<<parseErrors
<<", total queries: "<<totalQueries
<<endl
;
204 typedef vector
<queries_t::value_type
> diff_t
;
206 set_difference(questions
.begin(), questions
.end(), answers
.begin(), answers
.end(), back_inserter(diff
));
207 cerr
<<questions
.size()<<" different rd questions, "<< answers
.size()<<" different rd answers, diff: "<<diff
.size()<<endl
;
208 cerr
<<skipped
<<" skipped\n";
210 cerr
<<"Generating 'failed' file with failed queries and counts\n";
211 ofstream
failed("failed");
212 failed
<<"name\ttype\tnumber\n";
213 for(diff_t::const_iterator i
= diff
.begin(); i
!= diff
.end() ; ++i
) {
214 failed
<< i
->first
<< "\t" << DNSRecordContent::NumberToType(i
->second
) << "\t"<< counts
[make_pair(i
->first
, i
->second
)]<<"\n";
219 set_difference(answers
.begin(), answers
.end(), questions
.begin(), questions
.end(), back_inserter(diff
));
220 cerr
<<diff
.size()<<" answers w/o questions\n";
222 cerr
<<"Generating 'succeeded' file with all unique answers and counts\n";
223 ofstream
succeeded("succeeded");
224 succeeded
<<"name\ttype\tnumber\n";
225 for(queries_t::const_iterator i
= answers
.begin(); i
!= answers
.end() ; ++i
) {
226 succeeded
<< i
->first
<< "\t" <<DNSRecordContent::NumberToType(i
->second
) << "\t" << counts
[make_pair(i
->first
, i
->second
)]<<"\n";
230 catch(std::exception
& e
)
232 cerr
<<"Fatal: "<<e
.what()<<endl
;