From bae1b0a23f54e56abf063e32c00cd036dfa1a0fe Mon Sep 17 00:00:00 2001 From: bert hubert Date: Thu, 25 Feb 2016 13:03:29 +0100 Subject: [PATCH] this commit uglifies DNSName escaped representation parsing for tremendous speedup (2x) during bulk zone loading from disk or database. Part of the uglification is that we now special case unescaped names, which are the vast majority of cases. Simultaneously, this moves us back to DNSName boost::container::string on non-Apple platforms, which delivered another 15% speedup on general operations Finally, an additional unit test is added. --- pdns/dnslabeltext.rl | 64 +++++++++++++++++++++++++---------------- pdns/dnsname.cc | 37 ++++++++++++++++++++---- pdns/dnsname.hh | 16 +++++++++-- pdns/test-dnsname_cc.cc | 3 ++ 4 files changed, 87 insertions(+), 33 deletions(-) diff --git a/pdns/dnslabeltext.rl b/pdns/dnslabeltext.rl index 21abd67448..fb3c3d210f 100644 --- a/pdns/dnslabeltext.rl +++ b/pdns/dnslabeltext.rl @@ -3,6 +3,7 @@ #include #include #include +#include "dnsname.hh" #include "namespaces.hh" namespace { @@ -81,79 +82,92 @@ vector segmentDNSText(const string& input ) return ret; }; -deque segmentDNSName(const string& input ) + +DNSName::string_t segmentDNSNameRaw(const char* realinput) { - // cerr<<"segmentDNSName("< ret; + DNSName::string_t ret; - string realinput; - if(input.empty() || input == ".") return ret; + if(!*realinput || *realinput == '.') { + ret.append(1, (char)0); + return ret; + } - if(input[input.size()-1]!='.') realinput=input+"."; // FIXME400 YOLO - else realinput=input; + unsigned int inputlen=strlen(realinput); + ret.reserve(inputlen+1); - const char *p = realinput.c_str(), *pe = realinput.c_str() + realinput.length(); + const char *p = realinput, *pe = realinput + inputlen; const char* eof = pe; int cs; char val = 0; - - string label; - label.reserve(10); + char labellen=0; + unsigned int lenpos=0; %%{ action labelEnd { - ret.push_back(label); - label.clear(); + ret[lenpos]=labellen; + labellen=0; } action labelBegin { - label.clear(); + lenpos=ret.size(); + ret.append(1, (char)0); + labellen=0; } action reportEscaped { char c = *fpc; - label.append(1, c); + ret.append(1, c); + labellen++; } action reportEscapedNumber { char c = *fpc; val *= 10; val += c-'0'; - } action doneEscapedNumber { - label.append(1, val); + ret.append(1, val); + labellen++; val=0; } action reportPlain { - label.append(1, *(fpc)); + ret.append(1, *(fpc)); + labellen++; } escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber)); plain = (extend-'\\'-'.') $ reportPlain; labelElement = escaped | plain; - main := ((labelElement+ '.') >labelBegin %labelEnd)+; + label = labelElement+ >labelBegin %labelEnd; + + main:= label ('.' label )* '.'?; + + #main := labelElement((labelElement+ '.') >labelBegin %labelEnd)+; + + # label = (plain | escaped | escdecb)+ >label_init %label_fin; + # dnsname := '.'? label ('.' label >label_sep)* '.'?; # Initialize and execute. write init; write exec; }%% - if ( cs < dnsname_first_final ) { - throw runtime_error("Unable to parse DNS name '"+input+"' ('"+realinput+"'): cs="+std::to_string(cs)); + if ( cs < dnsnameraw_first_final ) { + throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': cs="+std::to_string(cs)); } - + ret.append(1, (char)0); return ret; }; + #if 0 int main() { diff --git a/pdns/dnsname.cc b/pdns/dnsname.cc index ddc3998c07..94f7c542ab 100644 --- a/pdns/dnsname.cc +++ b/pdns/dnsname.cc @@ -17,19 +17,46 @@ std::ostream & operator<<(std::ostream &os, const DNSName& d) return os < 63) + throw std::range_error("label too long to append"); + + if(iter-pbegin > 254) // reserve two bytes, one for length and one for the root label + throw std::range_error("name too long to append"); + + d_storage[lenpos]=labellen; + } + d_storage.append(1, (char)0); + } + else + d_storage=segmentDNSNameRaw(p); } } + DNSName::DNSName(const char* pos, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed) { if (offset >= len) diff --git a/pdns/dnsname.hh b/pdns/dnsname.hh index 5c49c525f7..20b7d1c6e5 100644 --- a/pdns/dnsname.hh +++ b/pdns/dnsname.hh @@ -5,7 +5,11 @@ #include #include #include + +// it crashes on OSX.. +#ifndef __APPLE__ #include +#endif uint32_t burtleCI(const unsigned char* k, uint32_t lengh, uint32_t init); @@ -38,7 +42,7 @@ class DNSName public: DNSName() {} //!< Constructs an *empty* DNSName, NOT the root! explicit DNSName(const char* p); //!< Constructs from a human formatted, escaped presentation - explicit DNSName(const std::string& str) : DNSName(str.c_str()) {} //!< Constructs from a human formatted, escaped presentation + explicit DNSName(const std::string& str) : DNSName(str.c_str()) {}; //!< Constructs from a human formatted, escaped presentation DNSName(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=0, uint16_t* qclass=0, unsigned int* consumed=0); //!< Construct from a DNS Packet, taking the first question if offset=12 bool isPartOf(const DNSName& rhs) const; //!< Are we part of the rhs name? @@ -95,10 +99,14 @@ public: inline bool canonCompare(const DNSName& rhs) const; bool slowCanonCompare(const DNSName& rhs) const; -private: + +#ifdef __APPLE__ + typedef std::string string_t; +#else typedef boost::container::string string_t; - // typedef std::string string_t; +#endif +private: string_t d_storage; void packetParser(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=0, uint16_t* qclass=0, unsigned int* consumed=0, int depth=0); @@ -256,3 +264,5 @@ namespace std { size_t operator () (const DNSName& dn) const { return dn.hash(0); } }; } + +DNSName::string_t segmentDNSNameRaw(const char* input); // from ragel diff --git a/pdns/test-dnsname_cc.cc b/pdns/test-dnsname_cc.cc index a3cdb3969e..dc8a6388d5 100644 --- a/pdns/test-dnsname_cc.cc +++ b/pdns/test-dnsname_cc.cc @@ -176,7 +176,10 @@ BOOST_AUTO_TEST_CASE(test_trim) { } BOOST_AUTO_TEST_CASE(test_toolong) { + BOOST_CHECK_THROW(DNSName w("1234567890123456789012345678901234567890123456789012345678901234567890.com."), std::range_error); + + BOOST_CHECK_THROW(DNSName w("12345678901234567890.12345678901234567890123456.789012345678901.234567890.12345678901234567890.12345678901234567890123456.789012345678901.234567890.12345678901234567890.12345678901234567890123456.789012345678901.234567890.234567890.789012345678901.234567890.234567890.789012345678901.234567890.234567890.com."), std::range_error); } BOOST_AUTO_TEST_CASE(test_dnsstrings) { -- 2.47.2