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