]>
Commit | Line | Data |
---|---|---|
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 | |
41 | StatBag S; | |
42 | ||
b6c31ee0 BH |
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 | ||
d74f4d55 | 50 | int32_t g_clientQuestions, g_clientResponses, g_serverQuestions, g_serverResponses, g_skipped; |
b6c31ee0 BH |
51 | struct pdns_timeval g_lastanswerTime, g_lastquestionTime; |
52 | void makeReport(const struct pdns_timeval& tv) | |
a9b1aa91 BH |
53 | { |
54 | int64_t clientdiff = g_clientQuestions - g_clientResponses; | |
d74f4d55 BH |
55 | int64_t serverdiff = g_serverQuestions - g_serverResponses; |
56 | ||
a0381aff | 57 | if(clientdiff > 1 && clientdiff > 0.02*g_clientQuestions) { |
a9b1aa91 | 58 | char tmp[80]; |
b6c31ee0 | 59 | struct tm tm=*pdns_localtime_r(&tv.tv_sec, &tm); |
a9b1aa91 BH |
60 | strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm); |
61 | ||
62 | cout << tmp << ": Resolver dropped too many questions (" | |
4957a608 | 63 | << g_clientQuestions <<" vs " << g_clientResponses << "), diff: " <<clientdiff<<endl; |
a9b1aa91 | 64 | |
b6c31ee0 | 65 | tm=*pdns_localtime_r(&g_lastanswerTime.tv_sec, &tm); |
a9b1aa91 BH |
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 | ||
b6c31ee0 | 70 | tm=*pdns_localtime_r(&g_lastquestionTime.tv_sec, &tm); |
a9b1aa91 BH |
71 | strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm); |
72 | ||
73 | cout<<"Last question: "<<tmp<<"."<<g_lastquestionTime.tv_usec/1000000.0<<endl; | |
d74f4d55 | 74 | } |
a9b1aa91 | 75 | |
a0381aff | 76 | if(serverdiff > 1 && serverdiff > 0.02*g_serverQuestions) { |
d74f4d55 | 77 | char tmp[80]; |
b6c31ee0 | 78 | struct tm tm=*pdns_localtime_r(&tv.tv_sec, &tm); |
d74f4d55 BH |
79 | strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm); |
80 | ||
81 | cout << tmp << ": Auth server dropped too many questions (" | |
4957a608 | 82 | << g_serverQuestions <<" vs " << g_serverResponses << "), diff: " <<serverdiff<<endl; |
a9b1aa91 | 83 | |
b6c31ee0 | 84 | tm=*pdns_localtime_r(&g_lastanswerTime.tv_sec, &tm); |
d74f4d55 BH |
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 | ||
b6c31ee0 | 89 | tm=*pdns_localtime_r(&g_lastquestionTime.tv_sec, &tm); |
d74f4d55 BH |
90 | strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm); |
91 | ||
92 | cout<<"Last question: "<<tmp<<"."<<g_lastquestionTime.tv_usec/1000000.0<<endl; | |
a9b1aa91 | 93 | } |
d74f4d55 BH |
94 | // cout <<"Recursive questions: "<<g_clientQuestions<<", recursive responses: " << g_clientResponses<< |
95 | // ", server questions: "<<g_serverQuestions<<", server responses: "<<g_serverResponses<<endl; | |
96 | ||
97 | ||
97b1caa0 | 98 | // cerr << tv.tv_sec << " " <<g_clientQuestions<<" " << g_clientResponses<< " "<<g_serverQuestions<<" "<<g_serverResponses<<" "<<g_skipped<<endl; |
a9b1aa91 | 99 | g_clientQuestions=g_clientResponses=g_serverQuestions=g_serverResponses=0; |
d74f4d55 | 100 | g_skipped=0; |
a9b1aa91 BH |
101 | } |
102 | ||
7f6996e3 PL |
103 | void usage() { |
104 | cerr<<"syntax: dnsgram INFILE..."<<endl; | |
105 | } | |
a9b1aa91 BH |
106 | |
107 | int main(int argc, char** argv) | |
108 | try | |
109 | { | |
7f6996e3 PL |
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 | ||
649528b6 | 128 | reportAllTypes(); |
a9b1aa91 BH |
129 | for(int n=1 ; n < argc; ++n) { |
130 | cout<<argv[n]<<endl; | |
d74f4d55 | 131 | unsigned int parseErrors=0, totalQueries=0, skipped=0; |
a9b1aa91 | 132 | PcapPacketReader pr(argv[n]); |
97b1caa0 | 133 | // PcapPacketWriter pw(argv[n]+string(".out"), pr); |
a9b1aa91 BH |
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 | ||
9814a674 | 144 | struct pdns_timeval lastreport; |
a9b1aa91 | 145 | |
af6406f5 | 146 | typedef set<pair<DNSName, uint16_t> > queries_t; |
d74f4d55 BH |
147 | queries_t questions, answers; |
148 | ||
97b1caa0 | 149 | // unsigned int count = 50000; |
438a98f8 | 150 | |
af6406f5 | 151 | map<pair<DNSName, uint16_t>, int> counts; |
d74f4d55 | 152 | |
a0381aff | 153 | map<double, int> rdqcounts, rdacounts; |
154 | ||
a9b1aa91 BH |
155 | while(pr.getUDPPacket()) { |
156 | if((ntohs(pr.d_udp->uh_dport)==5300 || ntohs(pr.d_udp->uh_sport)==5300 || | |
4957a608 BH |
157 | ntohs(pr.d_udp->uh_dport)==53 || ntohs(pr.d_udp->uh_sport)==53) && |
158 | pr.d_len > 12) { | |
159 | try { | |
27c0050c | 160 | MOADNSParser mdp(false, (const char*)pr.d_payload, pr.d_len); |
4957a608 BH |
161 | |
162 | if(lastreport.tv_sec == 0) { | |
163 | lastreport = pr.d_pheader.ts; | |
164 | } | |
4957a608 BH |
165 | |
166 | if(mdp.d_header.rd && !mdp.d_header.qr) { | |
a0381aff | 167 | rdqcounts[pr.d_pheader.ts.tv_sec + 0.01*(pr.d_pheader.ts.tv_usec/10000)]++; |
4957a608 BH |
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) { | |
a0381aff | 175 | rdacounts[pr.d_pheader.ts.tv_sec + 0.01*(pr.d_pheader.ts.tv_usec/10000)]++; |
4957a608 BH |
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 | ||
a0381aff | 192 | if(pr.d_pheader.ts.tv_sec - lastreport.tv_sec >= 1) { |
4957a608 BH |
193 | makeReport(pr.d_pheader.ts); |
194 | lastreport = pr.d_pheader.ts; | |
eda307fc | 195 | } |
4957a608 | 196 | } |
16ce7f18 | 197 | catch(const MOADNSException &mde) { |
232f0877 | 198 | // cerr<<"error parsing packet: "<<mde.what()<<endl; |
4957a608 BH |
199 | parseErrors++; |
200 | continue; | |
201 | } | |
202 | catch(std::exception& e) { | |
203 | cerr << e.what() << endl; | |
204 | continue; | |
205 | } | |
a9b1aa91 | 206 | } |
a0381aff | 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 | } | |
d74f4d55 | 217 | |
a0381aff | 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; | |
d74f4d55 BH |
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"; | |
97b1caa0 | 230 | |
97b1caa0 | 231 | cerr<<"Generating 'failed' file with failed queries and counts\n"; |
d74f4d55 | 232 | ofstream failed("failed"); |
eda307fc | 233 | failed<<"name\ttype\tnumber\n"; |
d74f4d55 | 234 | for(diff_t::const_iterator i = diff.begin(); i != diff.end() ; ++i) { |
7bd81806 | 235 | failed << i->first << "\t" << DNSRecordContent::NumberToType(i->second) << "\t"<< counts[make_pair(i->first, i->second)]<<"\n"; |
d74f4d55 BH |
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 | ||
eda307fc | 243 | cerr<<"Generating 'succeeded' file with all unique answers and counts\n"; |
d74f4d55 | 244 | ofstream succeeded("succeeded"); |
eda307fc | 245 | succeeded<<"name\ttype\tnumber\n"; |
d74f4d55 | 246 | for(queries_t::const_iterator i = answers.begin(); i != answers.end() ; ++i) { |
7bd81806 | 247 | succeeded << i->first << "\t" <<DNSRecordContent::NumberToType(i->second) << "\t" << counts[make_pair(i->first, i->second)]<<"\n"; |
a9b1aa91 BH |
248 | } |
249 | } | |
250 | } | |
adc10f99 | 251 | catch(std::exception& e) |
a9b1aa91 BH |
252 | { |
253 | cerr<<"Fatal: "<<e.what()<<endl; | |
254 | } |