| 1 | #include "inflighter.cc" |
|---|
| 2 | #include <deque> |
|---|
| 3 | #include "namespaces.hh" |
|---|
| 4 | #include "dnsparser.hh" |
|---|
| 5 | #include "sstuff.hh" |
|---|
| 6 | #include "misc.hh" |
|---|
| 7 | #include "dnswriter.hh" |
|---|
| 8 | #include "dnsrecords.hh" |
|---|
| 9 | |
|---|
| 10 | StatBag S; |
|---|
| 11 | |
|---|
| 12 | struct DNSResult |
|---|
| 13 | { |
|---|
| 14 | vector<ComboAddress> ips; |
|---|
| 15 | int rcode; |
|---|
| 16 | bool seenauthsoa; |
|---|
| 17 | }; |
|---|
| 18 | |
|---|
| 19 | struct SendReceive |
|---|
| 20 | { |
|---|
| 21 | typedef int Identifier; |
|---|
| 22 | typedef DNSResult Answer; // ip |
|---|
| 23 | int d_socket; |
|---|
| 24 | deque<uint16_t> d_idqueue; |
|---|
| 25 | |
|---|
| 26 | |
|---|
| 27 | SendReceive(const std::string& remoteAddr, uint16_t port) |
|---|
| 28 | { |
|---|
| 29 | d_socket = socket(AF_INET, SOCK_DGRAM, 0); |
|---|
| 30 | int val=1; |
|---|
| 31 | setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val)); |
|---|
| 32 | |
|---|
| 33 | ComboAddress remote(remoteAddr, port); |
|---|
| 34 | connect(d_socket, (struct sockaddr*)&remote, remote.getSocklen()); |
|---|
| 35 | d_oks = d_errors = d_nodatas = d_nxdomains = d_unknowns = 0; |
|---|
| 36 | d_receiveds = d_receiveerrors = 0; |
|---|
| 37 | for(unsigned int id =0 ; id < numeric_limits<uint16_t>::max(); ++id) |
|---|
| 38 | d_idqueue.push_back(id); |
|---|
| 39 | } |
|---|
| 40 | |
|---|
| 41 | ~SendReceive() |
|---|
| 42 | { |
|---|
| 43 | close(d_socket); |
|---|
| 44 | } |
|---|
| 45 | |
|---|
| 46 | Identifier send(string& domain) |
|---|
| 47 | { |
|---|
| 48 | //cerr<<"Sending query for '"<<domain<<"'"<<endl; |
|---|
| 49 | |
|---|
| 50 | // send it, copy code from 'sdig' |
|---|
| 51 | vector<uint8_t> packet; |
|---|
| 52 | |
|---|
| 53 | DNSPacketWriter pw(packet, domain, QType::A); |
|---|
| 54 | |
|---|
| 55 | pw.getHeader()->id = d_idqueue.front(); |
|---|
| 56 | d_idqueue.pop_front(); |
|---|
| 57 | pw.getHeader()->rd = 1; |
|---|
| 58 | pw.getHeader()->qr = 0; |
|---|
| 59 | |
|---|
| 60 | ::send(d_socket, &*packet.begin(), packet.size(), 0); |
|---|
| 61 | |
|---|
| 62 | return pw.getHeader()->id; |
|---|
| 63 | } |
|---|
| 64 | |
|---|
| 65 | bool receive(Identifier& id, DNSResult& dr) |
|---|
| 66 | { |
|---|
| 67 | if(waitForData(d_socket, 0, 500000) > 0) { |
|---|
| 68 | char buf[512]; |
|---|
| 69 | |
|---|
| 70 | int len = recv(d_socket, buf, sizeof(buf), 0); |
|---|
| 71 | if(len < 0) { |
|---|
| 72 | d_receiveerrors++; |
|---|
| 73 | return 0; |
|---|
| 74 | } |
|---|
| 75 | else { |
|---|
| 76 | d_receiveds++; |
|---|
| 77 | } |
|---|
| 78 | // parse packet, set 'id', fill out 'ip' |
|---|
| 79 | |
|---|
| 80 | MOADNSParser mdp(string(buf, len)); |
|---|
| 81 | cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl; |
|---|
| 82 | cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr; |
|---|
| 83 | cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl; |
|---|
| 84 | dr.rcode = mdp.d_header.rcode; |
|---|
| 85 | for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) { |
|---|
| 86 | if(i->first.d_place == 1 && i->first.d_type == QType::A) |
|---|
| 87 | dr.ips.push_back(ComboAddress(i->first.d_content->getZoneRepresentation())); |
|---|
| 88 | if(i->first.d_place == 2 && i->first.d_type == QType::SOA) { |
|---|
| 89 | dr.seenauthsoa = 1; |
|---|
| 90 | } |
|---|
| 91 | cout<<i->first.d_place-1<<"\t"<<i->first.d_label<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type); |
|---|
| 92 | cout<<"\t"<<i->first.d_ttl<<"\t"<< i->first.d_content->getZoneRepresentation()<<"\n"; |
|---|
| 93 | } |
|---|
| 94 | |
|---|
| 95 | id = mdp.d_header.id; |
|---|
| 96 | |
|---|
| 97 | return 1; |
|---|
| 98 | } |
|---|
| 99 | return 0; |
|---|
| 100 | } |
|---|
| 101 | |
|---|
| 102 | void deliverTimeout(const Identifier& id) |
|---|
| 103 | { |
|---|
| 104 | d_idqueue.push_back(id); |
|---|
| 105 | } |
|---|
| 106 | |
|---|
| 107 | void deliverAnswer(string& domain, const DNSResult& dr) |
|---|
| 108 | { |
|---|
| 109 | cout<<domain<<": rcode: "<<dr.rcode; |
|---|
| 110 | BOOST_FOREACH(const ComboAddress& ca, dr.ips) { |
|---|
| 111 | cout<<", "<<ca.toString(); |
|---|
| 112 | } |
|---|
| 113 | cout<<endl; |
|---|
| 114 | if(dr.rcode == RCode::NXDomain) { |
|---|
| 115 | d_nxdomains++; |
|---|
| 116 | } |
|---|
| 117 | else if(dr.rcode) { |
|---|
| 118 | d_errors++; |
|---|
| 119 | } |
|---|
| 120 | else if(dr.ips.empty() && dr.seenauthsoa) |
|---|
| 121 | d_nodatas++; |
|---|
| 122 | else if(!dr.ips.empty()) |
|---|
| 123 | d_oks++; |
|---|
| 124 | else { |
|---|
| 125 | cout<<"UNKNOWN!! ^^"<<endl; |
|---|
| 126 | d_unknowns++; |
|---|
| 127 | } |
|---|
| 128 | } |
|---|
| 129 | unsigned int d_errors, d_nxdomains, d_nodatas, d_oks, d_unknowns; |
|---|
| 130 | unsigned int d_receiveds, d_receiveerrors; |
|---|
| 131 | }; |
|---|
| 132 | |
|---|
| 133 | |
|---|
| 134 | int main(int argc, char** argv) |
|---|
| 135 | { |
|---|
| 136 | SendReceive sr(argv[1], atoi(argv[2])); |
|---|
| 137 | unsigned int limit = 0; |
|---|
| 138 | if(argc==4) |
|---|
| 139 | limit = atoi(argv[3]); |
|---|
| 140 | |
|---|
| 141 | reportAllTypes(); |
|---|
| 142 | vector<string> domains; |
|---|
| 143 | |
|---|
| 144 | Inflighter<vector<string>, SendReceive> inflighter(domains, sr); |
|---|
| 145 | inflighter.d_maxInFlight = 1000; |
|---|
| 146 | inflighter.d_timeoutSeconds = 15; |
|---|
| 147 | string line; |
|---|
| 148 | |
|---|
| 149 | pair<string, string> split; |
|---|
| 150 | while(stringfgets(stdin, line)) { |
|---|
| 151 | if(limit && domains.size() >= limit) |
|---|
| 152 | break; |
|---|
| 153 | |
|---|
| 154 | trim_right(line); |
|---|
| 155 | split=splitField(line,','); |
|---|
| 156 | domains.push_back(split.second); |
|---|
| 157 | domains.push_back("www."+split.second); |
|---|
| 158 | } |
|---|
| 159 | cerr<<"Read "<<domains.size()<<" domains!"<<endl; |
|---|
| 160 | random_shuffle(domains.begin(), domains.end()); |
|---|
| 161 | |
|---|
| 162 | for(;;) { |
|---|
| 163 | try { |
|---|
| 164 | inflighter.run(); |
|---|
| 165 | break; |
|---|
| 166 | } |
|---|
| 167 | catch(exception& e) { |
|---|
| 168 | cerr<<"Caught exception: "<<e.what()<<endl; |
|---|
| 169 | } |
|---|
| 170 | } |
|---|
| 171 | cerr<<"Results: "<<sr.d_errors<<" errors, "<<sr.d_oks<<" oks, "<<sr.d_nodatas<<" nodatas, "<<sr.d_nxdomains<<" nxdomains, "<<inflighter.getTimeouts()<<" timeouts"<<endl; |
|---|
| 172 | cerr<<sr.d_unknowns<<" answers with an unknown status"<<endl; |
|---|
| 173 | |
|---|
| 174 | cerr<<domains.size() - (sr.d_errors + sr.d_oks + sr.d_nodatas + sr.d_nxdomains + inflighter.getTimeouts() + sr.d_unknowns)<<" status results missing"<<endl; |
|---|
| 175 | cerr<<sr.d_receiveerrors<<" receive errors, "<<sr.d_receiveds<<" packets received correctly"<<endl; |
|---|
| 176 | |
|---|
| 177 | cerr<<inflighter.getUnexpecteds()<<" unexpected responses (probably seen as timeouts)"<<endl; |
|---|
| 178 | } |
|---|
| 179 | |
|---|
| 180 | |
|---|