1
#include "dnsparser.hh"
4
#include "dnswriter.hh"
5
#include "dnsrecords.hh"
6
#include <boost/format.hpp>
13
volatile bool g_ret; // make sure the optimizer does not get too smart
18
void alarmHandler(int)
23
template<typename C> void doRun(const C& cmd, int mseconds=100)
26
it.it_value.tv_sec=mseconds/1000;
27
it.it_value.tv_usec = 1000* (mseconds%1000);
28
it.it_interval.tv_sec=0;
29
it.it_interval.tv_usec=0;
31
signal(SIGVTALRM, alarmHandler);
32
setitimer(ITIMER_VIRTUAL, &it, 0);
38
while(runs++, !g_stop) {
41
double delta=dt.udiff()/1000000.0;
42
boost::format fmt("'%s' %.02f seconds: %.1f runs/s, %.02f usec/run");
44
cerr<< (fmt % cmd.getName() % delta % (runs/delta) % (delta* 1000000.0/runs)) << endl;
50
explicit ARecordTest(int records) : d_records(records) {}
52
string getName() const
54
return (boost::format("%d a records") % d_records).str();
57
void operator()() const
59
vector<uint8_t> packet;
60
DNSPacketWriter pw(packet, "outpost.ds9a.nl", QType::A);
61
for(int records = 0; records < d_records; records++) {
62
pw.startRecord("outpost.ds9a.nl", QType::A);
63
ARecordContent arc("1.2.3.4");
72
struct MakeStringFromCharStarTest
74
MakeStringFromCharStarTest() : d_size(0){}
75
string getName() const
77
return (boost::format("make a std::string")).str();
80
void operator()() const
82
string name("outpost.ds9a.nl");
83
d_size += name.length();
92
string getName() const
94
return "gettimeofday-test";
97
void operator()() const
100
gettimeofday(&tv, 0);
104
pthread_mutex_t s_testlock=PTHREAD_MUTEX_INITIALIZER;
106
struct GetLockUncontendedTest
108
string getName() const
110
return "getlock-uncontended-test";
113
void operator()() const
115
pthread_mutex_lock(&s_testlock);
116
pthread_mutex_unlock(&s_testlock);
121
struct StaticMemberTest
123
string getName() const
125
return "static-member-test";
128
void operator()() const
130
static string* s_ptr;
132
s_ptr = new string();
137
struct MakeARecordTest
139
string getName() const
141
return (boost::format("make a-record")).str();
144
void operator()() const
146
static string src("1.2.3.4");
147
ARecordContent arc(src);
148
//ARecordContent arc(0x01020304);
153
struct MakeARecordTestMM
155
string getName() const
157
return (boost::format("make a-record (mm)")).str();
160
void operator()() const
162
DNSRecordContent*drc = DNSRecordContent::mastermake(QType::A, 1,
171
explicit A2RecordTest(int records) : d_records(records) {}
173
string getName() const
175
return (boost::format("%d a records") % d_records).str();
178
void operator()() const
180
vector<uint8_t> packet;
181
DNSPacketWriter pw(packet, "outpost.ds9a.nl", QType::A);
182
ARecordContent arc("1.2.3.4");
183
string name("outpost.ds9a.nl");
184
for(int records = 0; records < d_records; records++) {
185
pw.startRecord(name, QType::A);
197
explicit TXTRecordTest(int records) : d_records(records) {}
199
string getName() const
201
return (boost::format("%d TXT records") % d_records).str();
204
void operator()() const
206
vector<uint8_t> packet;
207
DNSPacketWriter pw(packet, "outpost.ds9a.nl", QType::TXT);
208
for(int records = 0; records < d_records; records++) {
209
pw.startRecord("outpost.ds9a.nl", QType::TXT);
210
TXTRecordContent arc("\"een leuk verhaaltje in een TXT\"");
219
struct GenericRecordTest
221
explicit GenericRecordTest(int records, uint16_t type, const std::string& content)
222
: d_records(records), d_type(type), d_content(content) {}
224
string getName() const
226
return (boost::format("%d %s records") % d_records %
227
DNSRecordContent::NumberToType(d_type)).str();
230
void operator()() const
232
vector<uint8_t> packet;
233
DNSPacketWriter pw(packet, "outpost.ds9a.nl", d_type);
234
for(int records = 0; records < d_records; records++) {
235
pw.startRecord("outpost.ds9a.nl", d_type);
236
DNSRecordContent*drc = DNSRecordContent::mastermake(d_type, 1,
249
struct AAAARecordTest
251
explicit AAAARecordTest(int records) : d_records(records) {}
253
string getName() const
255
return (boost::format("%d aaaa records (mm)") % d_records).str();
258
void operator()() const
260
vector<uint8_t> packet;
261
DNSPacketWriter pw(packet, "outpost.ds9a.nl", QType::AAAA);
262
for(int records = 0; records < d_records; records++) {
263
pw.startRecord("outpost.ds9a.nl", QType::AAAA);
264
DNSRecordContent*drc = DNSRecordContent::mastermake(QType::AAAA, 1, "fe80::21d:92ff:fe6d:8441");
275
explicit SOARecordTest(int records) : d_records(records) {}
277
string getName() const
279
return (boost::format("%d soa records (mm)") % d_records).str();
282
void operator()() const
284
vector<uint8_t> packet;
285
DNSPacketWriter pw(packet, "outpost.ds9a.nl", QType::SOA);
287
for(int records = 0; records < d_records; records++) {
288
pw.startRecord("outpost.ds9a.nl", QType::SOA);
289
DNSRecordContent*drc = DNSRecordContent::mastermake(QType::SOA, 1, "a0.org.afilias-nst.info. noc.afilias-nst.info. 2008758137 1800 900 604800 86400");
298
vector<uint8_t> makeEmptyQuery()
300
vector<uint8_t> packet;
301
DNSPacketWriter pw(packet, "outpost.ds9a.nl", QType::SOA);
306
vector<uint8_t> makeRootReferral()
308
vector<uint8_t> packet;
309
DNSPacketWriter pw(packet, "outpost.ds9a.nl", QType::SOA);
311
// nobody reads what we output, but it appears to be the magic that shuts some nameservers up
312
static const char*ips[]={"198.41.0.4", "192.228.79.201", "192.33.4.12", "128.8.10.90", "192.203.230.10", "192.5.5.241", "192.112.36.4", "128.63.2.53",
313
"192.36.148.17","192.58.128.30", "193.0.14.129", "198.32.64.12", "202.12.27.33"};
314
static char templ[40];
315
strncpy(templ,"a.root-servers.net", sizeof(templ) - 1);
318
for(char c='a';c<='m';++c) {
320
pw.startRecord(".", QType::NS, 3600, 1, DNSPacketWriter::AUTHORITY);
321
DNSRecordContent* drc = DNSRecordContent::mastermake(QType::NS, 1, templ);
326
for(char c='a';c<='m';++c) {
328
pw.startRecord(".", QType::A, 3600, 1, DNSPacketWriter::ADDITIONAL);
329
DNSRecordContent* drc = DNSRecordContent::mastermake(QType::A, 1, ips[c-'a']);
338
vector<uint8_t> makeTypicalReferral()
340
vector<uint8_t> packet;
341
DNSPacketWriter pw(packet, "outpost.ds9a.nl", QType::A);
343
pw.startRecord("ds9a.nl", QType::NS, 3600, 1, DNSPacketWriter::AUTHORITY);
344
DNSRecordContent* drc = DNSRecordContent::mastermake(QType::NS, 1, "ns1.ds9a.nl");
348
pw.startRecord("ds9a.nl", QType::NS, 3600, 1, DNSPacketWriter::AUTHORITY);
349
drc = DNSRecordContent::mastermake(QType::NS, 1, "ns2.ds9a.nl");
354
pw.startRecord("ns1.ds9a.nl", QType::A, 3600, 1, DNSPacketWriter::ADDITIONAL);
355
drc = DNSRecordContent::mastermake(QType::A, 1, "1.2.3.4");
359
pw.startRecord("ns2.ds9a.nl", QType::A, 3600, 1, DNSPacketWriter::ADDITIONAL);
360
drc = DNSRecordContent::mastermake(QType::A, 1, "4.3.2.1");
372
string getName() const
374
return "write rootreferral";
377
void operator()() const
379
vector<uint8_t> packet=makeRootReferral();
384
struct StackMallocTest
386
string getName() const
388
return "stack allocation";
391
void operator()() const
393
char *buffer= new char[200000];
400
struct EmptyQueryTest
402
string getName() const
404
return "write empty query";
407
void operator()() const
409
vector<uint8_t> packet=makeEmptyQuery();
414
struct TypicalRefTest
416
string getName() const
418
return "write typical referral";
421
void operator()() const
423
vector<uint8_t> packet=makeTypicalReferral();
430
bool operator()(const pair<string, QType>& a, const pair<string, QType>& b) const
432
int cmp=strcasecmp(a.first.c_str(), b.first.c_str());
438
return a.second < b.second;
450
struct timeval d_now;
452
static bool magicAddrMatch(const QType& query, const QType& answer)
454
if(query.getCode() != QType::ADDR)
456
return answer.getCode() == QType::A || answer.getCode() == QType::AAAA;
460
bool moreSpecificThan(const string& a, const string &b)
462
static string dot(".");
463
int counta=(a!=dot), countb=(b!=dot);
465
for(string::size_type n=0;n<a.size();++n)
468
for(string::size_type n=0;n<b.size();++n)
471
return counta>countb;
475
struct ParsePacketTest
477
explicit ParsePacketTest(const vector<uint8_t>& packet, const std::string& name)
478
: d_packet(packet), d_name(name)
481
string getName() const
483
return "parse '"+d_name+"'";
486
void operator()() const
488
MOADNSParser mdp((const char*)&*d_packet.begin(), d_packet.size());
489
typedef map<pair<string, QType>, set<DNSResourceRecord>, TCacheComp > tcache_t;
493
vector<DNSResourceRecord> d_result;
497
DNSResourceRecord rr;
498
for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
499
DNSResourceRecord rr;
500
rr.qtype=i->first.d_type;
501
rr.qname=i->first.d_label;
503
rr.ttl=i->first.d_ttl;
504
rr.content=i->first.d_content->getZoneRepresentation(); // this should be the serialised form
505
rr.d_place=(DNSResourceRecord::Place) i->first.d_place;
506
lwr.d_result.push_back(rr);
512
// reap all answers from this packet that are acceptable
513
for(vector<DNSResourceRecord>::iterator i=lwr.d_result.begin();i != lwr.d_result.end();++i) {
514
if(i->qtype.getCode() == QType::OPT) {
515
// <<prefix<<qname<<": skipping OPT answer '"<<i->qname<<"' from '"<<auth<<"' nameservers" <<endl;
518
// LOG<<prefix<<qname<<": accept answer '"<<i->qname<<"|"<<i->qtype.getName()<<"|"<<i->content<<"' from '"<<auth<<"' nameservers? ";
519
if(i->qtype.getCode()==QType::ANY) {
520
// LOG<<"NO! - we don't accept 'ANY' data"<<endl;
524
if(dottedEndsOn(i->qname, auth)) {
525
if(lwr.d_aabit && lwr.d_rcode==RCode::NoError && i->d_place==DNSResourceRecord::ANSWER && 0) {
526
// LOG<<"NO! Is from delegation-only zone"<<endl;
528
return; // RCode::NXDomain;
531
// LOG<<"YES!"<<endl;
533
// i->ttl=min(s_maxcachettl, i->ttl);
535
DNSResourceRecord rr=*i;
536
rr.d_place=DNSResourceRecord::ANSWER;
538
// rr.ttl += d_now.tv_sec;
540
if(rr.qtype.getCode() == QType::NS) // people fiddle with the case
541
rr.content=toLower(rr.content); // this must stay! (the cache can't be case-insensitive on the RHS of records)
542
tcache[make_pair(i->qname,i->qtype)].insert(rr);
546
; // LOG<<"NO!"<<endl;
550
for(tcache_t::iterator i=tcache.begin();i!=tcache.end();++i) {
551
if(i->second.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2)
552
uint32_t lowestTTL=numeric_limits<uint32_t>::max();
553
for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j)
554
lowestTTL=min(lowestTTL, j->ttl);
556
for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j)
557
((tcache_t::value_type::second_type::value_type*)&(*j))->ttl=lowestTTL;
560
// RC.replace(d_now.tv_sec, i->first.first, i->first.second, i->second, lwr.d_aabit);
562
set<string, CIStringCompare> nsset;
563
// LOG<<prefix<<qname<<": determining status after receiving this packet"<<endl;
565
bool done=false, realreferral=false, negindic=false;
566
string newauth, soaname, newtarget;
568
vector<DNSResourceRecord> ret;
569
QType qtype(QType::A);
572
for(vector<DNSResourceRecord>::const_iterator i=lwr.d_result.begin();i!=lwr.d_result.end();++i) {
573
if(i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA &&
574
lwr.d_rcode==RCode::NXDomain) {
575
// LOG<<prefix<<qname<<": got negative caching indication for RECORD '"<<qname+"'"<<endl;
581
ne.d_ttd=d_now.tv_sec + min(i->ttl, 3600U); // controversial
583
ne.d_qtype=QType(0); // this encodes 'whole record'
586
// Lock l(&s_negcachelock);
587
// replacing_insert(s_negcache, ne);
591
else if(i->d_place==DNSResourceRecord::ANSWER && pdns_iequals(i->qname, qname) && i->qtype.getCode()==QType::CNAME && (!(qtype==QType(QType::CNAME)))) {
593
newtarget=i->content;
595
// for ANY answers we *must* have an authoritive answer
596
else if(i->d_place==DNSResourceRecord::ANSWER && pdns_iequals(i->qname, qname) &&
598
i->qtype==qtype || (lwr.d_aabit && (qtype==QType(QType::ANY) || magicAddrMatch(qtype, i->qtype) ) )
603
// LOG<<prefix<<qname<<": answer is in: resolved to '"<< i->content<<"|"<<i->qtype.getName()<<"'"<<endl;
608
else if(i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::NS) {
609
if(moreSpecificThan(i->qname,auth)) {
611
// LOG<<prefix<<qname<<": got NS record '"<<i->qname<<"' -> '"<<i->content<<"'"<<endl;
615
;// // LOG<<prefix<<qname<<": got upwards/level NS record '"<<i->qname<<"' -> '"<<i->content<<"', had '"<<auth<<"'"<<endl;
616
nsset.insert(i->content);
618
else if(!done && i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA &&
619
lwr.d_rcode==RCode::NoError) {
620
// LOG<<prefix<<qname<<": got negative caching indication for '"<< (qname+"|"+i->qtype.getName()+"'") <<endl;
625
ne.d_ttd=d_now.tv_sec + i->ttl;
628
if(qtype.getCode()) { // prevents us from blacking out a whole domain
629
// Lock l(&s_negcachelock);
630
// replacing_insert(s_negcache, ne);
637
const vector<uint8_t>& d_packet;
641
struct ParsePacketBareTest
643
explicit ParsePacketBareTest(const vector<uint8_t>& packet, const std::string& name)
644
: d_packet(packet), d_name(name)
647
string getName() const
649
return "parse '"+d_name+"' bare";
652
void operator()() const
654
MOADNSParser mdp((const char*)&*d_packet.begin(), d_packet.size());
656
const vector<uint8_t>& d_packet;
661
struct SimpleCompressTest
663
explicit SimpleCompressTest(const std::string& name)
667
string getName() const
669
return "compress '"+d_name+"'";
672
void operator()() const
674
simpleCompress(d_name);
679
struct VectorExpandTest
681
string getName() const
683
return "vector expand";
686
void operator()() const
688
vector<uint8_t> d_record;
691
string out="\x03www\x04ds9a\x02nl";
692
string::size_type len = d_record.size();
693
d_record.resize(len + out.length());
694
memcpy(&d_record[len], out.c_str(), out.length());
703
string getName() const
705
return "iequals test";
708
void operator()() const
710
static string a("www.ds9a.nl"), b("www.lwn.net");
711
g_ret = boost::iequals(a, b);
718
string getName() const
720
return "pdns_iequals test";
723
void operator()() const
725
static string a("www.ds9a.nl"), b("www.lwn.net");
726
g_ret = pdns_iequals(a, b);
732
struct StrcasecmpTest
734
string getName() const
736
return "strcasecmp test";
739
void operator()() const
741
static string a("www.ds9a.nl"), b("www.lwn.net");
742
g_ret = strcasecmp(a.c_str(), b.c_str());
749
string getName() const
754
void operator()() const
762
int main(int argc, char** argv)
768
doRun(IEqualsTest());
769
doRun(MyIEqualsTest());
770
doRun(StrcasecmpTest());
772
doRun(StackMallocTest());
774
vector<uint8_t> packet = makeRootReferral();
775
doRun(ParsePacketBareTest(packet, "root-referral"));
776
doRun(ParsePacketTest(packet, "root-referral"));
778
doRun(RootRefTest());
780
doRun(EmptyQueryTest());
781
doRun(TypicalRefTest());
784
packet = makeEmptyQuery();
785
doRun(ParsePacketTest(packet, "empty-query"));
787
packet = makeTypicalReferral();
788
cerr<<"typical referral size: "<<packet.size()<<endl;
789
doRun(ParsePacketBareTest(packet, "typical-referral"));
791
doRun(ParsePacketTest(packet, "typical-referral"));
793
doRun(SimpleCompressTest("www.france.ds9a.nl"));
796
doRun(VectorExpandTest());
798
doRun(GetTimeTest());
800
doRun(GetLockUncontendedTest());
801
doRun(StaticMemberTest());
803
doRun(ARecordTest(1));
804
doRun(ARecordTest(2));
805
doRun(ARecordTest(4));
806
doRun(ARecordTest(64));
808
doRun(A2RecordTest(1));
809
doRun(A2RecordTest(2));
810
doRun(A2RecordTest(4));
811
doRun(A2RecordTest(64));
813
doRun(MakeStringFromCharStarTest());
814
doRun(MakeARecordTest());
815
doRun(MakeARecordTestMM());
817
doRun(AAAARecordTest(1));
818
doRun(AAAARecordTest(2));
819
doRun(AAAARecordTest(4));
820
doRun(AAAARecordTest(64));
822
doRun(TXTRecordTest(1));
823
doRun(TXTRecordTest(2));
824
doRun(TXTRecordTest(4));
825
doRun(TXTRecordTest(64));
827
doRun(GenericRecordTest(1, QType::NS, "powerdnssec1.ds9a.nl"));
828
doRun(GenericRecordTest(2, QType::NS, "powerdnssec1.ds9a.nl"));
829
doRun(GenericRecordTest(4, QType::NS, "powerdnssec1.ds9a.nl"));
830
doRun(GenericRecordTest(64, QType::NS, "powerdnssec1.ds9a.nl"));
834
doRun(SOARecordTest(1));
835
doRun(SOARecordTest(2));
836
doRun(SOARecordTest(4));
837
doRun(SOARecordTest(64));
839
cerr<<"Total runs: " << g_totalRuns<<endl;
842
catch(std::exception &e)
844
cerr<<"Fatal: "<<e.what()<<endl;