]> git.ipfire.org Git - thirdparty/pdns.git/blob - pdns/dnsgram.cc
Merge pull request #4871 from pieterlexis/docs-fixes
[thirdparty/pdns.git] / pdns / dnsgram.cc
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 */
22 #define __FAVOR_BSD
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26 #include "statbag.hh"
27 #include "dnspcap.hh"
28 #include "dnsrecords.hh"
29 #include "dnsparser.hh"
30 #include <boost/tuple/tuple.hpp>
31 #include <boost/tuple/tuple_comparison.hpp>
32 #include <map>
33 #include <set>
34 #include <fstream>
35 #include <algorithm>
36 #include "anadns.hh"
37
38 #include "namespaces.hh"
39 #include "namespaces.hh"
40
41 StatBag S;
42
43 struct tm* pdns_localtime_r(const uint32_t* then, struct tm* tm)
44 {
45 time_t t = *then;
46
47 return localtime_r(&t, tm);
48 }
49
50 int32_t g_clientQuestions, g_clientResponses, g_serverQuestions, g_serverResponses, g_skipped;
51 struct pdns_timeval g_lastanswerTime, g_lastquestionTime;
52 void makeReport(const struct pdns_timeval& tv)
53 {
54 int64_t clientdiff = g_clientQuestions - g_clientResponses;
55 int64_t serverdiff = g_serverQuestions - g_serverResponses;
56
57 if(clientdiff > 1 && clientdiff > 0.02*g_clientQuestions) {
58 char tmp[80];
59 struct tm tm=*pdns_localtime_r(&tv.tv_sec, &tm);
60 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
61
62 cout << tmp << ": Resolver dropped too many questions ("
63 << g_clientQuestions <<" vs " << g_clientResponses << "), diff: " <<clientdiff<<endl;
64
65 tm=*pdns_localtime_r(&g_lastanswerTime.tv_sec, &tm);
66 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
67
68 cout<<"Last answer: "<<tmp<<"."<<g_lastanswerTime.tv_usec/1000000.0<<endl;
69
70 tm=*pdns_localtime_r(&g_lastquestionTime.tv_sec, &tm);
71 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
72
73 cout<<"Last question: "<<tmp<<"."<<g_lastquestionTime.tv_usec/1000000.0<<endl;
74 }
75
76 if(serverdiff > 1 && serverdiff > 0.02*g_serverQuestions) {
77 char tmp[80];
78 struct tm tm=*pdns_localtime_r(&tv.tv_sec, &tm);
79 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
80
81 cout << tmp << ": Auth server dropped too many questions ("
82 << g_serverQuestions <<" vs " << g_serverResponses << "), diff: " <<serverdiff<<endl;
83
84 tm=*pdns_localtime_r(&g_lastanswerTime.tv_sec, &tm);
85 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
86
87 cout<<"Last answer: "<<tmp<<"."<<g_lastanswerTime.tv_usec/1000000.0<<endl;
88
89 tm=*pdns_localtime_r(&g_lastquestionTime.tv_sec, &tm);
90 strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
91
92 cout<<"Last question: "<<tmp<<"."<<g_lastquestionTime.tv_usec/1000000.0<<endl;
93 }
94 // cout <<"Recursive questions: "<<g_clientQuestions<<", recursive responses: " << g_clientResponses<<
95 // ", server questions: "<<g_serverQuestions<<", server responses: "<<g_serverResponses<<endl;
96
97
98 // cerr << tv.tv_sec << " " <<g_clientQuestions<<" " << g_clientResponses<< " "<<g_serverQuestions<<" "<<g_serverResponses<<" "<<g_skipped<<endl;
99 g_clientQuestions=g_clientResponses=g_serverQuestions=g_serverResponses=0;
100 g_skipped=0;
101 }
102
103 void usage() {
104 cerr<<"syntax: dnsgram INFILE..."<<endl;
105 }
106
107 int main(int argc, char** argv)
108 try
109 {
110 // Parse possible options
111 if (argc == 1) {
112 usage();
113 return EXIT_SUCCESS;
114 }
115
116 for(int n=1 ; n < argc; ++n) {
117 if ((string) argv[n] == "--help") {
118 usage();
119 return EXIT_SUCCESS;
120 }
121
122 if ((string) argv[n] == "--version") {
123 cerr<<"dnsgram "<<VERSION<<endl;
124 return EXIT_SUCCESS;
125 }
126 }
127
128 reportAllTypes();
129 for(int n=1 ; n < argc; ++n) {
130 cout<<argv[n]<<endl;
131 unsigned int parseErrors=0, totalQueries=0, skipped=0;
132 PcapPacketReader pr(argv[n]);
133 // PcapPacketWriter pw(argv[n]+string(".out"), pr);
134 /* four sorts of packets:
135 "rd": question from a client pc
136 "rd qr": answer to a client pc
137 "": question from the resolver
138 "qr": answer to the resolver */
139
140 /* what are interesting events to note? */
141 /* we measure every 60 seconds, each interval with 10% less answers than questions is interesting */
142 /* report chunked */
143
144 struct pdns_timeval lastreport;
145
146 typedef set<pair<DNSName, uint16_t> > queries_t;
147 queries_t questions, answers;
148
149 // unsigned int count = 50000;
150
151 map<pair<DNSName, uint16_t>, int> counts;
152
153 map<double, int> rdqcounts, rdacounts;
154
155 while(pr.getUDPPacket()) {
156 if((ntohs(pr.d_udp->uh_dport)==5300 || ntohs(pr.d_udp->uh_sport)==5300 ||
157 ntohs(pr.d_udp->uh_dport)==53 || ntohs(pr.d_udp->uh_sport)==53) &&
158 pr.d_len > 12) {
159 try {
160 MOADNSParser mdp(false, (const char*)pr.d_payload, pr.d_len);
161
162 if(lastreport.tv_sec == 0) {
163 lastreport = pr.d_pheader.ts;
164 }
165
166 if(mdp.d_header.rd && !mdp.d_header.qr) {
167 rdqcounts[pr.d_pheader.ts.tv_sec + 0.01*(pr.d_pheader.ts.tv_usec/10000)]++;
168 g_lastquestionTime=pr.d_pheader.ts;
169 g_clientQuestions++;
170 totalQueries++;
171 counts[make_pair(mdp.d_qname, mdp.d_qtype)]++;
172 questions.insert(make_pair(mdp.d_qname, mdp.d_qtype));
173 }
174 else if(mdp.d_header.rd && mdp.d_header.qr) {
175 rdacounts[pr.d_pheader.ts.tv_sec + 0.01*(pr.d_pheader.ts.tv_usec/10000)]++;
176 g_lastanswerTime=pr.d_pheader.ts;
177 g_clientResponses++;
178 answers.insert(make_pair(mdp.d_qname, mdp.d_qtype));
179 }
180 else if(!mdp.d_header.rd && !mdp.d_header.qr) {
181 g_lastquestionTime=pr.d_pheader.ts;
182 g_serverQuestions++;
183 counts[make_pair(mdp.d_qname, mdp.d_qtype)]++;
184 questions.insert(make_pair(mdp.d_qname, mdp.d_qtype));
185 totalQueries++;
186 }
187 else if(!mdp.d_header.rd && mdp.d_header.qr) {
188 answers.insert(make_pair(mdp.d_qname, mdp.d_qtype));
189 g_serverResponses++;
190 }
191
192 if(pr.d_pheader.ts.tv_sec - lastreport.tv_sec >= 1) {
193 makeReport(pr.d_pheader.ts);
194 lastreport = pr.d_pheader.ts;
195 }
196 }
197 catch(MOADNSException& mde) {
198 // cerr<<"error parsing packet: "<<mde.what()<<endl;
199 parseErrors++;
200 continue;
201 }
202 catch(std::exception& e) {
203 cerr << e.what() << endl;
204 continue;
205 }
206 }
207 }
208
209 map<double, pair<int, int>> splot;
210
211 for(auto& a : rdqcounts) {
212 splot[a.first].first = a.second;
213 }
214 for(auto& a : rdacounts) {
215 splot[a.first].second = a.second;
216 }
217
218 cerr<<"Writing out sub-second rd query/response stats to ./rdqaplot"<<endl;
219 ofstream plot("rdqaplot");
220 plot<<std::fixed;
221 for(auto& a : splot) {
222 plot << a.first<<"\t"<<a.second.first<<"\t"<<a.second.second<<endl;
223 }
224 cerr<<"Parse errors: "<<parseErrors<<", total queries: "<<totalQueries<<endl;
225 typedef vector<queries_t::value_type> diff_t;
226 diff_t diff;
227 set_difference(questions.begin(), questions.end(), answers.begin(), answers.end(), back_inserter(diff));
228 cerr<<questions.size()<<" different rd questions, "<< answers.size()<<" different rd answers, diff: "<<diff.size()<<endl;
229 cerr<<skipped<<" skipped\n";
230
231 cerr<<"Generating 'failed' file with failed queries and counts\n";
232 ofstream failed("failed");
233 failed<<"name\ttype\tnumber\n";
234 for(diff_t::const_iterator i = diff.begin(); i != diff.end() ; ++i) {
235 failed << i->first << "\t" << DNSRecordContent::NumberToType(i->second) << "\t"<< counts[make_pair(i->first, i->second)]<<"\n";
236 }
237
238 diff.clear();
239
240 set_difference(answers.begin(), answers.end(), questions.begin(), questions.end(), back_inserter(diff));
241 cerr<<diff.size()<<" answers w/o questions\n";
242
243 cerr<<"Generating 'succeeded' file with all unique answers and counts\n";
244 ofstream succeeded("succeeded");
245 succeeded<<"name\ttype\tnumber\n";
246 for(queries_t::const_iterator i = answers.begin(); i != answers.end() ; ++i) {
247 succeeded << i->first << "\t" <<DNSRecordContent::NumberToType(i->second) << "\t" << counts[make_pair(i->first, i->second)]<<"\n";
248 }
249 }
250 }
251 catch(std::exception& e)
252 {
253 cerr<<"Fatal: "<<e.what()<<endl;
254 }