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