From 2c9cf4e0e526a314898f1cb234891d4958d9abe7 Mon Sep 17 00:00:00 2001 From: Bert Hubert Date: Sat, 18 Dec 2010 20:40:04 +0000 Subject: [PATCH] first stab at all singing & dancing dnslabel class to replace our (ab)use of human readable strings to pass around DNS labels git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1752 d19b8d6e-7fed-0310-83ef-9ca221ded41b --- pdns/dnslabel.cc | 242 +++++++++++++++++++++++++++++++++++++++++++++++ pdns/dnslabel.hh | 91 ++++++++++++++++++ 2 files changed, 333 insertions(+) create mode 100644 pdns/dnslabel.cc create mode 100644 pdns/dnslabel.hh diff --git a/pdns/dnslabel.cc b/pdns/dnslabel.cc new file mode 100644 index 000000000..a3ef293d9 --- /dev/null +++ b/pdns/dnslabel.cc @@ -0,0 +1,242 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2010 Netherlabs Computer Consulting BV + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License version 2 + as published by the Free Software Foundation + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "dnslabel.hh" + +void DNSLabel::init(unsigned int len) +{ + d_capacity = len; + d_storage = new char[d_capacity]; + + d_fulllen = 0; + d_offset = 0; +} + +DNSLabel::DNSLabel(const DNSLabel& rhs) +{ + init(); + *this=rhs; +} + +DNSLabel::DNSLabel() +{ + init(); + appendChar(0); // "root" +} + +// FIXME: this should validate if 'raw' is a valid dns label! +DNSLabel::DNSLabel(const char*raw, unsigned int len) +{ + if(!validateStrict(raw, len)) + throw std::range_error("invalid raw label passed to DNSLabel"); + init(len); + memcpy(d_storage, raw, len); + d_fulllen = len; +} + +DNSLabel& DNSLabel::operator=(const DNSLabel& rhs) +{ + unsigned int newlen = rhs.getLength(); + if(newlen > d_capacity) { + delete[] d_storage; + d_storage = new char[newlen]; + } + d_fulllen = newlen; + d_offset=0; + memcpy(d_storage, rhs.d_storage, d_fulllen); + + return *this; +} + +DNSLabel::~DNSLabel() +{ + delete[] d_storage; +} + +DNSLabel::DNSLabel(const char* human) +{ + // FIXME: do the escaping thing + init(); + const char* labelStart=human; + const char* p; + for(p=human; *p; ++p) { + if(*p=='.') { + char labelLen = p - labelStart; + // cerr<<"input, labelLen: "<<(int)labelLen< (const unsigned char*)raw + maxLen) // beyond the end + return -1; + + if(*p > 64) // label length too long, or a compression pointer + return -1; + + if(!*p) { // final label, return bytes consumed + return 1 + (p - (const unsigned char*)raw); + } + + p += *p + 1; + } + return -1; // we should not get here, but if we do, it's bad +} + + +string DNSLabel::human() const +{ + // FIXME: do the escaping thing + const char* p = getStart(); + char labelLen; + + if(!*p) + return "."; + + string ret; + for(;;) { + labelLen = *p; + // cerr<<"human, labelLen: "<<(int) labelLen< +#include +#include +#include +#include +using std::string; +using std::cerr; +using std::endl; + + +/* the idea of dnslabel is that we guard our input, and from that point + * onwards, trust the contents of d_storage. + * + * On input we deal with escapes etc, on output we re-escape. + * This can be slow since we hope with all our might not to be + * using the 'human' interfaces too much, and keep everything as a + * native DNS label all the time. + * + * The goal for DNSLabel is to be 'holier than thou' and adhere + * to all relevant RFCs. This means implementing the really odd DNS case + * sensitivity rules, doing all the escaping properly and deal + * with embedded nuls. + * + * Design + * As a special speedup, we implement 'chopping' by having an offset + * counter. This means that the oft-repeated 'www.powerdns.com.' + * 'powerdns.com.', 'com.', '.' sequence does not involve any mallocs. + */ +class DNSLabel +{ + public: + explicit DNSLabel(const char* human); + explicit DNSLabel(const std::string& human); + DNSLabel(const char* raw, unsigned int length); + DNSLabel(const DNSLabel& rhs); + DNSLabel(); + ~DNSLabel(); + string human() const; + string binary() const; + bool endsOn(const DNSLabel& rhs) const; + bool chopOff(); + bool operator<(const DNSLabel& rhs) const; + bool operator==(const DNSLabel& rhs) const; + DNSLabel& operator=(const DNSLabel& rhs); + int project(char* target, unsigned int length); + static int validateConsume(const char* raw, unsigned int len); + static bool validateStrict(const char* raw, unsigned int len); + + static DNSLabel createFromBuffer(const char* raw, unsigned int* len); + private: + char* d_storage; + unsigned int d_fulllen; + unsigned int d_offset; + unsigned int d_capacity; + void init(unsigned int len=64); + unsigned int getLength() const + { + return d_fulllen - d_offset; + } + + const char* getStart() const + { + return d_storage + d_offset; + } + + void appendChar(char c) + { + if(d_fulllen == d_capacity) + expandCapacity(); + d_storage[d_fulllen++]= c; + } + void expandCapacity(); +}; -- 2.40.0