]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsgram.cc
Merge pull request #4061 from mind04/various
[thirdparty/pdns.git] / pdns / dnsgram.cc
1 #define __FAVOR_BSD
2 #ifdef HAVE_CONFIG_H
3 #include "config.h"
4 #endif
5 #include "statbag.hh"
6 #include "dnspcap.hh"
7 #include "dnsrecords.hh"
8 #include "dnsparser.hh"
9 #include <boost/tuple/tuple.hpp>
10 #include <boost/tuple/tuple_comparison.hpp>
11 #include <map>
12 #include <set>
13 #include <fstream>
14 #include <algorithm>
15 #include "anadns.hh"
16
17 #include "namespaces.hh"
18 #include "namespaces.hh"
19
20 StatBag S;
21
22 struct tm* pdns_localtime_r(const uint32_t* then, struct tm* tm)
23 {
24 time_t t = *then;
25
26 return localtime_r(&t, tm);
27 }
28
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)
32 {
33 int64_t clientdiff = g_clientQuestions - g_clientResponses;
34 int64_t serverdiff = g_serverQuestions - g_serverResponses;
35
36 if(clientdiff > 1 && clientdiff > 0.02*g_clientQuestions) {
37 char tmp[80];
38 struct tm tm=*pdns_localtime_r(&tv.tv_sec, &tm);
39 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
40
41 cout << tmp << ": Resolver dropped too many questions ("
42 << g_clientQuestions <<" vs " << g_clientResponses << "), diff: " <<clientdiff<<endl;
43
44 tm=*pdns_localtime_r(&g_lastanswerTime.tv_sec, &tm);
45 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
46
47 cout<<"Last answer: "<<tmp<<"."<<g_lastanswerTime.tv_usec/1000000.0<<endl;
48
49 tm=*pdns_localtime_r(&g_lastquestionTime.tv_sec, &tm);
50 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
51
52 cout<<"Last question: "<<tmp<<"."<<g_lastquestionTime.tv_usec/1000000.0<<endl;
53 }
54
55 if(serverdiff > 1 && serverdiff > 0.02*g_serverQuestions) {
56 char tmp[80];
57 struct tm tm=*pdns_localtime_r(&tv.tv_sec, &tm);
58 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
59
60 cout << tmp << ": Auth server dropped too many questions ("
61 << g_serverQuestions <<" vs " << g_serverResponses << "), diff: " <<serverdiff<<endl;
62
63 tm=*pdns_localtime_r(&g_lastanswerTime.tv_sec, &tm);
64 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
65
66 cout<<"Last answer: "<<tmp<<"."<<g_lastanswerTime.tv_usec/1000000.0<<endl;
67
68 tm=*pdns_localtime_r(&g_lastquestionTime.tv_sec, &tm);
69 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
70
71 cout<<"Last question: "<<tmp<<"."<<g_lastquestionTime.tv_usec/1000000.0<<endl;
72 }
73 // cout <<"Recursive questions: "<<g_clientQuestions<<", recursive responses: " << g_clientResponses<<
74 // ", server questions: "<<g_serverQuestions<<", server responses: "<<g_serverResponses<<endl;
75
76
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;
79 g_skipped=0;
80 }
81
82 void usage() {
83 cerr<<"syntax: dnsgram INFILE..."<<endl;
84 }
85
86 int main(int argc, char** argv)
87 try
88 {
89 // Parse possible options
90 if (argc == 1) {
91 usage();
92 return EXIT_SUCCESS;
93 }
94
95 for(int n=1 ; n < argc; ++n) {
96 if ((string) argv[n] == "--help") {
97 usage();
98 return EXIT_SUCCESS;
99 }
100
101 if ((string) argv[n] == "--version") {
102 cerr<<"dnsgram "<<VERSION<<endl;
103 return EXIT_SUCCESS;
104 }
105 }
106
107 reportAllTypes();
108 for(int n=1 ; n < argc; ++n) {
109 cout<<argv[n]<<endl;
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 */
118
119 /* what are interesting events to note? */
120 /* we measure every 60 seconds, each interval with 10% less answers than questions is interesting */
121 /* report chunked */
122
123 struct pdns_timeval lastreport;
124
125 typedef set<pair<DNSName, uint16_t> > queries_t;
126 queries_t questions, answers;
127
128 // unsigned int count = 50000;
129
130 map<pair<DNSName, uint16_t>, int> counts;
131
132 map<double, int> rdqcounts, rdacounts;
133
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) &&
137 pr.d_len > 12) {
138 try {
139 MOADNSParser mdp((const char*)pr.d_payload, pr.d_len);
140
141 if(lastreport.tv_sec == 0) {
142 lastreport = pr.d_pheader.ts;
143 }
144
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;
148 g_clientQuestions++;
149 totalQueries++;
150 counts[make_pair(mdp.d_qname, mdp.d_qtype)]++;
151 questions.insert(make_pair(mdp.d_qname, mdp.d_qtype));
152 }
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;
156 g_clientResponses++;
157 answers.insert(make_pair(mdp.d_qname, mdp.d_qtype));
158 }
159 else if(!mdp.d_header.rd && !mdp.d_header.qr) {
160 g_lastquestionTime=pr.d_pheader.ts;
161 g_serverQuestions++;
162 counts[make_pair(mdp.d_qname, mdp.d_qtype)]++;
163 questions.insert(make_pair(mdp.d_qname, mdp.d_qtype));
164 totalQueries++;
165 }
166 else if(!mdp.d_header.rd && mdp.d_header.qr) {
167 answers.insert(make_pair(mdp.d_qname, mdp.d_qtype));
168 g_serverResponses++;
169 }
170
171 if(pr.d_pheader.ts.tv_sec - lastreport.tv_sec >= 1) {
172 makeReport(pr.d_pheader.ts);
173 lastreport = pr.d_pheader.ts;
174 }
175 }
176 catch(MOADNSException& mde) {
177 // cerr<<"error parsing packet: "<<mde.what()<<endl;
178 parseErrors++;
179 continue;
180 }
181 catch(std::exception& e) {
182 cerr << e.what() << endl;
183 continue;
184 }
185 }
186 }
187
188 map<double, pair<int, int>> splot;
189
190 for(auto& a : rdqcounts) {
191 splot[a.first].first = a.second;
192 }
193 for(auto& a : rdacounts) {
194 splot[a.first].second = a.second;
195 }
196
197 cerr<<"Writing out sub-second rd query/response stats to ./rdqaplot"<<endl;
198 ofstream plot("rdqaplot");
199 plot<<std::fixed;
200 for(auto& a : splot) {
201 plot << a.first<<"\t"<<a.second.first<<"\t"<<a.second.second<<endl;
202 }
203 cerr<<"Parse errors: "<<parseErrors<<", total queries: "<<totalQueries<<endl;
204 typedef vector<queries_t::value_type> diff_t;
205 diff_t diff;
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";
209
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.toString() << "\t" << DNSRecordContent::NumberToType(i->second) << "\t"<< counts[make_pair(i->first, i->second)]<<"\n";
215 }
216
217 diff.clear();
218
219 set_difference(answers.begin(), answers.end(), questions.begin(), questions.end(), back_inserter(diff));
220 cerr<<diff.size()<<" answers w/o questions\n";
221
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.toString() << "\t" <<DNSRecordContent::NumberToType(i->second) << "\t" << counts[make_pair(i->first, i->second)]<<"\n";
227 }
228 }
229 }
230 catch(std::exception& e)
231 {
232 cerr<<"Fatal: "<<e.what()<<endl;
233 }