struct QuestionData
{
- QuestionData() : d_assignedID(-1), d_origRcode(-1), d_newRcode(-1), d_norecursionavailable(false)
- {}
+ QuestionData() : d_assignedID(-1), d_origRcode(-1), d_newRcode(-1), d_norecursionavailable(false), d_origlate(false), d_newlate(false)
+ {
+ }
int d_assignedID;
MOADNSParser::answers_t d_origAnswers, d_newAnswers;
int d_origRcode, d_newRcode;
struct timeval d_resentTime;
bool d_norecursionavailable;
+ bool d_origlate, d_newlate;
};
-typedef map<QuestionIdentifier, QuestionData> qids_t;
+typedef map<QuestionIdentifier, shared_ptr<QuestionData> > qids_t;
qids_t qids;
-unsigned int s_questions, s_answers, s_timedout, s_perfect, s_mostly, s_nooriginalanswer;
+typedef map<uint16_t, struct QuestionIdentifier > id2qi_t;
+id2qi_t id2qi;
+
+unsigned int s_questions, s_answers, s_wetimedout, s_perfect, s_mostly, s_origtimedout;
+unsigned int s_wenever, s_orignever;
unsigned int s_webetter, s_origbetter, s_norecursionavailable;
unsigned int s_weunmatched, s_origunmatched;
unsigned int s_wednserrors, s_origdnserrors;
}
-pair<unsigned int, unsigned int> WeOrigSlowQueries()
+pair<unsigned int, unsigned int> WeOrigSlowQueriesDelta()
{
struct timeval now;
gettimeofday(&now, 0);
pair<unsigned int, unsigned int> ret=make_pair(0,0);
for(qids_t::iterator i=qids.begin(); i!=qids.end(); ++i) {
- double dt=DiffTime(i->second.d_resentTime, now);
- if(dt > 2) {
- if(i->second.d_newRcode == -1)
+ double dt=DiffTime(i->second->d_resentTime, now);
+ if(dt > 2.0) {
+ if(i->second->d_newRcode == -1) {
+ if(!i->second->d_newlate) {
+ i->second->d_newlate=true;
+ s_wetimedout++;
+ }
ret.first++;
- else
+ }
+ if(i->second->d_origRcode == -1) {
+ if(!i->second->d_origlate) {
+ i->second->d_origlate=true;
+ s_origtimedout++;
+ }
ret.second++;
+ }
}
}
return ret;
}
-void pruneQids()
-{
- struct timeval now;
- gettimeofday(&now, 0);
-
- for(qids_t::iterator i=qids.begin(); i!=qids.end(); ) {
- if(now.tv_sec < i->second.d_resentTime.tv_sec + 4 || (now.tv_sec == i->second.d_resentTime.tv_sec && now.tv_usec < i->second.d_resentTime.tv_usec))
- ++i;
- else {
- // s_idmanager.releaseID(i->second.d_assignedID);
- if(i->second.d_newRcode==-1)
- s_timedout++;
- else if(i->second.d_origRcode==-1)
- s_nooriginalanswer++;
- else
- cerr<<"Impossible - finished QI in the pool"<<endl;
- qids.erase(i++);
- }
- }
-}
-
void compactAnswerSet(MOADNSParser::answers_t orig, set<DNSRecord>& compacted)
{
for(MOADNSParser::answers_t::const_iterator i=orig.begin(); i != orig.end(); ++i)
void measureResultAndClean(const QuestionIdentifier& qi)
{
- QuestionData qd=qids[qi];
+ QuestionData qd=*qids[qi];
set<DNSRecord> canonicOrig, canonicNew;
compactAnswerSet(qd.d_origAnswers, canonicOrig);
cout<<"\n";
}
}
+
qids.erase(qi);
s_idmanager.releaseID(qd.d_assignedID);
Socket *s_socket;
-static pthread_mutex_t s_lock=PTHREAD_MUTEX_INITIALIZER;
-
-void* incomingThread(void*)
+void receiveFromReference()
try
{
string packet;
IPEndpoint remote;
- for(;;) {
- s_socket->recvFrom(packet, remote);
+ while(s_socket->recvFromAsync(packet, remote)) {
try {
MOADNSParser mdp(packet.c_str(), packet.length());
if(!mdp.d_header.qr) {
cout<<"Received a question from our reference nameserver!"<<endl;
continue;
}
-
- Lock l(&s_lock);
-
- qids_t::iterator i=qids.begin();
- for(; i!=qids.end(); ++i)
- if(i->second.d_assignedID == ntohs(mdp.d_header.id))
- break;
-
- if(i==qids.end()) {
- cout<<"Received an answer from reference nameserver with id "<<mdp.d_header.id<<" which we can't match to a question!"<<endl;
+
+ id2qi_t::iterator found=id2qi.find(ntohs(mdp.d_header.id));
+ if(found==id2qi.end()) {
+ cout<<"Received an answer ("<<mdp.d_qname<<") from reference nameserver with id "<<mdp.d_header.id<<" which we can't match to a question!"<<endl;
s_weunmatched++;
continue;
}
+ QuestionIdentifier qi=found->second;
+ QuestionData& qd=*qids[qi];
- // cout<<"Matched answer from reference to a question we asked"<<endl;
-
- QuestionData& qd=i->second;
-
+
qd.d_newAnswers=mdp.d_answers;
qd.d_newRcode=mdp.d_header.rcode;
if(qd.d_origRcode!=-1) {
// cout<<"Removing entry "<<i->first<<", is done [in socket]"<<endl;
- measureResultAndClean(i->first);
+ id2qi.erase(found);
+ measureResultAndClean(qi);
}
}
catch(MOADNSException &e)
exit(1);
}
-int main(int argc, char** argv)
-try
+void pruneQids()
{
- if(argc < 2 || argc > 4) {
- cerr<<"dnsreplay - replay DNS traffic to a reference server to compare performance"<<endl;
- cerr<<"Syntax: dnsreplay pcapfile [target IP] [target port]\nDefaults to 127.0.0.1 and 5300"<<endl;
- return EXIT_FAILURE;
+ struct timeval now;
+ gettimeofday(&now, 0);
+
+ for(qids_t::iterator i=qids.begin(); i!=qids.end(); ) {
+ if(DiffTime(i->second->d_resentTime, now) < 60)
+ ++i;
+ else {
+ s_idmanager.releaseID(i->second->d_assignedID);
+ if(i->second->d_newRcode==-1) {
+ s_wenever++;
+ }
+ if(i->second->d_origRcode==-1) {
+ s_orignever++;
+ }
+
+ id2qi.erase(i->second->d_assignedID);
+ qids.erase(i++);
+ }
+ }
+}
+
+
+void houseKeeping()
+{
+ pair<unsigned int, unsigned int> slows=WeOrigSlowQueriesDelta();
+
+ int waitingFor=qids.size() - slows.first - slows.second;
+ if(waitingFor > 1000) {
+ cerr<<"Too many questions outstanding, waiting 0.25 seconds"<<endl;
+ usleep(250000);
}
- PcapPacketReader pr(argv[1]);
- s_socket= new Socket(InterNetwork, Datagram);
+ cerr<<waitingFor<<" queries that could still come in on time, "<<qids.size()<<" outstanding"<<endl;
- pthread_t tid;
- pthread_create(&tid, 0, incomingThread, 0);
+ cerr<<"we late: "<<s_wetimedout<<", orig late: "<< s_origtimedout<<", "<<s_questions<<" questions sent, "<<s_answers
+ <<" original answers, "<<s_perfect<<" perfect, "<<s_mostly<<" mostly correct"<<", "<<s_webetter<<" we better, "<<s_origbetter<<" orig better ("<<s_origbetterset.size()<<" diff)"<<endl;
+ cerr<<"we never: "<<s_wenever<<", orig never: "<<s_orignever<<endl;
+ cerr<<"original questions from IP addresses for which recursion was not available: "<<s_norecursionavailable<<endl;
+ cerr<<"Unmatched from us: "<<s_weunmatched<<", unmatched from original: "<<s_origunmatched << " ( - decoding err: "<<s_origunmatched-s_origdnserrors<<")"<<endl;
+ cerr<<"DNS decoding errors from us: "<<s_wednserrors<<", from original: "<<s_origdnserrors<<endl<<endl;
- IPEndpoint remote(argc > 2 ? argv[2] : "127.0.0.1",
- argc > 3 ? atoi(argv[3]) : 5300);
- struct timeval lastsent={0,0};
+ pruneQids();
- unsigned int once=0;
- for(;;) {
- if(!pr.getUDPPacket())
- break;
+}
- if(!((once++)%2000)) {
- Lock l(&s_lock);
- pair<unsigned int, unsigned int> slows=WeOrigSlowQueries();
+void sendPacketFromPR(PcapPacketReader& pr, const IPEndpoint& remote)
+{
+ static struct timeval lastsent;
- int waitingFor=qids.size() - slows.first - slows.second;
- if(waitingFor > 1000) {
- cerr<<"Too many questions outstanding, waiting 0.25 seconds"<<endl;
- usleep(250000);
+ HEADER* dh=(HEADER*)pr.d_payload;
+ // non-recursive
+ if((ntohs(pr.d_udp->uh_dport)!=53 && ntohs(pr.d_udp->uh_sport)!=53) || !dh->rd || (unsigned int)pr.d_len <= sizeof(HEADER))
+ return;
+
+ try {
+ MOADNSParser mdp((const char*)pr.d_payload, pr.d_len);
+ QuestionIdentifier qi=QuestionIdentifier::create(pr.d_ip, pr.d_udp, mdp);
+
+ if(!mdp.d_header.qr) {
+ s_questions++;
+ if(qids.count(qi)) {
+ if(!s_quiet)
+ cout<<"Saw an exact duplicate question, "<<qi<< endl;
+ return;
}
-
- //pruneQids();
-
- cerr<<waitingFor<<" queries that could still come in on time, "<<qids.size()<<" outstanding"<<endl;
+
+ // new question!
+ qids[qi]=shared_ptr<QuestionData>(new QuestionData);
+
+ QuestionData& qd=*qids[qi];
+ gettimeofday(&qd.d_resentTime,0);
+
+ qd.d_assignedID = s_idmanager.getID();
+
+ id2qi[qd.d_assignedID]=qi;
+ dh->id=htons(qd.d_assignedID);
- cerr<<"we late: "<<slows.first+s_timedout<<", orig late: "<< slows.second + s_nooriginalanswer<<", "<<s_questions<<" questions sent, "<<s_answers
- <<" original answers, "<<s_perfect<<" perfect, "<<s_mostly<<" mostly correct"<<", "<<s_webetter<<" we better, "<<s_origbetter<<" orig better ("<<s_origbetterset.size()<<" diff)"<<endl;
- cerr<<"original questions from IP addresses for which recursion was not available: "<<s_norecursionavailable<<endl;
- cerr<<"Unmatched from us: "<<s_weunmatched<<", unmatched from original: "<<s_origunmatched<<endl;
- cerr<<"DNS decoding errors from us: "<<s_wednserrors<<", from original: "<<s_origdnserrors<<endl<<endl;
+ if(lastsent.tv_sec && (!(s_questions%25))) {
+ double seconds=pr.d_pheader.ts.tv_sec - lastsent.tv_sec;
+ double useconds=(pr.d_pheader.ts.tv_usec - lastsent.tv_usec);
+
+ if(useconds < 0) {
+ seconds-=1;
+ useconds+=1000000;
+ }
+
+ double factor=20;
+
+ seconds/=factor;
+ useconds/=factor;
+
+ long long nanoseconds=(long long)(1000000000ULL*seconds + useconds * 1000);
+
+ struct timespec tosleep;
+ tosleep.tv_sec=nanoseconds/1000000000UL;
+ tosleep.tv_nsec=nanoseconds%1000000000UL;
+
+ nanosleep(&tosleep, 0);
+ lastsent=pr.d_pheader.ts;
+ }
+ if(!lastsent.tv_sec)
+ lastsent=pr.d_pheader.ts;
+
+ // cout<<"sending!"<<endl;
+ s_socket->sendTo(string(pr.d_payload, pr.d_payload + pr.d_len), remote);
}
-
- HEADER* dh=(HEADER*)pr.d_payload;
- // non-recursive
- if((ntohs(pr.d_udp->uh_dport)!=53 && ntohs(pr.d_udp->uh_sport)!=53) || !dh->rd || (unsigned int)pr.d_len <= sizeof(HEADER))
- continue;
-
- try {
- MOADNSParser mdp((const char*)pr.d_payload, pr.d_len);
- QuestionIdentifier qi=QuestionIdentifier::create(pr.d_ip, pr.d_udp, mdp);
+ else {
+ s_answers++;
- if(!mdp.d_header.qr) {
- s_questions++;
- {
- Lock l(&s_lock);
- if(qids.count(qi)) {
- if(!s_quiet)
- cout<<"Saw an exact duplicate question, "<<qi<< endl;
- continue;
- }
-
- // new question!
- QuestionData& qd=qids[qi];
- gettimeofday(&qd.d_resentTime,0);
-
- qd.d_assignedID = s_idmanager.getID();
-
- dh->id=htons(qd.d_assignedID);
- }
+ if(qids.count(qi)) {
+ QuestionData& qd=*qids[qi];
- if(lastsent.tv_sec && (!(s_questions%25))) {
- double seconds=pr.d_pheader.ts.tv_sec - lastsent.tv_sec;
- double useconds=(pr.d_pheader.ts.tv_usec - lastsent.tv_usec);
-
- if(useconds < 0) {
- seconds-=1;
- useconds+=1000000;
- }
-
- double factor=10;
-
- seconds/=factor;
- useconds/=factor;
-
- long long nanoseconds=(long long)(1000000000ULL*seconds + useconds * 1000);
-
- struct timespec tosleep;
- tosleep.tv_sec=nanoseconds/1000000000UL;
- tosleep.tv_nsec=nanoseconds%1000000000UL;
-
- nanosleep(&tosleep, 0);
- lastsent=pr.d_pheader.ts;
+ // cout<<"Matched answer "<<qi<<endl;
+ qd.d_origAnswers=mdp.d_answers;
+ qd.d_origRcode=mdp.d_header.rcode;
+
+ if(!dh->ra) {
+ s_norecursionavailable++;
+ qd.d_norecursionavailable=true;
}
- if(!lastsent.tv_sec)
- lastsent=pr.d_pheader.ts;
-
- // cout<<"sending!"<<endl;
- s_socket->sendTo(string(pr.d_payload, pr.d_payload + pr.d_len), remote);
+
+ if(qd.d_newRcode!=-1) {
+ // cout<<"Removing entry "<<qi<<", is done [in main loop]"<<endl;
+ id2qi.erase(qd.d_assignedID);
+ measureResultAndClean(qi);
+ }
+
+ return;
}
else {
- s_answers++;
- Lock l(&s_lock);
- if(qids.count(qi)) {
- QuestionData& qd=qids[qi];
- // cout<<"Matched answer "<<qi<<endl;
- qd.d_origAnswers=mdp.d_answers;
- qd.d_origRcode=mdp.d_header.rcode;
-
- if(!dh->ra) {
- s_norecursionavailable++;
- qd.d_norecursionavailable=true;
- }
-
- if(qd.d_newRcode!=-1) {
- // cout<<"Removing entry "<<qi<<", is done [in main loop]"<<endl;
- measureResultAndClean(qi);
- }
-
-
- continue;
- }
- else {
- s_origunmatched++;
- if(!s_quiet)
- cout<<"Unmatched original answer "<<qi<<endl;
- }
+ s_origunmatched++;
+ if(!s_quiet)
+ cout<<"Unmatched original answer "<<qi<<endl;
}
}
- catch(MOADNSException &e)
- {
- s_origdnserrors++;
- }
- catch(out_of_range &e)
- {
- s_origdnserrors++;
- }
}
+ catch(MOADNSException &e)
+ {
+ s_origdnserrors++;
+ }
+ catch(out_of_range &e)
+ {
+ s_origdnserrors++;
+ }
+}
+
+int main(int argc, char** argv)
+try
+{
+ if(argc < 2 || argc > 4) {
+ cerr<<"dnsreplay - replay DNS traffic to a reference server to compare performance"<<endl;
+ cerr<<"Syntax: dnsreplay pcapfile [target IP] [target port]\nDefaults to 127.0.0.1 and 5300"<<endl;
+ return EXIT_FAILURE;
+ }
+
+ PcapPacketReader pr(argv[1]);
+ s_socket= new Socket(InterNetwork, Datagram);
+
+ s_socket->setNonBlocking();
+
+ IPEndpoint remote(argc > 2 ? argv[2] : "127.0.0.1",
+ argc > 3 ? atoi(argv[3]) : 5300);
+
+ unsigned int once=0;
+ for(;;) {
+ if(!((once++)%4000))
+ houseKeeping();
+
+ if(!pr.getUDPPacket())
+ break;
+
+ sendPacketFromPR(pr, remote);
+ receiveFromReference();
+ }
}
catch(exception& e)
{