| 1 | #define __FAVOR_BSD |
|---|
| 2 | #include "statbag.hh" |
|---|
| 3 | #include "dnspcap.hh" |
|---|
| 4 | #include "dnsparser.hh" |
|---|
| 5 | #include <boost/tuple/tuple.hpp> |
|---|
| 6 | #include <boost/tuple/tuple_comparison.hpp> |
|---|
| 7 | #include <boost/algorithm/string.hpp> |
|---|
| 8 | #include <map> |
|---|
| 9 | #include <set> |
|---|
| 10 | #include <fstream> |
|---|
| 11 | #include <algorithm> |
|---|
| 12 | #include "anadns.hh" |
|---|
| 13 | |
|---|
| 14 | #include "namespaces.hh" |
|---|
| 15 | using namespace std; |
|---|
| 16 | |
|---|
| 17 | StatBag S; |
|---|
| 18 | |
|---|
| 19 | struct tm* pdns_localtime_r(const uint32_t* then, struct tm* tm) |
|---|
| 20 | { |
|---|
| 21 | time_t t = *then; |
|---|
| 22 | |
|---|
| 23 | return localtime_r(&t, tm); |
|---|
| 24 | } |
|---|
| 25 | |
|---|
| 26 | int32_t g_clientQuestions, g_clientResponses, g_serverQuestions, g_serverResponses, g_skipped; |
|---|
| 27 | struct pdns_timeval g_lastanswerTime, g_lastquestionTime; |
|---|
| 28 | void makeReport(const struct pdns_timeval& tv) |
|---|
| 29 | { |
|---|
| 30 | int64_t clientdiff = g_clientQuestions - g_clientResponses; |
|---|
| 31 | int64_t serverdiff = g_serverQuestions - g_serverResponses; |
|---|
| 32 | |
|---|
| 33 | if(clientdiff > 5 && clientdiff > 0.02*g_clientQuestions) { |
|---|
| 34 | char tmp[80]; |
|---|
| 35 | struct tm tm=*pdns_localtime_r(&tv.tv_sec, &tm); |
|---|
| 36 | strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm); |
|---|
| 37 | |
|---|
| 38 | cout << tmp << ": Resolver dropped too many questions (" |
|---|
| 39 | << g_clientQuestions <<" vs " << g_clientResponses << "), diff: " <<clientdiff<<endl; |
|---|
| 40 | |
|---|
| 41 | tm=*pdns_localtime_r(&g_lastanswerTime.tv_sec, &tm); |
|---|
| 42 | strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm); |
|---|
| 43 | |
|---|
| 44 | cout<<"Last answer: "<<tmp<<"."<<g_lastanswerTime.tv_usec/1000000.0<<endl; |
|---|
| 45 | |
|---|
| 46 | tm=*pdns_localtime_r(&g_lastquestionTime.tv_sec, &tm); |
|---|
| 47 | strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm); |
|---|
| 48 | |
|---|
| 49 | cout<<"Last question: "<<tmp<<"."<<g_lastquestionTime.tv_usec/1000000.0<<endl; |
|---|
| 50 | } |
|---|
| 51 | |
|---|
| 52 | if(serverdiff > 5 && serverdiff > 0.02*g_serverQuestions) { |
|---|
| 53 | char tmp[80]; |
|---|
| 54 | struct tm tm=*pdns_localtime_r(&tv.tv_sec, &tm); |
|---|
| 55 | strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm); |
|---|
| 56 | |
|---|
| 57 | cout << tmp << ": Auth server dropped too many questions (" |
|---|
| 58 | << g_serverQuestions <<" vs " << g_serverResponses << "), diff: " <<serverdiff<<endl; |
|---|
| 59 | |
|---|
| 60 | tm=*pdns_localtime_r(&g_lastanswerTime.tv_sec, &tm); |
|---|
| 61 | strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm); |
|---|
| 62 | |
|---|
| 63 | cout<<"Last answer: "<<tmp<<"."<<g_lastanswerTime.tv_usec/1000000.0<<endl; |
|---|
| 64 | |
|---|
| 65 | tm=*pdns_localtime_r(&g_lastquestionTime.tv_sec, &tm); |
|---|
| 66 | strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm); |
|---|
| 67 | |
|---|
| 68 | cout<<"Last question: "<<tmp<<"."<<g_lastquestionTime.tv_usec/1000000.0<<endl; |
|---|
| 69 | } |
|---|
| 70 | // cout <<"Recursive questions: "<<g_clientQuestions<<", recursive responses: " << g_clientResponses<< |
|---|
| 71 | // ", server questions: "<<g_serverQuestions<<", server responses: "<<g_serverResponses<<endl; |
|---|
| 72 | |
|---|
| 73 | |
|---|
| 74 | // cerr << tv.tv_sec << " " <<g_clientQuestions<<" " << g_clientResponses<< " "<<g_serverQuestions<<" "<<g_serverResponses<<" "<<g_skipped<<endl; |
|---|
| 75 | g_clientQuestions=g_clientResponses=g_serverQuestions=g_serverResponses=0; |
|---|
| 76 | g_skipped=0; |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | |
|---|
| 80 | int main(int argc, char** argv) |
|---|
| 81 | try |
|---|
| 82 | { |
|---|
| 83 | for(int n=1 ; n < argc; ++n) { |
|---|
| 84 | cout<<argv[n]<<endl; |
|---|
| 85 | unsigned int parseErrors=0, totalQueries=0, skipped=0; |
|---|
| 86 | PcapPacketReader pr(argv[n]); |
|---|
| 87 | // PcapPacketWriter pw(argv[n]+string(".out"), pr); |
|---|
| 88 | /* four sorts of packets: |
|---|
| 89 | "rd": question from a client pc |
|---|
| 90 | "rd qr": answer to a client pc |
|---|
| 91 | "": question from the resolver |
|---|
| 92 | "qr": answer to the resolver */ |
|---|
| 93 | |
|---|
| 94 | /* what are interesting events to note? */ |
|---|
| 95 | /* we measure every 60 seconds, each interval with 10% less answers than questions is interesting */ |
|---|
| 96 | /* report chunked */ |
|---|
| 97 | |
|---|
| 98 | struct pdns_timeval lastreport={0, 0}; |
|---|
| 99 | |
|---|
| 100 | typedef set<pair<string, uint16_t> > queries_t; |
|---|
| 101 | queries_t questions, answers; |
|---|
| 102 | |
|---|
| 103 | // unsigned int count = 50000; |
|---|
| 104 | |
|---|
| 105 | map<pair<string, uint16_t>, int> counts; |
|---|
| 106 | |
|---|
| 107 | while(pr.getUDPPacket()) { |
|---|
| 108 | if((ntohs(pr.d_udp->uh_dport)==5300 || ntohs(pr.d_udp->uh_sport)==5300 || |
|---|
| 109 | ntohs(pr.d_udp->uh_dport)==53 || ntohs(pr.d_udp->uh_sport)==53) && |
|---|
| 110 | pr.d_len > 12) { |
|---|
| 111 | try { |
|---|
| 112 | MOADNSParser mdp((const char*)pr.d_payload, pr.d_len); |
|---|
| 113 | if(mdp.d_header.id==htons(4575)) { |
|---|
| 114 | // cerr << ntohl(*(uint32_t*)&pr.d_ip->ip_src)<<endl; |
|---|
| 115 | g_skipped++; |
|---|
| 116 | continue; |
|---|
| 117 | } |
|---|
| 118 | if(pdns_iequals(mdp.d_qname,"ycjnakisys1m.post.yamaha.co.jp.")) |
|---|
| 119 | cerr<<"hit: "<<mdp.d_qtype<<", rd="<<mdp.d_header.rd<< ", id="<<mdp.d_header.id<<", qr="<<mdp.d_header.qr<<"\n"; |
|---|
| 120 | |
|---|
| 121 | if(lastreport.tv_sec == 0) { |
|---|
| 122 | lastreport = pr.d_pheader.ts; |
|---|
| 123 | } |
|---|
| 124 | |
|---|
| 125 | // if(pr.d_pheader.ts.tv_sec > 1176897290 && pr.d_pheader.ts.tv_sec < 1176897310 ) |
|---|
| 126 | // pw.write(); |
|---|
| 127 | |
|---|
| 128 | if(mdp.d_header.rd && !mdp.d_header.qr) { |
|---|
| 129 | g_lastquestionTime=pr.d_pheader.ts; |
|---|
| 130 | g_clientQuestions++; |
|---|
| 131 | totalQueries++; |
|---|
| 132 | counts[make_pair(mdp.d_qname, mdp.d_qtype)]++; |
|---|
| 133 | questions.insert(make_pair(mdp.d_qname, mdp.d_qtype)); |
|---|
| 134 | } |
|---|
| 135 | else if(mdp.d_header.rd && mdp.d_header.qr) { |
|---|
| 136 | g_lastanswerTime=pr.d_pheader.ts; |
|---|
| 137 | g_clientResponses++; |
|---|
| 138 | answers.insert(make_pair(mdp.d_qname, mdp.d_qtype)); |
|---|
| 139 | } |
|---|
| 140 | else if(!mdp.d_header.rd && !mdp.d_header.qr) { |
|---|
| 141 | g_lastquestionTime=pr.d_pheader.ts; |
|---|
| 142 | g_serverQuestions++; |
|---|
| 143 | counts[make_pair(mdp.d_qname, mdp.d_qtype)]++; |
|---|
| 144 | questions.insert(make_pair(mdp.d_qname, mdp.d_qtype)); |
|---|
| 145 | totalQueries++; |
|---|
| 146 | } |
|---|
| 147 | else if(!mdp.d_header.rd && mdp.d_header.qr) { |
|---|
| 148 | answers.insert(make_pair(mdp.d_qname, mdp.d_qtype)); |
|---|
| 149 | g_serverResponses++; |
|---|
| 150 | } |
|---|
| 151 | |
|---|
| 152 | if(pr.d_pheader.ts.tv_sec - lastreport.tv_sec > 5) { |
|---|
| 153 | makeReport(pr.d_pheader.ts); |
|---|
| 154 | lastreport = pr.d_pheader.ts; |
|---|
| 155 | |
|---|
| 156 | } |
|---|
| 157 | |
|---|
| 158 | } |
|---|
| 159 | catch(MOADNSException& mde) { |
|---|
| 160 | // cerr<<"error parsing packet: "<<mde.what()<<endl; |
|---|
| 161 | parseErrors++; |
|---|
| 162 | continue; |
|---|
| 163 | } |
|---|
| 164 | catch(std::exception& e) { |
|---|
| 165 | cerr << e.what() << endl; |
|---|
| 166 | continue; |
|---|
| 167 | } |
|---|
| 168 | } |
|---|
| 169 | |
|---|
| 170 | } |
|---|
| 171 | cerr<<"Parse errors: "<<parseErrors<<", total queries: "<<totalQueries<<endl; |
|---|
| 172 | typedef vector<queries_t::value_type> diff_t; |
|---|
| 173 | diff_t diff; |
|---|
| 174 | set_difference(questions.begin(), questions.end(), answers.begin(), answers.end(), back_inserter(diff)); |
|---|
| 175 | cerr<<questions.size()<<" different rd questions, "<< answers.size()<<" different rd answers, diff: "<<diff.size()<<endl; |
|---|
| 176 | cerr<<skipped<<" skipped\n"; |
|---|
| 177 | |
|---|
| 178 | |
|---|
| 179 | cerr<<"Generating 'failed' file with failed queries and counts\n"; |
|---|
| 180 | ofstream failed("failed"); |
|---|
| 181 | for(diff_t::const_iterator i = diff.begin(); i != diff.end() ; ++i) { |
|---|
| 182 | failed << i->first << "\t" << i->second << "\t"<< counts[make_pair(i->first, i->second)]<<"\n"; |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | diff.clear(); |
|---|
| 186 | |
|---|
| 187 | set_difference(answers.begin(), answers.end(), questions.begin(), questions.end(), back_inserter(diff)); |
|---|
| 188 | cerr<<diff.size()<<" answers w/o questions\n"; |
|---|
| 189 | |
|---|
| 190 | cerr<<"Generating 'succeeded' file with failed queries and counts\n"; |
|---|
| 191 | ofstream succeeded("succeeded"); |
|---|
| 192 | for(queries_t::const_iterator i = answers.begin(); i != answers.end() ; ++i) { |
|---|
| 193 | succeeded << i->first << "\t" << i->second << counts[make_pair(i->first, i->second)]<<"\n"; |
|---|
| 194 | } |
|---|
| 195 | } |
|---|
| 196 | } |
|---|
| 197 | catch(std::exception& e) |
|---|
| 198 | { |
|---|
| 199 | cerr<<"Fatal: "<<e.what()<<endl; |
|---|
| 200 | } |
|---|