diff -Nru pdns-recursor-3.3/ahuexception.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/ahuexception.hh --- pdns-recursor-3.3/ahuexception.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/ahuexception.hh 2012-07-08 18:20:53.000000000 +0000 @@ -22,7 +22,7 @@ #include -using namespace std; +#include "namespaces.hh" //! Generic Exception thrown class AhuException diff -Nru pdns-recursor-3.3/arguments.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/arguments.hh --- pdns-recursor-3.3/arguments.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/arguments.hh 2012-07-08 18:20:53.000000000 +0000 @@ -32,7 +32,7 @@ # include #endif -using namespace std; +#include "namespaces.hh" typedef AhuException ArgException; @@ -94,7 +94,7 @@ bool mustDo(const string &var); //!< if a switch is given, if we must do something (--help) int asNum(const string &var); //!< return a variable value as a number #ifndef WIN32 - mode_t asMode(const string &var); // #include #include "base32.hh" -using namespace std; +#include "namespaces.hh" /* based on freebsd:src/contrib/opie/libopie/btoe.c extract: get bit ranges from a char* */ uint32_t extract_bits(const char *s, int start, int length) @@ -112,7 +112,7 @@ toWrite = 0; } } - ret.append(block, (7+toWrite*5)/8); // round up + ret.append(block, (toWrite*5)/8); return ret; } diff -Nru pdns-recursor-3.3/base64.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/base64.cc --- pdns-recursor-3.3/base64.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/base64.cc 2012-07-08 18:20:53.000000000 +0000 @@ -109,7 +109,7 @@ // incoming Base64 character is first decoded, and // then it is inserted into the decode buffer // (with any relevant shifting, as required). - // Later, after all 3 bytes have been reconsituted, + // Later, after all 3 bytes have been reconstituted, // we assign them to the output string, ultimately // to be returned as the original message. int iInSize = strInput.size(); @@ -124,7 +124,8 @@ // Decode a character if(strInput.at(iInNum)=='=') pad++; - + while(isspace(strInput.at(iInNum))) + iInNum++; cChar = B64Decode1(strInput.at(iInNum++)); } // if diff -Nru pdns-recursor-3.3/cachecleaner.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/cachecleaner.hh --- pdns-recursor-3.3/cachecleaner.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/cachecleaner.hh 2012-07-08 18:20:53.000000000 +0000 @@ -11,7 +11,7 @@ unsigned int cacheSize=collection.size(); - if(maxCached && cacheSize > maxCached) { + if(cacheSize > maxCached) { toTrim = cacheSize - maxCached; } diff -Nru pdns-recursor-3.3/config.h pdns-recursor-3.5.pre.20120708.2673~crass~precise/config.h --- pdns-recursor-3.3/config.h 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/config.h 2012-07-08 18:20:53.000000000 +0000 @@ -1,4 +1,4 @@ #define SYSCONFDIR "/etc/powerdns/" #define LOCALSTATEDIR "/var/run/" -#define VERSION "3.3" +#define VERSION "3.5-pre" #define RECURSOR diff -Nru pdns-recursor-3.3/debian/changelog pdns-recursor-3.5.pre.20120708.2673~crass~precise/debian/changelog --- pdns-recursor-3.3/debian/changelog 2011-08-08 09:57:13.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/debian/changelog 2012-07-10 20:01:40.000000000 +0000 @@ -1,3 +1,9 @@ +pdns-recursor (3.5.pre.20120708.2673~crass~precise) precise; urgency=low + + * Upstream snapshot + + -- Glenn Washburn Tue, 10 Jul 2012 15:01:40 +0000 + pdns-recursor (3.3-2) unstable; urgency=low * Fix my name in the init script and debian/control too. diff -Nru pdns-recursor-3.3/debian/patches/series pdns-recursor-3.5.pre.20120708.2673~crass~precise/debian/patches/series --- pdns-recursor-3.3/debian/patches/series 2010-11-06 10:29:26.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/debian/patches/series 2012-07-10 18:14:12.000000000 +0000 @@ -1,4 +1 @@ do-not-strip-binaries -kfreebsd-ftbfs-patch -pdns-recursor-less-chatty -hurd-ftbfs-patch diff -Nru pdns-recursor-3.3/devpollmplexer.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/devpollmplexer.cc --- pdns-recursor-3.3/devpollmplexer.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/devpollmplexer.cc 2012-07-08 18:20:53.000000000 +0000 @@ -8,7 +8,7 @@ #include "syncres.hh" #include "namespaces.hh" -using namespace std; +#include "namespaces.hh" class DevPollFDMultiplexer : public FDMultiplexer { diff -Nru pdns-recursor-3.3/dns.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/dns.cc --- pdns-recursor-3.3/dns.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/dns.cc 2012-07-08 18:20:53.000000000 +0000 @@ -1,5 +1,6 @@ #include "dns.hh" #include "misc.hh" +#include "arguments.hh" #include #include #include @@ -9,7 +10,7 @@ { unsigned char n = 0; for(n = 0 ; n < labellen; ++n) - if(begin[n] == '.' || begin[n] == '\\') + if(begin[n] == '.' || begin[n] == '\\' || begin[n] == ' ') break; if( n == labellen) { @@ -19,6 +20,7 @@ string label(begin, labellen); boost::replace_all(label, "\\", "\\\\"); boost::replace_all(label, ".", "\\."); + boost::replace_all(label, " ", "\\032"); ret.append(label); } @@ -48,7 +50,7 @@ //! compares two dns packets, skipping the header, but including the question and the qtype bool dnspacketLessThan(const std::string& a, const std::string& b) { - if(a.length() < 12 || b.length() < 12) + if(a.length() <= 12 || b.length() <= 12) return a.length() < b.length(); // throw runtime_error("Error parsing question in dnspacket comparison: packet too short"); @@ -123,3 +125,80 @@ // cerr << "returning: '"<parts; + stringtok(parts,content); + int pleft=parts.size(); + + // cout<<"'"<1) + data.hostmaster=attodot(parts[1]); // ahu@ds9a.nl -> ahu.ds9a.nl, piet.puk@ds9a.nl -> piet\.puk.ds9a.nl + + if(pleft>2) + data.serial=strtoul(parts[2].c_str(), NULL, 10); + + if(pleft>3) + data.refresh=atoi(parts[3].c_str()); + + if(pleft>4) + data.retry=atoi(parts[4].c_str()); + + if(pleft>5) + data.expire=atoi(parts[5].c_str()); + + if(pleft>6) + data.default_ttl=atoi(parts[6].c_str()); + +} + +string serializeSOAData(const SOAData &d) +{ + ostringstream o; + // nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ] + o<((int)rcode); +} diff -Nru pdns-recursor-3.3/dns.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/dns.hh --- pdns-recursor-3.3/dns.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/dns.hh 2012-07-08 18:20:53.000000000 +0000 @@ -1,6 +1,6 @@ /* PowerDNS Versatile Database Driven Nameserver - Copyright (C) 2002 PowerDNS.COM BV + Copyright (C) 2002 - 2011 PowerDNS.COM 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 @@ -16,7 +16,7 @@ along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ -// $Id: dns.hh 1554 2010-04-18 12:24:37Z ahu $ +// $Id: dns.hh 2589 2012-04-29 13:02:29Z peter $ /* (C) 2002 POWERDNS.COM BV */ #ifndef DNS_HH #define DNS_HH @@ -25,6 +25,10 @@ #include #include #include +#include +#include + + #include "utility.hh" #include "qtype.hh" #include @@ -44,13 +48,14 @@ uint32_t default_ttl; int domain_id; DNSBackend *db; + uint8_t scopeMask; }; class RCode { public: - enum rcodes_ { NoError=0, FormErr=1, ServFail=2, NXDomain=3, NotImp=4, Refused=5 }; + enum rcodes_ { NoError=0, FormErr=1, ServFail=2, NXDomain=3, NotImp=4, Refused=5, NotAuth=9 }; }; class Opcode @@ -63,12 +68,9 @@ class DNSResourceRecord { public: - DNSResourceRecord() : qclass(1), priority(0), d_place(ANSWER) {}; + DNSResourceRecord() : qclass(1), priority(0), last_modified(0), d_place(ANSWER), auth(1), scopeMask(0) {}; ~DNSResourceRecord(){}; - string serialize() const; - int unSerialize(const string &str); - // data QType qtype; //!< qtype of this record, ie A, CNAME, MX etc @@ -76,7 +78,7 @@ string qname; //!< the name of this record, for example: www.powerdns.com string wildcardname; string content; //!< what this record points to. Example: 10.1.2.3 - uint16_t priority; //!< For qtype's that support a priority or preference. Currently only MX + uint16_t priority; //!< For qtypes that support a priority or preference (MX, SRV) uint32_t ttl; //!< Time To Live of this record int domain_id; //!< If a backend implements this, the domain_id of the zone this record is in time_t last_modified; //!< For autocalculating SOA serial numbers - the backend needs to fill this in @@ -84,6 +86,23 @@ Place d_place; //!< This specifies where a record goes within the packet bool auth; + uint8_t scopeMask; + + template + void serialize(Archive & ar, const unsigned int version) + { + ar & qtype; + ar & qclass; + ar & qname; + ar & wildcardname; + ar & content; + ar & priority; + ar & ttl; + ar & domain_id; + ar & last_modified; + ar & d_place; + ar & auth; + } bool operator<(const DNSResourceRecord &b) const { @@ -93,9 +112,6 @@ return(content < b.content); return false; } - -private: - string escape(const string &str) const; }; #ifdef _MSC_VER @@ -163,8 +179,15 @@ ns_t_cert = 37, /* Certification record */ ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */ ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */ - ns_t_sink = 40, /* Kitchen sink (experimentatl) */ + ns_t_sink = 40, /* Kitchen sink (experimental) */ ns_t_opt = 41, /* EDNS0 option (meta-RR) */ + ns_t_ds = 43, /* Delegation signer */ + ns_t_rrsig = 46, /* Resoure Record signature */ + ns_t_nsec = 47, /* Next Record */ + ns_t_dnskey = 48, /* DNSKEY record */ + ns_t_nsec3 = 50, /* Next Record v3 */ + ns_t_nsec3param = 51, /* NSEC Parameters */ + ns_t_tlsa = 52, /* TLSA */ ns_t_tsig = 250, /* Transaction signature. */ ns_t_ixfr = 251, /* Incremental zone transfer. */ ns_t_axfr = 252, /* Transfer zone of authority. */ @@ -176,7 +199,7 @@ #ifdef WIN32 #define BYTE_ORDER 1 #define LITTLE_ENDIAN 1 -#elif __FreeBSD__ || __APPLE__ +#elif __FreeBSD__ || __APPLE__ || __OpenBSD__ #include #elif __linux__ # include @@ -253,4 +276,12 @@ extern time_t s_starttime; std::string questionExpand(const char* packet, uint16_t len, uint16_t& type); bool dnspacketLessThan(const std::string& a, const std::string& b); + +/** helper function for both DNSPacket and addSOARecord() - converts a line into a struct, for easier parsing */ +void fillSOAData(const string &content, SOAData &data); + +/** for use by DNSPacket, converts a SOAData class to a ascii line again */ +string serializeSOAData(const SOAData &data); +string &attodot(string &str); //!< for when you need to insert an email address in the SOA +string strrcode(unsigned char rcode); #endif diff -Nru pdns-recursor-3.3/dnslabeltext.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnslabeltext.cc --- pdns-recursor-3.3/dnslabeltext.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnslabeltext.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,475 @@ + +#line 1 "dnslabeltext.rl" +#include +#include +#include +#include +#include +#include "namespaces.hh" + + +namespace { +void appendSplit(vector& ret, string& segment, char c) +{ + if(segment.size()>254) { + ret.push_back(segment); + segment.clear(); + } + segment.append(1, c); +} +} + +vector segmentDNSText(const string& input ) +{ + +#line 26 "dnslabeltext.cc" +static const char _dnstext_actions[] = { + 0, 1, 0, 1, 1, 1, 2, 1, + 3, 1, 4, 1, 5, 2, 0, 1, + 2, 4, 5 +}; + +static const char _dnstext_key_offsets[] = { + 0, 0, 1, 7, 11, 13, 15, 21, + 25 +}; + +static const char _dnstext_trans_keys[] = { + 34, 34, 92, 9, 10, 32, 126, 34, + 92, 48, 57, 48, 57, 48, 57, 34, + 92, 9, 10, 32, 126, 32, 34, 9, + 13, 34, 0 +}; + +static const char _dnstext_single_lengths[] = { + 0, 1, 2, 2, 0, 0, 2, 2, + 1 +}; + +static const char _dnstext_range_lengths[] = { + 0, 0, 2, 1, 1, 1, 2, 1, + 0 +}; + +static const char _dnstext_index_offsets[] = { + 0, 0, 2, 7, 11, 13, 15, 20, + 24 +}; + +static const char _dnstext_trans_targs[] = { + 2, 0, 7, 3, 2, 2, 0, 2, + 2, 4, 0, 5, 0, 6, 0, 7, + 3, 2, 2, 0, 8, 2, 8, 0, + 2, 0, 0 +}; + +static const char _dnstext_trans_actions[] = { + 3, 0, 0, 0, 11, 11, 0, 5, + 5, 7, 0, 7, 0, 7, 0, 9, + 9, 16, 16, 0, 0, 13, 0, 0, + 13, 0, 0 +}; + +static const char _dnstext_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 1 +}; + +static const int dnstext_start = 1; +static const int dnstext_first_final = 7; +static const int dnstext_error = 0; + +static const int dnstext_en_main = 1; + + +#line 25 "dnslabeltext.rl" + + (void)dnstext_error; // silence warnings + (void)dnstext_en_main; + const char *p = input.c_str(), *pe = input.c_str() + input.length(); + const char* eof = pe; + int cs; + char val = 0; + + string segment; + vector ret; + + +#line 99 "dnslabeltext.cc" + { + cs = dnstext_start; + } + +#line 104 "dnslabeltext.cc" + { + int _klen; + unsigned int _trans; + const char *_acts; + unsigned int _nacts; + const char *_keys; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _dnstext_trans_keys + _dnstext_key_offsets[cs]; + _trans = _dnstext_index_offsets[cs]; + + _klen = _dnstext_single_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + _klen - 1; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + ((_upper-_lower) >> 1); + if ( (*p) < *_mid ) + _upper = _mid - 1; + else if ( (*p) > *_mid ) + _lower = _mid + 1; + else { + _trans += (_mid - _keys); + goto _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _dnstext_range_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + (_klen<<1) - 2; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + (((_upper-_lower) >> 1) & ~1); + if ( (*p) < _mid[0] ) + _upper = _mid - 2; + else if ( (*p) > _mid[1] ) + _lower = _mid + 2; + else { + _trans += ((_mid - _keys)>>1); + goto _match; + } + } + _trans += _klen; + } + +_match: + cs = _dnstext_trans_targs[_trans]; + + if ( _dnstext_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _dnstext_actions + _dnstext_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) + { + switch ( *_acts++ ) + { + case 0: +#line 37 "dnslabeltext.rl" + { + ret.push_back(segment); + segment.clear(); + } + break; + case 1: +#line 41 "dnslabeltext.rl" + { + segment.clear(); + } + break; + case 2: +#line 45 "dnslabeltext.rl" + { + char c = *p; + appendSplit(ret, segment, c); + } + break; + case 3: +#line 49 "dnslabeltext.rl" + { + char c = *p; + val *= 10; + val += c-'0'; + + } + break; + case 4: +#line 55 "dnslabeltext.rl" + { + appendSplit(ret, segment, val); + val=0; + } + break; + case 5: +#line 60 "dnslabeltext.rl" + { + appendSplit(ret, segment, *(p)); + } + break; +#line 219 "dnslabeltext.cc" + } + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + const char *__acts = _dnstext_actions + _dnstext_eof_actions[cs]; + unsigned int __nacts = (unsigned int) *__acts++; + while ( __nacts-- > 0 ) { + switch ( *__acts++ ) { + case 0: +#line 37 "dnslabeltext.rl" + { + ret.push_back(segment); + segment.clear(); + } + break; +#line 242 "dnslabeltext.cc" + } + } + } + + _out: {} + } + +#line 73 "dnslabeltext.rl" + + + if ( cs < dnstext_first_final ) { + throw runtime_error("Unable to parse DNS TXT '"+input+"'"); + } + + return ret; +}; +string segmentDNSLabel(const string& input ) +{ + +#line 262 "dnslabeltext.cc" +static const char _dnslabel_actions[] = { + 0, 1, 0, 1, 1, 1, 2, 1, + 3, 1, 4, 2, 3, 0, 2, 3, + 4 +}; + +static const char _dnslabel_key_offsets[] = { + 0, 0, 4, 8, 10, 12, 16 +}; + +static const char _dnslabel_trans_keys[] = { + 46, 92, 32, 126, 46, 92, 48, 57, + 48, 57, 48, 57, 46, 92, 32, 126, + 46, 92, 32, 126, 0 +}; + +static const char _dnslabel_single_lengths[] = { + 0, 2, 2, 0, 0, 2, 2 +}; + +static const char _dnslabel_range_lengths[] = { + 0, 1, 1, 1, 1, 1, 1 +}; + +static const char _dnslabel_index_offsets[] = { + 0, 0, 4, 8, 10, 12, 16 +}; + +static const char _dnslabel_trans_targs[] = { + 6, 2, 1, 0, 1, 1, 3, 0, + 4, 0, 5, 0, 6, 2, 1, 0, + 6, 2, 1, 0, 0 +}; + +static const char _dnslabel_trans_actions[] = { + 1, 0, 9, 0, 3, 3, 5, 0, + 5, 0, 5, 0, 11, 7, 14, 0, + 1, 0, 9, 0, 0 +}; + +static const int dnslabel_start = 1; +static const int dnslabel_first_final = 6; +static const int dnslabel_error = 0; + +static const int dnslabel_en_main = 1; + + +#line 86 "dnslabeltext.rl" + + (void)dnslabel_error; // silence warnings + (void)dnslabel_en_main; + const char *p = input.c_str(), *pe = input.c_str() + input.length(); + //const char* eof = pe; + int cs; + char val = 0; + + string ret; + string segment; + + +#line 323 "dnslabeltext.cc" + { + cs = dnslabel_start; + } + +#line 328 "dnslabeltext.cc" + { + int _klen; + unsigned int _trans; + const char *_acts; + unsigned int _nacts; + const char *_keys; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _dnslabel_trans_keys + _dnslabel_key_offsets[cs]; + _trans = _dnslabel_index_offsets[cs]; + + _klen = _dnslabel_single_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + _klen - 1; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + ((_upper-_lower) >> 1); + if ( (*p) < *_mid ) + _upper = _mid - 1; + else if ( (*p) > *_mid ) + _lower = _mid + 1; + else { + _trans += (_mid - _keys); + goto _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _dnslabel_range_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + (_klen<<1) - 2; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + (((_upper-_lower) >> 1) & ~1); + if ( (*p) < _mid[0] ) + _upper = _mid - 2; + else if ( (*p) > _mid[1] ) + _lower = _mid + 2; + else { + _trans += ((_mid - _keys)>>1); + goto _match; + } + } + _trans += _klen; + } + +_match: + cs = _dnslabel_trans_targs[_trans]; + + if ( _dnslabel_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _dnslabel_actions + _dnslabel_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) + { + switch ( *_acts++ ) + { + case 0: +#line 98 "dnslabeltext.rl" + { + printf("Segment end, segment = '%s'\n", segment.c_str()); + ret.append(1, (unsigned char)segment.size()); + ret.append(segment); + segment.clear(); + } + break; + case 1: +#line 105 "dnslabeltext.rl" + { + printf("'\\%c' ", *p); + segment.append(1, *p); + } + break; + case 2: +#line 109 "dnslabeltext.rl" + { + char c = *p; + val *= 10; + val += c-'0'; + + } + break; + case 3: +#line 115 "dnslabeltext.rl" + { + printf("_%c_ ", val); + segment.append(1, val); + val=0; + } + break; + case 4: +#line 121 "dnslabeltext.rl" + { + printf("'%c' ", *p); + segment.append(1, *p); + } + break; +#line 441 "dnslabeltext.cc" + } + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + _out: {} + } + +#line 136 "dnslabeltext.rl" + + + if ( cs < dnslabel_first_final ) { + throw runtime_error("Unable to parse DNS Label '"+input+"'"); + } + + if(ret.empty() || ret[0] != 0) + ret.append(1, 0); + return ret; +}; +#if 0 +int main() +{ + //char blah[]="\"blah\" \"bleh\" \"bloeh\\\"bleh\" \"\\97enzo\""; + char blah[]="\"v=spf1 ip4:67.106.74.128/25 ip4:63.138.42.224/28 ip4:65.204.46.224/27 \\013\\010ip4:66.104.217.176/28 \\013\\010ip4:209.48.147.0/27 ~all\""; + //char blah[]="\"abc \\097\\098 def\""; + printf("Input: '%s'\n", blah); + vector res=dnstext(blah); + cerr<second(content); } - DNSRecordContent::typemap_t& DNSRecordContent::getTypemap() { static DNSRecordContent::typemap_t typemap; return typemap; } -DNSRecordContent::namemap_t& DNSRecordContent::getNamemap() +DNSRecordContent::n2typemap_t& DNSRecordContent::getN2Typemap() +{ + static DNSRecordContent::n2typemap_t n2typemap; + return n2typemap; +} + +DNSRecordContent::t2namemap_t& DNSRecordContent::getT2Namemap() { - static DNSRecordContent::namemap_t namemap; - return namemap; + static DNSRecordContent::t2namemap_t t2namemap; + return t2namemap; } + DNSRecordContent::zmakermap_t& DNSRecordContent::getZmakermap() { static DNSRecordContent::zmakermap_t zmakermap; return zmakermap; } - - void MOADNSParser::init(const char *packet, unsigned int len) { if(len < sizeof(dnsheader)) @@ -264,7 +266,7 @@ } #endif } - catch(out_of_range &re) { + catch(std::out_of_range &re) { if(validPacket && d_header.tc) { // don't sweat it over truncated packets, but do adjust an, ns and arcount if(n < d_header.ancount) { d_header.ancount=n; d_header.nscount = d_header.arcount = 0; @@ -317,7 +319,7 @@ void PacketReader::copyRecord(unsigned char* dest, uint16_t len) { if(d_pos + len > d_content.size()) - throw MOADNSException("Attempt to copy outside of packet"); + throw std::out_of_range("Attempt to copy outside of packet"); memcpy(dest, &d_content.at(d_pos), len); d_pos+=len; @@ -388,7 +390,10 @@ string ret; for(string::const_iterator i=name.begin();i!=name.end();++i) - if(*i=='"' || *i=='\\'){ + if(*i=='\n') { // XXX FIXME this should do a way better job! + ret += "\\010"; + } + else if(*i=='"' || *i=='\\'){ ret += '\\'; ret += *i; } @@ -445,9 +450,15 @@ // XXX FIXME THIS MIGHT BE VERY SLOW! ret.reserve(ret.size() + labellen + 2); for(string::size_type n = 0 ; n < labellen; ++n, frompos++) { - if(content.at(frompos)=='.' || content.at(frompos)=='\\') + if(content.at(frompos)=='.' || content.at(frompos)=='\\') { ret.append(1, '\\'); - ret.append(1, content[frompos]); + ret.append(1, content[frompos]); + } + else if(content.at(frompos)==' ') { + ret+="\\032"; + } + else + ret.append(1, content[frompos]); } ret.append(1,'.'); } @@ -456,7 +467,7 @@ void PacketReader::xfrBlob(string& blob) { - if(d_recordlen) + if(d_recordlen && !(d_pos == (d_startrecordpos + d_recordlen))) blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1); else blob.clear(); @@ -476,7 +487,7 @@ } -void PacketReader::xfrHexBlob(string& blob) +void PacketReader::xfrHexBlob(string& blob, bool keepReading) { xfrBlob(blob); } @@ -574,7 +585,7 @@ { d_notyouroffset += by; if(d_notyouroffset > d_packet.length()) - throw range_error("dns packet out of range: "+lexical_cast(d_notyouroffset) +" > " + throw std::out_of_range("dns packet out of range: "+lexical_cast(d_notyouroffset) +" > " + lexical_cast(d_packet.length()) ); } std::string& d_packet; @@ -587,16 +598,17 @@ // method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it void ageDNSPacket(std::string& packet, uint32_t seconds) { - if(packet.length() < 12) + if(packet.length() < sizeof(dnsheader)) return; try { - const dnsheader* dh = (const dnsheader*)packet.c_str(); - int numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount); + dnsheader dh; + memcpy((void*)&dh, (const dnsheader*)packet.c_str(), sizeof(dh)); + int numrecords = ntohs(dh.ancount) + ntohs(dh.nscount) + ntohs(dh.arcount); DNSPacketMangler dpm(packet); int n; - for(n=0; n < ntohs(dh->qdcount) ; ++n) { + for(n=0; n < ntohs(dh.qdcount) ; ++n) { dpm.skipLabel(); dpm.skipBytes(4); // qtype, qclass } diff -Nru pdns-recursor-3.3/dnsparser.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnsparser.hh --- pdns-recursor-3.3/dnsparser.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnsparser.hh 2012-07-08 18:20:53.000000000 +0000 @@ -1,6 +1,6 @@ /* PowerDNS Versatile Database Driven Nameserver - Copyright (C) 2005 - 2010 PowerDNS.COM BV + Copyright (C) 2005 - 2011 PowerDNS.COM 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 @@ -47,7 +47,7 @@ And we might be able to reverse 2 -> 3 as well */ -using namespace std; +#include "namespaces.hh" #include "namespaces.hh" class MOADNSException : public runtime_error @@ -64,8 +64,10 @@ { public: PacketReader(const vector& content) - : d_pos(0), d_content(content) - {} + : d_pos(0), d_startrecordpos(0), d_content(content) + { + d_recordlen = content.size(); + } uint32_t get32BitInt(); uint16_t get16BitInt(); @@ -119,7 +121,7 @@ void xfrBlob(string& blob); void xfrBlob(string& blob, int length); - void xfrHexBlob(string& blob); + void xfrHexBlob(string& blob, bool keepReading=false); static uint16_t get16BitInt(const vector&content, uint16_t& pos); static void getLabelFromContent(const vector& content, uint16_t& frompos, string& ret, int recurs); @@ -135,7 +137,7 @@ private: uint16_t d_startrecordpos; // needed for getBlob later on - uint16_t d_recordlen; // dito + uint16_t d_recordlen; // ditto const vector& d_content; }; @@ -150,7 +152,7 @@ virtual std::string getZoneRepresentation() const = 0; virtual ~DNSRecordContent() {} virtual void toPacket(DNSPacketWriter& pw)=0; - virtual string serialize(const string& qname, bool canonic=false) // it would rock if this were const, but it is too hard + virtual string serialize(const string& qname, bool canonic=false, bool lowerCase=false) // it would rock if this were const, but it is too hard { vector packet; string empty; @@ -158,6 +160,9 @@ if(canonic) pw.setCanonic(true); + if(lowerCase) + pw.setLowercase(true); + pw.startRecord(qname, d_qtype); this->toPacket(pw); pw.commit(); @@ -184,7 +189,8 @@ if(z) getZmakermap()[make_pair(cl,ty)]=z; - getNamemap()[make_pair(cl,ty)]=name; + getT2Namemap().insert(make_pair(make_pair(cl,ty), name)); + getN2Typemap().insert(make_pair(name, make_pair(cl,ty))); } static void unregist(uint16_t cl, uint16_t ty) @@ -196,19 +202,23 @@ static uint16_t TypeToNumber(const string& name) { - for(namemap_t::const_iterator i=getNamemap().begin(); i!=getNamemap().end();++i) - if(pdns_iequals(i->second, name)) - return i->first.second; - + n2typemap_t::const_iterator iter = getN2Typemap().find(toUpper(name)); + if(iter != getN2Typemap().end()) + return iter->second.second; + + if(boost::starts_with(name, "TYPE")) + return atoi(name.c_str()+4); + throw runtime_error("Unknown DNS type '"+name+"'"); } static const string NumberToType(uint16_t num, uint16_t classnum=1) { - if(!getNamemap().count(make_pair(classnum,num))) - return "#" + lexical_cast(num); + t2namemap_t::const_iterator iter = getT2Namemap().find(make_pair(classnum, num)); + if(iter == getT2Namemap().end()) + return "TYPE" + lexical_cast(num); // throw runtime_error("Unknown DNS type with numerical id "+lexical_cast(num)); - return getNamemap()[make_pair(classnum,num)]; + return iter->second; } explicit DNSRecordContent(uint16_t type) : d_qtype(type) @@ -229,10 +239,11 @@ protected: typedef std::map, makerfunc_t* > typemap_t; typedef std::map, zmakerfunc_t* > zmakermap_t; - typedef std::map, string > namemap_t; - + typedef std::map, string > t2namemap_t; + typedef std::map > n2typemap_t; static typemap_t& getTypemap(); - static namemap_t& getNamemap(); + static t2namemap_t& getT2Namemap(); + static n2typemap_t& getN2Typemap(); static zmakermap_t& getZmakermap(); }; @@ -298,7 +309,7 @@ dnsheader d_header; string d_qname; uint16_t d_qclass, d_qtype; - uint8_t d_rcode; + //uint8_t d_rcode; typedef vector > answers_t; diff -Nru pdns-recursor-3.3/dns_random.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/dns_random.cc --- pdns-recursor-3.3/dns_random.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/dns_random.cc 2012-07-08 18:20:53.000000000 +0000 @@ -13,6 +13,8 @@ static unsigned char g_counter[16]; static uint32_t g_in; +static bool g_initialized; + void dns_random_init(const char data[16]) { aes_init(); @@ -24,6 +26,8 @@ memcpy(g_counter, &now.tv_usec, sizeof(now.tv_usec)); memcpy(g_counter+sizeof(now.tv_usec), &now.tv_sec, sizeof(now.tv_sec)); g_in = getpid() | (getppid()<<16); + + g_initialized = true; srandom(dns_random(numeric_limits::max())); } @@ -50,6 +54,8 @@ unsigned int dns_random(unsigned int n) { + if(!g_initialized) + abort(); uint32_t out; aes_ctr_encrypt((unsigned char*) &g_in, (unsigned char*)& out, sizeof(g_in), g_counter, counterIncrement, &g_cx); return out % n; diff -Nru pdns-recursor-3.3/dnsrecords.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnsrecords.cc --- pdns-recursor-3.3/dnsrecords.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnsrecords.cc 2012-07-08 18:20:53.000000000 +0000 @@ -18,6 +18,7 @@ #include "utility.hh" #include "dnsrecords.hh" +#include boilerplate_conv(A, ns_t_a, conv.xfrIP(d_ip)); @@ -61,7 +62,7 @@ static DNSRecordContent* make(const string& zone) { AAAARecordContent *ar=new AAAARecordContent(); - if(Utility::inet_pton( AF_INET6, zone.c_str(), static_cast< void * >( ar->d_ip6 )) < 0) + if(Utility::inet_pton( AF_INET6, zone.c_str(), static_cast< void * >( ar->d_ip6 )) <= 0) throw MOADNSException("Asked to encode '"+zone+"' as an IPv6 address, but does not parse"); return ar; } @@ -114,8 +115,8 @@ string::size_type pos=0; uint16_t code, len; while(d_data.size() >= 4 + pos) { - code = 0xff * d_data[pos] + d_data[pos+1]; - len = 0xff * d_data[pos+2] + d_data[pos+3]; + code = 256 * (unsigned char)d_data[pos] + (unsigned char)d_data[pos+1]; + len = 256 * (unsigned char)d_data[pos+2] + (unsigned char)d_data[pos+3]; pos+=4; if(pos + len > d_data.size()) @@ -221,15 +222,32 @@ conv.xfr8BitInt(d_algorithm); conv.xfrBlob(d_certificate); ) + +boilerplate_conv(TLSA, 52, + conv.xfr8BitInt(d_certusage); + conv.xfr8BitInt(d_selector); + conv.xfr8BitInt(d_matchtype); + conv.xfrHexBlob(d_cert, true); + ) + #undef DS DSRecordContent::DSRecordContent() : DNSRecordContent(43) {} boilerplate_conv(DS, 43, conv.xfr16BitInt(d_tag); conv.xfr8BitInt(d_algorithm); conv.xfr8BitInt(d_digesttype); - conv.xfrHexBlob(d_digest); + conv.xfrHexBlob(d_digest, true); // keep reading across spaces ) +DLVRecordContent::DLVRecordContent() : DNSRecordContent(32769) {} +boilerplate_conv(DLV,32769 , + conv.xfr16BitInt(d_tag); + conv.xfr8BitInt(d_algorithm); + conv.xfr8BitInt(d_digesttype); + conv.xfrHexBlob(d_digest, true); // keep reading across spaces + ) + + boilerplate_conv(SSHFP, 44, conv.xfr8BitInt(d_algorithm); conv.xfr8BitInt(d_fptype); @@ -240,7 +258,6 @@ conv.xfrType(d_type); conv.xfr8BitInt(d_algorithm); conv.xfr8BitInt(d_labels); - conv.xfr32BitInt(d_originalttl); conv.xfrTime(d_sigexpire); conv.xfrTime(d_siginception); @@ -274,35 +291,6 @@ return ac & 0xFFFF; } -void DNSKEYRecordContent::getExpLen(uint16_t& startPos, uint16_t& expLen) const -{ - unsigned char* decoded=(unsigned char*) d_key.c_str(); - if(decoded[0] != 0) { - startPos=1; - expLen=decoded[0]; - } - else { - startPos=3; - expLen=decoded[1]*0xff + decoded[2]; // XXX FIXME - } -} - -string DNSKEYRecordContent::getExponent() const -{ - uint16_t startPos, expLen; - getExpLen(startPos, expLen); - return d_key.substr(startPos, expLen); -} - -string DNSKEYRecordContent::getModulus() const -{ - uint16_t startPos, expLen; - getExpLen(startPos, expLen); - - return d_key.substr(startPos+expLen); -} - - // "fancy records" boilerplate_conv(URL, QType::URL, conv.xfrLabel(d_url); @@ -312,29 +300,32 @@ conv.xfrLabel(d_mboxfw); ) + + bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo) { - if(mdp.d_header.arcount && !mdp.d_answers.empty() && - mdp.d_answers.back().first.d_type == QType::OPT) { - eo->d_packetsize=mdp.d_answers.back().first.d_class; - - EDNS0Record stuff; - uint32_t ttl=ntohl(mdp.d_answers.back().first.d_ttl); - memcpy(&stuff, &ttl, sizeof(stuff)); - - eo->d_extRCode=stuff.extRCode; - eo->d_version=stuff.version; - eo->d_Z = ntohs(stuff.Z); - OPTRecordContent* orc = - dynamic_cast(mdp.d_answers.back().first.d_content.get()); - if(!orc) - return false; - orc->getData(eo->d_options); - - return true; + if(mdp.d_header.arcount && !mdp.d_answers.empty()) { + BOOST_FOREACH(const MOADNSParser::answers_t::value_type& val, mdp.d_answers) { + if(val.first.d_place == DNSRecord::Additional && val.first.d_type == QType::OPT) { + eo->d_packetsize=val.first.d_class; + + EDNS0Record stuff; + uint32_t ttl=ntohl(val.first.d_ttl); + memcpy(&stuff, &ttl, sizeof(stuff)); + + eo->d_extRCode=stuff.extRCode; + eo->d_version=stuff.version; + eo->d_Z = ntohs(stuff.Z); + OPTRecordContent* orc = + dynamic_cast(val.first.d_content.get()); + if(!orc) + return false; + orc->getData(eo->d_options); + return true; + } + } } - else - return false; + return false; } @@ -370,6 +361,8 @@ NSECRecordContent::report(); NSEC3RecordContent::report(); NSEC3PARAMRecordContent::report(); + TLSARecordContent::report(); + DLVRecordContent::report(); DNSRecordContent::regist(0xff, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG"); OPTRecordContent::report(); } diff -Nru pdns-recursor-3.3/dnsrecords.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnsrecords.hh --- pdns-recursor-3.3/dnsrecords.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnsrecords.hh 2012-07-08 18:20:53.000000000 +0000 @@ -26,7 +26,7 @@ #include #include -using namespace std; +#include "namespaces.hh" #include "namespaces.hh" #define includeboilerplate(RNAME) RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr); \ @@ -231,15 +231,11 @@ DNSKEYRecordContent(); includeboilerplate(DNSKEY) uint16_t getTag(); - string getExponent() const; - string getModulus() const; uint16_t d_flags; uint8_t d_protocol; uint8_t d_algorithm; string d_key; -private: - void getExpLen(uint16_t& startPos, uint16_t& expLen) const; }; class DSRecordContent : public DNSRecordContent @@ -253,6 +249,18 @@ string d_digest; }; +class DLVRecordContent : public DNSRecordContent +{ +public: + DLVRecordContent(); + includeboilerplate(DLV) + + uint16_t d_tag; + uint8_t d_algorithm, d_digesttype; + string d_digest; +}; + + class SSHFPRecordContent : public DNSRecordContent { public: @@ -296,6 +304,17 @@ string d_certificate; }; +class TLSARecordContent : public DNSRecordContent +{ +public: + includeboilerplate(TLSA) + +private: + uint8_t d_certusage, d_selector, d_matchtype; + string d_cert; +}; + + class RRSIGRecordContent : public DNSRecordContent { public: diff -Nru pdns-recursor-3.3/dnswriter.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnswriter.cc --- pdns-recursor-3.3/dnswriter.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnswriter.cc 2012-07-08 18:20:53.000000000 +0000 @@ -1,12 +1,11 @@ #include "dnswriter.hh" #include "misc.hh" #include "dnsparser.hh" -#include -#include +#include #include DNSPacketWriter::DNSPacketWriter(vector& content, const string& qname, uint16_t qtype, uint16_t qclass, uint8_t opcode) - : d_pos(0), d_content(content), d_qname(qname), d_qtype(qtype), d_qclass(qclass), d_canonic(false) + : d_pos(0), d_content(content), d_qname(qname), d_qtype(qtype), d_qclass(qclass), d_canonic(false), d_lowerCase(false) { d_content.clear(); dnsheader dnsheader; @@ -107,7 +106,7 @@ void DNSPacketWriter::xfr48BitInt(uint64_t val) { unsigned char bytes[6]; - uint16_t theLeft = htons(val >> 32); + uint16_t theLeft = htons((val >> 32)&0xffffU); uint32_t theRight = htonl(val & 0xffffffffU); memcpy(bytes, (void*)&theLeft, 2); memcpy(bytes+2, (void*)&theRight, 4); @@ -135,30 +134,26 @@ d_record.push_back(val); } + +/* input: + "" -> 0 + "blah" -> 4blah + "blah" "blah" -> output 4blah4blah + "verylongstringlongerthan256....characters" \xffverylongstring\x23characters (autosplit) + "blah\"blah" -> 9blah"blah + "blah\97" -> 5blahb + */ void DNSPacketWriter::xfrText(const string& text, bool) { - using boost::escaped_list_separator; - using boost::tokenizer; - - escaped_list_separator sep('\\', ' ' , '"'); - tokenizer > tok(text, sep); - - tokenizer >::iterator beg=tok.begin(); - - if(beg==tok.end()) { + if(text.empty()) { d_record.push_back(0); + return; + } + vector segments = segmentDNSText(text); + BOOST_FOREACH(const string& str, segments) { + d_record.push_back(str.length()); + d_record.insert(d_record.end(), str.c_str(), str.c_str() + str.length()); } - else - for(; beg!=tok.end(); ++beg){ - if(beg->empty()) - d_record.push_back(0); - else - for (unsigned int i = 0; i < beg->length(); i += 0xff){ - d_record.push_back(min((string::size_type)0xffU, beg->length()-i)); - const uint8_t* ptr=(uint8_t*)(beg->c_str()) + i; - d_record.insert(d_record.end(), ptr, ptr+min((string::size_type)0xffU, beg->length()-i)); - } - } } DNSPacketWriter::lmap_t::iterator find(DNSPacketWriter::lmap_t& lmap, const string& label) @@ -197,8 +192,9 @@ } // this is the absolute hottest function in the pdns recursor -void DNSPacketWriter::xfrLabel(const string& label, bool compress) +void DNSPacketWriter::xfrLabel(const string& Label, bool compress) { + string label = d_lowerCase ? toLower(Label) : Label; labelparts_t parts; if(d_canonic) @@ -209,7 +205,6 @@ d_record.push_back(0); return; } - bool unescaped=labeltokUnescape(parts, label); // d_stuff is amount of stuff that is yet to be written out - the dnsrecordheader for example @@ -243,6 +238,7 @@ if(unescaped) { string part(label.c_str() + i -> first, i->second - i->first); boost::replace_all(part, "\\.", "."); + boost::replace_all(part, "\\032", " "); boost::replace_all(part, "\\\\", "\\"); if(part.size() > 255) throw MOADNSException("DNSPacketWriter::xfrLabel() tried to write an overly large label"); @@ -269,22 +265,20 @@ void DNSPacketWriter::xfrBlob(const string& blob, int ) { const uint8_t* ptr=reinterpret_cast(blob.c_str()); - d_record.insert(d_record.end(), ptr, ptr+blob.size()); } -void DNSPacketWriter::xfrHexBlob(const string& blob) +void DNSPacketWriter::xfrHexBlob(const string& blob, bool keepReading) { xfrBlob(blob); } - void DNSPacketWriter::getRecords(string& records) { records.assign(d_content.begin() + d_sor, d_content.end()); } -uint16_t DNSPacketWriter::size() +uint32_t DNSPacketWriter::size() { return d_content.size() + d_stuff + d_record.size(); } diff -Nru pdns-recursor-3.3/dnswriter.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnswriter.hh --- pdns-recursor-3.3/dnswriter.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/dnswriter.hh 2012-07-08 18:20:53.000000000 +0000 @@ -10,7 +10,7 @@ #include "utility.hh" #endif #include "dns.hh" -using namespace std; +#include "namespaces.hh" /** this class can be used to write DNS packets. It knows about DNS in the sense that it makes the packet header and record headers. @@ -61,7 +61,7 @@ */ void commit(); - uint16_t size(); + uint32_t size(); // needs to be 32 bit because otherwise we don't see the wrap coming when it happened! /** Should the packet have grown too big for the writer's liking, rollback removes the record currently being written */ void rollback(); @@ -87,7 +87,7 @@ void xfrLabel(const string& label, bool compress=false); void xfrText(const string& text, bool multi=false); void xfrBlob(const string& blob, int len=-1); - void xfrHexBlob(const string& blob); + void xfrHexBlob(const string& blob, bool keepReading=false); uint16_t d_pos; @@ -100,6 +100,15 @@ d_canonic=val; } + void setLowercase(bool val) + { + d_lowerCase=val; + } + vector & getContent() + { + return d_content; + } + private: vector & d_content; vector d_record; @@ -113,9 +122,10 @@ uint16_t d_sor; uint16_t d_rollbackmarker; // start of last complete packet, for rollback Place d_recordplace; - bool d_canonic; + bool d_canonic, d_lowerCase; }; typedef vector > labelparts_t; bool labeltokUnescape(labelparts_t& parts, const string& label); +std::vector segmentDNSText(const string& text); // from dnslabeltext.rl #endif diff -Nru pdns-recursor-3.3/epollmplexer.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/epollmplexer.cc --- pdns-recursor-3.3/epollmplexer.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/epollmplexer.cc 2012-07-08 18:20:53.000000000 +0000 @@ -10,7 +10,7 @@ #endif #include "namespaces.hh" -using namespace std; +#include "namespaces.hh" class EpollFDMultiplexer : public FDMultiplexer { diff -Nru pdns-recursor-3.3/iputils.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/iputils.hh --- pdns-recursor-3.3/iputils.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/iputils.hh 2012-07-08 18:20:53.000000000 +0000 @@ -1,6 +1,6 @@ /* PowerDNS Versatile Database Driven Nameserver - Copyright (C) 2002 - 2008 PowerDNS.COM BV + Copyright (C) 2002 - 2011 PowerDNS.COM 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 @@ -32,11 +32,14 @@ #include #include "ahuexception.hh" #include "misc.hh" +#include +#include + #include #include #include -using namespace std; +#include "namespaces.hh" union ComboAddress { struct sockaddr_in sin4; @@ -78,7 +81,7 @@ return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16) > 0; } - struct addressOnlyLessThan: public binary_function + struct addressOnlyLessThan: public std::binary_function { bool operator()(const ComboAddress& a, const ComboAddress& b) const { @@ -108,18 +111,20 @@ sin4.sin_port=0; } + // 'port' sets a default value in case 'str' does not set a port explicit ComboAddress(const string& str, uint16_t port=0) { memset(&sin6, 0, sizeof(sin6)); sin4.sin_family = AF_INET; - - if(!IpToU32(str, (uint32_t*)&sin4.sin_addr.s_addr)) { + sin4.sin_port = 0; + if(makeIPv4sockaddr(str, &sin4)) { sin6.sin6_family = AF_INET6; if(makeIPv6sockaddr(str, &sin6) < 0) throw AhuException("Unable to convert presentation address '"+ str +"'"); } - sin4.sin_port=htons(port); + if(!sin4.sin_port) // 'str' overrides port! + sin4.sin_port=htons(port); } bool isMappedIPv4() const @@ -156,14 +161,10 @@ string toString() const { - char tmp[128]; - if(sin4.sin_family==AF_INET && !Utility::inet_ntop(AF_INET, ( const char * ) &sin4.sin_addr, tmp, sizeof(tmp))) - return tmp; - - if(sin4.sin_family==AF_INET6 && !Utility::inet_ntop(AF_INET6, ( const char * ) &sin6.sin6_addr, tmp, sizeof(tmp))) - return tmp; + char host[1024]; + getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST); - return tmp; + return host; } string toStringWithPort() const @@ -199,6 +200,25 @@ class Netmask { public: + Netmask() + { + d_network.sin4.sin_family=0; // disable this doing anything useful + } + + Netmask(const ComboAddress& network, uint8_t bits=0xff) + { + d_network = network; + + if(bits == 0xff) + bits = (network.sin4.sin_family == AF_INET) ? 32 : 128; + + d_bits = bits; + if(d_bits<32) + d_mask=~(0xFFFFFFFF>>d_bits); + else + d_mask=0xFFFFFFFF; // not actually used for IPv6 + } + //! Constructor supplies the mask, which cannot be changed Netmask(const string &mask) { @@ -206,7 +226,7 @@ d_network=makeComboAddress(split.first); if(!split.second.empty()) { - d_bits = (uint8_t) atoi(split.second.c_str()); + d_bits = lexical_cast(split.second); if(d_bits<32) d_mask=~(0xFFFFFFFF>>d_bits); else @@ -270,9 +290,21 @@ string toString() const { - return d_network.toString()+"/"+boost::lexical_cast(d_bits); + return d_network.toString()+"/"+boost::lexical_cast((unsigned int)d_bits); } + string toStringNoMask() const + { + return d_network.toString(); + } + const ComboAddress& getNetwork() const + { + return d_network; + } + int getBits() const + { + return d_bits; + } private: ComboAddress d_network; uint32_t d_mask; diff -Nru pdns-recursor-3.3/kqueuemplexer.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/kqueuemplexer.cc --- pdns-recursor-3.3/kqueuemplexer.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/kqueuemplexer.cc 2012-07-08 18:20:53.000000000 +0000 @@ -12,7 +12,7 @@ #include #include "namespaces.hh" -using namespace std; +#include "namespaces.hh" class KqueueFDMultiplexer : public FDMultiplexer { diff -Nru pdns-recursor-3.3/logger.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/logger.cc --- pdns-recursor-3.3/logger.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/logger.cc 2012-07-08 18:20:53.000000000 +0000 @@ -23,7 +23,7 @@ extern StatBag S; #endif -using namespace std; +#include "namespaces.hh" Logger &theL(const string &pname) { @@ -125,6 +125,14 @@ return *this; } +Logger& Logger::operator<<(double i) +{ + ostringstream tmp; + tmp< + +#if !defined(PDNS_ENABLE_LUA) + +// stub implementation + +PowerDNSLua::PowerDNSLua(const std::string& fname) +{ + throw runtime_error("Lua support disabled"); +} + + +PowerDNSLua::~PowerDNSLua() +{ + +} + +#else + +extern "C" { +#undef L +/* Include the Lua API header files. */ +#include +#include +#include +} + +#include +#include +#include +#include +#include +#include "logger.hh" +#include "namespaces.hh" + +bool netmaskMatchTable(lua_State* lua, const std::string& ip) +{ + lua_pushnil(lua); /* first key */ + while (lua_next(lua, 2) != 0) { + string netmask=lua_tostring(lua, -1); + Netmask nm(netmask); + ComboAddress ca(ip); + lua_pop(lua, 1); + + if(nm.match(ip)) + return true; + } + return false; +} + +static bool getFromTable(lua_State *lua, const std::string &key, std::string& value) +{ + lua_pushstring(lua, key.c_str()); // 4 is now '1' + lua_gettable(lua, -2); // replace by the first entry of our table we hope + + bool ret=false; + if(!lua_isnil(lua, -1)) { + value = lua_tostring(lua, -1); + ret=true; + } + lua_pop(lua, 1); + return ret; +} + +static bool getFromTable(lua_State *lua, const std::string &key, uint32_t& value) +{ + lua_pushstring(lua, key.c_str()); // 4 is now '1' + lua_gettable(lua, -2); // replace by the first entry of our table we hope + + bool ret=false; + if(!lua_isnil(lua, -1)) { + value = (uint32_t)lua_tonumber(lua, -1); + ret=true; + } + lua_pop(lua, 1); + return ret; +} + +void pushResourceRecordsTable(lua_State* lua, const vector& records) +{ + // make a table of tables + lua_newtable(lua); + + int pos=0; + BOOST_FOREACH(const DNSResourceRecord& rr, records) + { + // row number, used by 'lua_settable' below + lua_pushnumber(lua, ++pos); + // "row" table + lua_newtable(lua); + + lua_pushstring(lua, rr.qname.c_str()); + lua_setfield(lua, -2, "qname"); // pushes value at the top of the stack to the table immediately below that (-1 = top, -2 is below) + + lua_pushstring(lua, rr.content.c_str()); + lua_setfield(lua, -2, "content"); + + lua_pushnumber(lua, rr.qtype.getCode()); + lua_setfield(lua, -2, "qtype"); + + lua_pushnumber(lua, rr.ttl); + lua_setfield(lua, -2, "ttl"); + + lua_pushnumber(lua, rr.d_place); + lua_setfield(lua, -2, "place"); + + lua_settable(lua, -3); // pushes the table we just built into the master table at position pushed above + } +} + +void popResourceRecordsTable(lua_State *lua, const string &query, vector& ret) +{ + /* get the result */ + DNSResourceRecord rr; + rr.qname = query; + rr.d_place = DNSResourceRecord::ANSWER; + rr.ttl = 3600; + + cerr<<"Lua stacksize "<= 2) { + string ip=lua_tostring(lua, 1); + if(lua_istable(lua, 2)) { + result = netmaskMatchTable(lua, ip); + } + else { + for(int n=2 ; n <= lua_gettop(lua); ++n) { + string netmask=lua_tostring(lua, n); + Netmask nm(netmask); + ComboAddress ca(ip); + + result = nm.match(ip); + if(result) + break; + } + } + } + + lua_pushboolean(lua, result); + return 1; +} + +int getLocalAddressLua(lua_State* lua) +{ + lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); + PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1); + + lua_pushstring(lua, pl->getLocal().toString().c_str()); + return 1; +} + +// called by lua to indicate that this answer is 'variable' and should not be cached +int setVariableLua(lua_State* lua) +{ + lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); + PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1); + pl->setVariable(); + return 0; +} + +int logLua(lua_State *lua) +{ + if(lua_gettop(lua) >= 1) { + string message=lua_tostring(lua, 1); + theL()<::const_iterator iter = QType::names.begin(); iter != QType::names.end(); ++iter) { + lua_pushnumber(d_lua, iter->second); + lua_setfield(d_lua, -2, iter->first.c_str()); + } + lua_pushnumber(d_lua, 0); + lua_setfield(d_lua, -2, "NOERROR"); + lua_pushnumber(d_lua, 1); + lua_setfield(d_lua, -2, "FORMERR"); + lua_pushnumber(d_lua, 2); + lua_setfield(d_lua, -2, "SERVFAIL"); + lua_pushnumber(d_lua, 3); + lua_setfield(d_lua, -2, "NXDOMAIN"); + lua_pushnumber(d_lua, 4); + lua_setfield(d_lua, -2, "NOTIMP"); + lua_pushnumber(d_lua, 5); + lua_setfield(d_lua, -2, "REFUSED"); + lua_setglobal(d_lua, "pdns"); + + lua_pushlightuserdata(d_lua, (void*)this); + lua_setfield(d_lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); +} + +bool PowerDNSLua::getFromTable(const std::string& key, std::string& value) +{ + return ::getFromTable(d_lua, key, value); +} + +bool PowerDNSLua::getFromTable(const std::string& key, uint32_t& value) +{ + return ::getFromTable(d_lua, key, value); +} + + +PowerDNSLua::~PowerDNSLua() +{ + lua_close(d_lua); +} +#endif diff -Nru pdns-recursor-3.3/lua-pdns.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/lua-pdns.hh --- pdns-recursor-3.3/lua-pdns.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/lua-pdns.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,37 @@ +#ifndef PDNS_LUA_PDNS_HH +#define PDNS_LUA_PDNS_HH +#include "dns.hh" +#include "iputils.hh" + +struct lua_State; + +class PowerDNSLua +{ +public: + explicit PowerDNSLua(const std::string& fname); + ~PowerDNSLua(); + void reload(); + ComboAddress getLocal() + { + return d_local; + } + + void setVariable() + { + d_variable=true; + } + +protected: // FIXME? + lua_State* d_lua; + bool passthrough(const string& func, const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable); + bool getFromTable(const std::string& key, std::string& value); + bool getFromTable(const std::string& key, uint32_t& value); + bool d_failed; + bool d_variable; + ComboAddress d_local; +}; + +void pushResourceRecordsTable(lua_State* lua, const vector& records); +void popResourceRecordsTable(lua_State *lua, const string &query, vector& ret); + +#endif diff -Nru pdns-recursor-3.3/lua-pdns-recursor.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/lua-pdns-recursor.cc --- pdns-recursor-3.3/lua-pdns-recursor.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/lua-pdns-recursor.cc 1970-01-01 00:00:00.000000000 +0000 @@ -1,288 +0,0 @@ -#include "lua-pdns-recursor.hh" - -#if !defined(PDNS_ENABLE_LUA) && !defined(LIBDIR) - -// stub implementation - -PowerDNSLua::PowerDNSLua(const std::string& fname) -{ - throw runtime_error("Lua support disabled"); -} - -bool PowerDNSLua::nxdomain(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable) -{ - return false; -} - -bool PowerDNSLua::preresolve(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable) -{ - return false; -} - -PowerDNSLua::~PowerDNSLua() -{ - -} - -#else - -extern "C" { -#undef L -/* Include the Lua API header files. */ -#include -#include -#include -} - -#include -#include -#include -#include -#include -#include "logger.hh" -using namespace std; - -bool netmaskMatchTable(lua_State* lua, const std::string& ip) -{ - lua_pushnil(lua); /* first key */ - while (lua_next(lua, 2) != 0) { - string netmask=lua_tostring(lua, -1); - Netmask nm(netmask); - ComboAddress ca(ip); - lua_pop(lua, 1); - - if(nm.match(ip)) - return true; - } - return false; -} - -extern "C" { - -int netmaskMatchLua(lua_State *lua) -{ - bool result=false; - if(lua_gettop(lua) >= 2) { - string ip=lua_tostring(lua, 1); - if(lua_istable(lua, 2)) { - result = netmaskMatchTable(lua, ip); - } - else { - for(int n=2 ; n <= lua_gettop(lua); ++n) { - string netmask=lua_tostring(lua, n); - Netmask nm(netmask); - ComboAddress ca(ip); - - result = nm.match(ip); - if(result) - break; - } - } - } - - lua_pushboolean(lua, result); - return 1; -} - -int getLocalAddressLua(lua_State* lua) -{ - lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); - PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1); - - lua_pushstring(lua, pl->getLocal().toString().c_str()); - return 1; -} - -// called by lua to indicate that this answer is 'variable' and should not be cached -int setVariableLua(lua_State* lua) -{ - lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); - PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1); - pl->setVariable(); - return 0; -} - -int logLua(lua_State *lua) -{ - if(lua_gettop(lua) >= 1) { - string message=lua_tostring(lua, 1); - theL()<::const_iterator iter = QType::names.begin(); iter != QType::names.end(); ++iter) { - lua_pushnumber(d_lua, iter->second); - lua_setfield(d_lua, -2, iter->first.c_str()); - } - lua_pushnumber(d_lua, 3); - lua_setfield(d_lua, -2, "NXDOMAIN"); - lua_setglobal(d_lua, "pdns"); - - lua_pushlightuserdata(d_lua, (void*)this); - lua_setfield(d_lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); -} - -bool PowerDNSLua::nxdomain(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector& ret, int& res, bool* variable) -{ - return passthrough("nxdomain", remote, local, query, qtype, ret, res, variable); -} - -bool PowerDNSLua::preresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector& ret, int& res, bool* variable) -{ - return passthrough("preresolve", remote, local, query, qtype, ret, res, variable); -} - -bool PowerDNSLua::getFromTable(const std::string& key, std::string& value) -{ - lua_pushstring(d_lua, key.c_str()); // 4 is now '1' - lua_gettable(d_lua, -2); // replace by the first entry of our table we hope - - bool ret=false; - if(!lua_isnil(d_lua, -1)) { - value = lua_tostring(d_lua, -1); - ret=true; - } - lua_pop(d_lua, 1); - return ret; -} - - -bool PowerDNSLua::getFromTable(const std::string& key, uint32_t& value) -{ - lua_pushstring(d_lua, key.c_str()); // 4 is now '1' - lua_gettable(d_lua, -2); // replace by the first entry of our table we hope - - bool ret=false; - if(!lua_isnil(d_lua, -1)) { - value = (uint32_t)lua_tonumber(d_lua, -1); - ret=true; - } - lua_pop(d_lua, 1); - return ret; -} - - -bool PowerDNSLua::passthrough(const string& func, const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& ret, - int& res, bool* variable) -{ - d_variable = false; - lua_getglobal(d_lua, func.c_str()); - if(!lua_isfunction(d_lua, -1)) { - // cerr<<"No such function '"<& res, int& ret, bool* variable); - bool nxdomain(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& res, int& ret, bool* variable); - - ComboAddress getLocal() - { - return d_local; - } - - void setVariable() - { - d_variable=true; - } - -private: - lua_State* d_lua; - bool passthrough(const string& func, const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable); - bool getFromTable(const std::string& key, std::string& value); - bool getFromTable(const std::string& key, uint32_t& value); - bool d_failed; - bool d_variable; - ComboAddress d_local; -}; - -#endif diff -Nru pdns-recursor-3.3/lua-recursor.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/lua-recursor.cc --- pdns-recursor-3.3/lua-recursor.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/lua-recursor.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,173 @@ +#include "lua-recursor.hh" + +// to avoid including all of syncres.hh +int directResolve(const std::string& qname, const QType& qtype, int qclass, vector& ret); + +#if !defined(PDNS_ENABLE_LUA) + +RecursorLua::RecursorLua(const std::string &fname) + : PowerDNSLua(fname) +{ + // empty +} + +bool RecursorLua::nxdomain(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return false; +} + +bool RecursorLua::nodata(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return false; +} + +bool RecursorLua::postresolve(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return false; +} + + +bool RecursorLua::preresolve(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return false; +} + + +#else + +extern "C" { +#undef L +/* Include the Lua API header files. */ +#include +#include +#include +} + +#include +#include +#include +#include +#include +#include +#include "logger.hh" +#include "namespaces.hh" + +RecursorLua::RecursorLua(const std::string &fname) + : PowerDNSLua(fname) +{ + // empty +} + +int getFakeAAAARecords(const std::string& qname, const std::string& prefix, vector& ret) +{ + int rcode=directResolve(qname, QType(QType::A), 1, ret); + + ComboAddress prefixAddress(prefix); + + BOOST_FOREACH(DNSResourceRecord& rr, ret) + { + if(rr.qtype.getCode() == QType::A && rr.d_place==DNSResourceRecord::ANSWER) { + ComboAddress ipv4(rr.content); + uint32_t tmp; + memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4); + // tmp=htonl(tmp); + memcpy(((char*)&prefixAddress.sin6.sin6_addr.s6_addr)+12, &tmp, 4); + rr.content = prefixAddress.toString(); + rr.qtype = QType(QType::AAAA); + } + } + return rcode; +} + +bool RecursorLua::nxdomain(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return passthrough("nxdomain", remote, local, query, qtype, ret, res, variable); +} + +bool RecursorLua::preresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return passthrough("preresolve", remote, local, query, qtype, ret, res, variable); +} + +bool RecursorLua::nodata(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return passthrough("nodata", remote, local, query, qtype, ret, res, variable); +} + +bool RecursorLua::postresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return passthrough("postresolve", remote, local, query, qtype, ret, res, variable); +} + + +bool RecursorLua::passthrough(const string& func, const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& ret, + int& res, bool* variable) +{ + d_variable = false; + lua_getglobal(d_lua, func.c_str()); + if(!lua_isfunction(d_lua, -1)) { + // cerr<<"No such function '"<& res, int& ret, bool* variable); + bool nxdomain(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& res, int& ret, bool* variable); + bool nodata(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& res, int& ret, bool* variable); + bool postresolve(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& res, int& ret, bool* variable); + +private: + bool passthrough(const string& func, const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable); +}; + +#endif diff -Nru pdns-recursor-3.3/lwres.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/lwres.cc --- pdns-recursor-3.3/lwres.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/lwres.cc 2012-07-08 18:20:53.000000000 +0000 @@ -164,6 +164,7 @@ lwr->d_result.clear(); try { + lwr->d_tcbit=0; MOADNSParser mdp((const char*)buf.get(), len); lwr->d_aabit=mdp.d_header.aa; lwr->d_tcbit=mdp.d_header.tc; @@ -186,7 +187,6 @@ rr.priority = 0; rr.qtype=i->first.d_type; rr.qname=i->first.d_label; - rr.ttl=i->first.d_ttl; rr.content=i->first.d_content->getZoneRepresentation(); // this should be the serialised form rr.d_place=(DNSResourceRecord::Place) i->first.d_place; diff -Nru pdns-recursor-3.3/lwres.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/lwres.hh --- pdns-recursor-3.3/lwres.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/lwres.hh 2012-07-08 18:20:53.000000000 +0000 @@ -38,7 +38,7 @@ #include "ahuexception.hh" #include "dns.hh" -using namespace std; +#include "namespaces.hh" int asendto(const char *data, int len, int flags, const ComboAddress& ip, uint16_t id, const string& domain, uint16_t qtype, int* fd); diff -Nru pdns-recursor-3.3/Makefile pdns-recursor-3.5.pre.20120708.2673~crass~precise/Makefile --- pdns-recursor-3.3/Makefile 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/Makefile 2012-07-08 18:20:53.000000000 +0000 @@ -18,8 +18,9 @@ arguments.o lwres.o pdns_recursor.o recursor_cache.o dnsparser.o \ dnswriter.o dnsrecords.o rcpgenerator.o base64.o zoneparser-tng.o \ rec_channel.o rec_channel_rec.o selectmplexer.o sillyrecords.o \ -dns_random.o aescrypt.o aeskey.o aes_modes.o aestab.o lua-pdns-recursor.o \ -randomhelper.o recpacketcache.o dns.o reczones.o base32.o nsecrecords.o +dns_random.o aescrypt.o aeskey.o aes_modes.o aestab.o dnslabeltext.o \ +lua-pdns.o lua-recursor.o randomhelper.o recpacketcache.o dns.o \ +reczones.o base32.o nsecrecords.o REC_CONTROL_OBJECTS=rec_channel.o rec_control.o arguments.o misc.o \ unix_utility.o logger.o qtype.o diff -Nru pdns-recursor-3.3/misc.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/misc.cc --- pdns-recursor-3.3/misc.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/misc.cc 2012-07-08 18:20:53.000000000 +0000 @@ -317,11 +317,45 @@ ret = poll(&pfd, 1, seconds * 1000 + useconds/1000); if ( ret == -1 ) - errno = ETIMEDOUT; + errno = ETIMEDOUT; // ??? return ret; } +// returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set +int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int*fd) +{ + int ret; + + struct pollfd pfds[2]; + memset(&pfds[0], 0, 2*sizeof(struct pollfd)); + pfds[0].fd = fd1; + pfds[1].fd = fd2; + + pfds[0].events= pfds[1].events = POLLIN; + + int nsocks = 1 + (fd2 >= 0); // fd2 can optionally be -1 + + if(seconds >= 0) + ret = poll(pfds, nsocks, seconds * 1000 + useconds/1000); + else + ret = poll(pfds, nsocks, -1); + if(!ret || ret < 0) + return ret; + + if((pfds[0].revents & POLLIN) && !(pfds[1].revents & POLLIN)) + *fd = pfds[0].fd; + else if((pfds[1].revents & POLLIN) && !(pfds[0].revents & POLLIN)) + *fd = pfds[1].fd; + else if(ret == 2) { + *fd = pfds[random()%2].fd; + } + else + *fd = -1; // should never happen + + return 1; +} + string humanDuration(time_t passed) { @@ -329,13 +363,13 @@ if(passed<60) ret<sin_family == AF_INET) { - struct sockaddr_in sip; - memcpy(&sip,(struct sockaddr_in*)remote,sizeof(sip)); - return inet_ntoa(sip.sin_addr); - } - else { - char tmp[128]; - - if(!Utility::inet_ntop(AF_INET6, ( const char * ) &((struct sockaddr_in6 *)remote)->sin6_addr, tmp, sizeof(tmp))) - return "IPv6 untranslateable"; - - return tmp; - } -} - string makeHexDump(const string& str) { char tmp[5]; @@ -511,8 +531,6 @@ return ret; } - - // shuffle, maintaining some semblance of order void shuffle(vector& rrs) { @@ -541,6 +559,18 @@ // we don't shuffle the rest } +static bool comparePlace(DNSResourceRecord a, DNSResourceRecord b) +{ + return (a.d_place < b.d_place); +} + +// make sure rrs is sorted in d_place order to avoid surprises later +// then shuffle the parts that desire shuffling +void orderAndShuffle(vector& rrs) +{ + std::stable_sort(rrs.begin(), rrs.end(), comparePlace); + shuffle(rrs); +} void normalizeTV(struct timeval& tv) { @@ -585,10 +615,8 @@ return ret; } -boost::optional logFacilityToLOG(unsigned int facility) +int logFacilityToLOG(unsigned int facility) { - boost::optional ret; - switch(facility) { case 0: return LOG_LOCAL0; @@ -607,7 +635,7 @@ case 7: return(LOG_LOCAL7); default: - return ret; + return -1; } } @@ -665,6 +693,18 @@ int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret) { + if(addr.empty()) + return -1; + string ourAddr(addr); + int port = -1; + if(addr[0]=='[') { // [::]:53 style address + string::size_type pos = addr.find(']'); + if(pos == string::npos || pos + 2 > addr.size() || addr[pos+1]!=':') + return -1; + ourAddr.assign(addr.c_str() + 1, pos-1); + port = atoi(addr.c_str()+pos+2); + } + struct addrinfo* res; struct addrinfo hints; memset(&hints, 0, sizeof(hints)); @@ -672,17 +712,57 @@ hints.ai_family = AF_INET6; hints.ai_flags = AI_NUMERICHOST; - if(getaddrinfo(addr.c_str(), 0, &hints, &res) < 0) { - perror("getaddrinfo"); + int error; + if((error=getaddrinfo(ourAddr.c_str(), 0, &hints, &res))) { // this is correct + /* + cerr<<"Error translating IPv6 address '"<ai_addr, sizeof(*ret)); - + memcpy(ret, res->ai_addr, res->ai_addrlen); + if(port >= 0) + ret->sin6_port = htons(port); freeaddrinfo(res); return 0; } +int makeIPv4sockaddr(const string &str, struct sockaddr_in* ret) +{ + if(str.empty()) { + return -1; + } + struct in_addr inp; + + string::size_type pos = str.find(':'); + if(pos == string::npos) { // no port specified, not touching the port + if(Utility::inet_aton(str.c_str(), &inp)) { + ret->sin_addr.s_addr=inp.s_addr; + return 0; + } + return -1; + } + if(!*(str.c_str() + pos + 1)) // trailing : + return -1; + + char *eptr = (char*)str.c_str() + str.size(); + int port = strtol(str.c_str() + pos + 1, &eptr, 10); + if(*eptr) + return -1; + + ret->sin_port = htons(port); + if(Utility::inet_aton(str.substr(0, pos).c_str(), &inp)) { + ret->sin_addr.s_addr=inp.s_addr; + return 0; + } + return -1; +} + + //! read a line of text from a FILE* to a std::string, returns false on 'no data' bool stringfgets(FILE* fp, std::string& line) { diff -Nru pdns-recursor-3.3/misc.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/misc.hh --- pdns-recursor-3.3/misc.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/misc.hh 2012-07-08 18:20:53.000000000 +0000 @@ -6,7 +6,6 @@ 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 @@ -22,6 +21,12 @@ #include #include #include +#include +#include +#include +#include +#include +using namespace ::boost::multi_index; #if 0 #include using std::cout; @@ -61,9 +66,8 @@ #include #include #include -#include -using namespace std; +#include "namespaces.hh" bool chopOff(string &domain); bool chopOffDotted(string &domain); @@ -72,38 +76,18 @@ string nowTime(); const string unquotify(const string &item); string humanDuration(time_t passed); -void chomp(string &line, const string &delim); bool stripDomainSuffix(string *qname, const string &domain); void stripLine(string &line); string getHostname(); string urlEncode(const string &text); int waitForData(int fd, int seconds, int useconds=0); +int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd); int waitForRWData(int fd, bool waitForRead, int seconds, int useconds); uint16_t getShort(const unsigned char *p); uint16_t getShort(const char *p); uint32_t getLong(const unsigned char *p); uint32_t getLong(const char *p); -boost::optional logFacilityToLOG(unsigned int facility); - -inline void putLong(unsigned char* p, uint32_t val) -{ - *p++=(val>>24)&0xff; - *p++=(val>>16)&0xff; - *p++=(val>>8)&0xff; - *p++=(val )&0xff; - -} -inline void putLong(char* p, uint32_t val) -{ - putLong((unsigned char *)p,val); -} - - -inline uint32_t getLong(unsigned char *p) -{ - return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]; -} - +int logFacilityToLOG(unsigned int facility); struct ServiceTuple { @@ -198,6 +182,7 @@ time_t time(); inline void set(); //!< Reset the timer inline int udiff(); //!< Return the number of microseconds since the timer was last set. + inline int udiffNoReset(); //!< Return the number of microseconds since the timer was last set. void setTimeval(const struct timeval& tv) { d_set=tv; @@ -209,7 +194,7 @@ private: struct timeval d_set; }; -const string sockAddrToString(struct sockaddr_in *remote); + int sendData(const char *buffer, int replen, int outsock); inline void DTime::set() @@ -219,14 +204,21 @@ inline int DTime::udiff() { + int res=udiffNoReset(); + Utility::gettimeofday(&d_set,0); + return res; +} + +inline int DTime::udiffNoReset() +{ struct timeval now; Utility::gettimeofday(&now,0); int ret=1000000*(now.tv_sec-d_set.tv_sec)+(now.tv_usec-d_set.tv_usec); - d_set=now; return ret; } + inline bool dns_isspace(char c) { return c==' ' || c=='\t' || c=='\r' || c=='\n'; @@ -296,6 +288,7 @@ string makeHexDump(const string& str); void shuffle(vector& rrs); +void orderAndShuffle(vector& rrs); void normalizeTV(struct timeval& tv); const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs); @@ -401,7 +394,7 @@ }; -struct CIStringCompare: public binary_function +struct CIStringCompare: public std::binary_function { bool operator()(const string& a, const string& b) const { @@ -444,5 +437,17 @@ string labelReverse(const std::string& qname); std::string dotConcat(const std::string& a, const std::string &b); int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret); +int makeIPv4sockaddr(const string &str, struct sockaddr_in* ret); bool stringfgets(FILE* fp, std::string& line); + +template +std::pair +replacing_insert(Index& i,const typename Index::value_type& x) +{ + std::pair res=i.insert(x); + if(!res.second)res.second=i.replace(res.first,x); + return res; +} + + #endif diff -Nru pdns-recursor-3.3/mtasker.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/mtasker.cc --- pdns-recursor-3.3/mtasker.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/mtasker.cc 2012-07-08 18:20:53.000000000 +0000 @@ -40,7 +40,7 @@ MTasker is designed to offer the performance of statemachines while maintaining simple thread semantics. It is not a replacement for a full threading system. - \section compatability Compatability + \section compatibility Compatibility MTasker is only guaranteed to work on Linux with glibc 2.2.5 and higher. It does not work on FreeBSD and notably, not on Red Hat 6.0. It may work on Solaris, please test. @@ -71,7 +71,7 @@ \section events Events By default, Events are recognized by an int and their value is also an int. - This can be overriden by specifying the EventKey and EventVal template parameters. + This can be overridden by specifying the EventKey and EventVal template parameters. An event can be a keypress, but also a UDP packet, or a bit of data from a TCP socket. The sample code provided works with keypresses, but that is just a not very useful example. @@ -144,7 +144,7 @@ //! puts a thread to sleep waiting until a specified event arrives /** Threads can call waitEvent to register that they are waiting on an event with a certain key. - If so desidered, the event can carry data which is returned in val in case that is non-zero. + If so desired, the event can carry data which is returned in val in case that is non-zero. Furthermore, a timeout can be specified in seconds. @@ -192,6 +192,9 @@ if(val && d_waitstatus==Answer) *val=d_waitval; d_tid=w.tid; + if((char*)&w < d_threads[d_tid].highestStackSeen) { + d_threads[d_tid].highestStackSeen = (char*)&w; + } key=d_eventkey; return d_waitstatus; } @@ -202,7 +205,7 @@ templatevoid MTasker::yield() { d_runQueue.push(d_tid); - if(swapcontext(d_threads[d_tid] ,&d_kernel) < 0) { // give control to the kernel + if(swapcontext(d_threads[d_tid].context ,&d_kernel) < 0) { // give control to the kernel perror("swapcontext in yield"); exit(EXIT_FAILURE); } @@ -271,7 +274,7 @@ makecontext (uc, (void (*)(void))threadWrapper, 6, thispair.first, thispair.second, start, d_maxtid, valpair.first, valpair.second); - d_threads[d_maxtid]=uc; + d_threads[d_maxtid].context = uc; d_runQueue.push(d_maxtid++); // will run at next schedule invocation } @@ -290,7 +293,7 @@ { if(!d_runQueue.empty()) { d_tid=d_runQueue.front(); - if(swapcontext(&d_kernel, d_threads[d_tid])) { + if(swapcontext(&d_kernel, d_threads[d_tid].context)) { perror("swapcontext in schedule"); exit(EXIT_FAILURE); } @@ -299,8 +302,8 @@ return true; } if(!d_zombiesQueue.empty()) { - delete[] (char *)d_threads[d_zombiesQueue.front()]->uc_stack.ss_sp; - delete d_threads[d_zombiesQueue.front()]; + delete[] (char *)d_threads[d_zombiesQueue.front()].context->uc_stack.ss_sp; + delete d_threads[d_zombiesQueue.front()].context; d_threads.erase(d_zombiesQueue.front()); d_zombiesQueue.pop(); return true; @@ -369,11 +372,11 @@ } } - templatevoid MTasker::threadWrapper(uint32_t self1, uint32_t self2, tfunc_t *tf, int tid, uint32_t val1, uint32_t val2) { void* val = joinPtr(val1, val2); MTasker* self = (MTasker*) joinPtr(self1, self2); + self->d_threads[self->d_tid].startOfStack = self->d_threads[self->d_tid].highestStackSeen = (char*)&val; (*tf)(val); self->d_zombiesQueue.push(tid); @@ -388,3 +391,10 @@ { return d_tid; } + + +//! Returns the maximum stack usage so far of this MThread +templateunsigned int MTasker::getMaxStackUsage() +{ + return d_threads[d_tid].startOfStack - d_threads[d_tid].highestStackSeen; +} diff -Nru pdns-recursor-3.3/mtasker.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/mtasker.hh --- pdns-recursor-3.3/mtasker.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/mtasker.hh 2012-07-08 18:20:53.000000000 +0000 @@ -50,8 +50,14 @@ std::queue d_runQueue; std::queue d_zombiesQueue; + struct ThreadInfo + { + ucontext_t* context; + char* startOfStack; + char* highestStackSeen; + }; - typedef std::map mthreads_t; + typedef std::map mthreads_t; mthreads_t d_threads; int d_tid; int d_maxtid; @@ -66,7 +72,7 @@ EventKey key; ucontext_t *context; struct timeval ttd; - int tid; + int tid; }; typedef multi_index_container< @@ -99,6 +105,7 @@ bool noProcesses(); unsigned int numProcesses(); int getTid(); + unsigned int getMaxStackUsage(); private: static void threadWrapper(uint32_t self1, uint32_t self2, tfunc_t *tf, int tid, uint32_t val1, uint32_t val2); diff -Nru pdns-recursor-3.3/namespaces.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/namespaces.hh --- pdns-recursor-3.3/namespaces.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/namespaces.hh 2012-07-08 18:20:53.000000000 +0000 @@ -10,6 +10,36 @@ #include #include #include +#include +#include +#include +#include +#include +#include + +using std::vector; +using std::map; +using std::pair; +using std::make_pair; +using std::runtime_error; +using std::ostringstream; +using std::set; +using std::deque; +using std::cerr; +using std::cout; +using std::clog; +using std::endl; +using std::ifstream; +using std::ofstream; +using std::ostream; +using std::min; // these are a bit scary, everybody uses 'min' +using std::max; + +namespace pdns { + typedef std::string string; +}; + +typedef pdns::string string; using boost::lexical_cast; using boost::tie; diff -Nru pdns-recursor-3.3/nsecrecords.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/nsecrecords.cc --- pdns-recursor-3.3/nsecrecords.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/nsecrecords.cc 2012-07-08 18:20:53.000000000 +0000 @@ -27,19 +27,32 @@ pw.xfrLabel(d_next); uint8_t res[34]; - memset(res, 0, sizeof(res)); - set::const_iterator i; - for(i=d_set.begin(); i != d_set.end() && *i<255; ++i){ - res[2+*i/8] |= 1 << (7-(*i%8)); - } - int len=0; - if(!d_set.empty()) - len=1+*--i/8; + int oldWindow = -1; + int window = 0; + int len = 0; + string tmp; - res[1]=len; + for(i=d_set.begin(); i != d_set.end(); ++i){ + uint16_t bit = (*i)%256; + window = static_cast((*i) / 256); + + if (window != oldWindow) { + if (oldWindow > -1) { + res[0] = static_cast(oldWindow); + res[1] = static_cast(len); + tmp.assign(res, res+len+2); + pw.xfrBlob(tmp); + } + memset(res, 0, 34); + oldWindow = window; + } + res[2+bit/8] |= 1 << (7-(bit%8)); + len=1+bit/8; + } - string tmp; + res[0] = static_cast(window); + res[1] = static_cast(len); tmp.assign(res, res+len+2); pw.xfrBlob(tmp); } @@ -50,27 +63,31 @@ pr.xfrLabel(ret->d_next); string bitmap; pr.xfrBlob(bitmap); - + // 00 06 20 00 00 00 00 03 -> NS RRSIG NSEC ( 2, 46, 47 ) counts from left - + if(bitmap.empty()) + return ret; + if(bitmap.size() < 2) throw MOADNSException("NSEC record with impossibly small bitmap"); - if(bitmap[0]) - throw MOADNSException("Can't deal with NSEC mappings > 255 yet"); - - unsigned int len=bitmap[1]; - if(bitmap.size()!=2+len) - throw MOADNSException("Can't deal with multi-part NSEC mappings yet"); - - for(unsigned int n=0 ; n < len ; ++n) { - uint8_t val=bitmap[2+n]; - for(int bit = 0; bit < 8 ; ++bit , val>>=1) - if(val & 1) { - ret->d_set.insert((7-bit) + 8*(n)); + for(unsigned int n = 0; n+1 < bitmap.size();) { + unsigned int window=static_cast(bitmap[n++]); + unsigned int len=static_cast(bitmap[n++]); + + // end if zero padding and ensure packet length + if(window == 0&&len == 0) break; + if(n+len>bitmap.size()) + throw MOADNSException("NSEC record with bitmap length > packet length"); + + for(unsigned int k=0; k < len; k++) { + uint8_t val=bitmap[n++]; + for(int bit = 0; bit < 8 ; ++bit , val>>=1) + if(val & 1) { + ret->d_set.insert((7-bit) + 8*(k) + 256*window); + } } } - return ret; } @@ -129,19 +146,32 @@ pw.xfrBlob(d_nexthash); uint8_t res[34]; - memset(res, 0, sizeof(res)); - set::const_iterator i; - for(i=d_set.begin(); i != d_set.end() && *i<255; ++i){ - res[2+*i/8] |= 1 << (7-(*i%8)); - } - int len=0; - if(!d_set.empty()) - len=1+*--i/8; + int oldWindow = -1; + int window = 0; + int len = 0; + string tmp; - res[1]=len; + for(i=d_set.begin(); i != d_set.end(); ++i){ + uint16_t bit = (*i)%256; + window = static_cast((*i) / 256); + + if (window != oldWindow) { + if (oldWindow > -1) { + res[0] = static_cast(oldWindow); + res[1] = static_cast(len); + tmp.assign(res, res+len+2); + pw.xfrBlob(tmp); + } + memset(res, 0, 34); + oldWindow = window; + } + res[2+bit/8] |= 1 << (7-(bit%8)); + len=1+bit/8; + } - string tmp; + res[0] = static_cast(window); + res[1] = static_cast(len); tmp.assign(res, res+len+2); pw.xfrBlob(tmp); } @@ -170,22 +200,24 @@ if(bitmap.size() < 2) throw MOADNSException("NSEC3 record with impossibly small bitmap"); - - if(bitmap[0]) - throw MOADNSException("Can't deal with NSEC3 mappings > 255 yet"); - - unsigned int bitmaplen=bitmap[1]; - if(bitmap.size()!=2+bitmaplen) - throw MOADNSException("Can't deal with multi-part NSEC3 mappings yet"); - - for(unsigned int n=0 ; n < bitmaplen ; ++n) { - uint8_t val=bitmap[2+n]; - for(int bit = 0; bit < 8 ; ++bit , val>>=1) - if(val & 1) { - ret->d_set.insert((7-bit) + 8*(n)); + + for(unsigned int n = 0; n+1 < bitmap.size();) { + unsigned int window=static_cast(bitmap[n++]); + unsigned int len=static_cast(bitmap[n++]); + + // end if zero padding and ensure packet length + if(window == 0&&len == 0) break; + if(n+len>bitmap.size()) + throw MOADNSException("NSEC record with bitmap length > packet length"); + + for(unsigned int k=0; k < len; k++) { + uint8_t val=bitmap[n++]; + for(int bit = 0; bit < 8 ; ++bit , val>>=1) + if(val & 1) { + ret->d_set.insert((7-bit) + 8*(k) + 256*window); + } } } - return ret; } diff -Nru pdns-recursor-3.3/pdns_hw.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns_hw.cc --- pdns-recursor-3.3/pdns_hw.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns_hw.cc 2012-07-08 18:20:53.000000000 +0000 @@ -11,7 +11,7 @@ #include #include -using namespace std; +#include "namespaces.hh" int main() { ostringstream str; diff -Nru pdns-recursor-3.3/pdns_recursor.1 pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns_recursor.1 --- pdns-recursor-3.3/pdns_recursor.1 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns_recursor.1 2012-07-08 18:20:53.000000000 +0000 @@ -1,13 +1,22 @@ '\" t .\" Title: pdns_recursor .\" Author: [see the "AUTHOR" section] -.\" Generator: DocBook XSL Stylesheets v1.75.1 -.\" Date: 02/10/2010 -.\" Manual: [FIXME: manual] -.\" Source: [FIXME: source] +.\" Generator: DocBook XSL Stylesheets v1.75.2 +.\" Date: 07/08/2012 +.\" Manual: \ \& +.\" Source: \ \& 3.0 .\" Language: English .\" -.TH "PDNS_RECURSOR" "1" "02/10/2010" "[FIXME: source]" "[FIXME: manual]" +.TH "PDNS_RECURSOR" "1" "07/08/2012" "\ \& 3\&.0" "\ \&" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aescpp.h pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aescpp.h --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aescpp.h 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aescpp.h 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,148 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 + + This file contains the definitions required to use AES (Rijndael) in C++. +*/ + +#ifndef _AESCPP_H +#define _AESCPP_H + +#include "aes.h" + +#if defined( AES_ENCRYPT ) + +class AESencrypt +{ +public: + aes_encrypt_ctx cx[1]; + AESencrypt(void) { aes_init(); }; +#if defined(AES_128) + AESencrypt(const unsigned char key[]) + { aes_encrypt_key128(key, cx); } + AES_RETURN key128(const unsigned char key[]) + { return aes_encrypt_key128(key, cx); } +#endif +#if defined(AES_192) + AES_RETURN key192(const unsigned char key[]) + { return aes_encrypt_key192(key, cx); } +#endif +#if defined(AES_256) + AES_RETURN key256(const unsigned char key[]) + { return aes_encrypt_key256(key, cx); } +#endif +#if defined(AES_VAR) + AES_RETURN key(const unsigned char key[], int key_len) + { return aes_encrypt_key(key, key_len, cx); } +#endif + AES_RETURN encrypt(const unsigned char in[], unsigned char out[]) const + { return aes_encrypt(in, out, cx); } +#ifndef AES_MODES + AES_RETURN ecb_encrypt(const unsigned char in[], unsigned char out[], int nb) const + { while(nb--) + { aes_encrypt(in, out, cx), in += AES_BLOCK_SIZE, out += AES_BLOCK_SIZE; } + } +#endif +#ifdef AES_MODES + AES_RETURN mode_reset(void) { return aes_mode_reset(cx); } + + AES_RETURN ecb_encrypt(const unsigned char in[], unsigned char out[], int nb) const + { return aes_ecb_encrypt(in, out, nb, cx); } + + AES_RETURN cbc_encrypt(const unsigned char in[], unsigned char out[], int nb, + unsigned char iv[]) const + { return aes_cbc_encrypt(in, out, nb, iv, cx); } + + AES_RETURN cfb_encrypt(const unsigned char in[], unsigned char out[], int nb, + unsigned char iv[]) + { return aes_cfb_encrypt(in, out, nb, iv, cx); } + + AES_RETURN cfb_decrypt(const unsigned char in[], unsigned char out[], int nb, + unsigned char iv[]) + { return aes_cfb_decrypt(in, out, nb, iv, cx); } + + AES_RETURN ofb_crypt(const unsigned char in[], unsigned char out[], int nb, + unsigned char iv[]) + { return aes_ofb_crypt(in, out, nb, iv, cx); } + + typedef void ctr_fn(unsigned char ctr[]); + + AES_RETURN ctr_crypt(const unsigned char in[], unsigned char out[], int nb, + unsigned char iv[], ctr_fn cf) + { return aes_ctr_crypt(in, out, nb, iv, cf, cx); } + +#endif + +}; + +#endif + +#if defined( AES_DECRYPT ) + +class AESdecrypt +{ +public: + aes_decrypt_ctx cx[1]; + AESdecrypt(void) { aes_init(); }; +#if defined(AES_128) + AESdecrypt(const unsigned char key[]) + { aes_decrypt_key128(key, cx); } + AES_RETURN key128(const unsigned char key[]) + { return aes_decrypt_key128(key, cx); } +#endif +#if defined(AES_192) + AES_RETURN key192(const unsigned char key[]) + { return aes_decrypt_key192(key, cx); } +#endif +#if defined(AES_256) + AES_RETURN key256(const unsigned char key[]) + { return aes_decrypt_key256(key, cx); } +#endif +#if defined(AES_VAR) + AES_RETURN key(const unsigned char key[], int key_len) + { return aes_decrypt_key(key, key_len, cx); } +#endif + AES_RETURN decrypt(const unsigned char in[], unsigned char out[]) const + { return aes_decrypt(in, out, cx); } +#ifndef AES_MODES + AES_RETURN ecb_decrypt(const unsigned char in[], unsigned char out[], int nb) const + { while(nb--) + { aes_decrypt(in, out, cx), in += AES_BLOCK_SIZE, out += AES_BLOCK_SIZE; } + } +#endif +#ifdef AES_MODES + + AES_RETURN ecb_decrypt(const unsigned char in[], unsigned char out[], int nb) const + { return aes_ecb_decrypt(in, out, nb, cx); } + + AES_RETURN cbc_decrypt(const unsigned char in[], unsigned char out[], int nb, + unsigned char iv[]) const + { return aes_cbc_decrypt(in, out, nb, iv, cx); } +#endif +}; + +#endif + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aescrypt.c pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aescrypt.c --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aescrypt.c 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aescrypt.c 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,301 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 +*/ + +#include "aesopt.h" +#include "aestab.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c]) +#define so(y,x,c) word_out(y, c, s(x,c)) + +#if defined(ARRAYS) +#define locals(y,x) x[4],y[4] +#else +#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 +#endif + +#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ + s(y,2) = s(x,2); s(y,3) = s(x,3); +#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) +#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) +#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) + +#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimiation with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined( _MSC_VER ) && !defined( _WIN64 ) +#pragma optimize( "s", on ) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define fwd_var(x,r,c)\ + ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ + : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\ + : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ + : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))) + +#if defined(FT4_SET) +#undef dec_fmvars +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c)) +#elif defined(FT1_SET) +#undef dec_fmvars +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c)) +#else +#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c))) +#endif + +#if defined(FL4_SET) +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c)) +#elif defined(FL1_SET) +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c)) +#else +#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c)) +#endif + +AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]) +{ uint_32t locals(b0, b1); + const uint_32t *kp; +#if defined( dec_fmvars ) + dec_fmvars; /* declare variables for fwd_mcol() if needed */ +#endif + + if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 ) + return EXIT_FAILURE; + + kp = cx->ks; + state_in(b0, in, kp); + +#if (ENC_UNROLL == FULL) + + switch(cx->inf.b[0]) + { + case 14 * 16: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + case 12 * 16: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + kp += 2 * N_COLS; + case 10 * 16: + round(fwd_rnd, b1, b0, kp + 1 * N_COLS); + round(fwd_rnd, b0, b1, kp + 2 * N_COLS); + round(fwd_rnd, b1, b0, kp + 3 * N_COLS); + round(fwd_rnd, b0, b1, kp + 4 * N_COLS); + round(fwd_rnd, b1, b0, kp + 5 * N_COLS); + round(fwd_rnd, b0, b1, kp + 6 * N_COLS); + round(fwd_rnd, b1, b0, kp + 7 * N_COLS); + round(fwd_rnd, b0, b1, kp + 8 * N_COLS); + round(fwd_rnd, b1, b0, kp + 9 * N_COLS); + round(fwd_lrnd, b0, b1, kp +10 * N_COLS); + } + +#else + +#if (ENC_UNROLL == PARTIAL) + { uint_32t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) + { + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + kp += N_COLS; + round(fwd_rnd, b0, b1, kp); + } + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); +#else + { uint_32t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) + { + kp += N_COLS; + round(fwd_rnd, b1, b0, kp); + l_copy(b0, b1); + } +#endif + kp += N_COLS; + round(fwd_lrnd, b0, b1, kp); + } +#endif + + state_out(out, b0); + return EXIT_SUCCESS; +} + +#endif + +#if ( FUNCS_IN_C & DECRYPTION_IN_C) + +/* Visual C++ .Net v7.1 provides the fastest encryption code when using + Pentium optimiation with small code but this is poor for decryption + so we need to control this with the following VC++ pragmas +*/ + +#if defined( _MSC_VER ) && !defined( _WIN64 ) +#pragma optimize( "t", on ) +#endif + +/* Given the column (c) of the output state variable, the following + macros give the input state variables which are needed in its + computation for each row (r) of the state. All the alternative + macros give the same end values but expand into different ways + of calculating these values. In particular the complex macro + used for dynamically variable block sizes is designed to expand + to a compile time constant whenever possible but will expand to + conditional clauses on some branches (I am grateful to Frank + Yellin for this construction) +*/ + +#define inv_var(x,r,c)\ + ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ + : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\ + : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ + : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))) + +#if defined(IT4_SET) +#undef dec_imvars +#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c)) +#elif defined(IT1_SET) +#undef dec_imvars +#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c)) +#else +#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))) +#endif + +#if defined(IL4_SET) +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c)) +#elif defined(IL1_SET) +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c)) +#else +#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)) +#endif + +/* This code can work with the decryption key schedule in the */ +/* order that is used for encrytpion (where the 1st decryption */ +/* round key is at the high end ot the schedule) or with a key */ +/* schedule that has been reversed to put the 1st decryption */ +/* round key at the low end of the schedule in memory (when */ +/* AES_REV_DKS is defined) */ + +#ifdef AES_REV_DKS +#define key_ofs 0 +#define rnd_key(n) (kp + n * N_COLS) +#else +#define key_ofs 1 +#define rnd_key(n) (kp - n * N_COLS) +#endif + +AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]) +{ uint_32t locals(b0, b1); +#if defined( dec_imvars ) + dec_imvars; /* declare variables for inv_mcol() if needed */ +#endif + const uint_32t *kp; + + if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 ) + return EXIT_FAILURE; + + kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); + state_in(b0, in, kp); + +#if (DEC_UNROLL == FULL) + + kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); + switch(cx->inf.b[0]) + { + case 14 * 16: + round(inv_rnd, b1, b0, rnd_key(-13)); + round(inv_rnd, b0, b1, rnd_key(-12)); + case 12 * 16: + round(inv_rnd, b1, b0, rnd_key(-11)); + round(inv_rnd, b0, b1, rnd_key(-10)); + case 10 * 16: + round(inv_rnd, b1, b0, rnd_key(-9)); + round(inv_rnd, b0, b1, rnd_key(-8)); + round(inv_rnd, b1, b0, rnd_key(-7)); + round(inv_rnd, b0, b1, rnd_key(-6)); + round(inv_rnd, b1, b0, rnd_key(-5)); + round(inv_rnd, b0, b1, rnd_key(-4)); + round(inv_rnd, b1, b0, rnd_key(-3)); + round(inv_rnd, b0, b1, rnd_key(-2)); + round(inv_rnd, b1, b0, rnd_key(-1)); + round(inv_lrnd, b0, b1, rnd_key( 0)); + } + +#else + +#if (DEC_UNROLL == PARTIAL) + { uint_32t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) + { + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); + kp = rnd_key(1); + round(inv_rnd, b0, b1, kp); + } + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); +#else + { uint_32t rnd; + for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) + { + kp = rnd_key(1); + round(inv_rnd, b1, b0, kp); + l_copy(b0, b1); + } +#endif + kp = rnd_key(1); + round(inv_lrnd, b0, b1, kp); + } +#endif + + state_out(out, b0); + return EXIT_SUCCESS; +} + +#endif + +#if defined(__cplusplus) +} +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aes.h pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aes.h --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aes.h 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aes.h 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,205 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 + + This file contains the definitions required to use AES in C. See aesopt.h + for optimisation details. +*/ + +#ifndef _AES_H +#define _AES_H + +#include + +/* This include is used to find 8 & 32 bit unsigned integer types */ +#include "brg_types.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#define AES_128 /* if a fast 128 bit key scheduler is needed */ +#define AES_192 /* if a fast 192 bit key scheduler is needed */ +#define AES_256 /* if a fast 256 bit key scheduler is needed */ +#define AES_VAR /* if variable key size scheduler is needed */ +#define AES_MODES /* if support is needed for modes */ + +/* The following must also be set in assembler files if being used */ + +#define AES_ENCRYPT /* if support for encryption is needed */ +#define AES_DECRYPT /* if support for decryption is needed */ +#define AES_REV_DKS /* define to reverse decryption key schedule */ + +#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */ +#define N_COLS 4 /* the number of columns in the state */ + +/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ +/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ +/* or 44, 52 or 60 32-bit words. */ + +#if defined( AES_VAR ) || defined( AES_256 ) +#define KS_LENGTH 60 +#elif defined( AES_192 ) +#define KS_LENGTH 52 +#else +#define KS_LENGTH 44 +#endif + +#define AES_RETURN INT_RETURN + +/* the character array 'inf' in the following structures is used */ +/* to hold AES context information. This AES code uses cx->inf.b[0] */ +/* to hold the number of rounds multiplied by 16. The other three */ +/* elements can be used by code that implements additional modes */ + +typedef union +{ uint_32t l; + uint_8t b[4]; +} aes_inf; + +typedef struct +{ uint_32t ks[KS_LENGTH]; + aes_inf inf; +} aes_encrypt_ctx; + +typedef struct +{ uint_32t ks[KS_LENGTH]; + aes_inf inf; +} aes_decrypt_ctx; + +/* This routine must be called before first use if non-static */ +/* tables are being used */ + +AES_RETURN aes_init(void); + +/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */ +/* those in the range 128 <= key_len <= 256 are given in bits */ + +#if defined( AES_ENCRYPT ) + +#if defined( AES_128 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); +#endif + +#if defined( AES_192 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); +#endif + +#if defined( AES_256 ) || defined( AES_VAR) +AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); +#endif + +#if defined( AES_VAR ) +AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); +#endif + +AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); + +#endif + +#if defined( AES_DECRYPT ) + +#if defined( AES_128 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif + +#if defined( AES_192 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif + +#if defined( AES_256 ) || defined( AES_VAR) +AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); +#endif + +#if defined( AES_VAR ) +AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); +#endif + +AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); + +#endif + +#if defined( AES_MODES ) + +/* Multiple calls to the following subroutines for multiple block */ +/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */ +/* long messages incremantally provided that the context AND the iv */ +/* are preserved between all such calls. For the ECB and CBC modes */ +/* each individual call within a series of incremental calls must */ +/* process only full blocks (i.e. len must be a multiple of 16) but */ +/* the CFB, OFB and CTR mode calls can handle multiple incremental */ +/* calls of any length. Each mode is reset when a new AES key is */ +/* set but ECB and CBC operations can be reset without setting a */ +/* new key by setting a new IV value. To reset CFB, OFB and CTR */ +/* without setting the key, aes_mode_reset() must be called and the */ +/* IV must be set. NOTE: All these calls update the IV on exit so */ +/* this has to be reset if a new operation with the same IV as the */ +/* previous one is required (or decryption follows encryption with */ +/* the same IV array). */ + +AES_RETURN aes_test_alignment_detection(unsigned int n); + +AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_encrypt_ctx cx[1]); + +AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_decrypt_ctx cx[1]); + +AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_decrypt_ctx cx[1]); + +AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +#define aes_ofb_encrypt aes_ofb_crypt +#define aes_ofb_decrypt aes_ofb_crypt + +AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx cx[1]); + +typedef void cbuf_inc(unsigned char *cbuf); + +#define aes_ctr_encrypt aes_ctr_crypt +#define aes_ctr_decrypt aes_ctr_crypt + +AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]); + +#endif + +#if defined(__cplusplus) +} +#endif + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aeskey.c pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aeskey.c --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aeskey.c 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aeskey.c 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,555 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 +*/ + +#include "aesopt.h" +#include "aestab.h" + +#ifdef USE_VIA_ACE_IF_PRESENT +# include "aes_via_ace.h" +#endif + +#if defined(__cplusplus) +extern "C" +{ +#endif + +/* Initialise the key schedule from the user supplied key. The key + length can be specified in bytes, with legal values of 16, 24 + and 32, or in bits, with legal values of 128, 192 and 256. These + values correspond with Nk values of 4, 6 and 8 respectively. + + The following macros implement a single cycle in the key + schedule generation process. The number of cycles needed + for each cx->n_col and nk value is: + + nk = 4 5 6 7 8 + ------------------------------ + cx->n_col = 4 10 9 8 7 7 + cx->n_col = 5 14 11 10 9 9 + cx->n_col = 6 19 15 12 11 11 + cx->n_col = 7 21 19 16 13 14 + cx->n_col = 8 29 23 19 17 14 +*/ + +#if defined( REDUCE_CODE_SIZE ) +# define ls_box ls_sub + uint_32t ls_sub(const uint_32t t, const uint_32t n); +# define inv_mcol im_sub + uint_32t im_sub(const uint_32t x); +# ifdef ENC_KS_UNROLL +# undef ENC_KS_UNROLL +# endif +# ifdef DEC_KS_UNROLL +# undef DEC_KS_UNROLL +# endif +#endif + +#if (FUNCS_IN_C & ENC_KEYING_IN_C) + +#if defined(AES_128) || defined( AES_VAR ) + +#define ke4(k,i) \ +{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + k[4*(i)+5] = ss[1] ^= ss[0]; \ + k[4*(i)+6] = ss[2] ^= ss[1]; \ + k[4*(i)+7] = ss[3] ^= ss[2]; \ +} + +AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint_32t ss[4]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + +#ifdef ENC_KS_UNROLL + ke4(cx->ks, 0); ke4(cx->ks, 1); + ke4(cx->ks, 2); ke4(cx->ks, 3); + ke4(cx->ks, 4); ke4(cx->ks, 5); + ke4(cx->ks, 6); ke4(cx->ks, 7); + ke4(cx->ks, 8); +#else + { uint_32t i; + for(i = 0; i < 9; ++i) + ke4(cx->ks, i); + } +#endif + ke4(cx->ks, 9); + cx->inf.l = 0; + cx->inf.b[0] = 10 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_192) || defined( AES_VAR ) + +#define kef6(k,i) \ +{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + k[6*(i)+ 7] = ss[1] ^= ss[0]; \ + k[6*(i)+ 8] = ss[2] ^= ss[1]; \ + k[6*(i)+ 9] = ss[3] ^= ss[2]; \ +} + +#define ke6(k,i) \ +{ kef6(k,i); \ + k[6*(i)+10] = ss[4] ^= ss[3]; \ + k[6*(i)+11] = ss[5] ^= ss[4]; \ +} + +AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint_32t ss[6]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + cx->ks[4] = ss[4] = word_in(key, 4); + cx->ks[5] = ss[5] = word_in(key, 5); + +#ifdef ENC_KS_UNROLL + ke6(cx->ks, 0); ke6(cx->ks, 1); + ke6(cx->ks, 2); ke6(cx->ks, 3); + ke6(cx->ks, 4); ke6(cx->ks, 5); + ke6(cx->ks, 6); +#else + { uint_32t i; + for(i = 0; i < 7; ++i) + ke6(cx->ks, i); + } +#endif + kef6(cx->ks, 7); + cx->inf.l = 0; + cx->inf.b[0] = 12 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_256) || defined( AES_VAR ) + +#define kef8(k,i) \ +{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + k[8*(i)+ 9] = ss[1] ^= ss[0]; \ + k[8*(i)+10] = ss[2] ^= ss[1]; \ + k[8*(i)+11] = ss[3] ^= ss[2]; \ +} + +#define ke8(k,i) \ +{ kef8(k,i); \ + k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \ + k[8*(i)+13] = ss[5] ^= ss[4]; \ + k[8*(i)+14] = ss[6] ^= ss[5]; \ + k[8*(i)+15] = ss[7] ^= ss[6]; \ +} + +AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]) +{ uint_32t ss[8]; + + cx->ks[0] = ss[0] = word_in(key, 0); + cx->ks[1] = ss[1] = word_in(key, 1); + cx->ks[2] = ss[2] = word_in(key, 2); + cx->ks[3] = ss[3] = word_in(key, 3); + cx->ks[4] = ss[4] = word_in(key, 4); + cx->ks[5] = ss[5] = word_in(key, 5); + cx->ks[6] = ss[6] = word_in(key, 6); + cx->ks[7] = ss[7] = word_in(key, 7); + +#ifdef ENC_KS_UNROLL + ke8(cx->ks, 0); ke8(cx->ks, 1); + ke8(cx->ks, 2); ke8(cx->ks, 3); + ke8(cx->ks, 4); ke8(cx->ks, 5); +#else + { uint_32t i; + for(i = 0; i < 6; ++i) + ke8(cx->ks, i); + } +#endif + kef8(cx->ks, 6); + cx->inf.l = 0; + cx->inf.b[0] = 14 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined( AES_VAR ) + +AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]) +{ + switch(key_len) + { + case 16: case 128: return aes_encrypt_key128(key, cx); + case 24: case 192: return aes_encrypt_key192(key, cx); + case 32: case 256: return aes_encrypt_key256(key, cx); + default: return EXIT_FAILURE; + } +} + +#endif + +#endif + +#if (FUNCS_IN_C & DEC_KEYING_IN_C) + +/* this is used to store the decryption round keys */ +/* in forward or reverse order */ + +#ifdef AES_REV_DKS +#define v(n,i) ((n) - (i) + 2 * ((i) & 3)) +#else +#define v(n,i) (i) +#endif + +#if DEC_ROUND == NO_TABLES +#define ff(x) (x) +#else +#define ff(x) inv_mcol(x) +#if defined( dec_imvars ) +#define d_vars dec_imvars +#endif +#endif + +#if defined(AES_128) || defined( AES_VAR ) + +#define k4e(k,i) \ +{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \ + k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \ + k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \ +} + +#if 1 + +#define kdf4(k,i) \ +{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ + ss[1] = ss[1] ^ ss[3]; \ + ss[2] = ss[2] ^ ss[3]; \ + ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ + ss[i % 4] ^= ss[4]; \ + ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \ + ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \ +} + +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ + ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ + k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \ + k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \ + k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \ + k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \ +} + +#define kdl4(k,i) \ +{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ + k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ + k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \ + k[v(40,(4*(i))+6)] = ss[0]; \ + k[v(40,(4*(i))+7)] = ss[1]; \ +} + +#else + +#define kdf4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \ +} + +#define kd4(k,i) \ +{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \ +} + +#define kdl4(k,i) \ +{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \ +} + +#endif + +AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint_32t ss[5]; +#if defined( d_vars ) + d_vars; +#endif + cx->ks[v(40,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(40,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(40,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(40,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + kdf4(cx->ks, 0); kd4(cx->ks, 1); + kd4(cx->ks, 2); kd4(cx->ks, 3); + kd4(cx->ks, 4); kd4(cx->ks, 5); + kd4(cx->ks, 6); kd4(cx->ks, 7); + kd4(cx->ks, 8); kdl4(cx->ks, 9); +#else + { uint_32t i; + for(i = 0; i < 10; ++i) + k4e(cx->ks, i); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 10 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 10 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_192) || defined( AES_VAR ) + +#define k6ef(k,i) \ +{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \ + k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \ + k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \ +} + +#define k6e(k,i) \ +{ k6ef(k,i); \ + k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \ + k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \ +} + +#define kdf6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \ + ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \ + ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \ +} + +#define kd6(k,i) \ +{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \ + ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \ + ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \ +} + +#define kdl6(k,i) \ +{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \ +} + +AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint_32t ss[7]; +#if defined( d_vars ) + d_vars; +#endif + cx->ks[v(48,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(48,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(48,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(48,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + cx->ks[v(48,(4))] = ff(ss[4] = word_in(key, 4)); + cx->ks[v(48,(5))] = ff(ss[5] = word_in(key, 5)); + kdf6(cx->ks, 0); kd6(cx->ks, 1); + kd6(cx->ks, 2); kd6(cx->ks, 3); + kd6(cx->ks, 4); kd6(cx->ks, 5); + kd6(cx->ks, 6); kdl6(cx->ks, 7); +#else + cx->ks[v(48,(4))] = ss[4] = word_in(key, 4); + cx->ks[v(48,(5))] = ss[5] = word_in(key, 5); + { uint_32t i; + + for(i = 0; i < 7; ++i) + k6e(cx->ks, i); + k6ef(cx->ks, 7); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 12 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 12 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined(AES_256) || defined( AES_VAR ) + +#define k8ef(k,i) \ +{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \ + k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \ + k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \ +} + +#define k8e(k,i) \ +{ k8ef(k,i); \ + k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \ + k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \ + k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \ + k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \ +} + +#define kdf8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \ + ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \ + ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \ + ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \ + ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \ +} + +#define kd8(k,i) \ +{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \ + ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \ + ss[8] = ls_box(ss[3],0); \ + ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \ + ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \ + ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \ + ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \ +} + +#define kdl8(k,i) \ +{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \ + ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \ + ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \ + ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \ +} + +AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]) +{ uint_32t ss[9]; +#if defined( d_vars ) + d_vars; +#endif + cx->ks[v(56,(0))] = ss[0] = word_in(key, 0); + cx->ks[v(56,(1))] = ss[1] = word_in(key, 1); + cx->ks[v(56,(2))] = ss[2] = word_in(key, 2); + cx->ks[v(56,(3))] = ss[3] = word_in(key, 3); + +#ifdef DEC_KS_UNROLL + cx->ks[v(56,(4))] = ff(ss[4] = word_in(key, 4)); + cx->ks[v(56,(5))] = ff(ss[5] = word_in(key, 5)); + cx->ks[v(56,(6))] = ff(ss[6] = word_in(key, 6)); + cx->ks[v(56,(7))] = ff(ss[7] = word_in(key, 7)); + kdf8(cx->ks, 0); kd8(cx->ks, 1); + kd8(cx->ks, 2); kd8(cx->ks, 3); + kd8(cx->ks, 4); kd8(cx->ks, 5); + kdl8(cx->ks, 6); +#else + cx->ks[v(56,(4))] = ss[4] = word_in(key, 4); + cx->ks[v(56,(5))] = ss[5] = word_in(key, 5); + cx->ks[v(56,(6))] = ss[6] = word_in(key, 6); + cx->ks[v(56,(7))] = ss[7] = word_in(key, 7); + { uint_32t i; + + for(i = 0; i < 6; ++i) + k8e(cx->ks, i); + k8ef(cx->ks, 6); +#if !(DEC_ROUND == NO_TABLES) + for(i = N_COLS; i < 14 * N_COLS; ++i) + cx->ks[i] = inv_mcol(cx->ks[i]); +#endif + } +#endif + cx->inf.l = 0; + cx->inf.b[0] = 14 * 16; + +#ifdef USE_VIA_ACE_IF_PRESENT + if(VIA_ACE_AVAILABLE) + cx->inf.b[1] = 0xff; +#endif + return EXIT_SUCCESS; +} + +#endif + +#if defined( AES_VAR ) + +AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]) +{ + switch(key_len) + { + case 16: case 128: return aes_decrypt_key128(key, cx); + case 24: case 192: return aes_decrypt_key192(key, cx); + case 32: case 256: return aes_decrypt_key256(key, cx); + default: return EXIT_FAILURE; + } +} + +#endif + +#endif + +#if defined(__cplusplus) +} +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aes_modes.c pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aes_modes.c --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aes_modes.c 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aes_modes.c 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,918 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 + + These subroutines implement multiple block AES modes for ECB, CBC, CFB, + OFB and CTR encryption, The code provides support for the VIA Advanced + Cryptography Engine (ACE). + + NOTE: In the following subroutines, the AES contexts (ctx) must be + 16 byte aligned if VIA ACE is being used +*/ + +#include +#include + +#include "aesopt.h" + +#if defined( AES_MODES ) +#if defined(__cplusplus) +extern "C" +{ +#endif + +#if defined( _MSC_VER ) && ( _MSC_VER > 800 ) +#pragma intrinsic(memcpy) +#endif + +#define BFR_BLOCKS 8 + +/* These values are used to detect long word alignment in order to */ +/* speed up some buffer operations. This facility may not work on */ +/* some machines so this define can be commented out if necessary */ + +#define FAST_BUFFER_OPERATIONS + +#define lp32(x) ((uint_32t*)(x)) + +#if defined( USE_VIA_ACE_IF_PRESENT ) + +#include "aes_via_ace.h" + +#pragma pack(16) + +aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA; +aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA; +aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA; +aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA; +aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA; +aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA; + +/* NOTE: These control word macros must only be used after */ +/* a key has been set up because they depend on key size */ + +#if NEH_KEY_TYPE == NEH_LOAD +#define kd_adr(c) ((uint_8t*)(c)->ks) +#elif NEH_KEY_TYPE == NEH_GENERATE +#define kd_adr(c) ((uint_8t*)(c)->ks + (c)->inf.b[0]) +#else +#define kd_adr(c) ((uint_8t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0)) +#endif + +#else + +#define aligned_array(type, name, no, stride) type name[no] +#define aligned_auto(type, name, no, stride) type name[no] + +#endif + +#if defined( _MSC_VER ) && _MSC_VER > 1200 + +#define via_cwd(cwd, ty, dir, len) \ + unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4)) + +#else + +#define via_cwd(cwd, ty, dir, len) \ + aligned_auto(unsigned long, cwd, 4, 16); \ + cwd[1] = cwd[2] = cwd[3] = 0; \ + cwd[0] = neh_##dir##_##ty##_key(len) + +#endif + +/* test the code for detecting and setting pointer alignment */ + +AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */ +{ uint_8t p[16]; + uint_32t i, count_eq = 0, count_neq = 0; + + if(n < 4 || n > 16) + return EXIT_FAILURE; + + for(i = 0; i < n; ++i) + { + uint_8t *qf = ALIGN_FLOOR(p + i, n), + *qh = ALIGN_CEIL(p + i, n); + + if(qh == qf) + ++count_eq; + else if(qh == qf + n) + ++count_neq; + else + return EXIT_FAILURE; + } + return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS); +} + +AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1]) +{ + ctx->inf.b[2] = 0; + return EXIT_SUCCESS; +} + +AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_encrypt_ctx ctx[1]) +{ int nb = len >> 4; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint_8t *ksp = (uint_8t*)(ctx->ks); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_ecb_op5(ksp,cwd,ibuf,obuf,nb); + } + else + { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint_8t *ip, *op; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ecb_op5(ksp,cwd,ip,op,m); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + return EXIT_SUCCESS; + } + +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) + while(nb--) + { + if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, const aes_decrypt_ctx ctx[1]) +{ int nb = len >> 4; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint_8t *ksp = kd_adr(ctx); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_ecb_op5(ksp,cwd,ibuf,obuf,nb); + } + else + { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint_8t *ip, *op; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ecb_op5(ksp,cwd,ip,op,m); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + return EXIT_SUCCESS; + } + +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) + while(nb--) + { + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_encrypt_ctx ctx[1]) +{ int nb = len >> 4; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv; + aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) + { + via_cbc_op7(ksp,cwd,ibuf,obuf,nb,ivp,ivp); + } + else + { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint_8t *ip, *op; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cbc_op7(ksp,cwd,ip,op,m,ivp,ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + if(iv != ivp) + memcpy(iv, ivp, AES_BLOCK_SIZE); + + return EXIT_SUCCESS; + } + +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(nb--) + { + lp32(iv)[0] ^= lp32(ibuf)[0]; + lp32(iv)[1] ^= lp32(ibuf)[1]; + lp32(iv)[2] ^= lp32(ibuf)[2]; + lp32(iv)[3] ^= lp32(ibuf)[3]; + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + memcpy(obuf, iv, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +# endif + while(nb--) + { + iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1]; + iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3]; + iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5]; + iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7]; + iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9]; + iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11]; + iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13]; + iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15]; + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + memcpy(obuf, iv, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, const aes_decrypt_ctx ctx[1]) +{ unsigned char tmp[AES_BLOCK_SIZE]; + int nb = len >> 4; + + if(len & (AES_BLOCK_SIZE - 1)) + return EXIT_FAILURE; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { uint_8t *ksp = kd_adr(ctx), *ivp = iv; + aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) + { + via_cbc_op6(ksp,cwd,ibuf,obuf,nb,ivp); + } + else + { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint_8t *ip, *op; + + while(nb) + { + int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cbc_op6(ksp,cwd,ip,op,m,ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + nb -= m; + } + } + + if(iv != ivp) + memcpy(iv, ivp, AES_BLOCK_SIZE); + + return EXIT_SUCCESS; + } +#endif + +#if !defined( ASSUME_VIA_ACE_PRESENT ) +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(nb--) + { + memcpy(tmp, ibuf, AES_BLOCK_SIZE); + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + lp32(obuf)[0] ^= lp32(iv)[0]; + lp32(obuf)[1] ^= lp32(iv)[1]; + lp32(obuf)[2] ^= lp32(iv)[2]; + lp32(obuf)[3] ^= lp32(iv)[3]; + memcpy(iv, tmp, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +# endif + while(nb--) + { + memcpy(tmp, ibuf, AES_BLOCK_SIZE); + if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1]; + obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3]; + obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5]; + obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7]; + obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9]; + obuf[10] ^= iv[10]; obuf[11] ^= iv[11]; + obuf[12] ^= iv[12]; obuf[13] ^= iv[13]; + obuf[14] ^= iv[14]; obuf[15] ^= iv[15]; + memcpy(iv, tmp, AES_BLOCK_SIZE); + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } +#endif + return EXIT_SUCCESS; +} + +AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) +{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; + + if(b_pos) /* complete any partial block */ + { + while(b_pos < AES_BLOCK_SIZE && cnt < len) + *obuf++ = iv[b_pos++] ^= *ibuf++, cnt++; + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ + { +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { int m; + uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv; + aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } + else /* input, output or both are unaligned */ + { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint_8t *ip, *op; + + while(nb) + { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) + memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0]; + lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1]; + lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2]; + lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +# endif + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1]; + obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3]; + obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5]; + obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7]; + obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9]; + obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11]; + obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13]; + obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) + { + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) + *obuf++ = iv[b_pos++] ^= *ibuf++, cnt++; + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = b_pos; + return EXIT_SUCCESS; +} + +AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) +{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; + + if(b_pos) /* complete any partial block */ + { uint_8t t; + + while(b_pos < AES_BLOCK_SIZE && cnt < len) + t = *ibuf++, *obuf++ = t ^ iv[b_pos], iv[b_pos++] = t, cnt++; + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ + { +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { int m; + uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv; + aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } + else /* input, output or both are unaligned */ + { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint_8t *ip, *op; + + while(nb) + { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) /* input buffer is not aligned */ + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_cfb_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) /* output buffer is not aligned */ + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) + memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 )) + while(cnt + AES_BLOCK_SIZE <= len) + { uint_32t t; + + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t; + t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t; + t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t; + t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +# endif + while(cnt + AES_BLOCK_SIZE <= len) + { uint_8t t; + + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t; + t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t; + t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t; + t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t; + t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t; + t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t; + t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t; + t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t; + t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t; + t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t; + t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t; + t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t; + t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t; + t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t; + t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t; + t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) + { uint_8t t; + + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) + t = *ibuf++, *obuf++ = t ^ iv[b_pos], iv[b_pos++] = t, cnt++; + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = b_pos; + return EXIT_SUCCESS; +} + +AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) +{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; + + if(b_pos) /* complete any partial block */ + { + while(b_pos < AES_BLOCK_SIZE && cnt < len) + *obuf++ = iv[b_pos++] ^ *ibuf++, cnt++; + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ + { +#if defined( USE_VIA_ACE_IF_PRESENT ) + + if(ctx->inf.b[1] == 0xff) + { int m; + uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv; + aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + + if(ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; + + if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ + { + ivp = liv; + memcpy(liv, iv, AES_BLOCK_SIZE); + } + + if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) + { + via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp); + ibuf += nb * AES_BLOCK_SIZE; + obuf += nb * AES_BLOCK_SIZE; + cnt += nb * AES_BLOCK_SIZE; + } + else /* input, output or both are unaligned */ + { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); + uint_8t *ip, *op; + + while(nb) + { + m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; + + ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); + op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); + + if(ip != ibuf) + memcpy(buf, ibuf, m * AES_BLOCK_SIZE); + + via_ofb_op6(ksp, cwd, ip, op, m, ivp); + + if(op != obuf) + memcpy(obuf, buf, m * AES_BLOCK_SIZE); + + ibuf += m * AES_BLOCK_SIZE; + obuf += m * AES_BLOCK_SIZE; + cnt += m * AES_BLOCK_SIZE; + } + } + + if(ivp != iv) + memcpy(iv, ivp, AES_BLOCK_SIZE); + } +#else +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0]; + lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1]; + lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2]; + lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } + else +# endif + while(cnt + AES_BLOCK_SIZE <= len) + { + assert(b_pos == 0); + if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1]; + obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3]; + obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5]; + obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7]; + obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9]; + obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11]; + obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13]; + obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15]; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + cnt += AES_BLOCK_SIZE; + } +#endif + } + + while(cnt < len) + { + if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + while(cnt < len && b_pos < AES_BLOCK_SIZE) + *obuf++ = iv[b_pos++] ^ *ibuf++, cnt++; + + b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); + } + + ctx->inf.b[2] = b_pos; + return EXIT_SUCCESS; +} + +#define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE) + +AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, + int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1]) +{ uint_8t *ip; + int i, blen, b_pos = (int)(ctx->inf.b[2]); + +#if defined( USE_VIA_ACE_IF_PRESENT ) + aligned_auto(uint_8t, buf, BFR_LENGTH, 16); + if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 )) + return EXIT_FAILURE; +#else + uint_8t buf[BFR_LENGTH]; +#endif + + if(b_pos) + { + memcpy(buf, cbuf, AES_BLOCK_SIZE); + if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + while(b_pos < AES_BLOCK_SIZE && len) + *obuf++ = *ibuf++ ^ buf[b_pos++], --len; + if(len) + ctr_inc(cbuf), b_pos = 0; + } + + while(len) + { + blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen; + + for(i = 0, ip = buf; i < (blen >> 4); ++i) + { + memcpy(ip, cbuf, AES_BLOCK_SIZE); + ctr_inc(cbuf); + ip += AES_BLOCK_SIZE; + } + + if(blen & (AES_BLOCK_SIZE - 1)) + memcpy(ip, cbuf, AES_BLOCK_SIZE), i++; + +#if defined( USE_VIA_ACE_IF_PRESENT ) + if(ctx->inf.b[1] == 0xff) + { + via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); + via_ecb_op5((ctx->ks),cwd,buf,buf,i); + } + else +#endif + if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) + return EXIT_FAILURE; + + i = 0; ip = buf; +# ifdef FAST_BUFFER_OPERATIONS + if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 )) + while(i + AES_BLOCK_SIZE <= blen) + { + lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0]; + lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1]; + lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2]; + lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3]; + i += AES_BLOCK_SIZE; + ip += AES_BLOCK_SIZE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + else +#endif + while(i + AES_BLOCK_SIZE <= blen) + { + obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1]; + obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3]; + obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5]; + obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7]; + obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9]; + obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11]; + obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13]; + obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15]; + i += AES_BLOCK_SIZE; + ip += AES_BLOCK_SIZE; + ibuf += AES_BLOCK_SIZE; + obuf += AES_BLOCK_SIZE; + } + + while(i++ < blen) + *obuf++ = *ibuf++ ^ ip[b_pos++]; + } + + ctx->inf.b[2] = b_pos; + return EXIT_SUCCESS; +} + +#if defined(__cplusplus) +} +#endif +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aesopt.h pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aesopt.h --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aesopt.h 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aesopt.h 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,746 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 + + This file contains the compilation options for AES (Rijndael) and code + that is common across encryption, key scheduling and table generation. + + OPERATION + + These source code files implement the AES algorithm Rijndael designed by + Joan Daemen and Vincent Rijmen. This version is designed for the standard + block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 + and 32 bytes). + + This version is designed for flexibility and speed using operations on + 32-bit words rather than operations on bytes. It can be compiled with + either big or little endian internal byte order but is faster when the + native byte order for the processor is used. + + THE CIPHER INTERFACE + + The cipher interface is implemented as an array of bytes in which lower + AES bit sequence indexes map to higher numeric significance within bytes. + + uint_8t (an unsigned 8-bit type) + uint_32t (an unsigned 32-bit type) + struct aes_encrypt_ctx (structure for the cipher encryption context) + struct aes_decrypt_ctx (structure for the cipher decryption context) + AES_RETURN the function return type + + C subroutine calls: + + AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); + AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, + const aes_encrypt_ctx cx[1]); + + AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); + AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, + const aes_decrypt_ctx cx[1]); + + IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that + you call aes_init() before AES is used so that the tables are initialised. + + C++ aes class subroutines: + + Class AESencrypt for encryption + + Construtors: + AESencrypt(void) + AESencrypt(const unsigned char *key) - 128 bit key + Members: + AES_RETURN key128(const unsigned char *key) + AES_RETURN key192(const unsigned char *key) + AES_RETURN key256(const unsigned char *key) + AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const + + Class AESdecrypt for encryption + Construtors: + AESdecrypt(void) + AESdecrypt(const unsigned char *key) - 128 bit key + Members: + AES_RETURN key128(const unsigned char *key) + AES_RETURN key192(const unsigned char *key) + AES_RETURN key256(const unsigned char *key) + AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const +*/ + +#if !defined( _AESOPT_H ) +#define _AESOPT_H + +#if defined( __cplusplus ) +#include "aescpp.h" +#else +#include "aes.h" +#endif + +/* PLATFORM SPECIFIC INCLUDES */ + +#include "brg_endian.h" + +/* CONFIGURATION - THE USE OF DEFINES + + Later in this section there are a number of defines that control the + operation of the code. In each section, the purpose of each define is + explained so that the relevant form can be included or excluded by + setting either 1's or 0's respectively on the branches of the related + #if clauses. The following local defines should not be changed. +*/ + +#define ENCRYPTION_IN_C 1 +#define DECRYPTION_IN_C 2 +#define ENC_KEYING_IN_C 4 +#define DEC_KEYING_IN_C 8 + +#define NO_TABLES 0 +#define ONE_TABLE 1 +#define FOUR_TABLES 4 +#define NONE 0 +#define PARTIAL 1 +#define FULL 2 + +/* --- START OF USER CONFIGURED OPTIONS --- */ + +/* 1. BYTE ORDER WITHIN 32 BIT WORDS + + The fundamental data processing units in Rijndael are 8-bit bytes. The + input, output and key input are all enumerated arrays of bytes in which + bytes are numbered starting at zero and increasing to one less than the + number of bytes in the array in question. This enumeration is only used + for naming bytes and does not imply any adjacency or order relationship + from one byte to another. When these inputs and outputs are considered + as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to + byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. + In this implementation bits are numbered from 0 to 7 starting at the + numerically least significant end of each byte (bit n represents 2^n). + + However, Rijndael can be implemented more efficiently using 32-bit + words by packing bytes into words so that bytes 4*n to 4*n+3 are placed + into word[n]. While in principle these bytes can be assembled into words + in any positions, this implementation only supports the two formats in + which bytes in adjacent positions within words also have adjacent byte + numbers. This order is called big-endian if the lowest numbered bytes + in words have the highest numeric significance and little-endian if the + opposite applies. + + This code can work in either order irrespective of the order used by the + machine on which it runs. Normally the internal byte order will be set + to the order of the processor on which the code is to be run but this + define can be used to reverse this in special situations + + WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set. + This define will hence be redefined later (in section 4) if necessary +*/ + +#if 1 +# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER +#elif 0 +# define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 +# define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error The algorithm byte order is not defined +#endif + +/* 2. VIA ACE SUPPORT */ + +#if defined( __GNUC__ ) && defined( __i386__ ) \ + || defined( _WIN32 ) && defined( _M_IX86 ) \ + && !(defined( _WIN64 ) || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 )) +# define VIA_ACE_POSSIBLE +#endif + +/* Define this option if support for the VIA ACE is required. This uses + inline assembler instructions and is only implemented for the Microsoft, + Intel and GCC compilers. If VIA ACE is known to be present, then defining + ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption + code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if + it is detected (both present and enabled) but the normal AES code will + also be present. + + When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte + aligned; other input/output buffers do not need to be 16 byte aligned + but there are very large performance gains if this can be arranged. + VIA ACE also requires the decryption key schedule to be in reverse + order (which later checks below ensure). +*/ + +#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) +# define USE_VIA_ACE_IF_PRESENT +#endif + +#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT ) +# define ASSUME_VIA_ACE_PRESENT +# endif + +/* 3. ASSEMBLER SUPPORT + + This define (which can be on the command line) enables the use of the + assembler code routines for encryption, decryption and key scheduling + as follows: + + ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for + encryption and decryption and but with key scheduling in C + ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for + encryption, decryption and key scheduling + ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for + encryption and decryption and but with key scheduling in C + ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for + encryption and decryption and but with key scheduling in C + + Change one 'if 0' below to 'if 1' to select the version or define + as a compilation option. +*/ + +#if 0 && !defined( ASM_X86_V1C ) +# define ASM_X86_V1C +#elif 0 && !defined( ASM_X86_V2 ) +# define ASM_X86_V2 +#elif 0 && !defined( ASM_X86_V2C ) +# define ASM_X86_V2C +#elif 0 && !defined( ASM_AMD64_C ) +# define ASM_AMD64_C +#endif + +#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \ + && !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 ) +# error Assembler code is only available for x86 and AMD64 systems +#endif + +/* 4. FAST INPUT/OUTPUT OPERATIONS. + + On some machines it is possible to improve speed by transferring the + bytes in the input and output arrays to and from the internal 32-bit + variables by addressing these arrays as if they are arrays of 32-bit + words. On some machines this will always be possible but there may + be a large performance penalty if the byte arrays are not aligned on + the normal word boundaries. On other machines this technique will + lead to memory access errors when such 32-bit word accesses are not + properly aligned. The option SAFE_IO avoids such problems but will + often be slower on those machines that support misaligned access + (especially so if care is taken to align the input and output byte + arrays on 32-bit word boundaries). If SAFE_IO is not defined it is + assumed that access to byte arrays as if they are arrays of 32-bit + words will not cause problems when such accesses are misaligned. +*/ +#if 1 && !defined( _MSC_VER ) +# define SAFE_IO +#endif + +/* 5. LOOP UNROLLING + + The code for encryption and decrytpion cycles through a number of rounds + that can be implemented either in a loop or by expanding the code into a + long sequence of instructions, the latter producing a larger program but + one that will often be much faster. The latter is called loop unrolling. + There are also potential speed advantages in expanding two iterations in + a loop with half the number of iterations, which is called partial loop + unrolling. The following options allow partial or full loop unrolling + to be set independently for encryption and decryption +*/ +#if 1 +# define ENC_UNROLL FULL +#elif 0 +# define ENC_UNROLL PARTIAL +#else +# define ENC_UNROLL NONE +#endif + +#if 1 +# define DEC_UNROLL FULL +#elif 0 +# define DEC_UNROLL PARTIAL +#else +# define DEC_UNROLL NONE +#endif + +#if 1 +# define ENC_KS_UNROLL +#endif + +#if 1 +# define DEC_KS_UNROLL +#endif + +/* 6. FAST FINITE FIELD OPERATIONS + + If this section is included, tables are used to provide faster finite + field arithmetic (this has no effect if FIXED_TABLES is defined). +*/ +#if 1 +# define FF_TABLES +#endif + +/* 7. INTERNAL STATE VARIABLE FORMAT + + The internal state of Rijndael is stored in a number of local 32-bit + word varaibles which can be defined either as an array or as individual + names variables. Include this section if you want to store these local + varaibles in arrays. Otherwise individual local variables will be used. +*/ +#if 1 +# define ARRAYS +#endif + +/* 8. FIXED OR DYNAMIC TABLES + + When this section is included the tables used by the code are compiled + statically into the binary file. Otherwise the subroutine aes_init() + must be called to compute them before the code is first used. +*/ +#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 )) +# define FIXED_TABLES +#endif + +/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES + + In some systems it is better to mask longer values to extract bytes + rather than using a cast. This option allows this choice. +*/ +#if 0 +# define to_byte(x) ((uint_8t)(x)) +#else +# define to_byte(x) ((x) & 0xff) +#endif + +/* 10. TABLE ALIGNMENT + + On some sytsems speed will be improved by aligning the AES large lookup + tables on particular boundaries. This define should be set to a power of + two giving the desired alignment. It can be left undefined if alignment + is not needed. This option is specific to the Microsft VC++ compiler - + it seems to sometimes cause trouble for the VC++ version 6 compiler. +*/ + +#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) +# define TABLE_ALIGN 32 +#endif + +/* 11. REDUCE CODE AND TABLE SIZE + + This replaces some expanded macros with function calls if AES_ASM_V2 or + AES_ASM_V2C are defined +*/ + +#if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) +# define REDUCE_CODE_SIZE +#endif + +/* 12. TABLE OPTIONS + + This cipher proceeds by repeating in a number of cycles known as 'rounds' + which are implemented by a round function which can optionally be speeded + up using tables. The basic tables are each 256 32-bit words, with either + one or four tables being required for each round function depending on + how much speed is required. The encryption and decryption round functions + are different and the last encryption and decrytpion round functions are + different again making four different round functions in all. + + This means that: + 1. Normal encryption and decryption rounds can each use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + 2. The last encryption and decryption rounds can also use either 0, 1 + or 4 tables and table spaces of 0, 1024 or 4096 bytes each. + + Include or exclude the appropriate definitions below to set the number + of tables used by this implementation. +*/ + +#if 1 /* set tables for the normal encryption round */ +# define ENC_ROUND FOUR_TABLES +#elif 0 +# define ENC_ROUND ONE_TABLE +#else +# define ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last encryption round */ +# define LAST_ENC_ROUND FOUR_TABLES +#elif 0 +# define LAST_ENC_ROUND ONE_TABLE +#else +# define LAST_ENC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the normal decryption round */ +# define DEC_ROUND FOUR_TABLES +#elif 0 +# define DEC_ROUND ONE_TABLE +#else +# define DEC_ROUND NO_TABLES +#endif + +#if 1 /* set tables for the last decryption round */ +# define LAST_DEC_ROUND FOUR_TABLES +#elif 0 +# define LAST_DEC_ROUND ONE_TABLE +#else +# define LAST_DEC_ROUND NO_TABLES +#endif + +/* The decryption key schedule can be speeded up with tables in the same + way that the round functions can. Include or exclude the following + defines to set this requirement. +*/ +#if 1 +# define KEY_SCHED FOUR_TABLES +#elif 0 +# define KEY_SCHED ONE_TABLE +#else +# define KEY_SCHED NO_TABLES +#endif + +/* ---- END OF USER CONFIGURED OPTIONS ---- */ + +/* VIA ACE support is only available for VC++ and GCC */ + +#if !defined( _MSC_VER ) && !defined( __GNUC__ ) +# if defined( ASSUME_VIA_ACE_PRESENT ) +# undef ASSUME_VIA_ACE_PRESENT +# endif +# if defined( USE_VIA_ACE_IF_PRESENT ) +# undef USE_VIA_ACE_IF_PRESENT +# endif +#endif + +#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT ) +# define USE_VIA_ACE_IF_PRESENT +#endif + +#if defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS ) +# define AES_REV_DKS +#endif + +/* Assembler support requires the use of platform byte order */ + +#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \ + && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER) +# undef ALGORITHM_BYTE_ORDER +# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER +#endif + +/* In this implementation the columns of the state array are each held in + 32-bit words. The state array can be held in various ways: in an array + of words, in a number of individual word variables or in a number of + processor registers. The following define maps a variable name x and + a column number c to the way the state array variable is to be held. + The first define below maps the state into an array x[c] whereas the + second form maps the state into a number of individual variables x0, + x1, etc. Another form could map individual state colums to machine + register names. +*/ + +#if defined( ARRAYS ) +# define s(x,c) x[c] +#else +# define s(x,c) x##c +#endif + +/* This implementation provides subroutines for encryption, decryption + and for setting the three key lengths (separately) for encryption + and decryption. Since not all functions are needed, masks are set + up here to determine which will be implemented in C +*/ + +#if !defined( AES_ENCRYPT ) +# define EFUNCS_IN_C 0 +#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ + || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) +# define EFUNCS_IN_C ENC_KEYING_IN_C +#elif !defined( ASM_X86_V2 ) +# define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C ) +#else +# define EFUNCS_IN_C 0 +#endif + +#if !defined( AES_DECRYPT ) +# define DFUNCS_IN_C 0 +#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ + || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) +# define DFUNCS_IN_C DEC_KEYING_IN_C +#elif !defined( ASM_X86_V2 ) +# define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C ) +#else +# define DFUNCS_IN_C 0 +#endif + +#define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C ) + +/* END OF CONFIGURATION OPTIONS */ + +#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) + +/* Disable or report errors on some combinations of options */ + +#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES +# undef LAST_ENC_ROUND +# define LAST_ENC_ROUND NO_TABLES +#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES +# undef LAST_ENC_ROUND +# define LAST_ENC_ROUND ONE_TABLE +#endif + +#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE +# undef ENC_UNROLL +# define ENC_UNROLL NONE +#endif + +#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES +# undef LAST_DEC_ROUND +# define LAST_DEC_ROUND NO_TABLES +#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES +# undef LAST_DEC_ROUND +# define LAST_DEC_ROUND ONE_TABLE +#endif + +#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE +# undef DEC_UNROLL +# define DEC_UNROLL NONE +#endif + +#if defined( bswap32 ) +# define aes_sw32 bswap32 +#elif defined( bswap_32 ) +# define aes_sw32 bswap_32 +#else +# define brot(x,n) (((uint_32t)(x) << n) | ((uint_32t)(x) >> (32 - n))) +# define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00)) +#endif + +/* upr(x,n): rotates bytes within words by n positions, moving bytes to + higher index positions with wrap around into low positions + ups(x,n): moves bytes by n positions to higher index positions in + words but without wrap around + bval(x,n): extracts a byte from a word + + WARNING: The definitions given here are intended only for use with + unsigned variables and with shift counts that are compile + time constants +*/ + +#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN ) +# define upr(x,n) (((uint_32t)(x) << (8 * (n))) | ((uint_32t)(x) >> (32 - 8 * (n)))) +# define ups(x,n) ((uint_32t) (x) << (8 * (n))) +# define bval(x,n) to_byte((x) >> (8 * (n))) +# define bytes2word(b0, b1, b2, b3) \ + (((uint_32t)(b3) << 24) | ((uint_32t)(b2) << 16) | ((uint_32t)(b1) << 8) | (b0)) +#endif + +#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN ) +# define upr(x,n) (((uint_32t)(x) >> (8 * (n))) | ((uint_32t)(x) << (32 - 8 * (n)))) +# define ups(x,n) ((uint_32t) (x) >> (8 * (n))) +# define bval(x,n) to_byte((x) >> (24 - 8 * (n))) +# define bytes2word(b0, b1, b2, b3) \ + (((uint_32t)(b0) << 24) | ((uint_32t)(b1) << 16) | ((uint_32t)(b2) << 8) | (b3)) +#endif + +#if defined( SAFE_IO ) +# define word_in(x,c) bytes2word(((const uint_8t*)(x)+4*c)[0], ((const uint_8t*)(x)+4*c)[1], \ + ((const uint_8t*)(x)+4*c)[2], ((const uint_8t*)(x)+4*c)[3]) +# define word_out(x,c,v) { ((uint_8t*)(x)+4*c)[0] = bval(v,0); ((uint_8t*)(x)+4*c)[1] = bval(v,1); \ + ((uint_8t*)(x)+4*c)[2] = bval(v,2); ((uint_8t*)(x)+4*c)[3] = bval(v,3); } +#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER ) +# define word_in(x,c) (*((uint_32t*)(x)+(c))) +# define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = (v)) +#else +# define word_in(x,c) aes_sw32(*((uint_32t*)(x)+(c))) +# define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = aes_sw32(v)) +#endif + +/* the finite field modular polynomial and elements */ + +#define WPOLY 0x011b +#define BPOLY 0x1b + +/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ + +#define m1 0x80808080 +#define m2 0x7f7f7f7f +#define gf_mulx(x) ((((x) & m2) << 1) ^ ((((x) & m1) >> 7) * BPOLY)) + +/* The following defines provide alternative definitions of gf_mulx that might + give improved performance if a fast 32-bit multiply is not available. Note + that a temporary variable u needs to be defined where gf_mulx is used. + +#define gf_mulx(x) (u = (x) & m1, u |= (u >> 1), ((x) & m2) << 1) ^ ((u >> 3) | (u >> 6)) +#define m4 (0x01010101 * BPOLY) +#define gf_mulx(x) (u = (x) & m1, ((x) & m2) << 1) ^ ((u - (u >> 7)) & m4) +*/ + +/* Work out which tables are needed for the different options */ + +#if defined( ASM_X86_V1C ) +# if defined( ENC_ROUND ) +# undef ENC_ROUND +# endif +# define ENC_ROUND FOUR_TABLES +# if defined( LAST_ENC_ROUND ) +# undef LAST_ENC_ROUND +# endif +# define LAST_ENC_ROUND FOUR_TABLES +# if defined( DEC_ROUND ) +# undef DEC_ROUND +# endif +# define DEC_ROUND FOUR_TABLES +# if defined( LAST_DEC_ROUND ) +# undef LAST_DEC_ROUND +# endif +# define LAST_DEC_ROUND FOUR_TABLES +# if defined( KEY_SCHED ) +# undef KEY_SCHED +# define KEY_SCHED FOUR_TABLES +# endif +#endif + +#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C ) +# if ENC_ROUND == ONE_TABLE +# define FT1_SET +# elif ENC_ROUND == FOUR_TABLES +# define FT4_SET +# else +# define SBX_SET +# endif +# if LAST_ENC_ROUND == ONE_TABLE +# define FL1_SET +# elif LAST_ENC_ROUND == FOUR_TABLES +# define FL4_SET +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +#endif + +#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C ) +# if DEC_ROUND == ONE_TABLE +# define IT1_SET +# elif DEC_ROUND == FOUR_TABLES +# define IT4_SET +# else +# define ISB_SET +# endif +# if LAST_DEC_ROUND == ONE_TABLE +# define IL1_SET +# elif LAST_DEC_ROUND == FOUR_TABLES +# define IL4_SET +# elif !defined(ISB_SET) +# define ISB_SET +# endif +#endif + +#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) +# if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) +# if KEY_SCHED == ONE_TABLE +# if !defined( FL1_SET ) && !defined( FL4_SET ) +# define LS1_SET +# endif +# elif KEY_SCHED == FOUR_TABLES +# if !defined( FL4_SET ) +# define LS4_SET +# endif +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +# endif +# if (FUNCS_IN_C & DEC_KEYING_IN_C) +# if KEY_SCHED == ONE_TABLE +# define IM1_SET +# elif KEY_SCHED == FOUR_TABLES +# define IM4_SET +# elif !defined( SBX_SET ) +# define SBX_SET +# endif +# endif +#endif + +/* generic definitions of Rijndael macros that use tables */ + +#define no_table(x,box,vf,rf,c) bytes2word( \ + box[bval(vf(x,0,c),rf(0,c))], \ + box[bval(vf(x,1,c),rf(1,c))], \ + box[bval(vf(x,2,c),rf(2,c))], \ + box[bval(vf(x,3,c),rf(3,c))]) + +#define one_table(x,op,tab,vf,rf,c) \ + ( tab[bval(vf(x,0,c),rf(0,c))] \ + ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ + ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ + ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) + +#define four_tables(x,tab,vf,rf,c) \ + ( tab[0][bval(vf(x,0,c),rf(0,c))] \ + ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ + ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ + ^ tab[3][bval(vf(x,3,c),rf(3,c))]) + +#define vf1(x,r,c) (x) +#define rf1(r,c) (r) +#define rf2(r,c) ((8+r-c)&3) + +/* perform forward and inverse column mix operation on four bytes in long word x in */ +/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ + +#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) + +#if defined( FM4_SET ) /* not currently used */ +# define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) +#elif defined( FM1_SET ) /* not currently used */ +# define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0) +#else +# define dec_fmvars uint_32t g2 +# define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) +#endif + +#if defined( IM4_SET ) +# define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0) +#elif defined( IM1_SET ) +# define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0) +#else +# define dec_imvars uint_32t g2, g4, g9 +# define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \ + (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) +#endif + +#if defined( FL4_SET ) +# define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c) +#elif defined( LS4_SET ) +# define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c) +#elif defined( FL1_SET ) +# define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c) +#elif defined( LS1_SET ) +# define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c) +#else +# define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c) +#endif + +#endif + +#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET ) +# define ISB_SET +#endif + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aestab.c pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aestab.c --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aestab.c 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aestab.c 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,383 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 +*/ + +#define DO_TABLES + +#include "aes.h" +#include "aesopt.h" + +#if defined(FIXED_TABLES) + +#define sb_data(w) {\ + w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ + w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ + w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ + w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ + w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ + w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ + w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ + w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ + w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ + w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ + w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ + w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ + w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ + w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ + w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ + w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ + w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ + w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ + w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ + w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ + w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ + w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ + w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ + w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ + w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ + w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ + w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ + w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ + w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ + w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ + w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ + w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } + +#define isb_data(w) {\ + w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ + w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ + w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ + w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ + w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ + w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ + w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ + w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ + w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ + w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ + w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ + w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ + w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ + w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ + w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ + w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ + w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ + w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ + w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ + w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ + w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ + w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ + w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ + w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ + w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ + w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ + w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ + w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ + w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ + w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ + w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ + w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } + +#define mm_data(w) {\ + w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ + w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ + w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ + w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ + w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ + w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ + w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ + w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ + w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ + w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ + w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ + w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ + w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ + w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ + w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ + w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ + w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ + w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ + w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ + w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ + w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ + w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ + w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ + w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ + w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ + w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ + w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ + w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ + w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ + w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ + w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ + w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } + +#define rc_data(w) {\ + w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\ + w(0x1b), w(0x36) } + +#define h0(x) (x) + +#define w0(p) bytes2word(p, 0, 0, 0) +#define w1(p) bytes2word(0, p, 0, 0) +#define w2(p) bytes2word(0, 0, p, 0) +#define w3(p) bytes2word(0, 0, 0, p) + +#define u0(p) bytes2word(f2(p), p, p, f3(p)) +#define u1(p) bytes2word(f3(p), f2(p), p, p) +#define u2(p) bytes2word(p, f3(p), f2(p), p) +#define u3(p) bytes2word(p, p, f3(p), f2(p)) + +#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) +#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) +#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) +#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) + +#endif + +#if defined(FIXED_TABLES) || !defined(FF_TABLES) + +#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) +#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) +#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ + ^ (((x>>5) & 4) * WPOLY)) +#define f3(x) (f2(x) ^ x) +#define f9(x) (f8(x) ^ x) +#define fb(x) (f8(x) ^ f2(x) ^ x) +#define fd(x) (f8(x) ^ f4(x) ^ x) +#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) + +#else + +#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) +#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) +#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) +#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) +#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) +#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) +#define fi(x) ((x) ? pow[ 255 - log[x]] : 0) + +#endif + +#include "aestab.h" + +#if defined(__cplusplus) +extern "C" +{ +#endif + +#if defined(FIXED_TABLES) + +/* implemented in case of wrong call for fixed tables */ + +AES_RETURN aes_init(void) +{ + return EXIT_SUCCESS; +} + +#else /* dynamic table generation */ + +#if !defined(FF_TABLES) + +/* Generate the tables for the dynamic table option + + It will generally be sensible to use tables to compute finite + field multiplies and inverses but where memory is scarse this + code might sometimes be better. But it only has effect during + initialisation so its pretty unimportant in overall terms. +*/ + +/* return 2 ^ (n - 1) where n is the bit number of the highest bit + set in x with x in the range 1 < x < 0x00000200. This form is + used so that locals within fi can be bytes rather than words +*/ + +static uint_8t hibit(const uint_32t x) +{ uint_8t r = (uint_8t)((x >> 1) | (x >> 2)); + + r |= (r >> 2); + r |= (r >> 4); + return (r + 1) >> 1; +} + +/* return the inverse of the finite field element x */ + +static uint_8t fi(const uint_8t x) +{ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; + + if(x < 2) return x; + + for(;;) + { + if(!n1) return v1; + + while(n2 >= n1) + { + n2 /= n1; p2 ^= p1 * n2; v2 ^= v1 * n2; n2 = hibit(p2); + } + + if(!n2) return v2; + + while(n1 >= n2) + { + n1 /= n2; p1 ^= p2 * n1; v1 ^= v2 * n1; n1 = hibit(p1); + } + } +} + +#endif + +/* The forward and inverse affine transformations used in the S-box */ + +#define fwd_affine(x) \ + (w = (uint_32t)x, w ^= (w<<1)^(w<<2)^(w<<3)^(w<<4), 0x63^(uint_8t)(w^(w>>8))) + +#define inv_affine(x) \ + (w = (uint_32t)x, w = (w<<1)^(w<<3)^(w<<6), 0x05^(uint_8t)(w^(w>>8))) + +static int init = 0; + +AES_RETURN aes_init(void) +{ uint_32t i, w; + +#if defined(FF_TABLES) + + uint_8t pow[512], log[256]; + + if(init) + return EXIT_SUCCESS; + /* log and power tables for GF(2^8) finite field with + WPOLY as modular polynomial - the simplest primitive + root is 0x03, used here to generate the tables + */ + + i = 0; w = 1; + do + { + pow[i] = (uint_8t)w; + pow[i + 255] = (uint_8t)w; + log[w] = (uint_8t)i++; + w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); + } + while (w != 1); + +#else + if(init) + return EXIT_SUCCESS; +#endif + + for(i = 0, w = 1; i < RC_LENGTH; ++i) + { + t_set(r,c)[i] = bytes2word(w, 0, 0, 0); + w = f2(w); + } + + for(i = 0; i < 256; ++i) + { uint_8t b; + + b = fwd_affine(fi((uint_8t)i)); + w = bytes2word(f2(b), b, b, f3(b)); + +#if defined( SBX_SET ) + t_set(s,box)[i] = b; +#endif + +#if defined( FT1_SET ) /* tables for a normal encryption round */ + t_set(f,n)[i] = w; +#endif +#if defined( FT4_SET ) + t_set(f,n)[0][i] = w; + t_set(f,n)[1][i] = upr(w,1); + t_set(f,n)[2][i] = upr(w,2); + t_set(f,n)[3][i] = upr(w,3); +#endif + w = bytes2word(b, 0, 0, 0); + +#if defined( FL1_SET ) /* tables for last encryption round (may also */ + t_set(f,l)[i] = w; /* be used in the key schedule) */ +#endif +#if defined( FL4_SET ) + t_set(f,l)[0][i] = w; + t_set(f,l)[1][i] = upr(w,1); + t_set(f,l)[2][i] = upr(w,2); + t_set(f,l)[3][i] = upr(w,3); +#endif + +#if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/ + t_set(l,s)[i] = w; /* not of the required form */ +#endif +#if defined( LS4_SET ) + t_set(l,s)[0][i] = w; + t_set(l,s)[1][i] = upr(w,1); + t_set(l,s)[2][i] = upr(w,2); + t_set(l,s)[3][i] = upr(w,3); +#endif + + b = fi(inv_affine((uint_8t)i)); + w = bytes2word(fe(b), f9(b), fd(b), fb(b)); + +#if defined( IM1_SET ) /* tables for the inverse mix column operation */ + t_set(i,m)[b] = w; +#endif +#if defined( IM4_SET ) + t_set(i,m)[0][b] = w; + t_set(i,m)[1][b] = upr(w,1); + t_set(i,m)[2][b] = upr(w,2); + t_set(i,m)[3][b] = upr(w,3); +#endif + +#if defined( ISB_SET ) + t_set(i,box)[i] = b; +#endif +#if defined( IT1_SET ) /* tables for a normal decryption round */ + t_set(i,n)[i] = w; +#endif +#if defined( IT4_SET ) + t_set(i,n)[0][i] = w; + t_set(i,n)[1][i] = upr(w,1); + t_set(i,n)[2][i] = upr(w,2); + t_set(i,n)[3][i] = upr(w,3); +#endif + w = bytes2word(b, 0, 0, 0); +#if defined( IL1_SET ) /* tables for last decryption round */ + t_set(i,l)[i] = w; +#endif +#if defined( IL4_SET ) + t_set(i,l)[0][i] = w; + t_set(i,l)[1][i] = upr(w,1); + t_set(i,l)[2][i] = upr(w,2); + t_set(i,l)[3][i] = upr(w,3); +#endif + } + init = 1; + return EXIT_SUCCESS; +} + +#endif + +#if defined(__cplusplus) +} +#endif + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aestab.h pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aestab.h --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/aestab.h 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/aestab.h 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,174 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 + + This file contains the code for declaring the tables needed to implement + AES. The file aesopt.h is assumed to be included before this header file. + If there are no global variables, the definitions here can be used to put + the AES tables in a structure so that a pointer can then be added to the + AES context to pass them to the AES routines that need them. If this + facility is used, the calling program has to ensure that this pointer is + managed appropriately. In particular, the value of the t_dec(in,it) item + in the table structure must be set to zero in order to ensure that the + tables are initialised. In practice the three code sequences in aeskey.c + that control the calls to aes_init() and the aes_init() routine itself will + have to be changed for a specific implementation. If global variables are + available it will generally be preferable to use them with the precomputed + FIXED_TABLES option that uses static global tables. + + The following defines can be used to control the way the tables + are defined, initialised and used in embedded environments that + require special features for these purposes + + the 't_dec' construction is used to declare fixed table arrays + the 't_set' construction is used to set fixed table values + the 't_use' construction is used to access fixed table values + + 256 byte tables: + + t_xxx(s,box) => forward S box + t_xxx(i,box) => inverse S box + + 256 32-bit word OR 4 x 256 32-bit word tables: + + t_xxx(f,n) => forward normal round + t_xxx(f,l) => forward last round + t_xxx(i,n) => inverse normal round + t_xxx(i,l) => inverse last round + t_xxx(l,s) => key schedule table + t_xxx(i,m) => key schedule table + + Other variables and tables: + + t_xxx(r,c) => the rcon table +*/ + +#if !defined( _AESTAB_H ) +#define _AESTAB_H + +#define t_dec(m,n) t_##m##n +#define t_set(m,n) t_##m##n +#define t_use(m,n) t_##m##n + +#if defined(FIXED_TABLES) +# if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ )) +/* make tables far data to avoid using too much DGROUP space (PG) */ +# define CONST const far +# else +# define CONST const +# endif +#else +# define CONST +#endif + +#if defined(__cplusplus) +# define EXTERN extern "C" +#elif defined(DO_TABLES) +# define EXTERN +#else +# define EXTERN extern +#endif + +#if defined(_MSC_VER) && defined(TABLE_ALIGN) +#define ALIGN __declspec(align(TABLE_ALIGN)) +#else +#define ALIGN +#endif + +#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) +# define XP_DIR __cdecl +#else +# define XP_DIR +#endif + +#if defined(DO_TABLES) && defined(FIXED_TABLES) +#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) +#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } +EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0); +#else +#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] +#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] +EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH]; +#endif + +#if defined( SBX_SET ) + d_1(uint_8t, t_dec(s,box), sb_data, h0); +#endif +#if defined( ISB_SET ) + d_1(uint_8t, t_dec(i,box), isb_data, h0); +#endif + +#if defined( FT1_SET ) + d_1(uint_32t, t_dec(f,n), sb_data, u0); +#endif +#if defined( FT4_SET ) + d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3); +#endif + +#if defined( FL1_SET ) + d_1(uint_32t, t_dec(f,l), sb_data, w0); +#endif +#if defined( FL4_SET ) + d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3); +#endif + +#if defined( IT1_SET ) + d_1(uint_32t, t_dec(i,n), isb_data, v0); +#endif +#if defined( IT4_SET ) + d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3); +#endif + +#if defined( IL1_SET ) + d_1(uint_32t, t_dec(i,l), isb_data, w0); +#endif +#if defined( IL4_SET ) + d_4(uint_32t, t_dec(i,l), isb_data, w0, w1, w2, w3); +#endif + +#if defined( LS1_SET ) +#if defined( FL1_SET ) +#undef LS1_SET +#else + d_1(uint_32t, t_dec(l,s), sb_data, w0); +#endif +#endif + +#if defined( LS4_SET ) +#if defined( FL4_SET ) +#undef LS4_SET +#else + d_4(uint_32t, t_dec(l,s), sb_data, w0, w1, w2, w3); +#endif +#endif + +#if defined( IM1_SET ) + d_1(uint_32t, t_dec(i,m), mm_data, v0); +#endif +#if defined( IM4_SET ) + d_4(uint_32t, t_dec(i,m), mm_data, v0, v1, v2, v3); +#endif + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/ahuexception.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/ahuexception.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/ahuexception.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/ahuexception.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,40 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 PowerDNS.COM 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 +*/ +#ifndef AHUEXCEPTION_HH +#define AHUEXCEPTION_HH +/* (C) 2002 POWERDNS.COM BV */ + +#include + +#include "namespaces.hh" + +//! Generic Exception thrown +class AhuException +{ +public: + AhuException(){reason="Unspecified";}; + AhuException(string r){reason=r;}; + + string reason; //! Print this to tell the user what went wrong +}; + +class TimeoutException : public AhuException +{}; + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/arguments.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/arguments.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/arguments.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/arguments.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,423 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2008 PowerDNS.COM 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 "arguments.hh" +#include +#include "namespaces.hh" + +const ArgvMap::param_t::const_iterator ArgvMap::begin() +{ + return params.begin(); +} + +const ArgvMap::param_t::const_iterator ArgvMap::end() +{ + return params.end(); +} + +string & ArgvMap::set(const string &var) +{ + return params[var]; +} + +bool ArgvMap::mustDo(const string &var) +{ + return ((*this)[var]!="no") && ((*this)[var]!="off"); +} + +vectorArgvMap::list() +{ + vector ret; + for(map::const_iterator i=params.begin();i!=params.end();++i) + ret.push_back(i->first); + return ret; +} + +string ArgvMap::getHelp(const string &item) +{ + return helpmap[item]; +} + +string & ArgvMap::set(const string &var, const string &help) +{ + helpmap[var]=help; + d_typeMap[var]="Parameter"; + return set(var); +} + +void ArgvMap::setCmd(const string &var, const string &help) +{ + helpmap[var]=help; + d_typeMap[var]="Command"; + set(var)="no"; +} + +string & ArgvMap::setSwitch(const string &var, const string &help) +{ + helpmap[var]=help; + d_typeMap[var]="Switch"; + return set(var); +} + + +bool ArgvMap::contains(const string &var, const string &val) +{ + params_t::const_iterator param = params.find(var); + if(param == params.end() || param->second.empty()) { + return false; + } + vector parts; + vector::const_iterator i; + + stringtok( parts, param->second, ", \t" ); + for( i = parts.begin(); i != parts.end(); i++ ) { + if( *i == val ) { + return true; + } + } + + return false; +} + +string ArgvMap::helpstring(string prefix) +{ + if(prefix=="no") + prefix=""; + + string help; + + for(map::const_iterator i=helpmap.begin(); + i!=helpmap.end(); + i++) + { + if(!prefix.empty() && i->first.find(prefix)) // only print items with prefix + continue; + + help+=" --"; + help+=i->first; + + string type=d_typeMap[i->first]; + + if(type=="Parameter") + help+="=..."; + else if(type=="Switch") + { + help+=" | --"+i->first+"=yes"; + help+=" | --"+i->first+"=no"; + } + + + help+="\n\t"; + help+=i->second; + help+="\n"; + + } + return help; +} + +string ArgvMap::configstring() +{ + string help; + + help="# Autogenerated configuration file template\n"; + for(map::const_iterator i=helpmap.begin(); + i!=helpmap.end(); + i++) + { + if(d_typeMap[i->first]=="Command") + continue; + + help+="#################################\n"; + help+="# "; + help+=i->first; + help+="\t"; + help+=i->second; + help+="\n#\n"; + help+="# "+i->first+"="+params[i->first]+"\n\n"; + + } + return help; +} + + +const string & ArgvMap::operator[](const string &arg) +{ + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + + return params[arg]; +} + +#ifndef WIN32 +mode_t ArgvMap::asMode(const string &arg) +{ + mode_t mode; + const char *cptr_orig; + char *cptr_ret = NULL; + + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + cptr_orig = params[arg].c_str(); + mode = static_cast(strtol(cptr_orig, &cptr_ret, 8)); + if (mode == 0 && cptr_ret == cptr_orig) + throw ArgException("'" + arg + string("' contains invalid octal mode")); + return mode; +} + +gid_t ArgvMap::asGid(const string &arg) +{ + gid_t gid; + const char *cptr_orig; + char *cptr_ret = NULL; + + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + cptr_orig = params[arg].c_str(); + gid = static_cast(strtol(cptr_orig, &cptr_ret, 0)); + if (gid == 0 && cptr_ret == cptr_orig) { + // try to resolve + struct group *group = getgrnam(params[arg].c_str()); + if (group == NULL) + throw ArgException("'" + arg + string("' contains invalid group")); + gid = group->gr_gid; + } + return gid; +} + +uid_t ArgvMap::asUid(const string &arg) +{ + uid_t uid; + const char *cptr_orig; + char *cptr_ret = NULL; + + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + cptr_orig = params[arg].c_str(); + uid = static_cast(strtol(cptr_orig, &cptr_ret, 0)); + if (uid == 0 && cptr_ret == cptr_orig) { + // try to resolve + struct passwd *pwent = getpwnam(params[arg].c_str()); + if (pwent == NULL) + throw ArgException("'" + arg + string("' contains invalid group")); + uid = pwent->pw_uid; + } + return uid; +} +#endif + +int ArgvMap::asNum(const string &arg) +{ + int retval; + const char *cptr_orig; + char *cptr_ret = NULL; + + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + // treat empty values as zeros + if (params[arg].empty()) + return 0; + + cptr_orig = params[arg].c_str(); + retval = static_cast(strtol(cptr_orig, &cptr_ret, 0)); + if (!retval && cptr_ret == cptr_orig) + throw ArgException("'"+arg+string("' is not valid number")); + + return retval; +} + +bool ArgvMap::isEmpty(const string &arg) +{ + if(!parmIsset(arg)) + return true; + return params[arg].empty(); +} + +double ArgvMap::asDouble(const string &arg) +{ + double retval; + const char *cptr_orig; + char *cptr_ret = NULL; + + if(!parmIsset(arg)) + throw ArgException(string("Undefined but needed argument: '")+arg+"'"); + + if (params[arg].empty()) + return 0.0; + + cptr_orig = params[arg].c_str(); + retval = strtod(cptr_orig, &cptr_ret); + + if (retval == 0 && cptr_ret == cptr_orig) + throw ArgException("'"+arg+string("' is not valid double")); + + return retval; +} + +ArgvMap::ArgvMap() +{ + +} + +bool ArgvMap::parmIsset(const string &var) +{ + return (params.find(var)!=params.end()); +} + +void ArgvMap::parseOne(const string &arg, const string &parseOnly, bool lax) +{ + string var, val; + string::size_type pos; + + if(!arg.find("--") &&(pos=arg.find("="))!=string::npos) // this is a --port=25 case + { + var=arg.substr(2,pos-2); + val=arg.substr(pos+1); + } + else if(!arg.find("--") && (arg.find("=")==string::npos)) // this is a --daemon case + { + var=arg.substr(2); + val=""; + } + else if(arg[0]=='-') + { + var=arg.substr(1); + val=""; + } + else { // command + d_cmds.push_back(arg); + } + + if(var!="" && (parseOnly.empty() || var==parseOnly)) { + + pos=val.find_first_not_of(" \t"); // strip leading whitespace + if(pos && pos!=string::npos) + val=val.substr(pos); + + if(parmIsset(var)) + params[var]=val; + else + if(!lax) + throw ArgException("Trying to set unexisting parameter '"+var+"'"); + } +} + +const vector&ArgvMap::getCommands() +{ + return d_cmds; +} + +void ArgvMap::parse(int &argc, char **argv, bool lax) +{ + for(int n=1;n +#include +#include +#include +#include +#include "misc.hh" +#include "ahuexception.hh" +#ifndef WIN32 +# include +# include +# include +#endif + +#include "namespaces.hh" + +typedef AhuException ArgException; + +/** This class helps parsing argc and argv into a map of parameters. We have 3 kinds of formats: + + + -w this leads to a key/value pair of "w"/void + + --port=25 "port"/"25" + + --daemon "daemon"/void + + We do not support "--port 25" syntax. + + It can also read from a file. This file can contain '#' to delimit comments. + + Some sample code: + + \code + + ArgvMap R; + + R.set("port")="25"; // use this to specify default parameters + R.file("./default.conf"); // parse configuration file + + R.parse(argc, argv); // read the arguments from main() + + cout<<"Will we be a deamon?: "<::const_iterator i; + cout<<"via iterator"<first<<"="<second< param_t; //!< use this if you need to know the content of the map + bool parmIsset(const string &var); //!< Checks if a parameter is set to *a* value + bool mustDo(const string &var); //!< if a switch is given, if we must do something (--help) + int asNum(const string &var); //!< return a variable value as a number +#ifndef WIN32 + mode_t asMode(const string &var); //list(); + string getHelp(const string &item); + + const param_t::const_iterator begin(); //!< iterator semantics + const param_t::const_iterator end(); //!< iterator semantics + const string &operator[](const string &); //!< iterator semantics + const vector&getCommands(); +private: + void parseOne(const string &unparsed, const string &parseOnly="", bool lax=false); + typedef map params_t; + params_t params; + map helpmap; + map d_typeMap; + vector d_cmds; +}; + +extern ArgvMap &arg(); + +#endif /* ARGUMENTS_HH */ diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/base32.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/base32.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/base32.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/base32.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,136 @@ +#include +#include +#include +#include +#include +#include +#include "base32.hh" +#include "namespaces.hh" + +/* based on freebsd:src/contrib/opie/libopie/btoe.c extract: get bit ranges from a char* */ +uint32_t extract_bits(const char *s, int start, int length) +{ + uint32_t x; + unsigned char cl, cc, cr; + + cl = s[start / 8]; + cc = s[start / 8 + 1]; + cr = s[start / 8 + 2]; + x = ((uint32_t) (cl << 8 | cc) << 8 | cr); + x = x >> (24 - (length + (start % 8))); + x = (x & (0xffff >> (16 - length))); + return (x); +} + +/* same, set bit ranges in a char* */ +static void set_bits(char* s, int x, int start, int length) +{ + unsigned char cl, cc, cr; + uint32_t y; + int shift; + + shift = ((8 - ((start + length) % 8)) % 8); + y = (uint32_t) x << shift; + cl = (y >> 16) & 0xff; + cc = (y >> 8) & 0xff; + cr = y & 0xff; + if (shift + length > 16) { + s[start / 8] |= cl; + s[start / 8 + 1] |= cc; + s[start / 8 + 2] |= cr; + } + else { + if (shift + length > 8) { + s[start / 8] |= cc; + s[start / 8 + 1] |= cr; + } else { + s[start / 8] |= cr; + } + } +} + +/* convert a base32 hex character to its decoded equivalent */ +static int unbase32hex(char c) +{ + if(c >= '0' && c<='9') + return c-'0'; + if(c >= 'a' && c<='z') + return 10 + (c-'a'); + if(c >= 'A' && c<='Z') + return 10 + (c-'A'); + if(c=='=') + return '='; + return -1; +} + +/* convert a binary string to base32hex */ +string toBase32Hex(const std::string& input) +{ + static const char base32hex[] = "0123456789ABCDEFGHIJKLMNOPQRSTUV="; + string ret; + ret.reserve(4+ 8*input.length()/5); // optimization + // process input in groups of 5 8-bit chunks, emit 8 5-bit chunks + for(string::size_type offset = 0 ; offset < input.length(); offset+=5) { + int todo = input.length() - offset; + int stuffing; // how much '=' to add at the end + + switch(todo) { + case 1: + stuffing = 6; break; + case 2: + stuffing = 4; break; + case 3: + stuffing = 3; break; + case 4: + stuffing = 1; break; + default: // -> 0 or more than 5, no stuffing + stuffing = 0; break; + } + + for(int n=0; n < 8 - stuffing; ++n) + ret.append(1, base32hex[extract_bits(input.c_str()+offset, n*5, 5)]); + ret.append(stuffing, '='); + } + + return ret; +} + +// convert base32hex encoded string to normal string +string fromBase32Hex(const std::string& input) +{ + string ret; + char block[5]={0,0,0,0,0}; // we process 5 8-bit chunks at a time + string::size_type n, toWrite=0; + for(n = 0; n < input.length(); ++n) { + int c=unbase32hex(input[n]); + if(c == '=' || c < 0) // stop at stuffing or error + break; + set_bits(block, c , (n % 8) * 5, 5); + if(++toWrite == 8) { + ret.append(block, sizeof(block)); + memset(block, 0, sizeof(block)); + toWrite = 0; + } + } + ret.append(block, (toWrite*5)/8); + + return ret; +} + +#if 0 +int main(int argc, char **argv) +{ + if(argc!=3 || (argc==3 && strcmp(argv[1],"from") && strcmp(argv[1],"to"))) { + printf("syntax: base32 from|to string\n"); + exit(0); + } + if(!strcmp(argv[1],"to")) { + printf("input: '%s'\noutput: '%s'\n", + argv[2], + toBase32Hex(argv[2]).c_str()); + } + else { + cout<<"input: '"< + +std::string toBase32Hex(const std::string& input); +std::string fromBase32Hex(const std::string& input); + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/base64.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/base64.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/base64.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/base64.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,232 @@ +#include "base64.hh" +#include + +namespace anonpdns { +char B64Decode1(char cInChar) +{ + // The incoming character will be A-Z, a-z, 0-9, +, /, or =. + // The idea is to quickly determine which grouping the + // letter belongs to and return the associated value + // without having to search the global encoding string + // (the value we're looking for would be the resulting + // index into that string). + // + // To do that, we'll play some tricks... + unsigned char iIndex = '\0'; + switch ( cInChar ) { + case '+': + iIndex = 62; + break; + + case '/': + iIndex = 63; + break; + + case '=': + iIndex = 0; + break; + + default: + // Must be 'A'-'Z', 'a'-'z', '0'-'9', or an error... + // + // Numerically, small letters are "greater" in value than + // capital letters and numerals (ASCII value), and capital + // letters are "greater" than numerals (again, ASCII value), + // so we check for numerals first, then capital letters, + // and finally small letters. + iIndex = '9' - cInChar; + if ( iIndex > 0x3F ) { + // Not from '0' to '9'... + iIndex = 'Z' - cInChar; + if ( iIndex > 0x3F ) { + // Not from 'A' to 'Z'... + iIndex = 'z' - cInChar; + if ( iIndex > 0x3F ) { + // Invalid character...cannot + // decode! + iIndex = 0x80; // set the high bit + } // if + else { + // From 'a' to 'z' + iIndex = (('z' - iIndex) - 'a') + 26; + } // else + } // if + else { + // From 'A' to 'Z' + iIndex = ('Z' - iIndex) - 'A'; + } // else + } // if + else { + // Adjust the index... + iIndex = (('9' - iIndex) - '0') + 52; + } // else + break; + + } // switch + + return iIndex; +} + +inline char B64Encode1(unsigned char uc) +{ + if (uc < 26) + { + return 'A'+uc; + } + if (uc < 52) + { + return 'a'+(uc-26); + } + if (uc < 62) + { + return '0'+(uc-52); + } + if (uc == 62) + { + return '+'; + } + return '/'; +}; + + + +} +using namespace anonpdns; + +int B64Decode(const std::string& strInput, std::string& strOutput) +{ + // Set up a decoding buffer + long cBuf = 0; + char* pBuf = (char*)&cBuf; + + // Decoding management... + int iBitGroup = 0, iInNum = 0; + + // While there are characters to process... + // + // We'll decode characters in blocks of 4, as + // there are 4 groups of 6 bits in 3 bytes. The + // incoming Base64 character is first decoded, and + // then it is inserted into the decode buffer + // (with any relevant shifting, as required). + // Later, after all 3 bytes have been reconstituted, + // we assign them to the output string, ultimately + // to be returned as the original message. + int iInSize = strInput.size(); + unsigned char cChar = '\0'; + uint8_t pad = 0; + while ( iInNum < iInSize ) { + // Fill the decode buffer with 4 groups of 6 bits + cBuf = 0; // clear + pad = 0; + for ( iBitGroup = 0; iBitGroup < 4; ++iBitGroup ) { + if ( iInNum < iInSize ) { + // Decode a character + if(strInput.at(iInNum)=='=') + pad++; + while(isspace(strInput.at(iInNum))) + iInNum++; + cChar = B64Decode1(strInput.at(iInNum++)); + + } // if + else { + // Decode a padded zero + cChar = '\0'; + } // else + + // Check for valid decode + if ( cChar > 0x7F ) + return -1; + + // Adjust the bits + switch ( iBitGroup ) { + case 0: + // The first group is copied into + // the least significant 6 bits of + // the decode buffer...these 6 bits + // will eventually shift over to be + // the most significant bits of the + // third byte. + cBuf = cBuf | cChar; + break; + + default: + // For groupings 1-3, simply shift + // the bits in the decode buffer over + // by 6 and insert the 6 from the + // current decode character. + cBuf = (cBuf << 6) | cChar; + break; + + } // switch + } // for + + // Interpret the resulting 3 bytes...note there + // may have been padding, so those padded bytes + // are actually ignored. + strOutput += pBuf[2]; + strOutput += pBuf[1]; + strOutput += pBuf[0]; + } // while + if(pad) + strOutput.resize(strOutput.length()-pad); + + return 1; +} + +/* +www.kbcafe.com +Copyright 2001-2002 Randy Charles Morin +The Encode static method takes an array of 8-bit values and returns a base-64 stream. +*/ + + +std::string Base64Encode (const std::string& vby) +{ + std::string retval; + if (vby.size () == 0) + { + return retval; + }; + for (unsigned int i = 0; i < vby.size (); i += 3) + { + unsigned char by1 = 0, by2 = 0, by3 = 0; + by1 = vby[i]; + if (i + 1 < vby.size ()) + { + by2 = vby[i + 1]; + }; + if (i + 2 < vby.size ()) + { + by3 = vby[i + 2]; + } + unsigned char by4 = 0, by5 = 0, by6 = 0, by7 = 0; + by4 = by1 >> 2; + by5 = ((by1 & 0x3) << 4) | (by2 >> 4); + by6 = ((by2 & 0xf) << 2) | (by3 >> 6); + by7 = by3 & 0x3f; + retval += B64Encode1 (by4); + retval += B64Encode1 (by5); + if (i + 1 < vby.size ()) + { + retval += B64Encode1 (by6); + } + else + { + retval += "="; + }; + if (i + 2 < vby.size ()) + { + retval += B64Encode1 (by7); + } + else + { + retval += "="; + }; + /* if ((i % (76 / 4 * 3)) == 0) + { + retval += "\r\n"; + }*/ + }; + return retval; +}; diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/base64.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/base64.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/base64.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/base64.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,8 @@ +#ifndef PDNS_BASE64_HH +#define PDNS_BASE64_HH +#include +#include + +int B64Decode(const std::string& strInput, std::string& strOutput); +std::string Base64Encode (const std::string& vby); +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/brg_endian.h pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/brg_endian.h --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/brg_endian.h 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/brg_endian.h 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,133 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 +*/ + +#ifndef _BRG_ENDIAN_H +#define _BRG_ENDIAN_H + +#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ +#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ + +/* Include files where endian defines and byteswap functions may reside */ +#if defined( __sun ) +# include +#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) +# include +#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ + defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) +# include +#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) +# if !defined( __MINGW32__ ) && !defined( _AIX ) +# include +# if !defined( __BEOS__ ) +# include +# endif +# endif +#endif + +/* Now attempt to set the define for platform byte order using any */ +/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ +/* seem to encompass most endian symbol definitions */ + +#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) +# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) +# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( _BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( _LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) +# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) +# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +# endif +#elif defined( __BIG_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#elif defined( __LITTLE_ENDIAN__ ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#endif + +/* if the platform byte order could not be determined, then try to */ +/* set this define using common machine defines */ +#if !defined(PLATFORM_BYTE_ORDER) + +#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ + defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ + defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ + defined( vax ) || defined( vms ) || defined( VMS ) || \ + defined( __VMS ) || defined( _M_X64 ) +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN + +#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ + defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ + defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ + defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ + defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ + defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ + defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN + +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN +#elif 0 /* **** EDIT HERE IF NECESSARY **** */ +# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN +#else +# error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order +#endif + +#endif + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/brg_types.h pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/brg_types.h --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/brg_types.h 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/brg_types.h 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,223 @@ +/* + --------------------------------------------------------------------------- + Copyright (c) 1998-2007, Brian Gladman, Worcester, UK. All rights reserved. + + LICENSE TERMS + + The free distribution and use of this software is allowed (with or without + changes) provided that: + + 1. source code distributions include the above copyright notice, this + list of conditions and the following disclaimer; + + 2. binary distributions include the above copyright notice, this list + of conditions and the following disclaimer in their documentation; + + 3. the name of the copyright holder is not used to endorse products + built using this software without specific written permission. + + DISCLAIMER + + This software is provided 'as is' with no explicit or implied warranties + in respect of its properties, including, but not limited to, correctness + and/or fitness for purpose. + --------------------------------------------------------------------------- + Issue Date: 20/12/2007 + + The unsigned integer types defined here are of the form uint_t where + is the length of the type; for example, the unsigned 32-bit type is + 'uint_32t'. These are NOT the same as the 'C99 integer types' that are + defined in the inttypes.h and stdint.h headers since attempts to use these + types have shown that support for them is still highly variable. However, + since the latter are of the form uint_t, a regular expression search + and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') + can be used to convert the types used here to the C99 standard types. +*/ + +#ifndef _BRG_TYPES_H +#define _BRG_TYPES_H + +#if defined(__cplusplus) +extern "C" { +#endif + +#include + +#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) +# include +# define ptrint_t intptr_t +#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 ) +# include +# define ptrint_t intptr_t +#else +# define ptrint_t int +#endif + +#ifndef BRG_UI8 +# define BRG_UI8 +# if UCHAR_MAX == 255u + typedef unsigned char uint_8t; +# else +# error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h +# endif +#endif + +#ifndef BRG_UI16 +# define BRG_UI16 +# if USHRT_MAX == 65535u + typedef unsigned short uint_16t; +# else +# error Please define uint_16t as a 16-bit unsigned short type in brg_types.h +# endif +#endif + +#ifndef BRG_UI32 +# define BRG_UI32 +# if UINT_MAX == 4294967295u +# define li_32(h) 0x##h##u + typedef unsigned int uint_32t; +# elif ULONG_MAX == 4294967295u +# define li_32(h) 0x##h##ul + typedef unsigned long uint_32t; +# elif defined( _CRAY ) +# error This code needs 32-bit data types, which Cray machines do not provide +# else +# error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h +# endif +#endif + +#ifndef BRG_UI64 +# if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) +# define BRG_UI64 +# define li_64(h) 0x##h##ui64 + typedef unsigned __int64 uint_64t; +# elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ +# define BRG_UI64 +# define li_64(h) 0x##h##ui64 + typedef unsigned __int64 uint_64t; +# elif defined( __sun ) && defined(ULONG_MAX) && ULONG_MAX == 0xfffffffful +# define BRG_UI64 +# define li_64(h) 0x##h##ull + typedef unsigned long long uint_64t; +# elif defined( __MVS__ ) +# define BRG_UI64 +# define li_64(h) 0x##h##ull + typedef unsigned int long long uint_64t; +# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u +# if UINT_MAX == 18446744073709551615u +# define BRG_UI64 +# define li_64(h) 0x##h##u + typedef unsigned int uint_64t; +# endif +# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u +# if ULONG_MAX == 18446744073709551615ul +# define BRG_UI64 +# define li_64(h) 0x##h##ul + typedef unsigned long uint_64t; +# endif +# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u +# if ULLONG_MAX == 18446744073709551615ull +# define BRG_UI64 +# define li_64(h) 0x##h##ull + typedef unsigned long long uint_64t; +# endif +# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u +# if ULONG_LONG_MAX == 18446744073709551615ull +# define BRG_UI64 +# define li_64(h) 0x##h##ull + typedef unsigned long long uint_64t; +# endif +# endif +#endif + +#if !defined( BRG_UI64 ) +# if defined( NEED_UINT_64T ) +# error Please define uint_64t as an unsigned 64 bit type in brg_types.h +# endif +#endif + +#ifndef RETURN_VALUES +# define RETURN_VALUES +# if defined( DLL_EXPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllexport ) void __stdcall +# define INT_RETURN __declspec( dllexport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllexport__ ) void +# define INT_RETURN __declspec( __dllexport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( DLL_IMPORT ) +# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) +# define VOID_RETURN __declspec( dllimport ) void __stdcall +# define INT_RETURN __declspec( dllimport ) int __stdcall +# elif defined( __GNUC__ ) +# define VOID_RETURN __declspec( __dllimport__ ) void +# define INT_RETURN __declspec( __dllimport__ ) int +# else +# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers +# endif +# elif defined( __WATCOMC__ ) +# define VOID_RETURN void __cdecl +# define INT_RETURN int __cdecl +# else +# define VOID_RETURN void +# define INT_RETURN int +# endif +#endif + +/* These defines are used to detect and set the memory alignment of pointers. + Note that offsets are in bytes. + + ALIGN_OFFSET(x,n) return the positive or zero offset of + the memory addressed by the pointer 'x' + from an address that is aligned on an + 'n' byte boundary ('n' is a power of 2) + + ALIGN_FLOOR(x,n) return a pointer that points to memory + that is aligned on an 'n' byte boundary + and is not higher than the memory address + pointed to by 'x' ('n' is a power of 2) + + ALIGN_CEIL(x,n) return a pointer that points to memory + that is aligned on an 'n' byte boundary + and is not lower than the memory address + pointed to by 'x' ('n' is a power of 2) +*/ + +#define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1)) +#define ALIGN_FLOOR(x,n) ((uint_8t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1))) +#define ALIGN_CEIL(x,n) ((uint_8t*)(x) + (-((ptrint_t)(x)) & ((n) - 1))) + +/* These defines are used to declare buffers in a way that allows + faster operations on longer variables to be used. In all these + defines 'size' must be a power of 2 and >= 8. NOTE that the + buffer size is in bytes but the type length is in bits + + UNIT_TYPEDEF(x,size) declares a variable 'x' of length + 'size' bits + + BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize' + bytes defined as an array of variables + each of 'size' bits (bsize must be a + multiple of size / 8) + + UNIT_CAST(x,size) casts a variable to a type of + length 'size' bits + + UPTR_CAST(x,size) casts a pointer to a pointer to a + varaiable of length 'size' bits +*/ + +#define UI_TYPE(size) uint_##size##t +#define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x +#define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)] +#define UNIT_CAST(x,size) ((UI_TYPE(size) )(x)) +#define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x)) + +#if defined(__cplusplus) +} +#endif + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/cachecleaner.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/cachecleaner.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/cachecleaner.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/cachecleaner.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,83 @@ +#ifndef PDNS_CACHECLEANER_HH +#define PDNS_CACHECLEANER_HH + +// this function can clean any cache that has a getTTD() method on its entries, and a 'sequence' index as its second index +// the ritual is that the oldest entries are in *front* of the sequence collection, so on a hit, move an item to the end +// on a miss, move it to the beginning +template void pruneCollection(T& collection, unsigned int maxCached, unsigned int scanFraction=1000) +{ + uint32_t now=(uint32_t)time(0); + unsigned int toTrim=0; + + unsigned int cacheSize=collection.size(); + + if(cacheSize > maxCached) { + toTrim = cacheSize - maxCached; + } + +// cout<<"Need to trim "<::type sequence_t; + sequence_t& sidx=collection.get<1>(); + + unsigned int tried=0, lookAt, erased=0; + + // two modes - if toTrim is 0, just look through 1/scanFraction of all records + // and nuke everything that is expired + // otherwise, scan first 5*toTrim records, and stop once we've nuked enough + if(toTrim) + lookAt=5*toTrim; + else + lookAt=cacheSize/scanFraction; + + typename sequence_t::iterator iter=sidx.begin(), eiter; + for(; iter != sidx.end() && tried < lookAt ; ++tried) { + if(iter->getTTD() < now) { + sidx.erase(iter++); + erased++; + } + else + ++iter; + + if(toTrim && erased > toTrim) + break; + } + + //cout<<"erased "<= toTrim) // done + return; + + toTrim -= erased; + + //if(toTrim) + // cout<<"Still have "< void moveCacheItemToFrontOrBack(T& collection, typename T::iterator& iter, bool front) +{ + typedef typename T::template nth_index<1>::type sequence_t; + sequence_t& sidx=collection.get<1>(); + typename sequence_t::iterator si=collection.project<1>(iter); + if(front) + sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue + else + sidx.relocate(sidx.end(), si); // back +} + +template void moveCacheItemToFront(T& collection, typename T::iterator& iter) +{ + moveCacheItemToFrontOrBack(collection, iter, true); +} + +template void moveCacheItemToBack(T& collection, typename T::iterator& iter) +{ + moveCacheItemToFrontOrBack(collection, iter, false); +} + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/config.h pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/config.h --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/config.h 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/config.h 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,4 @@ +#define SYSCONFDIR "/etc/powerdns/" +#define LOCALSTATEDIR "/var/run/" +#define VERSION "3.5-pre" +#define RECURSOR diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/configure pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/configure --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/configure 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/configure 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,12 @@ +#!/bin/sh +echo Testing dependencies and compiler. + +GMAKE=`which gmake` +if test -z "$GMAKE" +then + make basic_checks +else + echo Using gmake to build + gmake basic_checks +fi + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/COPYING pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/COPYING --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/COPYING 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/COPYING 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/devpollmplexer.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/devpollmplexer.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/devpollmplexer.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/devpollmplexer.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,156 @@ +#include +#include "mplexer.hh" +#include "sstuff.hh" +#include +#include +#include "misc.hh" +#include +#include "syncres.hh" + +#include "namespaces.hh" +#include "namespaces.hh" + +class DevPollFDMultiplexer : public FDMultiplexer +{ +public: + DevPollFDMultiplexer(); + virtual ~DevPollFDMultiplexer() + { + close(d_devpollfd); + } + + virtual int run(struct timeval* tv); + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter); + virtual void removeFD(callbackmap_t& cbmap, int fd); + string getName() + { + return "/dev/poll"; + } +private: + int d_devpollfd; +}; + + +static FDMultiplexer* makeDevPoll() +{ + return new DevPollFDMultiplexer(); +} + +static struct DevPollRegisterOurselves +{ + DevPollRegisterOurselves() { + FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makeDevPoll)); // priority 0! + } +} doItDevPoll; + + +//int DevPollFDMultiplexer::s_maxevents=1024; +DevPollFDMultiplexer::DevPollFDMultiplexer() +{ + d_devpollfd=open("/dev/poll", O_RDWR); + if(d_devpollfd < 0) + throw FDMultiplexerException("Setting up /dev/poll: "+stringerror()); + +} + +void DevPollFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter) +{ + accountingAddFD(cbmap, fd, toDo, parameter); + + struct pollfd devent; + devent.fd=fd; + devent.events= (&cbmap == &d_readCallbacks) ? POLLIN : POLLOUT; + devent.revents = 0; + + if(write(d_devpollfd, &devent, sizeof(devent)) != sizeof(devent)) { + cbmap.erase(fd); + throw FDMultiplexerException("Adding fd to /dev/poll/ set: "+stringerror()); + } +} + +void DevPollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) +{ + if(!cbmap.erase(fd)) + throw FDMultiplexerException("Tried to remove unlisted fd "+lexical_cast(fd)+ " from multiplexer"); + + struct pollfd devent; + devent.fd=fd; + devent.events= POLLREMOVE; + devent.revents = 0; + + if(write(d_devpollfd, &devent, sizeof(devent)) != sizeof(devent)) { + cbmap.erase(fd); + throw FDMultiplexerException("Removing fd from epoll set: "+stringerror()); + } +} + +int DevPollFDMultiplexer::run(struct timeval* now) +{ + if(d_inrun) { + throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); + } + struct dvpoll dvp; + dvp.dp_nfds = d_readCallbacks.size() + d_writeCallbacks.size(); + dvp.dp_fds = new pollfd[dvp.dp_nfds]; + dvp.dp_timeout = 500; + int ret=ioctl(d_devpollfd, DP_POLL, &dvp); + gettimeofday(now,0); // MANDATORY! + + if(ret < 0 && errno!=EINTR) + throw FDMultiplexerException("/dev/poll returned error: "+stringerror()); + + if(ret < 1) // thanks AB! + return 0; + + d_inrun=true; + for(int n=0; n < ret; ++n) { + d_iter=d_readCallbacks.find(dvp.dp_fds[n].fd); + + if(d_iter != d_readCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + continue; // so we don't refind ourselves as writable! + } + d_iter=d_writeCallbacks.find(dvp.dp_fds[n].fd); + + if(d_iter != d_writeCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + } + } + delete[] dvp.dp_fds; + d_inrun=false; + return 0; +} + +#if 0 +void acceptData(int fd, funcparam_t& parameter) +{ + cout<<"Have data on fd "<(parameter); + string packet; + IPEndpoint rem; + sock->recvFrom(packet, rem); + cout<<"Received "< +#include +#include +#include + +static void appendEscapedLabel(string& ret, const char* begin, unsigned char labellen) +{ + unsigned char n = 0; + for(n = 0 ; n < labellen; ++n) + if(begin[n] == '.' || begin[n] == '\\' || begin[n] == ' ') + break; + + if( n == labellen) { + ret.append(begin, labellen); + return; + } + string label(begin, labellen); + boost::replace_all(label, "\\", "\\\\"); + boost::replace_all(label, ".", "\\."); + boost::replace_all(label, " ", "\\032"); + ret.append(label); +} + +class BoundsCheckingPointer +{ +public: + explicit BoundsCheckingPointer(const char* a, unsigned int length) + : d_ptr(a), d_length(length) + {} + + explicit BoundsCheckingPointer(const std::string& str) + : d_ptr(str.c_str()), d_length(str.size()) + {} + + + const char operator[](unsigned int offset) const + { + if(offset < d_length) + return d_ptr[offset]; + else throw runtime_error("out of bounds: "+boost::lexical_cast(offset)+" >= " + boost::lexical_cast(d_length)); + } +private: + const char* d_ptr; + const unsigned int d_length; +}; + +//! compares two dns packets, skipping the header, but including the question and the qtype +bool dnspacketLessThan(const std::string& a, const std::string& b) +{ + if(a.length() <= 12 || b.length() <= 12) + return a.length() < b.length(); +// throw runtime_error("Error parsing question in dnspacket comparison: packet too short"); + + // we find: 3www4ds9a2nl0XXYY, where XX and YY are each 2 bytes describing class and type + + BoundsCheckingPointer aSafe(a), bSafe(b); + int aPos=12, bPos=12; + + unsigned char aLabelLen, bLabelLen; + + do { + aLabelLen = aSafe[aPos++]; bLabelLen = bSafe[bPos++]; + // cerr<<"aLabelLen: "<<(int)aLabelLen<<", bLabelLen: "<< (int)bLabelLen< end) + throw runtime_error("Error parsing question in incoming packet: label extends beyond packet"); + + appendEscapedLabel(ret, (const char*) pos, labellen); + + ret.append(1, '.'); + pos += labellen; + } + + if(pos + labellen + 2 <= end) + type=(*pos)*256 + *(pos+1); + // cerr << "returning: '"<parts; + stringtok(parts,content); + int pleft=parts.size(); + + // cout<<"'"<1) + data.hostmaster=attodot(parts[1]); // ahu@ds9a.nl -> ahu.ds9a.nl, piet.puk@ds9a.nl -> piet\.puk.ds9a.nl + + if(pleft>2) + data.serial=strtoul(parts[2].c_str(), NULL, 10); + + if(pleft>3) + data.refresh=atoi(parts[3].c_str()); + + if(pleft>4) + data.retry=atoi(parts[4].c_str()); + + if(pleft>5) + data.expire=atoi(parts[5].c_str()); + + if(pleft>6) + data.default_ttl=atoi(parts[6].c_str()); + +} + +string serializeSOAData(const SOAData &d) +{ + ostringstream o; + // nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ] + o<((int)rcode); +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dns.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dns.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dns.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dns.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,287 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2011 PowerDNS.COM 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 +*/ +// $Id: dns.hh 2589 2012-04-29 13:02:29Z peter $ +/* (C) 2002 POWERDNS.COM BV */ +#ifndef DNS_HH +#define DNS_HH +#include +#include +#include +#include +#include +#include +#include + + +#include "utility.hh" +#include "qtype.hh" +#include +#include +class DNSBackend; + +struct SOAData +{ + string qname; + string nameserver; + string hostmaster; + uint32_t ttl; + uint32_t serial; + uint32_t refresh; + uint32_t retry; + uint32_t expire; + uint32_t default_ttl; + int domain_id; + DNSBackend *db; + uint8_t scopeMask; +}; + + +class RCode +{ +public: + enum rcodes_ { NoError=0, FormErr=1, ServFail=2, NXDomain=3, NotImp=4, Refused=5, NotAuth=9 }; +}; + +class Opcode +{ +public: + enum { Query=0, IQuery=1, Status=2, Notify=4, Update=5 }; +}; + +//! This class represents a resource record +class DNSResourceRecord +{ +public: + DNSResourceRecord() : qclass(1), priority(0), last_modified(0), d_place(ANSWER), auth(1), scopeMask(0) {}; + ~DNSResourceRecord(){}; + + // data + + QType qtype; //!< qtype of this record, ie A, CNAME, MX etc + uint16_t qclass; //!< class of this record + string qname; //!< the name of this record, for example: www.powerdns.com + string wildcardname; + string content; //!< what this record points to. Example: 10.1.2.3 + uint16_t priority; //!< For qtypes that support a priority or preference (MX, SRV) + uint32_t ttl; //!< Time To Live of this record + int domain_id; //!< If a backend implements this, the domain_id of the zone this record is in + time_t last_modified; //!< For autocalculating SOA serial numbers - the backend needs to fill this in + enum Place {QUESTION=0, ANSWER=1, AUTHORITY=2, ADDITIONAL=3}; //!< Type describing the positioning of a DNSResourceRecord within, say, a DNSPacket + Place d_place; //!< This specifies where a record goes within the packet + + bool auth; + uint8_t scopeMask; + + template + void serialize(Archive & ar, const unsigned int version) + { + ar & qtype; + ar & qclass; + ar & qname; + ar & wildcardname; + ar & content; + ar & priority; + ar & ttl; + ar & domain_id; + ar & last_modified; + ar & d_place; + ar & auth; + } + + bool operator<(const DNSResourceRecord &b) const + { + if(qname < b.qname) + return true; + if(qname == b.qname) + return(content < b.content); + return false; + } +}; + +#ifdef _MSC_VER +# pragma pack ( push ) +# pragma pack ( 1 ) +# define GCCPACKATTRIBUTE +#else +# define GCCPACKATTRIBUTE __attribute__((packed)) +#endif +struct dnsrecordheader +{ + uint16_t d_type; + uint16_t d_class; + uint32_t d_ttl; + uint16_t d_clen; +} GCCPACKATTRIBUTE; + +struct EDNS0Record +{ + uint8_t extRCode, version; + uint16_t Z; +} GCCPACKATTRIBUTE; +#ifdef _MSC_VER +#pragma pack (pop) +#endif + +enum { + ns_t_invalid = 0, /* Cookie. */ + ns_t_a = 1, /* Host address. */ + ns_t_ns = 2, /* Authoritative server. */ + ns_t_md = 3, /* Mail destination. */ + ns_t_mf = 4, /* Mail forwarder. */ + ns_t_cname = 5, /* Canonical name. */ + ns_t_soa = 6, /* Start of authority zone. */ + ns_t_mb = 7, /* Mailbox domain name. */ + ns_t_mg = 8, /* Mail group member. */ + ns_t_mr = 9, /* Mail rename name. */ + ns_t_null = 10, /* Null resource record. */ + ns_t_wks = 11, /* Well known service. */ + ns_t_ptr = 12, /* Domain name pointer. */ + ns_t_hinfo = 13, /* Host information. */ + ns_t_minfo = 14, /* Mailbox information. */ + ns_t_mx = 15, /* Mail routing information. */ + ns_t_txt = 16, /* Text strings. */ + ns_t_rp = 17, /* Responsible person. */ + ns_t_afsdb = 18, /* AFS cell database. */ + ns_t_x25 = 19, /* X_25 calling address. */ + ns_t_isdn = 20, /* ISDN calling address. */ + ns_t_rt = 21, /* Router. */ + ns_t_nsap = 22, /* NSAP address. */ + ns_t_nsap_ptr = 23, /* Reverse NSAP lookup (deprecated). */ + ns_t_sig = 24, /* Security signature. */ + ns_t_key = 25, /* Security key. */ + ns_t_px = 26, /* X.400 mail mapping. */ + ns_t_gpos = 27, /* Geographical position (withdrawn). */ + ns_t_aaaa = 28, /* Ip6 Address. */ + ns_t_loc = 29, /* Location Information. */ + ns_t_nxt = 30, /* Next domain (security). */ + ns_t_eid = 31, /* Endpoint identifier. */ + ns_t_nimloc = 32, /* Nimrod Locator. */ + ns_t_srv = 33, /* Server Selection. */ + ns_t_atma = 34, /* ATM Address */ + ns_t_naptr = 35, /* Naming Authority PoinTeR */ + ns_t_kx = 36, /* Key Exchange */ + ns_t_cert = 37, /* Certification record */ + ns_t_a6 = 38, /* IPv6 address (deprecates AAAA) */ + ns_t_dname = 39, /* Non-terminal DNAME (for IPv6) */ + ns_t_sink = 40, /* Kitchen sink (experimental) */ + ns_t_opt = 41, /* EDNS0 option (meta-RR) */ + ns_t_ds = 43, /* Delegation signer */ + ns_t_rrsig = 46, /* Resoure Record signature */ + ns_t_nsec = 47, /* Next Record */ + ns_t_dnskey = 48, /* DNSKEY record */ + ns_t_nsec3 = 50, /* Next Record v3 */ + ns_t_nsec3param = 51, /* NSEC Parameters */ + ns_t_tlsa = 52, /* TLSA */ + ns_t_tsig = 250, /* Transaction signature. */ + ns_t_ixfr = 251, /* Incremental zone transfer. */ + ns_t_axfr = 252, /* Transfer zone of authority. */ + ns_t_mailb = 253, /* Transfer mailbox records. */ + ns_t_maila = 254, /* Transfer mail agent records. */ + ns_t_any = 255, /* Wildcard match. */ +}; + +#ifdef WIN32 +#define BYTE_ORDER 1 +#define LITTLE_ENDIAN 1 +#elif __FreeBSD__ || __APPLE__ || __OpenBSD__ +#include +#elif __linux__ +# include + +#else // with thanks to + +# define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */ +# define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */ +# define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */ + +#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \ + defined(__i386) || defined(__ia64) || defined(__amd64) || \ + defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \ + defined(__alpha__) || defined(__alpha) || \ + (defined(__Lynx__) && defined(__x86__)) +# define BYTE_ORDER LITTLE_ENDIAN +#endif + +#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \ + defined(__sparc) || \ + defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \ + defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\ + defined(apollo) || defined(__convex__) || defined(_CRAY) || \ + defined(__hppa) || defined(__hp9000) || \ + defined(__hp9000s300) || defined(__hp9000s700) || \ + defined(__hp3000s900) || defined(MPE) || \ + defined(BIT_ZERO_ON_LEFT) || defined(m68k) || \ + (defined(__Lynx__) && \ + (defined(__68k__) || defined(__sparc__) || defined(__powerpc__))) +# define BYTE_ORDER BIG_ENDIAN +#endif + +#endif + +struct dnsheader { + unsigned id :16; /* query identification number */ +#if BYTE_ORDER == BIG_ENDIAN + /* fields in third byte */ + unsigned qr: 1; /* response flag */ + unsigned opcode: 4; /* purpose of message */ + unsigned aa: 1; /* authoritive answer */ + unsigned tc: 1; /* truncated message */ + unsigned rd: 1; /* recursion desired */ + /* fields in fourth byte */ + unsigned ra: 1; /* recursion available */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ad: 1; /* authentic data from named */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned rcode :4; /* response code */ +#endif +#if BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN + /* fields in third byte */ + unsigned rd :1; /* recursion desired */ + unsigned tc :1; /* truncated message */ + unsigned aa :1; /* authoritive answer */ + unsigned opcode :4; /* purpose of message */ + unsigned qr :1; /* response flag */ + /* fields in fourth byte */ + unsigned rcode :4; /* response code */ + unsigned cd: 1; /* checking disabled by resolver */ + unsigned ad: 1; /* authentic data from named */ + unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */ + unsigned ra :1; /* recursion available */ +#endif + /* remaining bytes */ + unsigned qdcount :16; /* number of question entries */ + unsigned ancount :16; /* number of answer entries */ + unsigned nscount :16; /* number of authority entries */ + unsigned arcount :16; /* number of resource entries */ +}; + + +#define L theL() +extern time_t s_starttime; +std::string questionExpand(const char* packet, uint16_t len, uint16_t& type); +bool dnspacketLessThan(const std::string& a, const std::string& b); + +/** helper function for both DNSPacket and addSOARecord() - converts a line into a struct, for easier parsing */ +void fillSOAData(const string &content, SOAData &data); + +/** for use by DNSPacket, converts a SOAData class to a ascii line again */ +string serializeSOAData(const SOAData &data); +string &attodot(string &str); //!< for when you need to insert an email address in the SOA +string strrcode(unsigned char rcode); +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dnslabeltext.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dnslabeltext.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dnslabeltext.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dnslabeltext.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,475 @@ + +#line 1 "dnslabeltext.rl" +#include +#include +#include +#include +#include +#include "namespaces.hh" + + +namespace { +void appendSplit(vector& ret, string& segment, char c) +{ + if(segment.size()>254) { + ret.push_back(segment); + segment.clear(); + } + segment.append(1, c); +} +} + +vector segmentDNSText(const string& input ) +{ + +#line 26 "dnslabeltext.cc" +static const char _dnstext_actions[] = { + 0, 1, 0, 1, 1, 1, 2, 1, + 3, 1, 4, 1, 5, 2, 0, 1, + 2, 4, 5 +}; + +static const char _dnstext_key_offsets[] = { + 0, 0, 1, 7, 11, 13, 15, 21, + 25 +}; + +static const char _dnstext_trans_keys[] = { + 34, 34, 92, 9, 10, 32, 126, 34, + 92, 48, 57, 48, 57, 48, 57, 34, + 92, 9, 10, 32, 126, 32, 34, 9, + 13, 34, 0 +}; + +static const char _dnstext_single_lengths[] = { + 0, 1, 2, 2, 0, 0, 2, 2, + 1 +}; + +static const char _dnstext_range_lengths[] = { + 0, 0, 2, 1, 1, 1, 2, 1, + 0 +}; + +static const char _dnstext_index_offsets[] = { + 0, 0, 2, 7, 11, 13, 15, 20, + 24 +}; + +static const char _dnstext_trans_targs[] = { + 2, 0, 7, 3, 2, 2, 0, 2, + 2, 4, 0, 5, 0, 6, 0, 7, + 3, 2, 2, 0, 8, 2, 8, 0, + 2, 0, 0 +}; + +static const char _dnstext_trans_actions[] = { + 3, 0, 0, 0, 11, 11, 0, 5, + 5, 7, 0, 7, 0, 7, 0, 9, + 9, 16, 16, 0, 0, 13, 0, 0, + 13, 0, 0 +}; + +static const char _dnstext_eof_actions[] = { + 0, 0, 0, 0, 0, 0, 0, 1, + 1 +}; + +static const int dnstext_start = 1; +static const int dnstext_first_final = 7; +static const int dnstext_error = 0; + +static const int dnstext_en_main = 1; + + +#line 25 "dnslabeltext.rl" + + (void)dnstext_error; // silence warnings + (void)dnstext_en_main; + const char *p = input.c_str(), *pe = input.c_str() + input.length(); + const char* eof = pe; + int cs; + char val = 0; + + string segment; + vector ret; + + +#line 99 "dnslabeltext.cc" + { + cs = dnstext_start; + } + +#line 104 "dnslabeltext.cc" + { + int _klen; + unsigned int _trans; + const char *_acts; + unsigned int _nacts; + const char *_keys; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _dnstext_trans_keys + _dnstext_key_offsets[cs]; + _trans = _dnstext_index_offsets[cs]; + + _klen = _dnstext_single_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + _klen - 1; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + ((_upper-_lower) >> 1); + if ( (*p) < *_mid ) + _upper = _mid - 1; + else if ( (*p) > *_mid ) + _lower = _mid + 1; + else { + _trans += (_mid - _keys); + goto _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _dnstext_range_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + (_klen<<1) - 2; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + (((_upper-_lower) >> 1) & ~1); + if ( (*p) < _mid[0] ) + _upper = _mid - 2; + else if ( (*p) > _mid[1] ) + _lower = _mid + 2; + else { + _trans += ((_mid - _keys)>>1); + goto _match; + } + } + _trans += _klen; + } + +_match: + cs = _dnstext_trans_targs[_trans]; + + if ( _dnstext_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _dnstext_actions + _dnstext_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) + { + switch ( *_acts++ ) + { + case 0: +#line 37 "dnslabeltext.rl" + { + ret.push_back(segment); + segment.clear(); + } + break; + case 1: +#line 41 "dnslabeltext.rl" + { + segment.clear(); + } + break; + case 2: +#line 45 "dnslabeltext.rl" + { + char c = *p; + appendSplit(ret, segment, c); + } + break; + case 3: +#line 49 "dnslabeltext.rl" + { + char c = *p; + val *= 10; + val += c-'0'; + + } + break; + case 4: +#line 55 "dnslabeltext.rl" + { + appendSplit(ret, segment, val); + val=0; + } + break; + case 5: +#line 60 "dnslabeltext.rl" + { + appendSplit(ret, segment, *(p)); + } + break; +#line 219 "dnslabeltext.cc" + } + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + if ( p == eof ) + { + const char *__acts = _dnstext_actions + _dnstext_eof_actions[cs]; + unsigned int __nacts = (unsigned int) *__acts++; + while ( __nacts-- > 0 ) { + switch ( *__acts++ ) { + case 0: +#line 37 "dnslabeltext.rl" + { + ret.push_back(segment); + segment.clear(); + } + break; +#line 242 "dnslabeltext.cc" + } + } + } + + _out: {} + } + +#line 73 "dnslabeltext.rl" + + + if ( cs < dnstext_first_final ) { + throw runtime_error("Unable to parse DNS TXT '"+input+"'"); + } + + return ret; +}; +string segmentDNSLabel(const string& input ) +{ + +#line 262 "dnslabeltext.cc" +static const char _dnslabel_actions[] = { + 0, 1, 0, 1, 1, 1, 2, 1, + 3, 1, 4, 2, 3, 0, 2, 3, + 4 +}; + +static const char _dnslabel_key_offsets[] = { + 0, 0, 4, 8, 10, 12, 16 +}; + +static const char _dnslabel_trans_keys[] = { + 46, 92, 32, 126, 46, 92, 48, 57, + 48, 57, 48, 57, 46, 92, 32, 126, + 46, 92, 32, 126, 0 +}; + +static const char _dnslabel_single_lengths[] = { + 0, 2, 2, 0, 0, 2, 2 +}; + +static const char _dnslabel_range_lengths[] = { + 0, 1, 1, 1, 1, 1, 1 +}; + +static const char _dnslabel_index_offsets[] = { + 0, 0, 4, 8, 10, 12, 16 +}; + +static const char _dnslabel_trans_targs[] = { + 6, 2, 1, 0, 1, 1, 3, 0, + 4, 0, 5, 0, 6, 2, 1, 0, + 6, 2, 1, 0, 0 +}; + +static const char _dnslabel_trans_actions[] = { + 1, 0, 9, 0, 3, 3, 5, 0, + 5, 0, 5, 0, 11, 7, 14, 0, + 1, 0, 9, 0, 0 +}; + +static const int dnslabel_start = 1; +static const int dnslabel_first_final = 6; +static const int dnslabel_error = 0; + +static const int dnslabel_en_main = 1; + + +#line 86 "dnslabeltext.rl" + + (void)dnslabel_error; // silence warnings + (void)dnslabel_en_main; + const char *p = input.c_str(), *pe = input.c_str() + input.length(); + //const char* eof = pe; + int cs; + char val = 0; + + string ret; + string segment; + + +#line 323 "dnslabeltext.cc" + { + cs = dnslabel_start; + } + +#line 328 "dnslabeltext.cc" + { + int _klen; + unsigned int _trans; + const char *_acts; + unsigned int _nacts; + const char *_keys; + + if ( p == pe ) + goto _test_eof; + if ( cs == 0 ) + goto _out; +_resume: + _keys = _dnslabel_trans_keys + _dnslabel_key_offsets[cs]; + _trans = _dnslabel_index_offsets[cs]; + + _klen = _dnslabel_single_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + _klen - 1; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + ((_upper-_lower) >> 1); + if ( (*p) < *_mid ) + _upper = _mid - 1; + else if ( (*p) > *_mid ) + _lower = _mid + 1; + else { + _trans += (_mid - _keys); + goto _match; + } + } + _keys += _klen; + _trans += _klen; + } + + _klen = _dnslabel_range_lengths[cs]; + if ( _klen > 0 ) { + const char *_lower = _keys; + const char *_mid; + const char *_upper = _keys + (_klen<<1) - 2; + while (1) { + if ( _upper < _lower ) + break; + + _mid = _lower + (((_upper-_lower) >> 1) & ~1); + if ( (*p) < _mid[0] ) + _upper = _mid - 2; + else if ( (*p) > _mid[1] ) + _lower = _mid + 2; + else { + _trans += ((_mid - _keys)>>1); + goto _match; + } + } + _trans += _klen; + } + +_match: + cs = _dnslabel_trans_targs[_trans]; + + if ( _dnslabel_trans_actions[_trans] == 0 ) + goto _again; + + _acts = _dnslabel_actions + _dnslabel_trans_actions[_trans]; + _nacts = (unsigned int) *_acts++; + while ( _nacts-- > 0 ) + { + switch ( *_acts++ ) + { + case 0: +#line 98 "dnslabeltext.rl" + { + printf("Segment end, segment = '%s'\n", segment.c_str()); + ret.append(1, (unsigned char)segment.size()); + ret.append(segment); + segment.clear(); + } + break; + case 1: +#line 105 "dnslabeltext.rl" + { + printf("'\\%c' ", *p); + segment.append(1, *p); + } + break; + case 2: +#line 109 "dnslabeltext.rl" + { + char c = *p; + val *= 10; + val += c-'0'; + + } + break; + case 3: +#line 115 "dnslabeltext.rl" + { + printf("_%c_ ", val); + segment.append(1, val); + val=0; + } + break; + case 4: +#line 121 "dnslabeltext.rl" + { + printf("'%c' ", *p); + segment.append(1, *p); + } + break; +#line 441 "dnslabeltext.cc" + } + } + +_again: + if ( cs == 0 ) + goto _out; + if ( ++p != pe ) + goto _resume; + _test_eof: {} + _out: {} + } + +#line 136 "dnslabeltext.rl" + + + if ( cs < dnslabel_first_final ) { + throw runtime_error("Unable to parse DNS Label '"+input+"'"); + } + + if(ret.empty() || ret[0] != 0) + ret.append(1, 0); + return ret; +}; +#if 0 +int main() +{ + //char blah[]="\"blah\" \"bleh\" \"bloeh\\\"bleh\" \"\\97enzo\""; + char blah[]="\"v=spf1 ip4:67.106.74.128/25 ip4:63.138.42.224/28 ip4:65.204.46.224/27 \\013\\010ip4:66.104.217.176/28 \\013\\010ip4:209.48.147.0/27 ~all\""; + //char blah[]="\"abc \\097\\098 def\""; + printf("Input: '%s'\n", blah); + vector res=dnstext(blah); + cerr< +#include + +#include "namespaces.hh" + +class UnknownRecordContent : public DNSRecordContent +{ +public: + UnknownRecordContent(const DNSRecord& dr, PacketReader& pr) + : DNSRecordContent(dr.d_type), d_dr(dr) + { + pr.copyRecord(d_record, dr.d_clen); + } + + UnknownRecordContent(const string& zone) : DNSRecordContent(0) + { + d_record.insert(d_record.end(), zone.begin(), zone.end()); + } + + string getZoneRepresentation() const + { + ostringstream str; + str<<"\\# "<<(unsigned int)d_record.size()<<" "; + char hex[4]; + for(size_t n=0; n parts; + stringtok(parts, tmp); + if(parts.size()!=3 && !(parts.size()==2 && equals(parts[1],"0")) ) + throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got "+lexical_cast(parts.size())+": "+tmp ); + const string& relevant=(parts.size() > 2) ? parts[2] : ""; + unsigned int total=atoi(parts[1].c_str()); + if(relevant.size()!=2*total) + throw runtime_error("invalid unknown record"); + string out; + out.reserve(total+1); + for(unsigned int n=0; n < total; ++n) { + int c; + sscanf(relevant.c_str()+2*n, "%02x", &c); + out.append(1, (char)c); + } + pw.xfrBlob(out); + } +private: + DNSRecord d_dr; + vector d_record; +}; + +static const string EncodeDNSLabel(const string& input) +{ + if(input.length() == 1 && input[0]=='.') // otherwise we encode .. (long story) + return string (1, 0); + + labelparts_t parts; + bool unescapedSomething = labeltokUnescape(parts, input); + string ret; + + if(!unescapedSomething) { + for(labelparts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) { + ret.append(1, i->second - i->first); + ret.append(input.c_str() + i->first, i->second - i->first); + } + + } else { + for(labelparts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) { + string part(input.c_str() + i->first, i->second - i->first); + boost::replace_all(part, "\\\\", "\\"); + boost::replace_all(part, "\\.", "."); + + ret.append(1, part.length()); + ret.append(part); + } + } + ret.append(1, 0); + return ret; +} + + +shared_ptr DNSRecordContent::unserialize(const string& qname, uint16_t qtype, const string& serialized) +{ + dnsheader dnsheader; + memset(&dnsheader, 0, sizeof(dnsheader)); + dnsheader.qdcount=htons(1); + dnsheader.ancount=htons(1); + + vector packet; // build pseudo packet + + /* will look like: dnsheader, 5 bytes, encoded qname, dns record header, serialized data */ + + string encoded=EncodeDNSLabel(qname); + + packet.resize(sizeof(dnsheader) + 5 + encoded.size() + sizeof(struct dnsrecordheader) + serialized.size()); + + uint16_t pos=0; + + memcpy(&packet[0], &dnsheader, sizeof(dnsheader)); pos+=sizeof(dnsheader); + + char tmp[6]="\x0" "\x0\x1" "\x0\x1"; // root question for ns_t_a + memcpy(&packet[pos], &tmp, 5); pos+=5; + + memcpy(&packet[pos], encoded.c_str(), encoded.size()); pos+=(uint16_t)encoded.size(); + + struct dnsrecordheader drh; + drh.d_type=htons(qtype); + drh.d_class=htons(1); + drh.d_ttl=0; + drh.d_clen=htons(serialized.size()); + + memcpy(&packet[pos], &drh, sizeof(drh)); pos+=sizeof(drh); + memcpy(&packet[pos], serialized.c_str(), serialized.size()); pos+=(uint16_t)serialized.size(); + + MOADNSParser mdp((char*)&*packet.begin(), (unsigned int)packet.size()); + shared_ptr ret= mdp.d_answers.begin()->first.d_content; + ret->header.d_type=ret->d_qtype; + ret->label=mdp.d_answers.begin()->first.d_label; + ret->header.d_ttl=mdp.d_answers.begin()->first.d_ttl; + return ret; +} + +DNSRecordContent* DNSRecordContent::mastermake(const DNSRecord &dr, + PacketReader& pr) +{ + uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT + + typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type)); + if(i==getTypemap().end() || !i->second) { + return new UnknownRecordContent(dr, pr); + } + + return i->second(dr, pr); +} + +DNSRecordContent* DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass, + const string& content) +{ + zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype)); + if(i==getZmakermap().end()) { + return new UnknownRecordContent(content); + } + + return i->second(content); +} + +DNSRecordContent::typemap_t& DNSRecordContent::getTypemap() +{ + static DNSRecordContent::typemap_t typemap; + return typemap; +} + +DNSRecordContent::n2typemap_t& DNSRecordContent::getN2Typemap() +{ + static DNSRecordContent::n2typemap_t n2typemap; + return n2typemap; +} + +DNSRecordContent::t2namemap_t& DNSRecordContent::getT2Namemap() +{ + static DNSRecordContent::t2namemap_t t2namemap; + return t2namemap; +} + + +DNSRecordContent::zmakermap_t& DNSRecordContent::getZmakermap() +{ + static DNSRecordContent::zmakermap_t zmakermap; + return zmakermap; +} + +void MOADNSParser::init(const char *packet, unsigned int len) +{ + if(len < sizeof(dnsheader)) + throw MOADNSException("Packet shorter than minimal header"); + + memcpy(&d_header, packet, sizeof(dnsheader)); + + if(d_header.opcode!=0 && d_header.opcode != 4) // notification + throw MOADNSException("Can't parse non-query packet with opcode="+ lexical_cast(d_header.opcode)); + + d_header.qdcount=ntohs(d_header.qdcount); + d_header.ancount=ntohs(d_header.ancount); + d_header.nscount=ntohs(d_header.nscount); + d_header.arcount=ntohs(d_header.arcount); + + uint16_t contentlen=len-sizeof(dnsheader); + + d_content.resize(contentlen); + copy(packet+sizeof(dnsheader), packet+len, d_content.begin()); + + unsigned int n=0; + + PacketReader pr(d_content); + bool validPacket=false; + try { + d_qtype = d_qclass = 0; // sometimes replies come in with no question, don't present garbage then + + for(n=0;n < d_header.qdcount; ++n) { + d_qname=pr.getLabel(); + d_qtype=pr.get16BitInt(); + d_qclass=pr.get16BitInt(); + } + + struct dnsrecordheader ah; + vector record; + validPacket=true; + for(n=0;n < (unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount); ++n) { + DNSRecord dr; + + if(n < d_header.ancount) + dr.d_place=DNSRecord::Answer; + else if(n < d_header.ancount + d_header.nscount) + dr.d_place=DNSRecord::Nameserver; + else + dr.d_place=DNSRecord::Additional; + + unsigned int recordStartPos=pr.d_pos; + + string label=pr.getLabel(); + + pr.getDnsrecordheader(ah); + dr.d_ttl=ah.d_ttl; + dr.d_type=ah.d_type; + dr.d_class=ah.d_class; + + dr.d_label=label; + dr.d_clen=ah.d_clen; + + dr.d_content=boost::shared_ptr(DNSRecordContent::mastermake(dr, pr)); + d_answers.push_back(make_pair(dr, pr.d_pos)); + + if(dr.d_type == QType::TSIG && dr.d_class == 0xff) + d_tsigPos = recordStartPos + sizeof(struct dnsheader); + } + +#if 0 + if(pr.d_pos!=contentlen) { + throw MOADNSException("Packet ("+d_qname+"|#"+lexical_cast(d_qtype)+") has trailing garbage ("+ lexical_cast(pr.d_pos) + " < " + + lexical_cast(contentlen) + ")"); + } +#endif + } + catch(std::out_of_range &re) { + if(validPacket && d_header.tc) { // don't sweat it over truncated packets, but do adjust an, ns and arcount + if(n < d_header.ancount) { + d_header.ancount=n; d_header.nscount = d_header.arcount = 0; + } + else if(n < d_header.ancount + d_header.nscount) { + d_header.nscount = n - d_header.ancount; d_header.arcount=0; + } + else { + d_header.arcount = n - d_header.ancount - d_header.nscount; + } + } + else { + throw MOADNSException("Error parsing packet of "+lexical_cast(len)+" bytes (rd="+ + lexical_cast(d_header.rd)+ + "), out of bounds: "+string(re.what())); + } + } +} + + +void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah) +{ + unsigned int n; + unsigned char *p=reinterpret_cast(&ah); + + for(n=0; n < sizeof(dnsrecordheader); ++n) + p[n]=d_content.at(d_pos++); + + ah.d_type=ntohs(ah.d_type); + ah.d_class=ntohs(ah.d_class); + ah.d_clen=ntohs(ah.d_clen); + ah.d_ttl=ntohl(ah.d_ttl); + + d_startrecordpos=d_pos; // needed for getBlob later on + d_recordlen=ah.d_clen; +} + + +void PacketReader::copyRecord(vector& dest, uint16_t len) +{ + dest.resize(len); + if(!len) + return; + + for(uint16_t n=0;n d_content.size()) + throw std::out_of_range("Attempt to copy outside of packet"); + + memcpy(dest, &d_content.at(d_pos), len); + d_pos+=len; +} + +void PacketReader::xfr48BitInt(uint64_t& ret) +{ + ret=0; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); +} + +uint32_t PacketReader::get32BitInt() +{ + uint32_t ret=0; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + ret<<=8; + ret+=d_content.at(d_pos++); + + return ret; +} + + +uint16_t PacketReader::get16BitInt() +{ + return get16BitInt(d_content, d_pos); +} + +uint16_t PacketReader::get16BitInt(const vector&content, uint16_t& pos) +{ + uint16_t ret=0; + ret+=content.at(pos++); + ret<<=8; + ret+=content.at(pos++); + + return ret; +} + +uint8_t PacketReader::get8BitInt() +{ + return d_content.at(d_pos++); +} + + +string PacketReader::getLabel(unsigned int recurs) +{ + string ret; + ret.reserve(40); + getLabelFromContent(d_content, d_pos, ret, recurs++); + return ret; +} + +static string txtEscape(const string &name) +{ + string ret; + + for(string::const_iterator i=name.begin();i!=name.end();++i) + if(*i=='\n') { // XXX FIXME this should do a way better job! + ret += "\\010"; + } + else if(*i=='"' || *i=='\\'){ + ret += '\\'; + ret += *i; + } + else + ret += *i; + return ret; +} + +// exceptions thrown here do not result in logging in the main pdns auth server - just so you know! +string PacketReader::getText(bool multi) +{ + string ret; + ret.reserve(40); + while(d_pos < d_startrecordpos + d_recordlen ) { + if(!ret.empty()) { + ret.append(1,' '); + } + unsigned char labellen=d_content.at(d_pos++); + + ret.append(1,'"'); + if(labellen) { // no need to do anything for an empty string + string val(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1); + ret.append(txtEscape(val)); // the end is one beyond the packet + } + ret.append(1,'"'); + d_pos+=labellen; + if(!multi) + break; + } + + return ret; +} + + +void PacketReader::getLabelFromContent(const vector& content, uint16_t& frompos, string& ret, int recurs) +{ + if(recurs > 10) + throw MOADNSException("Loop"); + + for(;;) { + unsigned char labellen=content.at(frompos++); + + if(!labellen) { + if(ret.empty()) + ret.append(1,'.'); + break; + } + if((labellen & 0xc0) == 0xc0) { + uint16_t offset=256*(labellen & ~0xc0) + (unsigned int)content.at(frompos++) - sizeof(dnsheader); + // cout<<"This is an offset, need to go to: "< > parts_t; + parts_t parts; + vstringtok(parts, label, "."); + string ret; + ret.reserve(label.size()+4); + for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) { + if(!root.empty() && !strncasecmp(root.c_str(), label.c_str() + i->first, 1 + label.length() - i->first)) { // also match trailing 0, hence '1 +' + const char rootptr[2]={0xc0,0x11}; + ret.append(rootptr, 2); + return ret; + } + ret.append(1, (char)(i->second - i->first)); + ret.append(label.c_str() + i->first, i->second - i->first); + } + ret.append(1, (char)0); + return ret; +} + + +void simpleExpandTo(const string& label, unsigned int frompos, string& ret) +{ + unsigned int labellen=0; + while((labellen=label.at(frompos++))) { + ret.append(label.c_str()+frompos, labellen); + ret.append(1,'.'); + frompos+=labellen; + } +} + +/** Simple DNSPacketMangler. Ritual is: get a pointer into the packet and moveOffset() to beyond your needs + * If you survive that, feel free to read from the pointer */ +class DNSPacketMangler +{ +public: + explicit DNSPacketMangler(std::string& packet) + : d_packet(packet), d_notyouroffset(12), d_offset(d_notyouroffset) + {} + + void skipLabel() + { + uint8_t len; + while((len=get8BitInt())) { + if(len >= 0xc0) { // extended label + get8BitInt(); + return; + } + skipBytes(len); + } + } + void skipBytes(uint16_t bytes) + { + moveOffset(bytes); + } + uint16_t get16BitInt() + { + const char* p = d_packet.c_str() + d_offset; + moveOffset(2); + uint16_t ret; + memcpy(&ret, (void*)p, 2); + return ntohs(ret); + } + + uint8_t get8BitInt() + { + const char* p = d_packet.c_str() + d_offset; + moveOffset(1); + return *p; + } + + void skipRData() + { + int toskip = get16BitInt(); + moveOffset(toskip); + } + void decreaseAndSkip32BitInt(uint32_t decrease) + { + const char *p = (const char*)d_packet.c_str() + d_offset; + moveOffset(4); + + uint32_t tmp; + memcpy(&tmp, (void*) p, sizeof(tmp)); + tmp = ntohl(tmp); + tmp-=decrease; + tmp = htonl(tmp); + d_packet.replace(d_offset-4, sizeof(tmp), (const char*)&tmp, sizeof(tmp)); + } +private: + void moveOffset(uint16_t by) + { + d_notyouroffset += by; + if(d_notyouroffset > d_packet.length()) + throw std::out_of_range("dns packet out of range: "+lexical_cast(d_notyouroffset) +" > " + + lexical_cast(d_packet.length()) ); + } + std::string& d_packet; + + uint32_t d_notyouroffset; // only 'moveOffset' can touch this + const uint32_t& d_offset; // look.. but don't touch + +}; + +// method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it +void ageDNSPacket(std::string& packet, uint32_t seconds) +{ + if(packet.length() < sizeof(dnsheader)) + return; + try + { + dnsheader dh; + memcpy((void*)&dh, (const dnsheader*)packet.c_str(), sizeof(dh)); + int numrecords = ntohs(dh.ancount) + ntohs(dh.nscount) + ntohs(dh.arcount); + DNSPacketMangler dpm(packet); + + int n; + for(n=0; n < ntohs(dh.qdcount) ; ++n) { + dpm.skipLabel(); + dpm.skipBytes(4); // qtype, qclass + } + // cerr<<"Skipped "< +#include +#include +#include +#include +#include +// #include +#include "misc.hh" +#include +#include +#include +#include +#include "dns.hh" +#include "dnswriter.hh" + +/** DNS records have three representations: + 1) in the packet + 2) parsed in a class, ready for use + 3) in the zone + + We should implement bidirectional transitions between 1&2 and 2&3. + Currently we have: 1 -> 2 + 2 -> 3 + + We can add: 2 -> 1 easily by reversing the packetwriter + And we might be able to reverse 2 -> 3 as well +*/ + +#include "namespaces.hh" +#include "namespaces.hh" + +class MOADNSException : public runtime_error +{ +public: + MOADNSException(const string& str) : runtime_error(str) + {} +}; + + +class MOADNSParser; + +class PacketReader +{ +public: + PacketReader(const vector& content) + : d_pos(0), d_startrecordpos(0), d_content(content) + { + d_recordlen = content.size(); + } + + uint32_t get32BitInt(); + uint16_t get16BitInt(); + uint8_t get8BitInt(); + + void xfr48BitInt(uint64_t& val); + + void xfr32BitInt(uint32_t& val) + { + val=get32BitInt(); + } + + void xfrIP(uint32_t& val) + { + xfr32BitInt(val); + val=htonl(val); + } + + void xfrTime(uint32_t& val) + { + xfr32BitInt(val); + } + + + void xfr16BitInt(uint16_t& val) + { + val=get16BitInt(); + } + + void xfrType(uint16_t& val) + { + xfr16BitInt(val); + } + + + void xfr8BitInt(uint8_t& val) + { + val=get8BitInt(); + } + + + void xfrLabel(string &label, bool compress=false) + { + label=getLabel(); + } + + void xfrText(string &text, bool multi=false) + { + text=getText(multi); + } + + void xfrBlob(string& blob); + void xfrBlob(string& blob, int length); + void xfrHexBlob(string& blob, bool keepReading=false); + + static uint16_t get16BitInt(const vector&content, uint16_t& pos); + static void getLabelFromContent(const vector& content, uint16_t& frompos, string& ret, int recurs); + + void getDnsrecordheader(struct dnsrecordheader &ah); + void copyRecord(vector& dest, uint16_t len); + void copyRecord(unsigned char* dest, uint16_t len); + + string getLabel(unsigned int recurs=0); + string getText(bool multi); + + uint16_t d_pos; + +private: + uint16_t d_startrecordpos; // needed for getBlob later on + uint16_t d_recordlen; // ditto + const vector& d_content; +}; + +struct DNSRecord; + +class DNSRecordContent +{ +public: + static DNSRecordContent* mastermake(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* mastermake(uint16_t qtype, uint16_t qclass, const string& zone); + + virtual std::string getZoneRepresentation() const = 0; + virtual ~DNSRecordContent() {} + virtual void toPacket(DNSPacketWriter& pw)=0; + virtual string serialize(const string& qname, bool canonic=false, bool lowerCase=false) // it would rock if this were const, but it is too hard + { + vector packet; + string empty; + DNSPacketWriter pw(packet, empty, 1); + if(canonic) + pw.setCanonic(true); + + if(lowerCase) + pw.setLowercase(true); + + pw.startRecord(qname, d_qtype); + this->toPacket(pw); + pw.commit(); + + string record; + pw.getRecords(record); + return record; + } + + static shared_ptr unserialize(const string& qname, uint16_t qtype, const string& serialized); + + void doRecordCheck(const struct DNSRecord&){} + + std::string label; + struct dnsrecordheader header; + + typedef DNSRecordContent* makerfunc_t(const struct DNSRecord& dr, PacketReader& pr); + typedef DNSRecordContent* zmakerfunc_t(const string& str); + + static void regist(uint16_t cl, uint16_t ty, makerfunc_t* f, zmakerfunc_t* z, const char* name) + { + if(f) + getTypemap()[make_pair(cl,ty)]=f; + if(z) + getZmakermap()[make_pair(cl,ty)]=z; + + getT2Namemap().insert(make_pair(make_pair(cl,ty), name)); + getN2Typemap().insert(make_pair(name, make_pair(cl,ty))); + } + + static void unregist(uint16_t cl, uint16_t ty) + { + pair key=make_pair(cl, ty); + getTypemap().erase(key); + getZmakermap().erase(key); + } + + static uint16_t TypeToNumber(const string& name) + { + n2typemap_t::const_iterator iter = getN2Typemap().find(toUpper(name)); + if(iter != getN2Typemap().end()) + return iter->second.second; + + if(boost::starts_with(name, "TYPE")) + return atoi(name.c_str()+4); + + throw runtime_error("Unknown DNS type '"+name+"'"); + } + + static const string NumberToType(uint16_t num, uint16_t classnum=1) + { + t2namemap_t::const_iterator iter = getT2Namemap().find(make_pair(classnum, num)); + if(iter == getT2Namemap().end()) + return "TYPE" + lexical_cast(num); + // throw runtime_error("Unknown DNS type with numerical id "+lexical_cast(num)); + return iter->second; + } + + explicit DNSRecordContent(uint16_t type) : d_qtype(type) + {} + + + DNSRecordContent& operator=(const DNSRecordContent& orig) + { + const_cast(d_qtype) = orig.d_qtype; // **COUGH** + label = orig.label; + header = orig.header; + return *this; + } + + + const uint16_t d_qtype; + +protected: + typedef std::map, makerfunc_t* > typemap_t; + typedef std::map, zmakerfunc_t* > zmakermap_t; + typedef std::map, string > t2namemap_t; + typedef std::map > n2typemap_t; + static typemap_t& getTypemap(); + static t2namemap_t& getT2Namemap(); + static n2typemap_t& getN2Typemap(); + static zmakermap_t& getZmakermap(); +}; + +struct DNSRecord +{ + std::string d_label; + uint16_t d_type; + uint16_t d_class; + uint32_t d_ttl; + uint16_t d_clen; + enum {Answer=1, Nameserver, Additional} d_place; + boost::shared_ptr d_content; + + bool operator<(const DNSRecord& rhs) const + { + string lzrp, rzrp; + if(d_content) + lzrp=toLower(d_content->getZoneRepresentation()); + if(rhs.d_content) + rzrp=toLower(rhs.d_content->getZoneRepresentation()); + + string llabel=toLower(d_label); + string rlabel=toLower(rhs.d_label); + + return + tie(llabel, d_type, d_class, lzrp) < + tie(rlabel, rhs.d_type, rhs.d_class, rzrp); + } + + bool operator==(const DNSRecord& rhs) const + { + string lzrp, rzrp; + if(d_content) + lzrp=toLower(d_content->getZoneRepresentation()); + if(rhs.d_content) + rzrp=toLower(rhs.d_content->getZoneRepresentation()); + + string llabel=toLower(d_label); + string rlabel=toLower(rhs.d_label); + + return + tie(llabel, d_type, d_class, lzrp) == + tie(rlabel, rhs.d_type, rhs.d_class, rzrp); + } +}; + +//! This class can be used to parse incoming packets, and is copyable +class MOADNSParser : public boost::noncopyable +{ +public: + //! Parse from a string + MOADNSParser(const string& buffer) : d_tsigPos(0) + { + init(buffer.c_str(), (unsigned int)buffer.size()); + } + + //! Parse from a pointer and length + MOADNSParser(const char *packet, unsigned int len) : d_tsigPos(0) + { + init(packet, len); + } + + dnsheader d_header; + string d_qname; + uint16_t d_qclass, d_qtype; + //uint8_t d_rcode; + + typedef vector > answers_t; + + //! All answers contained in this packet + answers_t d_answers; + + shared_ptr getPacketReader(uint16_t offset) + { + shared_ptr pr(new PacketReader(d_content)); + pr->d_pos=offset; + return pr; + } + + uint16_t getTSIGPos() + { + return d_tsigPos; + } +private: + void getDnsrecordheader(struct dnsrecordheader &ah); + void init(const char *packet, unsigned int len); + vector d_content; + uint16_t d_tsigPos; +}; + +string simpleCompress(const string& label, const string& root=""); +void simpleExpandTo(const string& label, unsigned int frompos, string& ret); +void ageDNSPacket(std::string& packet, uint32_t seconds); +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dns_random.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dns_random.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dns_random.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dns_random.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,72 @@ +#include "aescpp.h" +#include +#include +#include +#include +#include +#include +#include "dns_random.hh" + +using namespace std; + +static aes_encrypt_ctx g_cx; +static unsigned char g_counter[16]; +static uint32_t g_in; + +static bool g_initialized; + +void dns_random_init(const char data[16]) +{ + aes_init(); + + aes_encrypt_key128((const unsigned char*)data, &g_cx); + struct timeval now; + gettimeofday(&now, 0); + + memcpy(g_counter, &now.tv_usec, sizeof(now.tv_usec)); + memcpy(g_counter+sizeof(now.tv_usec), &now.tv_sec, sizeof(now.tv_sec)); + g_in = getpid() | (getppid()<<16); + + g_initialized = true; + srandom(dns_random(numeric_limits::max())); +} + +static void counterIncrement(unsigned char* counter) +{ + if(!++counter[0]) + if(!++counter[1]) + if(!++counter[2]) + if(!++counter[3]) + if(!++counter[4]) + if(!++counter[5]) + if(!++counter[6]) + if(!++counter[7]) + if(!++counter[8]) + if(!++counter[9]) + if(!++counter[10]) + if(!++counter[11]) + if(!++counter[12]) + if(!++counter[13]) + if(!++counter[14]) + ++counter[15]; + +} + +unsigned int dns_random(unsigned int n) +{ + if(!g_initialized) + abort(); + uint32_t out; + aes_ctr_encrypt((unsigned char*) &g_in, (unsigned char*)& out, sizeof(g_in), g_counter, counterIncrement, &g_cx); + return out % n; +} + +#if 0 +int main() +{ + dns_random_init("0123456789abcdef"); + + for(int n = 0; n < 16; n++) + cerr< + +boilerplate_conv(A, ns_t_a, conv.xfrIP(d_ip)); + +ARecordContent::ARecordContent(uint32_t ip) : DNSRecordContent(ns_t_a) +{ + d_ip = ip; +} + +uint32_t ARecordContent::getIP() const +{ + return d_ip; +} + +void ARecordContent::doRecordCheck(const DNSRecord& dr) +{ + if(dr.d_clen!=4) + throw MOADNSException("Wrong size for A record ("+lexical_cast(dr.d_clen)+")"); +} + +class AAAARecordContent : public DNSRecordContent +{ +public: + AAAARecordContent() : DNSRecordContent(ns_t_aaaa) + {} + + static void report(void) + { + regist(1, ns_t_aaaa, &make, &make, "AAAA"); + } + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr) + { + if(dr.d_clen!=16) + throw MOADNSException("Wrong size for AAAA record"); + + AAAARecordContent* ret=new AAAARecordContent(); + pr.copyRecord((unsigned char*) &ret->d_ip6, 16); + return ret; + } + + static DNSRecordContent* make(const string& zone) + { + AAAARecordContent *ar=new AAAARecordContent(); + if(Utility::inet_pton( AF_INET6, zone.c_str(), static_cast< void * >( ar->d_ip6 )) <= 0) + throw MOADNSException("Asked to encode '"+zone+"' as an IPv6 address, but does not parse"); + return ar; + } + + void toPacket(DNSPacketWriter& pw) + { + string blob(d_ip6, d_ip6+16); + pw.xfrBlob(blob); + } + + string getZoneRepresentation() const + { + struct sockaddr_in6 addr; + memset(&addr, 0, sizeof(addr)); + addr.sin6_family=AF_INET6; + memcpy(&addr.sin6_addr, d_ip6, 16); + + char tmp[128]; + tmp[0]=0; + Utility::inet_ntop(AF_INET6, (const char*)& addr.sin6_addr, tmp, sizeof(tmp)); + return tmp; + } + +private: + unsigned char d_ip6[16]; +}; + + + +boilerplate_conv(NS, ns_t_ns, conv.xfrLabel(d_content, true)); +boilerplate_conv(PTR, ns_t_ptr, conv.xfrLabel(d_content, true)); +boilerplate_conv(CNAME, ns_t_cname, conv.xfrLabel(d_content, true)); +boilerplate_conv(MR, ns_t_mr, conv.xfrLabel(d_alias, false)); +boilerplate_conv(TXT, ns_t_txt, conv.xfrText(d_text, true)); +boilerplate_conv(SPF, 99, conv.xfrText(d_text, true)); +boilerplate_conv(HINFO, ns_t_hinfo, conv.xfrText(d_cpu); conv.xfrText(d_host)); + +boilerplate_conv(RP, ns_t_rp, + conv.xfrLabel(d_mbox); + conv.xfrLabel(d_info) + ); + + +boilerplate_conv(OPT, ns_t_opt, + conv.xfrBlob(d_data) + ); + +void OPTRecordContent::getData(vector >& options) +{ + string::size_type pos=0; + uint16_t code, len; + while(d_data.size() >= 4 + pos) { + code = 256 * (unsigned char)d_data[pos] + (unsigned char)d_data[pos+1]; + len = 256 * (unsigned char)d_data[pos+2] + (unsigned char)d_data[pos+3]; + pos+=4; + + if(pos + len > d_data.size()) + break; + + string field(d_data.c_str() + pos, len); + pos+=len; + options.push_back(make_pair(code, field)); + } +} + +boilerplate_conv(TSIG, ns_t_tsig, + conv.xfrLabel(d_algoName); + conv.xfr48BitInt(d_time); + conv.xfr16BitInt(d_fudge); + uint16_t size=d_mac.size(); + conv.xfr16BitInt(size); + conv.xfrBlob(d_mac, size); + conv.xfr16BitInt(d_origID); + conv.xfr16BitInt(d_eRcode); + size=d_otherData.size(); + conv.xfr16BitInt(size); + conv.xfrBlob(d_otherData, size); + ); + +MXRecordContent::MXRecordContent(uint16_t preference, const string& mxname) : DNSRecordContent(ns_t_mx), d_preference(preference), d_mxname(mxname) +{ +} + +boilerplate_conv(MX, ns_t_mx, + conv.xfr16BitInt(d_preference); + conv.xfrLabel(d_mxname, true); + ) + +boilerplate_conv(KX, ns_t_kx, + conv.xfr16BitInt(d_preference); + conv.xfrLabel(d_exchanger, false); + ) + +boilerplate_conv(IPSECKEY, 45, /* ns_t_ipsec */ + conv.xfr8BitInt(d_preference); + conv.xfr8BitInt(d_gatewaytype); + conv.xfr8BitInt(d_algorithm); + conv.xfrLabel(d_gateway, false); + conv.xfrBlob(d_publickey); + ) + +boilerplate_conv(DHCID, 49, + conv.xfrBlob(d_content); + ) + + +boilerplate_conv(AFSDB, ns_t_afsdb, + conv.xfr16BitInt(d_subtype); + conv.xfrLabel(d_hostname); + ) + + +boilerplate_conv(NAPTR, ns_t_naptr, + conv.xfr16BitInt(d_order); conv.xfr16BitInt(d_preference); + conv.xfrText(d_flags); conv.xfrText(d_services); conv.xfrText(d_regexp); + conv.xfrLabel(d_replacement); + ) + + +SRVRecordContent::SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, const string& target) + : DNSRecordContent(ns_t_srv), d_preference(preference), d_weight(weight), d_port(port), d_target(target) +{} + +boilerplate_conv(SRV, ns_t_srv, + conv.xfr16BitInt(d_preference); conv.xfr16BitInt(d_weight); conv.xfr16BitInt(d_port); + conv.xfrLabel(d_target); + ) + + + +SOARecordContent::SOARecordContent(const string& mname, const string& rname, const struct soatimes& st) + : DNSRecordContent(ns_t_soa), d_mname(mname), d_rname(rname) +{ + d_st=st; +} + +boilerplate_conv(SOA, ns_t_soa, + conv.xfrLabel(d_mname, true); + conv.xfrLabel(d_rname, true); + conv.xfr32BitInt(d_st.serial); + conv.xfr32BitInt(d_st.refresh); + conv.xfr32BitInt(d_st.retry); + conv.xfr32BitInt(d_st.expire); + conv.xfr32BitInt(d_st.minimum); + ); +#undef KEY +boilerplate_conv(KEY, ns_t_key, + conv.xfr16BitInt(d_flags); + conv.xfr8BitInt(d_protocol); + conv.xfr8BitInt(d_algorithm); + conv.xfrBlob(d_certificate); + ); + +boilerplate_conv(CERT, 37, + conv.xfr16BitInt(d_type); + conv.xfr16BitInt(d_tag); + conv.xfr8BitInt(d_algorithm); + conv.xfrBlob(d_certificate); + ) + +boilerplate_conv(TLSA, 52, + conv.xfr8BitInt(d_certusage); + conv.xfr8BitInt(d_selector); + conv.xfr8BitInt(d_matchtype); + conv.xfrHexBlob(d_cert, true); + ) + +#undef DS +DSRecordContent::DSRecordContent() : DNSRecordContent(43) {} +boilerplate_conv(DS, 43, + conv.xfr16BitInt(d_tag); + conv.xfr8BitInt(d_algorithm); + conv.xfr8BitInt(d_digesttype); + conv.xfrHexBlob(d_digest, true); // keep reading across spaces + ) + +DLVRecordContent::DLVRecordContent() : DNSRecordContent(32769) {} +boilerplate_conv(DLV,32769 , + conv.xfr16BitInt(d_tag); + conv.xfr8BitInt(d_algorithm); + conv.xfr8BitInt(d_digesttype); + conv.xfrHexBlob(d_digest, true); // keep reading across spaces + ) + + +boilerplate_conv(SSHFP, 44, + conv.xfr8BitInt(d_algorithm); + conv.xfr8BitInt(d_fptype); + conv.xfrHexBlob(d_fingerprint); + ) + +boilerplate_conv(RRSIG, 46, + conv.xfrType(d_type); + conv.xfr8BitInt(d_algorithm); + conv.xfr8BitInt(d_labels); + conv.xfr32BitInt(d_originalttl); + conv.xfrTime(d_sigexpire); + conv.xfrTime(d_siginception); + conv.xfr16BitInt(d_tag); + conv.xfrLabel(d_signer); + conv.xfrBlob(d_signature); + ) + +RRSIGRecordContent::RRSIGRecordContent() : DNSRecordContent(46) {} + +boilerplate_conv(DNSKEY, 48, + conv.xfr16BitInt(d_flags); + conv.xfr8BitInt(d_protocol); + conv.xfr8BitInt(d_algorithm); + conv.xfrBlob(d_key); + ) +DNSKEYRecordContent::DNSKEYRecordContent() : DNSRecordContent(48) {} + +uint16_t DNSKEYRecordContent::getTag() +{ + string data=this->serialize(""); + const unsigned char* key=(const unsigned char*)data.c_str(); + unsigned int keysize=data.length(); + + unsigned long ac; /* assumed to be 32 bits or larger */ + unsigned int i; /* loop index */ + + for ( ac = 0, i = 0; i < keysize; ++i ) + ac += (i & 1) ? key[i] : key[i] << 8; + ac += (ac >> 16) & 0xFFFF; + return ac & 0xFFFF; +} + +// "fancy records" +boilerplate_conv(URL, QType::URL, + conv.xfrLabel(d_url); + ) + +boilerplate_conv(MBOXFW, QType::MBOXFW, + conv.xfrLabel(d_mboxfw); + ) + + + +bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo) +{ + if(mdp.d_header.arcount && !mdp.d_answers.empty()) { + BOOST_FOREACH(const MOADNSParser::answers_t::value_type& val, mdp.d_answers) { + if(val.first.d_place == DNSRecord::Additional && val.first.d_type == QType::OPT) { + eo->d_packetsize=val.first.d_class; + + EDNS0Record stuff; + uint32_t ttl=ntohl(val.first.d_ttl); + memcpy(&stuff, &ttl, sizeof(stuff)); + + eo->d_extRCode=stuff.extRCode; + eo->d_version=stuff.version; + eo->d_Z = ntohs(stuff.Z); + OPTRecordContent* orc = + dynamic_cast(val.first.d_content.get()); + if(!orc) + return false; + orc->getData(eo->d_options); + return true; + } + } + } + return false; +} + + +void reportBasicTypes() +{ + ARecordContent::report(); + AAAARecordContent::report(); + NSRecordContent::report(); + CNAMERecordContent::report(); + MXRecordContent::report(); + SOARecordContent::report(); + SRVRecordContent::report(); + PTRRecordContent::report(); + DNSRecordContent::regist(3, ns_t_txt, &TXTRecordContent::make, &TXTRecordContent::make, "TXT"); + TXTRecordContent::report(); + DNSRecordContent::regist(1, QType::ANY, 0, 0, "ANY"); +} + +void reportOtherTypes() +{ + AFSDBRecordContent::report(); + SPFRecordContent::report(); + NAPTRRecordContent::report(); + LOCRecordContent::report(); + HINFORecordContent::report(); + RPRecordContent::report(); + KEYRecordContent::report(); + DNSKEYRecordContent::report(); + RRSIGRecordContent::report(); + DSRecordContent::report(); + SSHFPRecordContent::report(); + CERTRecordContent::report(); + NSECRecordContent::report(); + NSEC3RecordContent::report(); + NSEC3PARAMRecordContent::report(); + TLSARecordContent::report(); + DLVRecordContent::report(); + DNSRecordContent::regist(0xff, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG"); + OPTRecordContent::report(); +} + +void reportFancyTypes() +{ + URLRecordContent::report(); + MBOXFWRecordContent::report(); +} + +void reportAllTypes() +{ + reportBasicTypes(); + reportOtherTypes(); +} + +#if 0 +static struct Reporter +{ + Reporter() + { + reportAllTypes(); + } +} reporter __attribute__((init_priority(65535))); +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dnsrecords.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dnsrecords.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dnsrecords.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dnsrecords.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,552 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2005 - 2010 PowerDNS.COM 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 +*/ + +#ifndef PDNS_DNSRECORDS_HH +#define PDNS_DNSRECORDS_HH + +#include "dnsparser.hh" +#include "dnswriter.hh" +#include "rcpgenerator.hh" +#include +#include +#include + +#include "namespaces.hh" +#include "namespaces.hh" + +#define includeboilerplate(RNAME) RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr); \ + RNAME##RecordContent(const string& zoneData); \ + static void report(void); \ + static void unreport(void); \ + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); \ + static DNSRecordContent* make(const string& zonedata); \ + string getZoneRepresentation() const; \ + void toPacket(DNSPacketWriter& pw); \ + template void xfrPacket(Convertor& conv); + +class NAPTRRecordContent : public DNSRecordContent +{ +public: + NAPTRRecordContent(uint16_t order, uint16_t preference, string flags, string services, string regexp, string replacement); + + includeboilerplate(NAPTR); + template void xfrRecordContent(Convertor& conv); +private: + uint16_t d_order, d_preference; + string d_flags, d_services, d_regexp, d_replacement; +}; + + +class ARecordContent : public DNSRecordContent +{ +public: + explicit ARecordContent(uint32_t ip); + includeboilerplate(A); + void doRecordCheck(const DNSRecord& dr); + uint32_t getIP() const; + +private: + uint32_t d_ip; +}; + +class MXRecordContent : public DNSRecordContent +{ +public: + MXRecordContent(uint16_t preference, const string& mxname); + + includeboilerplate(MX) + +private: + uint16_t d_preference; + string d_mxname; +}; + +class KXRecordContent : public DNSRecordContent +{ +public: + KXRecordContent(uint16_t preference, const string& exchanger); + + includeboilerplate(KX) + +private: + uint16_t d_preference; + string d_exchanger; +}; + +class IPSECKEYRecordContent : public DNSRecordContent +{ +public: + IPSECKEYRecordContent(uint16_t preference, uint8_t gatewaytype, uint8_t algo, const std::string& gateway, const std::string &publickey); + + includeboilerplate(IPSECKEY) + +private: + uint8_t d_preference, d_gatewaytype, d_algorithm; + string d_gateway, d_publickey; +}; + +class DHCIDRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(DHCID) + +private: + string d_content; +}; + + +class SRVRecordContent : public DNSRecordContent +{ +public: + SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, const string& target); + + includeboilerplate(SRV) + +private: + uint16_t d_preference, d_weight, d_port; + string d_target; +}; + +class TSIGRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(TSIG) + TSIGRecordContent() : DNSRecordContent(QType::TSIG) {} + + string d_algoName; + uint64_t d_time; // 48 bits + uint16_t d_fudge; + // uint16_t d_macSize; + string d_mac; + uint16_t d_origID; + uint16_t d_eRcode; + // uint16_t d_otherLen + string d_otherData; +}; + + +class TXTRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(TXT) + +private: + string d_text; +}; + +class SPFRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(SPF) + +private: + string d_text; +}; + + +class NSRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(NS) + +private: + string d_content; +}; + +class PTRRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(PTR) + +private: + string d_content; +}; + +class CNAMERecordContent : public DNSRecordContent +{ +public: + includeboilerplate(CNAME) + +private: + string d_content; +}; + +class MRRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(MR) + +private: + string d_alias; +}; + + +class OPTRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(OPT) + void getData(vector > &opts); +private: + string d_data; +}; + + +class HINFORecordContent : public DNSRecordContent +{ +public: + includeboilerplate(HINFO) + +private: + string d_cpu, d_host; +}; + +class RPRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(RP) + +private: + string d_mbox, d_info; +}; + + +class DNSKEYRecordContent : public DNSRecordContent +{ +public: + DNSKEYRecordContent(); + includeboilerplate(DNSKEY) + uint16_t getTag(); + + uint16_t d_flags; + uint8_t d_protocol; + uint8_t d_algorithm; + string d_key; +}; + +class DSRecordContent : public DNSRecordContent +{ +public: + DSRecordContent(); + includeboilerplate(DS) + + uint16_t d_tag; + uint8_t d_algorithm, d_digesttype; + string d_digest; +}; + +class DLVRecordContent : public DNSRecordContent +{ +public: + DLVRecordContent(); + includeboilerplate(DLV) + + uint16_t d_tag; + uint8_t d_algorithm, d_digesttype; + string d_digest; +}; + + +class SSHFPRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(SSHFP) + +private: + uint8_t d_algorithm, d_fptype; + string d_fingerprint; +}; + +class KEYRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(KEY) + +private: + uint16_t d_flags; + uint8_t d_protocol, d_algorithm; + string d_certificate; +}; + +class AFSDBRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(AFSDB) + +private: + uint16_t d_subtype; + string d_hostname; +}; + + +class CERTRecordContent : public DNSRecordContent +{ +public: + includeboilerplate(CERT) + +private: + uint16_t d_type, d_tag; + uint8_t d_algorithm; + string d_certificate; +}; + +class TLSARecordContent : public DNSRecordContent +{ +public: + includeboilerplate(TLSA) + +private: + uint8_t d_certusage, d_selector, d_matchtype; + string d_cert; +}; + + +class RRSIGRecordContent : public DNSRecordContent +{ +public: + RRSIGRecordContent(); + includeboilerplate(RRSIG) + + uint16_t d_type; + uint8_t d_algorithm, d_labels; + uint32_t d_originalttl, d_sigexpire, d_siginception; + uint16_t d_tag; + string d_signer, d_signature; +}; + + + +//namespace { + struct soatimes + { + uint32_t serial; + uint32_t refresh; + uint32_t retry; + uint32_t expire; + uint32_t minimum; + }; +//} + + +class SOARecordContent : public DNSRecordContent +{ +public: + includeboilerplate(SOA) + SOARecordContent(const string& mname, const string& rname, const struct soatimes& st); + + string d_mname; + string d_rname; + struct soatimes d_st; +}; + +class NSECRecordContent : public DNSRecordContent +{ +public: + static void report(void); + NSECRecordContent() : DNSRecordContent(47) + {} + NSECRecordContent(const string& content, const string& zone=""); + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& content); + string getZoneRepresentation() const; + void toPacket(DNSPacketWriter& pw); + string d_next; + std::set d_set; +private: +}; + +class NSEC3RecordContent : public DNSRecordContent +{ +public: + static void report(void); + NSEC3RecordContent() : DNSRecordContent(50) + {} + NSEC3RecordContent(const string& content, const string& zone=""); + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& content); + string getZoneRepresentation() const; + void toPacket(DNSPacketWriter& pw); + + uint8_t d_algorithm, d_flags; + uint16_t d_iterations; + uint8_t d_saltlength; + string d_salt; + uint8_t d_nexthashlength; + string d_nexthash; + std::set d_set; + +private: +}; + + +class NSEC3PARAMRecordContent : public DNSRecordContent +{ +public: + static void report(void); + NSEC3PARAMRecordContent() : DNSRecordContent(51) + {} + NSEC3PARAMRecordContent(const string& content, const string& zone=""); + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& content); + string getZoneRepresentation() const; + void toPacket(DNSPacketWriter& pw); + + + uint8_t d_algorithm, d_flags; + uint16_t d_iterations; + uint8_t d_saltlength; + string d_salt; +}; + + +class LOCRecordContent : public DNSRecordContent +{ +public: + static void report(void); + LOCRecordContent() : DNSRecordContent(ns_t_loc) + {} + LOCRecordContent(const string& content, const string& zone=""); + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& content); + string getZoneRepresentation() const; + void toPacket(DNSPacketWriter& pw); + + uint8_t d_version, d_size, d_horizpre, d_vertpre; + uint32_t d_latitude, d_longitude, d_altitude; + +private: +}; + + +class WKSRecordContent : public DNSRecordContent +{ +public: + static void report(void); + WKSRecordContent() : DNSRecordContent(ns_t_wks) + {} + WKSRecordContent(const string& content, const string& zone=""); + + static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); + static DNSRecordContent* make(const string& content); + string getZoneRepresentation() const; + void toPacket(DNSPacketWriter& pw); + + uint32_t d_ip; + std::bitset<65535> d_services; +private: +}; + + +class URLRecordContent : public DNSRecordContent // Fake, 'fancy record' with type 256 +{ +public: + includeboilerplate(URL) +private: + string d_url; +}; + +class MBOXFWRecordContent : public DNSRecordContent // Fake, 'fancy record' with type 256 +{ +public: + includeboilerplate(MBOXFW) +private: + string d_mboxfw; +}; + + +#define boilerplate(RNAME, RTYPE) \ +RNAME##RecordContent::DNSRecordContent* RNAME##RecordContent::make(const DNSRecord& dr, PacketReader& pr) \ +{ \ + return new RNAME##RecordContent(dr, pr); \ +} \ + \ +RNAME##RecordContent::RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr) : DNSRecordContent(RTYPE) \ +{ \ + doRecordCheck(dr); \ + xfrPacket(pr); \ +} \ + \ +RNAME##RecordContent::DNSRecordContent* RNAME##RecordContent::make(const string& zonedata) \ +{ \ + return new RNAME##RecordContent(zonedata); \ +} \ + \ +void RNAME##RecordContent::toPacket(DNSPacketWriter& pw) \ +{ \ + this->xfrPacket(pw); \ +} \ + \ +void RNAME##RecordContent::report(void) \ +{ \ + regist(1, RTYPE, &RNAME##RecordContent::make, &RNAME##RecordContent::make, #RNAME); \ +} \ +void RNAME##RecordContent::unreport(void) \ +{ \ + unregist(1, RTYPE); \ +} \ + \ +RNAME##RecordContent::RNAME##RecordContent(const string& zoneData) : DNSRecordContent(RTYPE) \ +{ \ + try { \ + RecordTextReader rtr(zoneData); \ + xfrPacket(rtr); \ + } \ + catch(RecordTextException& rtr) { \ + throw MOADNSException("Parsing record content: "+string(rtr.what())); \ + } \ +} \ + \ +string RNAME##RecordContent::getZoneRepresentation() const \ +{ \ + string ret; \ + RecordTextWriter rtw(ret); \ + const_cast(this)->xfrPacket(rtw); \ + return ret; \ +} + + +#define boilerplate_conv(RNAME, TYPE, CONV) \ +boilerplate(RNAME, TYPE) \ +template \ +void RNAME##RecordContent::xfrPacket(Convertor& conv) \ +{ \ + CONV; \ +} \ + +struct EDNSOpts +{ + uint16_t d_packetsize; + uint8_t d_extRCode, d_version; + uint16_t d_Z; + vector > d_options; + enum zFlags { DNSSECOK=32768 }; +}; +//! Convenience function that fills out EDNS0 options, and returns true if there are any + +class MOADNSParser; +bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo); + +void reportBasicTypes(); +void reportOtherTypes(); +void reportAllTypes(); +void reportFancyTypes(); + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dnswriter.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dnswriter.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dnswriter.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dnswriter.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,333 @@ +#include "dnswriter.hh" +#include "misc.hh" +#include "dnsparser.hh" +#include +#include + +DNSPacketWriter::DNSPacketWriter(vector& content, const string& qname, uint16_t qtype, uint16_t qclass, uint8_t opcode) + : d_pos(0), d_content(content), d_qname(qname), d_qtype(qtype), d_qclass(qclass), d_canonic(false), d_lowerCase(false) +{ + d_content.clear(); + dnsheader dnsheader; + + memset(&dnsheader, 0, sizeof(dnsheader)); + dnsheader.id=0; + dnsheader.qdcount=htons(1); + dnsheader.opcode=opcode; + + const uint8_t* ptr=(const uint8_t*)&dnsheader; + uint32_t len=d_content.size(); + d_content.resize(len + sizeof(dnsheader)); + uint8_t* dptr=(&*d_content.begin()) + len; + + memcpy(dptr, ptr, sizeof(dnsheader)); + d_stuff=0; + + xfrLabel(qname, false); + + len=d_content.size(); + d_content.resize(len + d_record.size() + 4); + + ptr=&*d_record.begin(); + dptr=(&*d_content.begin()) + len; + + memcpy(dptr, ptr, d_record.size()); + + len+=d_record.size(); + d_record.clear(); + + qtype=htons(qtype); + qclass=htons(qclass); + + vector::iterator i=d_content.begin()+len; // this works around a gcc 3.4 bug + memcpy(&*i, &qtype, 2); + i+=2; + memcpy(&*i, &qclass, 2); + + d_stuff=0xffff; + d_labelmap.reserve(16); +} + +dnsheader* DNSPacketWriter::getHeader() +{ + return (dnsheader*)&*d_content.begin(); +} + +void DNSPacketWriter::startRecord(const string& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, Place place) +{ + if(!d_record.empty()) + commit(); + + d_recordqname=name; + d_recordqtype=qtype; + d_recordqclass=qclass; + d_recordttl=ttl; + d_recordplace=place; + + d_stuff = 0; + d_rollbackmarker=d_content.size(); + + if(pdns_iequals(d_qname, d_recordqname)) { // don't do the whole label compression thing if we *know* we can get away with "see question" + static char marker[2]={0xc0, 0x0c}; + d_content.insert(d_content.end(), &marker[0], &marker[2]); + } + else { + xfrLabel(d_recordqname, true); + d_content.insert(d_content.end(), d_record.begin(), d_record.end()); + d_record.clear(); + } + + d_stuff = sizeof(dnsrecordheader); // this is needed to get compressed label offsets right, the dnsrecordheader will be interspersed + d_sor=d_content.size() + d_stuff; // start of real record +} + +void DNSPacketWriter::addOpt(int udpsize, int extRCode, int Z, const vector >& options) +{ + uint32_t ttl=0; + + EDNS0Record stuff; + + stuff.extRCode=extRCode; + stuff.version=0; + stuff.Z=htons(Z); + + memcpy(&ttl, &stuff, sizeof(stuff)); + + ttl=ntohl(ttl); // will be reversed later on + + startRecord("", ns_t_opt, ttl, udpsize, ADDITIONAL); + for(optvect_t::const_iterator iter = options.begin(); iter != options.end(); ++iter) { + xfr16BitInt(iter->first); + xfr16BitInt(iter->second.length()); + xfrBlob(iter->second); + } +} + +void DNSPacketWriter::xfr48BitInt(uint64_t val) +{ + unsigned char bytes[6]; + uint16_t theLeft = htons((val >> 32)&0xffffU); + uint32_t theRight = htonl(val & 0xffffffffU); + memcpy(bytes, (void*)&theLeft, 2); + memcpy(bytes+2, (void*)&theRight, 4); + + d_record.insert(d_record.end(), bytes, bytes + 6); +} + + +void DNSPacketWriter::xfr32BitInt(uint32_t val) +{ + int rval=htonl(val); + uint8_t* ptr=reinterpret_cast(&rval); + d_record.insert(d_record.end(), ptr, ptr+4); +} + +void DNSPacketWriter::xfr16BitInt(uint16_t val) +{ + uint16_t rval=htons(val); + uint8_t* ptr=reinterpret_cast(&rval); + d_record.insert(d_record.end(), ptr, ptr+2); +} + +void DNSPacketWriter::xfr8BitInt(uint8_t val) +{ + d_record.push_back(val); +} + + +/* input: + "" -> 0 + "blah" -> 4blah + "blah" "blah" -> output 4blah4blah + "verylongstringlongerthan256....characters" \xffverylongstring\x23characters (autosplit) + "blah\"blah" -> 9blah"blah + "blah\97" -> 5blahb + */ +void DNSPacketWriter::xfrText(const string& text, bool) +{ + if(text.empty()) { + d_record.push_back(0); + return; + } + vector segments = segmentDNSText(text); + BOOST_FOREACH(const string& str, segments) { + d_record.push_back(str.length()); + d_record.insert(d_record.end(), str.c_str(), str.c_str() + str.length()); + } +} + +DNSPacketWriter::lmap_t::iterator find(DNSPacketWriter::lmap_t& lmap, const string& label) +{ + DNSPacketWriter::lmap_t::iterator ret; + for(ret=lmap.begin(); ret != lmap.end(); ++ret) + if(pdns_iequals(ret->first ,label)) + break; + return ret; +} + +//! tokenize a label into parts, the parts describe a begin offset and an end offset +bool labeltokUnescape(labelparts_t& parts, const string& label) +{ + string::size_type epos = label.size(), lpos(0), pos; + bool unescapedSomething = false; + const char* ptr=label.c_str(); + + parts.clear(); + + for(pos = 0 ; pos < epos; ++pos) { + if(ptr[pos]=='\\') { + pos++; + unescapedSomething = true; + continue; + } + if(ptr[pos]=='.') { + parts.push_back(make_pair(lpos, pos)); + lpos=pos+1; + } + } + + if(lpos < pos) + parts.push_back(make_pair(lpos, pos)); + return unescapedSomething; +} + +// this is the absolute hottest function in the pdns recursor +void DNSPacketWriter::xfrLabel(const string& Label, bool compress) +{ + string label = d_lowerCase ? toLower(Label) : Label; + labelparts_t parts; + + if(d_canonic) + compress=false; + + string::size_type labellen = label.size(); + if(labellen==1 && label[0]=='.') { // otherwise we encode '..' + d_record.push_back(0); + return; + } + bool unescaped=labeltokUnescape(parts, label); + + // d_stuff is amount of stuff that is yet to be written out - the dnsrecordheader for example + unsigned int pos=d_content.size() + d_record.size() + d_stuff; + string chopped; + bool deDot = labellen && (label[labellen-1]=='.'); // make sure we don't store trailing dots in the labelmap + + for(labelparts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) { + if(deDot) + chopped.assign(label.c_str() + i->first, labellen - i->first -1); + else + chopped.assign(label.c_str() + i->first); + + lmap_t::iterator li=d_labelmap.end(); + // see if we've written out this domain before + // cerr<<"Searching for compression pointer to '"<second<second; + offset|=0xc000; + d_record.push_back((char)(offset >> 8)); + d_record.push_back((char)(offset & 0xff)); + goto out; // skip trailing 0 in case of compression + } + + if(li==d_labelmap.end() && pos< 16384) { + // cerr<<"\tStoring a compression pointer to '"< 16384, won't work + } + + if(unescaped) { + string part(label.c_str() + i -> first, i->second - i->first); + boost::replace_all(part, "\\.", "."); + boost::replace_all(part, "\\032", " "); + boost::replace_all(part, "\\\\", "\\"); + if(part.size() > 255) + throw MOADNSException("DNSPacketWriter::xfrLabel() tried to write an overly large label"); + d_record.push_back(part.size()); + unsigned int len=d_record.size(); + d_record.resize(len + part.size()); + + memcpy(((&*d_record.begin()) + len), part.c_str(), part.size()); + pos+=(part.size())+1; + } + else { + d_record.push_back((char)(i->second - i->first)); + unsigned int len=d_record.size(); + d_record.resize(len + i->second - i->first); + memcpy(((&*d_record.begin()) + len), label.c_str() + i-> first, i->second - i->first); + pos+=(i->second - i->first)+1; + } + } + d_record.push_back(0); + + out:; +} + +void DNSPacketWriter::xfrBlob(const string& blob, int ) +{ + const uint8_t* ptr=reinterpret_cast(blob.c_str()); + d_record.insert(d_record.end(), ptr, ptr+blob.size()); +} + +void DNSPacketWriter::xfrHexBlob(const string& blob, bool keepReading) +{ + xfrBlob(blob); +} + +void DNSPacketWriter::getRecords(string& records) +{ + records.assign(d_content.begin() + d_sor, d_content.end()); +} + +uint32_t DNSPacketWriter::size() +{ + return d_content.size() + d_stuff + d_record.size(); +} + +void DNSPacketWriter::rollback() +{ + d_content.resize(d_rollbackmarker); + d_record.clear(); + d_stuff=0; +} + +void DNSPacketWriter::commit() +{ + if(d_stuff==0xffff && (d_content.size()!=d_sor || !d_record.empty())) + throw MOADNSException("DNSPacketWriter::commit() called without startRecord ever having been called, but a record was added"); + // build dnsrecordheader + struct dnsrecordheader drh; + drh.d_type=htons(d_recordqtype); + drh.d_class=htons(d_recordqclass); + drh.d_ttl=htonl(d_recordttl); + drh.d_clen=htons(d_record.size()); + + // and write out the header + const uint8_t* ptr=(const uint8_t*)&drh; + d_content.insert(d_content.end(), ptr, ptr+sizeof(drh)); + + d_stuff=0; + + // write out pending d_record + d_content.insert(d_content.end(), d_record.begin(), d_record.end()); + + dnsheader* dh=reinterpret_cast( &*d_content.begin()); + switch(d_recordplace) { + case ANSWER: + dh->ancount = htons(ntohs(dh->ancount) + 1); + break; + case AUTHORITY: + dh->nscount = htons(ntohs(dh->nscount) + 1); + break; + case ADDITIONAL: + dh->arcount = htons(ntohs(dh->arcount) + 1); + break; + } + + d_record.clear(); // clear d_record, ready for next record +} + + + + + + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dnswriter.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dnswriter.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/dnswriter.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/dnswriter.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,131 @@ +#ifndef PDNS_DNSWRITER_HH +#define PDNS_DNSWRITER_HH + +#include +#include +#include +#if !defined SOLARIS8 && !defined WIN32 + +#elif defined WIN32 +#include "utility.hh" +#endif +#include "dns.hh" +#include "namespaces.hh" + +/** this class can be used to write DNS packets. It knows about DNS in the sense that it makes + the packet header and record headers. + + The model is: + + packetheader (recordheader recordcontent)* + + The packetheader needs to be updated with the amount of packets of each kind (answer, auth, additional) + + Each recordheader contains the length of a dns record. + + Calling convention: + + vector content; + DNSPacketWriter dpw(content, const string& qname, uint16_t qtype, uint16_t qclass=1); // sets the question + dpw.startrecord("this.is.an.ip.address.", ns_t_a); // does nothing, except store qname and qtype + dpw.xfr32BitInt(0x01020304); // adds 4 bytes (0x01020304) to the record buffer + dpw.startrecord("this.is.an.ip.address.", ns_t_a); // aha! writes out dnsrecord header containing qname and qtype and length 4, plus the recordbuffer, which gets emptied + // new qname and qtype are stored + dpw.xfr32BitInt(0x04030201); // adds 4 bytes (0x04030201) to the record buffer + dpw.commit(); // writes out dnsrecord header containing qname and qtype and length 4, plus the recordbuffer + + // content now contains the ready packet, with 1 question and 2 answers + +*/ + +class DNSPacketWriter : public boost::noncopyable +{ + +public: + typedef vector > lmap_t; + enum Place {ANSWER=1, AUTHORITY=2, ADDITIONAL=3}; + + //! Start a DNS Packet in the vector passed, with question qname, qtype and qclass + DNSPacketWriter(vector& content, const string& qname, uint16_t qtype, uint16_t qclass=1, uint8_t opcode=0); + + /** Start a new DNS record within this packet for namq, qtype, ttl, class and in the requested place. Note that packets can only be written in natural order - + ANSWER, AUTHORITY, ADDITIONAL */ + void startRecord(const string& name, uint16_t qtype, uint32_t ttl=3600, uint16_t qclass=1, Place place=ANSWER); + + /** Shorthand way to add an Opt-record, for example for EDNS0 purposes */ + typedef vector > optvect_t; + void addOpt(int udpsize, int extRCode, int Z, const optvect_t& options=optvect_t()); + + /** needs to be called after the last record is added, but can be called again and again later on. Is called internally by startRecord too. + The content of the vector<> passed to the constructor is inconsistent until commit is called. + */ + void commit(); + + uint32_t size(); // needs to be 32 bit because otherwise we don't see the wrap coming when it happened! + + /** Should the packet have grown too big for the writer's liking, rollback removes the record currently being written */ + void rollback(); + + void xfr48BitInt(uint64_t val); + void xfr32BitInt(uint32_t val); + void xfr16BitInt(uint16_t val); + void xfrType(uint16_t val) + { + xfr16BitInt(val); + } + void xfrIP(const uint32_t& val) + { + xfr32BitInt(htonl(val)); + } + void xfrTime(const uint32_t& val) + { + xfr32BitInt(val); + } + + void xfr8BitInt(uint8_t val); + + void xfrLabel(const string& label, bool compress=false); + void xfrText(const string& text, bool multi=false); + void xfrBlob(const string& blob, int len=-1); + void xfrHexBlob(const string& blob, bool keepReading=false); + + uint16_t d_pos; + + dnsheader* getHeader(); + void getRecords(string& records); + const vector& getRecordBeingWritten() { return d_record; } + + void setCanonic(bool val) + { + d_canonic=val; + } + + void setLowercase(bool val) + { + d_lowerCase=val; + } + vector & getContent() + { + return d_content; + } + +private: + vector & d_content; + vector d_record; + string d_qname; + uint16_t d_qtype, d_qclass; + string d_recordqname; + uint16_t d_recordqtype, d_recordqclass; + uint32_t d_recordttl; + lmap_t d_labelmap; + uint16_t d_stuff; + uint16_t d_sor; + uint16_t d_rollbackmarker; // start of last complete packet, for rollback + Place d_recordplace; + bool d_canonic, d_lowerCase; +}; + +typedef vector > labelparts_t; +bool labeltokUnescape(labelparts_t& parts, const string& label); +std::vector segmentDNSText(const string& text); // from dnslabeltext.rl +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/epollmplexer.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/epollmplexer.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/epollmplexer.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/epollmplexer.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,169 @@ +#include "mplexer.hh" +#include "sstuff.hh" +#include +#include +#include "misc.hh" +#include +#include "syncres.hh" +#ifdef __linux__ +#include +#endif + +#include "namespaces.hh" +#include "namespaces.hh" + +class EpollFDMultiplexer : public FDMultiplexer +{ +public: + EpollFDMultiplexer(); + virtual ~EpollFDMultiplexer() + { + close(d_epollfd); + } + + virtual int run(struct timeval* tv); + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter); + virtual void removeFD(callbackmap_t& cbmap, int fd); + string getName() + { + return "epoll"; + } +private: + int d_epollfd; + boost::shared_array d_eevents; + static int s_maxevents; // not a hard maximum +}; + + +static FDMultiplexer* makeEpoll() +{ + return new EpollFDMultiplexer(); +} + +static struct EpollRegisterOurselves +{ + EpollRegisterOurselves() { + FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makeEpoll)); // priority 0! + } +} doItEpoll; + + +int EpollFDMultiplexer::s_maxevents=1024; +EpollFDMultiplexer::EpollFDMultiplexer() : d_eevents(new epoll_event[s_maxevents]) +{ + d_epollfd=epoll_create(s_maxevents); // not hard max + if(d_epollfd < 0) + throw FDMultiplexerException("Setting up epoll: "+stringerror()); + int fd=socket(AF_INET, SOCK_DGRAM, 0); // for self-test + if(fd < 0) + return; + try { + addReadFD(fd, 0); + removeReadFD(fd); + close(fd); + return; + } + catch(FDMultiplexerException &fe) { + close(fd); + close(d_epollfd); + throw FDMultiplexerException("epoll multiplexer failed self-test: "+string(fe.what())); + } + +} + +void EpollFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter) +{ + accountingAddFD(cbmap, fd, toDo, parameter); + + struct epoll_event eevent; + + eevent.events = (&cbmap == &d_readCallbacks) ? EPOLLIN : EPOLLOUT; + + eevent.data.u64=0; // placate valgrind (I love it so much) + eevent.data.fd=fd; + + if(epoll_ctl(d_epollfd, EPOLL_CTL_ADD, fd, &eevent) < 0) { + cbmap.erase(fd); + throw FDMultiplexerException("Adding fd to epoll set: "+stringerror()); + } +} + +void EpollFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) +{ + if(!cbmap.erase(fd)) + throw FDMultiplexerException("Tried to remove unlisted fd "+lexical_cast(fd)+ " from multiplexer"); + + struct epoll_event dummy; + dummy.events = 0; + dummy.data.u64 = 0; + + if(epoll_ctl(d_epollfd, EPOLL_CTL_DEL, fd, &dummy) < 0) + throw FDMultiplexerException("Removing fd from epoll set: "+stringerror()); +} + +int EpollFDMultiplexer::run(struct timeval* now) +{ + if(d_inrun) { + throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); + } + + int ret=epoll_wait(d_epollfd, d_eevents.get(), s_maxevents, 500); + gettimeofday(now,0); // MANDATORY + + if(ret < 0 && errno!=EINTR) + throw FDMultiplexerException("epoll returned error: "+stringerror()); + + if(ret < 1) // thanks AB! + return 0; + + d_inrun=true; + for(int n=0; n < ret; ++n) { + d_iter=d_readCallbacks.find(d_eevents[n].data.fd); + + if(d_iter != d_readCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + continue; // so we don't refind ourselves as writable! + } + d_iter=d_writeCallbacks.find(d_eevents[n].data.fd); + + if(d_iter != d_writeCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + } + } + d_inrun=false; + return 0; +} + +#if 0 +void acceptData(int fd, funcparam_t& parameter) +{ + cout<<"Have data on fd "<(parameter); + string packet; + IPEndpoint rem; + sock->recvFrom(packet, rem); + cout<<"Received "< + +#ifndef WIN32 +#include +#include +#include +#endif // WIN32 + +#include +#include +#include +#include "ahuexception.hh" +#include "misc.hh" +#include +#include + +#include +#include +#include + +#include "namespaces.hh" + +union ComboAddress { + struct sockaddr_in sin4; + struct sockaddr_in6 sin6; + + bool operator==(const ComboAddress& rhs) const + { + if(boost::tie(sin4.sin_family, sin4.sin_port) != boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) + return false; + if(sin4.sin_family == AF_INET) + return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr; + else + return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16)==0; + } + + bool operator<(const ComboAddress& rhs) const + { + if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) + return true; + if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) + return false; + + if(sin4.sin_family == AF_INET) + return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr; + else + return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16) < 0; + } + + bool operator>(const ComboAddress& rhs) const + { + if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) + return true; + if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port)) + return false; + + if(sin4.sin_family == AF_INET) + return sin4.sin_addr.s_addr > rhs.sin4.sin_addr.s_addr; + else + return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, 16) > 0; + } + + struct addressOnlyLessThan: public std::binary_function + { + bool operator()(const ComboAddress& a, const ComboAddress& b) const + { + if(a.sin4.sin_family < b.sin4.sin_family) + return true; + if(a.sin4.sin_family > b.sin4.sin_family) + return false; + if(a.sin4.sin_family == AF_INET) + return a.sin4.sin_addr.s_addr < b.sin4.sin_addr.s_addr; + else + return memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, 16) < 0; + } + }; + + socklen_t getSocklen() const + { + if(sin4.sin_family == AF_INET) + return sizeof(sin4); + else + return sizeof(sin6); + } + + ComboAddress() + { + sin4.sin_family=AF_INET; + sin4.sin_addr.s_addr=0; + sin4.sin_port=0; + } + + // 'port' sets a default value in case 'str' does not set a port + explicit ComboAddress(const string& str, uint16_t port=0) + { + memset(&sin6, 0, sizeof(sin6)); + sin4.sin_family = AF_INET; + sin4.sin_port = 0; + if(makeIPv4sockaddr(str, &sin4)) { + sin6.sin6_family = AF_INET6; + if(makeIPv6sockaddr(str, &sin6) < 0) + throw AhuException("Unable to convert presentation address '"+ str +"'"); + + } + if(!sin4.sin_port) // 'str' overrides port! + sin4.sin_port=htons(port); + } + + bool isMappedIPv4() const + { + if(sin4.sin_family!=AF_INET6) + return false; + + int n=0; + const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr; + for(n=0; n < 10; ++n) + if(ptr[n]) + return false; + + for(; n < 12; ++n) + if(ptr[n]!=0xff) + return false; + + return true; + } + + ComboAddress mapToIPv4() const + { + if(!isMappedIPv4()) + throw AhuException("ComboAddress can't map non-mapped IPv6 address back to IPv4"); + ComboAddress ret; + ret.sin4.sin_family=AF_INET; + ret.sin4.sin_port=sin4.sin_port; + + const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr; + ptr+=12; + memcpy(&ret.sin4.sin_addr.s_addr, ptr, 4); + return ret; + } + + string toString() const + { + char host[1024]; + getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST); + + return host; + } + + string toStringWithPort() const + { + if(sin4.sin_family==AF_INET) + return toString() + ":" + boost::lexical_cast(ntohs(sin4.sin_port)); + else + return "["+toString() + "]:" + boost::lexical_cast(ntohs(sin4.sin_port)); + } +}; + +/** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */ +class NetmaskException: public AhuException +{ +public: + NetmaskException(const string &a) : AhuException(a) {} +}; + +inline ComboAddress makeComboAddress(const string& str) +{ + ComboAddress address; + address.sin4.sin_family=AF_INET; + if(Utility::inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) { + address.sin4.sin_family=AF_INET6; + if(makeIPv6sockaddr(str, &address.sin6) < 0) + throw NetmaskException("Unable to convert '"+str+"' to a netmask"); + } + return address; +} + +/** This class represents a netmask and can be queried to see if a certain + IP address is matched by this mask */ +class Netmask +{ +public: + Netmask() + { + d_network.sin4.sin_family=0; // disable this doing anything useful + } + + Netmask(const ComboAddress& network, uint8_t bits=0xff) + { + d_network = network; + + if(bits == 0xff) + bits = (network.sin4.sin_family == AF_INET) ? 32 : 128; + + d_bits = bits; + if(d_bits<32) + d_mask=~(0xFFFFFFFF>>d_bits); + else + d_mask=0xFFFFFFFF; // not actually used for IPv6 + } + + //! Constructor supplies the mask, which cannot be changed + Netmask(const string &mask) + { + pair split=splitField(mask,'/'); + d_network=makeComboAddress(split.first); + + if(!split.second.empty()) { + d_bits = lexical_cast(split.second); + if(d_bits<32) + d_mask=~(0xFFFFFFFF>>d_bits); + else + d_mask=0xFFFFFFFF; + } + else if(d_network.sin4.sin_family==AF_INET) { + d_bits = 32; + d_mask = 0xFFFFFFFF; + } + else { + d_bits=128; + d_mask=0; // silence silly warning - d_mask is unused for IPv6 + } + } + + bool match(const ComboAddress& ip) const + { + return match(&ip); + } + + //! If this IP address in socket address matches + bool match(const ComboAddress *ip) const + { + if(d_network.sin4.sin_family != ip->sin4.sin_family) { + return false; + } + if(d_network.sin4.sin_family == AF_INET) { + return match4(htonl((unsigned int)ip->sin4.sin_addr.s_addr)); + } + if(d_network.sin6.sin6_family == AF_INET6) { + uint8_t bytes=d_bits/8, n; + const uint8_t *us=(const uint8_t*) &d_network.sin6.sin6_addr.s6_addr; + const uint8_t *them=(const uint8_t*) &ip->sin6.sin6_addr.s6_addr; + + for(n=0; n < bytes; ++n) { + if(us[n]!=them[n]) { + return false; + } + } + // still here, now match remaining bits + uint8_t bits= d_bits % 8; + uint8_t mask= ~(0xFF>>bits); + + return((us[n] & mask) == (them[n] & mask)); + } + return false; + } + + //! If this ASCII IP address matches + bool match(const string &ip) const + { + ComboAddress address=makeComboAddress(ip); + return match(&address); + } + + //! If this IP address in native format matches + bool match4(uint32_t ip) const + { + return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr) & d_mask); + } + + string toString() const + { + return d_network.toString()+"/"+boost::lexical_cast((unsigned int)d_bits); + } + + string toStringNoMask() const + { + return d_network.toString(); + } + const ComboAddress& getNetwork() const + { + return d_network; + } + int getBits() const + { + return d_bits; + } +private: + ComboAddress d_network; + uint32_t d_mask; + uint8_t d_bits; +}; + +/** This class represents a group of supplemental Netmask classes. An IP address matchs + if it is matched by zero or more of the Netmask classes within. +*/ +class NetmaskGroup +{ +public: + //! If this IP address is matched by any of the classes within + bool match(const ComboAddress *ip) + { + for(container_t::const_iterator i=d_masks.begin();i!=d_masks.end();++i) + if(i->match(ip) || (ip->isMappedIPv4() && i->match(ip->mapToIPv4()) )) + return true; + + return false; + } + //! Add this Netmask to the list of possible matches + void addMask(const string &ip) + { + d_masks.push_back(Netmask(ip)); + } + + bool empty() + { + return d_masks.empty(); + } + + unsigned int size() + { + return (unsigned int)d_masks.size(); + } + + string toString() const + { + ostringstream str; + for(container_t::const_iterator iter = d_masks.begin(); iter != d_masks.end(); ++iter) { + if(iter != d_masks.begin()) + str <<", "; + str<toString(); + } + return str.str(); + } + + +private: + typedef vector container_t; + container_t d_masks; + +}; + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/kqueuemplexer.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/kqueuemplexer.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/kqueuemplexer.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/kqueuemplexer.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,155 @@ +#include "mplexer.hh" +#include "sstuff.hh" +#include +#include +#include "misc.hh" +#include +#include "syncres.hh" +#include +#ifdef __FreeBSD__ +#include +#endif +#include + +#include "namespaces.hh" +#include "namespaces.hh" + +class KqueueFDMultiplexer : public FDMultiplexer +{ +public: + KqueueFDMultiplexer(); + virtual ~KqueueFDMultiplexer() + { + close(d_kqueuefd); + } + + virtual int run(struct timeval* tv); + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter); + virtual void removeFD(callbackmap_t& cbmap, int fd); + string getName() + { + return "kqueue"; + } +private: + int d_kqueuefd; + boost::shared_array d_kevents; + static unsigned int s_maxevents; // not a hard maximum +}; + +unsigned int KqueueFDMultiplexer::s_maxevents=1024; + +static FDMultiplexer* make() +{ + return new KqueueFDMultiplexer(); +} + +static struct KqueueRegisterOurselves +{ + KqueueRegisterOurselves() { + FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &make)); // priority 0! + } +} kQueuedoIt; + +KqueueFDMultiplexer::KqueueFDMultiplexer() : d_kevents(new struct kevent[s_maxevents]) +{ + d_kqueuefd=kqueue(); + if(d_kqueuefd < 0) + throw FDMultiplexerException("Setting up kqueue: "+stringerror()); +} + +void KqueueFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter) +{ + accountingAddFD(cbmap, fd, toDo, parameter); + + struct kevent kqevent; + EV_SET(&kqevent, fd, (&cbmap == &d_readCallbacks) ? EVFILT_READ : EVFILT_WRITE, EV_ADD, 0,0,0); + + if(kevent(d_kqueuefd, &kqevent, 1, 0, 0, 0) < 0) { + cbmap.erase(fd); + throw FDMultiplexerException("Adding fd to kqueue set: "+stringerror()); + } +} + +void KqueueFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) +{ + accountingRemoveFD(cbmap, fd); + + struct kevent kqevent; + EV_SET(&kqevent, fd, (&cbmap == &d_readCallbacks) ? EVFILT_READ : EVFILT_WRITE, EV_DELETE, 0,0,0); + + if(kevent(d_kqueuefd, &kqevent, 1, 0, 0, 0) < 0) // ponder putting Callback back on the map.. + throw FDMultiplexerException("Removing fd from kqueue set: "+stringerror()); +} + +int KqueueFDMultiplexer::run(struct timeval* now) +{ + if(d_inrun) { + throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); + } + + struct timespec ts; + ts.tv_sec=0; + ts.tv_nsec=500000000U; + + int ret=kevent(d_kqueuefd, 0, 0, d_kevents.get(), s_maxevents, &ts); + gettimeofday(now,0); // MANDATORY! + + if(ret < 0 && errno!=EINTR) + throw FDMultiplexerException("kqueue returned error: "+stringerror()); + + if(ret < 0) // nothing - thanks AB! + return 0; + + d_inrun=true; + + for(int n=0; n < ret; ++n) { + d_iter=d_readCallbacks.find(d_kevents[n].ident); + if(d_iter != d_readCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + continue; // so we don't find ourselves as writable again + } + + d_iter=d_writeCallbacks.find(d_kevents[n].ident); + + if(d_iter != d_writeCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + } + } + + d_inrun=false; + return 0; +} + +#if 0 +void acceptData(int fd, boost::any& parameter) +{ + cout<<"Have data on fd "<(parameter); + string packet; + IPEndpoint rem; + sock->recvFrom(packet, rem); + cout<<"Received "< +#include +#include "misc.hh" +#include "ahuexception.hh" + +extern bool g_singleThreaded; + +class Lock +{ + pthread_mutex_t *d_lock; +public: + + Lock(pthread_mutex_t *lock) : d_lock(lock) + { + if(g_singleThreaded) + return; + if((errno=pthread_mutex_lock(d_lock))) + throw AhuException("error acquiring lock: "+stringerror()); + } + ~Lock() + { + if(g_singleThreaded) + return; + + pthread_mutex_unlock(d_lock); + } +}; + +class WriteLock +{ + pthread_rwlock_t *d_lock; +public: + + WriteLock(pthread_rwlock_t *lock) : d_lock(lock) + { + if(g_singleThreaded) + return; + + if((errno=pthread_rwlock_wrlock(d_lock))) { + throw AhuException("error acquiring rwlock wrlock: "+stringerror()); + } + } + ~WriteLock() + { + if(g_singleThreaded) + return; + + pthread_rwlock_unlock(d_lock); + } +}; + +class TryWriteLock +{ + pthread_rwlock_t *d_lock; + bool d_havelock; +public: + + TryWriteLock(pthread_rwlock_t *lock) : d_lock(lock) + { + if(g_singleThreaded) { + d_havelock=true; + return; + } + + d_havelock=false; + if((errno=pthread_rwlock_trywrlock(d_lock)) && errno!=EBUSY) + throw AhuException("error acquiring rwlock tryrwlock: "+stringerror()); + d_havelock=(errno==0); + } + ~TryWriteLock() + { + if(g_singleThreaded) + return; + + if(d_havelock) + pthread_rwlock_unlock(d_lock); + } + bool gotIt() + { + if(g_singleThreaded) + return true; + + return d_havelock; + } +}; + +class TryReadLock +{ + pthread_rwlock_t *d_lock; + bool d_havelock; +public: + + TryReadLock(pthread_rwlock_t *lock) : d_lock(lock) + { + if(g_singleThreaded) { + d_havelock=true; + return; + } + + if((errno=pthread_rwlock_tryrdlock(d_lock)) && errno!=EBUSY) + throw AhuException("error acquiring rwlock tryrdlock: "+stringerror()); + d_havelock=(errno==0); + } + ~TryReadLock() + { + if(g_singleThreaded) + return; + + if(d_havelock) + pthread_rwlock_unlock(d_lock); + } + bool gotIt() + { + if(g_singleThreaded) + return true; + + return d_havelock; + } +}; + + +class ReadLock +{ + pthread_rwlock_t *d_lock; +public: + + ReadLock(pthread_rwlock_t *lock) : d_lock(lock) + { + if(g_singleThreaded) + return; + + if((errno=pthread_rwlock_rdlock(d_lock))) + throw AhuException("error acquiring rwlock tryrwlock: "+stringerror()); + } + ~ReadLock() + { + if(g_singleThreaded) + return; + + pthread_rwlock_unlock(d_lock); + } + + void upgrade() + { + if(g_singleThreaded) + return; + + pthread_rwlock_unlock(d_lock); + pthread_rwlock_wrlock(d_lock); + } +}; +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/logger.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/logger.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/logger.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/logger.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,188 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2005 PowerDNS.COM 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 "logger.hh" +#include "config.h" + +#ifndef RECURSOR +#include "statbag.hh" +extern StatBag S; +#endif + +#include "namespaces.hh" + +Logger &theL(const string &pname) +{ + static Logger l("", LOG_DAEMON); + if(!pname.empty()) + l.setName(pname); + return l; +} + +void Logger::log(const string &msg, Urgency u) +{ + struct tm tm; + time_t t; + time(&t); + tm=*localtime(&t); + + if(u<=consoleUrgency) {// Sep 14 06:52:09 + char buffer[50]; + strftime(buffer,sizeof(buffer),"%b %d %H:%M:%S ", &tm); + clog< +#include +#include +#include +#include +#include "config.h" +#ifndef WIN32 +# include +#include + +#else +# define WINDOWS_LEAN_AND_MEAN +# include +typedef int pthread_mutex_t; +typedef int pthread_t; +#endif // WIN32 + +#include "namespaces.hh" + +//! The Logger class can be used to log messages in various ways. +class Logger +{ +public: +#ifndef WIN32 + Logger(const string &, int facility=LOG_DAEMON); //!< pass the identification you wish to appear in the log + + //! The urgency of a log message + enum Urgency {All=99999,NTLog=12345,Alert=LOG_ALERT, Critical=LOG_CRIT, Error=LOG_ERR, Warning=LOG_WARNING, + Notice=LOG_NOTICE,Info=LOG_INFO, Debug=LOG_DEBUG, None=-1}; + +#else + Logger( const string &, int facility = 0 ); //!< pass the identification you wish to appear in the log + + //! The urgency of a log message + enum Urgency + { + All = 99999, + NTLog = 12345, + Alert = EVENTLOG_ERROR_TYPE, + Critical= EVENTLOG_ERROR_TYPE, + Error = EVENTLOG_ERROR_TYPE, + Warning = EVENTLOG_WARNING_TYPE, + Notice = EVENTLOG_INFORMATION_TYPE, + Info = EVENTLOG_INFORMATION_TYPE, + Debug = EVENTLOG_INFORMATION_TYPE, + None = -1 + }; + + void toNTLog( void ); + +private: + //! Handle used to communicate with the event log. + HANDLE m_eventLogHandle; + + //! Log file handle. + FILE *m_pLogFile; + + //! Log current message to the NT log? + map< pthread_t, bool > m_toNTLog; + +public: + +#endif // WIN32 + + /** Log a message. + \param msg Message you wish to log + \param Urgency Urgency of the message you wish to log + */ + void log(const string &msg, Urgency u=Notice); + + void setFacility(int f){d_facility=f;open();} //!< Choose logging facility + void setFlag(int f){flags|=f;open();} //!< set a syslog flag + void setName(const string &); + + //! set lower limit of urgency needed for console display. Messages of this urgency, and higher, will be displayed + void toConsole(Urgency); + void setLoglevel( Urgency ); + + //! Log to a file. + void toFile( const string & filename ); + + void resetFlags(){flags=0;open();} //!< zero the flags + /** Use this to stream to your log, like this: + \code + L<<"This is an informational message"<d_strings; + map d_outputurgencies; + void open(); + string name; + int flags; + int d_facility; + bool opened; + Urgency d_loglevel; + Urgency consoleUrgency; + pthread_mutex_t lock; +}; + +extern Logger &theL(const string &pname=""); + +#ifdef VERBOSELOG +#define DLOG(x) x +#else +#define DLOG(x) +#endif + + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/lua-pdns.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/lua-pdns.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/lua-pdns.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/lua-pdns.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,282 @@ +#include "lua-pdns.hh" +// #include "syncres.hh" +#include + +#if !defined(PDNS_ENABLE_LUA) + +// stub implementation + +PowerDNSLua::PowerDNSLua(const std::string& fname) +{ + throw runtime_error("Lua support disabled"); +} + + +PowerDNSLua::~PowerDNSLua() +{ + +} + +#else + +extern "C" { +#undef L +/* Include the Lua API header files. */ +#include +#include +#include +} + +#include +#include +#include +#include +#include +#include "logger.hh" +#include "namespaces.hh" + +bool netmaskMatchTable(lua_State* lua, const std::string& ip) +{ + lua_pushnil(lua); /* first key */ + while (lua_next(lua, 2) != 0) { + string netmask=lua_tostring(lua, -1); + Netmask nm(netmask); + ComboAddress ca(ip); + lua_pop(lua, 1); + + if(nm.match(ip)) + return true; + } + return false; +} + +static bool getFromTable(lua_State *lua, const std::string &key, std::string& value) +{ + lua_pushstring(lua, key.c_str()); // 4 is now '1' + lua_gettable(lua, -2); // replace by the first entry of our table we hope + + bool ret=false; + if(!lua_isnil(lua, -1)) { + value = lua_tostring(lua, -1); + ret=true; + } + lua_pop(lua, 1); + return ret; +} + +static bool getFromTable(lua_State *lua, const std::string &key, uint32_t& value) +{ + lua_pushstring(lua, key.c_str()); // 4 is now '1' + lua_gettable(lua, -2); // replace by the first entry of our table we hope + + bool ret=false; + if(!lua_isnil(lua, -1)) { + value = (uint32_t)lua_tonumber(lua, -1); + ret=true; + } + lua_pop(lua, 1); + return ret; +} + +void pushResourceRecordsTable(lua_State* lua, const vector& records) +{ + // make a table of tables + lua_newtable(lua); + + int pos=0; + BOOST_FOREACH(const DNSResourceRecord& rr, records) + { + // row number, used by 'lua_settable' below + lua_pushnumber(lua, ++pos); + // "row" table + lua_newtable(lua); + + lua_pushstring(lua, rr.qname.c_str()); + lua_setfield(lua, -2, "qname"); // pushes value at the top of the stack to the table immediately below that (-1 = top, -2 is below) + + lua_pushstring(lua, rr.content.c_str()); + lua_setfield(lua, -2, "content"); + + lua_pushnumber(lua, rr.qtype.getCode()); + lua_setfield(lua, -2, "qtype"); + + lua_pushnumber(lua, rr.ttl); + lua_setfield(lua, -2, "ttl"); + + lua_pushnumber(lua, rr.d_place); + lua_setfield(lua, -2, "place"); + + lua_settable(lua, -3); // pushes the table we just built into the master table at position pushed above + } +} + +void popResourceRecordsTable(lua_State *lua, const string &query, vector& ret) +{ + /* get the result */ + DNSResourceRecord rr; + rr.qname = query; + rr.d_place = DNSResourceRecord::ANSWER; + rr.ttl = 3600; + + cerr<<"Lua stacksize "<= 2) { + string ip=lua_tostring(lua, 1); + if(lua_istable(lua, 2)) { + result = netmaskMatchTable(lua, ip); + } + else { + for(int n=2 ; n <= lua_gettop(lua); ++n) { + string netmask=lua_tostring(lua, n); + Netmask nm(netmask); + ComboAddress ca(ip); + + result = nm.match(ip); + if(result) + break; + } + } + } + + lua_pushboolean(lua, result); + return 1; +} + +int getLocalAddressLua(lua_State* lua) +{ + lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); + PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1); + + lua_pushstring(lua, pl->getLocal().toString().c_str()); + return 1; +} + +// called by lua to indicate that this answer is 'variable' and should not be cached +int setVariableLua(lua_State* lua) +{ + lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); + PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1); + pl->setVariable(); + return 0; +} + +int logLua(lua_State *lua) +{ + if(lua_gettop(lua) >= 1) { + string message=lua_tostring(lua, 1); + theL()<::const_iterator iter = QType::names.begin(); iter != QType::names.end(); ++iter) { + lua_pushnumber(d_lua, iter->second); + lua_setfield(d_lua, -2, iter->first.c_str()); + } + lua_pushnumber(d_lua, 0); + lua_setfield(d_lua, -2, "NOERROR"); + lua_pushnumber(d_lua, 1); + lua_setfield(d_lua, -2, "FORMERR"); + lua_pushnumber(d_lua, 2); + lua_setfield(d_lua, -2, "SERVFAIL"); + lua_pushnumber(d_lua, 3); + lua_setfield(d_lua, -2, "NXDOMAIN"); + lua_pushnumber(d_lua, 4); + lua_setfield(d_lua, -2, "NOTIMP"); + lua_pushnumber(d_lua, 5); + lua_setfield(d_lua, -2, "REFUSED"); + lua_setglobal(d_lua, "pdns"); + + lua_pushlightuserdata(d_lua, (void*)this); + lua_setfield(d_lua, LUA_REGISTRYINDEX, "__PowerDNSLua"); +} + +bool PowerDNSLua::getFromTable(const std::string& key, std::string& value) +{ + return ::getFromTable(d_lua, key, value); +} + +bool PowerDNSLua::getFromTable(const std::string& key, uint32_t& value) +{ + return ::getFromTable(d_lua, key, value); +} + + +PowerDNSLua::~PowerDNSLua() +{ + lua_close(d_lua); +} +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/lua-pdns.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/lua-pdns.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/lua-pdns.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/lua-pdns.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,37 @@ +#ifndef PDNS_LUA_PDNS_HH +#define PDNS_LUA_PDNS_HH +#include "dns.hh" +#include "iputils.hh" + +struct lua_State; + +class PowerDNSLua +{ +public: + explicit PowerDNSLua(const std::string& fname); + ~PowerDNSLua(); + void reload(); + ComboAddress getLocal() + { + return d_local; + } + + void setVariable() + { + d_variable=true; + } + +protected: // FIXME? + lua_State* d_lua; + bool passthrough(const string& func, const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable); + bool getFromTable(const std::string& key, std::string& value); + bool getFromTable(const std::string& key, uint32_t& value); + bool d_failed; + bool d_variable; + ComboAddress d_local; +}; + +void pushResourceRecordsTable(lua_State* lua, const vector& records); +void popResourceRecordsTable(lua_State *lua, const string &query, vector& ret); + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/lua-recursor.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/lua-recursor.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/lua-recursor.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/lua-recursor.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,173 @@ +#include "lua-recursor.hh" + +// to avoid including all of syncres.hh +int directResolve(const std::string& qname, const QType& qtype, int qclass, vector& ret); + +#if !defined(PDNS_ENABLE_LUA) + +RecursorLua::RecursorLua(const std::string &fname) + : PowerDNSLua(fname) +{ + // empty +} + +bool RecursorLua::nxdomain(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return false; +} + +bool RecursorLua::nodata(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return false; +} + +bool RecursorLua::postresolve(const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return false; +} + + +bool RecursorLua::preresolve(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return false; +} + + +#else + +extern "C" { +#undef L +/* Include the Lua API header files. */ +#include +#include +#include +} + +#include +#include +#include +#include +#include +#include +#include "logger.hh" +#include "namespaces.hh" + +RecursorLua::RecursorLua(const std::string &fname) + : PowerDNSLua(fname) +{ + // empty +} + +int getFakeAAAARecords(const std::string& qname, const std::string& prefix, vector& ret) +{ + int rcode=directResolve(qname, QType(QType::A), 1, ret); + + ComboAddress prefixAddress(prefix); + + BOOST_FOREACH(DNSResourceRecord& rr, ret) + { + if(rr.qtype.getCode() == QType::A && rr.d_place==DNSResourceRecord::ANSWER) { + ComboAddress ipv4(rr.content); + uint32_t tmp; + memcpy((void*)&tmp, &ipv4.sin4.sin_addr.s_addr, 4); + // tmp=htonl(tmp); + memcpy(((char*)&prefixAddress.sin6.sin6_addr.s6_addr)+12, &tmp, 4); + rr.content = prefixAddress.toString(); + rr.qtype = QType(QType::AAAA); + } + } + return rcode; +} + +bool RecursorLua::nxdomain(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return passthrough("nxdomain", remote, local, query, qtype, ret, res, variable); +} + +bool RecursorLua::preresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return passthrough("preresolve", remote, local, query, qtype, ret, res, variable); +} + +bool RecursorLua::nodata(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return passthrough("nodata", remote, local, query, qtype, ret, res, variable); +} + +bool RecursorLua::postresolve(const ComboAddress& remote, const ComboAddress& local,const string& query, const QType& qtype, vector& ret, int& res, bool* variable) +{ + return passthrough("postresolve", remote, local, query, qtype, ret, res, variable); +} + + +bool RecursorLua::passthrough(const string& func, const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& ret, + int& res, bool* variable) +{ + d_variable = false; + lua_getglobal(d_lua, func.c_str()); + if(!lua_isfunction(d_lua, -1)) { + // cerr<<"No such function '"<& res, int& ret, bool* variable); + bool nxdomain(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& res, int& ret, bool* variable); + bool nodata(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& res, int& ret, bool* variable); + bool postresolve(const ComboAddress& remote, const ComboAddress& local, const string& query, const QType& qtype, vector& res, int& ret, bool* variable); + +private: + bool passthrough(const string& func, const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector& ret, int& res, bool* variable); +}; + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/lwres.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/lwres.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/lwres.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/lwres.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,232 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2010 PowerDNS.COM 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 "utility.hh" +#include "lwres.hh" +#include +#include "dnsrecords.hh" +#include +#include "misc.hh" +#include +#include +#include +#include +#include +#include "dns.hh" +#include "qtype.hh" +#include "ahuexception.hh" +#include "arguments.hh" +#include "sstuff.hh" +#include "syncres.hh" +#include "dnswriter.hh" +#include "dnsparser.hh" +#include "logger.hh" +#include "dns_random.hh" +#include +#include + +string dns0x20(const std::string& in) +{ + string ret(in); + string::size_type len=ret.size(); + for(string::size_type pos = 0 ; pos < len; ++pos) { + if(isalpha(in[pos]) && dns_random(2)) + ret[pos]^=0x20; + } + // cerr<<"'"< '"< buf(new unsigned char[bufsize]); + vector vpacket; + // string mapped0x20=dns0x20(domain); + DNSPacketWriter pw(vpacket, domain, type); + + pw.getHeader()->rd=sendRDQuery; + pw.getHeader()->id=dns_random(0xffff); + + string ping; + + uint32_t nonce=dns_random(0xffffffff); + ping.assign((char*) &nonce, 4); + + if(EDNS0Level && !doTCP) { + DNSPacketWriter::optvect_t opts; + if(EDNS0Level > 1) { + opts.push_back(make_pair(5, ping)); + } + + pw.addOpt(1200, 0, 0, opts); // 1200 bytes answer size + pw.commit(); + } + lwr->d_rcode = 0; + lwr->d_pingCorrect = false; + lwr->d_haveEDNS = false; + + int ret; + + DTime dt; + dt.setTimeval(*now); + errno=0; + if(!doTCP) { + int queryfd; + if(ip.sin4.sin_family==AF_INET6) + g_stats.ipv6queries++; + + if((ret=asendto((const char*)&*vpacket.begin(), (int)vpacket.size(), 0, ip, pw.getHeader()->id, + domain, type, &queryfd)) < 0) { + return ret; // passes back the -2 EMFILE + } + + // sleep until we see an answer to this, interface to mtasker + + ret=arecvfrom(reinterpret_cast(buf.get()), bufsize-1,0, ip, &len, pw.getHeader()->id, + domain, type, queryfd, now); + } + else { + try { + Socket s((AddressFamily)ip.sin4.sin_family, Stream); + + s.setNonBlocking(); + ComboAddress local = getQueryLocalAddress(ip.sin4.sin_family, 0); + + s.bind(local); + + ComboAddress remote = ip; + remote.sin4.sin_port = htons(53); + s.connect(remote); + + uint16_t tlen=htons(vpacket.size()); + char *lenP=(char*)&tlen; + const char *msgP=(const char*)&*vpacket.begin(); + string packet=string(lenP, lenP+2)+string(msgP, msgP+vpacket.size()); + + ret=asendtcp(packet, &s); + if(!(ret>0)) + return ret; + + packet.clear(); + ret=arecvtcp(packet, 2, &s); + if(!(ret > 0)) + return ret; + + memcpy(&tlen, packet.c_str(), 2); + len=ntohs(tlen); // switch to the 'len' shared with the rest of the function + + ret=arecvtcp(packet, len, &s); + if(!(ret > 0)) + return ret; + + if(len > bufsize) { + bufsize=len; + scoped_array narray(new unsigned char[bufsize]); + buf.swap(narray); + } + memcpy(buf.get(), packet.c_str(), len); + + ret=1; + } + catch(NetworkError& ne) { + ret = -2; // OS limits error + } + } + + + lwr->d_usec=dt.udiff(); + *now=dt.getTimeval(); + + if(ret <= 0) // includes 'timeout' + return ret; + + lwr->d_result.clear(); + try { + lwr->d_tcbit=0; + MOADNSParser mdp((const char*)buf.get(), len); + lwr->d_aabit=mdp.d_header.aa; + lwr->d_tcbit=mdp.d_header.tc; + lwr->d_rcode=mdp.d_header.rcode; + + if(mdp.d_header.rcode == RCode::FormErr && mdp.d_qname.empty() && mdp.d_qtype == 0 && mdp.d_qclass == 0) { + return 1; // this is "success", the error is set in lwr->d_rcode + } + + if(!pdns_iequals(domain, mdp.d_qname)) { + if(!mdp.d_qname.empty() && domain.find((char)0) == string::npos) {// embedded nulls are too noisy, plus empty domains are too + L<first.d_type; + rr.qname=i->first.d_label; + rr.ttl=i->first.d_ttl; + rr.content=i->first.d_content->getZoneRepresentation(); // this should be the serialised form + rr.d_place=(DNSResourceRecord::Place) i->first.d_place; + lwr->d_result.push_back(rr); + } + + EDNSOpts edo; + if(EDNS0Level > 1 && getEDNSOpts(mdp, &edo)) { + lwr->d_haveEDNS = true; + for(vector >::const_iterator iter = edo.d_options.begin(); + iter != edo.d_options.end(); + ++iter) { + if(iter->first == 5 || iter->first == 4) {// 'EDNS PING' + if(iter->second == ping) { + lwr->d_pingCorrect = true; + } + } + } + } + + return 1; + } + catch(std::exception &mde) { + if(::arg().mustDo("log-common-errors")) + L<d_rcode = RCode::FormErr; + g_stats.serverParseError++; + return 1; // success - oddly enough + } + catch(...) { + L<d_rcode) + lwr->d_rcode=RCode::ServFail; + + return -1; +} + + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/lwres.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/lwres.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/lwres.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/lwres.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,70 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2007 PowerDNS.COM 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 +*/ + +#ifndef PDNS_LWRES_HH +#define PDNS_LWRES_HH +#include +#include +#include +#include "misc.hh" +#include "iputils.hh" +#ifndef WIN32 +# include +# include +# include +# include +# include +# include +# include +# include +# undef res_mkquery +#endif // WIN32 + +#include "ahuexception.hh" +#include "dns.hh" +#include "namespaces.hh" + +int asendto(const char *data, int len, int flags, const ComboAddress& ip, uint16_t id, + const string& domain, uint16_t qtype, int* fd); +int arecvfrom(char *data, int len, int flags, const ComboAddress& ip, int *d_len, uint16_t id, + const string& domain, uint16_t, int fd, struct timeval* now); + +class LWResException : public AhuException +{ +public: + LWResException(const string &reason) : AhuException(reason){} +}; + +//! LWRes class +class LWResult +{ +public: + typedef vector res_t; + + vector d_result; + int d_rcode; + bool d_aabit, d_tcbit; + uint32_t d_usec; + bool d_pingCorrect; + bool d_haveEDNS; +}; + +int asyncresolve(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool sendRDQuery, int EDNS0Level, struct timeval* now, LWResult* res); + +#endif // PDNS_LWRES_HH diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/Makefile pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/Makefile --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/Makefile 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/Makefile 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,105 @@ +# user editable stuff: +SBINDIR=/usr/sbin/ +BINDIR=/usr/bin/ +CONFIGDIR="/etc/powerdns/" +OPTFLAGS?=-O3 +CXXFLAGS:= $(CXXFLAGS) -Wall $(OPTFLAGS) $(PROFILEFLAGS) $(ARCHFLAGS) -pthread +CFLAGS:=$(CFLAGS) -Wall $(OPTFLAGS) $(PROFILEFLAGS) $(ARCHFLAGS) -pthread +LDFLAGS:=$(LDFLAGS) $(ARCHFLAGS) -pthread + +LINKCC=$(CXX) +CC?=gcc + +# Lua 5.1 settings + +# static dependencies + +PDNS_RECURSOR_OBJECTS=syncres.o misc.o unix_utility.o qtype.o logger.o \ +arguments.o lwres.o pdns_recursor.o recursor_cache.o dnsparser.o \ +dnswriter.o dnsrecords.o rcpgenerator.o base64.o zoneparser-tng.o \ +rec_channel.o rec_channel_rec.o selectmplexer.o sillyrecords.o \ +dns_random.o aescrypt.o aeskey.o aes_modes.o aestab.o dnslabeltext.o \ +lua-pdns.o lua-recursor.o randomhelper.o recpacketcache.o dns.o \ +reczones.o base32.o nsecrecords.o + +REC_CONTROL_OBJECTS=rec_channel.o rec_control.o arguments.o misc.o \ + unix_utility.o logger.o qtype.o + +# what we need +all: message pdns_recursor rec_control + +# OS specific instructions +-include sysdeps/$(shell uname).inc + +ifeq ($(LUA), 1) + LUALIBS=$(LUA_LIBS_CONFIG) + CXXFLAGS+=$(LUA_CPPFLAGS_CONFIG) -DPDNS_ENABLE_LUA +endif + + +ifeq ($(STATIC),semi) + STATICFLAGS=-Wl,-Bstatic -lstdc++ $(LUALIBS) -lgcc -Wl,-Bdynamic -static-libgcc -lm -lc + LINKCC=$(CC) + LDFLAGS += -ldl -lm +else + ifeq ($(STATIC),full) + STATICFLAGS=-lstdc++ $(LUALIBS) -ldl -lm -static + LINKCC=$(CC) + else + LDFLAGS += $(LUALIBS) + endif +endif + + +LDFLAGS += $(PROFILEFLAGS) $(STATICFLAGS) + +message: + @echo + @echo PLEASE READ: If you get an error mentioning \#include '', please read README + @echo PLEASE READ: for an easy fix! + @echo + +basic_checks: + @-rm -f pdns_hw + -$(CXX) $(CXXFLAGS) pdns_hw.cc -o pdns_hw + @echo + @if test -x ./pdns_hw ; \ + then if ./pdns_hw; then echo Everything ok, now run $(MAKE) using same settings \(if any\) you passed ./configure; else echo Could compile binary, but not run it, read README please ; fi; \ + else \ + echo; echo Could not compile simple binary, read README please; \ + rm -f dep ; \ + fi + +install: all + -mkdir -p $(DESTDIR)/$(SBINDIR) + mv pdns_recursor $(DESTDIR)/$(SBINDIR) + strip $(DESTDIR)/$(SBINDIR)/pdns_recursor + mkdir -p $(DESTDIR)/$(BINDIR) + mv rec_control $(DESTDIR)/$(BINDIR) + strip $(DESTDIR)/$(BINDIR)/rec_control + -mkdir -p $(DESTDIR)/$(CONFIGDIR) + $(DESTDIR)/$(SBINDIR)/pdns_recursor --config > $(DESTDIR)/$(CONFIGDIR)/recursor.conf-dist + -mkdir -p $(DESTDIR)/usr/share/man/man1 + cp pdns_recursor.1 rec_control.1 $(DESTDIR)/usr/share/man/man1 + $(OS_SPECIFIC_INSTALL) + +clean: binclean + -rm -f dep *~ *.gcda *.gcno optional/*.gcda optional/*.gcno + +binclean: + -rm -f *.o pdns_recursor rec_control optional/*.o + +dep: + $(CXX) $(CXXFLAGS) -MM -MG *.cc *.c *.hh > $@ + +-include dep + +optional: + mkdir optional + +pdns_recursor: optional $(OPTIONALS) $(PDNS_RECURSOR_OBJECTS) + $(LINKCC) $(PDNS_RECURSOR_OBJECTS) $(wildcard optional/*.o) $(LDFLAGS) -o $@ + +rec_control: $(REC_CONTROL_OBJECTS) + $(LINKCC) $(REC_CONTROL_OBJECTS) $(LDFLAGS) -o $@ + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/Makefile.win32 pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/Makefile.win32 --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/Makefile.win32 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/Makefile.win32 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,70 @@ +# user editable stuff: +CONFIGDIR="/etc/powerdns/" +OPTFLAGS?=-O3 +CXXFLAGS:= $(CXXFLAGS) -Wall $(OPTFLAGS) $(PROFILEFLAGS) -g +CFLAGS:=$(CFLAGS) -Wall $(OPTFLAGS) $(PROFILEFLAGS) +LINKCC=i586-mingw32msvc-g++ +CC=i586-mingw32msvc-gcc +CXX=i586-mingw32msvc-g++ +# static dependencies + +PDNS_RECURSOR_OBJECTS=syncres.o misc.o win32_utility.o qtype.o \ +arguments.o lwres.o pdns_recursor.o recursor_cache.o dnsparser.o \ +dnswriter.o dnsrecords.o rcpgenerator.o base64.o zoneparser-tng.o \ +malloc.o selectmplexer.o win32_logger.o win32_rec_channel.o rec_channel_rec.o \ +recursorservice.o ntservice.o + +# REC_CONTROL_OBJECTS=rec_channel.o rec_control.o arguments.o + +# what we need +all: message pdns_recursor.exe + +LDFLAGS += -lwinmm -lwsock32 -lws2_32 $(PROFILEFLAGS) $(STATICFLAGS) + +message: + @echo + @echo PLEASE READ: If you get an error mentioning \#include '', please read README + @echo PLEASE READ: for an easy fix! + @echo + +basic_checks: + @-rm -f pdns_hw + -$(CXX) $(CXXFLAGS) pdns_hw.cc -o pdns_hw + @echo + @if test -x ./pdns_hw ; \ + then if ./pdns_hw; then echo Everything ok, now run $(MAKE) using same settings \(if any\) you passed ./configure; else echo Could compile binary, but not run it, read README please ; fi; \ + else \ + echo; echo Could not compile simple binary, read README please; \ + rm -f dep ; \ + fi + +install: all + -mkdir -p $(DESTDIR)/$(SBINDIR) + mv pdns_recursor $(DESTDIR)/$(SBINDIR) + strip $(DESTDIR)/$(SBINDIR)/pdns_recursor + mkdir -p $(DESTDIR)/$(BINDIR) + mv rec_control $(DESTDIR)/$(BINDIR) + strip $(DESTDIR)/$(BINDIR)/rec_control + -mkdir -p $(DESTDIR)/$(CONFIGDIR) + $(DESTDIR)/$(SBINDIR)/pdns_recursor --config > $(DESTDIR)/$(CONFIGDIR)/recursor.conf-dist + -mkdir -p $(DESTDIR)/usr/share/man/man1 + cp pdns_recursor.1 rec_control.1 $(DESTDIR)/usr/share/man/man1 + $(OS_SPECIFIC_INSTALL) + +clean: + -rm -f dep *.o *~ pdns_recursor rec_control optional/*.o + +dep: + $(CXX) $(CXXFLAGS) -MM -MG *.cc *.hh > $@ + +-include dep + +optional: + mkdir optional + +pdns_recursor.exe: optional $(OPTIONALS) $(PDNS_RECURSOR_OBJECTS) + $(LINKCC) $(PDNS_RECURSOR_OBJECTS) $(wildcard optional/*.o) $(LDFLAGS) -o $@ + +rec_control: $(REC_CONTROL_OBJECTS) + $(LINKCC) $(REC_CONTROL_OBJECTS) $(LDFLAGS) -o $@ + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/misc.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/misc.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/misc.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/misc.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,779 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2010 PowerDNS.COM 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 +*/ + +#ifndef WIN32 +#include +#include +#include +#include +#include +#include +#endif // WIN32 + +#include "misc.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "ahuexception.hh" +#include +#include "utility.hh" +#include + +bool g_singleThreaded; + +int writen2(int fd, const void *buf, size_t count) +{ + const char *ptr = (char*)buf; + const char *eptr = ptr + count; + + int res; + while(ptr != eptr) { + res = ::write(fd, ptr, eptr - ptr); + if(res < 0) { + if (errno == EAGAIN) + throw std::runtime_error("used writen2 on non-blocking socket, got EAGAIN"); + else + unixDie("failed in writen2"); + } + else if (res == 0) + throw std::runtime_error("could not write all bytes, got eof in writen2"); + + ptr += res; + } + + return count; +} + + +string nowTime() +{ + time_t now=time(0); + string t=ctime(&now); + boost::trim_right(t); + return t; +} + +uint16_t getShort(const unsigned char *p) +{ + return p[0] * 256 + p[1]; +} + + +uint16_t getShort(const char *p) +{ + return getShort((const unsigned char *)p); +} + +uint32_t getLong(const unsigned char* p) +{ + return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3]; +} + +uint32_t getLong(const char* p) +{ + return getLong((unsigned char *)p); +} + + + +/** strips a domain suffix from a domain, returns true if it stripped */ +bool stripDomainSuffix(string *qname, const string &domain) +{ + if(!endsOn(*qname, domain)) + return false; + + if(toLower(*qname)==toLower(domain)) + *qname="@"; + else { + if((*qname)[qname->size()-domain.size()-1]!='.') + return false; + + qname->resize(qname->size()-domain.size()-1); + } + return true; +} + +/** Chops off the start of a domain, so goes from 'www.ds9a.nl' to 'ds9a.nl' to 'nl' to ''. Return zero on the empty string */ +bool chopOff(string &domain) +{ + if(domain.empty()) + return false; + + string::size_type fdot=domain.find('.'); + + if(fdot==string::npos) + domain=""; + else { + string::size_type remain = domain.length() - (fdot + 1); + char tmp[remain]; + memcpy(tmp, domain.c_str()+fdot+1, remain); + domain.assign(tmp, remain); // don't dare to do this w/o tmp holder :-) + } + return true; +} + +/** Chops off the start of a domain, so goes from 'www.ds9a.nl.' to 'ds9a.nl.' to 'nl.' to '.' Return zero on the empty string */ +bool chopOffDotted(string &domain) +{ + if(domain.empty() || (domain.size()==1 && domain[0]=='.')) + return false; + + string::size_type fdot=domain.find('.'); + if(fdot == string::npos) + return false; + + if(fdot==domain.size()-1) + domain="."; + else { + string::size_type remain = domain.length() - (fdot + 1); + char tmp[remain]; + memcpy(tmp, domain.c_str()+fdot+1, remain); + domain.assign(tmp, remain); + } + return true; +} + + +bool ciEqual(const string& a, const string& b) +{ + if(a.size()!=b.size()) + return false; + + string::size_type pos=0, epos=a.size(); + for(;pos < epos; ++pos) + if(dns_tolower(a[pos])!=dns_tolower(b[pos])) + return false; + return true; +} + +/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */ +bool endsOn(const string &domain, const string &suffix) +{ + if( suffix.empty() || ciEqual(domain, suffix) ) + return true; + + if(domain.size()<=suffix.size()) + return false; + + string::size_type dpos=domain.size()-suffix.size()-1, spos=0; + + if(domain[dpos++]!='.') + return false; + + for(; dpos < domain.size(); ++dpos, ++spos) + if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos])) + return false; + + return true; +} + +/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */ +bool dottedEndsOn(const string &domain, const string &suffix) +{ + if( suffix=="." || ciEqual(domain, suffix) ) + return true; + + if(domain.size()<=suffix.size()) + return false; + + string::size_type dpos=domain.size()-suffix.size()-1, spos=0; + + if(domain[dpos++]!='.') + return false; + + for(; dpos < domain.size(); ++dpos, ++spos) + if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos])) + return false; + + return true; +} + +int sendData(const char *buffer, int replen, int outsock) +{ + uint16_t nlen=htons(replen); + Utility::iovec iov[2]; + iov[0].iov_base=(char*)&nlen; + iov[0].iov_len=2; + iov[1].iov_base=(char*)buffer; + iov[1].iov_len=replen; + int ret=Utility::writev(outsock,iov,2); + + if(ret <= 0) // "EOF is error" - we can't deal with EAGAIN errors at this stage yet + return -1; + + if(ret!=replen+2) { + // we can safely assume ret > 2, as 2 is < PIPE_BUF + + buffer += (ret - 2); + replen -= (ret - 2); + + while (replen) { + ret = write(outsock, buffer, replen); + if(ret < 0) { + if(errno==EAGAIN) { // wait, we might've exhausted the window + while(waitForRWData(outsock, false, 1, 0)==0) + ; + continue; + } + return ret; + } + if(!ret) + return -1; // "EOF == error" + replen -= ret; + buffer += ret; + } + if(!replen) + return 0; + return -1; + } + return 0; +} + +static void parseService4(const string &descr, ServiceTuple &st) +{ + vectorparts; + stringtok(parts,descr,":"); + if(parts.empty()) + throw AhuException("Unable to parse '"+descr+"' as a service"); + st.host=parts[0]; + if(parts.size()>1) + st.port=atoi(parts[1].c_str()); +} + +static void parseService6(const string &descr, ServiceTuple &st) +{ + string::size_type pos=descr.find(']'); + if(pos == string::npos) + throw AhuException("Unable to parse '"+descr+"' as an IPv6 service"); + + st.host=descr.substr(1, pos-1); + if(pos + 2 < descr.length()) + st.port=atoi(descr.c_str() + pos +2); +} + + +void parseService(const string &descr, ServiceTuple &st) +{ + if(descr.empty()) + throw AhuException("Unable to parse '"+descr+"' as a service"); + + vector parts; + stringtok(parts, descr, ":"); + + if(descr[0]=='[') { + parseService6(descr, st); + } + else if(descr[0]==':' || parts.size() > 2 || descr.find("::") != string::npos) { + st.host=descr; + } + else { + parseService4(descr, st); + } +} + +// returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set +int waitForData(int fd, int seconds, int useconds) +{ + return waitForRWData(fd, true, seconds, useconds); +} + +int waitForRWData(int fd, bool waitForRead, int seconds, int useconds) +{ + int ret; + + struct pollfd pfd; + memset(&pfd, 0, sizeof(pfd)); + pfd.fd = fd; + + if(waitForRead) + pfd.events=POLLIN; + else + pfd.events=POLLOUT; + + ret = poll(&pfd, 1, seconds * 1000 + useconds/1000); + if ( ret == -1 ) + errno = ETIMEDOUT; // ??? + + return ret; +} + +// returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set +int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int*fd) +{ + int ret; + + struct pollfd pfds[2]; + memset(&pfds[0], 0, 2*sizeof(struct pollfd)); + pfds[0].fd = fd1; + pfds[1].fd = fd2; + + pfds[0].events= pfds[1].events = POLLIN; + + int nsocks = 1 + (fd2 >= 0); // fd2 can optionally be -1 + + if(seconds >= 0) + ret = poll(pfds, nsocks, seconds * 1000 + useconds/1000); + else + ret = poll(pfds, nsocks, -1); + if(!ret || ret < 0) + return ret; + + if((pfds[0].revents & POLLIN) && !(pfds[1].revents & POLLIN)) + *fd = pfds[0].fd; + else if((pfds[1].revents & POLLIN) && !(pfds[0].revents & POLLIN)) + *fd = pfds[1].fd; + else if(ret == 2) { + *fd = pfds[random()%2].fd; + } + else + *fd = -1; // should never happen + + return 1; +} + + +string humanDuration(time_t passed) +{ + ostringstream ret; + if(passed<60) + ret<> 24)&0xff, + (val >> 16)&0xff, + (val >> 8)&0xff, + (val )&0xff); + return tmp; +} + + +string makeHexDump(const string& str) +{ + char tmp[5]; + string ret; + ret.reserve((int)(str.size()*2.2)); + + for(string::size_type n=0;n& rrs) +{ + vector::iterator first, second; + for(first=rrs.begin();first!=rrs.end();++first) + if(first->d_place==DNSResourceRecord::ANSWER && first->qtype.getCode() != QType::CNAME) // CNAME must come first + break; + for(second=first;second!=rrs.end();++second) + if(second->d_place!=DNSResourceRecord::ANSWER) + break; + + if(second-first>1) + random_shuffle(first,second); + + // now shuffle the additional records + for(first=second;first!=rrs.end();++first) + if(first->d_place==DNSResourceRecord::ADDITIONAL && first->qtype.getCode() != QType::CNAME) // CNAME must come first + break; + for(second=first;second!=rrs.end();++second) + if(second->d_place!=DNSResourceRecord::ADDITIONAL) + break; + + if(second-first>1) + random_shuffle(first,second); + + // we don't shuffle the rest +} + +static bool comparePlace(DNSResourceRecord a, DNSResourceRecord b) +{ + return (a.d_place < b.d_place); +} + +// make sure rrs is sorted in d_place order to avoid surprises later +// then shuffle the parts that desire shuffling +void orderAndShuffle(vector& rrs) +{ + std::stable_sort(rrs.begin(), rrs.end(), comparePlace); + shuffle(rrs); +} + +void normalizeTV(struct timeval& tv) +{ + if(tv.tv_usec > 1000000) { + ++tv.tv_sec; + tv.tv_usec-=1000000; + } + else if(tv.tv_usec < 0) { + --tv.tv_sec; + tv.tv_usec+=1000000; + } +} + +const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs) +{ + struct timeval ret; + ret.tv_sec=lhs.tv_sec + rhs.tv_sec; + ret.tv_usec=lhs.tv_usec + rhs.tv_usec; + normalizeTV(ret); + return ret; +} + +const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs) +{ + struct timeval ret; + ret.tv_sec=lhs.tv_sec - rhs.tv_sec; + ret.tv_usec=lhs.tv_usec - rhs.tv_usec; + normalizeTV(ret); + return ret; +} + +pair splitField(const string& inp, char sepa) +{ + pair ret; + string::size_type cpos=inp.find(sepa); + if(cpos==string::npos) + ret.first=inp; + else { + ret.first=inp.substr(0, cpos); + ret.second=inp.substr(cpos+1); + } + return ret; +} + +int logFacilityToLOG(unsigned int facility) +{ + switch(facility) { + case 0: + return LOG_LOCAL0; + case 1: + return(LOG_LOCAL1); + case 2: + return(LOG_LOCAL2); + case 3: + return(LOG_LOCAL3); + case 4: + return(LOG_LOCAL4); + case 5: + return(LOG_LOCAL5); + case 6: + return(LOG_LOCAL6); + case 7: + return(LOG_LOCAL7); + default: + return -1; + } +} + +string stripDot(const string& dom) +{ + if(dom.empty()) + return dom; + + if(dom[dom.size()-1]!='.') + return dom; + + return dom.substr(0,dom.size()-1); +} + + +string labelReverse(const std::string& qname) +{ + if(qname.empty()) + return qname; + + bool dotName = qname.find('.') != string::npos; + + vector labels; + stringtok(labels, qname, ". "); + if(labels.size()==1) + return qname; + + string ret; // vv const_reverse_iter http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729 + for(vector::reverse_iterator iter = labels.rbegin(); iter != labels.rend(); ++iter) { + if(iter != labels.rbegin()) + ret.append(1, dotName ? ' ' : '.'); + ret+=*iter; + } + return ret; +} + +// do NOT feed trailing dots! +// www.powerdns.com, powerdns.com -> www +string makeRelative(const std::string& fqdn, const std::string& zone) +{ + if(zone.empty()) + return fqdn; + if(fqdn != zone) + return fqdn.substr(0, fqdn.size() - zone.length() - 1); // strip domain name + return ""; +} + +string dotConcat(const std::string& a, const std::string &b) +{ + if(a.empty() || b.empty()) + return a+b; + else + return a+"."+b; +} + +int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret) +{ + if(addr.empty()) + return -1; + string ourAddr(addr); + int port = -1; + if(addr[0]=='[') { // [::]:53 style address + string::size_type pos = addr.find(']'); + if(pos == string::npos || pos + 2 > addr.size() || addr[pos+1]!=':') + return -1; + ourAddr.assign(addr.c_str() + 1, pos-1); + port = atoi(addr.c_str()+pos+2); + } + + struct addrinfo* res; + struct addrinfo hints; + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = AF_INET6; + hints.ai_flags = AI_NUMERICHOST; + + int error; + if((error=getaddrinfo(ourAddr.c_str(), 0, &hints, &res))) { // this is correct + /* + cerr<<"Error translating IPv6 address '"<ai_addr, res->ai_addrlen); + if(port >= 0) + ret->sin6_port = htons(port); + freeaddrinfo(res); + return 0; +} + +int makeIPv4sockaddr(const string &str, struct sockaddr_in* ret) +{ + if(str.empty()) { + return -1; + } + struct in_addr inp; + + string::size_type pos = str.find(':'); + if(pos == string::npos) { // no port specified, not touching the port + if(Utility::inet_aton(str.c_str(), &inp)) { + ret->sin_addr.s_addr=inp.s_addr; + return 0; + } + return -1; + } + if(!*(str.c_str() + pos + 1)) // trailing : + return -1; + + char *eptr = (char*)str.c_str() + str.size(); + int port = strtol(str.c_str() + pos + 1, &eptr, 10); + if(*eptr) + return -1; + + ret->sin_port = htons(port); + if(Utility::inet_aton(str.substr(0, pos).c_str(), &inp)) { + ret->sin_addr.s_addr=inp.s_addr; + return 0; + } + return -1; +} + + +//! read a line of text from a FILE* to a std::string, returns false on 'no data' +bool stringfgets(FILE* fp, std::string& line) +{ + char buffer[1024]; + line.clear(); + + do { + if(!fgets(buffer, sizeof(buffer), fp)) + return !line.empty(); + + line.append(buffer); + } while(!strchr(buffer, '\n')); + return true; +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/misc.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/misc.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/misc.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/misc.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,453 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002-2009 PowerDNS.COM 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 +*/ +#ifndef MISC_HH +#define MISC_HH +#include +#include +#include +#include +#include +#include +#include +#include +#include +using namespace ::boost::multi_index; +#if 0 +#include +using std::cout; +using std::endl; + +struct TSCTimer +{ + TSCTimer() + { + RDTSC(d_tsc1); + } + ~TSCTimer() + { + uint64_t tsc2; + RDTSC(tsc2); + cout<<"Timer: "<< (tsc2 - d_tsc1)/3000.0 << endl; + } + uint64_t d_tsc1; +}; +#endif + +#include "utility.hh" +#include "dns.hh" +#ifndef WIN32 +# include +# include +# include +# include +# include +#else +# define WINDOWS_LEAN_AND_MEAN +# include +# include "utility.hh" +#endif // WIN32 +#include +#include +#include +#include +#include + +#include "namespaces.hh" +bool chopOff(string &domain); +bool chopOffDotted(string &domain); + +bool endsOn(const string &domain, const string &suffix); +bool dottedEndsOn(const string &domain, const string &suffix); +string nowTime(); +const string unquotify(const string &item); +string humanDuration(time_t passed); +bool stripDomainSuffix(string *qname, const string &domain); +void stripLine(string &line); +string getHostname(); +string urlEncode(const string &text); +int waitForData(int fd, int seconds, int useconds=0); +int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd); +int waitForRWData(int fd, bool waitForRead, int seconds, int useconds); +uint16_t getShort(const unsigned char *p); +uint16_t getShort(const char *p); +uint32_t getLong(const unsigned char *p); +uint32_t getLong(const char *p); +int logFacilityToLOG(unsigned int facility); + +struct ServiceTuple +{ + string host; + uint16_t port; +}; +void parseService(const string &descr, ServiceTuple &st); + +template +void +stringtok (Container &container, string const &in, + const char * const delimiters = " \t\n") +{ + const string::size_type len = in.length(); + string::size_type i = 0; + + while (i +void +vstringtok (Container &container, string const &in, + const char * const delimiters = " \t\n") +{ + const string::size_type len = in.length(); + string::size_type i = 0; + + while (i='A' && c<='Z') + c+='a'-'A'; + return c; +} + +inline const string toLower(const string &upper) +{ + string reply(upper); + char c; + for(unsigned int i = 0; i < reply.length(); i++) { + c = dns_tolower(upper[i]); + if( c != upper[i]) + reply[i] = c; + } + return reply; +} + +inline const string toLowerCanonic(const string &upper) +{ + string reply(upper); + if(!upper.empty()) { + unsigned int i, limit= ( unsigned int ) reply.length(); + char c; + for(i = 0; i < limit ; i++) { + c = dns_tolower(upper[i]); + if(c != upper[i]) + reply[i] = c; + } + if(upper[i-1]=='.') + reply.resize(i-1); + } + + return reply; +} + + + +// Make s uppercase: +inline string toUpper( const string& s ) +{ + string r(s); + for( unsigned int i = 0; i < s.length(); i++ ) { + r[i] = toupper( r[i] ); + } + return r; +} + +inline double getTime() +{ + struct timeval now; + Utility::gettimeofday(&now,0); + + return now.tv_sec+now.tv_usec/1000000.0; +} + +inline void unixDie(const string &why) +{ + throw runtime_error(why+": "+strerror(errno)); +} + +string makeHexDump(const string& str); +void shuffle(vector& rrs); +void orderAndShuffle(vector& rrs); + +void normalizeTV(struct timeval& tv); +const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs); +const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs); +inline float makeFloat(const struct timeval& tv) +{ + return tv.tv_sec + tv.tv_usec/1000000.0f; +} + +inline bool operator<(const struct timeval& lhs, const struct timeval& rhs) +{ + return make_pair(lhs.tv_sec, lhs.tv_usec) < make_pair(rhs.tv_sec, rhs.tv_usec); +} + +inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) __attribute__((pure)); +inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) +{ + string::size_type aLen = a.length(), bLen = b.length(), n; + const unsigned char *aPtr = (const unsigned char*)a.c_str(), *bPtr = (const unsigned char*)b.c_str(); + int result; + + for(n = 0 ; n < aLen && n < bLen ; ++n) { + if((result = dns_tolower(*aPtr++) - dns_tolower(*bPtr++))) { + return result < 0; + } + } + if(n == aLen && n == bLen) // strings are equal (in length) + return 0; + if(n == aLen) // first string was shorter + return true; + return false; +} + +inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure)); + +inline bool pdns_iequals(const std::string& a, const std::string& b) +{ + string::size_type aLen = a.length(), bLen = b.length(), n; + const char *aPtr = a.c_str(), *bPtr = b.c_str(); + + for(n = 0 ; n < aLen && n < bLen ; ++n) { + if(dns_tolower(*aPtr++) != dns_tolower(*bPtr++)) + return false; + } + return aLen == bLen; // strings are equal (in length) +} + +// lifted from boost, with thanks +class AtomicCounter +{ +public: + + explicit AtomicCounter( unsigned int v = 0) : value_( v ) {} + + unsigned int operator++() + { + return atomic_exchange_and_add( &value_, +1 ) + 1; + } + + unsigned int operator--() + { + return atomic_exchange_and_add( &value_, -1 ) - 1; + } + + operator unsigned int() const + { + return atomic_exchange_and_add( &value_, 0); + } + +private: + AtomicCounter(AtomicCounter const &); + AtomicCounter &operator=(AtomicCounter const &); + + mutable unsigned int value_; + + // the below is necessary because __sync_fetch_and_add is not universally available on i386.. I 3> RHEL5. + #if defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) + static int atomic_exchange_and_add( unsigned int * pw, int dv ) + { + // int r = *pw; + // *pw += dv; + // return r; + + int r; + + __asm__ __volatile__ + ( + "lock\n\t" + "xadd %1, %0": + "+m"( *pw ), "=r"( r ): // outputs (%0, %1) + "1"( dv ): // inputs (%2 == %1) + "memory", "cc" // clobbers + ); + + return r; + } + #else + static int atomic_exchange_and_add( unsigned int * pw, int dv ) + { + return __sync_fetch_and_add(pw, dv); + } + #endif +}; + + +struct CIStringCompare: public std::binary_function +{ + bool operator()(const string& a, const string& b) const + { + return pdns_ilexicographical_compare(a, b); + } +}; + +pair splitField(const string& inp, char sepa); + +inline bool isCanonical(const string& dom) +{ + if(dom.empty()) + return false; + return dom[dom.size()-1]=='.'; +} + +inline string toCanonic(const string& zone, const string& domain) +{ + if(domain.length()==1 && domain[0]=='@') + return zone; + + if(isCanonical(domain)) + return domain; + string ret=domain; + ret.append(1,'.'); + if(!zone.empty() && zone[0]!='.') + ret.append(zone); + return ret; +} + +inline void setSocketReusable(int fd) +{ + int tmp=1; + setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, static_cast(sizeof tmp)); +} + +string stripDot(const string& dom); +void seedRandom(const string& source); +string makeRelative(const std::string& fqdn, const std::string& zone); +string labelReverse(const std::string& qname); +std::string dotConcat(const std::string& a, const std::string &b); +int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret); +int makeIPv4sockaddr(const string &str, struct sockaddr_in* ret); +bool stringfgets(FILE* fp, std::string& line); + +template +std::pair +replacing_insert(Index& i,const typename Index::value_type& x) +{ + std::pair res=i.insert(x); + if(!res.second)res.second=i.replace(res.first,x); + return res; +} + + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/mplexer.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/mplexer.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/mplexer.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/mplexer.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,161 @@ +#ifndef PDNS_MPLEXER_HH +#define PDNS_MPLEXER_HH +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "utility.hh" + +class FDMultiplexerException : public std::runtime_error +{ +public: + FDMultiplexerException(const std::string& str) : std::runtime_error(str) + {} +}; + + +/** Very simple FD multiplexer, based on callbacks and boost::any parameters + As a special service, this parameter is kept around and can be modified, + allowing for state to be stored inside the multiplexer. + + It has some "interesting" semantics +*/ + +class FDMultiplexer +{ +public: + // typedef boost::variant funcparam_t; + typedef boost::any funcparam_t; +protected: + + typedef boost::function< void(int, funcparam_t&) > callbackfunc_t; + struct Callback + { + callbackfunc_t d_callback; + funcparam_t d_parameter; + struct timeval d_ttd; + }; + +public: + FDMultiplexer() : d_inrun(false) + {} + virtual ~FDMultiplexer() + {} + + virtual int run(struct timeval* tv) = 0; + + //! Add an fd to the read watch list - currently an fd can only be on one list at a time! + virtual void addReadFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t()) + { + this->addFD(d_readCallbacks, fd, toDo, parameter); + } + + //! Add an fd to the write watch list - currently an fd can only be on one list at a time! + virtual void addWriteFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t()) + { + this->addFD(d_writeCallbacks, fd, toDo, parameter); + } + + //! Remove an fd from the read watch list. You can't call this function on an fd that is closed already! + /** WARNING: references to 'parameter' become invalid after this function! */ + virtual void removeReadFD(int fd) + { + this->removeFD(d_readCallbacks, fd); + } + + //! Remove an fd from the write watch list. You can't call this function on an fd that is closed already! + /** WARNING: references to 'parameter' become invalid after this function! */ + virtual void removeWriteFD(int fd) + { + this->removeFD(d_writeCallbacks, fd); + } + + virtual void setReadTTD(int fd, struct timeval tv, int timeout) + { + if(!d_readCallbacks.count(fd)) + throw FDMultiplexerException("attempt to timestamp fd not in the multiplexer"); + tv.tv_sec += timeout; + d_readCallbacks[fd].d_ttd=tv; + } + + virtual funcparam_t& getReadParameter(int fd) + { + if(!d_readCallbacks.count(fd)) + throw FDMultiplexerException("attempt to look up data in multiplexer for unlisted fd "+boost::lexical_cast(fd)); + return d_readCallbacks[fd].d_parameter; + } + + virtual std::vector > getTimeouts(const struct timeval& tv) + { + std::vector > ret; + for(callbackmap_t::iterator i=d_readCallbacks.begin(); i!=d_readCallbacks.end(); ++i) + if(i->second.d_ttd.tv_sec && boost::tie(tv.tv_sec, tv.tv_usec) > boost::tie(i->second.d_ttd.tv_sec, i->second.d_ttd.tv_usec)) + ret.push_back(std::make_pair(i->first, i->second.d_parameter)); + return ret; + } + + typedef FDMultiplexer* getMultiplexer_t(); + typedef std::multimap FDMultiplexermap_t; + + static FDMultiplexermap_t& getMultiplexerMap() + { + static FDMultiplexermap_t theMap; + return theMap; + } + + virtual std::string getName() = 0; + + +protected: + typedef std::map callbackmap_t; + callbackmap_t d_readCallbacks, d_writeCallbacks; + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)=0; + virtual void removeFD(callbackmap_t& cbmap, int fd)=0; + bool d_inrun; + callbackmap_t::iterator d_iter; + + void accountingAddFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter) + { + Callback cb; + cb.d_callback=toDo; + cb.d_parameter=parameter; + memset(&cb.d_ttd, 0, sizeof(cb.d_ttd)); + + if(cbmap.count(fd)) + throw FDMultiplexerException("Tried to add fd "+boost::lexical_cast(fd)+ " to multiplexer twice"); + cbmap[fd]=cb; + } + + void accountingRemoveFD(callbackmap_t& cbmap, int fd) + { + if(!cbmap.erase(fd)) + throw FDMultiplexerException("Tried to remove unlisted fd "+boost::lexical_cast(fd)+ " from multiplexer"); + } +}; + +class SelectFDMultiplexer : public FDMultiplexer +{ +public: + SelectFDMultiplexer() + {} + virtual ~SelectFDMultiplexer() + {} + + virtual int run(struct timeval* tv); + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter); + virtual void removeFD(callbackmap_t& cbmap, int fd); + std::string getName() + { + return "select"; + } +}; + +#endif \ No newline at end of file diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/mtasker.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/mtasker.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/mtasker.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/mtasker.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,400 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2009 PowerDNS.COM 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 "mtasker.hh" +#include +#include + +/** \page MTasker + Simple system for implementing cooperative multitasking of functions, with + support for waiting on events which can return values. + + \section copyright Copyright and License + MTasker is (c) 2002 - 2009 by bert hubert. It is licensed to you under the terms of the GPL version 2. + + \section overview High level overview + MTasker is designed to support very simple cooperative multitasking to facilitate writing + code that would ordinarily require a statemachine, for which the author does not consider + himself smart enough. + + This class does not perform any magic it only makes calls to makecontext() and swapcontext(). + Getting the details right however is complicated and MTasker does that for you. + + If preemptive multitasking or more advanced concepts such as semaphores, locks or mutexes + are required, the use of POSIX threads is advised. + + MTasker is designed to offer the performance of statemachines while maintaining simple thread semantics. It is not + a replacement for a full threading system. + + \section compatibility Compatibility + MTasker is only guaranteed to work on Linux with glibc 2.2.5 and higher. It does not work on FreeBSD and notably, + not on Red Hat 6.0. It may work on Solaris, please test. + + \section concepts Concepts + + There are two important concepts, the 'kernel' and the 'thread'. Each thread starts out as a function, + which is passed to MTasker::makeThread(), together with a possible argument. + + This function is now free to do whatever it wants, but realise that MTasker implements cooperative + multitasking, which means that the coder has the responsiblilty of not taking the CPU overly long. + Other threads can only get the CPU if MTasker::yield() is called or if a thread sleeps to wait for an event, + using the MTasker::waitEvent() method. + + \section kernel The Kernel + The Kernel consists of functions that do housekeeping, but also of code that the client coder + can call to report events. A minimal kernel loop looks like this: + \code + for(;;) { + MT.schedule(); + if(MT.noProcesses()) // exit if no processes are left + break; + } + \endcode + + The kernel typically starts from the main() function of your program. New threads are also + created from the kernel. This can also happen before entering the main loop. To start a thread, + the method MTasker::makeThread is provided. + + \section events Events + By default, Events are recognized by an int and their value is also an int. + This can be overridden by specifying the EventKey and EventVal template parameters. + + An event can be a keypress, but also a UDP packet, or a bit of data from a TCP socket. The + sample code provided works with keypresses, but that is just a not very useful example. + + A thread can also wait for an event only for a limited time, and receive a timeout of that + event did not occur within the specified timeframe. + + \section example A simple menu system + \code +MTasker<> MT; + +void menuHandler(void *p) +{ + int num=(int)p; + cout<<"Key handler for key "<int MTasker::waitEvent(EventKey &key, EventVal *val, unsigned int timeoutMsec, struct timeval* now) +{ + if(d_waiters.count(key)) { // there was already an exact same waiter + return -1; + } + + Waiter w; + w.context=new ucontext_t; + w.ttd.tv_sec = 0; w.ttd.tv_usec = 0; + if(timeoutMsec) { + struct timeval increment; + increment.tv_sec = timeoutMsec / 1000; + increment.tv_usec = 1000 * (timeoutMsec % 1000); + if(now) + w.ttd = increment + *now; + else { + struct timeval realnow; + gettimeofday(&realnow, 0); + w.ttd = increment + realnow; + } + } + + w.tid=d_tid; + w.key=key; + + d_waiters.insert(w); + + if(swapcontext(d_waiters.find(key)->context,&d_kernel)) { // 'A' will return here when 'key' has arrived, hands over control to kernel first + perror("swapcontext"); + exit(EXIT_FAILURE); // no way we can deal with this + } + if(val && d_waitstatus==Answer) + *val=d_waitval; + d_tid=w.tid; + if((char*)&w < d_threads[d_tid].highestStackSeen) { + d_threads[d_tid].highestStackSeen = (char*)&w; + } + key=d_eventkey; + return d_waitstatus; +} + +//! yields control to the kernel or other threads +/** Hands over control to the kernel, allowing other processes to run, or events to arrive */ + +templatevoid MTasker::yield() +{ + d_runQueue.push(d_tid); + if(swapcontext(d_threads[d_tid].context ,&d_kernel) < 0) { // give control to the kernel + perror("swapcontext in yield"); + exit(EXIT_FAILURE); + } +} + +//! reports that an event took place for which threads may be waiting +/** From the kernel loop, sendEvent can be called to report that something occured for which there may be waiters. + \param key Key of the event for which threads may be waiting + \param val If non-zero, pointer to the content of the event + \return Returns -1 in case of error, 0 if there were no waiters, 1 if a thread was woken up. + + WARNING: when passing val as zero, d_waitval is undefined, and hence waitEvent will return undefined! +*/ +templateint MTasker::sendEvent(const EventKey& key, const EventVal* val) +{ + typename waiters_t::iterator waiter=d_waiters.find(key); + + if(waiter == d_waiters.end()) { + // cout<<"Event sent nobody was waiting for!"<context; + d_tid=waiter->tid; // set tid + d_eventkey=waiter->key; // pass waitEvent the exact key it was woken for + d_waiters.erase(waiter); // removes the waitpoint + if(swapcontext(&d_kernel,userspace)) { // swaps back to the above point 'A' + perror("swapcontext in sendEvent"); + exit(EXIT_FAILURE); + } + delete userspace; + return 1; +} + +inline pair splitPointer(void *ptr) +{ + uint64_t ll = (uint64_t) ptr; + return make_pair(ll >> 32, ll & 0xffffffff); +} + +inline void* joinPtr(uint32_t val1, uint32_t val2) +{ + return (void*)(((uint64_t)val1 << 32) | (uint64_t)val2); +} + +//! launches a new thread +/** The kernel can call this to make a new thread, which starts at the function start and gets passed the val void pointer. + \param start Pointer to the function which will form the start of the thread + \param val A void pointer that can be used to pass data to the thread +*/ +templatevoid MTasker::makeThread(tfunc_t *start, void* val) +{ + ucontext_t *uc=new ucontext_t; + getcontext(uc); + + uc->uc_link = &d_kernel; // come back to kernel after dying + uc->uc_stack.ss_sp = new char[d_stacksize]; + + uc->uc_stack.ss_size = d_stacksize; + pair valpair = splitPointer(val); + pair thispair = splitPointer(this); + + makecontext (uc, (void (*)(void))threadWrapper, 6, thispair.first, thispair.second, start, d_maxtid, valpair.first, valpair.second); + + d_threads[d_maxtid].context = uc; + d_runQueue.push(d_maxtid++); // will run at next schedule invocation +} + + +//! needs to be called periodically so threads can run and housekeeping can be performed +/** The kernel should call this function every once in a while. It makes sense + to call this function if you: + - reported an event + - called makeThread + - want to have threads running waitEvent() to get a timeout if enough time passed + + \return Returns if there is more work scheduled and recalling schedule now would be useful + +*/ +templatebool MTasker::schedule(struct timeval* now) +{ + if(!d_runQueue.empty()) { + d_tid=d_runQueue.front(); + if(swapcontext(&d_kernel, d_threads[d_tid].context)) { + perror("swapcontext in schedule"); + exit(EXIT_FAILURE); + } + + d_runQueue.pop(); + return true; + } + if(!d_zombiesQueue.empty()) { + delete[] (char *)d_threads[d_zombiesQueue.front()].context->uc_stack.ss_sp; + delete d_threads[d_zombiesQueue.front()].context; + d_threads.erase(d_zombiesQueue.front()); + d_zombiesQueue.pop(); + return true; + } + if(!d_waiters.empty()) { + struct timeval rnow; + if(!now) + gettimeofday(&rnow, 0); + else + rnow = *now; + + typedef typename waiters_t::template index::type waiters_by_ttd_index_t; + // waiters_by_ttd_index_t& ttdindex=d_waiters.template get(); + waiters_by_ttd_index_t& ttdindex=boost::multi_index::get(d_waiters); + + for(typename waiters_by_ttd_index_t::iterator i=ttdindex.begin(); i != ttdindex.end(); ) { + if(i->ttd.tv_sec && i->ttd < rnow) { + d_waitstatus=TimeOut; + d_eventkey=i->key; // pass waitEvent the exact key it was woken for + ucontext_t* uc = i->context; + ttdindex.erase(i++); // removes the waitpoint + + if(swapcontext(&d_kernel, uc)) { // swaps back to the above point 'A' + perror("swapcontext in schedule2"); + exit(EXIT_FAILURE); + } + delete uc; + } + else if(i->ttd.tv_sec) + break; + } + } + return false; +} + +//! returns true if there are no processes +/** Call this to check if no processes are running anymore + \return true if no processes are left + */ +templatebool MTasker::noProcesses() +{ + return d_threads.empty(); +} + +//! returns the number of processes running +/** Call this to perhaps limit activities if too many threads are running + \return number of processes running + */ +templateunsigned int MTasker::numProcesses() +{ + return d_threads.size(); +} + +//! gives access to the list of Events threads are waiting for +/** The kernel can call this to get a list of Events threads are waiting for. This is very useful + to setup 'select' or 'poll' or 'aio' events needed to satisfy these requests. + getEvents clears the events parameter before filling it. + + \param events Vector which is to be filled with keys threads are waiting for +*/ +templatevoid MTasker::getEvents(std::vector& events) +{ + events.clear(); + for(typename waiters_t::const_iterator i=d_waiters.begin();i!=d_waiters.end();++i) { + events.push_back(i->first); + } +} + +templatevoid MTasker::threadWrapper(uint32_t self1, uint32_t self2, tfunc_t *tf, int tid, uint32_t val1, uint32_t val2) +{ + void* val = joinPtr(val1, val2); + MTasker* self = (MTasker*) joinPtr(self1, self2); + self->d_threads[self->d_tid].startOfStack = self->d_threads[self->d_tid].highestStackSeen = (char*)&val; + (*tf)(val); + self->d_zombiesQueue.push(tid); + + // we now jump to &kernel, automatically +} + +//! Returns the current Thread ID (tid) +/** Processes can call this to get a numerical representation of their current thread ID. + This can be useful for logging purposes. +*/ +templateint MTasker::getTid() +{ + return d_tid; +} + + +//! Returns the maximum stack usage so far of this MThread +templateunsigned int MTasker::getMaxStackUsage() +{ + return d_threads[d_tid].startOfStack - d_threads[d_tid].highestStackSeen; +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/mtasker.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/mtasker.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/mtasker.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/mtasker.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,118 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2009 PowerDNS.COM 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 +*/ +#ifndef MTASKER_HH +#define MTASKER_HH + +#ifdef WIN32 +# include "win32_mtasker.hh" +#else + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "namespaces.hh" +using namespace ::boost::multi_index; + +struct KeyTag {}; + +//! The main MTasker class +/** The main MTasker class. See the main page for more information. + \param EventKey Type of the key with which events are to be identified. Defaults to int. + \param EventVal Type of the content or value of an event. Defaults to int. Cannot be set to void. + \note The EventKey needs to have an operator< defined because it is used as the key of an associative array +*/ +template class MTasker +{ +private: + ucontext_t d_kernel; + std::queue d_runQueue; + std::queue d_zombiesQueue; + + struct ThreadInfo + { + ucontext_t* context; + char* startOfStack; + char* highestStackSeen; + }; + + typedef std::map mthreads_t; + mthreads_t d_threads; + int d_tid; + int d_maxtid; + size_t d_stacksize; + + EventVal d_waitval; + enum waitstatusenum {Error=-1,TimeOut=0,Answer} d_waitstatus; + +public: + struct Waiter + { + EventKey key; + ucontext_t *context; + struct timeval ttd; + int tid; + }; + + typedef multi_index_container< + Waiter, + indexed_by < + ordered_unique >, + ordered_non_unique, member > + > + > waiters_t; + + waiters_t d_waiters; + + //! Constructor + /** Constructor with a small default stacksize. If any of your threads exceeds this stack, your application will crash. + This limit applies solely to the stack, the heap is not limited in any way. If threads need to allocate a lot of data, + the use of new/delete is suggested. + */ + MTasker(size_t stacksize=8192) : d_stacksize(stacksize) + { + d_maxtid=0; + } + + typedef void tfunc_t(void *); //!< type of the pointer that starts a thread + int waitEvent(EventKey &key, EventVal *val=0, unsigned int timeoutMsec=0, struct timeval* now=0); + void yield(); + int sendEvent(const EventKey& key, const EventVal* val=0); + void getEvents(std::vector& events); + void makeThread(tfunc_t *start, void* val); + bool schedule(struct timeval* now=0); + bool noProcesses(); + unsigned int numProcesses(); + int getTid(); + unsigned int getMaxStackUsage(); + +private: + static void threadWrapper(uint32_t self1, uint32_t self2, tfunc_t *tf, int tid, uint32_t val1, uint32_t val2); + EventKey d_eventkey; // for waitEvent, contains exact key it was awoken for +}; +#include "mtasker.cc" + +#endif // WIN32 +#endif // MTASKER_HH + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/namespaces.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/namespaces.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/namespaces.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/namespaces.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,64 @@ +#ifndef PDNS_NAMESPACES_HH +#define PDNS_NAMESPACES_HH +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using std::vector; +using std::map; +using std::pair; +using std::make_pair; +using std::runtime_error; +using std::ostringstream; +using std::set; +using std::deque; +using std::cerr; +using std::cout; +using std::clog; +using std::endl; +using std::ifstream; +using std::ofstream; +using std::ostream; +using std::min; // these are a bit scary, everybody uses 'min' +using std::max; + +namespace pdns { + typedef std::string string; +}; + +typedef pdns::string string; + +using boost::lexical_cast; +using boost::tie; +using boost::shared_ptr; +using boost::shared_array; +using boost::scoped_array; +using boost::tuple; +using boost::format; +using boost::make_tuple; +using boost::optional; +using boost::any_cast; +using boost::any; +using boost::function; +using boost::trim; +using boost::trim_left; +using boost::trim_right; +using boost::is_any_of; +using boost::trim_right_copy_if; +using boost::equals; +using boost::ends_with; +using boost::iends_with; +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/nsecrecords.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/nsecrecords.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/nsecrecords.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/nsecrecords.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,294 @@ +#include "dnsrecords.hh" + +void NSECRecordContent::report(void) +{ + regist(1, 47, &make, &make, "NSEC"); +} + +DNSRecordContent* NSECRecordContent::make(const string& content) +{ + return new NSECRecordContent(content); +} + +NSECRecordContent::NSECRecordContent(const string& content, const string& zone) : DNSRecordContent(47) +{ + RecordTextReader rtr(content, zone); + rtr.xfrLabel(d_next); + + while(!rtr.eof()) { + uint16_t type; + rtr.xfrType(type); + d_set.insert(type); + } +} + +void NSECRecordContent::toPacket(DNSPacketWriter& pw) +{ + pw.xfrLabel(d_next); + + uint8_t res[34]; + set::const_iterator i; + int oldWindow = -1; + int window = 0; + int len = 0; + string tmp; + + for(i=d_set.begin(); i != d_set.end(); ++i){ + uint16_t bit = (*i)%256; + window = static_cast((*i) / 256); + + if (window != oldWindow) { + if (oldWindow > -1) { + res[0] = static_cast(oldWindow); + res[1] = static_cast(len); + tmp.assign(res, res+len+2); + pw.xfrBlob(tmp); + } + memset(res, 0, 34); + oldWindow = window; + } + res[2+bit/8] |= 1 << (7-(bit%8)); + len=1+bit/8; + } + + res[0] = static_cast(window); + res[1] = static_cast(len); + tmp.assign(res, res+len+2); + pw.xfrBlob(tmp); +} + +NSECRecordContent::DNSRecordContent* NSECRecordContent::make(const DNSRecord &dr, PacketReader& pr) +{ + NSECRecordContent* ret=new NSECRecordContent(); + pr.xfrLabel(ret->d_next); + string bitmap; + pr.xfrBlob(bitmap); + + // 00 06 20 00 00 00 00 03 -> NS RRSIG NSEC ( 2, 46, 47 ) counts from left + if(bitmap.empty()) + return ret; + + if(bitmap.size() < 2) + throw MOADNSException("NSEC record with impossibly small bitmap"); + + for(unsigned int n = 0; n+1 < bitmap.size();) { + unsigned int window=static_cast(bitmap[n++]); + unsigned int len=static_cast(bitmap[n++]); + + // end if zero padding and ensure packet length + if(window == 0&&len == 0) break; + if(n+len>bitmap.size()) + throw MOADNSException("NSEC record with bitmap length > packet length"); + + for(unsigned int k=0; k < len; k++) { + uint8_t val=bitmap[n++]; + for(int bit = 0; bit < 8 ; ++bit , val>>=1) + if(val & 1) { + ret->d_set.insert((7-bit) + 8*(k) + 256*window); + } + } + } + return ret; +} + +string NSECRecordContent::getZoneRepresentation() const +{ + string ret; + RecordTextWriter rtw(ret); + rtw.xfrLabel(d_next); + + for(set::const_iterator i=d_set.begin(); i!=d_set.end(); ++i) { + ret+=" "; + ret+=NumberToType(*i); + } + + return ret; +} + +////// begin of NSEC3 + +void NSEC3RecordContent::report(void) +{ + regist(1, 50, &make, &make, "NSEC3"); +} + +DNSRecordContent* NSEC3RecordContent::make(const string& content) +{ + return new NSEC3RecordContent(content); +} + +NSEC3RecordContent::NSEC3RecordContent(const string& content, const string& zone) : DNSRecordContent(50) +{ + RecordTextReader rtr(content, zone); + rtr.xfr8BitInt(d_algorithm); + rtr.xfr8BitInt(d_flags); + rtr.xfr16BitInt(d_iterations); + + rtr.xfrHexBlob(d_salt); + rtr.xfrBase32HexBlob(d_nexthash); + + while(!rtr.eof()) { + uint16_t type; + rtr.xfrType(type); + d_set.insert(type); + } +} + +void NSEC3RecordContent::toPacket(DNSPacketWriter& pw) +{ + pw.xfr8BitInt(d_algorithm); + pw.xfr8BitInt(d_flags); + pw.xfr16BitInt(d_iterations); + pw.xfr8BitInt(d_salt.length()); + pw.xfrBlob(d_salt); + + pw.xfr8BitInt(d_nexthash.length()); + pw.xfrBlob(d_nexthash); + + uint8_t res[34]; + set::const_iterator i; + int oldWindow = -1; + int window = 0; + int len = 0; + string tmp; + + for(i=d_set.begin(); i != d_set.end(); ++i){ + uint16_t bit = (*i)%256; + window = static_cast((*i) / 256); + + if (window != oldWindow) { + if (oldWindow > -1) { + res[0] = static_cast(oldWindow); + res[1] = static_cast(len); + tmp.assign(res, res+len+2); + pw.xfrBlob(tmp); + } + memset(res, 0, 34); + oldWindow = window; + } + res[2+bit/8] |= 1 << (7-(bit%8)); + len=1+bit/8; + } + + res[0] = static_cast(window); + res[1] = static_cast(len); + tmp.assign(res, res+len+2); + pw.xfrBlob(tmp); +} + +NSEC3RecordContent::DNSRecordContent* NSEC3RecordContent::make(const DNSRecord &dr, PacketReader& pr) +{ + NSEC3RecordContent* ret=new NSEC3RecordContent(); + pr.xfr8BitInt(ret->d_algorithm); + pr.xfr8BitInt(ret->d_flags); + pr.xfr16BitInt(ret->d_iterations); + uint8_t len; + pr.xfr8BitInt(len); + pr.xfrBlob(ret->d_salt, len); + + pr.xfr8BitInt(len); + + pr.xfrBlob(ret->d_nexthash, len); + + string bitmap; + pr.xfrBlob(bitmap); + + // 00 06 20 00 00 00 00 03 -> NS RRSIG NSEC ( 2, 46, 47 ) counts from left + + if(bitmap.empty()) + return ret; + + if(bitmap.size() < 2) + throw MOADNSException("NSEC3 record with impossibly small bitmap"); + + for(unsigned int n = 0; n+1 < bitmap.size();) { + unsigned int window=static_cast(bitmap[n++]); + unsigned int len=static_cast(bitmap[n++]); + + // end if zero padding and ensure packet length + if(window == 0&&len == 0) break; + if(n+len>bitmap.size()) + throw MOADNSException("NSEC record with bitmap length > packet length"); + + for(unsigned int k=0; k < len; k++) { + uint8_t val=bitmap[n++]; + for(int bit = 0; bit < 8 ; ++bit , val>>=1) + if(val & 1) { + ret->d_set.insert((7-bit) + 8*(k) + 256*window); + } + } + } + return ret; +} + +string NSEC3RecordContent::getZoneRepresentation() const +{ + string ret; + RecordTextWriter rtw(ret); + rtw.xfr8BitInt(d_algorithm); + rtw.xfr8BitInt(d_flags); + rtw.xfr16BitInt(d_iterations); + + rtw.xfrHexBlob(d_salt); + rtw.xfrBase32HexBlob(d_nexthash); + for(set::const_iterator i=d_set.begin(); i!=d_set.end(); ++i) { + ret+=" "; + ret+=NumberToType(*i); + } + + return ret; +} + + +void NSEC3PARAMRecordContent::report(void) +{ + regist(1, 51, &make, &make, "NSEC3PARAM"); +} + +DNSRecordContent* NSEC3PARAMRecordContent::make(const string& content) +{ + return new NSEC3PARAMRecordContent(content); +} + +NSEC3PARAMRecordContent::NSEC3PARAMRecordContent(const string& content, const string& zone) : DNSRecordContent(51) +{ + RecordTextReader rtr(content, zone); + rtr.xfr8BitInt(d_algorithm); + rtr.xfr8BitInt(d_flags); + rtr.xfr16BitInt(d_iterations); + rtr.xfrHexBlob(d_salt); +} + +void NSEC3PARAMRecordContent::toPacket(DNSPacketWriter& pw) +{ + pw.xfr8BitInt(d_algorithm); + pw.xfr8BitInt(d_flags); + pw.xfr16BitInt(d_iterations); + pw.xfr8BitInt(d_salt.length()); + // cerr<<"salt: '"<d_algorithm); + pr.xfr8BitInt(ret->d_flags); + pr.xfr16BitInt(ret->d_iterations); + pr.xfr8BitInt(ret->d_saltlength); + pr.xfrHexBlob(ret->d_salt); + + return ret; +} + +string NSEC3PARAMRecordContent::getZoneRepresentation() const +{ + string ret; + RecordTextWriter rtw(ret); + rtw.xfr8BitInt(d_algorithm); + rtw.xfr8BitInt(d_flags); + rtw.xfr16BitInt(d_iterations); + rtw.xfrHexBlob(d_salt); + return ret; +} + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/ntservice.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/ntservice.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/ntservice.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/ntservice.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,302 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 PowerDNS.COM 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 +*/ + +/*! +\file ntservice.cpp +\brief This file contains the NTService class implementation. +*/ + +#include "utility.hh" +#include +#include +#include "logger.hh" +#include "ntservice.hh" + +#define L theL("pdns") + + +// Default constructor. +NTService::NTService( void ) +{ + m_runningAsService = false; + m_errorCode = 0; + m_statusCode = 0; + m_serviceStatusHandle = NULL; +} + + +// Destructor. +NTService::~NTService( void ) +{ +} + + +// Returns whether the program is running as a service. +bool NTService::isRunningAsService( void ) +{ + return m_runningAsService; +} + + +// Registers the service. +bool NTService::registerService( const std::string & description, bool registerLog ) +{ + std::stringstream str; + HKEY key, pkey; + SC_HANDLE sc; + char temp[ 512 ]; + DWORD flags; + + sc = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); + if ( sc == NULL ) + return false; // Could not open the Service Control Manager. + + GetModuleFileName( NULL, temp, sizeof( temp )); + + str << temp << " --ntservice"; + + if ( CreateService( + sc, + getServiceName().c_str(), + getServiceName().c_str(), + SERVICE_ALL_ACCESS, + SERVICE_WIN32_OWN_PROCESS, + SERVICE_AUTO_START, + SERVICE_ERROR_NORMAL, + str.str().c_str(), + NULL, + NULL, + NULL, + NULL, + NULL ) == NULL ) + { + if(GetLastError() != ERROR_SERVICE_EXISTS) + return false; // Don't we all like functions with 43 billion parameters? + } + CloseServiceHandle( sc ); + + str.str( "" ); + + // Set description. + if ( !description.empty()) + { + str << "SYSTEM\\CurrentControlSet\\Services\\" << getServiceName(); + + if ( RegCreateKey( HKEY_LOCAL_MACHINE, str.str().c_str(), &key ) != ERROR_SUCCESS ) + return false; + + if ( RegSetValueEx( key, "Description", 0, REG_SZ, reinterpret_cast< const unsigned char * >( description.c_str()), description.length()) != ERROR_SUCCESS ) + { + RegCloseKey( key ); + return false; + } + + RegCloseKey( key ); + } + + // Register event log. + if ( registerLog ) + { + str.str( "" ); + + str << "SYSTEM\\CurrentControlSet\\Services\\Eventlog\\Application\\" << getServiceName(); + if ( RegCreateKey( HKEY_LOCAL_MACHINE, str.str().c_str(), &pkey ) != ERROR_SUCCESS ) + return false; + + flags = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE; + + if ( RegSetValueEx( pkey, "TypesSupported", 0, REG_DWORD, reinterpret_cast< const unsigned char * >( &flags ), sizeof( flags )) != ERROR_SUCCESS ) + { + RegCloseKey( pkey ); + return false; + } + + // For the message file this function assumes %SystemRoot%\\System32\\msg.dll + str.str( "" ); + + char path[ MAX_PATH ]; + GetCurrentDirectory( sizeof( path ), path ); + + // FIXME: This really should be: str << path << "\\" << getServiceName() << "msg.dll"; + str << path << "\\Eventlogger.dll"; + if ( RegSetValueEx( pkey, "EventMessageFile", 0, REG_SZ, reinterpret_cast< const unsigned char * >( str.str().c_str()), str.str().length()) != ERROR_SUCCESS ) + { + RegCloseKey( pkey ); + return false; + } + + RegCloseKey( pkey ); + } + + return true; +} + + +// Calls the control handler. +void WINAPI NTService::s_ctrlHandler( DWORD controlCode ) +{ + NTService::instance()->ctrlHandler( controlCode ); +} + + +// Calls the service's main function. +void WINAPI NTService::s_serviceMain( DWORD argc, LPTSTR *argv ) +{ + // IEEEEUUWWWW!! + + NTService::instance()->m_serviceStatusHandle = RegisterServiceCtrlHandler( NTService::instance()->getServiceName().c_str(), s_ctrlHandler ); + if ( NTService::instance()->m_serviceStatusHandle == 0 ) + { + // Could not register service ctrl handler. + return; + } + + NTService::instance()->setStatus( SERVICE_START_PENDING ); + // Initialize. + if ( !NTService::instance()->init()) + { + NTService::instance()->setStatus( SERVICE_STOPPED, -1 ); + return; + } + + NTService::instance()->setStatus( SERVICE_RUNNING ); + + // Run. + NTService::instance()->main( argc, argv ); + + NTService::instance()->setStatus( SERVICE_STOP_PENDING ); + + // Shut down. + NTService::instance()->shutdown(); + + NTService::instance()->setStatus( SERVICE_STOPPED ); +} + + +// Sets the service's status. +void NTService::setStatus( DWORD status, DWORD error ) +{ + SERVICE_STATUS stat; + + if ( !m_serviceStatusHandle ) + return; + + stat.dwServiceType = SERVICE_WIN32_OWN_PROCESS; + stat.dwCurrentState = status; + stat.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN; + stat.dwWin32ExitCode = ( error ? ERROR_SERVICE_SPECIFIC_ERROR : NO_ERROR ); + stat.dwServiceSpecificExitCode = error; + stat.dwCheckPoint = 0; + stat.dwWaitHint = 0; + + SetServiceStatus( m_serviceStatusHandle, &stat ); +} + + +// Starts the service. +int NTService::start( int argc, char *argv[], bool asService ) +{ + int res = 0; + char name[ 128 ]; + + strncpy( name, getServiceName().c_str(), sizeof( name )); + + SERVICE_TABLE_ENTRY entries[] = + { + { name, s_serviceMain }, + { NULL, NULL } + }; + + if ( asService ) + { + // Run as service. + m_runningAsService = true; + + if ( StartServiceCtrlDispatcher( entries )) + return 0; // Success! + + // StartServiceCtrlDispatcher() failed, check if we should run as a normal + // console program. + if ( GetLastError() != ERROR_FAILED_SERVICE_CONTROLLER_CONNECT ) + return -1; + + } + + DLOG( L << "Running as a normal (console) program." << endl ); + + // Run as normal (console) program. + m_runningAsService = false; + + if ( !init()) + return -1; // Could not initialize. + + // Run. + res = main( argc, argv ); + + shutdown(); + + return res; +} + + +// Stops the service. +bool NTService::stop( void ) +{ + if ( !isRunningAsService()) + exit( 0 ); + + setStatus( SERVICE_STOPPED, 0 ); + + return true; +} + + +// Unregister service. +bool NTService::unregisterService( void ) +{ + HKEY key; + SC_HANDLE sc, svc; + + sc = OpenSCManager( NULL, NULL, SC_MANAGER_ALL_ACCESS ); + if ( sc == NULL ) + return false; + + svc = OpenService( sc, getServiceName().c_str(), DELETE ); + if ( GetLastError() != ERROR_SERVICE_DOES_NOT_EXIST ) + { + if ( svc == NULL ) + { + CloseServiceHandle( sc ); + return false; + } + + DeleteService( svc ); + CloseServiceHandle( svc ); + CloseServiceHandle( sc ); + } + + if ( RegOpenKeyEx( HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application", 0, KEY_WRITE, &key ) != ERROR_SUCCESS ) + return false; + + RegDeleteKey( key, getServiceName().c_str()); + + RegCloseKey( key ); + + return true; +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/ntservice.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/ntservice.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/ntservice.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/ntservice.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,102 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 PowerDNS.COM 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 +*/ + +/*! +\file ntservice.hh +\brief This file contains the NTService class specification. +*/ + +#ifndef NTSERVICE_HH +#define NTSERVICE_HH +#include "utility.hh" + +#include +#include "singleton.hh" + + +//! The NTService class is responsible for giving the program NT Service characteristics. +class NTService : public Singleton< NTService > +{ +private: + //! Is the program running as a NT Service? + bool m_runningAsService; + + //! Service status handle. + SERVICE_STATUS_HANDLE m_serviceStatusHandle; + +protected: + //! Status code. + DWORD m_statusCode; + + //! Error code. + DWORD m_errorCode; + + //! Main function. + virtual int main( int argc, char *argv[] ) + { + return 0; + } + + //! Control handler. + virtual void ctrlHandler( DWORD controlCode ) + { + } + + //! Sets the service's status and error codes. + void setStatus( DWORD status, DWORD error = 0 ); + +public: + //! Default constructor. + NTService( void ); + + //! Destructor. + virtual ~NTService( void ); + + //! Starts the service. + int start( int argc, char *argv[], bool asService = true ); + + //! Control handler (calls NTService::ctrlHandler()). + static void WINAPI s_ctrlHandler( DWORD controlCode ); + + //! Service main (calls NTService::main()). + static void WINAPI s_serviceMain( DWORD argc, LPTSTR *argv ); + + //! Returns the name of the service. + virtual std::string getServiceName( void ) + { + return "NTService"; + } + + //! Returns whether the program is running as a service or not. + bool isRunningAsService( void ); + + //! Registers the service with the system. + bool registerService( const std::string & description, bool registerLog = true ); + + //! Unregisters the service. + bool unregisterService( void ); + + //! Stops the service. + bool stop( void ); + +}; + + +#endif // NTSERVICE_H + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/pdns_hw.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/pdns_hw.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/pdns_hw.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/pdns_hw.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,20 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "namespaces.hh" +int main() +{ + ostringstream str; + str << "Everything is ok!"<< boost::lexical_cast("") <<"\n"; + exit(0); +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/pdns_recursor.1 pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/pdns_recursor.1 --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/pdns_recursor.1 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/pdns_recursor.1 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,285 @@ +'\" t +.\" Title: pdns_recursor +.\" Author: [see the "AUTHOR" section] +.\" Generator: DocBook XSL Stylesheets v1.75.2 +.\" Date: 07/08/2012 +.\" Manual: \ \& +.\" Source: \ \& 3.0 +.\" Language: English +.\" +.TH "PDNS_RECURSOR" "1" "07/08/2012" "\ \& 3\&.0" "\ \&" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +pdns_recursor \- high\-performance, simple and secure recursing nameserver +.SH "SYNOPSIS" +.sp +\fIpdns_recursor\fR [\-\-daemon] [\-\-local\-address] [\-\-help, \-h] [\-\-allow\-from] +.SH "DESCRIPTION" +.sp +pdns_recursor(1) is a high performance, simple and secure recursing nameserver\&. It currently powers over two million internet connections\&. +.sp +The recursor is configured via a configuration file, but each item in that file can be overridden on the command line\&. +.sp +This manpage lists the core set of features needed to get the PowerDNS recursor working, for full and up to date details head to \m[blue]\fBhttp://doc\&.powerdns\&.com/built\-in\-recursor\&.html\fR\m[] +.SH "EXAMPLES" +.sp +To listen on 1\&.2\&.3\&.4 and allow the 1\&.2\&.3\&.0/8 subnet to recurse, and run as a daemon, execute: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# pdns_recursor \-\-local\-address=1\&.2\&.3\&.4 \-\-allow\-from=1\&.2\&.3\&.0/8 \-\-daemon +.fi +.if n \{\ +.RE +.\} +.sp +To stop the recursor by hand, run: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# rec_control quit +.fi +.if n \{\ +.RE +.\} +.sp +.if n \{\ +.RS 4 +.\} +.nf +Alternatively, use the init\&.d script provided\&. +.fi +.if n \{\ +.RE +.\} +.SH "OPTIONS" +.sp +For authoritative listing of options, consult the documentation referenced above\&. +.PP +\-\-aaaa\-additional\-processing +.RS 4 +turn on to do AAAA additional processing (slow) +.RE +.PP +\-\-allow\-from +.RS 4 +If set, only allow these comma separated netmasks to recurse +.RE +.PP +\-\-auth\-can\-lower\-ttl +.RS 4 +Authoritative zones can transmit a TTL value that is lower than that specified in the parent zone\&. This is called a +\fIdelegation inconsistency\fR\&. To follow RFC 2181 paragraphs 5\&.2 and 5\&.4 to the letter, enable this feature\&. This will mean a slight deterioration of performance, and it will not solve any problems, but does make the recursor more standards compliant\&. Not recommended unless you have to tick an +\fIRFC 2181 compliant\fR +box\&. Off by default\&. +.RE +.PP +\-\-auth\-zones +.RS 4 +Comma separated list of +\fIzonename=filename\fR +pairs\&. Zones read from these files are served authoritatively\&. Example: auth\-zones= ds9a\&.nl=/var/zones/ds9a\&.nl, powerdns\&.com=/var/zones/powerdns\&.com\&. Available since 3\&.1\&. +.RE +.PP +\-\-chroot +.RS 4 +switch to chroot jail +.RE +.PP +\-\-client\-tcp\-timeout +.RS 4 +Timeout in seconds when talking to TCP clients +.RE +.PP +\-\-config\-dir +.RS 4 +Location of configuration directory (recursor\&.conf) +.RE +.PP +\-\-daemon +.RS 4 +Operate as a daemon +.RE +.PP +\-\-delegation\-only +.RS 4 +Which domains we only accept delegations from +.RE +.PP +\-\-entropy\-source +.RS 4 +Where to read new entropy from, defaults to /dev/urandom\&. +.RE +.PP +\-\-export\-etc\-hosts +.RS 4 +If set, this flag will export the host names and IP addresses mentioned in /etc/hosts\&. Available since 3\&.1\&. +.RE +.PP +\-\-fork +.RS 4 +If set, fork the daemon for possible double performance +.RE +.PP +\-\-forward\-zones +.RS 4 +Comma separated list of +\fIzonename=IP\fR +pairs\&. Queries for zones listed here will be forwarded to the IP address listed\&. forward\-zones= ds9a\&.nl=213\&.244\&.168\&.210, powerdns\&.com=127\&.0\&.0\&.1\&. Available since 3\&.1\&. For more details, see the manual\&. +.RE +.PP +\-\-forward\-zones\-file +.RS 4 +listed here will be forwarded to the IP address listed\&. One zone per line, like: ds9a\&.nl=213\&.244\&.168\&.210 Available since 3\&.1\&.5\&. For more details, see the manual\&. +.RE +.PP +\-\-hint\-file +.RS 4 +If set, load root hints from this file +.RE +.PP +\-\-local\-address +.RS 4 +IP addresses to listen on, separated by spaces or commas +.RE +.PP +\-\-local\-port +.RS 4 +port to listen on +.RE +.PP +\-\-log\-common\-errors +.RS 4 +If we should log rather common errors +.RE +.PP +\-\-max\-cache\-entries +.RS 4 +If set, maximum number of entries in the main cache +.RE +.PP +\-\-max\-negative\-ttl +.RS 4 +maximum number of seconds to keep a negative cached entry in memory +.RE +.PP +\-\-max\-tcp\-clients +.RS 4 +Maximum number of simultaneous TCP clients +.RE +.PP +\-\-max\-tcp\-per\-client +.RS 4 +If set, maximum number of TCP sessions per client (IP address) +.RE +.PP +\-\-query\-local\-address +.RS 4 +Source IP address for sending queries +.RE +.PP +\-\-query\-local\-address6 +.RS 4 +Send out local IPv6 queries from this address\&. Disabled by default, which also disables outgoing IPv6 support\&. A useful setting is +\fI::0\fR\&. +.RE +.PP +\-\-quiet +.RS 4 +Suppress logging of questions and answers +.RE +.PP +\-\-remotes\-ringbuffer\-entries +.RS 4 +maximum number of packets to store statistics for +.RE +.PP +\-\-server\-id +.RS 4 +Returned when queried for +\fIserver\&.id\fR +TXT, defaults to hostname +.RE +.PP +\-\-serve\-rfc1918 +.RS 4 +On by default, this makes the server authoritatively aware of: 10\&.in\-addr\&.arpa, 168\&.192\&.in\-addr\&.arpa and 16\-31\&.172\&.in\-addr\&.arpa, which saves load on the AS112 servers\&. Individual parts of these zones can still be loaded or forwarded\&. +.RE +.PP +\-\-setgid +.RS 4 +If set, change group id to this gid for more security +.RE +.PP +\-\-setuid +.RS 4 +If set, change user id to this uid for more security +.RE +.PP +\-\-single\-socket +.RS 4 +If set, only use a single socket for outgoing queries +.RE +.PP +\-\-socket\-dir +.RS 4 +Where the controlsocket will live +.RE +.PP +\-\-spoof\-nearmiss\-max +.RS 4 +If non\-zero, assume spoofing after this many near misses +.RE +.PP +\-\-trace +.RS 4 +if we should output heaps of logging +.RE +.PP +\-\-version\-string +.RS 4 +string reported on version\&.pdns or version\&.bind +.RE +.SH "BUGS" +.sp +None known\&. File new ones at \m[blue]\fBhttp://wiki\&.powerdns\&.com\fR\m[]\&. +.SH "AUTHOR" +.sp +Written by PowerDNS\&.COM BV, bert hubert, <\m[blue]\fBbert\&.hubert@netherlabs\&.nl\fR\m[]\&\s-2\u[1]\d\s+2> +.SH "RESOURCES" +.sp +Website: \m[blue]\fBhttp://wiki\&.powerdns\&.com\fR\m[], \m[blue]\fBhttp://www\&.powerdns\&.com\fR\m[] +.SH "SEE ALSO" +.sp +rec_control(1) +.SH "COPYING" +.sp +Copyright \(co 2006 PowerDNS\&.COM BV\&. Free use of this software is granted under the terms of the GNU General Public License (GPL) version 2\&. +.SH "NOTES" +.IP " 1." 4 +bert.hubert@netherlabs.nl +.RS 4 +\%mailto:bert.hubert@netherlabs.nl +.RE diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/pdns_recursor.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/pdns_recursor.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/pdns_recursor.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/pdns_recursor.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,2083 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2003 - 2012 PowerDNS.COM 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 +*/ + +#ifndef WIN32 +# include +# include +# include +#else + #include "ntservice.hh" + #include "recursorservice.hh" +#endif // WIN32 + +#include + +#include +#include "recpacketcache.hh" +#include "utility.hh" +#include "dns_random.hh" +#include +#include +#include +#include +#include "recursor_cache.hh" +#include "cachecleaner.hh" +#include +#include +#include +#include "misc.hh" +#include "mtasker.hh" +#include +#include "arguments.hh" +#include "syncres.hh" +#include +#include +#include "sstuff.hh" +#include +#include +#include +#include +#include +#include +#include +#include "dnsparser.hh" +#include "dnswriter.hh" +#include "dnsrecords.hh" +#include "zoneparser-tng.hh" +#include "rec_channel.hh" +#include "logger.hh" +#include "iputils.hh" +#include "mplexer.hh" +#include "config.h" +#include "lua-recursor.hh" + +#ifndef RECURSOR +#include "statbag.hh" +StatBag S; +#endif + +__thread FDMultiplexer* t_fdm; +__thread unsigned int t_id; +unsigned int g_maxTCPPerClient; +unsigned int g_networkTimeoutMsec; +bool g_logCommonErrors; +__thread shared_ptr* t_pdl; +__thread RemoteKeeper* t_remotes; + +RecursorControlChannel s_rcc; // only active in thread 0 + +// for communicating with our threads +struct ThreadPipeSet +{ + int writeToThread; + int readToThread; + int writeFromThread; + int readFromThread; +}; + +vector g_pipes; // effectively readonly after startup + +SyncRes::domainmap_t* g_initialDomainMap; // new threads needs this to be setup + +#include "namespaces.hh" + +__thread MemRecursorCache* t_RC; +__thread RecursorPacketCache* t_packetCache; +RecursorStats g_stats; +bool g_quiet; + +bool g_weDistributeQueries; // if true, only 1 thread listens on the incoming query sockets + +static __thread NetmaskGroup* t_allowFrom; +static NetmaskGroup* g_initialAllowFrom; // new thread needs to be setup with this + +NetmaskGroup* g_dontQuery; +string s_programname="pdns_recursor"; + +typedef vector tcpListenSockets_t; +tcpListenSockets_t g_tcpListenSockets; // shared across threads, but this is fine, never written to from a thread. All threads listen on all sockets +int g_tcpTimeout; +unsigned int g_maxMThreads; +struct timeval g_now; // timestamp, updated (too) frequently +map g_listenSocketsAddresses; // is shared across all threads right now + +__thread MT_t* MT; // the big MTasker + +unsigned int g_numThreads; + +#define LOCAL_NETS "127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10" + +//! used to send information to a newborn mthread +struct DNSComboWriter { + DNSComboWriter(const char* data, uint16_t len, const struct timeval& now) : d_mdp(data, len), d_now(now), + d_tcp(false), d_socket(-1) + {} + MOADNSParser d_mdp; + void setRemote(const ComboAddress* sa) + { + d_remote=*sa; + } + + void setSocket(int sock) + { + d_socket=sock; + } + + string getRemote() const + { + return d_remote.toString(); + } + + struct timeval d_now; + ComboAddress d_remote; + bool d_tcp; + int d_socket; + shared_ptr d_tcpConnection; +}; + + +ArgvMap &arg() +{ + static ArgvMap theArg; + return theArg; +} + + +void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var); + +// -1 is error, 0 is timeout, 1 is success +int asendtcp(const string& data, Socket* sock) +{ + PacketID pident; + pident.sock=sock; + pident.outMSG=data; + + t_fdm->addWriteFD(sock->getHandle(), handleTCPClientWritable, pident); + string packet; + + int ret=MT->waitEvent(pident, &packet, g_networkTimeoutMsec); + + if(!ret || ret==-1) { // timeout + t_fdm->removeWriteFD(sock->getHandle()); + } + else if(packet.size() !=data.size()) { // main loop tells us what it sent out, or empty in case of an error + return -1; + } + return ret; +} + +void handleTCPClientReadable(int fd, FDMultiplexer::funcparam_t& var); + +// -1 is error, 0 is timeout, 1 is success +int arecvtcp(string& data, int len, Socket* sock) +{ + data.clear(); + PacketID pident; + pident.sock=sock; + pident.inNeeded=len; + t_fdm->addReadFD(sock->getHandle(), handleTCPClientReadable, pident); + + int ret=MT->waitEvent(pident,&data, g_networkTimeoutMsec); + if(!ret || ret==-1) { // timeout + t_fdm->removeReadFD(sock->getHandle()); + } + else if(data.empty()) {// error, EOF or other + return -1; + } + + return ret; +} + +vector g_localQueryAddresses4, g_localQueryAddresses6; +const ComboAddress g_local4("0.0.0.0"), g_local6("::"); + +//! pick a random query local address +ComboAddress getQueryLocalAddress(int family, uint16_t port) +{ + ComboAddress ret; + if(family==AF_INET) { + if(g_localQueryAddresses4.empty()) + ret = g_local4; + else + ret = g_localQueryAddresses4[dns_random(g_localQueryAddresses4.size())]; + ret.sin4.sin_port = htons(port); + } + else { + if(g_localQueryAddresses6.empty()) + ret = g_local6; + else + ret = g_localQueryAddresses6[dns_random(g_localQueryAddresses6.size())]; + + ret.sin6.sin6_port = htons(port); + } + return ret; +} + +void handleUDPServerResponse(int fd, FDMultiplexer::funcparam_t&); + +void setSocketBuffer(int fd, int optname, uint32_t size) +{ + uint32_t psize=0; + socklen_t len=sizeof(psize); + + if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) { + L< socks_t; + socks_t d_socks; + + // returning -1 means: temporary OS error (ie, out of files), -2 means OS error + int getSocket(const ComboAddress& toaddr, int* fd) + { + *fd=makeClientSocket(toaddr.sin4.sin_family); + if(*fd < 0) // temporary error - receive exception otherwise + return -1; + + if(connect(*fd, (struct sockaddr*)(&toaddr), toaddr.getSocklen()) < 0) { + int err = errno; + // returnSocket(*fd); + Utility::closesocket(*fd); + if(err==ENETUNREACH) // Seth "My Interfaces Are Like A Yo Yo" Arnold special + return -2; + return -1; + } + + d_socks.insert(*fd); + d_numsocks++; + return 0; + } + + void returnSocket(int fd) + { + socks_t::iterator i=d_socks.find(fd); + if(i==d_socks.end()) { + throw AhuException("Trying to return a socket (fd="+lexical_cast(fd)+") not in the pool"); + } + returnSocketLocked(i); + } + + // return a socket to the pool, or simply erase it + void returnSocketLocked(socks_t::iterator& i) + { + if(i==d_socks.end()) { + throw AhuException("Trying to return a socket not in the pool"); + } + try { + t_fdm->removeReadFD(*i); + } + catch(FDMultiplexerException& e) { + // we sometimes return a socket that has not yet been assigned to t_fdm + } + Utility::closesocket(*i); + + d_socks.erase(i++); + --d_numsocks; + } + + // returns -1 for errors which might go away, throws for ones that won't + static int makeClientSocket(int family) + { + int ret=(int)socket(family, SOCK_DGRAM, 0); + Utility::setCloseOnExec(ret); + + if(ret < 0 && errno==EMFILE) // this is not a catastrophic error + return ret; + + if(ret<0) + throw AhuException("Making a socket for resolver: "+stringerror()); + + + int tries=10; + while(--tries) { + uint16_t port; + + if(tries==1) // fall back to kernel 'random' + port = 0; + else + port = 1025 + dns_random(64510); + + ComboAddress sin=getQueryLocalAddress(family, port); // does htons for us + + if (::bind(ret, (struct sockaddr *)&sin, sin.getSocklen()) >= 0) + break; + } + if(!tries) + throw AhuException("Resolver binding to local query client socket: "+stringerror()); + + Utility::setNonBlocking(ret); + return ret; + } +}; + +static __thread UDPClientSocks* t_udpclientsocks; + +/* these two functions are used by LWRes */ +// -2 is OS error, -1 is error that depends on the remote, > 0 is success +int asendto(const char *data, int len, int flags, + const ComboAddress& toaddr, uint16_t id, const string& domain, uint16_t qtype, int* fd) +{ + + PacketID pident; + pident.domain = domain; + pident.remote = toaddr; + pident.type = qtype; + + // see if there is an existing outstanding request we can chain on to, using partial equivalence function + pair chain=MT->d_waiters.equal_range(pident, PacketIDBirthdayCompare()); + + for(; chain.first != chain.second; chain.first++) { + if(chain.first->key.fd > -1) { // don't chain onto existing chained waiter! + /* + cerr<<"Orig: "<key.domain<<", "<key.remote.toString()<<", id="<key.id + <<", count="<key.chain.size()<<", origfd: "<key.fd<key.chain.insert(id); // we can chain + *fd=-1; // gets used in waitEvent / sendEvent later on + return 1; + } + } + + int ret=t_udpclientsocks->getSocket(toaddr, fd); + if(ret < 0) + return ret; + + pident.fd=*fd; + pident.id=id; + + t_fdm->addReadFD(*fd, handleUDPServerResponse, pident); + ret = send(*fd, data, len, 0); + + int tmp = errno; + + if(ret < 0) + t_udpclientsocks->returnSocket(*fd); + + errno = tmp; // this is for logging purposes only + return ret; +} + +// -1 is error, 0 is timeout, 1 is success +int arecvfrom(char *data, int len, int flags, const ComboAddress& fromaddr, int *d_len, + uint16_t id, const string& domain, uint16_t qtype, int fd, struct timeval* now) +{ + static optional nearMissLimit; + if(!nearMissLimit) + nearMissLimit=::arg().asNum("spoof-nearmiss-max"); + + PacketID pident; + pident.fd=fd; + pident.id=id; + pident.domain=domain; + pident.type = qtype; + pident.remote=fromaddr; + + string packet; + int ret=MT->waitEvent(pident, &packet, g_networkTimeoutMsec, now); + + if(ret > 0) { + if(packet.empty()) // means "error" + return -1; + + *d_len=(int)packet.size(); + memcpy(data,packet.c_str(),min(len,*d_len)); + if(*nearMissLimit && pident.nearMisses > *nearMissLimit) { + L< "<<*nearMissLimit<<") bogus answers for '"<= 0) + t_udpclientsocks->returnSocket(fd); + } + return ret; +} + + +string s_pidfname; +static void writePid(void) +{ + ofstream of(s_pidfname.c_str(), std::ios_base::app); + if(of) + of<< Utility::getpid() < tcpClientCounts_t; +tcpClientCounts_t __thread* t_tcpClientCounts; + +TCPConnection::TCPConnection(int fd, const ComboAddress& addr) : d_remote(addr), d_fd(fd) +{ + ++s_currentConnections; + (*t_tcpClientCounts)[d_remote]++; +} + +TCPConnection::~TCPConnection() +{ + if(Utility::closesocket(d_fd) < 0) + unixDie("closing socket for TCPConnection"); + if(t_tcpClientCounts->count(d_remote) && !(*t_tcpClientCounts)[d_remote]--) + t_tcpClientCounts->erase(d_remote); + --s_currentConnections; +} + +AtomicCounter TCPConnection::s_currentConnections; +void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var); + +void updateRcodeStats(int res) +{ + switch(res) { + case RCode::ServFail: + g_stats.servFails++; + break; + case RCode::NXDomain: + g_stats.nxDomains++; + break; + case RCode::NoError: + g_stats.noErrors++; + break; + } +} + +void startDoResolve(void *p) +{ + DNSComboWriter* dc=(DNSComboWriter *)p; + + try { + uint32_t maxanswersize= dc->d_tcp ? 65535 : 512; + EDNSOpts edo; + if(getEDNSOpts(dc->d_mdp, &edo)) { + maxanswersize = min(edo.d_packetsize, (uint16_t) (dc->d_tcp ? 65535 : 1680)); + } + + vector ret; + vector packet; + + DNSPacketWriter pw(packet, dc->d_mdp.d_qname, dc->d_mdp.d_qtype, dc->d_mdp.d_qclass); + + pw.getHeader()->aa=0; + pw.getHeader()->ra=1; + pw.getHeader()->qr=1; + pw.getHeader()->tc=0; + pw.getHeader()->id=dc->d_mdp.d_header.id; + pw.getHeader()->rd=dc->d_mdp.d_header.rd; + + SyncRes sr(dc->d_now); + if(!g_quiet) + L<getTid()<<"] " << (dc->d_tcp ? "TCP " : "") << "question for '"<d_mdp.d_qname<<"|" + <d_mdp.d_qtype)<<"' from "<getRemote()<getTid()); + if(!dc->d_mdp.d_header.rd) + sr.setCacheOnly(); + + int res; + + bool variableAnswer = false; + // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve + if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer)) { + res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret); + + if(t_pdl->get()) { + if(res == RCode::NoError) { + vector::const_iterator i; + for(i=ret.begin(); i!=ret.end(); ++i) + if(i->qtype.getCode() == dc->d_mdp.d_qtype && i->d_place == DNSResourceRecord::ANSWER) + break; + if(i == ret.end()) + (*t_pdl)->nodata(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer); + } + else if(res == RCode::NXDomain) + (*t_pdl)->nxdomain(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer); + + (*t_pdl)->postresolve(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer); + } + } + + + + uint32_t minTTL=std::numeric_limits::max(); + if(res < 0) { + pw.getHeader()->rcode=RCode::ServFail; + // no commit here, because no record + g_stats.servFails++; + } + else { + pw.getHeader()->rcode=res; + updateRcodeStats(res); + + if(ret.size()) { + orderAndShuffle(ret); + + for(vector::const_iterator i=ret.begin(); i!=ret.end(); ++i) { + pw.startRecord(i->qname, i->qtype.getCode(), i->ttl, i->qclass, (DNSPacketWriter::Place)i->d_place); + minTTL = min(minTTL, i->ttl); + if(i->qtype.getCode() == QType::A) { // blast out A record w/o doing whole dnswriter thing + uint32_t ip=0; + IpToU32(i->content, &ip); + pw.xfr32BitInt(htonl(ip)); + } else { + shared_ptr drc(DNSRecordContent::mastermake(i->qtype.getCode(), i->qclass, i->content)); + drc->toPacket(pw); + } + if(pw.size() > maxanswersize) { + pw.rollback(); + if(i->d_place==DNSResourceRecord::ANSWER) // only truncate if we actually omitted parts of the answer + pw.getHeader()->tc=1; + goto sendit; // need to jump over pw.commit + } + } + + pw.commit(); + } + } + sendit:; + if(!dc->d_tcp) { + sendto(dc->d_socket, (const char*)&*packet.begin(), packet.size(), 0, (struct sockaddr *)(&dc->d_remote), dc->d_remote.getSocklen()); + if(!SyncRes::s_nopacketcache && !variableAnswer ) { + t_packetCache->insertResponsePacket(string((const char*)&*packet.begin(), packet.size()), g_now.tv_sec, + min(minTTL, + (pw.getHeader()->rcode == RCode::ServFail) ? SyncRes::s_packetcacheservfailttl : SyncRes::s_packetcachettl + ) + ); + } + } + else { + char buf[2]; + buf[0]=packet.size()/256; + buf[1]=packet.size()%256; + + Utility::iovec iov[2]; + + iov[0].iov_base=(void*)buf; iov[0].iov_len=2; + iov[1].iov_base=(void*)&*packet.begin(); iov[1].iov_len = packet.size(); + + int ret=Utility::writev(dc->d_socket, iov, 2); + bool hadError=true; + + if(ret == 0) + L<getRemote()<getRemote()<<": "<< strerror(errno) <getRemote()<<" for "<d_mdp.d_qname<<" (size="<< (2 + packet.size()) <<", sent "<d_socket = -1; + } + else { + dc->d_tcpConnection->state=TCPConnection::BYTE0; + Utility::gettimeofday(&g_now, 0); // needs to be updated + t_fdm->addReadFD(dc->d_socket, handleRunningTCPQuestion, dc->d_tcpConnection); + t_fdm->setReadTTD(dc->d_socket, g_now, g_tcpTimeout); + } + } + + if(!g_quiet) { + L<getTid()<<"] answer to "<<(dc->d_mdp.d_header.rd?"":"non-rd ")<<"question '"<d_mdp.d_qname<<"|"<d_mdp.d_qtype); + L<<"': "<ancount)<<" answers, "<arcount)<<" additional, took "<d_mdp.d_qname<<", "<getMaxStackUsage(), g_stats.maxMThreadStackUsage); +} + +void makeControlChannelSocket(int processNum=-1) +{ + string sockname=::arg()["socket-dir"]+"/pdns_recursor"; + if(processNum >= 0) + sockname += "."+lexical_cast(processNum); + sockname+=".controlsocket"; + s_rcc.listen(sockname); + +#ifndef WIN32 + int sockowner = -1; + int sockgroup = -1; + + if (!::arg().isEmpty("socket-group")) + sockgroup=::arg().asGid("socket-group"); + if (!::arg().isEmpty("socket-owner")) + sockowner=::arg().asUid("socket-owner"); + + if (sockgroup > -1 || sockowner > -1) { + if(chown(sockname.c_str(), sockowner, sockgroup) < 0) { + unixDie("Failed to chown control socket"); + } + } + + // do mode change if socket-mode is given + if(!::arg().isEmpty("socket-mode")) { + mode_t sockmode=::arg().asMode("socket-mode"); + chmod(sockname.c_str(), sockmode); + } +#endif +} + +void handleRunningTCPQuestion(int fd, FDMultiplexer::funcparam_t& var) +{ + shared_ptr conn=any_cast >(var); + + if(conn->state==TCPConnection::BYTE0) { + int bytes=recv(conn->getFD(), conn->data, 2, 0); + if(bytes==1) + conn->state=TCPConnection::BYTE1; + if(bytes==2) { + conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1]; + conn->bytesread=0; + conn->state=TCPConnection::GETQUESTION; + } + if(!bytes || bytes < 0) { + t_fdm->removeReadFD(fd); + return; + } + } + else if(conn->state==TCPConnection::BYTE1) { + int bytes=recv(conn->getFD(), conn->data+1, 1, 0); + if(bytes==1) { + conn->state=TCPConnection::GETQUESTION; + conn->qlen=(((unsigned char)conn->data[0]) << 8)+ (unsigned char)conn->data[1]; + conn->bytesread=0; + } + if(!bytes || bytes < 0) { + if(g_logCommonErrors) + L<d_remote.toString() <<" disconnected after first byte"<removeReadFD(fd); + return; + } + } + else if(conn->state==TCPConnection::GETQUESTION) { + int bytes=recv(conn->getFD(), conn->data + conn->bytesread, conn->qlen - conn->bytesread, 0); + if(!bytes || bytes < 0) { + L<d_remote.toString() <<" disconnected while reading question body"<removeReadFD(fd); + return; + } + conn->bytesread+=bytes; + if(conn->bytesread==conn->qlen) { + t_fdm->removeReadFD(fd); // should no longer awake ourselves when there is data to read + + DNSComboWriter* dc=0; + try { + dc=new DNSComboWriter(conn->data, conn->qlen, g_now); + } + catch(MOADNSException &mde) { + g_stats.clientParseError++; + if(g_logCommonErrors) + L<d_remote.toString() <d_tcpConnection = conn; // carry the torch + dc->setSocket(conn->getFD()); // this is the only time a copy is made of the actual fd + dc->d_tcp=true; + dc->setRemote(&conn->d_remote); + if(dc->d_mdp.d_header.qr) { + delete dc; + L<makeThread(startDoResolve, dc); // deletes dc, will set state to BYTE0 again + return; + } + } + } +} + +//! Handle new incoming TCP connection +void handleNewTCPQuestion(int fd, FDMultiplexer::funcparam_t& ) +{ + ComboAddress addr; + socklen_t addrlen=sizeof(addr); + int newsock=(int)accept(fd, (struct sockaddr*)&addr, &addrlen); + if(newsock>0) { + if(MT->numProcesses() > g_maxMThreads) { + g_stats.overCapacityDrops++; + Utility::closesocket(newsock); + return; + } + + t_remotes->addRemote(addr); + if(t_allowFrom && !t_allowFrom->match(&addr)) { + if(!g_quiet) + L<getTid()<<"] dropping TCP query from "<count(addr) && (*t_tcpClientCounts)[addr] >= g_maxTCPPerClient) { + g_stats.tcpClientOverflow++; + Utility::closesocket(newsock); // don't call TCPConnection::closeAndCleanup here - did not enter it in the counts yet! + return; + } + + Utility::setNonBlocking(newsock); + shared_ptr tc(new TCPConnection(newsock, addr)); + tc->state=TCPConnection::BYTE0; + + t_fdm->addReadFD(tc->getFD(), handleRunningTCPQuestion, tc); + + struct timeval now; + Utility::gettimeofday(&now, 0); + t_fdm->setReadTTD(tc->getFD(), now, g_tcpTimeout); + } +} + +string* doProcessUDPQuestion(const std::string& question, const ComboAddress& fromaddr, int fd) +{ + ++g_stats.qcounter; + + string response; + try { + uint32_t age; + if(!SyncRes::s_nopacketcache && t_packetCache->getResponsePacket(question, g_now.tv_sec, &response, &age)) { + if(!g_quiet) + L<= sizeof(struct dnsheader)) { + struct dnsheader dh; + memcpy(&dh, response.c_str(), sizeof(dh)); + updateRcodeStats(dh.rcode); + } + g_stats.avgLatencyUsec=(uint64_t)((1-0.0001)*g_stats.avgLatencyUsec + 0); // we assume 0 usec + return 0; + } + } + catch(std::exception& e) { + L<numProcesses() > g_maxMThreads) { + g_stats.overCapacityDrops++; + return 0; + } + + DNSComboWriter* dc = new DNSComboWriter(question.c_str(), question.size(), g_now); + dc->setSocket(fd); + dc->setRemote(&fromaddr); + + dc->d_tcp=false; + MT->makeThread(startDoResolve, (void*) dc); // deletes dc + return 0; +} + +void handleNewUDPQuestion(int fd, FDMultiplexer::funcparam_t& var) +{ + int len; + char data[1500]; + ComboAddress fromaddr; + socklen_t addrlen=sizeof(fromaddr); + + if((len=recvfrom(fd, data, sizeof(data), 0, (sockaddr *)&fromaddr, &addrlen)) >= 0) { + t_remotes->addRemote(fromaddr); + + if(t_allowFrom && !t_allowFrom->match(&fromaddr)) { + if(!g_quiet) + L<getTid()<<"] dropping UDP query from "<qr) { + if(g_logCommonErrors) + L< > > deferredAdd_t; +deferredAdd_t deferredAdd; + +void makeTCPServerSockets() +{ + int fd; + vectorlocals; + stringtok(locals,::arg()["local-address"]," ,"); + + if(locals.empty()) + throw AhuException("No local address specified"); + + for(vector::const_iterator i=locals.begin();i!=locals.end();++i) { + ServiceTuple st; + st.port=::arg().asNum("local-port"); + parseService(*i, st); + + ComboAddress sin; + + memset((char *)&sin,0, sizeof(sin)); + sin.sin4.sin_family = AF_INET; + if(!IpToU32(st.host, (uint32_t*)&sin.sin4.sin_addr.s_addr)) { + sin.sin6.sin6_family = AF_INET6; + if(makeIPv6sockaddr(st.host, &sin.sin6) < 0) + throw AhuException("Unable to resolve local address for TCP server on '"+ st.host +"'"); + } + + fd=socket(sin.sin6.sin6_family, SOCK_STREAM, 0); + Utility::setCloseOnExec(fd); + + if(fd<0) + throw AhuException("Making a TCP server socket for resolver: "+stringerror()); + + int tmp=1; + if(setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) { + L<= 0) { + if(i==locals.begin()) + L<locals; + stringtok(locals,::arg()["local-address"]," ,"); + + if(locals.empty()) + throw AhuException("No local address specified"); + + if(::arg()["local-address"]=="0.0.0.0") { + L<::const_iterator i=locals.begin();i!=locals.end();++i) { + ServiceTuple st; + st.port=::arg().asNum("local-port"); + parseService(*i, st); + + ComboAddress sin; + + memset(&sin, 0, sizeof(sin)); + sin.sin4.sin_family = AF_INET; + if(!IpToU32(st.host.c_str() , (uint32_t*)&sin.sin4.sin_addr.s_addr)) { + sin.sin6.sin6_family = AF_INET6; + if(makeIPv6sockaddr(st.host, &sin.sin6) < 0) + throw AhuException("Unable to resolve local address for UDP server on '"+ st.host +"'"); + } + + int fd=socket(sin.sin4.sin_family, SOCK_DGRAM, 0); + Utility::setCloseOnExec(fd); + + if(fd < 0) { + throw AhuException("Making a UDP server socket for resolver: "+netstringerror()); + } + + setSocketReceiveBuffer(fd, 200000); + sin.sin4.sin_port = htons(st.port); + + int socklen=sin.sin4.sin_family==AF_INET ? sizeof(sin.sin4) : sizeof(sin.sin6); + if (::bind(fd, (struct sockaddr *)&sin, socklen)<0) + throw AhuException("Resolver binding to server socket on port "+ lexical_cast(st.port) +" for "+ st.host+": "+stringerror()); + + Utility::setNonBlocking(fd); + + deferredAdd.push_back(make_pair(fd, handleNewUDPQuestion)); + g_listenSocketsAddresses[fd]=sin; // this is written to only from the startup thread, not from the workers + if(sin.sin4.sin_family == AF_INET) + L<cacheHits + t_RC->cacheMisses) && SyncRes::s_queries && SyncRes::s_outqueries) { // this only runs once thread 0 has had hits + uint64_t cacheHits = broadcastAccFunction(pleaseGetCacheHits); + uint64_t cacheMisses = broadcastAccFunction(pleaseGetCacheMisses); + + L<(pleaseGetCacheSize)<< " cache entries, "<< + broadcastAccFunction(pleaseGetNegCacheSize)<<" negative entries, "<< + (int)((cacheHits*100.0)/(cacheHits+cacheMisses))<<"% cache hits"<(pleaseGetThrottleSize) <<", ns speeds: " + << broadcastAccFunction(pleaseGetNsSpeedsSize)<(pleaseGetConcurrentQueries)<<" queries running, "<(pleaseGetPacketCacheSize) << + " packet cache entries, "<<(int)(100.0*broadcastAccFunction(pleaseGetPacketCacheHits)/SyncRes::s_queries) << "% packet cache hits"< (time_t)(5 + t_id)) { + DTime dt; + dt.setTimeval(now); + t_RC->doPrune(); // this function is local to a thread, so fine anyhow + t_packetCache->doPruneTo(::arg().asNum("max-packetcache-entries") / g_numThreads); + + pruneCollection(t_sstorage->negcache, ::arg().asNum("max-cache-entries") / (g_numThreads * 10), 200); + + if(!((cleanCounter++)%40)) { // this is a full scan! + time_t limit=now.tv_sec-300; + for(SyncRes::nsspeeds_t::iterator i = t_sstorage->nsSpeeds.begin() ; i!= t_sstorage->nsSpeeds.end(); ) + if(i->second.stale(limit)) + t_sstorage->nsSpeeds.erase(i++); + else + ++i; + } +// L< 1800) { + doStats(); + last_stat=time(0); + } + } + + if(now.tv_sec - last_rootupdate > 7200) { + SyncRes sr(now); + sr.setDoEDNS0(true); + vector ret; + + sr.setNoCache(); + int res=sr.beginResolve(".", QType(QType::NS), 1, ret); + if(!res) { + L<func = func; + tmsg->wantAnswer = true; + if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) + unixDie("write to thread pipe returned wrong size or error"); + + string* resp; + if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp)) + unixDie("read from thread pipe returned wrong size or error"); + + if(resp) { +// cerr <<"got response: " << *resp << endl; + delete resp; + } + } +} +void distributeAsyncFunction(const pipefunc_t& func) +{ + static unsigned int counter; + unsigned int target = 1 + (++counter % (g_pipes.size()-1)); + // cerr<<"Sending to: "<func = func; + tmsg->wantAnswer = false; + + if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) + unixDie("write to thread pipe returned wrong size or error"); + +} + +void handlePipeRequest(int fd, FDMultiplexer::funcparam_t& var) +{ + ThreadMSG* tmsg; + + if(read(fd, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) { // fd == readToThread + unixDie("read from thread pipe returned wrong size or error"); + } + + void *resp = tmsg->func(); + if(tmsg->wantAnswer) + if(write(g_pipes[t_id].writeFromThread, &resp, sizeof(resp)) != sizeof(resp)) + unixDie("write to thread pipe returned wrong size or error"); + + delete tmsg; +} + +template void *voider(const boost::function& func) +{ + return func(); +} + +vector& operator+=(vector&a, const vector& b) +{ + a.insert(a.end(), b.begin(), b.end()); + return a; +} + +template T broadcastAccFunction(const boost::function& func, bool skipSelf) +{ + unsigned int n = 0; + T ret=T(); + BOOST_FOREACH(ThreadPipeSet& tps, g_pipes) + { + if(n++ == t_id) { + if(!skipSelf) { + T* resp = (T*)func(); // don't write to ourselves! + if(resp) { + //~ cerr <<"got direct: " << *resp << endl; + ret += *resp; + delete resp; + } + } + continue; + } + + ThreadMSG* tmsg = new ThreadMSG(); + tmsg->func = boost::bind(voider, func); + tmsg->wantAnswer = true; + + if(write(tps.writeToThread, &tmsg, sizeof(tmsg)) != sizeof(tmsg)) + unixDie("write to thread pipe returned wrong size or error"); + + + T* resp; + if(read(tps.readFromThread, &resp, sizeof(resp)) != sizeof(resp)) + unixDie("read from thread pipe returned wrong size or error"); + + if(resp) { + //~ cerr <<"got response: " << *resp << endl; + ret += *resp; + delete resp; + } + } + return ret; +} + +template string broadcastAccFunction(const boost::function& fun, bool skipSelf); // explicit instantiation +template uint64_t broadcastAccFunction(const boost::function& fun, bool skipSelf); // explicit instantiation +template vector broadcastAccFunction(const boost::function *()>& fun, bool skipSelf); // explicit instantiation + +void handleRCC(int fd, FDMultiplexer::funcparam_t& var) +{ + string remote; + string msg=s_rcc.recv(&remote); + RecursorControlParser rcp; + RecursorControlParser::func_t* command; + string answer=rcp.getAnswer(msg, &command); + try { + s_rcc.send(answer, &remote); + command(); + } + catch(std::exception& e) { + L<(&var); + // cerr<<"handleTCPClientReadable called for fd "<inNeeded: "<inNeeded<<", "<sock->getHandle()< buffer(new char[pident->inNeeded]); + + int ret=recv(fd, buffer.get(), pident->inNeeded,0); + if(ret > 0) { + pident->inMSG.append(&buffer[0], &buffer[ret]); + pident->inNeeded-=ret; + if(!pident->inNeeded) { + // cerr<<"Got entire load of "<inMSG.size()<<" bytes"<inMSG; + + t_fdm->removeReadFD(fd); + MT->sendEvent(pid, &msg); + } + else { + // cerr<<"Still have "<inNeeded<<" left to go"<removeReadFD(fd); // pident might now be invalid (it isn't, but still) + string empty; + MT->sendEvent(tmp, &empty); // this conveys error status + } +} + +void handleTCPClientWritable(int fd, FDMultiplexer::funcparam_t& var) +{ + PacketID* pid=any_cast(&var); + int ret=send(fd, pid->outMSG.c_str() + pid->outPos, pid->outMSG.size() - pid->outPos,0); + if(ret > 0) { + pid->outPos+=ret; + if(pid->outPos==pid->outMSG.size()) { + PacketID tmp=*pid; + t_fdm->removeWriteFD(fd); + MT->sendEvent(tmp, &tmp.outMSG); // send back what we sent to convey everything is ok + } + } + else { // error or EOF + PacketID tmp(*pid); + t_fdm->removeWriteFD(fd); + string sent; + MT->sendEvent(tmp, &sent); // we convey error status by sending empty string + } +} + +// resend event to everybody chained onto it +void doResends(MT_t::waiters_t::iterator& iter, PacketID resend, const string& content) +{ + if(iter->key.chain.empty()) + return; + // cerr<<"doResends called!\n"; + for(PacketID::chain_t::iterator i=iter->key.chain.begin(); i != iter->key.chain.end() ; ++i) { + resend.fd=-1; + resend.id=*i; + // cerr<<"\tResending "<returnSocket(fd); + string empty; + + MT_t::waiters_t::iterator iter=MT->d_waiters.find(pid); + if(iter != MT->d_waiters.end()) + doResends(iter, pid, empty); + + MT->sendEvent(pid, &empty); // this denotes error (does lookup again.. at least L1 will be hot) + return; + } + + dnsheader dh; + memcpy(&dh, data, sizeof(dh)); + + if(dh.qr) { + PacketID pident; + pident.remote=fromaddr; + pident.id=dh.id; + pident.fd=fd; + if(!dh.qdcount) { // UPC, Nominum, very old BIND on FormErr, NSD + pident.domain.clear(); + pident.type = 0; + } + else { + try { + pident.domain=questionExpand(data, len, pident.type); // don't copy this from above - we need to do the actual read + } + catch(std::exception& e) { + g_stats.serverParseError++; // won't be fed to lwres.cc, so we have to increment + L<d_waiters.find(pident); + if(iter != MT->d_waiters.end()) { + doResends(iter, pident, packet); + } + + retryWithName: + + if(!MT->sendEvent(pident, &packet)) { + // we do a full scan for outstanding queries on unexpected answers. not too bad since we only accept them on the right port number, which is hard enough to guess + for(MT_t::waiters_t::iterator mthread=MT->d_waiters.begin(); mthread!=MT->d_waiters.end(); ++mthread) { + if(pident.fd==mthread->key.fd && mthread->key.remote==pident.remote && mthread->key.type == pident.type && + pdns_iequals(pident.domain, mthread->key.domain)) { + mthread->key.nearMisses++; + } + + // be a bit paranoid here since we're weakening our matching + if(pident.domain.empty() && !mthread->key.domain.empty() && !pident.type && mthread->key.type && + pident.id == mthread->key.id && mthread->key.remote == pident.remote) { + // cerr<<"Empty response, rest matches though, sending to a waiter"<key.domain; + pident.type = mthread->key.type; + goto retryWithName; // note that this only passes on an error, lwres will still reject the packet + } + } + g_stats.unexpectedCount++; // if we made it here, it really is an unexpected answer + if(g_logCommonErrors) { + L<d_waiters.size()<<" waiters"<= 0) { + t_udpclientsocks->returnSocket(fd); + } + } + else + L<second(); + return ret; + } + catch(FDMultiplexerException &fe) { + L<reset(); + L<(new RecursorLua(fname)); + } + } + catch(std::exception& e) { + L<::const_iterator begin, vector::const_iterator end) +{ + if(begin != end) + ::arg().set("lua-dns-script") = *begin; + + return broadcastAccFunction(doReloadLuaScript); +} + +void* recursorThread(void*); + +void* pleaseSupplantACLs(NetmaskGroup *ng) +{ + t_allowFrom = ng; + return 0; +} + +void parseACLs() +{ + static bool l_initialized; + + if(l_initialized) { // only reload configuration file on second call + string configname=::arg()["config-dir"]+"/recursor.conf"; + cleanSlashes(configname); + + if(!::arg().preParseFile(configname.c_str(), "allow-from-file")) + L<addMask(line); + } + L<size() <<" allow-from ranges from file '"<<::arg()["allow-from-file"]<<"' - overriding 'allow-from' setting"< ips; + stringtok(ips, ::arg()["allow-from"], ", "); + + L<::const_iterator i = ips.begin(); i!= ips.end(); ++i) { + allowFrom->addMask(*i); + if(i!=ips.begin()) + L<= 0) + theL().setFacility(val); + else + L< ips; + stringtok(ips, ::arg()["dont-query"], ", "); + ips.push_back("0.0.0.0"); + ips.push_back("::"); + + L<::const_iterator i = ips.begin(); i!= ips.end(); ++i) { + g_dontQuery->addMask(*i); + if(i!=ips.begin()) + L< addrs; + if(!::arg()["query-local-address6"].empty()) { + SyncRes::s_doIPv6=true; + L< 1 ? forks : -1); + + int newgid=0; + if(!::arg()["setgid"].empty()) + newgid=Utility::makeGidNumeric(::arg()["setgid"]); + int newuid=0; + if(!::arg()["setuid"].empty()) + newuid=Utility::makeUidNumeric(::arg()["setuid"]); + + if (!::arg()["chroot"].empty()) { + if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) { + L<domainmap = g_initialDomainMap; + t_allowFrom = g_initialAllowFrom; + t_udpclientsocks = new UDPClientSocks(); + t_tcpClientCounts = new tcpClientCounts_t(); + primeHints(); + + t_packetCache = new RecursorPacketCache(); + + L<d_followRFC2181=::arg().mustDo("auth-can-lower-ttl"); + t_pdl = new shared_ptr(); + + try { + if(!::arg()["lua-dns-script"].empty()) { + *t_pdl = shared_ptr(new RecursorLua(::arg()["lua-dns-script"])); + L<remotes.resize(::arg().asNum("remotes-ringbuffer-entries") / g_numThreads); + + if(!t_remotes->remotes.empty()) + memset(&t_remotes->remotes[0], 0, t_remotes->remotes.size() * sizeof(RemoteKeeper::remotes_t::value_type)); + + + MT=new MTasker(::arg().asNum("stack-size")); + + PacketID pident; + + t_fdm=getMultiplexer(); + if(!t_id) + L<getName() << "' multiplexer"<addReadFD(g_pipes[t_id].readToThread, handlePipeRequest); + + if(!g_weDistributeQueries || !t_id) // if we distribute queries, only t_id = 0 listens + for(deferredAdd_t::const_iterator i=deferredAdd.begin(); i!=deferredAdd.end(); ++i) + t_fdm->addReadFD(i->first, i->second); + + if(!t_id) { + t_fdm->addReadFD(s_rcc.d_fd, handleRCC); // control channel + } + + unsigned int maxTcpClients=::arg().asNum("max-tcp-clients"); + + bool listenOnTCP(true); + + counter=0; // used to periodically execute certain tasks + for(;;) { + while(MT->schedule(&g_now)); // MTasker letting the mthreads do their thing + + if(!(counter%500)) { + MT->makeThread(houseKeeping, 0); + } + + if(!(counter%55)) { + typedef vector > expired_t; + expired_t expired=t_fdm->getTimeouts(g_now); + + for(expired_t::iterator i=expired.begin() ; i != expired.end(); ++i) { + shared_ptr conn=any_cast >(i->second); + if(g_logCommonErrors) + L<d_remote.toString() <removeReadFD(i->first); + } + } + + counter++; + + if(!t_id && statsWanted) { + doStats(); + } + + Utility::gettimeofday(&g_now, 0); + t_fdm->run(&g_now); + // 'run' updates g_now for us + + if(listenOnTCP) { + if(TCPConnection::getCurrentConnections() > maxTcpClients) { // shutdown, too many connections + for(tcpListenSockets_t::iterator i=g_tcpListenSockets.begin(); i != g_tcpListenSockets.end(); ++i) + t_fdm->removeReadFD(*i); + listenOnTCP=false; + } + } + else { + if(TCPConnection::getCurrentConnections() <= maxTcpClients) { // reenable + for(tcpListenSockets_t::iterator i=g_tcpListenSockets.begin(); i != g_tcpListenSockets.end(); ++i) + t_fdm->addReadFD(*i, handleNewTCPQuestion); + listenOnTCP=true; + } + } + } +} +catch(AhuException &ae) { + L<start( argc, argv, ::arg().mustDo( "ntservice" )); +#endif + + } + catch(AhuException &ae) { + L< /dev/null` +} + + +doPC ping +NOTRUNNING=$? + +case "$1" in + status) + if test "$NOTRUNNING" = "0" + then + echo "running" + else + echo "not running" + fi + ;; + + stop) + echo -n "Stopping PowerDNS recursing nameserver: " + if test "$NOTRUNNING" = "0" + then + doPC quit + echo $ret + else + echo "not running" + fi + ;; + + + force-stop) + echo -n "Stopping PowerDNS recursing nameserver: " + killall -v -9 pdns_server + echo "killed" + ;; + + start) + echo -n "Starting PowerDNS recursing nameserver: " + if test "$NOTRUNNING" = "0" + then + echo "already running" + else + $pdns_server --daemon + if test "$?" = "0" + then + echo "started" + fi + fi + ;; + + force-reload | restart) + echo -n "Restarting PowerDNS recursing nameserver: " + echo -n stopping and waiting.. + doPC quit + sleep 3 + echo done + $0 start + ;; + + monitor) + if test "$NOTRUNNING" = "0" + then + echo "already running" + else + $pdns_server --daemon=no --quiet=no --control-console --loglevel=9 + fi + ;; + + *) + echo pdns [start\|stop\|force-reload\|restart\|status\|monitor] + + ;; +esac + + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/portsmplexer.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/portsmplexer.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/portsmplexer.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/portsmplexer.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,168 @@ +#if defined(__sun__) && defined(__svr4__) +#include +#include +#endif +#include +#include "mplexer.hh" +#include "sstuff.hh" +#include + +#include "misc.hh" +#include +#include "syncres.hh" + +#include "namespaces.hh" +#include "namespaces.hh" + +class PortsFDMultiplexer : public FDMultiplexer +{ +public: + PortsFDMultiplexer(); + virtual ~PortsFDMultiplexer() + { + close(d_portfd); + } + + virtual int run(struct timeval* tv); + + virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter); + virtual void removeFD(callbackmap_t& cbmap, int fd); + string getName() + { + return "solaris completion ports"; + } +private: + int d_portfd; + boost::shared_array d_pevents; + static int s_maxevents; // not a hard maximum +}; + + +static FDMultiplexer* makePorts() +{ + return new PortsFDMultiplexer(); +} + +static struct PortsRegisterOurselves +{ + PortsRegisterOurselves() { + FDMultiplexer::getMultiplexerMap().insert(make_pair(0, &makePorts)); // priority 0! + } +} doItPorts; + + +int PortsFDMultiplexer::s_maxevents=1024; +PortsFDMultiplexer::PortsFDMultiplexer() : d_pevents(new port_event_t[s_maxevents]) +{ + d_portfd=port_create(); // not hard max + if(d_portfd < 0) + throw FDMultiplexerException("Setting up port: "+stringerror()); +} + +void PortsFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter) +{ + accountingAddFD(cbmap, fd, toDo, parameter); + + if(port_associate(d_portfd, PORT_SOURCE_FD, fd, (&cbmap == &d_readCallbacks) ? POLLIN : POLLOUT, 0) < 0) { + cbmap.erase(fd); + throw FDMultiplexerException("Adding fd to port set: "+stringerror()); + } +} + +void PortsFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) +{ + if(!cbmap.erase(fd)) + throw FDMultiplexerException("Tried to remove unlisted fd "+lexical_cast(fd)+ " from multiplexer"); + + if(port_dissociate(d_portfd, PORT_SOURCE_FD, fd) < 0 && errno != ENOENT) // it appears under some circumstances, ENOENT will be returned, without this being an error. Apache has this same "fix" + throw FDMultiplexerException("Removing fd from port set: "+stringerror()); +} + +int PortsFDMultiplexer::run(struct timeval* now) +{ + if(d_inrun) { + throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); + } + + struct timespec timeout; + timeout.tv_sec=0; timeout.tv_nsec=500000000; + unsigned int numevents=1; + int ret= port_getn(d_portfd, d_pevents.get(), min(PORT_MAX_LIST, s_maxevents), &numevents, &timeout); + + /* port_getn has an unusual API - (ret == -1, errno == ETIME) can + mean partial success; you must check (*numevents) in this case + and process anything in there, otherwise you'll never see any + events from that object again. We don't care about pure timeouts + (ret == -1, errno == ETIME, *numevents == 0) so we don't bother + with that case. */ + if(ret == -1 && errno!=ETIME) { + if(errno!=EINTR) + throw FDMultiplexerException("completion port_getn returned error: "+stringerror()); + // EINTR is not really an error + gettimeofday(now,0); + return 0; + } + gettimeofday(now,0); + if(!numevents) // nothing + return 0; + + d_inrun=true; + + for(unsigned int n=0; n < numevents; ++n) { + d_iter=d_readCallbacks.find(d_pevents[n].portev_object); + + if(d_iter != d_readCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + if(d_readCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object, + POLLIN, 0) < 0) + throw FDMultiplexerException("Unable to add fd back to ports (read): "+stringerror()); + continue; // so we don't find ourselves as writable again + } + + d_iter=d_writeCallbacks.find(d_pevents[n].portev_object); + + if(d_iter != d_writeCallbacks.end()) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + if(d_writeCallbacks.count(d_pevents[n].portev_object) && port_associate(d_portfd, PORT_SOURCE_FD, d_pevents[n].portev_object, + POLLOUT, 0) < 0) + throw FDMultiplexerException("Unable to add fd back to ports (write): "+stringerror()); + } + + } + + d_inrun=false; + return 0; +} + +#if 0 +void acceptData(int fd, boost::any& parameter) +{ + cout<<"Have data on fd "<(parameter); + string packet; + IPEndpoint rem; + sock->recvFrom(packet, rem); + cout<<"Received "< + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/qtype.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/qtype.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/qtype.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/qtype.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,147 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2007 PowerDNS.COM 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 "utility.hh" +#include "dns.hh" +#include +#include +#include +#include +#include +#include "qtype.hh" +#include "misc.hh" +#include "lock.hh" + + +pthread_mutex_t QType::uninitlock = PTHREAD_MUTEX_INITIALIZER; +bool QType::uninit=true; +vector QType::names; + +void QType::insert(const char *p, int n) +{ + names.push_back(make_pair(string(p),n)); +} + + +QType::QType() +{ + Lock l(&uninitlock); + if(uninit) + { + uninit=false; + insert("A",1); + insert("NS",2); + insert("CNAME",5); + insert("SOA",6); + insert("MR",9); + insert("PTR",12); + insert("HINFO",13); + insert("MX",15); + insert("TXT",16); + insert("RP",17); + insert("AFSDB", 18); + insert("SIG",24); + insert("KEY",25); + insert("AAAA",28); + insert("LOC",29); + insert("SRV",33); + insert("CERT", 37); + insert("A6",38); + insert("NAPTR",35); + insert("DS", 43); + insert("SSHFP", 44); + insert("RRSIG", 46); + insert("NSEC", 47); + insert("DNSKEY", 48); + insert("NSEC3", 50); + insert("NSEC3PARAM", 51); + insert("TLSA",52); + insert("SPF",99); + insert("IXFR",251); + insert("AXFR",252); + insert("ANY",255); + insert("URL",256); + insert("MBOXFW",257); + insert("CURL",258); + insert("ADDR",259); + insert("DLV",32769); + } +} + +uint16_t QType::getCode() const +{ + return code; +} + +const string QType::getName() const +{ + vector::iterator pos; + for(pos=names.begin();possecond==code) + return pos->first; + + return "#"+itoa(code); +} + +QType &QType::operator=(uint16_t n) +{ + code=n; + return *this; +} + +int QType::chartocode(const char *p) +{ + static QType qt; + vector::iterator pos; + for(pos=names.begin();posfirst==p) + return pos->second; + + if(*p=='#') { + return atoi(p+1); + } + + if(boost::starts_with(p, "TYPE")) + return atoi(p+4); + + return 0; +} + +QType &QType::operator=(const char *p) +{ + code=chartocode(p); + return *this; +} + +bool QType::operator==(const QType &comp) const +{ + return(comp.code==code); +} + +QType &QType::operator=(const string &s) +{ + code=chartocode(s.c_str()); + return *this; +} + + +QType::QType(uint16_t n) +{ + QType(); + code=n; +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/qtype.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/qtype.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/qtype.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/qtype.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,97 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 PowerDNS.COM 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 +*/ +#ifndef QTYPE_HH +#define QTYPE_HH +/* (C) 2002 POWERDNS.COM BV */ +// $Id: qtype.hh 2579 2012-04-26 11:28:04Z peter $ +#include +#include +#include +#include "namespaces.hh" + +/** The QType class is meant to deal easily with the different kind of resource types, like 'A', 'NS', + * 'CNAME' etcetera. These types have both a name and a number. This class can seamlessly move between + * them. Use it like this: + +\code + QType t; + t="CNAME"; + cout< + void serialize(Archive &ar, const unsigned int version) + { + ar & code; + } + + bool operator==(const QType &) const; //!< equality operator + + const string getName() const; //!< Get a string representation of this type + uint16_t getCode() const; //!< Get the integer representation of this type + + static int chartocode(const char *p); //!< convert a character string to a code +// more solaris fun +#undef DS + enum typeenum {A=1,NS=2,CNAME=5,SOA=6, MR=9, PTR=12,HINFO=13,MX=15,TXT=16,RP=17,AFSDB=18,KEY=25,AAAA=28,LOC=29,SRV=33,NAPTR=35, KX=36, + CERT=37,OPT=41, DS=43, SSHFP=44, IPSECKEY=45, RRSIG=46, NSEC=47, DNSKEY=48, DHCID=49, NSEC3=50, NSEC3PARAM=51, + TLSA=52, SPF=99, TSIG=250, AXFR=252, IXFR=251, ANY=255, URL=256, MBOXFW=257, CURL=258, ADDR=259, DLV=32769} types; + typedef pair namenum; + static vector names; +private: + uint16_t code; + void insert(const char *p, int n); + + static pthread_mutex_t uninitlock; + static bool uninit; +}; + +struct QClass +{ + enum QClassEnum {IN=1, CHAOS=3}; +}; +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/randomhelper.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/randomhelper.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/randomhelper.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/randomhelper.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,36 @@ +#include "misc.hh" +#include "logger.hh" +#include +#include +#include +#include "dns_random.hh" + +void seedRandom(const string& source) +{ + L< +#include +#include +#include "base32.hh" +#include "base64.hh" +#include "namespaces.hh" + +RecordTextReader::RecordTextReader(const string& str, const string& zone) : d_string(str), d_zone(zone), d_pos(0), d_end(str.size()) +{ +} + +void RecordTextReader::xfr48BitInt(uint64_t &val) +{ + xfr64BitInt(val); +} + +void RecordTextReader::xfr64BitInt(uint64_t &val) +{ + skipSpaces(); + + if(!isdigit(d_string.at(d_pos))) + throw RecordTextException("expected digits at position "+lexical_cast(d_pos)+" in '"+d_string+"'"); + + char *endptr; + unsigned long ret=strtoull(d_string.c_str() + d_pos, &endptr, 10); + val=ret; + + d_pos = endptr - d_string.c_str(); +} + + +void RecordTextReader::xfr32BitInt(uint32_t &val) +{ + skipSpaces(); + + if(!isdigit(d_string.at(d_pos))) + throw RecordTextException("expected digits at position "+lexical_cast(d_pos)+" in '"+d_string+"'"); + + char *endptr; + unsigned long ret=strtoul(d_string.c_str() + d_pos, &endptr, 10); + val=ret; + + d_pos = endptr - d_string.c_str(); +} + +void RecordTextReader::xfrTime(uint32_t &val) +{ + struct tm tm; + memset(&tm, 0, sizeof(tm)); + + string tmp; + xfrLabel(tmp); // ends on number, so this works + + sscanf(tmp.c_str(), "%04d%02d%02d" "%02d%02d%02d", + &tm.tm_year, &tm.tm_mon, &tm.tm_mday, + &tm.tm_hour, &tm.tm_min, &tm.tm_sec); + + tm.tm_year-=1900; + tm.tm_mon-=1; + val=(uint32_t)Utility::timegm(&tm); +} + +void RecordTextReader::xfrIP(uint32_t &val) +{ + skipSpaces(); + + if(!isdigit(d_string.at(d_pos))) + throw RecordTextException("while parsing IP address, expected digits at position "+lexical_cast(d_pos)+" in '"+d_string+"'"); + + uint32_t octet=0; + val=0; + char count=0; + + for(;;) { + if(d_string.at(d_pos)=='.') { + val<<=8; + val+=octet; + octet=0; + count++; + if(count > 3) + break; + } + else if(isdigit(d_string.at(d_pos))) { + octet*=10; + octet+=d_string.at(d_pos) - '0'; + if(octet > 255) + throw RecordTextException("unable to parse IP address"); + } + else if(dns_isspace(d_string.at(d_pos))) + break; + else { + throw RecordTextException(string("unable to parse IP address, strange character: ")+d_string.at(d_pos)); + } + d_pos++; + if(d_pos == d_string.length()) + break; + } + if(count<=3) { + val<<=8; + val+=octet; + } + val=ntohl(val); +} + + +bool RecordTextReader::eof() +{ + return d_pos==d_end; +} + +void RecordTextReader::xfr16BitInt(uint16_t &val) +{ + uint32_t tmp; + xfr32BitInt(tmp); + val=tmp; + if(val!=tmp) + throw RecordTextException("Overflow reading 16 bit integer from record content"); // fixme improve +} + +void RecordTextReader::xfr8BitInt(uint8_t &val) +{ + uint32_t tmp; + xfr32BitInt(tmp); + val=tmp; + if(val!=tmp) + throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve +} + +// this code should leave all the escapes around +void RecordTextReader::xfrLabel(string& val, bool) +{ + skipSpaces(); + val.clear(); + val.reserve(d_end - d_pos); + + const char* strptr=d_string.c_str(); + string::size_type begin_pos = d_pos; + while(d_pos < d_end) { + if(strptr[d_pos]!='\r' && dns_isspace(strptr[d_pos])) + break; + + d_pos++; + } + val.append(strptr+begin_pos, strptr+d_pos); + + if(val.empty()) + val=d_zone; + else if(!d_zone.empty()) { + char last=val[val.size()-1]; + + if(last =='.') + val.resize(val.size()-1); + else if(last != '.' && !isdigit(last)) // don't add zone to IP address + val+="."+d_zone; + } +} + +static bool isbase64(char c) +{ + if(dns_isspace(c)) + return true; + if(c >= '0' && c <= '9') + return true; + if(c >= 'a' && c <= 'z') + return true; + if(c >= 'A' && c <= 'Z') + return true; + if(c=='+' || c=='/' || c=='=') + return true; + return false; +} + +void RecordTextReader::xfrBlob(string& val, int) +{ + skipSpaces(); + int pos=(int)d_pos; + const char* strptr=d_string.c_str(); + while(d_pos < d_end && isbase64(strptr[d_pos])) + d_pos++; + + string tmp; + tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); + boost::erase_all(tmp," "); + val.clear(); + B64Decode(tmp, val); +} + + +static inline uint8_t hextodec(uint8_t val) +{ + if(val >= '0' && val<='9') + return val-'0'; + else if(val >= 'A' && val<='F') + return 10+(val-'A'); + else if(val >= 'a' && val<='f') + return 10+(val-'a'); + else + throw RecordTextException("Unknown hexadecimal character '"+lexical_cast(val)+"'"); +} + + +void HEXDecode(const char* begin, const char* end, string& out) +{ + if(end - begin == 1 && *begin=='-') { + out.clear(); + return; + } + out.clear(); + out.reserve((end-begin)/2); + uint8_t mode=0, val=0; + for(; begin != end; ++begin) { + if(!isalnum(*begin)) + continue; + if(mode==0) { + val = 16*hextodec(*begin); + mode=1; + } else { + val += hextodec(*begin); + out.append(1, (char) val); + mode = 0; + val = 0; + } + } + if(mode) + out.append(1, (char) val); + +} + +void RecordTextReader::xfrHexBlob(string& val, bool keepReading) +{ + skipSpaces(); + int pos=(int)d_pos; + while(d_pos < d_end && (keepReading || !dns_isspace(d_string[d_pos]))) + d_pos++; + + HEXDecode(d_string.c_str()+pos, d_string.c_str() + d_pos, val); +} + +void RecordTextReader::xfrBase32HexBlob(string& val) +{ + skipSpaces(); + int pos=(int)d_pos; + while(d_pos < d_end && !dns_isspace(d_string[d_pos])) + d_pos++; + + val=fromBase32Hex(string(d_string.c_str()+pos, d_pos-pos)); +} + + +void RecordTextWriter::xfrBase32HexBlob(const string& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + d_string.append(toBase32Hex(val)); +} + + +void RecordTextReader::xfrText(string& val, bool multi) +{ + val.clear(); + val.reserve(d_end - d_pos); + + while(d_pos != d_end) { + if(!val.empty()) + val.append(1, ' '); + + skipSpaces(); + if(d_string[d_pos]!='"') { // special case 'plenus' - without quotes + string::size_type pos = d_pos; + while(pos != d_end && isalnum(d_string[pos])) + pos++; + if(pos == d_end) { + val.append(1, '"'); + val.append(d_string.c_str() + d_pos, d_end - d_pos); + val.append(1, '"'); + d_pos = d_end; + break; + } + throw RecordTextException("Data field in DNS should start with quote (\") at position "+lexical_cast(d_pos)+" of '"+d_string+"'"); + } + val.append(1, '"'); + while(++d_pos < d_end && d_string[d_pos]!='"') { + if(d_string[d_pos]=='\\' && d_pos+1!=d_end) { + val.append(1, d_string[d_pos++]); + } + val.append(1, d_string[d_pos]); + } + val.append(1,'"'); + if(d_pos == d_end) + throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'"); + d_pos++; + if(!multi) + break; + } +} + +void RecordTextReader::xfrType(uint16_t& val) +{ + skipSpaces(); + int pos=(int)d_pos; + while(d_pos < d_end && !dns_isspace(d_string[d_pos])) + d_pos++; + + string tmp; + tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos); + + val=DNSRecordContent::TypeToNumber(tmp); +} + + +void RecordTextReader::skipSpaces() +{ + const char* strptr = d_string.c_str(); + while(d_pos < d_end && dns_isspace(strptr[d_pos])) + d_pos++; + if(d_pos == d_end) + throw RecordTextException("missing field at the end of record content '"+d_string+"'"); +} + + +RecordTextWriter::RecordTextWriter(string& str) : d_string(str) +{ + d_string.clear(); +} + +void RecordTextWriter::xfr48BitInt(const uint64_t& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + d_string+=lexical_cast(val); +} + + +void RecordTextWriter::xfr32BitInt(const uint32_t& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + d_string+=lexical_cast(val); +} + +void RecordTextWriter::xfrType(const uint16_t& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + d_string+=DNSRecordContent::NumberToType(val); +} + +// this function is on the fast path for the pdns_recursor +void RecordTextWriter::xfrIP(const uint32_t& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + char tmp[17]; + uint32_t ip=val; + uint8_t vals[4]; + + memcpy(&vals[0], &ip, sizeof(ip)); + + char *pos=tmp; + + for(int n=0; n < 4; ++n) { + if(vals[n]<10) { + *(pos++)=vals[n]+'0'; + } else if(vals[n] < 100) { + *(pos++)=(vals[n]/10) +'0'; + *(pos++)=(vals[n]%10) +'0'; + } else { + *(pos++)=(vals[n]/100) +'0'; + vals[n]%=100; + *(pos++)=(vals[n]/10) +'0'; + *(pos++)=(vals[n]%10) +'0'; + } + if(n!=3) + *(pos++)='.'; + } + *pos=0; + d_string.append(tmp, pos); +} + + +void RecordTextWriter::xfrTime(const uint32_t& val) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + struct tm tm; + time_t time=val; // Y2038 bug! +#ifndef WIN32 + gmtime_r(&time, &tm); +#else + struct tm* tmptr; + tmptr=gmtime(&time); + if(!tmptr) + throw RecordTextException("Unable to convert timestamp into pretty printable time"); + tm=*tmptr; +#endif + + char tmp[16]; + snprintf(tmp,sizeof(tmp)-1, "%04d%02d%02d" "%02d%02d%02d", + tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday, + tm.tm_hour, tm.tm_min, tm.tm_sec); + + d_string += tmp; +} + + +void RecordTextWriter::xfr16BitInt(const uint16_t& val) +{ + xfr32BitInt(val); +} + +void RecordTextWriter::xfr8BitInt(const uint8_t& val) +{ + xfr32BitInt(val); +} + +// should not mess with the escapes +void RecordTextWriter::xfrLabel(const string& val, bool) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + d_string+=val; +} + +void RecordTextWriter::xfrBlob(const string& val, int) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + d_string+=Base64Encode(val); +} + +void RecordTextWriter::xfrHexBlob(const string& val, bool) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + if(val.empty()) { + d_string.append(1,'-'); + return; + } + + string::size_type limit=val.size(); + char tmp[5]; + for(string::size_type n = 0; n < limit; ++n) { + snprintf(tmp, sizeof(tmp)-1, "%02x", (unsigned char)val[n]); + d_string+=tmp; + } +} + +void RecordTextWriter::xfrText(const string& val, bool multi) +{ + if(!d_string.empty()) + d_string.append(1,' '); + + d_string.append(val); +} + + +#ifdef TESTING + +int main(int argc, char**argv) +try +{ + RecordTextReader rtr(argv[1], argv[2]); + + unsigned int order, pref; + string flags, services, regexp, replacement; + string mx; + + rtr.xfrInt(order); + rtr.xfrInt(pref); + rtr.xfrText(flags); + rtr.xfrText(services); + rtr.xfrText(regexp); + rtr.xfrLabel(replacement); + + cout<<"order: "< +#include +#include +#if !defined SOLARIS8 && !defined WIN32 + +#elif defined WIN32 +# include "utility.hh" +#endif + +#include "namespaces.hh" + +class RecordTextException : public runtime_error +{ +public: + RecordTextException(const string& str) : runtime_error(str) + {} +}; + +class RecordTextReader +{ +public: + RecordTextReader(const string& str, const string& zone=""); + void xfr64BitInt(uint64_t& val); + void xfr48BitInt(uint64_t& val); + void xfr32BitInt(uint32_t& val); + void xfr16BitInt(uint16_t& val); + void xfr8BitInt(uint8_t& val); + + void xfrType(uint16_t& val); + void xfrIP(uint32_t& val); + void xfrTime(uint32_t& val); + + void xfrLabel(string& val, bool compress=false); + void xfrText(string& val, bool multi=false); + void xfrHexBlob(string& val, bool keepReading=false); + void xfrBase32HexBlob(string& val); + + void xfrBlob(string& val, int len=-1); + + bool eof(); +private: + string d_string; + string d_zone; + string::size_type d_pos; + string::size_type d_end; + void skipSpaces(); +}; + +class RecordTextWriter +{ +public: + RecordTextWriter(string& str); + void xfr48BitInt(const uint64_t& val); + void xfr32BitInt(const uint32_t& val); + void xfr16BitInt(const uint16_t& val); + void xfr8BitInt(const uint8_t& val); + void xfrIP(const uint32_t& val); + void xfrTime(const uint32_t& val); + void xfrBase32HexBlob(const string& val); + + void xfrType(const uint16_t& val); + void xfrLabel(const string& val, bool compress=false); + void xfrText(const string& val, bool multi=false); + void xfrBlob(const string& val, int len=-1); + void xfrHexBlob(const string& val, bool keepReading=false); + +private: + string& d_string; +}; + +string segmentDNSLabel(const string& input ); +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/README pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/README --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/README 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/README 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,94 @@ +DOCUMENTATION +------------- +For full details, please read: + + http://doc.powerdns.com/built-in-recursor.html + +COMPILING +--------- + +$ ./configure +$ make or gmake + +The only dependency is Boost, http://boost.org/ +You only need to download it, there is no need to compile. + +On most modern UNIX distributions, you can simply install 'boost' or +'boost-dev' or 'boost-devel'. If you don't have that option, or don't want +to use it, try: + +1) head to http://sourceforge.net/project/showfiles.php?group_id=7586 and +download the latest boost tar.bz2 or tar.gz, perhaps from: +http://downloads.sourceforge.net/project/boost/boost/1.39.0/boost_1_39_0.tar.bz2?use_mirror=ovh +(use the first link if this one doesn't work) + +2) untar it: + +$ tar xjf boost_1_39_0.tar.bz2 + +3) Compile the PowerDNS recursor using: + +$ CXXFLAGS=-I./boost_1_39_0/ ./configure +$ CXXFLAGS=-I./boost_1_39_0/ make clean +$ CXXFLAGS=-I./boost_1_39_0/ make all +(the 'clean' is needed to have make pick up the new boost) + +4) Run ./pdns_recursor and you should be set! + +5) (g)make install + +(use gmake on many BSD variant and Solaris, regular make on Linux) + +OPTIONAL LUA SCRIPTING +---------------------- +To benefit from Lua scripting, as described on +http://doc.powerdns.com/recursor-scripting.html please compile like this: + +$ LUA=1 (g)make +or even + +$ LUA=1 LUA_CPPFLAGS_CONFIG=-I/usr/local/include/lua5.1 LUA_LIBS_CONFIG=-llua5.1\ + (g)make + +Use the _CONFIG settings to point out to PowerDNS where your Lua +installation resides. PowerDNS supports both Lua 5.0 and 5.1. + +PLATFORM SPECIFIC NOTES +----------------------- +When compiling on Solaris 8, use: +$ CPPFLAGS=-DSOLARIS8 ... gmake + +where ... stands for any possible CXXFLAGS or PROFILEFLAGS, see below. + +PERFORMANCE +----------- +When on Intel/AMD, by ALL means use a 64-bit binary (not just a 64-bit +kernel). This speeds up most things by at least a factor 2. + +For the utmost in performance, compile like this: + + $ PROFILEFLAGS=-fprofile-generate make + +Then run the program for a bit, in as much of a real-life setting as you +have available. Then run: + + $ rec_control quit-nicely + bye nicely + +Then do: + + $ PROFILEFLAGS=-fprofile-use make binclean all + +The resulting binary is up to 20% faster in our tests. + +Do run with g++ 4.4.1 if you can, it is the best. + +RUNNING ON A DIFFERENT MACHINE +------------------------------ +To prevent hassles with g++/c++ dependencies, you can build like this: + $ STATIC=semi make all + +PROBLEMS +-------- +If you have problems linking, try removing the GCC_SKIP_LOCKING line from +config.h diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rec_channel.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rec_channel.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rec_channel.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rec_channel.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,142 @@ +#include "rec_channel.hh" +#include +#include +#include "misc.hh" +#include +#include +#include +#include +#include +#include + +#include "ahuexception.hh" + +#include "namespaces.hh" + +RecursorControlChannel::RecursorControlChannel() +{ + d_fd=-1; + *d_local.sun_path=0; +} + +RecursorControlChannel::~RecursorControlChannel() +{ + if(d_fd > 0) + close(d_fd); + if(*d_local.sun_path) + unlink(d_local.sun_path); +} + +int RecursorControlChannel::listen(const string& fname) +{ + d_fd=socket(AF_UNIX,SOCK_DGRAM,0); + Utility::setCloseOnExec(d_fd); + + if(d_fd < 0) + throw AhuException("Creating UNIX domain socket: "+string(strerror(errno))); + + int tmp=1; + if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) + throw AhuException(string("Setsockopt failed: ")+strerror(errno)); + + int err=unlink(fname.c_str()); + if(err < 0 && errno!=ENOENT) + throw AhuException("Can't remove (previous) controlsocket '"+fname+"': "+string(strerror(errno)) + " (try --socket-dir)"); + + memset(&d_local,0,sizeof(d_local)); + d_local.sun_family=AF_UNIX; + strcpy(d_local.sun_path, fname.c_str()); + + if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0) + throw AhuException("Unable to bind to controlsocket '"+fname+"': "+string(strerror(errno))); + + return d_fd; +} + +void RecursorControlChannel::connect(const string& path, const string& fname) +{ + struct sockaddr_un remote; + + d_fd=socket(AF_UNIX,SOCK_DGRAM,0); + Utility::setCloseOnExec(d_fd); + + if(d_fd < 0) + throw AhuException("Creating UNIX domain socket: "+string(strerror(errno))); + + int tmp=1; + if(setsockopt(d_fd, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) { + close(d_fd); + d_fd=-1; + throw AhuException(string("Setsockopt failed: ")+strerror(errno)); + } + + string localname=path+"/lsockXXXXXX"; + strcpy(d_local.sun_path, localname.c_str()); + + if(mkstemp(d_local.sun_path) < 0) { + close(d_fd); + d_fd=-1; + d_local.sun_path[0]=0; + throw AhuException("Unable to generate local temporary file in directory '"+path+"': "+string(strerror(errno))); + } + + d_local.sun_family=AF_UNIX; + + int err=unlink(d_local.sun_path); + if(err < 0 && errno!=ENOENT) + throw AhuException("Unable to remove local controlsocket: "+string(strerror(errno))); + + if(bind(d_fd, (sockaddr*)&d_local,sizeof(d_local))<0) { + unlink(d_local.sun_path); + close(d_fd); + d_fd=-1; + throw AhuException("Unable to bind to local temporary file: "+string(strerror(errno))); + } + + if(chmod(d_local.sun_path,0666)<0) { // make sure that pdns can reply! + unlink(d_local.sun_path); + throw AhuException("Unable to chmnod local temporary socket: "+string(strerror(errno))); + } + + memset(&remote,0,sizeof(remote)); + + remote.sun_family=AF_UNIX; + strcpy(remote.sun_path,(path+"/"+fname).c_str()); + if(::connect(d_fd, (sockaddr*)&remote, sizeof(remote)) < 0) { + unlink(d_local.sun_path); + throw AhuException("Unable to connect to remote '"+path+fname+"': "+string(strerror(errno))); + } +} + +void RecursorControlChannel::send(const std::string& msg, const std::string* remote) +{ + if(remote) { + struct sockaddr_un remoteaddr; + memset(&remoteaddr, 0, sizeof(remoteaddr)); + + remoteaddr.sun_family=AF_UNIX; + strcpy(remoteaddr.sun_path, remote->c_str()); + + if(::sendto(d_fd, msg.c_str(), msg.length(), 0, (struct sockaddr*) &remoteaddr, sizeof(remoteaddr) ) < 0) + throw AhuException("Unable to send message over control channel '"+*remote+"': "+string(strerror(errno))); + } + else if(::send(d_fd, msg.c_str(), msg.length(), 0) < 0) + throw AhuException("Unable to send message over control channel: "+string(strerror(errno))); +} + +string RecursorControlChannel::recv(std::string* remote, unsigned int timeout) +{ + char buffer[16384]; + ssize_t len; + struct sockaddr_un remoteaddr; + socklen_t addrlen=sizeof(remoteaddr); + + if((waitForData(d_fd, timeout, 0 ) != 1) || (len=::recvfrom(d_fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&remoteaddr, &addrlen)) < 0) + throw AhuException("Unable to receive message over control channel: "+string(strerror(errno))); + + if(remote) + *remote=remoteaddr.sun_path; + + return string(buffer, buffer+len); +} + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rec_channel.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rec_channel.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rec_channel.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rec_channel.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,50 @@ +#ifndef PDNS_REC_CHANNEL +#define PDNS_REC_CHANNEL +#include +#include +#include +#if !defined SOLARIS8 && !defined WIN32 + +#elif defined WIN32 +#include "utility.hh" +#endif + +#ifndef WIN32 +#include +#else +// ? +struct sockaddr_un {}; +#endif + +/** this class is used both to send and answer channel commands to the PowerDNS Recursor */ +class RecursorControlChannel +{ +public: + RecursorControlChannel(); + + ~RecursorControlChannel(); + + int listen(const std::string& filename); + void connect(const std::string& path, const std::string& filename); + + uint64_t getStat(const std::string& name); + + void send(const std::string& msg, const std::string* remote=0); + std::string recv(std::string* remote=0, unsigned int timeout=5); + + int d_fd; +private: + struct sockaddr_un d_local; +}; + +class RecursorControlParser +{ +public: + RecursorControlParser(); + static void nop(void){} + typedef void func_t(void); + std::string getAnswer(const std::string& question, func_t** func); +}; + + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rec_channel_rec.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rec_channel_rec.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rec_channel_rec.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rec_channel_rec.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,639 @@ +#include "utility.hh" +#include "rec_channel.hh" +#include +#include +#include +#include "misc.hh" +#include "recursor_cache.hh" +#include "syncres.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "logger.hh" +#include "dnsparser.hh" +#include "arguments.hh" +#ifndef WIN32 +#include +#include +#endif + +#include "namespaces.hh" +#include "namespaces.hh" +map d_get32bitpointers; +map d_get64bitpointers; +map > d_get32bitmembers; + +void addGetStat(const string& name, const uint32_t* place) +{ + d_get32bitpointers[name]=place; +} +void addGetStat(const string& name, const uint64_t* place) +{ + d_get64bitpointers[name]=place; +} +void addGetStat(const string& name, function f ) +{ + d_get32bitmembers[name]=f; +} + +optional get(const string& name) +{ + optional ret; + + if(d_get32bitpointers.count(name)) + return *d_get32bitpointers.find(name)->second; + if(d_get64bitpointers.count(name)) + return *d_get64bitpointers.find(name)->second; + if(d_get32bitmembers.count(name)) + return d_get32bitmembers.find(name)->second(); + + return ret; +} + +string getAllStats() +{ + string ret; + pair the32bits; + pair the64bits; + pair > the32bitmembers; + BOOST_FOREACH(the32bits, d_get32bitpointers) { + ret += the32bits.first + "\t" + lexical_cast(*the32bits.second) + "\n"; + } + BOOST_FOREACH(the64bits, d_get64bitpointers) { + ret += the64bits.first + "\t" + lexical_cast(*the64bits.second) + "\n"; + } + BOOST_FOREACH(the32bitmembers, d_get32bitmembers) { + ret += the32bitmembers.first + "\t" + lexical_cast(the32bitmembers.second()) + "\n"; + } + return ret; +} + +template +string doGet(T begin, T end) +{ + string ret; + + for(T i=begin; i != end; ++i) { + optional num=get(*i); + if(num) + ret+=lexical_cast(*num)+"\n"; + else + ret+="UNKNOWN\n"; + } + return ret; +} + +template +string doGetParameter(T begin, T end) +{ + string ret; + string parm; + using boost::replace_all; + for(T i=begin; i != end; ++i) { + if(::arg().parmIsset(*i)) { + parm=::arg()[*i]; + replace_all(parm, "\\", "\\\\"); + replace_all(parm, "\"", "\\\""); + replace_all(parm, "\n", "\\n"); + ret += *i +"=\""+ parm +"\"\n"; + } + else + ret += *i +" not known\n"; + } + return ret; +} + + +static uint64_t dumpNegCache(SyncRes::negcache_t& negcache, int fd) +{ + FILE* fp=fdopen(dup(fd), "w"); + if(!fp) { // dup probably failed + return 0; + } + fprintf(fp, "; negcache dump from thread follows\n;\n"); + time_t now = time(0); + + typedef SyncRes::negcache_t::nth_index<1>::type sequence_t; + sequence_t& sidx=negcache.get<1>(); + + uint64_t count=0; + BOOST_FOREACH(const NegCacheEntry& neg, sidx) + { + ++count; + fprintf(fp, "%s IN %s %d VIA %s\n", neg.d_name.c_str(), neg.d_qtype.getName().c_str(), (unsigned int) (neg.d_ttd - now), neg.d_qname.c_str()); + } + fclose(fp); + return count; +} + +static uint64_t* pleaseDump(int fd) +{ + return new uint64_t(t_RC->doDump(fd) + dumpNegCache(t_sstorage->negcache, fd)); +} + +template +string doDumpCache(T begin, T end) +{ + T i=begin; + string fname; + + if(i!=end) + fname=*i; + + int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); + if(fd < 0) + return "Error opening dump file for writing: "+string(strerror(errno))+"\n"; + uint64_t total = 0; + try { + total = broadcastAccFunction(boost::bind(pleaseDump, fd)); + } + catch(...){} + + close(fd); + return "dumped "+lexical_cast(total)+" records\n"; +} + +template +string doDumpEDNSStatus(T begin, T end) +{ + T i=begin; + string fname; + + if(i!=end) + fname=*i; + + int fd=open(fname.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660); + if(fd < 0) + return "Error opening dump file for writing: "+string(strerror(errno))+"\n"; + + SyncRes::doEDNSDumpAndClose(fd); + + return "done\n"; +} + +uint64_t* pleaseWipeCache(const std::string& canon) +{ + return new uint64_t(t_RC->doWipeCache(canon)); +} + + +static uint64_t* pleaseWipeAndCountNegCache(const std::string& canon) +{ + uint64_t res = t_sstorage->negcache.count(tie(canon)); + pair range=t_sstorage->negcache.equal_range(tie(canon)); + t_sstorage->negcache.erase(range.first, range.second); + return new uint64_t(res); +} + +template +string doWipeCache(T begin, T end) +{ + int count=0, countNeg=0; + for(T i=begin; i != end; ++i) { + string canon=toCanonic("", *i); + count+= broadcastAccFunction(boost::bind(pleaseWipeCache, canon)); + countNeg+=broadcastAccFunction(boost::bind(pleaseWipeAndCountNegCache, canon)); + } + + return "wiped "+lexical_cast(count)+" records, "+lexical_cast(countNeg)+" negative records\n"; +} + +#ifndef WIN32 +static uint64_t getSysTimeMsec() +{ + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (ru.ru_stime.tv_sec*1000ULL + ru.ru_stime.tv_usec/1000); +} + +static uint64_t getUserTimeMsec() +{ + struct rusage ru; + getrusage(RUSAGE_SELF, &ru); + return (ru.ru_utime.tv_sec*1000ULL + ru.ru_utime.tv_usec/1000); +} +#endif + +static uint64_t calculateUptime() +{ + return time(0) - g_stats.startupTime; +} + +static string* pleaseGetCurrentQueries() +{ + ostringstream ostr; + + ostr << MT->d_waiters.size() <<" currently outstanding questions\n"; + + boost::format fmt("%1% %|40t|%2% %|47t|%3% %|63t|%4% %|68t|%5%\n"); + + ostr << (fmt % "qname" % "qtype" % "remote" % "tcp" % "chained"); + int n=0; + for(MT_t::waiters_t::iterator mthread=MT->d_waiters.begin(); mthread!=MT->d_waiters.end() && n < 100; ++mthread, ++n) { + const PacketID& pident = mthread->key; + ostr << (fmt + % pident.domain % DNSRecordContent::NumberToType(pident.type) + % pident.remote.toString() % (pident.sock ? 'Y' : 'n') + % (pident.fd == -1 ? 'Y' : 'n') + ); + } + ostr <<" - done\n"; + return new string(ostr.str()); +} + +static string doCurrentQueries() +{ + return broadcastAccFunction(pleaseGetCurrentQueries); +} + +uint64_t* pleaseGetThrottleSize() +{ + return new uint64_t(t_sstorage->throttle.size()); +} + +static uint64_t getThrottleSize() +{ + return broadcastAccFunction(pleaseGetThrottleSize); +} + +uint64_t* pleaseGetNegCacheSize() +{ + uint64_t tmp=t_sstorage->negcache.size(); + return new uint64_t(tmp); +} + +uint64_t getNegCacheSize() +{ + return broadcastAccFunction(pleaseGetNegCacheSize); +} + +uint64_t* pleaseGetNsSpeedsSize() +{ + return new uint64_t(t_sstorage->nsSpeeds.size()); +} + +uint64_t getNsSpeedsSize() +{ + return broadcastAccFunction(pleaseGetNsSpeedsSize); +} + +uint64_t* pleaseGetConcurrentQueries() +{ + return new uint64_t(MT->numProcesses()); +} + +static uint64_t getConcurrentQueries() +{ + return broadcastAccFunction(pleaseGetConcurrentQueries); +} + +uint64_t* pleaseGetCacheSize() +{ + return new uint64_t(t_RC->size()); +} + +uint64_t* pleaseGetCacheBytes() +{ + return new uint64_t(t_RC->bytes()); +} + + +uint64_t doGetCacheSize() +{ + return broadcastAccFunction(pleaseGetCacheSize); +} + +uint64_t doGetCacheBytes() +{ + return broadcastAccFunction(pleaseGetCacheBytes); +} + +uint64_t* pleaseGetCacheHits() +{ + return new uint64_t(t_RC->cacheHits); +} + +uint64_t doGetCacheHits() +{ + return broadcastAccFunction(pleaseGetCacheHits); +} + +uint64_t* pleaseGetCacheMisses() +{ + return new uint64_t(t_RC->cacheMisses); +} + +uint64_t doGetCacheMisses() +{ + return broadcastAccFunction(pleaseGetCacheMisses); +} + + +uint64_t* pleaseGetPacketCacheSize() +{ + return new uint64_t(t_packetCache->size()); +} + +uint64_t* pleaseGetPacketCacheBytes() +{ + return new uint64_t(t_packetCache->bytes()); +} + + +uint64_t doGetPacketCacheSize() +{ + return broadcastAccFunction(pleaseGetPacketCacheSize); +} + +uint64_t doGetPacketCacheBytes() +{ + return broadcastAccFunction(pleaseGetPacketCacheBytes); +} + + +uint64_t* pleaseGetPacketCacheHits() +{ + return new uint64_t(t_packetCache->d_hits); +} + +uint64_t doGetPacketCacheHits() +{ + return broadcastAccFunction(pleaseGetPacketCacheHits); +} + +uint64_t* pleaseGetPacketCacheMisses() +{ + return new uint64_t(t_packetCache->d_misses); +} + +uint64_t doGetPacketCacheMisses() +{ + return broadcastAccFunction(pleaseGetPacketCacheMisses); +} + +uint64_t doGetMallocated() +{ + // this turned out to be broken +/* struct mallinfo mi = mallinfo(); + return mi.uordblks; */ + return 0; +} + +RecursorControlParser::RecursorControlParser() +{ + addGetStat("questions", &g_stats.qcounter); + addGetStat("tcp-questions", &g_stats.tcpqcounter); + + addGetStat("cache-hits", doGetCacheHits); + addGetStat("cache-misses", doGetCacheMisses); + addGetStat("cache-entries", doGetCacheSize); + addGetStat("cache-bytes", doGetCacheBytes); + + addGetStat("packetcache-hits", doGetPacketCacheHits); + addGetStat("packetcache-misses", doGetPacketCacheMisses); + addGetStat("packetcache-entries", doGetPacketCacheSize); + addGetStat("packetcache-bytes", doGetPacketCacheBytes); + + addGetStat("malloc-bytes", doGetMallocated); + + addGetStat("servfail-answers", &g_stats.servFails); + addGetStat("nxdomain-answers", &g_stats.nxDomains); + addGetStat("noerror-answers", &g_stats.noErrors); + + addGetStat("unauthorized-udp", &g_stats.unauthorizedUDP); + addGetStat("unauthorized-tcp", &g_stats.unauthorizedTCP); + addGetStat("tcp-client-overflow", &g_stats.tcpClientOverflow); + + addGetStat("client-parse-errors", &g_stats.clientParseError); + addGetStat("server-parse-errors", &g_stats.serverParseError); + + addGetStat("answers0-1", &g_stats.answers0_1); + addGetStat("answers1-10", &g_stats.answers1_10); + addGetStat("answers10-100", &g_stats.answers10_100); + addGetStat("answers100-1000", &g_stats.answers100_1000); + addGetStat("answers-slow", &g_stats.answersSlow); + + addGetStat("qa-latency", &g_stats.avgLatencyUsec); + addGetStat("unexpected-packets", &g_stats.unexpectedCount); + addGetStat("case-mismatches", &g_stats.caseMismatchCount); + addGetStat("spoof-prevents", &g_stats.spoofCount); + + addGetStat("nsset-invalidations", &g_stats.nsSetInvalidations); + + addGetStat("resource-limits", &g_stats.resourceLimits); + addGetStat("over-capacity-drops", &g_stats.overCapacityDrops); + addGetStat("no-packet-error", &g_stats.noPacketError); + addGetStat("dlg-only-drops", &SyncRes::s_nodelegated); + addGetStat("max-mthread-stack", &g_stats.maxMThreadStackUsage); + + addGetStat("negcache-entries", boost::bind(getNegCacheSize)); + addGetStat("throttle-entries", boost::bind(getThrottleSize)); + + addGetStat("nsspeeds-entries", boost::bind(getNsSpeedsSize)); + + addGetStat("concurrent-queries", boost::bind(getConcurrentQueries)); + addGetStat("outgoing-timeouts", &SyncRes::s_outgoingtimeouts); + addGetStat("tcp-outqueries", &SyncRes::s_tcpoutqueries); + addGetStat("all-outqueries", &SyncRes::s_outqueries); + addGetStat("ipv6-outqueries", &g_stats.ipv6queries); + addGetStat("throttled-outqueries", &SyncRes::s_throttledqueries); + addGetStat("dont-outqueries", &SyncRes::s_dontqueries); + addGetStat("throttled-out", &SyncRes::s_throttledqueries); + addGetStat("unreachables", &SyncRes::s_unreachables); + addGetStat("chain-resends", &g_stats.chainResends); + addGetStat("tcp-clients", boost::bind(TCPConnection::getCurrentConnections)); + + addGetStat("edns-ping-matches", &g_stats.ednsPingMatches); + addGetStat("edns-ping-mismatches", &g_stats.ednsPingMismatches); + + addGetStat("noping-outqueries", &g_stats.noPingOutQueries); + addGetStat("noedns-outqueries", &g_stats.noEdnsOutQueries); + + addGetStat("uptime", calculateUptime); + +#ifndef WIN32 + // addGetStat("query-rate", getQueryRate); + addGetStat("user-msec", getUserTimeMsec); + addGetStat("sys-msec", getSysTimeMsec); +#endif +} + +static void doExitGeneric(bool nicely) +{ + L<* pleaseGetRemotes() +{ + return new vector(t_remotes->remotes); +} + +string doTopRemotes() +{ + typedef map counts_t; + counts_t counts; + + vector remotes=broadcastAccFunction >(pleaseGetRemotes); + + unsigned int total=0; + for(RemoteKeeper::remotes_t::const_iterator i = remotes.begin(); i != remotes.end(); ++i) + if(i->sin4.sin_family) { + total++; + counts[*i]++; + } + + typedef std::multimap rcounts_t; + rcounts_t rcounts; + + for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i) + rcounts.insert(make_pair(-i->second, i->first)); + + ostringstream ret; + ret<<"Over last "<first/total) % i->second.toString(); + + return ret.str(); +} + +static string* nopFunction() +{ + return new string("pong\n"); +} + +string RecursorControlParser::getAnswer(const string& question, RecursorControlParser::func_t** command) +{ + *command=nop; + vector words; + stringtok(words, question); + + if(words.empty()) + return "invalid command\n"; + + string cmd=toLower(words[0]); + vector::const_iterator begin=words.begin()+1, end=words.end(); + + // should probably have a smart dispatcher here, like auth has + if(cmd=="help") + return +"current-queries show currently active queries\n" +"dump-cache dump cache contents to the named file\n" +"dump-edns[status] dump EDNS status to the named file\n" +"get [key1] [key2] .. get specific statistics\n" +"get-all get all statistics\n" +"get-parameter [key1] [key2] .. get configuration parameters\n" +"help get this list\n" +"ping check that all threads are alive\n" +"quit stop the recursor daemon\n" +"quit-nicely stop the recursor daemon nicely\n" +"reload-acls reload ACLS\n" +"reload-lua-script [filename] (re)load Lua script\n" +"reload-zones reload all auth and forward zones\n" +"top-remotes show top remotes\n" +"unload-lua-script unload Lua script\n" +"wipe-cache domain0 [domain1] .. wipe domain data from cache\n"; + + if(cmd=="get-all") + return getAllStats(); + + if(cmd=="get") + return doGet(begin, end); + + if(cmd=="get-parameter") + return doGetParameter(begin, end); + + + if(cmd=="quit") { + *command=&doExit; + return "bye\n"; + } + + if(cmd=="quit-nicely") { + *command=&doExitNicely; + return "bye nicely\n"; + } + + if(cmd=="dump-cache") + return doDumpCache(begin, end); + + if(cmd=="dump-ednsstatus" || cmd=="dump-edns") + return doDumpEDNSStatus(begin, end); + + + if(cmd=="wipe-cache") + return doWipeCache(begin, end); + + if(cmd=="reload-lua-script") + return doQueueReloadLuaScript(begin, end); + + if(cmd=="unload-lua-script") { + vector empty; + empty.push_back(string()); + return doQueueReloadLuaScript(empty.begin(), empty.end()); + } + + if(cmd=="reload-acls") { + try { + parseACLs(); + } + catch(std::exception& e) + { + L<(nopFunction); + } + + if(cmd=="reload-zones") { + return reloadAuthAndForwards(); + } + + return "Unknown command '"+cmd+"', try 'help'\n"; +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rec_control.1 pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rec_control.1 --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rec_control.1 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rec_control.1 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,154 @@ +'\" t +.\" Title: rec_control +.\" Author: [see the "AUTHOR" section] +.\" Generator: DocBook XSL Stylesheets v1.75.2 +.\" Date: 07/08/2012 +.\" Manual: \ \& +.\" Source: \ \& 3.0 +.\" Language: English +.\" +.TH "REC_CONTROL" "1" "07/08/2012" "\ \& 3\&.0" "\ \&" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" ----------------------------------------------------------------- +.\" * set default formatting +.\" ----------------------------------------------------------------- +.\" disable hyphenation +.nh +.\" disable justification (adjust text to left margin only) +.ad l +.\" ----------------------------------------------------------------- +.\" * MAIN CONTENT STARTS HERE * +.\" ----------------------------------------------------------------- +.SH "NAME" +rec_control \- control pdns_recursor +.SH "SYNOPSIS" +.sp +\fIrec_control\fR [\-\-help] [\-\-socket\-dir] [\-\-socket\-pid] command \&.\&. +.SH "DESCRIPTION" +.sp +rec_control(1) allows the operator to control a running instance of the pdns_recursor\&. +.sp +The commands that can be passed to the recursor are described on \m[blue]\fBhttp://doc\&.powerdns\&.com/rec\-control\&.html\fR\m[] +.SH "EXAMPLES" +.sp +To stop the recursor by hand, run: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# rec_control quit +.fi +.if n \{\ +.RE +.\} +.sp +To dump the cache to disk, execute: +.sp +.if n \{\ +.RS 4 +.\} +.nf +# rec_control dump\-cache /tmp/the\-cache +.fi +.if n \{\ +.RE +.\} +.SH "OPTIONS" +.PP +\-\-help +.RS 4 +provide this helpful message +.RE +.PP +\-\-socket\-dir +.RS 4 +Where the controlsocket will live +.RE +.PP +\-\-socket\-pid +.RS 4 +When running in SMP mode, pid of pdns_recursor to control +.RE +.PP +\-\-timeout +.RS 4 +Number of seconds to wait for the remote PowerDNS Recursor to respond\&. Set to 0 for infinite\&. +.RE +.SH "COMMANDS" +.PP +dump\-cache filename +.RS 4 +Dumps the entire cache to the filename mentioned\&. This file should not exist already, PowerDNS will refuse to overwrite it\&. While dumping, the recursor will not answer questions\&. +.RE +.PP +get statistic +.RS 4 +Retrieve a statistic\&. For items that can be queried, see +\m[blue]\fBhttp://doc\&.powerdns\&.com/recursor\-stats\&.html\fR\m[] +.RE +.PP +get\-all +.RS 4 +Retrieve all known statistics\&. +.RE +.PP +ping +.RS 4 +Check if server is alive\&. +.RE +.PP +quit +.RS 4 +Request shutdown of the recursor +.RE +.PP +reload\-zones +.RS 4 +Reload authoritative and forward zones\&. Retains current configuration in case of errors\&. +.RE +.PP +top\-remotes +.RS 4 +Shows the top\-20 most active remote hosts\&. Statistics are over the last +\fIremotes\-ringbuffer\-entries\fR +queries, which defaults to 0\&. +.RE +.PP +wipe\-cache domain0 [domain1] +.RS 4 +Wipe entries from the cache\&. This is useful if, for example, an important server has a new IP address, but the TTL has not yet expired\&. Multiple domain names can be passed\&. Note that you must terminate a domain with a \&.! So to wipe powerdns\&.org, issue +\fIrec_control wipe\-cache powerdns\&.org\&.\fR\&. Versions beyond 3\&.1 don\(cqt need the trailing dot\&. Consider not only wiping +\fIwww\&.domain\&.com\&.\fR +but also +\fIdomain\&.com\&.\fR, as the cached nameservers or target of CNAME may continue to be undesired\&. +.RE +.SH "BUGS" +.sp +None known\&. File new ones at \m[blue]\fBhttp://wiki\&.powerdns\&.com\fR\m[]\&. +.SH "AUTHOR" +.sp +Written by PowerDNS\&.COM BV, bert hubert, <\m[blue]\fBbert\&.hubert@netherlabs\&.nl\fR\m[]\&\s-2\u[1]\d\s+2> +.SH "RESOURCES" +.sp +Website: \m[blue]\fBhttp://wiki\&.powerdns\&.com\fR\m[], \m[blue]\fBhttp://www\&.powerdns\&.com\fR\m[] +.SH "SEE ALSO" +.sp +pdns_recursor(1) +.SH "COPYING" +.sp +Copyright \(co 2006 PowerDNS\&.COM BV\&. Free use of this software is granted under the terms of the GNU General Public License (GPL) version 2\&. +.SH "NOTES" +.IP " 1." 4 +bert.hubert@netherlabs.nl +.RS 4 +\%mailto:bert.hubert@netherlabs.nl +.RE diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rec_control.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rec_control.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rec_control.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rec_control.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,89 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2006 - 2011 PowerDNS.COM 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 "rec_channel.hh" +#include +#include "ahuexception.hh" +#include "arguments.hh" +#include "config.h" + +#include "namespaces.hh" + +#ifndef RECURSOR +#include "statbag.hh" +StatBag S; +#endif + +ArgvMap &arg() +{ + static ArgvMap arg; + return arg; +} + +static void initArguments(int argc, char** argv) +{ + arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR; + + arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR; + arg().set("process","When controlling multiple recursors, the target process number")=""; + arg().set("timeout", "Number of seconds to wait for the recursor to respond")="5"; + arg().setCmd("help","Provide this helpful message"); + + arg().laxParse(argc,argv); + if(arg().getCommands().empty() || arg().mustDo("help")) { + cerr<<"syntax: rec_control [options] command, options as below: "<&commands=arg().getCommands(); + string command; + for(unsigned int i=0; i< commands.size(); ++i) { + if(i>0) + command+=" "; + command+=commands[i]; + } + rccS.send(command); + string receive=rccS.recv(0, arg().asNum("timeout")); + cout< +#include +#include "recpacketcache.hh" +#include "cachecleaner.hh" +#include "dns.hh" +#include "namespaces.hh" +#include "lock.hh" + + +RecursorPacketCache::RecursorPacketCache() +{ + d_hits = d_misses = 0; +} + +bool RecursorPacketCache::getResponsePacket(const std::string& queryPacket, time_t now, + std::string* responsePacket, uint32_t* age) +{ + struct Entry e; + e.d_packet=queryPacket; + + packetCache_t::const_iterator iter = d_packetCache.find(e); + + if(iter == d_packetCache.end()) { + d_misses++; + return false; + } + + if((uint32_t)now < iter->d_ttd) { // it is fresh! +// cerr<<"Fresh for another "<d_ttd - now<<" seconds!"<d_creation; + uint16_t id; + memcpy(&id, queryPacket.c_str(), 2); + *responsePacket = iter->d_packet; + responsePacket->replace(0, 2, (char*)&id, 2); + d_hits++; + moveCacheItemToBack(d_packetCache, iter); + + return true; + } + moveCacheItemToFront(d_packetCache, iter); + d_misses++; + return false; +} + +void RecursorPacketCache::insertResponsePacket(const std::string& responsePacket, time_t now, uint32_t ttl) +{ + struct Entry e; + e.d_packet = responsePacket; + e.d_ttd = now+ttl; + e.d_creation = now; + packetCache_t::iterator iter = d_packetCache.find(e); + + if(iter != d_packetCache.end()) { + iter->d_packet = responsePacket; + iter->d_ttd = now + ttl; + iter->d_creation = now; + } + else + d_packetCache.insert(e); +} + +uint64_t RecursorPacketCache::size() +{ + return d_packetCache.size(); +} + +uint64_t RecursorPacketCache::bytes() +{ + uint64_t sum=0; + BOOST_FOREACH(const struct Entry& e, d_packetCache) { + sum += sizeof(e) + e.d_packet.length() + 4; + } + return sum; +} + + +void RecursorPacketCache::doPruneTo(unsigned int maxCached) +{ + pruneCollection(d_packetCache, maxCached); +} + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/recpacketcache.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/recpacketcache.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/recpacketcache.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/recpacketcache.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,73 @@ +#ifndef PDNS_RECPACKETCACHE_HH +#define PDNS_RECPACKETCACHE_HH +#include +#include +#include +#include "dns.hh" +#include "namespaces.hh" +#include +#include +#include +#include +#include + + +using namespace ::boost::multi_index; + +//! Stores whole packets, ready for lobbing back at the client. Not threadsafe. +class RecursorPacketCache +{ +public: + RecursorPacketCache(); + bool getResponsePacket(const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age); + void insertResponsePacket(const std::string& responsePacket, time_t now, uint32_t ttd); + void doPruneTo(unsigned int maxSize=250000); + + void prune(); + uint64_t d_hits, d_misses; + uint64_t size(); + uint64_t bytes(); + +private: + + struct Entry + { + mutable uint32_t d_ttd; + mutable uint32_t d_creation; + mutable std::string d_packet; // "I know what I am doing" + + inline bool operator<(const struct Entry& rhs) const; + + uint32_t getTTD() const + { + return d_ttd; + } + }; + + typedef multi_index_container< + Entry, + indexed_by < + ordered_unique >, + sequenced<> + > + > packetCache_t; + + packetCache_t d_packetCache; +}; + +// needs to take into account: qname, qtype, opcode, rd, qdcount, EDNS size +inline bool RecursorPacketCache::Entry::operator<(const struct RecursorPacketCache::Entry &rhs) const +{ + const struct dnsheader* + dh=(const struct dnsheader*) d_packet.c_str(), + *rhsdh=(const struct dnsheader*)rhs.d_packet.c_str(); + if(make_tuple(dh->opcode, dh->rd, dh->qdcount) < + make_tuple(rhsdh->opcode, rhsdh->rd, rhsdh->qdcount)) + return true; + + return dnspacketLessThan(d_packet, rhs.d_packet); +} + + + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/recursor_cache.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/recursor_cache.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/recursor_cache.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/recursor_cache.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,362 @@ +#include "recursor_cache.hh" +#include "misc.hh" +#include +#include +#include "dnsrecords.hh" +#include "arguments.hh" +#include "syncres.hh" +#include "recursor_cache.hh" +#include "cachecleaner.hh" + +#include "namespaces.hh" +#include "namespaces.hh" + +#include "config.h" + +DNSResourceRecord String2DNSRR(const string& qname, const QType& qt, const string& serial, uint32_t ttd) +{ + DNSResourceRecord rr; + rr.ttl=ttd; + rr.qtype=qt; + rr.qname=qname; + + if(rr.qtype.getCode()==QType::A && serial.size()==4) { + uint32_t ip; + memcpy((char*)&ip, serial.c_str(), 4); + rr.content=U32ToIP(ntohl(ip)); + } + else if(rr.qtype.getCode()==QType::AAAA && serial.size()==16) { + ComboAddress tmp; + memset(&tmp, 0, sizeof(tmp)); + tmp.sin4.sin_family=AF_INET6; + memcpy(tmp.sin6.sin6_addr.s6_addr, serial.c_str(), 16); + rr.content=tmp.toString(); + } + else if(rr.qtype.getCode()==QType::CNAME || rr.qtype.getCode()==QType::NS || rr.qtype.getCode()==QType::PTR) { + unsigned int frompos=0; + unsigned char labellen; + + while((labellen=serial.at(frompos++))) { + if((labellen & 0xc0) == 0xc0) { + string encoded=simpleCompress(qname); + uint16_t offset=256*(labellen & ~0xc0) + (unsigned int)serial.at(frompos++) - sizeof(dnsheader)-5; + + simpleExpandTo(encoded, offset, rr.content); + // cerr<<"Oops, fallback, content so far: '"< regen=DNSRecordContent::unserialize(qname, qt.getCode(), serial); + rr.content=regen->getZoneRepresentation(); + } + rr.content.reserve(0); + rr.qname.reserve(0); + return rr; +} + +// returns the RDATA for rr - might be compressed! +string DNSRR2String(const DNSResourceRecord& rr) +{ + uint16_t type=rr.qtype.getCode(); + + if(type==QType::A) { + uint32_t ip; + IpToU32(rr.content, &ip); + return string((char*)&ip, 4); + } + else if(type==QType::AAAA) { + ComboAddress ca(rr.content); + return string((char*)&ca.sin6.sin6_addr.s6_addr, 16); + } + else if(type==QType::NS || type==QType::CNAME) + return simpleCompress(rr.content, rr.qname); + else { + string ret; + shared_ptr drc(DNSRecordContent::mastermake(type, 1, rr.content)); + ret=drc->serialize(rr.qname); + // cerr<<"stored '"<d_qname.length(); + for(vector::const_iterator j=i->d_records.begin(); j!= i->d_records.end(); ++j) + ret+=j->size(); + } + return ret; +} + +int MemRecursorCache::get(time_t now, const string &qname, const QType& qt, set* res) +{ + unsigned int ttd=0; + // cerr<<"looking up "<< qname+"|"+qt.getName()<<"\n"; + + if(!d_cachecachevalid || !pdns_iequals(d_cachedqname, qname)) { + // cerr<<"had cache cache miss"<clear(); + + if(d_cachecache.first!=d_cachecache.second) { + for(cache_t::const_iterator i=d_cachecache.first; i != d_cachecache.second; ++i) + if(i->d_qtype == qt.getCode() || qt.getCode()==QType::ANY || + (qt.getCode()==QType::ADDR && (i->d_qtype == QType::A || i->d_qtype == QType::AAAA) ) + ) { + for(vector::const_iterator k=i->d_records.begin(); k != i->d_records.end(); ++k) { + if(k->d_ttd < 1000000000 || k->d_ttd > (uint32_t) now) { // FIXME what does the 100000000 number mean? + ttd=k->d_ttd; + if(res) { + DNSResourceRecord rr=String2DNSRR(qname, QType(i->d_qtype), k->d_string, ttd); + res->insert(rr); + } + } + } + if(res) { + if(res->empty()) + moveCacheItemToFront(d_cache, i); + else + moveCacheItemToBack(d_cache, i); + } + if(qt.getCode()!=QType::ANY && qt.getCode()!=QType::ADDR) // normally if we have a hit, we are done + break; + } + + // cerr<<"time left : "<size() : 0) <<"\n"; + return (int)ttd-now; + } + return -1; +} + + + +bool MemRecursorCache::attemptToRefreshNSTTL(const QType& qt, const set& content, const CacheEntry& stored) +{ + if(!stored.d_auth) { + //~ cerr<<"feel free to scribble non-auth data!"<d_ttd > content.begin()->ttl) { + //~ cerr<<"attempt to LOWER TTL - fine by us"<& content, bool auth) +{ + d_cachecachevalid=false; + tuple key=make_tuple(qname, qt.getCode()); + cache_t::iterator stored=d_cache.find(key); + + bool isNew=false; + if(stored == d_cache.end()) { + stored=d_cache.insert(CacheEntry(key,vector(), auth)).first; + isNew=true; + } + pair::iterator, vector::iterator> range; + + StoredRecord dr; + CacheEntry ce=*stored; + + //~ cerr<<"asked to store "<< qname+"|"+qt.getName()<<" -> '"<content<<"', isnew="<::iterator j; + for(j = ce.d_records.begin() ; j != ce.d_records.end(); ++j) + if((time_t)j->d_ttd > now) + break; + if(j != ce.d_records.end()) { // we still have valid data, ignore unauth data + // cerr<<"\tStill hold valid auth data, and the new data is unauth, return\n"; + return; + } + else { + ce.d_auth = false; // new data won't be auth + } + } + + // make sure that we CAN refresh the root + if(auth && ((qname.length()==1 && qname[0]=='.') || !attemptToRefreshNSTTL(qt, content, ce) ) ) { + // cerr<<"\tGot auth data, and it was not refresh attempt of an NS record, nuking storage"<::const_iterator i=content.begin(); i != content.end(); ++i) { + // cerr<<"To store: "<content<ttl; + dr.d_string=DNSRR2String(*i); + + if(isNew) + ce.d_records.push_back(dr); + else { + range=equal_range(ce.d_records.begin(), ce.d_records.end(), dr); + + if(range.first != range.second) { + // cerr<<"\t\tMay need to modify TTL of stored record\n"; + for(vector::iterator j=range.first ; j!=range.second; ++j) { + /* see http://mailman.powerdns.com/pipermail/pdns-users/2006-May/003413.html */ + if(j->d_ttd > (unsigned int) now && i->ttl > j->d_ttd && qt.getCode()==QType::NS && auth) { // don't allow auth servers to *raise* TTL of an NS record + //~ cerr<<"\t\tNot doing so, trying to raise TTL NS\n"; + continue; + } + if(i->ttl > j->d_ttd || (auth && d_followRFC2181) ) { // authoritative packets can override the TTL to be lower + //~ cerr<<"\t\tUpdating the ttl, diff="<d_ttd - i->ttl<d_ttd=i->ttl; + } + else { + //~ cerr<<"\t\tNOT updating the ttl, old= " <d_ttd - now <<", new: "<ttl - now <(ce.d_records).swap(ce.d_records); + + d_cache.replace(stored, ce); +} + +int MemRecursorCache::doWipeCache(const string& name, uint16_t qtype) +{ + int count=0; + d_cachecachevalid=false; + pair range; + if(qtype==0xffff) + range=d_cache.equal_range(tie(name)); + else + range=d_cache.equal_range(tie(name, qtype)); + + for(cache_t::const_iterator i=range.first; i != range.second; ) { + count++; + d_cache.erase(i++); + } + return count; +} + +bool MemRecursorCache::doAgeCache(time_t now, const string& name, uint16_t qtype, int32_t newTTL) +{ + cache_t::iterator iter = d_cache.find(tie(name, qtype)); + if(iter == d_cache.end()) + return false; + + int32_t ttl = iter->getTTD() - now; + if(ttl < 0) + return false; // would be dead anyhow + + if(ttl > newTTL) { + d_cachecachevalid=false; + + ttl = newTTL; + uint32_t newTTD = now + ttl; + + CacheEntry ce = *iter; + for(vector::iterator j = ce.d_records.begin() ; j != ce.d_records.end(); ++j) { + j->d_ttd = newTTD; + } + + d_cache.replace(iter, ce); + return true; + } + return false; +} + + +uint64_t MemRecursorCache::doDump(int fd) +{ + FILE* fp=fdopen(dup(fd), "w"); + if(!fp) { // dup probably failed + return 0; + } + fprintf(fp, "; main record cache dump from thread follows\n;\n"); + typedef cache_t::nth_index<1>::type sequence_t; + sequence_t& sidx=d_cache.get<1>(); + + uint64_t count=0; + time_t now=time(0); + for(sequence_t::const_iterator i=sidx.begin(); i != sidx.end(); ++i) { + for(vector::const_iterator j=i->d_records.begin(); j != i->d_records.end(); ++j) { + count++; + try { + DNSResourceRecord rr=String2DNSRR(i->d_qname, QType(i->d_qtype), j->d_string, j->d_ttd - now); + fprintf(fp, "%s %d IN %s %s\n", rr.qname.c_str(), rr.ttl, rr.qtype.getName().c_str(), rr.content.c_str()); + } + catch(...) { + fprintf(fp, "; error printing '%s'\n", i->d_qname.c_str()); + } + } + } + fclose(fp); + return count; +} + +void MemRecursorCache::doPrune(void) +{ + d_cachecachevalid=false; + + unsigned int maxCached=::arg().asNum("max-cache-entries") / g_numThreads; + pruneCollection(d_cache, maxCached); +} + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/recursor_cache.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/recursor_cache.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/recursor_cache.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/recursor_cache.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,114 @@ +#ifndef RECURSOR_CACHE_HH +#define RECURSOR_CACHE_HH +#include +#include +#include "dns.hh" +#include "qtype.hh" +#include "misc.hh" +#include + +#include +#undef L +#include +#include +#include +#include +#include +#include + +#undef max + +#define L theL() +#include "namespaces.hh" +using namespace ::boost::multi_index; + +class MemRecursorCache : public boost::noncopyable // : public RecursorCache +{ +public: + MemRecursorCache() : d_followRFC2181(false), d_cachecachevalid(false) + { + cacheHits = cacheMisses = 0; + } + unsigned int size(); + unsigned int bytes(); + int get(time_t, const string &qname, const QType& qt, set* res); + + int getDirect(time_t now, const char* qname, const QType& qt, uint32_t ttd[10], char* data[10], uint16_t len[10]); + void replace(time_t, const string &qname, const QType& qt, const set& content, bool auth); + void doPrune(void); + void doSlash(int perc); + uint64_t doDump(int fd); + int doWipeCache(const string& name, uint16_t qtype=0xffff); + bool doAgeCache(time_t now, const string& name, uint16_t qtype, int32_t newTTL); + uint64_t cacheHits, cacheMisses; + bool d_followRFC2181; + +private: + struct StoredRecord + { + mutable uint32_t d_ttd; + + string d_string; + + bool operator<(const StoredRecord& rhs) const + { + return d_string < rhs.d_string; + } + + unsigned int size() const + { + return sizeof(*this) + d_string.size(); + } + + }; + + struct CacheEntry + { + CacheEntry(const tuple& key, const vector& records, bool auth) : + d_qname(key.get<0>()), d_qtype(key.get<1>()), d_auth(auth), d_records(records) + {} + + typedef vector records_t; + + uint32_t getTTD() const + { + if(d_records.size()==1) + return d_records.begin()->d_ttd; + + uint32_t earliest=std::numeric_limits::max(); + for(records_t::const_iterator i=d_records.begin(); i != d_records.end(); ++i) + earliest=min(earliest, i->d_ttd); + return earliest; + } + + string d_qname; + uint16_t d_qtype; + bool d_auth; + records_t d_records; + }; + + typedef multi_index_container< + CacheEntry, + indexed_by < + ordered_unique< + composite_key< + CacheEntry, + member, + member + >, + composite_key_compare > + >, + sequenced<> + > + > cache_t; + + cache_t d_cache; + pair d_cachecache; + string d_cachedqname; + bool d_cachecachevalid; + bool attemptToRefreshNSTTL(const QType& qt, const set& content, const CacheEntry& stored); +}; +string DNSRR2String(const DNSResourceRecord& rr); +DNSResourceRecord String2DNSRR(const string& qname, const QType& qt, const string& serial, uint32_t ttd); + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/recursorservice.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/recursorservice.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/recursorservice.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/recursorservice.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,64 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2006 PowerDNS.COM 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 "recursorservice.hh" + +extern int serviceMain( int argc, char *argv[] ); + +// Control handler. +void RecursorService::ctrlHandler( DWORD controlCode ) +{ + if ( m_statusCode == SERVICE_STOPPED ) + exit( 0 ); + + switch ( controlCode ) + { + case SERVICE_CONTROL_STOP: + setStatus( SERVICE_STOP_PENDING ); + shutdown(); + setStatus( SERVICE_STOPPED ); + // FIXME: Add a cleaner way to do this: + break; + + case SERVICE_CONTROL_INTERROGATE: + setStatus( m_statusCode, m_errorCode ); + break; + + case SERVICE_CONTROL_SHUTDOWN: + setStatus( SERVICE_STOP_PENDING ); + shutdown(); + setStatus( SERVICE_STOPPED ); + // FIXME: Add a cleaner way to do this: + break; + } +} + + +// Returns the service name. +std::string RecursorService::getServiceName( void ) +{ + return "PowerDNS Recursor"; +} + + +// Main procedure. +int RecursorService::main( int argc, char *argv[] ) +{ + return serviceMain( argc, argv ); + +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/recursorservice.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/recursorservice.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/recursorservice.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/recursorservice.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,46 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 PowerDNS.COM 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 +*/ + +#ifndef AHUDNSSERVICE_HH +#define AHUDNSSERVICE_HH + +#include +#include "ntservice.hh" + +class RecursorService : public NTService +{ +protected: + //! Main service procedure. + int main( int argc, char *argv[] ); + + //! Control handler. + void ctrlHandler( DWORD controlCode ); + +public: + //! Constructor. + RecursorService( void ) : NTService() + { + } + + //! Returns the service name. + std::string getServiceName( void ); + +}; + +#endif // AHUDNSSERVICE_HH diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/reczones.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/reczones.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/reczones.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/reczones.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,437 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2003 - 2010 PowerDNS.COM 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 "syncres.hh" +#include "arguments.hh" +#include "zoneparser-tng.hh" +#include "logger.hh" +#include "dnsrecords.hh" + +void primeHints(void) +{ + // prime root cache + setnsset; + if(!t_RC) + t_RC = new MemRecursorCache(); + + if(::arg()["hint-file"].empty()) { + 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", + "192.36.148.17","192.58.128.30", "193.0.14.129", "199.7.83.42", "202.12.27.33"}; + static const char *ip6s[]={ + "2001:503:ba3e::2:30", NULL, NULL, NULL, NULL, + "2001:500:2f::f", NULL, "2001:500:1::803f:235", "2001:7fe::53", + "2001:503:c27::2:30", "2001:7fd::1", "2001:500:3::42", "2001:dc3::35" + }; + + DNSResourceRecord arr, aaaarr, nsrr; + arr.qtype=QType::A; + aaaarr.qtype=QType::AAAA; + nsrr.qtype=QType::NS; + arr.ttl=aaaarr.ttl=nsrr.ttl=time(0)+3600000; + + for(char c='a';c<='m';++c) { + static char templ[40]; + strncpy(templ,"a.root-servers.net.", sizeof(templ) - 1); + *templ=c; + aaaarr.qname=arr.qname=nsrr.content=templ; + arr.content=ips[c-'a']; + set aset; + aset.insert(arr); + t_RC->replace(time(0), string(templ), QType(QType::A), aset, true); // auth, nuke it all + if (ip6s[c-'a'] != NULL) { + aaaarr.content=ip6s[c-'a']; + + set aaaaset; + aaaaset.insert(aaaarr); + t_RC->replace(time(0), string(templ), QType(QType::AAAA), aaaaset, true); + } + + nsset.insert(nsrr); + } + } + else { + ZoneParserTNG zpt(::arg()["hint-file"]); + DNSResourceRecord rr; + + while(zpt.get(rr)) { + rr.ttl+=time(0); + if(rr.qtype.getCode()==QType::A) { + set aset; + aset.insert(rr); + t_RC->replace(time(0), rr.qname, QType(QType::A), aset, true); // auth, etc see above + } else if(rr.qtype.getCode()==QType::AAAA) { + set aaaaset; + aaaaset.insert(rr); + t_RC->replace(time(0), rr.qname, QType(QType::AAAA), aaaaset, true); + } else if(rr.qtype.getCode()==QType::NS) { + rr.content=toLower(rr.content); + nsset.insert(rr); + } + } + } + t_RC->replace(time(0),".", QType(QType::NS), nsset, true); // and stuff in the cache (auth) +} + +static void makeNameToIPZone(SyncRes::domainmap_t* newMap, const string& hostname, const string& ip) +{ + SyncRes::AuthDomain ad; + DNSResourceRecord rr; + rr.qname=toCanonic("", hostname); + rr.d_place=DNSResourceRecord::ANSWER; + rr.ttl=86400; + rr.qtype=QType::SOA; + rr.content="localhost. root 1 604800 86400 2419200 604800"; + + ad.d_records.insert(rr); + + rr.qtype=QType::NS; + rr.content="localhost."; + + ad.d_records.insert(rr); + + rr.qtype=QType::A; + rr.content=ip; + ad.d_records.insert(rr); + + if(newMap->count(rr.qname)) { + L<& parts) +{ + string address=parts[0]; + vector ipparts; + stringtok(ipparts, address,"."); + + SyncRes::AuthDomain ad; + DNSResourceRecord rr; + for(int n=ipparts.size()-1; n>=0 ; --n) { + rr.qname.append(ipparts[n]); + rr.qname.append(1,'.'); + } + rr.qname.append("in-addr.arpa."); + + rr.d_place=DNSResourceRecord::ANSWER; + rr.ttl=86400; + rr.qtype=QType::SOA; + rr.content="localhost. root. 1 604800 86400 2419200 604800"; + + ad.d_records.insert(rr); + + rr.qtype=QType::NS; + rr.content="localhost."; + + ad.d_records.insert(rr); + rr.qtype=QType::PTR; + + if(ipparts.size()==4) // otherwise this is a partial zone + for(unsigned int n=1; n < parts.size(); ++n) { + rr.content=toCanonic("", parts[n]); + ad.d_records.insert(rr); + } + + if(newMap->count(rr.qname)) { + L< both; + + try { // case 2 + both=splitField(input,':'); + uint16_t newport=boost::lexical_cast(both.second); + return ComboAddress(both.first, newport); + } + catch(...){} + + if(input[0]=='[') { // case 4 + both=splitField(input.substr(1),']'); + return ComboAddress(both.first, both.second.empty() ? port : boost::lexical_cast(both.second.substr(1))); + } + + return ComboAddress(input, port); // case 3 +} + + +void convertServersForAD(const std::string& input, SyncRes::AuthDomain& ad, const char* sepa, bool verbose=true) +{ + vector servers; + stringtok(servers, input, sepa); + ad.d_servers.clear(); + + for(vector::const_iterator iter = servers.begin(); iter != servers.end(); ++iter) { + if(verbose && iter != servers.begin()) + L<<", "; + + ComboAddress addr=parseIPAndPort(*iter, 53); + if(verbose) + L<negcache.clear(); + return 0; +} + +void* pleaseUseNewSDomainsMap(SyncRes::domainmap_t* newmap) +{ + t_sstorage->domainmap = newmap; + return 0; +} + +string reloadAuthAndForwards() +{ + SyncRes::domainmap_t* original=t_sstorage->domainmap; + + try { + L<domainmap->begin(); i != t_sstorage->domainmap->end(); ++i) { + for(SyncRes::AuthDomain::records_t::const_iterator j = i->second.d_records.begin(); j != i->second.d_records.end(); ++j) + broadcastAccFunction(boost::bind(pleaseWipeCache, j->qname)); + } + + string configname=::arg()["config-dir"]+"/recursor.conf"; + cleanSlashes(configname); + + if(!::arg().preParseFile(configname.c_str(), "forward-zones")) + L<begin(); i != newDomainMap->end(); ++i) { + for(SyncRes::AuthDomain::records_t::const_iterator j = i->second.d_records.begin(); j != i->second.d_records.end(); ++j) + broadcastAccFunction(boost::bind(pleaseWipeCache, j->qname)); + } + + // this is pretty blunt + broadcastFunction(pleaseWipeNegCache); + broadcastFunction(boost::bind(pleaseUseNewSDomainsMap, newDomainMap)); + delete original; + return "ok\n"; + } + catch(std::exception& e) { + L< parts_t; + parts_t parts; + const char *option_names[3]={"auth-zones", "forward-zones", "forward-zones-recurse"}; + for(int n=0; n < 3 ; ++n ) { + parts.clear(); + stringtok(parts, ::arg()[option_names[n]], ",\t\n\r"); + for(parts_t::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) { + SyncRes::AuthDomain ad; + pair headers=splitField(*iter, '='); + trim(headers.first); + trim(headers.second); + headers.first=toCanonic("", headers.first); + if(n==0) { + L< fp=shared_ptr(rfp, fclose); + + string line; + int linenum=0; + uint64_t before = newMap->size(); + while(linenum++, stringfgets(fp.get(), line)) { + string domain, instructions; + tie(domain, instructions)=splitField(line, '='); + trim(domain); + trim(instructions); + if(domain.empty() && instructions.empty()) { // empty line + continue; + } + if(boost::starts_with(domain,"+")) { + domain=domain.c_str()+1; + ad.d_rdForward = true; + } + else + ad.d_rdForward = false; + if(domain.empty()) { + delete newMap; + throw AhuException("Error parsing line "+lexical_cast(linenum)+" of " +::arg()["forward-zones-file"]); + } + + try { + convertServersForAD(instructions, ad, ",; ", false); + } + catch(...) { + delete newMap; + throw AhuException("Conversion error parsing line "+lexical_cast(linenum)+" of " +::arg()["forward-zones-file"]); + } + + (*newMap)[toCanonic("", domain)]=ad; + } + L<size() - before<<" forwarding instructions from file '"<<::arg()["forward-zones-file"]<<"'"<(n); + makeIPToNamesZone(newMap,parts); + } + } + return newMap; +} + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rrd/create pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rrd/create --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rrd/create 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rrd/create 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,47 @@ +#!/bin/sh + +UPDATE_INTERVAL=60 + +rrdtool create pdns_recursor.rrd -s $UPDATE_INTERVAL \ +DS:questions:COUNTER:600:0:100000 \ +DS:tcp-questions:COUNTER:600:0:100000 \ +DS:cache-entries:GAUGE:600:0:U \ +DS:packetcache-entries:GAUGE:600:0:U \ +DS:throttle-entries:GAUGE:600:0:U \ +DS:concurrent-queries:GAUGE:600:0:50000 \ +DS:noerror-answers:COUNTER:600:0:100000 \ +DS:nxdomain-answers:COUNTER:600:0:100000 \ +DS:servfail-answers:COUNTER:600:0:100000 \ +DS:tcp-outqueries:COUNTER:600:0:100000 \ +DS:outgoing-timeouts:COUNTER:600:0:100000 \ +DS:throttled-out:COUNTER:600:0:100000 \ +DS:nsspeeds-entries:GAUGE:600:0:U \ +DS:negcache-entries:GAUGE:600:0:U \ +DS:all-outqueries:COUNTER:600:0:100000 \ +DS:cache-hits:COUNTER:600:0:100000 \ +DS:cache-misses:COUNTER:600:0:100000 \ +DS:packetcache-hits:COUNTER:600:0:100000 \ +DS:packetcache-misses:COUNTER:600:0:100000 \ +DS:answers0-1:COUNTER:600:0:100000 \ +DS:answers1-10:COUNTER:600:0:100000 \ +DS:answers10-100:COUNTER:600:0:100000 \ +DS:answers100-1000:COUNTER:600:0:100000 \ +DS:answers-slow:COUNTER:600:0:100000 \ +DS:udp-overruns:COUNTER:600:0:100000 \ +DS:qa-latency:GAUGE:600:0:10000000 \ +DS:user-msec:COUNTER:600:0:64000 \ +DS:uptime:GAUGE:600:0:U \ +DS:unexpected-packets:COUNTER:600:0:1000000 \ +DS:resource-limits:COUNTER:600:0:1000000 \ +DS:over-capacity-drops:COUNTER:600:0:1000000 \ +DS:client-parse-errors:COUNTER:600:0:1000000 \ +DS:server-parse-errors:COUNTER:600:0:1000000 \ +DS:unauthorized-udp:COUNTER:600:0:1000000 \ +DS:unauthorized-tcp:COUNTER:600:0:1000000 \ +DS:sys-msec:COUNTER:600:0:6400 \ + RRA:AVERAGE:0.5:1:9600 \ + RRA:AVERAGE:0.5:4:9600 \ + RRA:AVERAGE:0.5:24:6000 \ + RRA:MAX:0.5:1:9600 \ + RRA:MAX:0.5:4:9600 \ + RRA:MAX:0.5:24:6000 diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rrd/index.html pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rrd/index.html --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rrd/index.html 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rrd/index.html 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,59 @@ + + + +

PowerDNS Recursor Performance Graphs

+ + + + + + + + + + +
QuestionsEnd-user initiated DNS questions
Out-queriesRecursor initiated questions to other +nameservers
ThrottledIf a certain nameserver is not responding, or if +it is, but returning unuseful answers, it is not useful to keep repeating +identical queries. If PowerDNS prevents a duplicate query, and therefore +prevents needless server load and delays, this is called a 'throttled +out-query'
Outgoing timeoutAn out-query that did not generate an +answer within 1 or 2 seconds
Noerror answerA Question that was answered without an error +status
NXDOMAIN answerA Question that was answered with a positive +indication that there is no answer
SERVFAIL answerNo answer could be given because the nameservers +carrying the answer did not respond, or were throttled
Cache hits/missesA query is judged a cache-hit if it could +be answered without generating any out-queries
User/System CPU usageActual amount of CPU used exclusively +by the recursor, either in user or in system (kernel) mode
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ +
+ + + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rrd/makegraphs pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rrd/makegraphs --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rrd/makegraphs 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rrd/makegraphs 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,187 @@ +#!/bin/bash +WWWPREFIX=. +WSIZE=800 +HSIZE=250 + +# only recent rrds offer slope-mode: +GRAPHOPTS=--slope-mode + +function makeGraphs() +{ + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/questions-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Questions and answers per second" \ + -v "packets" \ + DEF:questions=pdns_recursor.rrd:questions:AVERAGE \ + DEF:nxdomainanswers=pdns_recursor.rrd:nxdomain-answers:AVERAGE \ + DEF:noerroranswers=pdns_recursor.rrd:noerror-answers:AVERAGE \ + DEF:servfailanswers=pdns_recursor.rrd:servfail-answers:AVERAGE \ + LINE1:questions#0000ff:"questions/s"\ + AREA:noerroranswers#00ff00:"noerror answers/s" \ + STACK:nxdomainanswers#ffa500:"nxdomain answers/s"\ + STACK:servfailanswers#ff0000:"servfail answers/s" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/tcp-questions-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "TCP questions and answers per second, unauthorized packets/s" \ + -v "packets" \ + DEF:tcpquestions=pdns_recursor.rrd:tcp-questions:AVERAGE \ + DEF:unauthudp=pdns_recursor.rrd:unauthorized-udp:AVERAGE \ + DEF:unauthtcp=pdns_recursor.rrd:unauthorized-tcp:AVERAGE \ + LINE1:tcpquestions#0000ff:"tcp questions/s" \ + LINE1:unauthudp#ff0000:"udp unauth/s" \ + LINE1:unauthtcp#00ff00:"tcp unauth/s" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/packet-errors-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Packet errors per second" \ + -v "packets" \ + DEF:clientparseerrors=pdns_recursor.rrd:client-parse-errors:AVERAGE \ + DEF:serverparseerrors=pdns_recursor.rrd:server-parse-errors:AVERAGE \ + DEF:unexpected=pdns_recursor.rrd:unexpected-packets:AVERAGE \ + DEF:udpoverruns=pdns_recursor.rrd:udp-overruns:AVERAGE \ + LINE1:clientparseerrors#0000ff:"bad packets from clients" \ + LINE1:serverparseerrors#00ff00:"bad packets from servers" \ + LINE1:unexpected#ff0000:"unexpected packets from servers" \ + LINE1:udpoverruns#ff00ff:"udp overruns from remotes" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/limits-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Limitations per second" \ + -v "events" \ + DEF:resourcelimits=pdns_recursor.rrd:resource-limits:AVERAGE \ + DEF:overcapacities=pdns_recursor.rrd:over-capacity-drops:AVERAGE \ + LINE1:resourcelimits#ff0000:"outqueries dropped because of resource limits" \ + LINE1:overcapacities#0000ff:"questions dropped because of mthread limit" + + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/latencies-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Questions answered within latency" \ + -v "questions" \ + DEF:questions=pdns_recursor.rrd:questions:AVERAGE \ + DEF:answers00=pdns_recursor.rrd:packetcache-hits:AVERAGE \ + DEF:answers01=pdns_recursor.rrd:answers0-1:AVERAGE \ + DEF:answers110=pdns_recursor.rrd:answers1-10:AVERAGE \ + DEF:answers10100=pdns_recursor.rrd:answers10-100:AVERAGE \ + DEF:answers1001000=pdns_recursor.rrd:answers100-1000:AVERAGE \ + DEF:answersslow=pdns_recursor.rrd:answers-slow:AVERAGE \ + LINE1:questions#0000ff:"questions/s" \ + AREA:answers00#00ff00:"<<1 ms" \ + STACK:answers01#00fff0:"<1 ms" \ + STACK:answers110#0000ff:"<10 ms" \ + STACK:answers10100#ff9900:"<100 ms" \ + STACK:answers1001000#ffff00:"<1000 ms" \ + STACK:answersslow#ff0000:">1000 ms" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/qoutq-$2.png -w $WSIZE -h $HSIZE -l 0 \ + -t "Questions/outqueries per second" \ + -v "packets" \ + DEF:questions=pdns_recursor.rrd:questions:AVERAGE \ + DEF:alloutqueries=pdns_recursor.rrd:all-outqueries:AVERAGE \ + LINE1:questions#ff0000:"questions/s"\ + LINE1:alloutqueries#00ff00:"outqueries/s" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/qa-latency-$2.png -w $WSIZE -h $HSIZE -l 0 \ + -t "Questions/answer latency in milliseconds" \ + -v "msec" \ + DEF:qalatency=pdns_recursor.rrd:qa-latency:AVERAGE \ + CDEF:mqalatency=qalatency,1000,/ \ + LINE1:mqalatency#ff0000:"questions/s" + + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/timeouts-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Outqueries/timeouts per second" \ + -v "events" \ + DEF:alloutqueries=pdns_recursor.rrd:all-outqueries:AVERAGE \ + DEF:outgoingtimeouts=pdns_recursor.rrd:outgoing-timeouts:AVERAGE \ + DEF:throttledout=pdns_recursor.rrd:throttled-out:AVERAGE \ + LINE1:alloutqueries#ff0000:"outqueries/s"\ + LINE1:outgoingtimeouts#00ff00:"outgoing timeouts/s"\ + LINE1:throttledout#0000ff:"throttled outqueries/s" + + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/caches-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Cache sizes" \ + -v "entries" \ + DEF:cacheentries=pdns_recursor.rrd:cache-entries:AVERAGE \ + DEF:packetcacheentries=pdns_recursor.rrd:packetcache-entries:AVERAGE \ + DEF:negcacheentries=pdns_recursor.rrd:negcache-entries:AVERAGE \ + DEF:nsspeedsentries=pdns_recursor.rrd:nsspeeds-entries:AVERAGE \ + DEF:throttleentries=pdns_recursor.rrd:throttle-entries:AVERAGE \ + LINE1:cacheentries#ff0000:"cache entries" \ + LINE1:packetcacheentries#ffff00:"packet cache entries" \ + LINE1:negcacheentries#0000ff:"negative cache entries" \ + LINE1:nsspeedsentries#00ff00:"NS speeds entries" \ + LINE1:throttleentries#00fff0:"throttle map entries" + + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/caches2-$2.png -w $WSIZE -h $HSIZE -l 0\ + -t "Cache sizes" \ + -v "entries" \ + DEF:negcacheentries=pdns_recursor.rrd:negcache-entries:AVERAGE \ + DEF:nsspeedsentries=pdns_recursor.rrd:nsspeeds-entries:AVERAGE \ + DEF:throttleentries=pdns_recursor.rrd:throttle-entries:AVERAGE \ + LINE1:negcacheentries#0000ff:"negative cache entries" \ + LINE1:nsspeedsentries#00ff00:"NS speeds entries" \ + LINE1:throttleentries#ffa000:"throttle map entries" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/load-$2.png -w $WSIZE -h $HSIZE -l 0\ + -v "MThreads" \ + -t "Concurrent queries" \ + DEF:concurrentqueries=pdns_recursor.rrd:concurrent-queries:AVERAGE \ + LINE1:concurrentqueries#0000ff:"concurrent queries" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/hitrate-$2.png -w $WSIZE -h $HSIZE -l 0\ + -v "percentage" \ + -t "cache hits" \ + DEF:cachehits=pdns_recursor.rrd:cache-hits:AVERAGE \ + DEF:cachemisses=pdns_recursor.rrd:cache-misses:AVERAGE \ + DEF:packetcachehits=pdns_recursor.rrd:packetcache-hits:AVERAGE \ + DEF:packetcachemisses=pdns_recursor.rrd:packetcache-misses:AVERAGE \ + CDEF:perc=cachehits,100,*,cachehits,cachemisses,+,/ \ + CDEF:packetperc=packetcachehits,100,*,packetcachehits,packetcachemisses,+,/ \ + LINE1:perc#0000ff:"percentage cache hits" \ + LINE1:packetperc#ff00ff:"percentage packetcache hits" \ + COMMENT:"\l" \ + COMMENT:"Cache hits " \ + GPRINT:perc:AVERAGE:"avg %-3.1lf%%\t" \ + GPRINT:perc:LAST:"last %-3.1lf%%\t" \ + GPRINT:perc:MAX:"max %-3.1lf%%" \ + COMMENT:"\l" \ + COMMENT:"Pkt hits " \ + GPRINT:packetperc:AVERAGE:"avg %-3.1lf%%\t" \ + GPRINT:packetperc:LAST:"last %-3.1lf%%\t" \ + GPRINT:packetperc:MAX:"max %-3.1lf%%" \ + COMMENT:"\l" + + rrdtool graph $GRAPHOPTS --start -$1 $WWWPREFIX/cpuload-$2.png -w $WSIZE -h $HSIZE -l 0\ + -v "percentage" \ + -t "cpu load" \ + DEF:usermsec=pdns_recursor.rrd:user-msec:AVERAGE \ + DEF:sysmsec=pdns_recursor.rrd:sys-msec:AVERAGE \ + DEF:musermsec=pdns_recursor.rrd:user-msec:MAX \ + DEF:msysmsec=pdns_recursor.rrd:sys-msec:MAX \ + CDEF:userperc=usermsec,10,/ \ + CDEF:sysperc=sysmsec,10,/ \ + CDEF:totmperc=usermsec,sysmsec,+,10,/ \ + LINE1:totmperc#ffff00:"max cpu use" \ + AREA:userperc#ff0000:"user cpu percentage" \ + STACK:sysperc#00ff00:"system cpu percentage" \ + COMMENT:"\l" \ + COMMENT:"System cpu " \ + GPRINT:sysperc:AVERAGE:"avg %-3.1lf%%\t" \ + GPRINT:sysperc:LAST:"last %-3.1lf%%\t" \ + GPRINT:sysperc:MAX:"max %-3.1lf%%\t" \ + COMMENT:"\l" \ + COMMENT:"User cpu " \ + GPRINT:userperc:AVERAGE:"avg %-3.1lf%%\t" \ + GPRINT:userperc:LAST:"last %-3.1lf%%\t" \ + GPRINT:userperc:MAX:"max %-3.1lf%%" \ + COMMENT:"\l" + + +} + +makeGraphs 6h 6h +makeGraphs 24h day +#makeGraphs 7d week +#makeGraphs 1m month +#makeGraphs 1y year + + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rrd/update pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rrd/update --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/rrd/update 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/rrd/update 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,75 @@ +#!/usr/bin/env bash +SOCKETDIR=/var/run/ +TSTAMP=$(date +%s) + +OS=`uname` +if [ "$OS" == "Linux" ] +then +# echo "Using Linux netstat directive" + NETSTAT_GREP="packet receive error" +elif [ "$OS" == "FreeBSD" ] +then +# echo "Using FreeBSD netstat directive" + NETSTAT_GREP="dropped due to full socket buffers" +else + echo "Unsupported OS found, please report to the PowerDNS team." + exit 1 +fi + + +VARIABLES="questions \ + tcp-questions \ + cache-entries \ + packetcache-entries \ + concurrent-queries \ + nxdomain-answers \ + noerror-answers \ + servfail-answers \ + tcp-outqueries \ + outgoing-timeouts \ + nsspeeds-entries \ + negcache-entries \ + all-outqueries \ + throttled-out \ + packetcache-hits \ + packetcache-misses \ + cache-hits \ + cache-misses \ + answers0-1 \ + answers1-10 \ + answers10-100 \ + answers100-1000 \ + answers-slow \ + qa-latency \ + throttle-entries \ + sys-msec user-msec \ + unauthorized-udp \ + unauthorized-tcp \ + client-parse-errors \ + server-parse-errors \ + uptime unexpected-packets \ + resource-limits \ + over-capacity-drops" + +UVARIABLES=$(echo $VARIABLES | tr '[a-z]' '[A-Z]' | tr - _ ) + +rec_control --socket-dir=$SOCKETDIR GET $VARIABLES | +( + for a in $UVARIABLES + do + read $a + done + rrdtool update pdns_recursor.rrd \ + -t "udp-overruns:"$(for a in $VARIABLES + do + echo -n $a: + done | sed 's/:$//' ) \ +$TSTAMP$( + echo -n : + netstat -s | grep "$NETSTAT_GREP" | awk '{printf $1}' + for a in $UVARIABLES + do + echo -n :${!a} + done + ) +) diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/selectmplexer.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/selectmplexer.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/selectmplexer.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/selectmplexer.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,130 @@ +#include "mplexer.hh" +#include "sstuff.hh" +#include +#include "misc.hh" +#include +#include "syncres.hh" +#include "utility.hh" + + +#include "namespaces.hh" +#include "namespaces.hh" + +static FDMultiplexer* make() +{ + return new SelectFDMultiplexer(); +} + +static struct RegisterOurselves +{ + RegisterOurselves() { + FDMultiplexer::getMultiplexerMap().insert(make_pair(1, &make)); + } +} doIt; + +void SelectFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter) +{ + Callback cb; + cb.d_callback=toDo; + cb.d_parameter=parameter; + memset(&cb.d_ttd, 0, sizeof(cb.d_ttd)); + if(cbmap.count(fd)) + throw FDMultiplexerException("Tried to add fd "+lexical_cast(fd)+ " to multiplexer twice"); + cbmap[fd]=cb; +} + +void SelectFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd) +{ + if(d_inrun && d_iter->first==fd) // trying to remove us! + d_iter++; + + if(!cbmap.erase(fd)) + throw FDMultiplexerException("Tried to remove unlisted fd "+lexical_cast(fd)+ " from multiplexer"); +} + +int SelectFDMultiplexer::run(struct timeval* now) +{ + if(d_inrun) { + throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n"); + } + fd_set readfds, writefds; + FD_ZERO(&readfds); + FD_ZERO(&writefds); + + int fdmax=0; + + for(callbackmap_t::const_iterator i=d_readCallbacks.begin(); i != d_readCallbacks.end(); ++i) { + FD_SET(i->first, &readfds); + fdmax=max(i->first, fdmax); + } + + for(callbackmap_t::const_iterator i=d_writeCallbacks.begin(); i != d_writeCallbacks.end(); ++i) { + FD_SET(i->first, &writefds); + fdmax=max(i->first, fdmax); + } + + struct timeval tv={0,500000}; + int ret=select(fdmax + 1, &readfds, &writefds, 0, &tv); + Utility::gettimeofday(now, 0); // MANDATORY! + + if(ret < 0 && errno!=EINTR) + throw FDMultiplexerException("select returned error: "+stringerror()); + + if(ret < 1) // nothing - thanks AB + return 0; + + d_iter=d_readCallbacks.end(); + d_inrun=true; + + for(callbackmap_t::iterator i=d_readCallbacks.begin(); i != d_readCallbacks.end() && i->first <= fdmax; ) { + d_iter=i++; + + if(FD_ISSET(d_iter->first, &readfds)) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + continue; // so we don't refind ourselves as writable + } + } + + for(callbackmap_t::iterator i=d_writeCallbacks.begin(); i != d_writeCallbacks.end() && i->first <= fdmax; ) { + d_iter=i++; + if(FD_ISSET(d_iter->first, &writefds)) { + d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter); + } + } + + d_inrun=false; + return 0; +} + +#if 0 + +void acceptData(int fd, boost::any& parameter) +{ + cout<<"Have data on fd "<(parameter); + string packet; + IPEndpoint rem; + sock->recvFrom(packet, rem); + cout<<"Received "< +#include +#include +#include +#include +#include +#include "dnsrecords.hh" + +static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000, + 1000000,10000000,100000000,1000000000}; + +/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer.*/ +static uint8_t precsize_aton(const char **strptr) +{ + unsigned int mval = 0, cmval = 0; + uint8_t retval = 0; + const char *cp; + int exponent; + int mantissa; + + cp = *strptr; + + while (isdigit(*cp)) + mval = mval * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* centimeters */ + cp++; + if (isdigit(*cp)) { + cmval = (*cp++ - '0') * 10; + if (isdigit(*cp)) { + cmval += (*cp++ - '0'); + } + } + } + cmval = (mval * 100) + cmval; + + for (exponent = 0; exponent < 9; exponent++) + if (cmval < poweroften[exponent+1]) + break; + + mantissa = cmval / poweroften[exponent]; + if (mantissa > 9) + mantissa = 9; + + retval = (mantissa << 4) | exponent; + + *strptr = cp; + + return (retval); +} + +/* converts ascii lat/lon to unsigned encoded 32-bit number. + * moves pointer. */ +static uint32_t +latlon2ul(const char **latlonstrptr, int *which) +{ + const char *cp; + uint32_t retval; + int deg = 0, min = 0, secs = 0, secsfrac = 0; + + cp = *latlonstrptr; + + while (isdigit(*cp)) + deg = deg * 10 + (*cp++ - '0'); + + while (isspace(*cp)) + cp++; + + if (!(isdigit(*cp))) + goto fndhemi; + + while (isdigit(*cp)) + min = min * 10 + (*cp++ - '0'); + + while (isspace(*cp)) + cp++; + + if (!(isdigit(*cp))) + goto fndhemi; + + while (isdigit(*cp)) + secs = secs * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal seconds */ + cp++; + if (isdigit(*cp)) { + secsfrac = (*cp++ - '0') * 100; + if (isdigit(*cp)) { + secsfrac += (*cp++ - '0') * 10; + if (isdigit(*cp)) { + secsfrac += (*cp++ - '0'); + } + } + } + } + + while (!isspace(*cp)) /* if any trailing garbage */ + cp++; + + while (isspace(*cp)) + cp++; + + fndhemi: + switch (*cp) { + case 'N': case 'n': + case 'E': case 'e': + retval = ((unsigned)1<<31) + + (((((deg * 60) + min) * 60) + secs) * 1000) + + secsfrac; + break; + case 'S': case 's': + case 'W': case 'w': + retval = ((unsigned)1<<31) + - (((((deg * 60) + min) * 60) + secs) * 1000) + - secsfrac; + break; + default: + retval = 0; /* invalid value -- indicates error */ + break; + } + + switch (*cp) { + case 'N': case 'n': + case 'S': case 's': + *which = 1; /* latitude */ + break; + case 'E': case 'e': + case 'W': case 'w': + *which = 2; /* longitude */ + break; + default: + *which = 0; /* error */ + break; + } + + cp++; /* skip the hemisphere */ + + while (!isspace(*cp)) /* if any trailing garbage */ + cp++; + + while (isspace(*cp)) /* move to next field */ + cp++; + + *latlonstrptr = cp; + + return (retval); +} + +void LOCRecordContent::report(void) +{ + regist(1, ns_t_loc, &make, &make, "LOC"); +} + +DNSRecordContent* LOCRecordContent::make(const string& content) +{ + return new LOCRecordContent(content); +} + + +void LOCRecordContent::toPacket(DNSPacketWriter& pw) +{ + pw.xfr8BitInt(d_version); + pw.xfr8BitInt(d_size); + pw.xfr8BitInt(d_horizpre); + pw.xfr8BitInt(d_vertpre); + + pw.xfr32BitInt(d_latitude); + pw.xfr32BitInt(d_longitude); + pw.xfr32BitInt(d_altitude); +} + +LOCRecordContent::DNSRecordContent* LOCRecordContent::make(const DNSRecord &dr, PacketReader& pr) +{ + LOCRecordContent* ret=new LOCRecordContent(); + pr.xfr8BitInt(ret->d_version); + pr.xfr8BitInt(ret->d_size); + pr.xfr8BitInt(ret->d_horizpre); + pr.xfr8BitInt(ret->d_vertpre); + + pr.xfr32BitInt(ret->d_latitude); + pr.xfr32BitInt(ret->d_longitude); + pr.xfr32BitInt(ret->d_altitude); + + return ret; +} + +LOCRecordContent::LOCRecordContent(const string& content, const string& zone) : DNSRecordContent(ns_t_loc) +{ + // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m + // convert this to d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude + d_version = 0; + + const char *cp, *maxcp; + + uint32_t lltemp1 = 0, lltemp2 = 0; + int altmeters = 0, altfrac = 0, altsign = 1; + d_horizpre = 0x16; /* default = 1e6 cm = 10000.00m = 10km */ + d_vertpre = 0x13; /* default = 1e3 cm = 10.00m */ + d_size = 0x12; /* default = 1e2 cm = 1.00m */ + int which1 = 0, which2 = 0; + + cp = content.c_str(); + maxcp = cp + strlen(content.c_str()); + + lltemp1 = latlon2ul(&cp, &which1); + lltemp2 = latlon2ul(&cp, &which2); + + switch (which1 + which2) { + case 3: /* 1 + 2, the only valid combination */ + if ((which1 == 1) && (which2 == 2)) { /* normal case */ + d_latitude = lltemp1; + d_longitude = lltemp2; + } else if ((which1 == 2) && (which2 == 1)) {/*reversed*/ + d_latitude = lltemp1; + d_longitude = lltemp2; + } else { /* some kind of brokenness */ + return; + } + break; + default: /* we didn't get one of each */ + return; + } + + /* altitude */ + if (*cp == '-') { + altsign = -1; + cp++; + } + + if (*cp == '+') + cp++; + + while (isdigit(*cp)) + altmeters = altmeters * 10 + (*cp++ - '0'); + + if (*cp == '.') { /* decimal meters */ + cp++; + if (isdigit(*cp)) { + altfrac = (*cp++ - '0') * 10; + if (isdigit(*cp)) { + altfrac += (*cp++ - '0'); + } + } + } + + d_altitude = (10000000 + (altsign * (altmeters * 100 + altfrac))); + + while (!isspace(*cp) && (cp < maxcp)) + /* if trailing garbage or m */ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + + if (cp >= maxcp) + goto defaults; + + d_size = precsize_aton(&cp); + + while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + d_horizpre = precsize_aton(&cp); + + while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/ + cp++; + + while (isspace(*cp) && (cp < maxcp)) + cp++; + + if (cp >= maxcp) + goto defaults; + + d_vertpre = precsize_aton(&cp); + + defaults: + ; +} + + +string LOCRecordContent::getZoneRepresentation() const +{ + // convert d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude to: + // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m + + double latitude= ((int32_t)d_latitude - (1<<31))/3600000.0; + double longitude=((int32_t)d_longitude - (1<<31))/3600000.0; + double altitude= ((int32_t)d_altitude )/100.0 - 100000; + + double size=0.01*((d_size>>4)&0xf); + int count=d_size & 0xf; + while(count--) + size*=10; + + double horizpre=0.01*((d_horizpre>>4) & 0xf); + count=d_horizpre&0xf; + while(count--) + horizpre*=10; + + double vertpre=0.01*((d_vertpre>>4)&0xf); + count=d_vertpre&0xf; + while(count--) + vertpre*=10; + + double remlat=60.0*(latitude-(int)latitude); + double remlong=60.0*(longitude-(int)longitude); + char ret[80]; + snprintf(ret,sizeof(ret)-1,"%d %d %2.03f %c %d %d %2.03f %c %.2fm %.2fm %.2fm %.2fm", + abs((int)latitude), abs((int) ((latitude-(int)latitude)*60)), + fabs((double)((remlat-(int)remlat)*60.0)), + latitude>0 ? 'N' : 'S', + abs((int)longitude), abs((int) ((longitude-(int)longitude)*60)), + fabs((double)((remlong-(int)remlong)*60.0)), + longitude>0 ? 'E' : 'W', + altitude, size, horizpre, vertpre); + + return ret; +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/singleton.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/singleton.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/singleton.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/singleton.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,127 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 PowerDNS.COM 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 +*/ + +#ifndef SINGLETON_HH +#define SINGLETON_HH + +#define WINDOWS_LEAN_AND_MEAN +#include + + +//! A common singleton template class. +template +class Singleton +{ +private: + static long m_refCount; //! Reference counter. + static _Ty *m_pInstance; //! Pointer to the actual instance. + + //! No assign operator allowed. + const _Ty & operator=( const _Ty & rhv ) + { + } + + //! No copy constructor. + Singleton( const _Ty & copy ) + { + } + +protected: +public: + //! Default constructor. + Singleton( void ) + { + if ( m_refCount == 0 ) + { + m_pInstance = reinterpret_cast< _Ty * >( this ); + } + + // Increase refcount. + InterlockedIncrement( &m_refCount ); + } + + //! Destructor. + virtual ~Singleton( void ) + { + if ( m_refCount == 0 ) + return; + + if ( InterlockedDecrement( &m_refCount ) == 0 ) + { + m_pInstance = NULL; + } + } + + //! Creates the singleton. + static _Ty *create( void ) + { + if ( m_refCount == 0 ) + { + m_pInstance = new _Ty; + } + + // Increase refcount. + InterlockedIncrement( &m_refCount ); + + return m_pInstance; + } + + //! Releases the singleton. + static void release( void ) + { + if ( m_refCount == 0 ) + return; + + if ( InterlockedDecrement( &m_refCount ) == 0 ) + { + // No more instances needed, delete object. + delete m_pInstance; + m_pInstance = NULL; + } + } + + //! Returns a pointer to the singleton. + static _Ty *instance( void ) + { + return m_pInstance; + } + + //! Initializes the singleton. + virtual bool init( void ) + { + return true; + } + + //! Shuts the singleton down. + virtual bool shutdown( void ) + { + return true; + } + +}; + + +template +_Ty *Singleton< _Ty >::m_pInstance = NULL; + +template +long Singleton< _Ty >::m_refCount = 0; + + +#endif // SINGLETON_HH diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/sstuff.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/sstuff.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/sstuff.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/sstuff.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,284 @@ +#ifndef SSTUFF_HH +#define SSTUFF_HH + +#include +#include +#include +#include "iputils.hh" +#include +#include +#ifndef WIN32 +#include +#include +#include +#include +#include +#endif +#include +#include +#include +#include +#include +#include "namespaces.hh" +#include "namespaces.hh" + + +class NetworkError : public runtime_error +{ +public: + NetworkError(const string& why="Network Error") : runtime_error(why.c_str()) + {} + NetworkError(const char *why="Network Error") : runtime_error(why) + {} +}; + + +enum AddressFamily {InterNetwork=AF_INET, InterNetwork6 = AF_INET6}; //!< Supported address families +enum SocketType {Datagram=SOCK_DGRAM,Stream=SOCK_STREAM}; //!< Supported socket families +typedef int ProtocolType; //!< Supported protocol types + +//! Representation of a Socket and many of the Berkeley functions available +class Socket : public boost::noncopyable +{ +private: + explicit Socket(int fd) + { + d_buflen=4096; + d_buffer=new char[d_buflen]; + d_socket=fd; + } +public: + //! Construct a socket of specified AddressFamily and SocketType. + Socket(AddressFamily af, SocketType st, ProtocolType pt=0) + { + d_family=af; + if((d_socket=(int)socket(af,st, pt))<0) + throw NetworkError(strerror(errno)); + Utility::setCloseOnExec(d_socket); + + d_buflen=4096; + d_buffer=new char[d_buflen]; + } + + ~Socket() + { + Utility::closesocket(d_socket); + delete[] d_buffer; + } + + //! If the socket is capable of doing so, this function will wait for a connection + Socket *accept() + { + struct sockaddr_in remote; + socklen_t remlen=sizeof(remote); + memset(&remote, 0, sizeof(remote)); + int s=(int)::accept(d_socket,(sockaddr *)&remote, &remlen); + if(s<0) { + if(errno==EAGAIN) + return 0; + + throw NetworkError("Accepting a connection: "+string(strerror(errno))); + } + + return new Socket(s); + } + + //! Set the socket to non-blocking + void setNonBlocking() + { + Utility::setNonBlocking(d_socket); + } + + //! Bind the socket to a specified endpoint + void bind(const ComboAddress &local) + { + int tmp=1; + if(setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) + throw NetworkError(string("Setsockopt failed: ")+strerror(errno)); + + if(::bind(d_socket,(struct sockaddr *)&local, local.getSocklen())<0) + throw NetworkError(strerror(errno)); + } + +#if 0 + //! Bind the socket to a specified endpoint + void bind(const ComboAddress &ep) + { + ComboAddress local; + memset(reinterpret_cast(&local),0,sizeof(local)); + local.sin_family=d_family; + local.sin_addr.s_addr=ep.address.byte; + local.sin_port=htons(ep.port); + + bind(local); + } +#endif + //! Connect the socket to a specified endpoint + void connect(const ComboAddress &ep) + { + if(::connect(d_socket,(struct sockaddr *)&ep, ep.getSocklen()) < 0 && errno != EINPROGRESS) + throw NetworkError(strerror(errno)); + } + + + //! For datagram sockets, receive a datagram and learn where it came from + /** For datagram sockets, receive a datagram and learn where it came from + \param dgram Will be filled with the datagram + \param ep Will be filled with the origin of the datagram */ + void recvFrom(string &dgram, ComboAddress &ep) + { + socklen_t remlen=sizeof(ep); + int bytes; + if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&ep , &remlen)) <0) + throw NetworkError(strerror(errno)); + + dgram.assign(d_buffer,bytes); + } + + bool recvFromAsync(string &dgram, ComboAddress &ep) + { + struct sockaddr_in remote; + socklen_t remlen=sizeof(remote); + int bytes; + if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&remote, &remlen))<0) { + if(errno!=EAGAIN) { + throw NetworkError(strerror(errno)); + } + else { + return false; + } + } + dgram.assign(d_buffer,bytes); + return true; + } + + + //! For datagram sockets, send a datagram to a destination + /** For datagram sockets, send a datagram to a destination + \param dgram The datagram + \param ep The intended destination of the datagram */ + void sendTo(const string &dgram, const ComboAddress &ep) + { + if(sendto(d_socket, dgram.c_str(), (int)dgram.size(), 0, (sockaddr *)&ep, ep.getSocklen())<0) + throw NetworkError(strerror(errno)); + } + + //! Write this data to the socket, taking care that all bytes are written out + void writen(const string &data) + { + if(data.empty()) + return; + + int toWrite=(int)data.length(); + int res; + const char *ptr=data.c_str(); + + do { + res=::send(d_socket, ptr, toWrite, 0); + if(res<0) + throw NetworkError("Writing to a socket: "+string(strerror(errno))); + if(!res) + throw NetworkError("EOF on socket"); + toWrite-=res; + ptr+=res; + }while(toWrite); + + } + + //! tries to write toWrite bytes from ptr to the socket + /** tries to write toWrite bytes from ptr to the socket, but does not make sure they al get written out + \param ptr Location to write from + \param toWrite number of bytes to try + */ + unsigned int tryWrite(const char *ptr, int toWrite) + { + int res; + res=::send(d_socket,ptr,toWrite,0); + if(res==0) + throw NetworkError("EOF on writing to a socket"); + + if(res>0) + return res; + + if(errno==EAGAIN) + return 0; + + throw NetworkError("Writing to a socket: "+string(strerror(errno))); + } + + //! Writes toWrite bytes from ptr to the socket + /** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */ + unsigned int write(const char *ptr, int toWrite) + { + int res; + res=::send(d_socket,ptr,toWrite,0); + if(res<0) { + throw NetworkError("Writing to a socket: "+string(strerror(errno))); + } + return res; + } + + + //! reads one character from the socket + int getChar() + { + char c; + + int res=::recv(d_socket,&c,1,0); + if(res) + return c; + return -1; + } + + void getline(string &data) + { + data=""; + int c; + while((c=getChar())!=-1) { + data+=(char)c; + if(c=='\n') + break; + } + } + + //! Reads a block of data from the socket to a string + void read(string &data) + { + int res=::recv(d_socket,d_buffer,d_buflen,0); + if(res<0) + throw NetworkError("Reading from a socket: "+string(strerror(errno))); + data.assign(d_buffer,res); + } + + //! Reads a block of data from the socket to a block of memory + int read(char *buffer, int bytes) + { + int res=::recv(d_socket,buffer,bytes,0); + if(res<0) + throw NetworkError("Reading from a socket: "+string(strerror(errno))); + return res; + + } + + //! Sets the socket to listen with a default listen backlog of 10 bytes + void listen(unsigned int length=10) + { + if(::listen(d_socket,length)<0) + throw NetworkError("Setting socket to listen: "+string(strerror(errno))); + } + + //! Returns the internal file descriptor of the socket + int getHandle() const + { + return d_socket; + } + +private: + int d_socket; + char *d_buffer; + int d_buflen; + int d_family; +}; + + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/syncres.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/syncres.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/syncres.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/syncres.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,1213 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2003 - 2011 PowerDNS.COM 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 +#include "utility.hh" +#include "syncres.hh" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "logger.hh" +#include "misc.hh" +#include "arguments.hh" +#include "lwres.hh" +#include "recursor_cache.hh" +#include "dnsparser.hh" +#include "dns_random.hh" +#include "lock.hh" +#include "cachecleaner.hh" + +__thread SyncRes::StaticStorage* t_sstorage; + +unsigned int SyncRes::s_maxnegttl; +unsigned int SyncRes::s_maxcachettl; +unsigned int SyncRes::s_packetcachettl; +unsigned int SyncRes::s_packetcacheservfailttl; +unsigned int SyncRes::s_queries; +unsigned int SyncRes::s_outgoingtimeouts; +unsigned int SyncRes::s_outqueries; +unsigned int SyncRes::s_tcpoutqueries; +unsigned int SyncRes::s_throttledqueries; +unsigned int SyncRes::s_dontqueries; +unsigned int SyncRes::s_nodelegated; +unsigned int SyncRes::s_unreachables; +bool SyncRes::s_doIPv6; +bool SyncRes::s_nopacketcache; + +string SyncRes::s_serverID; +bool SyncRes::s_log; + +#define LOG if(s_log) L<&ret) +{ + s_queries++; + + if( (qtype.getCode() == QType::AXFR)) + return -1; + + if( (qtype.getCode()==QType::PTR && pdns_iequals(qname, "1.0.0.127.in-addr.arpa.")) || + (qtype.getCode()==QType::A && qname.length()==10 && pdns_iequals(qname, "localhost."))) { + ret.clear(); + DNSResourceRecord rr; + rr.qname=qname; + rr.qtype=qtype; + rr.qclass=1; + rr.ttl=86400; + if(qtype.getCode()==QType::PTR) + rr.content="localhost."; + else + rr.content="127.0.0.1"; + ret.push_back(rr); + return 0; + } + + if(qclass==3 && qtype.getCode()==QType::TXT && + (pdns_iequals(qname, "version.bind.") || pdns_iequals(qname, "id.server.") || pdns_iequals(qname, "version.pdns.") ) + ) { + ret.clear(); + DNSResourceRecord rr; + rr.qname=qname; + rr.qtype=qtype; + rr.qclass=qclass; + rr.ttl=86400; + if(pdns_iequals(qname,"version.bind.") || pdns_iequals(qname,"version.pdns.")) + rr.content="\""+::arg()["version-string"]+"\""; + else + rr.content="\""+s_serverID+"\""; + ret.push_back(rr); + return 0; + } + + if(qclass==0xff) + qclass=1; + else if(qclass!=1) + return -1; + + set beenthere; + int res=doResolve(qname, qtype, ret, 0, beenthere); + if(!res && s_doAdditionalProcessing) + addCruft(qname, ret); + return res; +} + +//! This is the 'out of band resolver', in other words, the authoritative server +bool SyncRes::doOOBResolve(const string &qname, const QType &qtype, vector&ret, int depth, int& res) +{ + string prefix; + if(s_log) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + LOG<domainmap->end()) { + LOG< range; + + range=iter->second.d_records.equal_range(tie(qname)); // partial lookup + + ret.clear(); + AuthDomain::records_t::const_iterator ziter; + bool somedata=false; + for(ziter=range.first; ziter!=range.second; ++ziter) { + somedata=true; + if(qtype.getCode()==QType::ANY || ziter->qtype==qtype || ziter->qtype.getCode()==QType::CNAME) // let rest of nameserver do the legwork on this one + ret.push_back(*ziter); + } + if(!ret.empty()) { + LOG<second.d_records.find(make_tuple(authdomain, QType(QType::SOA))); + if(ziter!=iter->second.d_records.end()) { + DNSResourceRecord rr=*ziter; + rr.d_place=DNSResourceRecord::AUTHORITY; + ret.push_back(rr); + } + else + LOG<first) && chopOffDotted(wcarddomain)) { + LOG<second.d_records.equal_range(make_tuple("*."+wcarddomain)); + if(range.first==range.second) + continue; + + for(ziter=range.first; ziter!=range.second; ++ziter) { + DNSResourceRecord rr=*ziter; + if(rr.qtype == qtype || qtype.getCode() == QType::ANY) { + rr.qname = qname; + rr.d_place=DNSResourceRecord::ANSWER; + ret.push_back(rr); + } + } + LOG<first)) { + range=iter->second.d_records.equal_range(make_tuple(nsdomain,QType(QType::NS))); + if(range.first==range.second) + continue; + + for(ziter=range.first; ziter!=range.second; ++ziter) { + DNSResourceRecord rr=*ziter; + rr.d_place=DNSResourceRecord::AUTHORITY; + ret.push_back(rr); + } + } + if(ret.empty()) { + LOG<second.d_records.find(make_tuple(authdomain, QType(QType::SOA))); + if(ziter!=iter->second.d_records.end()) { + DNSResourceRecord rr=*ziter; + rr.d_place=DNSResourceRecord::AUTHORITY; + ret.push_back(rr); + } + else + LOG<ednsstatus.begin(); iter != t_sstorage->ednsstatus.end(); ++iter) { + fprintf(fp, "%s\t%d\t%s", iter->first.toString().c_str(), (int)iter->second.mode, ctime(&iter->second.modeSetAt)); + } + + fclose(fp); +} + +int SyncRes::asyncresolveWrapper(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, LWResult* res) +{ + /* what is your QUEST? + the goal is to get as many remotes as possible on the highest level of hipness: EDNS PING responders. + The levels are: + + -1) CONFIRMEDPINGER: Confirmed pinger! + 0) UNKNOWN Unknown state + 1) EDNSNOPING: Honors EDNS0 if no PING is included + 2) EDNSPINGOK: Ignores EDNS0+PING, but does generate EDNS0 response + 3) EDNSIGNORANT: Ignores EDNS0+PING, gives replies without EDNS0 nor PING + 4) NOEDNS: Generates FORMERR on EDNS queries + + Everybody starts out assumed to be '0'. + If '-1', send out EDNS0+Ping + If we get a FormErr, ignore + If we get a incorrect PING, ignore + If we get no PING, ignore + If '0', send out EDNS0+Ping + If we get a pure EDNS response, you are downgraded to '2'. + If you FORMERR us, go to '1', + If no EDNS in response, go to '3' - 3 and 0 are really identical, except confirmed + If with correct PING, upgrade to -1 + If '1', send out EDNS0, no PING + If FORMERR, downgrade to 4 + If '2', keep on including EDNS0+PING, just don't expect PING to be correct + If PING correct, move to '0', and cheer in the log file! + If '3', keep on including EDNS0+PING, see what happens + Same behaviour as 0 + If '4', send bare queries + */ + + if(s_noEDNS) { + g_stats.noEdnsOutQueries++; + return asyncresolve(ip, domain, type, doTCP, sendRDQuery, 0, now, res); + } + + SyncRes::EDNSStatus* ednsstatus; + ednsstatus = &t_sstorage->ednsstatus[ip]; + + if(ednsstatus->modeSetAt && ednsstatus->modeSetAt + 3600 < d_now.tv_sec) { + *ednsstatus=SyncRes::EDNSStatus(); + // cerr<<"Resetting EDNS Status for "<mode == EDNSStatus::UNKNOWN) + ednsstatus->mode = EDNSStatus::EDNSNOPING; + + SyncRes::EDNSStatus::EDNSMode& mode=ednsstatus->mode; + SyncRes::EDNSStatus::EDNSMode oldmode = mode; + int EDNSLevel=0; + + int ret; + for(int tries = 0; tries < 3; ++tries) { + // cerr<<"Remote '"<d_pingCorrect) { + L<d_rcode = RCode::ServFail; + g_stats.ednsPingMismatches++; + } + else { + g_stats.ednsPingMatches++; + ednsstatus->modeSetAt=d_now.tv_sec; // only the very best mode self-perpetuates + } + } + else if(mode==EDNSStatus::UNKNOWN || mode==EDNSStatus::EDNSPINGOK || mode == EDNSStatus::EDNSIGNORANT ) { + if(res->d_rcode == RCode::FormErr) { + // cerr<<"Downgrading to EDNSNOPING because of FORMERR!"<d_rcode == RCode::Refused || res->d_rcode == RCode::NotImp) ) { // this "fixes" F5 + // cerr<<"Downgrading an unknown status to EDNSNOPING because of RCODE="<d_rcode<d_pingCorrect && res->d_haveEDNS) + mode = EDNSStatus::EDNSPINGOK; + else if(res->d_pingCorrect) { + L<d_haveEDNS) { + if(mode != EDNSStatus::EDNSIGNORANT) { + mode = EDNSStatus::EDNSIGNORANT; + // cerr<<"We find that "<d_rcode == RCode::FormErr) { + // cerr<<"Downgrading to mode 4, FORMERR!"<d_pingCorrect) { + // an upgrade! + L<modeSetAt=d_now.tv_sec; + // cerr<<"Result: ret="<d_haveEDNS<<", EDNS-PING correct: "<d_pingCorrect<<", new mode: "<&ret, int depth, set& beenthere) +{ + string prefix; + if(s_log) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + int res=0; + if(!(d_nocache && qtype.getCode()==QType::NS && qname==".")) { + if(d_cacheonly) { // very limited OOB support + LWResult lwr; + LOG<domainmap->end()) { + const vector& servers = iter->second.d_servers; + if(servers.empty()) { + ret.clear(); + doOOBResolve(qname, qtype, ret, depth, res); + return res; + } + else { + const ComboAddress remoteIP = servers.front(); + LOG<d_place == DNSResourceRecord::ANSWER) + ret.push_back(*i); + } + return res; + } + } + } + + if(doCNAMECacheCheck(qname,qtype,ret,depth,res)) // will reroute us if needed + return res; + + if(doCacheCheck(qname,qtype,ret,depth,res)) // we done + return res; + } + + if(d_cacheonly) + return 0; + + LOG< nsset; + bool flawedNSSet=false; + + // the two retries allow getBestNSNamesFromCache&co to reprime the root + // hints, in case they ever go missing + for(int tries=0;tries<2 && nsset.empty();++tries) { + subdomain=getBestNSNamesFromCache(subdomain, nsset, &flawedNSSet, depth, beenthere); // pass beenthere to both occasions + } + + if(!(res=doResolveAt(nsset, subdomain, flawedNSSet, qname, qtype, ret, depth, beenthere))) + return 0; + + LOG< SyncRes::getAs(const string &qname, int depth, set& beenthere) +{ + typedef vector res_t; + res_t res; + + typedef vector ret_t; + ret_t ret; + + if(!doResolve(qname, s_doIPv6 ? QType(QType::ADDR) : QType(QType::A), res,depth+1,beenthere) && !res.empty()) { // this consults cache, OR goes out + for(res_t::const_iterator i=res.begin(); i!= res.end(); ++i) { + if(i->qtype.getCode()==QType::A || i->qtype.getCode()==QType::AAAA) { + ret.push_back(ComboAddress(i->content, 53)); + } + } + } + + if(ret.size() > 1) { + random_shuffle(ret.begin(), ret.end(), dns_random); + + // move 'best' address for this nameserver name up front + nsspeeds_t::iterator best = t_sstorage->nsSpeeds.find(qname); + + if(best != t_sstorage->nsSpeeds.end()) + for(ret_t::iterator i=ret.begin(); i != ret.end(); ++i) { + if(*i==best->second.d_best) { // got the fastest one + if(i!=ret.begin()) { + *i=*ret.begin(); + *ret.begin()=best->second.d_best; + } + break; + } + } + } + + return ret; +} + +void SyncRes::getBestNSFromCache(const string &qname, set&bestns, bool* flawedNSSet, int depth, set& beenthere) +{ + string prefix, subdomain(qname); + if(s_log) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + bestns.clear(); + + do { + LOG< ns; + *flawedNSSet = false; + if(t_RC->get(d_now.tv_sec, subdomain, QType(QType::NS), &ns) > 0) { + for(set::const_iterator k=ns.begin();k!=ns.end();++k) { + if(k->ttl > (unsigned int)d_now.tv_sec ) { + set aset; + + DNSResourceRecord rr=*k; + rr.content=k->content; + if(!dottedEndsOn(rr.content, subdomain) || t_RC->get(d_now.tv_sec, rr.content, s_doIPv6 ? QType(QType::ADDR) : QType(QType::A), + s_log ? &aset : 0) > 5) { + bestns.insert(rr); + LOG< '"<content<<") which we miss or is expired"<::const_iterator j=beenthere.begin();j!=beenthere.end();++j) + LOG<qname<<" ("<<(unsigned int)j->bestns.size()<<")"<domainmap->find(*qname); + if(ret!=t_sstorage->domainmap->end()) + break; + }while(chopOffDotted(*qname)); + return ret; +} + +/** doesn't actually do the work, leaves that to getBestNSFromCache */ +string SyncRes::getBestNSNamesFromCache(const string &qname, set& nsset, bool* flawedNSSet, int depth, set&beenthere) +{ + string subdomain(qname); + string authdomain(qname); + + domainmap_t::const_iterator iter=getBestAuthZone(&authdomain); + if(iter!=t_sstorage->domainmap->end()) { + if( iter->second.d_servers.empty() ) + nsset.insert(string()); // this gets picked up in doResolveAt, if empty it means "we are auth", otherwise it denotes a forward + else { + for(vector::const_iterator server=iter->second.d_servers.begin(); server != iter->second.d_servers.end(); ++server) + nsset.insert((iter->second.d_rdForward ? "+" : "-") + server->toStringWithPort()); // add a '+' if the rd bit should be set + } + + return authdomain; + } + + set bestns; + getBestNSFromCache(subdomain, bestns, flawedNSSet, depth, beenthere); + + for(set::const_iterator k=bestns.begin();k!=bestns.end();++k) { + nsset.insert(k->content); + if(k==bestns.begin()) + subdomain=k->qname; + } + return subdomain; +} + +bool SyncRes::doCNAMECacheCheck(const string &qname, const QType &qtype, vector&ret, int depth, int &res) +{ + string prefix; + if(s_log) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + if(depth>10) { + LOG< cset; + if(t_RC->get(d_now.tv_sec, qname,QType(QType::CNAME),&cset) > 0) { + + for(set::const_iterator j=cset.begin();j!=cset.end();++j) { + if(j->ttl>(unsigned int) d_now.tv_sec) { + LOG<content<<"'"<beenthere; + res=doResolve(j->content, qtype, ret, depth+1, beenthere); + } + else + res=0; + return true; + } + } + } + LOG<&ret, int depth, int &res) +{ + bool giveNegative=false; + + string prefix; + if(s_log) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + string sqname(qname); + QType sqt(qtype); + uint32_t sttl=0; + // cout<<"Lookup for '"< range=t_sstorage->negcache.equal_range(tie(qname)); + negcache_t::iterator ni; + for(ni=range.first; ni != range.second; ni++) { + // we have something + if(ni->d_qtype.getCode() == 0 || ni->d_qtype == qtype) { + res=0; + if((uint32_t)d_now.tv_sec < ni->d_ttd) { + sttl=ni->d_ttd - d_now.tv_sec; + if(ni->d_qtype.getCode()) { + LOG<d_qname<<"' for another "<d_qname<<"' for another "<d_qname; + sqt=QType::SOA; + moveCacheItemToBack(t_sstorage->negcache, ni); + break; + } + else { + LOG<negcache, ni); + } + } + } + + set cset; + bool found=false, expired=false; + + if(t_RC->get(d_now.tv_sec, sqname, sqt, &cset) > 0) { + LOG<::const_iterator j=cset.begin();j!=cset.end();++j) { + LOG<content; + if(j->ttl>(unsigned int) d_now.tv_sec) { + DNSResourceRecord rr=*j; + rr.ttl-=d_now.tv_sec; + if(giveNegative) { + rr.d_place=DNSResourceRecord::AUTHORITY; + rr.ttl=sttl; + } + ret.push_back(rr); + LOG<<"[ttl="<countb; +} + +struct speedOrder +{ + speedOrder(map &speeds) : d_speeds(speeds) {} + bool operator()(const string &a, const string &b) const + { + return d_speeds[a] < d_speeds[b]; + } + map& d_speeds; +}; + +inline vector SyncRes::shuffleInSpeedOrder(set &nameservers, const string &prefix) +{ + vector rnameservers; + rnameservers.reserve(nameservers.size()); + map speeds; + + for(set::const_iterator i=nameservers.begin();i!=nameservers.end();++i) { + rnameservers.push_back(*i); + double speed; + speed=t_sstorage->nsSpeeds[*i].get(&d_now); + speeds[*i]=speed; + } + random_shuffle(rnameservers.begin(),rnameservers.end(), dns_random); + speedOrder so(speeds); + stable_sort(rnameservers.begin(),rnameservers.end(), so); + + if(s_log) { + L<::const_iterator i=rnameservers.begin();i!=rnameservers.end();++i) { + if(i!=rnameservers.begin()) { + L<<", "; + if(!((i-rnameservers.begin())%3)) + L<& a, const pair& b) const + { + if(pdns_ilexicographical_compare(a.first, b.first)) + return true; + if(pdns_ilexicographical_compare(b.first, a.first)) + return false; + + return a.second < b.second; + } +}; + +static bool magicAddrMatch(const QType& query, const QType& answer) +{ + if(query.getCode() != QType::ADDR) + return false; + return answer.getCode() == QType::A || answer.getCode() == QType::AAAA; +} + +double g_avgLatency; + +/** returns -1 in case of no results, rcode otherwise */ +int SyncRes::doResolveAt(set nameservers, string auth, bool flawedNSSet, const string &qname, const QType &qtype, + vector&ret, + int depth, set&beenthere) +{ + string prefix; + if(s_log) { + prefix=d_prefix; + prefix.append(depth, ' '); + } + + LOG< rnameservers=shuffleInSpeedOrder(nameservers, s_log ? (prefix+qname+": ") : string() ); + + for(vector::const_iterator tns=rnameservers.begin();;++tns) { + if(tns==rnameservers.end()) { + LOG<doAgeCache(d_now.tv_sec, auth, QType::NS, 10)) + g_stats.nsSetInvalidations++; + } + return -1; + } + if(qname==*tns && qtype.getCode()==QType::A) { + LOG< remoteIPs_t; + remoteIPs_t remoteIPs; + remoteIPs_t::const_iterator remoteIP; + bool doTCP=false; + int resolveret; + bool pierceDontQuery=false; + bool sendRDQuery=false; + LWResult lwr; + if(tns->empty()) { + LOG<empty()) { + sendRDQuery = txtAddr[0] == '+'; + txtAddr=txtAddr.c_str()+1; + } + ComboAddress addr=parseIPAndPort(txtAddr, 53); + + remoteIPs.push_back(addr); + pierceDontQuery=true; + } + else { + remoteIPs=getAs(*tns, depth+1, beenthere); + pierceDontQuery=false; + } + + if(remoteIPs.empty()) { + LOG<toString(); + } + LOG<toStringWithPort() <<", asking '"<throttle.shouldThrottle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()))) { + LOG<match(&*remoteIP)) { + LOG<toString() << ", blocked by 'dont-query' setting" << endl; + s_dontqueries++; + continue; + } + else { + s_outqueries++; d_outqueries++; + TryTCP: + if(doTCP) { + LOG<toStringWithPort() <nsSpeeds[*tns].submit(*remoteIP, 1000000, &d_now); // 1 sec + } + if(resolveret==-1) + t_sstorage->throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // unreachable, 1 minute or 100 queries + else + t_sstorage->throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 10, 5); // timeout + } + continue; + } + + break; // this IP address worked! + wasLame:; // well, it didn't + LOG<toString() <<") is lame for '"<throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // lame + } + } + + if(remoteIP == remoteIPs.end()) // we tried all IP addresses, none worked + continue; + + if(lwr.d_tcbit) { + if(!doTCP) { + doTCP=true; + LOG<throttle.throttle(d_now.tv_sec,make_tuple(*remoteIP, qname, qtype.getCode()),60,3); // servfail + continue; + } + LOG<toString() <<"), rcode="<sin4.sin_family==AF_INET6) + lwr.d_usec/=3; + */ + // cout<<"msec: "<nsSpeeds[*tns].submit(*remoteIP, lwr.d_usec, &d_now); + } + + typedef map, set, TCacheComp > tcache_t; + tcache_t tcache; + + // reap all answers from this packet that are acceptable + for(LWResult::res_t::iterator i=lwr.d_result.begin();i != lwr.d_result.end();++i) { + if(i->qtype.getCode() == QType::OPT) { + LOG<qname<<"' from '"<qname<<"|"<qtype.getName()<<"|"<content<<"' from '"<qtype.getCode()==QType::ANY) { + LOG<<"NO! - we don't accept 'ANY' data"<qname, auth)) { + if(lwr.d_aabit && lwr.d_rcode==RCode::NoError && i->d_place==DNSResourceRecord::ANSWER && ::arg().contains("delegation-only",auth)) { + LOG<<"NO! Is from delegation-only zone"<ttl=min(s_maxcachettl, i->ttl); + + DNSResourceRecord rr=*i; + rr.d_place=DNSResourceRecord::ANSWER; + + rr.ttl += d_now.tv_sec; + + if(rr.qtype.getCode() == QType::NS) // people fiddle with the case + rr.content=toLower(rr.content); // this must stay! (the cache can't be case-insensitive on the RHS of records) + + tcache[make_pair(i->qname,i->qtype)].insert(rr); + } + } + else + LOG<<"NO!"<second.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2) + uint32_t lowestTTL=std::numeric_limits::max(); + for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j) + lowestTTL=min(lowestTTL, j->ttl); + + for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j) + ((tcache_t::value_type::second_type::value_type*)&(*j))->ttl=lowestTTL; + } + + t_RC->replace(d_now.tv_sec, i->first.first, i->first.second, i->second, lwr.d_aabit); + } + set nsset; + LOG<d_place==DNSResourceRecord::AUTHORITY && i->qtype.getCode()==QType::SOA && + lwr.d_rcode==RCode::NXDomain && dottedEndsOn(qname,i->qname) && dottedEndsOn(i->qname, auth)) { + LOG<ttl = min(i->ttl, s_maxnegttl); + if(!newtarget.length()) // only add a SOA if we're not going anywhere after this + ret.push_back(*i); + + NegCacheEntry ne; + + ne.d_qname=i->qname; + + ne.d_ttd=d_now.tv_sec + i->ttl; + + ne.d_name=qname; + ne.d_qtype=QType(0); // this encodes 'whole record' + + replacing_insert(t_sstorage->negcache, ne); + + negindic=true; + } + else if(i->d_place==DNSResourceRecord::ANSWER && pdns_iequals(i->qname, qname) && i->qtype.getCode()==QType::CNAME && (!(qtype==QType(QType::CNAME)))) { + ret.push_back(*i); + newtarget=i->content; + } + // for ANY answers we *must* have an authoritive answer + else if(i->d_place==DNSResourceRecord::ANSWER && pdns_iequals(i->qname, qname) && + ( + i->qtype==qtype || (lwr.d_aabit && (qtype==QType(QType::ANY) || magicAddrMatch(qtype, i->qtype) ) ) + ) + ) + { + + LOG<content<<"|"<qtype.getName()<<"'"<d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::NS) { + if(moreSpecificThan(i->qname,auth)) { + newauth=i->qname; + LOG<qname<<"' -> '"<content<<"'"<qname<<"' -> '"<content<<"', had '"<content); + } + else if(!done && i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA && + lwr.d_rcode==RCode::NoError) { + LOG<qtype.getName()+"'") < ttl = min(s_maxnegttl, i->ttl); + ret.push_back(*i); + NegCacheEntry ne; + ne.d_qname=i->qname; + ne.d_ttd=d_now.tv_sec + i->ttl; + ne.d_name=qname; + ne.d_qtype=qtype; + if(qtype.getCode()) { // prevents us from blacking out a whole domain + replacing_insert(t_sstorage->negcache, ne); + } + negindic=true; + } + } + } + + if(done){ + LOG< 10) { + LOG< beenthere2; + return doResolve(newtarget, qtype, ret, depth + 1, beenthere2); + } + if(lwr.d_rcode==RCode::NXDomain) { + LOG<& ret) +{ + for(vector::const_iterator k=ret.begin();k!=ret.end();++k) // don't add stuff to an NXDOMAIN! + if(k->d_place==DNSResourceRecord::AUTHORITY && k->qtype==QType(QType::SOA)) + return; + + // LOG< addit; + + for(vector::const_iterator k=ret.begin();k!=ret.end();++k) + if( (k->d_place==DNSResourceRecord::ANSWER && (k->qtype==QType(QType::MX) || k->qtype==QType(QType::SRV))) || + ((k->d_place==DNSResourceRecord::AUTHORITY || k->d_place==DNSResourceRecord::ANSWER) && k->qtype==QType(QType::NS))) { + LOG<content<<"|"<qtype.getName()<<"' needs IP for additional processing"< beenthere; + vector > fields; + vstringtok(fields, k->content, " "); + string host; + if(k->qtype==QType(QType::MX) && fields.size()==2) + host=string(k->content.c_str() + fields[1].first, fields[1].second - fields[1].first); + else if(k->qtype==QType(QType::NS)) + host=k->content; + else if(k->qtype==QType(QType::SRV) && fields.size()==4) + host=string(k->content.c_str() + fields[3].first, fields[3].second - fields[3].first); + else + continue; + doResolve(host, s_doAAAAAdditionalProcessing ? QType(QType::ADDR) : QType(QType::A), addit, 1, beenthere); + } + + if(!addit.empty()) { + sort(addit.begin(), addit.end()); + addit.erase(unique(addit.begin(), addit.end(), uniqueComp), addit.end()); + for(vector::iterator k=addit.begin();k!=addit.end();++k) { + if(k->qtype.getCode()==QType::A || k->qtype.getCode()==QType::AAAA) { + k->d_place=DNSResourceRecord::ADDITIONAL; + ret.push_back(*k); + } + } + } + LOG<& ret, int depth) +{ + set bestns; + set beenthere; + bool dontcare; + getBestNSFromCache(qname, bestns, &dontcare, depth, beenthere); + + for(set::const_iterator k=bestns.begin();k!=bestns.end();++k) { + DNSResourceRecord ns=*k; + ns.d_place=DNSResourceRecord::AUTHORITY; + ns.ttl-=d_now.tv_sec; + ret.push_back(ns); + } +} + +// used by PowerDNSLua +int directResolve(const std::string& qname, const QType& qtype, int qclass, vector& ret) +{ + struct timeval now; + gettimeofday(&now, 0); + + SyncRes sr(now); + + int res = sr.beginResolve(qname, QType(qtype), qclass, ret); + cerr<<"Result: "< +#include "dns.hh" +#include "qtype.hh" +#include +#include +#include +#include +#include +#include +#include "misc.hh" +#include "lwres.hh" +#include +#include "sstuff.hh" +#include "recursor_cache.hh" +#include "recpacketcache.hh" +#include +#include +#include +#include "mtasker.hh" +#include "iputils.hh" + +void primeHints(void); + +struct NegCacheEntry +{ + string d_name; + QType d_qtype; + string d_qname; + uint32_t d_ttd; + uint32_t getTTD() const + { + return d_ttd; + } +}; + + +template class Throttle : public boost::noncopyable +{ +public: + Throttle() + { + d_limit=3; + d_ttl=60; + d_last_clean=time(0); + } + bool shouldThrottle(time_t now, const Thing& t) + { + if(now > d_last_clean + 300 ) { + + d_last_clean=now; + for(typename cont_t::iterator i=d_cont.begin();i!=d_cont.end();) { + if( i->second.ttd < now) { + d_cont.erase(i++); + } + else + ++i; + } + } + + typename cont_t::iterator i=d_cont.find(t); + if(i==d_cont.end()) + return false; + if(now > i->second.ttd || i->second.count-- < 0) { + d_cont.erase(i); + return false; + } + + return true; // still listed, still blocked + } + void throttle(time_t now, const Thing& t, unsigned int ttl=0, unsigned int tries=0) + { + typename cont_t::iterator i=d_cont.find(t); + entry e={ now+(ttl ? ttl : d_ttl), tries ? tries : d_limit}; + + if(i==d_cont.end()) { + d_cont[t]=e; + } + else if(i->second.ttd > e.ttd || (i->second.count) < e.count) + d_cont[t]=e; + } + + unsigned int size() + { + return (unsigned int)d_cont.size(); + } +private: + int d_limit; + int d_ttl; + time_t d_last_clean; + struct entry + { + time_t ttd; + int count; + }; + typedef map cont_t; + cont_t d_cont; +}; + + +/** Class that implements a decaying EWMA. + This class keeps an exponentially weighted moving average which, additionally, decays over time. + The decaying is only done on get. +*/ +class DecayingEwma +{ +public: + DecayingEwma() : d_val(0.0) + { + d_needinit=true; + d_last.tv_sec = d_last.tv_usec = 0; + d_lastget=d_last; + } + + DecayingEwma(const DecayingEwma& orig) : d_last(orig.d_last), d_lastget(orig.d_lastget), d_val(orig.d_val), d_needinit(orig.d_needinit) + { + } + + struct timeval getOrMakeTime(struct timeval* tv) + { + if(tv) + return *tv; + else { + struct timeval ret; + Utility::gettimeofday(&ret, 0); + return ret; + } + } + + void submit(int val, struct timeval* tv) + { + struct timeval now=getOrMakeTime(tv); + + if(d_needinit) { + d_last=now; + d_needinit=false; + } + + float diff= makeFloat(d_last - now); + + d_last=now; + double factor=exp(diff)/2.0; // might be '0.5', or 0.0001 + d_val=(float)((1-factor)*val+ (float)factor*d_val); + } + + double get(struct timeval* tv) + { + struct timeval now=getOrMakeTime(tv); + float diff=makeFloat(d_lastget-now); + d_lastget=now; + float factor=exp(diff/60.0f); // is 1.0 or less + return d_val*=factor; + } + + bool stale(time_t limit) const + { + return limit > d_lastget.tv_sec; + } + +private: + struct timeval d_last; // stores time + struct timeval d_lastget; // stores time + float d_val; + bool d_needinit; +}; + + +class SyncRes : public boost::noncopyable +{ +public: + explicit SyncRes(const struct timeval& now); + + int beginResolve(const string &qname, const QType &qtype, uint16_t qclass, vector&ret); + void setId(int id) + { + if(s_log) + d_prefix="["+itoa(id)+"] "; + } + static void setLog(bool log) + { + s_log=log; + } + void setCacheOnly(bool state=true) + { + d_cacheonly=state; + } + void setNoCache(bool state=true) + { + d_nocache=state; + } + + void setDoEDNS0(bool state=true) + { + d_doEDNS0=state; + } + + int asyncresolveWrapper(const ComboAddress& ip, const string& domain, int type, bool doTCP, bool sendRDQuery, struct timeval* now, LWResult* res); + + static void doEDNSDumpAndClose(int fd); + + static unsigned int s_queries; + static unsigned int s_outgoingtimeouts; + static unsigned int s_throttledqueries; + static unsigned int s_dontqueries; + static unsigned int s_outqueries; + static unsigned int s_tcpoutqueries; + static unsigned int s_nodelegated; + static unsigned int s_unreachables; + static bool s_doAAAAAdditionalProcessing; + static bool s_doAdditionalProcessing; + static bool s_doIPv6; + unsigned int d_outqueries; + unsigned int d_tcpoutqueries; + unsigned int d_throttledqueries; + unsigned int d_timeouts; + unsigned int d_unreachables; + + // typedef map negcache_t; + + typedef multi_index_container < + NegCacheEntry, + indexed_by < + ordered_unique< + composite_key< + NegCacheEntry, + member, + member + >, + composite_key_compare > + >, + sequenced<> + > + > negcache_t; + + //! This represents a number of decaying Ewmas, used to store performance per nameserver-name. + /** Modelled to work mostly like the underlying DecayingEwma. After you've called get, + d_best is filled out with the best address for this collection */ + struct DecayingEwmaCollection + { + void submit(const ComboAddress& remote, int usecs, struct timeval* now) + { + collection_t::iterator pos; + for(pos=d_collection.begin(); pos != d_collection.end(); ++pos) + if(pos->first==remote) + break; + if(pos!=d_collection.end()) { + pos->second.submit(usecs, now); + } + else { + DecayingEwma de; + de.submit(usecs, now); + d_collection.push_back(make_pair(remote, de)); + } + } + + double get(struct timeval* now) + { + if(d_collection.empty()) + return 0; + double ret=std::numeric_limits::max(); + double tmp; + for(collection_t::iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) { + if((tmp=pos->second.get(now)) < ret) { + ret=tmp; + d_best=pos->first; + } + } + + return ret; + } + + bool stale(time_t limit) const + { + for(collection_t::const_iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) + if(!pos->second.stale(limit)) + return false; + return true; + } + + typedef vector > collection_t; + collection_t d_collection; + ComboAddress d_best; + }; + + typedef map nsspeeds_t; + + + struct EDNSStatus + { + EDNSStatus() : mode(UNKNOWN), modeSetAt(0), EDNSPingHitCount(0) {} + enum EDNSMode { CONFIRMEDPINGER=-1, UNKNOWN=0, EDNSNOPING=1, EDNSPINGOK=2, EDNSIGNORANT=3, NOEDNS=4 } mode; + time_t modeSetAt; + int EDNSPingHitCount; + }; + + typedef map ednsstatus_t; + + + + static bool s_noEDNSPing; + static bool s_noEDNS; + + struct AuthDomain + { + vector d_servers; + bool d_rdForward; + typedef multi_index_container < + DNSResourceRecord, + indexed_by < + ordered_non_unique< + composite_key< DNSResourceRecord, + member, + member + >, + composite_key_compare > + > + > + > records_t; + records_t d_records; + }; + + + typedef map domainmap_t; + + + typedef Throttle > throttle_t; + + struct timeval d_now; + static unsigned int s_maxnegttl; + static unsigned int s_maxcachettl; + static unsigned int s_packetcachettl; + static unsigned int s_packetcacheservfailttl; + static bool s_nopacketcache; + static string s_serverID; + + struct StaticStorage { + negcache_t negcache; + nsspeeds_t nsSpeeds; + ednsstatus_t ednsstatus; + throttle_t throttle; + domainmap_t* domainmap; + }; + +private: + struct GetBestNSAnswer; + int doResolveAt(set nameservers, string auth, bool flawedNSSet, const string &qname, const QType &qtype, vector&ret, + int depth, set&beenthere); + int doResolve(const string &qname, const QType &qtype, vector&ret, int depth, set& beenthere); + bool doOOBResolve(const string &qname, const QType &qtype, vector&ret, int depth, int &res); + domainmap_t::const_iterator getBestAuthZone(string* qname); + bool doCNAMECacheCheck(const string &qname, const QType &qtype, vector&ret, int depth, int &res); + bool doCacheCheck(const string &qname, const QType &qtype, vector&ret, int depth, int &res); + void getBestNSFromCache(const string &qname, set&bestns, bool* flawedNSSet, int depth, set& beenthere); + void addCruft(const string &qname, vector& ret); + string getBestNSNamesFromCache(const string &qname,set& nsset, bool* flawedNSSet, int depth, set&beenthere); + void addAuthorityRecords(const string& qname, vector& ret, int depth); + + inline vector shuffleInSpeedOrder(set &nameservers, const string &prefix); + bool moreSpecificThan(const string& a, const string &b); + vector getAs(const string &qname, int depth, set& beenthere); + +private: + string d_prefix; + static bool s_log; + bool d_cacheonly; + bool d_nocache; + bool d_doEDNS0; + + struct GetBestNSAnswer + { + string qname; + set bestns; + bool operator<(const GetBestNSAnswer &b) const + { + if(qname chain_t; + mutable chain_t chain; + int fd; + + bool operator<(const PacketID& b) const + { + int ourSock= sock ? sock->getHandle() : 0; + int bSock = b.sock ? b.sock->getHandle() : 0; + if( tie(remote, ourSock, type) < tie(b.remote, bSock, b.type)) + return true; + if( tie(remote, ourSock, type) > tie(b.remote, bSock, b.type)) + return false; + + if(pdns_ilexicographical_compare(domain, b.domain)) + return true; + if(pdns_ilexicographical_compare(b.domain, domain)) + return false; + + return tie(fd, id) < tie(b.fd, b.id); + } +}; + +struct PacketIDBirthdayCompare: public std::binary_function +{ + bool operator()(const PacketID& a, const PacketID& b) const + { + int ourSock= a.sock ? a.sock->getHandle() : 0; + int bSock = b.sock ? b.sock->getHandle() : 0; + if( tie(a.remote, ourSock, a.type) < tie(b.remote, bSock, b.type)) + return true; + if( tie(a.remote, ourSock, a.type) > tie(b.remote, bSock, b.type)) + return false; + + return pdns_ilexicographical_compare(a.domain, b.domain); + } +}; +extern __thread MemRecursorCache* t_RC; +extern __thread RecursorPacketCache* t_packetCache; +typedef MTasker MT_t; +extern __thread MT_t* MT; + + +struct RecursorStats +{ + uint64_t servFails; + uint64_t nxDomains; + uint64_t noErrors; + uint64_t answers0_1, answers1_10, answers10_100, answers100_1000, answersSlow; + uint64_t avgLatencyUsec; + uint64_t qcounter; + uint64_t tcpqcounter; + uint64_t unauthorizedUDP; + uint64_t unauthorizedTCP; + uint64_t tcpClientOverflow; + uint64_t clientParseError; + uint64_t serverParseError; + uint64_t unexpectedCount; + uint64_t caseMismatchCount; + uint64_t spoofCount; + uint64_t resourceLimits; + uint64_t overCapacityDrops; + uint64_t ipv6queries; + uint64_t chainResends; + uint64_t nsSetInvalidations; + uint64_t ednsPingMatches; + uint64_t ednsPingMismatches; + uint64_t noPingOutQueries, noEdnsOutQueries; + uint64_t packetCacheHits; + uint64_t noPacketError; + time_t startupTime; + unsigned int maxMThreadStackUsage; +}; + +//! represents a running TCP/IP client session +class TCPConnection : public boost::noncopyable +{ +public: + TCPConnection(int fd, const ComboAddress& addr); + ~TCPConnection(); + + int getFD() + { + return d_fd; + } + enum stateenum {BYTE0, BYTE1, GETQUESTION, DONE} state; + int qlen; + int bytesread; + const ComboAddress d_remote; + char data[65535]; // damn + + static unsigned int getCurrentConnections() { return s_currentConnections; } +private: + const int d_fd; + static AtomicCounter s_currentConnections; //!< total number of current TCP connections +}; + + +struct RemoteKeeper +{ + typedef vector remotes_t; + remotes_t remotes; + int d_remotepos; + void addRemote(const ComboAddress& remote) + { + if(!remotes.size()) + return; + + remotes[(d_remotepos++) % remotes.size()]=remote; + } +}; +extern __thread RemoteKeeper* t_remotes; +string doQueueReloadLuaScript(vector::const_iterator begin, vector::const_iterator end); +void parseACLs(); +extern RecursorStats g_stats; +extern unsigned int g_numThreads; + + + +std::string reloadAuthAndForwards(); +ComboAddress parseIPAndPort(const std::string& input, uint16_t port); +ComboAddress getQueryLocalAddress(int family, uint16_t port); +typedef boost::function pipefunc_t; +void broadcastFunction(const pipefunc_t& func, bool skipSelf = false); +void distributeAsyncFunction(const pipefunc_t& func); + +int directResolve(const std::string& qname, const QType& qtype, int qclass, vector& ret); + +template T broadcastAccFunction(const boost::function& func, bool skipSelf=false); + +SyncRes::domainmap_t* parseAuthAndForwards(); + +uint64_t* pleaseGetNsSpeedsSize(); +uint64_t* pleaseGetCacheSize(); +uint64_t* pleaseGetNegCacheSize(); +uint64_t* pleaseGetCacheHits(); +uint64_t* pleaseGetCacheMisses(); +uint64_t* pleaseGetConcurrentQueries(); +uint64_t* pleaseGetThrottleSize(); +uint64_t* pleaseGetPacketCacheHits(); +uint64_t* pleaseGetPacketCacheSize(); +uint64_t* pleaseWipeCache(const std::string& canon); + +#endif diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/sysdeps/Darwin.inc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/sysdeps/Darwin.inc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/sysdeps/Darwin.inc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/sysdeps/Darwin.inc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,9 @@ +CXXFLAGS+=-D_XOPEN_SOURCE + +LUA_CPPFLAGS_CONFIG ?= -I/usr/include/lua5.1 +LUA_LIBS_CONFIG ?= -llua5.1 -rdynamic + +# Lua 5.0 settings +#LUA_CPPFLAGS_CONFIG=-I/usr/include/lua50 +#LUA_LIBS_CONFIG=-llua50 -llualib50 + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/sysdeps/FreeBSD.inc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/sysdeps/FreeBSD.inc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/sysdeps/FreeBSD.inc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/sysdeps/FreeBSD.inc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,12 @@ +CXXFLAGS+=-I/usr/local/include/ +OPTIONALS:=optional/kqueuemplexer.o + +optional/kqueuemplexer.o: kqueuemplexer.cc + $(CXX) $(CXXFLAGS) -c $< -o $@ ; true + +LUA_CPPFLAGS_CONFIG ?= -I/usr/include/lua5.1 +LUA_LIBS_CONFIG ?= -llua5.1 -rdynamic + +# Lua 5.0 settings +#LUA_CPPFLAGS_CONFIG=-I/usr/include/lua50 +#LUA_LIBS_CONFIG=-llua50 -llualib50 diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/sysdeps/Linux.inc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/sysdeps/Linux.inc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/sysdeps/Linux.inc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/sysdeps/Linux.inc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,21 @@ +OPTIONALS:=optional/epollmplexer.o +OS_SPECIFIC_INSTALL=mkdir -p $(DESTDIR)/etc/init.d ; cp pdns-recursor.init.d $(DESTDIR)/etc/init.d/pdns-recursor + +ifeq ($(CC),cc) + CC:=gcc +endif + +CXXFLAGS := $(CXXFLAGS) -D_GNU_SOURCE +CFLAGS := $(CFLAGS) -D_GNU_SOURCE + +LUA_CPPFLAGS_CONFIG ?= -I/usr/include/lua5.1 +LUA_LIBS_CONFIG ?= -llua5.1 -rdynamic + +# Lua 5.0 settings +#LUA_CPPFLAGS_CONFIG=-I/usr/include/lua50 +#LUA_LIBS_CONFIG=-llua50 -llualib50 + + +optional/epollmplexer.o: epollmplexer.cc + $(CXX) $(CXXFLAGS) -c $< -o $@ ; true + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/sysdeps/SunOS.inc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/sysdeps/SunOS.inc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/sysdeps/SunOS.inc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/sysdeps/SunOS.inc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,20 @@ +ifeq ($(CC),cc) + CC:=gcc +endif + +LDFLAGS+=-lresolv -lsocket -lnsl -ldl +OS_SPECIFIC_INSTALL=mkdir -p $(DESTDIR)/etc/init.d ; cp pdns-recursor.init.d $(DESTDIR)/etc/init.d/pdns-recursor + +LUA_LIBS_CONFIG ?= -llua + +CXXFLAGS+= -D__MAKECONTEXT_V2_SOURCE + +OPTIONALS:=optional/portsmplexer.o optional/devpollmplexer.o + +optional/portsmplexer.o: portsmplexer.cc + $(CXX) $(CXXFLAGS) -c $< -o $@ ; true + + +optional/devpollmplexer.o: devpollmplexer.cc + $(CXX) $(CXXFLAGS) -c $< -o $@ ; true + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/unix_utility.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/unix_utility.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/unix_utility.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/unix_utility.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,271 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2011 PowerDNS.COM 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 "utility.hh" +#include +#include +#include +#include +#include "ahuexception.hh" +#include "logger.hh" +#include "misc.hh" +#include +#include +#include + +#ifdef NEED_INET_NTOP_PROTO +extern "C" { +const char *inet_ntop(int af, const void *src, char *dst, size_t cnt); +} +#endif + + +#include "namespaces.hh" + +// Closes a socket. +int Utility::closesocket( Utility::sock_t socket ) +{ + int ret=::close(socket); + if(ret < 0 && errno == ECONNRESET) // see ticket 192, odd BSD behaviour + return 0; + if(ret < 0) + throw AhuException("Error closing socket: "+stringerror()); + return ret; +} + +bool Utility::setNonBlocking(sock_t sock) +{ + int flags=fcntl(sock,F_GETFL,0); + if(flags<0 || fcntl(sock, F_SETFL,flags|O_NONBLOCK) <0) + return false; + return true; +} + +bool Utility::setBlocking(sock_t sock) +{ + int flags=fcntl(sock,F_GETFL,0); + if(flags<0 || fcntl(sock, F_SETFL,flags&(~O_NONBLOCK)) <0) + return false; + return true; +} + +bool Utility::setCloseOnExec(sock_t sock) +{ + int flags=fcntl(sock,F_GETFD,0); + if(flags<0 || fcntl(sock, F_SETFD,flags|FD_CLOEXEC) <0) + return false; + return true; +} + +const char *Utility::inet_ntop(int af, const char *src, char *dst, size_t size) +{ + return ::inet_ntop(af,src,dst,size); +} + +unsigned int Utility::sleep(unsigned int sec) +{ + return ::sleep(sec); +} + +void Utility::usleep(unsigned long usec) +{ + ::usleep(usec); +} + + +// Drops the program's privileges. +void Utility::dropPrivs( int uid, int gid ) +{ + if(gid) { + if(setgid(gid)<0) { + theL()<gr_gid; + } + return newgid; +} + + +// Retrieves an uid using a username. +int Utility::makeUidNumeric(const string &username) +{ + int newuid; + if(!(newuid=atoi(username.c_str()))) { + struct passwd *pw=getpwnam(username.c_str()); + if(!pw) { + theL()<pw_uid; + } + return newuid; +} + + +// Returns a random number. +long int Utility::random( void ) +{ + return rand(); +} + +// Sets the random seed. +void Utility::srandom( unsigned int seed ) +{ + ::srandom(seed); +} + + +// Writes a vector. +int Utility::writev(int socket, const iovec *vector, size_t count ) +{ + return ::writev(socket,vector,count); +} + +/* this is cut and pasted from dietlibc, gratefully copied! */ +static int isleap(int year) { + /* every fourth year is a leap year except for century years that are + * not divisible by 400. */ + return (!(year%4) && ((year%100) || !(year%400))); +} + +time_t Utility::timegm(struct tm *const t) +{ + const static short spm[13] = /* days per month -- nonleap! */ + { 0, + (31), + (31+28), + (31+28+31), + (31+28+31+30), + (31+28+31+30+31), + (31+28+31+30+31+30), + (31+28+31+30+31+30+31), + (31+28+31+30+31+30+31+31), + (31+28+31+30+31+30+31+31+30), + (31+28+31+30+31+30+31+31+30+31), + (31+28+31+30+31+30+31+31+30+31+30), + (31+28+31+30+31+30+31+31+30+31+30+31), + }; + + time_t day; + time_t i; + time_t years = t->tm_year - 70; + + if (t->tm_sec>60) { t->tm_min += t->tm_sec/60; t->tm_sec%=60; } + if (t->tm_min>60) { t->tm_hour += t->tm_min/60; t->tm_min%=60; } + if (t->tm_hour>60) { t->tm_mday += t->tm_hour/60; t->tm_hour%=60; } + if (t->tm_mon>12) { t->tm_year += t->tm_mon/12; t->tm_mon%=12; } + + while (t->tm_mday>spm[1+t->tm_mon]) { + if (t->tm_mon==1 && isleap(t->tm_year+1900)) { + if (t->tm_mon==31+29) break; + --t->tm_mday; + } + t->tm_mday-=spm[t->tm_mon]; + ++t->tm_mon; + if (t->tm_mon>11) { t->tm_mon=0; ++t->tm_year; } + } + + if (t->tm_year < 70) + return (time_t) -1; + /* Days since 1970 is 365 * number of years + number of leap years since 1970 */ + day = years * 365 + (years + 1) / 4; + + /* After 2100 we have to substract 3 leap years for every 400 years + This is not intuitive. Most mktime implementations do not support + dates after 2059, anyway, so we might leave this out for it's + bloat. */ + if ((years -= 131) >= 0) { + years /= 100; + day -= (years >> 2) * 3 + 1; + if ((years &= 3) == 3) years--; + day -= years; + } + + day += t->tm_yday = spm [t->tm_mon] + t->tm_mday-1 + ( isleap (t->tm_year+1900) & (t->tm_mon > 1) ); + + /* day is now the number of days since 'Jan 1 1970' */ + i = 7; + t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */ + + i = 24; + day *= i; + i = 60; + return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec; +} + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/utility.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/utility.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/utility.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/utility.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,213 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 PowerDNS.COM 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 +*/ +// Utility class specification. + +#ifndef UTILITY_HH +#define UTILITY_HH + +#ifndef WIN32 +// # include "config.h" +#endif // WIN32 + +#ifdef _MSC_VER +# define NEED_POSIX_TYPEDEF +# pragma warning (disable:4996) +#endif // _MSC_VER + +#ifdef NEED_POSIX_TYPEDEF +typedef unsigned char uint8_t; +typedef unsigned short int uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; +#endif + + +#ifndef WIN32 +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +# include +#else +typedef int socklen_t; +#define _WIN32_WINNT 0x0400 +#include +#include +#include +# define WINDOWS_LEAN_AND_MEAN +# include +# include +# include + +#ifndef ETIMEDOUT +# define ETIMEDOUT WSAETIMEDOUT +#endif // ETIMEDOUT + +# define EINPROGRESS WSAEWOULDBLOCK + +# define snprintf _snprintf +#endif // WIN32 +#include + +#include "namespaces.hh" + +//! A semaphore class. +class Semaphore +{ +private: + sem_t *m_pSemaphore; +#ifdef WIN32 + typedef int sem_value_t; + + //! The semaphore. + + + + //! Semaphore counter. + long m_counter; + +#else + typedef int sem_value_t; + + uint32_t m_magic; + pthread_mutex_t m_lock; + pthread_cond_t m_gtzero; + sem_value_t m_count; + uint32_t m_nwaiters; +#endif + +protected: +public: + //! Default constructor. + Semaphore( unsigned int value = 0 ); + + //! Destructor. + ~Semaphore( void ); + + //! Posts to a semaphore. + int post( void ); + + //! Waits for a semaphore. + int wait( void ); + + //! Tries to wait for a semaphore. + int tryWait( void ); + + //! Retrieves the semaphore value. + int getValue( Semaphore::sem_value_t *sval ); +}; + +//! This is a utility class used for platform independant abstraction. +class Utility +{ +#ifdef WIN32 +private: + static int inet_pton4( const char *src, void *dst ); + static int inet_pton6( const char *src, void *dst ); + + static const char *inet_ntop4( const char *src, char *dst, size_t size ); + static const char *inet_ntop6( const char *src, char *dst, size_t size ); + +#endif // WIN32 + +public: +#ifdef WIN32 + + //! iovec structure for windows. + typedef struct + { + void *iov_base; //!< Base address. + size_t iov_len; //!< Number of bytes. + } iovec; + + // A few type defines. + typedef DWORD pid_t; + typedef SOCKET sock_t; + typedef int socklen_t; + +#else + typedef ::iovec iovec; + typedef ::pid_t pid_t; + typedef int sock_t; + typedef ::socklen_t socklen_t; + +#endif // WIN32 + + //! Closes a socket. + static int closesocket( sock_t socket ); + + //! Returns the process id of the current process. + static pid_t getpid( void ); + + //! Gets the current time. + static int gettimeofday( struct timeval *tv, void *tz = NULL ); + + //! Converts an address from dot and numbers format to binary data. + static int inet_aton( const char *cp, struct in_addr *inp ); + + //! Converts an address from presentation format to network format. + static int inet_pton( int af, const char *src, void *dst ); + + //! The inet_ntop() function converts an address from network format (usually a struct in_addr or some other binary form, in network byte order) to presentation format. + static const char *inet_ntop( int af, const char *src, char *dst, size_t size ); + + //! Retrieves a gid using a groupname. + static int makeGidNumeric( const string & group ); + + //! Retrieves an uid using an username. + static int makeUidNumeric( const string & username ); + + //! Writes a vector. + static int writev( Utility::sock_t socket, const iovec *vector, size_t count ); + //! Returns a random number. + static long int random( void ); + + //! Sets the random seed. + static void srandom( unsigned int seed ); + + //! Drops the program's privileges. + static void dropPrivs( int uid, int gid ); + + //! Sets the socket into blocking mode. + static bool setBlocking( Utility::sock_t socket ); + + //! Sets the socket into non-blocking mode. + static bool setNonBlocking( Utility::sock_t socket ); + + //! Marks the socket to be closed on exec(). + static bool setCloseOnExec ( Utility::sock_t socket ); + + //! Sleeps for a number of seconds. + static unsigned int sleep( unsigned int seconds ); + + //! Sleeps for a number of microseconds. + static void usleep( unsigned long usec ); + + static time_t timegm(struct tm *tm); + +}; + + +#endif // UTILITY_HH diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/win32_logger.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/win32_logger.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/win32_logger.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/win32_logger.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,181 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 PowerDNS.COM 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 "utility.hh" +#include "logger.hh" +#include "ntservice.hh" +#include "pdnsmsg.hh" +#include "namespaces.hh" + +Logger &theL(const string &pname) +{ + static Logger l(""); + if(!pname.empty()) + l.setName(pname); + return l; +} + +void Logger::log(const string &msg, Urgency u) +{ + const char *tmp[ 2 ]; + + tmp[ 0 ] = msg.c_str(); + tmp[ 1 ] = NULL; + + char timestr[ 128 ]; + time_t curtime= time( NULL ); + strftime( timestr, sizeof( timestr ), "%a %d %b %X", localtime( &curtime )); + + if ( m_pLogFile != NULL ) + { + ostringstream message; + message << timestr << " (" << u << "): " << msg << endl; + fwrite( message.str().c_str(), sizeof( char ), message.str().length(), m_pLogFile ); + fflush( m_pLogFile ); + } + if(m_eventLogHandle) + ReportEvent( m_eventLogHandle, u, 0, MSG_WARNING, NULL, 1, 0, tmp, NULL ); + + clog << timestr<<" " <getServiceName().c_str()); +} + +void Logger::open() +{ + opened=true; +} + +void Logger::setName(const string &_name) +{ + name=_name; + open(); +} + +Logger::Logger(const string &n, int facility) +{ + opened=false; + flags=0; + d_facility=facility; + consoleUrgency=Error; + name=n; + m_pLogFile = NULL; + m_eventLogHandle = NULL; + open(); +} + +Logger& Logger::operator<<(Urgency u) +{ + d_outputurgencies[0]=u; + return *this; +} + +Logger& Logger::operator<<(const string &s) +{ + if(!d_outputurgencies.count(0)) // default urgency + d_outputurgencies[0]=Info; + + if ( !m_toNTLog.count( 0)) + m_toNTLog[ 0 ] = false; + + // if(d_outputurgencies[0]<=(unsigned int)consoleUrgency) // prevent building strings we won't ever print + d_strings[0].append(s); + + return *this; +} + +Logger& Logger::operator<<(int i) +{ + ostringstream tmp; + tmp< +#include + + +/** \mainpage + Simple system for implementing cooperative multitasking of functions, with + support for waiting on events which can return values. + + \section copyright Copyright and License + MTasker is (c) 2002 by bert hubert. It is licensed to you under the terms of the GPL version 2. + Quick and dirty port to Win32 by Christof Meerwald. + + \section overview High level overview + MTasker is designed to support very simple cooperative multitasking to facilitate writing + code that would ordinarily require a statemachine, for which the author does not consider + himself smart enough. + + This class does not perform any magic it only makes calls to makecontext() and swapcontext(). + Getting the details right however is complicated and MTasker does that for you. + + If preemptive multitasking or more advanced concepts such as semaphores, locks or mutexes + are required, the use of POSIX threads is advised. + + MTasker is designed to offer the performance of statemachines while maintaining simple thread semantics. It is not + a replacement for a full threading system. + + \section concepts Concepts + + There are two important concepts, the 'kernel' and the 'thread'. Each thread starts out as a function, + which is passed to MTasker::makeThread(), together with a possible argument. + + This function is now free to do whatever it wants, but realise that MTasker implements cooperative + multitasking, which means that the coder has the responsiblilty of not taking the CPU overly long. + Other threads can only get the CPU if MTasker::yield() is called or if a thread sleeps to wait for an event, + using the MTasker::waitEvent() method. + + \section kernel The Kernel + The Kernel consists of functions that do housekeeping, but also of code that the client coder + can call to report events. A minimal kernel loop looks like this: + \code + for(;;) { + MT.schedule(); + if(MT.noProcesses()) // exit if no processes are left + break; + } + \endcode + + The kernel typically starts from the main() function of your program. New threads are also + created from the kernel. This can also happen before entering the main loop. To start a thread, + the method MTasker::makeThread is provided. + + \section events Events + By default, Events are recognized by an int and their value is also an int. + This can be overridden by specifying the EventKey and EventVal template parameters. + + An event can be a keypress, but also a UDP packet, or a bit of data from a TCP socket. The + sample code provided works with keypresses, but that is just a not very useful example. + + A thread can also wait for an event only for a limited time, and receive a timeout of that + event did not occur within the specified timeframe. + + \section example A simple menu system + \code +MTasker<> MT; + +void menuHandler(void *p) +{ + int num=(int)p; + cout<<"Key handler for key "<int MTasker::waitEvent(EventKey &key, EventVal *val, unsigned int timeout) +{ + if(d_waiters.count(key)) { // there was already an exact same waiter + return -1; + } + + Waiter w; + w.context=GetCurrentFiber(); + w.ttd= timeout ? time(0)+timeout : 0; + w.tid=d_tid; + w.key=key; + + d_waiters.insert(w); + + SwitchToFiber(d_kernel); + if(val && d_waitstatus==Answer) + *val=d_waitval; + d_tid=w.tid; + return d_waitstatus; +} + +//! yields control to the kernel or other threads +/** Hands over control to the kernel, allowing other processes to run, or events to arrive */ + +templatevoid MTasker::yield() +{ + d_runQueue.push(d_tid); + SwitchToFiber(d_kernel); // give control to the kernel +} + +//! reports that an event took place for which threads may be waiting +/** From the kernel loop, sendEvent can be called to report that something occured for which there may be waiters. + \param key Key of the event for which threads may be waiting + \param val If non-zero, pointer to the content of the event + \return Returns -1 in case of error, 0 if there were no waiters, 1 if a thread was woken up. +*/ +templateint MTasker::sendEvent(const EventKey& key, const EventVal* val) +{ + + typename waiters_t::iterator waiter=d_waiters.find(key); + + if(waiter == d_waiters.end()) { + // cout<<"Event sent nobody was waiting for!"<context; + d_tid=waiter->tid; // set tid + d_eventkey=waiter->key; // pass waitEvent the exact key it was woken for + d_waiters.erase(waiter); // removes the waitpoint + SwitchToFiber(userspace); // swaps back to the above point 'A' + + return 1; +} + +//! launches a new thread +/** The kernel can call this to make a new thread, which starts at the function start and gets passed the val void pointer. + \param start Pointer to the function which will form the start of the thread + \param val A void pointer that can be used to pass data to the thread +*/ +templatevoid MTasker::makeThread(tfunc_t *start, void* val) +{ + ThreadParam *param = new ThreadParam; + + param->tf = start; + param->self = this; + param->tid = d_maxtid; + param->val = val; + + LPVOID uc = CreateFiber(d_stacksize, threadWrapper, param); + + d_threads[d_maxtid]=uc; + d_runQueue.push(d_maxtid++); // will run at next schedule invocation +} + + +//! needs to be called periodically so threads can run and housekeeping can be performed +/** The kernel should call this function every once in a while. It makes sense + to call this function if you: + - reported an event + - called makeThread + - want to have threads running waitEvent() to get a timeout if enough time passed + + \return Returns if there is more work scheduled and recalling schedule now would be useful + +*/ +templatebool MTasker::schedule() +{ + + if(!d_runQueue.empty()) { + d_tid=d_runQueue.front(); + SwitchToFiber(d_threads[d_tid]); + d_runQueue.pop(); + return true; + } + if(!d_zombiesQueue.empty()) { + DeleteFiber(d_threads[d_zombiesQueue.front()]); + d_threads.erase(d_zombiesQueue.front()); + d_zombiesQueue.pop(); + return true; + } + + if(!d_waiters.empty()) { + typedef typename waiters_t::template index::type waiters_by_ttd_index_t; + // waiters_by_ttd_index_t& ttdindex=d_waiters.template get(); + waiters_by_ttd_index_t& ttdindex=boost::multi_index::get(d_waiters); + + for(typename waiters_by_ttd_index_t::iterator i=ttdindex.begin(); i != ttdindex.end(); ) { + if(i->ttd && (unsigned int)i->ttd < now) { + d_waitstatus=TimeOut; + SwitchToFiber(i->context); + ttdindex.erase(i++); // removes the waitpoint + } + else if(i->ttd) + break; + } + } + return false; +} + +//! returns true if there are no processes +/** Call this to check if no processes are running anymore + \return true if no processes are left + */ +templatebool MTasker::noProcesses() +{ + return d_threads.empty(); +} + +//! returns the number of processes running +/** Call this to perhaps limit activities if too many threads are running + \return number of processes running + */ +templateunsigned int MTasker::numProcesses() +{ + return (unsigned int)d_threads.size(); +} + +//! gives access to the list of Events threads are waiting for +/** The kernel can call this to get a list of Events threads are waiting for. This is very useful + to setup 'select' or 'poll' or 'aio' events needed to satisfy these requests. + getEvents clears the events parameter before filling it. + + \param events Vector which is to be filled with keys threads are waiting for +*/ +templatevoid MTasker::getEvents(std::vector& events) +{ + events.clear(); + for(typename waiters_t::const_iterator i=d_waiters.begin();i!=d_waiters.end();++i) { + events.push_back(i->first); + } +} + + +//! Returns the current Thread ID (tid) +/** Processes can call this to get a numerical representation of their current thread ID. + This can be useful for logging purposes. +*/ +templateint MTasker::getTid() +{ + return d_tid; +} + + +template +VOID WINAPI MTasker::threadWrapper(LPVOID lpFiberParameter) +{ + ThreadParam *param = (ThreadParam *) lpFiberParameter; + + tfunc_t *tf = param->tf; + + tf(param->val); + + MTasker *self = param->self; + self->d_zombiesQueue.push(param->tid); + delete param; + + SwitchToFiber(self->d_kernel); +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/win32_mtasker.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/win32_mtasker.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/win32_mtasker.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/win32_mtasker.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,113 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 PowerDNS.COM BV + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +#ifndef WIN32_MTASKER_HH +#define WIN32_MTASKER_HH + +#define WINDOWS_LEAN_AND_MEAN +#include + +#include +#include +#include +#include +#include + +struct KeyTag {}; + +//! The main MTasker class +/** The main MTasker class. See the main page for more information. + \param EventKey Type of the key with which events are to be identified. Defaults to int. + \param EventVal Type of the content or value of an event. Defaults to int. Cannot be set to void. + \note The EventKey needs to have an operator< defined because it is used as the key of an associative array +*/ +template class MTasker +{ +public: + struct Waiter + { + LPVOID context; + time_t ttd; + int tid; + EventKey key; + }; + typedef multi_index_container< + Waiter, + indexed_by < + ordered_unique >, + ordered_non_unique, member > + > + > waiters_t; + + waiters_t d_waiters; + +private: + LPVOID d_kernel; + std::queue d_runQueue; + std::queue d_zombiesQueue; + + + std::map d_threads; + int d_tid; + int d_maxtid; + size_t d_stacksize; + + EventVal d_waitval; + EventKey d_eventkey; + enum {Error=-1,TimeOut=0,Answer} d_waitstatus; + +public: + //! Constructor + /** Constructor with a small default stacksize. If any of your threads exceeds this stack, your application will crash. + This limit applies solely to the stack, the heap is not limited in any way. If threads need to allocate a lot of data, + the use of new/delete is suggested. + */ + MTasker(size_t stacksize=8192) : d_stacksize(stacksize) + { + d_kernel=ConvertThreadToFiber( NULL ); + d_maxtid=0; + } + + typedef void tfunc_t(void *); //!< type of the pointer that starts a thread + int waitEvent(EventKey &key, EventVal *val=0, unsigned int timeout=0); + void yield(); + int sendEvent(const EventKey& key, const EventVal* val=0); + void getEvents(std::vector& events); + void makeThread(tfunc_t *start, void* val); + bool schedule(); + bool noProcesses(); + unsigned int numProcesses(); + int getTid(); + +private: + //! This structure holds some fiber data that is passed to the threadWrapper. + struct ThreadParam + { + tfunc_t *tf; + MTasker *self; + int tid; + LPVOID val; + }; + + static void WINAPI threadWrapper( LPVOID lpFiberParameter ); +}; + +#include "win32_mtasker.cc" + +#endif // WIN32_MTASKER_HH + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/win32_rec_channel.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/win32_rec_channel.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/win32_rec_channel.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/win32_rec_channel.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,38 @@ +#include "rec_channel.hh" +#include +#include +#include +#include + +#include "ahuexception.hh" + +#include "namespaces.hh" + +RecursorControlChannel::RecursorControlChannel() +{ +} + +RecursorControlChannel::~RecursorControlChannel() +{ +} + +int RecursorControlChannel::listen(const string& fname) +{ + return 0; +} + +void RecursorControlChannel::connect(const string& path, const string& fname) +{ + +} + +void RecursorControlChannel::send(const std::string& msg, const std::string* remote) +{ + +} + +string RecursorControlChannel::recv(std::string* remote) +{ + return 0; +} + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/win32_utility.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/win32_utility.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/win32_utility.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/win32_utility.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,414 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2002 - 2006 PowerDNS.COM BV + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// Utility class win32 implementation. + +#include "utility.hh" +#include +#include + +// Closes a socket. +int Utility::closesocket( Utility::sock_t socket ) +{ + return ::closesocket( socket ); +} + + +// Drops the program's privileges. +void Utility::dropPrivs( int uid, int gid ) +{ +} + + +// Returns the current process id. +Utility::pid_t Utility::getpid( void ) +{ + return GetCurrentProcessId(); +} + + +// Returns a monotonic clock +int Utility::gettimeofday( struct timeval *tv, void *tz ) +{ + if ( tv == NULL ) + return -1; + + DWORD ticks = timeGetTime(); + tv->tv_sec = 86400 + static_cast< long >( ticks / 1000 ); + tv->tv_usec = static_cast< long >( ticks % 1000 ); + + return 0; +} + + +// Converts an address from dot and numbers format to binary data. +int Utility::inet_aton( const char *cp, struct in_addr *inp ) +{ + if ( cp == NULL ) + return 0; + + if (( inp->s_addr = inet_addr( cp )) == -1 ) + return 0; + + return 1; +} + + +// The inet_ntop() function converts an address from network format (usually a struct in_addr or some other binary form, in network byte order) to presentation format. +const char *Utility::inet_ntop( int af, const char *src, char *dst, size_t size ) +{ + if ( af == AF_INET ) + return inet_ntop4( src, dst, size ); + else if ( af == AF_INET6 ) + return inet_ntop6( src, dst, size ); + + return NULL; +} + + +// Converts an address from presentation format to network format. +int Utility::inet_pton( int af, const char *src, void *dst ) +{ + if ( af == AF_INET ) + return inet_pton4( src, dst ); + else if ( af == AF_INET6 ) + return inet_pton6( src, dst ); + + // TODO: Implement this. + return 0; +} + + +// Converts an ipv4 address from www.xxx.yyy.zzz format to binary data. +int Utility::inet_pton4( const char *src, void *dst ) +{ + struct in_addr tmp; + + if ( inet_aton( src, &tmp ) == -1 ) + return 0; + + memcpy( dst, &tmp, sizeof( struct in_addr )); + + return 1; +} + + +const char *Utility::inet_ntop4( const char *src, char *dst, size_t size ) +{ + char *temp = inet_ntoa( *( reinterpret_cast< const struct in_addr * >( src ))); + + if ( temp == NULL ) + return NULL; + + memcpy( dst, temp, size ); + + return reinterpret_cast< const char * >( dst ); +} + +#define NS_IN6ADDRSZ 16 +#define NS_INT16SZ 2 +#define NS_INADDRSZ 4 + +const char * +Utility::inet_ntop6( const char *src, char *dst, size_t size ) +{ + /* + * Note that int32_t and int16_t need only be "at least" large enough + * to contain a value of the specified size. On some systems, like + * Crays, there is no such thing as an integer variable with 16 bits. + * Keep this in mind if you think this function should have been coded + * to use pointer overlays. All the world's not a VAX. + */ + char tmp[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"], *tp; + struct { int base, len; } best, cur; + uint16_t words[NS_IN6ADDRSZ / NS_INT16SZ]; + int i; + + /* + * Preprocess: + * Copy the input (bytewise) array into a wordwise array. + * Find the longest run of 0x00's in src[] for :: shorthanding. + */ + memset(words, '\0', sizeof words); + for (i = 0; i < NS_IN6ADDRSZ; i++) + words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); + best.base = -1; + cur.base = -1; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + if (words[i] == 0) { + if (cur.base == -1) + cur.base = i, cur.len = 1; + else + cur.len++; + } else { + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + cur.base = -1; + } + } + } + if (cur.base != -1) { + if (best.base == -1 || cur.len > best.len) + best = cur; + } + if (best.base != -1 && best.len < 2) + best.base = -1; + + /* + * Format the result. + */ + tp = tmp; + for (i = 0; i < (NS_IN6ADDRSZ / NS_INT16SZ); i++) { + /* Are we inside the best run of 0x00's? */ + if (best.base != -1 && i >= best.base && + i < (best.base + best.len)) { + if (i == best.base) + *tp++ = ':'; + continue; + } + /* Are we following an initial run of 0x00s or any real hex? */ + if (i != 0) + *tp++ = ':'; + /* Is this address an encapsulated IPv4? */ + if (i == 6 && best.base == 0 && (best.len == 6 || + (best.len == 7 && words[7] != 0x0001) || + (best.len == 5 && words[5] == 0xffff))) { + if (!inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp))) + return (NULL); + tp += strlen(tp); + break; + } + tp += sprintf(tp, "%x", words[i]); + } + /* Was it a trailing run of 0x00's? */ + if (best.base != -1 && (best.base + best.len) == + (NS_IN6ADDRSZ / NS_INT16SZ)) + *tp++ = ':'; + *tp++ = '\0'; + + /* + * Check for overflow, copy, and we're done. + */ + if ((size_t)(tp - tmp) > size) { + // errno = ENOSPC; + return (NULL); + } + strcpy(dst, tmp); + return (dst); +} + + + +/* int + * inet_pton6(src, dst) + * convert presentation level address to network order binary form. + * return: + * 1 if `src' is a valid [RFC1884 2.2] address, else 0. + * notice: + * (1) does not touch `dst' unless it's returning 1. + * (2) :: in a full address is silently ignored. + * credit: + * inspired by Mark Andrews. + * author: + * Paul Vixie, 1996. + */ +int +Utility::inet_pton6( const char *src, void *dst ) +{ + static const char xdigits_l[] = "0123456789abcdef", + xdigits_u[] = "0123456789ABCDEF"; + u_char tmp[NS_IN6ADDRSZ], *tp, *endp, *colonp; + const char *xdigits, *curtok; + int ch, saw_xdigit; + u_int val; + + memset((tp = tmp), '\0', NS_IN6ADDRSZ); + endp = tp + NS_IN6ADDRSZ; + colonp = NULL; + /* Leading :: requires some special handling. */ + if (*src == ':') + if (*++src != ':') + return (0); + curtok = src; + saw_xdigit = 0; + val = 0; + while ((ch = *src++) != '\0') { + const char *pch; + + if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) + pch = strchr((xdigits = xdigits_u), ch); + if (pch != NULL) { + val <<= 4; + val |= (pch - xdigits); + if (val > 0xffff) + return (0); + saw_xdigit = 1; + continue; + } + if (ch == ':') { + curtok = src; + if (!saw_xdigit) { + if (colonp) + return (0); + colonp = tp; + continue; + } else if (*src == '\0') { + return (0); + } + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + saw_xdigit = 0; + val = 0; + continue; + } + if (ch == '.' && ((tp + NS_INADDRSZ) <= endp) && + inet_pton4(curtok, tp) > 0) { + tp += NS_INADDRSZ; + saw_xdigit = 0; + break; /* '\0' was seen by inet_pton4(). */ + } + return (0); + } + if (saw_xdigit) { + if (tp + NS_INT16SZ > endp) + return (0); + *tp++ = (u_char) (val >> 8) & 0xff; + *tp++ = (u_char) val & 0xff; + } + if (colonp != NULL) { + /* + * Since some memmove()'s erroneously fail to handle + * overlapping regions, we'll do the shift by hand. + */ + const int n = tp - colonp; + int i; + + if (tp == endp) + return (0); + for (i = 1; i <= n; i++) { + endp[- i] = colonp[n - i]; + colonp[n - i] = 0; + } + tp = endp; + } + if (tp != endp) + return (0); + memcpy(dst, tmp, NS_IN6ADDRSZ); + return (1); +} +#undef NS_IN6ADDRSZ +#undef NS_INT16SZ +#undef NS_INADDRSZ + + +// Returns a random number. +long int Utility::random( void ) +{ + return rand(); +} + + +// Retrieves a gid using a groupname. +int Utility::makeGidNumeric( const std::string & group ) +{ + return 0; +} + + +// Retrieves an uid using a username. +int Utility::makeUidNumeric( const std::string & username ) +{ + return 0; +} + + +// Sets the socket into blocking mode. +bool Utility::setBlocking( Utility::sock_t socket ) +{ + unsigned long tmp = 0; + + if ( ioctlsocket( socket, FIONBIO, &tmp ) == SOCKET_ERROR ) + return false; + + return true; +} + + +// Sets the socket into non-blocking mode. +bool Utility::setNonBlocking( Utility::sock_t socket ) +{ + unsigned long tmp = 1; + + if( ioctlsocket( socket, FIONBIO, &tmp ) == SOCKET_ERROR ) + return false; + + return true; +} + +// Marks the socket to be closed on exec(). +// No-op on Windows. +bool Utility::setCloseOnExec(sock_t sock) +{ + return true; +} + +// Sleeps for a number of seconds. +unsigned int Utility::sleep( unsigned int seconds ) +{ + Sleep( seconds * 1000 ); + return 0; +} + + +// Sets the random seed. +void Utility::srandom( unsigned int seed ) +{ + srand( seed ); +} + + +// Sleeps for a number of microseconds. +void Utility::usleep( unsigned long usec ) +{ + Sleep( usec / 1000 ); +} + + +// Writes a vector. +int Utility::writev( Utility::sock_t socket, const Utility::iovec *vector, size_t count ) +{ + unsigned int i; + int res; + int nbytes = 0; + + for ( i = 0; i < count; i++ ) + { + res = send( socket, reinterpret_cast< const char * >( vector[ i ].iov_base ), vector[ i ].iov_len, 0 ); + if ( res == -1 ) + return -1; + + nbytes += res; + } + + return nbytes; +} + diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/zoneparser-tng.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/zoneparser-tng.cc --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/zoneparser-tng.cc 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/zoneparser-tng.cc 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,434 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2005 - 2008 PowerDNS.COM 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 "dnsparser.hh" +#include "sstuff.hh" +#include "misc.hh" +#include "dnswriter.hh" +#include "dnsrecords.hh" +#include "misc.hh" +#include +#include "dns.hh" +#include "zoneparser-tng.hh" +#include +#include +#include + +ZoneParserTNG::ZoneParserTNG(const string& fname, const string& zname, const string& reldir) : d_reldir(reldir), + d_zonename(zname), d_defaultttl(3600), + d_havedollarttl(false) +{ + d_zonename = toCanonic("", d_zonename); + stackFile(fname); +} + +void ZoneParserTNG::stackFile(const std::string& fname) +{ + FILE *fp=fopen(fname.c_str(), "r"); + if(!fp) + throw runtime_error("Unable to open file '"+fname+"': "+stringerror()); + + filestate fs(fp, fname); + d_filestates.push(fs); +} + +ZoneParserTNG::~ZoneParserTNG() +{ + while(!d_filestates.empty()) { + fclose(d_filestates.top().d_fp); + d_filestates.pop(); + } +} + +static string makeString(const string& line, const pair& range) +{ + return string(line.c_str() + range.first, range.second - range.first); +} + +static bool isTimeSpec(const string& nextpart) +{ + if(nextpart.empty()) + return false; + for(string::const_iterator iter = nextpart.begin(); iter != nextpart.end(); ++iter) { + if(isdigit(*iter)) + continue; + if(iter+1 != nextpart.end()) + return false; + char c=tolower(*iter); + return (c=='s' || c=='m' || c=='h' || c=='d' || c=='w' || c=='y'); + } + return true; +} + + +unsigned int ZoneParserTNG::makeTTLFromZone(const string& str) +{ + if(str.empty()) + return 0; + + unsigned int val=atoi(str.c_str()); + char lc=toupper(str[str.length()-1]); + if(!isdigit(lc)) + switch(lc) { + case 'S': + break; + case 'M': + val*=60; // minutes, not months! + break; + case 'H': + val*=3600; + break; + case 'D': + val*=3600*24; + break; + case 'W': + val*=3600*24*7; + break; + case 'Y': // ? :-) + val*=3600*24*365; + break; + + default: + throw ZoneParserTNG::exception("Unable to parse time specification '"+str+"' "+getLineOfFile()); + } + return val; +} + +bool ZoneParserTNG::getTemplateLine() +{ + if(d_templateparts.empty() || d_templatecounter > d_templatestop) // no template, or done with + return false; + + string retline; + for(parts_t::const_iterator iter = d_templateparts.begin() ; iter != d_templateparts.end(); ++iter) { + if(iter != d_templateparts.begin()) + retline+=" "; + + string part=makeString(d_templateline, *iter); + + /* a part can contain a 'naked' $, an escaped $ (\$), or ${offset,width,radix}, with width defaulting to 0, + and radix beging 'd', 'o', 'x' or 'X', defaulting to 'd'. + + The width is zero-padded, so if the counter is at 1, the offset is 15, with is 3, and the radix is 'x', + output will be '010', from the input of ${15,3,x} + */ + + string outpart; + outpart.reserve(part.size()+5); + bool inescape=false; + + for(string::size_type pos = 0; pos < part.size() ; ++pos) { + char c=part[pos]; + if(inescape) { + outpart.append(1, c); + inescape=false; + continue; + } + + if(part[pos]=='\\') { + inescape=true; + continue; + } + if(c=='$') { + if(pos + 1 == part.size() || part[pos+1]!='{') { // a trailing $, or not followed by { + outpart.append(lexical_cast(d_templatecounter)); + continue; + } + + // need to deal with { case + + pos+=2; + string::size_type startPos=pos; + for(; pos < part.size() && part[pos]!='}' ; ++pos) + ; + + if(pos == part.size()) // partial spec + break; + + // we are on the '}' + + string spec(part.c_str() + startPos, part.c_str() + pos); + int offset=0, width=0; + char radix='d'; + sscanf(spec.c_str(), "%d,%d,%c", &offset, &width, &radix); // parse format specifier + + char format[12]; + snprintf(format, sizeof(format) - 1, "%%0%d%c", width, radix); // make into printf-style format + + char tmp[80]; + snprintf(tmp, sizeof(tmp)-1, format, d_templatecounter + offset); // and do the actual printing + outpart+=tmp; + } + else + outpart.append(1, c); + } + retline+=outpart; + } + d_templatecounter+=d_templatestep; + + d_line = retline; + return true; +} + +void chopComment(string& line) +{ + string::size_type pos, len = line.length(); + bool inQuote=false; + for(pos = 0 ; pos < len; ++pos) { + if(line[pos]=='\\') + pos++; + else if(line[pos]=='"') + inQuote=!inQuote; + else if(line[pos]==';' && !inQuote) + break; + } + if(pos != len) + line.resize(pos); +} + +bool findAndElide(string& line, char c) +{ + string::size_type pos, len = line.length(); + bool inQuote=false; + for(pos = 0 ; pos < len; ++pos) { + if(line[pos]=='\\') + pos++; + else if(line[pos]=='"') + inQuote=!inQuote; + else if(line[pos]==c && !inQuote) + break; + } + if(pos != len) { + line.erase(pos, 1); + return true; + } + return false; +} + +string ZoneParserTNG::getLineOfFile() +{ + return "on line "+lexical_cast(d_filestates.top().d_lineno)+" of file '"+d_filestates.top().d_filename+"'"; +} + +// ODD: this function never fills out the prio field! rest of pdns compensates though +bool ZoneParserTNG::get(DNSResourceRecord& rr) +{ + retry:; + if(!getTemplateLine() && !getLine()) + return false; + + boost::trim_right_if(d_line, is_any_of(" \r\n\x1a")); + + parts_t parts; + vstringtok(parts, d_line); + + if(parts.empty()) + goto retry; + + if(parts[0].first != parts[0].second && makeString(d_line, parts[0])[0]==';') // line consisting of nothing but comments + goto retry; + + if(d_line[0]=='$') { + string command=makeString(d_line, parts[0]); + if(pdns_iequals(command,"$TTL") && parts.size() > 1) { + d_defaultttl=makeTTLFromZone(trim_right_copy_if(makeString(d_line, parts[1]), is_any_of(";"))); + d_havedollarttl=true; + } + else if(pdns_iequals(command,"$INCLUDE") && parts.size() > 1) { + string fname=unquotify(makeString(d_line, parts[1])); + if(!fname.empty() && fname[0]!='/' && !d_reldir.empty()) + fname=d_reldir+"/"+fname; + stackFile(fname); + } + else if(pdns_iequals(command, "$ORIGIN") && parts.size() > 1) { + d_zonename = toCanonic("", makeString(d_line, parts[1])); + } + else if(pdns_iequals(command, "$GENERATE") && parts.size() > 2) { + // $GENERATE 1-127 $ CNAME $.0 + string range=makeString(d_line, parts[1]); + d_templatestep=1; + d_templatestop=0; + sscanf(range.c_str(),"%d-%d/%d", &d_templatecounter, &d_templatestop, &d_templatestep); + d_templateline=d_line; + parts.pop_front(); + parts.pop_front(); + + d_templateparts=parts; + goto retry; + } + else + throw exception("Can't parse zone line '"+d_line+"' "+getLineOfFile()); + goto retry; + } + + if(isspace(d_line[0])) + rr.qname=d_prevqname; + else { + rr.qname=makeString(d_line, parts[0]); + parts.pop_front(); + if(rr.qname.empty() || rr.qname[0]==';') + goto retry; + } + if(rr.qname=="@") + rr.qname=d_zonename; + else if(!isCanonical(rr.qname)) { + if(d_zonename.empty() || d_zonename[0]!='.') // prevent us from adding a double dot + rr.qname.append(1,'.'); + + rr.qname.append(d_zonename); + } + d_prevqname=rr.qname; + + if(parts.empty()) + throw exception("Line with too little parts "+getLineOfFile()); + + string nextpart; + + rr.ttl=d_defaultttl; + bool haveTTL=0, haveQTYPE=0; + pair range; + + while(!parts.empty()) { + range=parts.front(); + parts.pop_front(); + nextpart=makeString(d_line, range); + if(nextpart.empty()) + break; + + if(nextpart.find(';')!=string::npos) + break; + + // cout<<"Next part: '"< recparts; + switch(rr.qtype.getCode()) { + case QType::MX: + stringtok(recparts, rr.content); + if(recparts.size()==2) { + recparts[1] = stripDot(toCanonic(d_zonename, recparts[1])); + rr.content=recparts[0]+" "+recparts[1]; + } + break; + + case QType::SRV: + stringtok(recparts, rr.content); + if(recparts.size()==4) { + recparts[3] = stripDot(toCanonic(d_zonename, recparts[3])); + rr.content=recparts[0]+" "+recparts[1]+" "+recparts[2]+" "+recparts[3]; + } + break; + + + case QType::NS: + case QType::CNAME: + case QType::PTR: + case QType::AFSDB: + rr.content=stripDot(toCanonic(d_zonename, rr.content)); + break; + + case QType::SOA: + stringtok(recparts, rr.content); + if(recparts.size() > 1) { + recparts[0]=toCanonic(d_zonename, recparts[0]); + recparts[1]=toCanonic(d_zonename, recparts[1]); + } + rr.content.clear(); + for(string::size_type n = 0; n < recparts.size(); ++n) { + if(n) + rr.content.append(1,' '); + + if(n > 1) + rr.content+=lexical_cast(makeTTLFromZone(recparts[n])); + else + rr.content+=recparts[n]; + + if(n==6 && !d_havedollarttl) + d_defaultttl=makeTTLFromZone(recparts[n]); + } + break; + default:; + } + + rr.d_place=DNSResourceRecord::ANSWER; + return true; +} + + +bool ZoneParserTNG::getLine() +{ + while(!d_filestates.empty()) { + if(stringfgets(d_filestates.top().d_fp, d_line)) { + d_filestates.top().d_lineno++; + return true; + } + fclose(d_filestates.top().d_fp); + d_filestates.pop(); + } + return false; +} diff -Nru pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/zoneparser-tng.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/zoneparser-tng.hh --- pdns-recursor-3.3/pdns-recursor-3.5-pre.20120708.2673/zoneparser-tng.hh 1970-01-01 00:00:00.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns-recursor-3.5-pre.20120708.2673/zoneparser-tng.hh 2012-07-08 18:20:53.000000000 +0000 @@ -0,0 +1,63 @@ +/* + PowerDNS Versatile Database Driven Nameserver + Copyright (C) 2005 - 2007 PowerDNS.COM 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 +*/ + +#ifndef PDNS_ZONEPARSER_TNG +#define PDNS_ZONEPARSER_TNG +#include +#include +#include +#include + +#include "namespaces.hh" + +class ZoneParserTNG +{ +public: + ZoneParserTNG(const string& fname, const string& zname="", const string& reldir=""); + + ~ZoneParserTNG(); + + bool get(DNSResourceRecord& rr); + typedef runtime_error exception; + typedef deque > parts_t; +private: + bool getLine(); + bool getTemplateLine(); + void stackFile(const std::string& fname); + unsigned makeTTLFromZone(const std::string& str); + string getLineOfFile(); + string d_reldir; + string d_line; + string d_prevqname; + string d_zonename; + int d_defaultttl; + bool d_havedollarttl; + uint32_t d_templatecounter, d_templatestop, d_templatestep; + string d_templateline; + parts_t d_templateparts; + + struct filestate { + filestate(FILE* fp, string filename) : d_fp(fp), d_filename(filename), d_lineno(0){} + FILE *d_fp; + string d_filename; + int d_lineno; + }; + std::stack d_filestates; +}; + +#endif diff -Nru pdns-recursor-3.3/pdns_recursor.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns_recursor.cc --- pdns-recursor-3.3/pdns_recursor.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/pdns_recursor.cc 2012-07-08 18:20:53.000000000 +0000 @@ -1,6 +1,6 @@ /* PowerDNS Versatile Database Driven Nameserver - Copyright (C) 2003 - 2010 PowerDNS.COM BV + Copyright (C) 2003 - 2012 PowerDNS.COM 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 @@ -64,7 +64,7 @@ #include "iputils.hh" #include "mplexer.hh" #include "config.h" -#include "lua-pdns-recursor.hh" +#include "lua-recursor.hh" #ifndef RECURSOR #include "statbag.hh" @@ -76,7 +76,7 @@ unsigned int g_maxTCPPerClient; unsigned int g_networkTimeoutMsec; bool g_logCommonErrors; -__thread shared_ptr* t_pdl; +__thread shared_ptr* t_pdl; __thread RemoteKeeper* t_remotes; RecursorControlChannel s_rcc; // only active in thread 0 @@ -323,6 +323,8 @@ static int makeClientSocket(int family) { int ret=(int)socket(family, SOCK_DGRAM, 0); + Utility::setCloseOnExec(ret); + if(ret < 0 && errno==EMFILE) // this is not a catastrophic error return ret; @@ -441,7 +443,7 @@ string s_pidfname; static void writePid(void) { - ofstream of(s_pidfname.c_str(), ios_base::app); + ofstream of(s_pidfname.c_str(), std::ios_base::app); if(of) of<< Utility::getpid() < tcpClientCounts_t; tcpClientCounts_t __thread* t_tcpClientCounts; - TCPConnection::TCPConnection(int fd, const ComboAddress& addr) : d_remote(addr), d_fd(fd) { ++s_currentConnections; @@ -490,10 +491,10 @@ DNSComboWriter* dc=(DNSComboWriter *)p; try { - uint16_t maxudpsize=512; + uint32_t maxanswersize= dc->d_tcp ? 65535 : 512; EDNSOpts edo; if(getEDNSOpts(dc->d_mdp, &edo)) { - maxudpsize=max(edo.d_packetsize, (uint16_t)1280); + maxanswersize = min(edo.d_packetsize, (uint16_t) (dc->d_tcp ? 65535 : 1680)); } vector ret; @@ -520,18 +521,30 @@ int res; bool variableAnswer = false; - // if there is a PowerDNSLua active, and it 'took' the query in preResolve, we don't launch beginResolve + // if there is a RecursorLua active, and it 'took' the query in preResolve, we don't launch beginResolve if(!t_pdl->get() || !(*t_pdl)->preresolve(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer)) { res = sr.beginResolve(dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), dc->d_mdp.d_qclass, ret); if(t_pdl->get()) { - if(res == RCode::NXDomain) + if(res == RCode::NoError) { + vector::const_iterator i; + for(i=ret.begin(); i!=ret.end(); ++i) + if(i->qtype.getCode() == dc->d_mdp.d_qtype && i->d_place == DNSResourceRecord::ANSWER) + break; + if(i == ret.end()) + (*t_pdl)->nodata(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer); + } + else if(res == RCode::NXDomain) (*t_pdl)->nxdomain(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer); + + (*t_pdl)->postresolve(dc->d_remote, g_listenSocketsAddresses[dc->d_socket], dc->d_mdp.d_qname, QType(dc->d_mdp.d_qtype), ret, res, &variableAnswer); } } + + - uint32_t minTTL=numeric_limits::max(); - if(res<0) { + uint32_t minTTL=std::numeric_limits::max(); + if(res < 0) { pw.getHeader()->rcode=RCode::ServFail; // no commit here, because no record g_stats.servFails++; @@ -541,7 +554,7 @@ updateRcodeStats(res); if(ret.size()) { - shuffle(ret); + orderAndShuffle(ret); for(vector::const_iterator i=ret.begin(); i!=ret.end(); ++i) { pw.startRecord(i->qname, i->qtype.getCode(), i->ttl, i->qclass, (DNSPacketWriter::Place)i->d_place); @@ -554,7 +567,7 @@ shared_ptr drc(DNSRecordContent::mastermake(i->qtype.getCode(), i->qclass, i->content)); drc->toPacket(pw); } - if(!dc->d_tcp && pw.size() > maxudpsize) { + if(pw.size() > maxanswersize) { pw.rollback(); if(i->d_place==DNSResourceRecord::ANSWER) // only truncate if we actually omitted parts of the answer pw.getHeader()->tc=1; @@ -653,11 +666,16 @@ catch(...) { L<getMaxStackUsage(), g_stats.maxMThreadStackUsage); } -void makeControlChannelSocket() +void makeControlChannelSocket(int processNum=-1) { - string sockname=::arg()["socket-dir"]+"/pdns_recursor.controlsocket"; + string sockname=::arg()["socket-dir"]+"/pdns_recursor"; + if(processNum >= 0) + sockname += "."+lexical_cast(processNum); + sockname+=".controlsocket"; s_rcc.listen(sockname); #ifndef WIN32 @@ -810,8 +828,11 @@ SyncRes::s_queries++; ageDNSPacket(response, age); sendto(fd, response.c_str(), response.length(), 0, (struct sockaddr*) &fromaddr, fromaddr.getSocklen()); - if(response.length() >= sizeof(struct dnsheader)) - updateRcodeStats(((struct dnsheader*)response.c_str())->rcode); + if(response.length() >= sizeof(struct dnsheader)) { + struct dnsheader dh; + memcpy(&dh, response.c_str(), sizeof(dh)); + updateRcodeStats(dh.rcode); + } g_stats.avgLatencyUsec=(uint64_t)((1-0.0001)*g_stats.avgLatencyUsec + 0); // we assume 0 usec return 0; } @@ -910,6 +931,8 @@ } fd=socket(sin.sin6.sin6_family, SOCK_STREAM, 0); + Utility::setCloseOnExec(fd); + if(fd<0) throw AhuException("Making a TCP server socket for resolver: "+stringerror()); @@ -974,6 +997,7 @@ } int fd=socket(sin.sin4.sin_family, SOCK_DGRAM, 0); + Utility::setCloseOnExec(fd); if(fd < 0) { throw AhuException("Making a UDP server socket for resolver: "+netstringerror()); @@ -1379,7 +1403,7 @@ else { g_stats.serverParseError++; if(g_logCommonErrors) - L<d_waiters.size()<<" waiters"<= 0) { t_udpclientsocks->returnSocket(fd); } } else - L<reset(); L<(new PowerDNSLua(fname)); + *t_pdl = shared_ptr(new RecursorLua(fname)); } } catch(std::exception& e) { L<::const_iterator begin, vector::const_iterator end) @@ -1501,9 +1528,7 @@ if(begin != end) ::arg().set("lua-dns-script") = *begin; - broadcastFunction(doReloadLuaScript); - - return "ok, reload/unload queued\n"; + return broadcastAccFunction(doReloadLuaScript); } void* recursorThread(void*); @@ -1585,14 +1610,14 @@ L.setLoglevel((Logger::Urgency)(6)); // info and up if(!::arg()["logging-facility"].empty()) { - boost::optional val=logFacilityToLOG(::arg().asNum("logging-facility") ); - if(val) - theL().setFacility(*val); + int val=logFacilityToLOG(::arg().asNum("logging-facility") ); + if(val >= 0) + theL().setFacility(val); else L< addrs; if(!::arg()["query-local-address6"].empty()) { SyncRes::s_doIPv6=true; - L< 1 ? forks : -1); int newgid=0; if(!::arg()["setgid"].empty()) @@ -1732,8 +1764,6 @@ } Utility::dropPrivs(newuid, newgid); - - g_numThreads = ::arg().asNum("threads") + ::arg().mustDo("pdns-distributes-queries"); makeThreadPipes(); @@ -1776,11 +1806,11 @@ L<d_followRFC2181=::arg().mustDo("auth-can-lower-ttl"); - t_pdl = new shared_ptr(); + t_pdl = new shared_ptr(); try { if(!::arg()["lua-dns-script"].empty()) { - *t_pdl = shared_ptr(new PowerDNSLua(::arg()["lua-dns-script"])); + *t_pdl = shared_ptr(new RecursorLua(::arg()["lua-dns-script"])); L< #include "qtype.hh" #include "misc.hh" +#include "lock.hh" + +pthread_mutex_t QType::uninitlock = PTHREAD_MUTEX_INITIALIZER; bool QType::uninit=true; vector QType::names; @@ -37,6 +40,7 @@ QType::QType() { + Lock l(&uninitlock); if(uninit) { uninit=false; @@ -66,6 +70,7 @@ insert("DNSKEY", 48); insert("NSEC3", 50); insert("NSEC3PARAM", 51); + insert("TLSA",52); insert("SPF",99); insert("IXFR",251); insert("AXFR",252); @@ -74,10 +79,11 @@ insert("MBOXFW",257); insert("CURL",258); insert("ADDR",259); + insert("DLV",32769); } } -int QType::getCode() const +uint16_t QType::getCode() const { return code; } @@ -92,7 +98,7 @@ return "#"+itoa(code); } -QType &QType::operator=(int n) +QType &QType::operator=(uint16_t n) { code=n; return *this; @@ -105,7 +111,14 @@ for(pos=names.begin();posfirst==p) return pos->second; + + if(*p=='#') { + return atoi(p+1); + } + if(boost::starts_with(p, "TYPE")) + return atoi(p+4); + return 0; } @@ -127,108 +140,8 @@ } -QType::QType(int n) +QType::QType(uint16_t n) { QType(); code=n; } - -QType::QType(const char *p) -{ - QType(); - code=chartocode(p); -} - -string DNSResourceRecord::serialize() const -{ - ostringstream ostr; - ostr< #include #include - -using namespace std; +#include "namespaces.hh" /** The QType class is meant to deal easily with the different kind of resource types, like 'A', 'NS', - * 'CNAME' etcetera. These types have both a name and a number. This class can seemlessly move between + * 'CNAME' etcetera. These types have both a name and a number. This class can seamlessly move between * them. Use it like this: \code @@ -46,12 +45,11 @@ { public: QType(); //!< Naked constructor - explicit QType(int); //!< convert from an integer to a QType - QType(const char *p); //!< convert from a char* to a QType + explicit QType(uint16_t); //!< convert from an integer to a QType QType(const QType& orig) : code(orig.code) { } - QType &operator=(int); //!< Assigns integers to us + QType &operator=(uint16_t); //!< Assigns integers to us QType &operator=(const char *); //!< Assings strings to us QType &operator=(const string &); //!< Assings strings to us QType &operator=(const QType&rhs) //!< Assings strings to us @@ -65,24 +63,30 @@ return code < rhs.code; } + template + void serialize(Archive &ar, const unsigned int version) + { + ar & code; + } + bool operator==(const QType &) const; //!< equality operator const string getName() const; //!< Get a string representation of this type - int getCode() const; //!< Get the integer representation of this type + uint16_t getCode() const; //!< Get the integer representation of this type static int chartocode(const char *p); //!< convert a character string to a code // more solaris fun #undef DS enum typeenum {A=1,NS=2,CNAME=5,SOA=6, MR=9, PTR=12,HINFO=13,MX=15,TXT=16,RP=17,AFSDB=18,KEY=25,AAAA=28,LOC=29,SRV=33,NAPTR=35, KX=36, - CERT=37,OPT=41, DS=43, SSHDP=44, IPSECKEY=45, RRSIG=46, NSEC=47, DNSKEY=48, DHCID=49, NSEC3=50, NSEC3PARAM=51, - SPF=99, TSIG=250, AXFR=252, IXFR=251, ANY=255, URL=256, MBOXFW=257, CURL=258, ADDR=259} types; - typedef pair namenum; + CERT=37,OPT=41, DS=43, SSHFP=44, IPSECKEY=45, RRSIG=46, NSEC=47, DNSKEY=48, DHCID=49, NSEC3=50, NSEC3PARAM=51, + TLSA=52, SPF=99, TSIG=250, AXFR=252, IXFR=251, ANY=255, URL=256, MBOXFW=257, CURL=258, ADDR=259, DLV=32769} types; + typedef pair namenum; static vector names; private: - short int code; + uint16_t code; void insert(const char *p, int n); - + static pthread_mutex_t uninitlock; static bool uninit; }; diff -Nru pdns-recursor-3.3/rcpgenerator.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/rcpgenerator.cc --- pdns-recursor-3.3/rcpgenerator.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/rcpgenerator.cc 2012-07-08 18:20:53.000000000 +0000 @@ -1,6 +1,6 @@ /* PowerDNS Versatile Database Driven Nameserver - Copyright (C) 2005 - 2007 PowerDNS.COM BV + Copyright (C) 2005 - 2011 PowerDNS.COM 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 @@ -147,6 +147,7 @@ throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve } +// this code should leave all the escapes around void RecordTextReader::xfrLabel(string& val, bool) { skipSpaces(); @@ -158,13 +159,9 @@ while(d_pos < d_end) { if(strptr[d_pos]!='\r' && dns_isspace(strptr[d_pos])) break; - - if(strptr[d_pos]=='\\' && d_pos < d_end - 1 && strptr[d_pos+1]!='.') // leave the \. escape around - d_pos++; - + d_pos++; } - val.append(strptr+begin_pos, strptr+d_pos); if(val.empty()) @@ -223,23 +220,38 @@ } -void HEXDecode(const char* begin, const char* end, string& val) +void HEXDecode(const char* begin, const char* end, string& out) { - if((end - begin)%2) - throw RecordTextException("Hexadecimal blob with odd number of characters"); - - int limit=(int)(end-begin)/2; - val.resize(limit); - for(int n=0; n < limit; ++n) { - val[n] = hextodec(begin[2*n])*16 + hextodec(begin[2*n+1]); + if(end - begin == 1 && *begin=='-') { + out.clear(); + return; + } + out.clear(); + out.reserve((end-begin)/2); + uint8_t mode=0, val=0; + for(; begin != end; ++begin) { + if(!isalnum(*begin)) + continue; + if(mode==0) { + val = 16*hextodec(*begin); + mode=1; + } else { + val += hextodec(*begin); + out.append(1, (char) val); + mode = 0; + val = 0; + } } + if(mode) + out.append(1, (char) val); + } -void RecordTextReader::xfrHexBlob(string& val) +void RecordTextReader::xfrHexBlob(string& val, bool keepReading) { skipSpaces(); int pos=(int)d_pos; - while(d_pos < d_end && !dns_isspace(d_string[d_pos])) + while(d_pos < d_end && (keepReading || !dns_isspace(d_string[d_pos]))) d_pos++; HEXDecode(d_string.c_str()+pos, d_string.c_str() + d_pos, val); @@ -425,24 +437,13 @@ xfr32BitInt(val); } - +// should not mess with the escapes void RecordTextWriter::xfrLabel(const string& val, bool) { if(!d_string.empty()) d_string.append(1,' '); - if(val.find(' ')==string::npos) - d_string+=val; - else { - d_string.reserve(d_string.size()+val.size()+3); - for(string::size_type pos=0; pos < val.size() ; ++pos) - if(dns_isspace(val[pos])) - d_string+="\\ "; - else if(val[pos]=='\\') - d_string.append(1,'\\'); - else - d_string.append(1,val[pos]); - } - // d_string.append(1,'.'); + + d_string+=val; } void RecordTextWriter::xfrBlob(const string& val, int) @@ -453,11 +454,16 @@ d_string+=Base64Encode(val); } -void RecordTextWriter::xfrHexBlob(const string& val) +void RecordTextWriter::xfrHexBlob(const string& val, bool) { if(!d_string.empty()) d_string.append(1,' '); + if(val.empty()) { + d_string.append(1,'-'); + return; + } + string::size_type limit=val.size(); char tmp[5]; for(string::size_type n = 0; n < limit; ++n) { diff -Nru pdns-recursor-3.3/rcpgenerator.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/rcpgenerator.hh --- pdns-recursor-3.3/rcpgenerator.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/rcpgenerator.hh 2012-07-08 18:20:53.000000000 +0000 @@ -28,7 +28,7 @@ # include "utility.hh" #endif -using namespace std; +#include "namespaces.hh" class RecordTextException : public runtime_error { @@ -53,7 +53,7 @@ void xfrLabel(string& val, bool compress=false); void xfrText(string& val, bool multi=false); - void xfrHexBlob(string& val); + void xfrHexBlob(string& val, bool keepReading=false); void xfrBase32HexBlob(string& val); void xfrBlob(string& val, int len=-1); @@ -83,11 +83,11 @@ void xfrLabel(const string& val, bool compress=false); void xfrText(const string& val, bool multi=false); void xfrBlob(const string& val, int len=-1); - void xfrHexBlob(const string& val); + void xfrHexBlob(const string& val, bool keepReading=false); private: string& d_string; }; - +string segmentDNSLabel(const string& input ); #endif diff -Nru pdns-recursor-3.3/rec_channel.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/rec_channel.cc --- pdns-recursor-3.3/rec_channel.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/rec_channel.cc 2012-07-08 18:20:53.000000000 +0000 @@ -11,7 +11,7 @@ #include "ahuexception.hh" -using namespace std; +#include "namespaces.hh" RecursorControlChannel::RecursorControlChannel() { @@ -30,7 +30,8 @@ int RecursorControlChannel::listen(const string& fname) { d_fd=socket(AF_UNIX,SOCK_DGRAM,0); - + Utility::setCloseOnExec(d_fd); + if(d_fd < 0) throw AhuException("Creating UNIX domain socket: "+string(strerror(errno))); @@ -57,7 +58,8 @@ struct sockaddr_un remote; d_fd=socket(AF_UNIX,SOCK_DGRAM,0); - + Utility::setCloseOnExec(d_fd); + if(d_fd < 0) throw AhuException("Creating UNIX domain socket: "+string(strerror(errno))); diff -Nru pdns-recursor-3.3/rec_channel_rec.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/rec_channel_rec.cc --- pdns-recursor-3.3/rec_channel_rec.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/rec_channel_rec.cc 2012-07-08 18:20:53.000000000 +0000 @@ -23,7 +23,7 @@ #include #endif -using namespace std; +#include "namespaces.hh" #include "namespaces.hh" map d_get32bitpointers; map d_get64bitpointers; @@ -298,11 +298,22 @@ return new uint64_t(t_RC->size()); } +uint64_t* pleaseGetCacheBytes() +{ + return new uint64_t(t_RC->bytes()); +} + + uint64_t doGetCacheSize() { return broadcastAccFunction(pleaseGetCacheSize); } +uint64_t doGetCacheBytes() +{ + return broadcastAccFunction(pleaseGetCacheBytes); +} + uint64_t* pleaseGetCacheHits() { return new uint64_t(t_RC->cacheHits); @@ -324,18 +335,28 @@ } - - uint64_t* pleaseGetPacketCacheSize() { return new uint64_t(t_packetCache->size()); } +uint64_t* pleaseGetPacketCacheBytes() +{ + return new uint64_t(t_packetCache->bytes()); +} + + uint64_t doGetPacketCacheSize() { return broadcastAccFunction(pleaseGetPacketCacheSize); } +uint64_t doGetPacketCacheBytes() +{ + return broadcastAccFunction(pleaseGetPacketCacheBytes); +} + + uint64_t* pleaseGetPacketCacheHits() { return new uint64_t(t_packetCache->d_hits); @@ -356,6 +377,13 @@ return broadcastAccFunction(pleaseGetPacketCacheMisses); } +uint64_t doGetMallocated() +{ + // this turned out to be broken +/* struct mallinfo mi = mallinfo(); + return mi.uordblks; */ + return 0; +} RecursorControlParser::RecursorControlParser() { @@ -365,12 +393,14 @@ addGetStat("cache-hits", doGetCacheHits); addGetStat("cache-misses", doGetCacheMisses); addGetStat("cache-entries", doGetCacheSize); + addGetStat("cache-bytes", doGetCacheBytes); addGetStat("packetcache-hits", doGetPacketCacheHits); addGetStat("packetcache-misses", doGetPacketCacheMisses); addGetStat("packetcache-entries", doGetPacketCacheSize); + addGetStat("packetcache-bytes", doGetPacketCacheBytes); - + addGetStat("malloc-bytes", doGetMallocated); addGetStat("servfail-answers", &g_stats.servFails); addGetStat("nxdomain-answers", &g_stats.nxDomains); @@ -400,6 +430,7 @@ addGetStat("over-capacity-drops", &g_stats.overCapacityDrops); addGetStat("no-packet-error", &g_stats.noPacketError); addGetStat("dlg-only-drops", &SyncRes::s_nodelegated); + addGetStat("max-mthread-stack", &g_stats.maxMThreadStackUsage); addGetStat("negcache-entries", boost::bind(getNegCacheSize)); addGetStat("throttle-entries", boost::bind(getThrottleSize)); @@ -455,6 +486,8 @@ static void doExitNicely() { + //extern void printCallers(); + // printCallers(); doExitGeneric(true); } @@ -477,7 +510,7 @@ counts[*i]++; } - typedef multimap rcounts_t; + typedef std::multimap rcounts_t; rcounts_t rcounts; for(counts_t::const_iterator i=counts.begin(); i != counts.end(); ++i) @@ -511,6 +544,26 @@ string cmd=toLower(words[0]); vector::const_iterator begin=words.begin()+1, end=words.end(); + // should probably have a smart dispatcher here, like auth has + if(cmd=="help") + return +"current-queries show currently active queries\n" +"dump-cache dump cache contents to the named file\n" +"dump-edns[status] dump EDNS status to the named file\n" +"get [key1] [key2] .. get specific statistics\n" +"get-all get all statistics\n" +"get-parameter [key1] [key2] .. get configuration parameters\n" +"help get this list\n" +"ping check that all threads are alive\n" +"quit stop the recursor daemon\n" +"quit-nicely stop the recursor daemon nicely\n" +"reload-acls reload ACLS\n" +"reload-lua-script [filename] (re)load Lua script\n" +"reload-zones reload all auth and forward zones\n" +"top-remotes show top remotes\n" +"unload-lua-script unload Lua script\n" +"wipe-cache domain0 [domain1] .. wipe domain data from cache\n"; + if(cmd=="get-all") return getAllStats(); @@ -529,8 +582,7 @@ if(cmd=="quit-nicely") { *command=&doExitNicely; return "bye nicely\n"; - } - + } if(cmd=="dump-cache") return doDumpCache(begin, end); @@ -555,10 +607,16 @@ try { parseACLs(); } - catch(exception& e) + catch(std::exception& e) { + L< -.\" Date: 08/30/2010 -.\" Manual: [FIXME: manual] -.\" Source: [FIXME: source] +.\" Generator: DocBook XSL Stylesheets v1.75.2 +.\" Date: 07/08/2012 +.\" Manual: \ \& +.\" Source: \ \& 3.0 .\" Language: English .\" -.TH "REC_CONTROL" "1" "08/30/2010" "[FIXME: source]" "[FIXME: manual]" +.TH "REC_CONTROL" "1" "07/08/2012" "\ \& 3\&.0" "\ \&" +.\" ----------------------------------------------------------------- +.\" * Define some portability stuff +.\" ----------------------------------------------------------------- +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.\" http://bugs.debian.org/507673 +.\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html +.\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- diff -Nru pdns-recursor-3.3/rec_control.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/rec_control.cc --- pdns-recursor-3.3/rec_control.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/rec_control.cc 2012-07-08 18:20:53.000000000 +0000 @@ -1,6 +1,6 @@ /* PowerDNS Versatile Database Driven Nameserver - Copyright (C) 2006 PowerDNS.COM BV + Copyright (C) 2006 - 2011 PowerDNS.COM 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 @@ -21,7 +21,7 @@ #include "arguments.hh" #include "config.h" -using namespace std; +#include "namespaces.hh" #ifndef RECURSOR #include "statbag.hh" @@ -36,10 +36,10 @@ static void initArguments(int argc, char** argv) { - arg().set("config-dir","Location of configuration directory (pdns.conf)")=SYSCONFDIR; + arg().set("config-dir","Location of configuration directory (recursor.conf)")=SYSCONFDIR; arg().set("socket-dir","Where the controlsocket will live")=LOCALSTATEDIR; - arg().set("socket-pid","When controlling multiple recursors, the target pid")=""; + arg().set("process","When controlling multiple recursors, the target process number")=""; arg().set("timeout", "Number of seconds to wait for the recursor to respond")="5"; arg().setCmd("help","Provide this helpful message"); @@ -49,7 +49,11 @@ cerr< +#include #include "recpacketcache.hh" #include "cachecleaner.hh" #include "dns.hh" @@ -27,9 +28,10 @@ if((uint32_t)now < iter->d_ttd) { // it is fresh! // cerr<<"Fresh for another "<d_ttd - now<<" seconds!"<d_creation; - uint16_t id = ((struct dnsheader*)queryPacket.c_str())->id; + uint16_t id; + memcpy(&id, queryPacket.c_str(), 2); *responsePacket = iter->d_packet; - ((struct dnsheader*)responsePacket->c_str())->id=id; + responsePacket->replace(0, 2, (char*)&id, 2); d_hits++; moveCacheItemToBack(d_packetCache, iter); @@ -62,6 +64,16 @@ return d_packetCache.size(); } +uint64_t RecursorPacketCache::bytes() +{ + uint64_t sum=0; + BOOST_FOREACH(const struct Entry& e, d_packetCache) { + sum += sizeof(e) + e.d_packet.length() + 4; + } + return sum; +} + + void RecursorPacketCache::doPruneTo(unsigned int maxCached) { pruneCollection(d_packetCache, maxCached); diff -Nru pdns-recursor-3.3/recpacketcache.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/recpacketcache.hh --- pdns-recursor-3.3/recpacketcache.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/recpacketcache.hh 2012-07-08 18:20:53.000000000 +0000 @@ -26,6 +26,7 @@ void prune(); uint64_t d_hits, d_misses; uint64_t size(); + uint64_t bytes(); private: diff -Nru pdns-recursor-3.3/recursor_cache.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/recursor_cache.cc --- pdns-recursor-3.3/recursor_cache.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/recursor_cache.cc 2012-07-08 18:20:53.000000000 +0000 @@ -8,7 +8,7 @@ #include "recursor_cache.hh" #include "cachecleaner.hh" -using namespace std; +#include "namespaces.hh" #include "namespaces.hh" #include "config.h" @@ -27,6 +27,7 @@ } else if(rr.qtype.getCode()==QType::AAAA && serial.size()==16) { ComboAddress tmp; + memset(&tmp, 0, sizeof(tmp)); tmp.sin4.sin_family=AF_INET6; memcpy(tmp.sin6.sin6_addr.s6_addr, serial.c_str(), 16); rr.content=tmp.toString(); @@ -95,6 +96,7 @@ unsigned int ret=0; for(cache_t::const_iterator i=d_cache.begin(); i!=d_cache.end(); ++i) { + ret+=sizeof(struct CacheEntry); ret+=(unsigned int)i->d_qname.length(); for(vector::const_iterator j=i->d_records.begin(); j!= i->d_records.end(); ++j) ret+=j->size(); diff -Nru pdns-recursor-3.3/recursor_cache.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/recursor_cache.hh --- pdns-recursor-3.3/recursor_cache.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/recursor_cache.hh 2012-07-08 18:20:53.000000000 +0000 @@ -57,7 +57,7 @@ unsigned int size() const { - return ( unsigned int ) 4+d_string.size(); + return sizeof(*this) + d_string.size(); } }; @@ -75,7 +75,7 @@ if(d_records.size()==1) return d_records.begin()->d_ttd; - uint32_t earliest=numeric_limits::max(); + uint32_t earliest=std::numeric_limits::max(); for(records_t::const_iterator i=d_records.begin(); i != d_records.end(); ++i) earliest=min(earliest, i->d_ttd); return earliest; diff -Nru pdns-recursor-3.3/reczones.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/reczones.cc --- pdns-recursor-3.3/reczones.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/reczones.cc 2012-07-08 18:20:53.000000000 +0000 @@ -389,6 +389,7 @@ L<>4)&0xf); int count=d_size & 0xf; diff -Nru pdns-recursor-3.3/sstuff.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/sstuff.hh --- pdns-recursor-3.3/sstuff.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/sstuff.hh 2012-07-08 18:20:53.000000000 +0000 @@ -19,7 +19,7 @@ #include #include #include -using namespace std; +#include "namespaces.hh" #include "namespaces.hh" @@ -54,6 +54,8 @@ d_family=af; if((d_socket=(int)socket(af,st, pt))<0) throw NetworkError(strerror(errno)); + Utility::setCloseOnExec(d_socket); + d_buflen=4096; d_buffer=new char[d_buflen]; } diff -Nru pdns-recursor-3.3/syncres.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/syncres.cc --- pdns-recursor-3.3/syncres.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/syncres.cc 2012-07-08 18:20:53.000000000 +0000 @@ -1,6 +1,6 @@ /* PowerDNS Versatile Database Driven Nameserver - Copyright (C) 2003 - 2010 PowerDNS.COM BV + Copyright (C) 2003 - 2011 PowerDNS.COM 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 @@ -62,6 +62,8 @@ bool SyncRes::s_noEDNSPing; bool SyncRes::s_noEDNS; +bool SyncRes::s_doAdditionalProcessing; +bool SyncRes::s_doAAAAAdditionalProcessing; SyncRes::SyncRes(const struct timeval& now) : d_outqueries(0), d_tcpoutqueries(0), d_throttledqueries(0), d_timeouts(0), d_unreachables(0), d_now(now), @@ -120,7 +122,7 @@ set beenthere; int res=doResolve(qname, qtype, ret, 0, beenthere); - if(!res) + if(!res && s_doAdditionalProcessing) addCruft(qname, ret); return res; } @@ -174,6 +176,27 @@ return true; } + LOG<first) && chopOffDotted(wcarddomain)) { + LOG<second.d_records.equal_range(make_tuple("*."+wcarddomain)); + if(range.first==range.second) + continue; + + for(ziter=range.first; ziter!=range.second; ++ziter) { + DNSResourceRecord rr=*ziter; + if(rr.qtype == qtype || qtype.getCode() == QType::ANY) { + rr.qname = qname; + rr.d_place=DNSResourceRecord::ANSWER; + ret.push_back(rr); + } + } + LOG<first)) { @@ -205,8 +228,6 @@ return true; } - - void SyncRes::doEDNSDumpAndClose(int fd) { FILE* fp=fdopen(fd, "w"); @@ -407,20 +428,11 @@ set nsset; bool flawedNSSet=false; + + // the two retries allow getBestNSNamesFromCache&co to reprime the root + // hints, in case they ever go missing for(int tries=0;tries<2 && nsset.empty();++tries) { subdomain=getBestNSNamesFromCache(subdomain, nsset, &flawedNSSet, depth, beenthere); // pass beenthere to both occasions - - if(nsset.empty()) { // must've lost root records - set rootset; - /* this additional test is needed since getBestNSNamesFromCache sometimes returns that no - useful NS records were found, even without the root being expired. This might for example - be the case when the . records are not acceptable because they are part of a loop, a loop - caused by the invalidation of an nsset during the resolution algorithm */ - if(t_RC->get(d_now.tv_sec, ".", QType(QType::NS), &rootset) <= 0) { - L< SyncRes::getAs(const string &qname, int depth, set& beenthere) { @@ -534,6 +546,7 @@ } } LOG<nsSpeeds[*tns].submit(*remoteIP, 1000000, &d_now); // 1 sec } if(resolveret==-1) - t_sstorage->throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // unreachable + t_sstorage->throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // unreachable, 1 minute or 100 queries else - t_sstorage->throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 20, 5); // timeout + t_sstorage->throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 10, 5); // timeout } continue; } @@ -914,7 +927,7 @@ break; // this IP address worked! wasLame:; // well, it didn't LOG<toString() <<") is lame for '"<throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); + t_sstorage->throttle.throttle(d_now.tv_sec, make_tuple(*remoteIP, qname, qtype.getCode()), 60, 100); // lame } } @@ -933,7 +946,7 @@ if(lwr.d_rcode==RCode::ServFail) { LOG<throttle.throttle(d_now.tv_sec,make_tuple(*remoteIP, qname, qtype.getCode()),60,3); + t_sstorage->throttle.throttle(d_now.tv_sec,make_tuple(*remoteIP, qname, qtype.getCode()),60,3); // servfail continue; } LOG<toString() <<"), rcode="<second.size() > 1) { // need to group the ttl to be the minimum of the RRSET (RFC 2181, 5.2) - uint32_t lowestTTL=numeric_limits::max(); + uint32_t lowestTTL=std::numeric_limits::max(); for(tcache_t::value_type::second_type::iterator j=i->second.begin(); j != i->second.end(); ++j) lowestTTL=min(lowestTTL, j->ttl); @@ -1010,11 +1023,13 @@ string newauth, soaname, newtarget; for(LWResult::res_t::iterator i=lwr.d_result.begin();i!=lwr.d_result.end();++i) { - if(i->d_place==DNSResourceRecord::AUTHORITY && dottedEndsOn(qname,i->qname) && i->qtype.getCode()==QType::SOA && - lwr.d_rcode==RCode::NXDomain) { - LOG<d_place==DNSResourceRecord::AUTHORITY && i->qtype.getCode()==QType::SOA && + lwr.d_rcode==RCode::NXDomain && dottedEndsOn(qname,i->qname) && dottedEndsOn(i->qname, auth)) { + LOG<ttl = min(i->ttl, s_maxnegttl); - ret.push_back(*i); + if(!newtarget.length()) // only add a SOA if we're not going anywhere after this + ret.push_back(*i); NegCacheEntry ne; @@ -1083,10 +1098,6 @@ LOG< beenthere2; return doResolve(newtarget, qtype, ret, depth + 1, beenthere2); } + if(lwr.d_rcode==RCode::NXDomain) { + LOG< addit; - static optional l_doIPv6AP; - if(!l_doIPv6AP) - l_doIPv6AP=::arg().mustDo("aaaa-additional-processing"); for(vector::const_iterator k=ret.begin();k!=ret.end();++k) if( (k->d_place==DNSResourceRecord::ANSWER && (k->qtype==QType(QType::MX) || k->qtype==QType(QType::SRV))) || @@ -1156,7 +1168,7 @@ host=string(k->content.c_str() + fields[3].first, fields[3].second - fields[3].first); else continue; - doResolve(host, *l_doIPv6AP ? QType(QType::ADDR) : QType(QType::A), addit, 1, beenthere); + doResolve(host, s_doAAAAAdditionalProcessing ? QType(QType::ADDR) : QType(QType::A), addit, 1, beenthere); } if(!addit.empty()) { @@ -1186,3 +1198,16 @@ ret.push_back(ns); } } + +// used by PowerDNSLua +int directResolve(const std::string& qname, const QType& qtype, int qclass, vector& ret) +{ + struct timeval now; + gettimeofday(&now, 0); + + SyncRes sr(now); + + int res = sr.beginResolve(qname, QType(qtype), qclass, ret); + cerr<<"Result: "< i->second.ttd || i->second.count-- < 0) { d_cont.erase(i); + return false; } return true; // still listed, still blocked @@ -206,6 +207,8 @@ static unsigned int s_tcpoutqueries; static unsigned int s_nodelegated; static unsigned int s_unreachables; + static bool s_doAAAAAdditionalProcessing; + static bool s_doAdditionalProcessing; static bool s_doIPv6; unsigned int d_outqueries; unsigned int d_tcpoutqueries; @@ -230,7 +233,7 @@ > > negcache_t; - //! This represents a number of decaying Ewmas, used to store performance per namerserver-name. + //! This represents a number of decaying Ewmas, used to store performance per nameserver-name. /** Modelled to work mostly like the underlying DecayingEwma. After you've called get, d_best is filled out with the best address for this collection */ struct DecayingEwmaCollection @@ -255,7 +258,7 @@ { if(d_collection.empty()) return 0; - double ret=numeric_limits::max(); + double ret=std::numeric_limits::max(); double tmp; for(collection_t::iterator pos=d_collection.begin(); pos != d_collection.end(); ++pos) { if((tmp=pos->second.get(now)) < ret) { @@ -429,7 +432,7 @@ } }; -struct PacketIDBirthdayCompare: public binary_function +struct PacketIDBirthdayCompare: public std::binary_function { bool operator()(const PacketID& a, const PacketID& b) const { @@ -477,6 +480,7 @@ uint64_t packetCacheHits; uint64_t noPacketError; time_t startupTime; + unsigned int maxMThreadStackUsage; }; //! represents a running TCP/IP client session @@ -522,14 +526,6 @@ extern RecursorStats g_stats; extern unsigned int g_numThreads; -template -std::pair -replacing_insert(Index& i,const typename Index::value_type& x) -{ - std::pair res=i.insert(x); - if(!res.second)res.second=i.replace(res.first,x); - return res; -} std::string reloadAuthAndForwards(); @@ -539,6 +535,7 @@ void broadcastFunction(const pipefunc_t& func, bool skipSelf = false); void distributeAsyncFunction(const pipefunc_t& func); +int directResolve(const std::string& qname, const QType& qtype, int qclass, vector& ret); template T broadcastAccFunction(const boost::function& func, bool skipSelf=false); diff -Nru pdns-recursor-3.3/unix_utility.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/unix_utility.cc --- pdns-recursor-3.3/unix_utility.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/unix_utility.cc 2012-07-08 18:20:53.000000000 +0000 @@ -1,6 +1,6 @@ /* PowerDNS Versatile Database Driven Nameserver - Copyright (C) 2002 - 2009 PowerDNS.COM BV + Copyright (C) 2002 - 2011 PowerDNS.COM 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 @@ -35,7 +35,7 @@ #endif -using namespace std; +#include "namespaces.hh" // Closes a socket. int Utility::closesocket( Utility::sock_t socket ) @@ -64,6 +64,14 @@ return true; } +bool Utility::setCloseOnExec(sock_t sock) +{ + int flags=fcntl(sock,F_GETFD,0); + if(flags<0 || fcntl(sock, F_SETFD,flags|FD_CLOEXEC) <0) + return false; + return true; +} + const char *Utility::inet_ntop(int af, const char *src, char *dst, size_t size) { return ::inet_ntop(af,src,dst,size); @@ -91,6 +99,11 @@ else theL()<gr_gid; @@ -155,7 +169,7 @@ if(!(newuid=atoi(username.c_str()))) { struct passwd *pw=getpwnam(username.c_str()); if(!pw) { - theL()<pw_uid; diff -Nru pdns-recursor-3.3/utility.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/utility.hh --- pdns-recursor-3.3/utility.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/utility.hh 2012-07-08 18:20:53.000000000 +0000 @@ -71,7 +71,7 @@ #endif // WIN32 #include -using namespace std; +#include "namespaces.hh" //! A semaphore class. class Semaphore @@ -196,6 +196,9 @@ //! Sets the socket into non-blocking mode. static bool setNonBlocking( Utility::sock_t socket ); + //! Marks the socket to be closed on exec(). + static bool setCloseOnExec ( Utility::sock_t socket ); + //! Sleeps for a number of seconds. static unsigned int sleep( unsigned int seconds ); diff -Nru pdns-recursor-3.3/win32_logger.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/win32_logger.cc --- pdns-recursor-3.3/win32_logger.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/win32_logger.cc 2012-07-08 18:20:53.000000000 +0000 @@ -21,7 +21,7 @@ #include "logger.hh" #include "ntservice.hh" #include "pdnsmsg.hh" -using namespace std; +#include "namespaces.hh" Logger &theL(const string &pname) { diff -Nru pdns-recursor-3.3/win32_mtasker.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/win32_mtasker.cc --- pdns-recursor-3.3/win32_mtasker.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/win32_mtasker.cc 2012-07-08 18:20:53.000000000 +0000 @@ -52,7 +52,7 @@ \section events Events By default, Events are recognized by an int and their value is also an int. - This can be overriden by specifying the EventKey and EventVal template parameters. + This can be overridden by specifying the EventKey and EventVal template parameters. An event can be a keypress, but also a UDP packet, or a bit of data from a TCP socket. The sample code provided works with keypresses, but that is just a not very useful example. @@ -126,7 +126,7 @@ //! puts a thread to sleep waiting until a specified event arrives /** Threads can call waitEvent to register that they are waiting on an event with a certain key. - If so desidered, the event can carry data which is returned in val in case that is non-zero. + If so desired, the event can carry data which is returned in val in case that is non-zero. Furthermore, a timeout can be specified in seconds. diff -Nru pdns-recursor-3.3/win32_rec_channel.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/win32_rec_channel.cc --- pdns-recursor-3.3/win32_rec_channel.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/win32_rec_channel.cc 2012-07-08 18:20:53.000000000 +0000 @@ -6,7 +6,7 @@ #include "ahuexception.hh" -using namespace std; +#include "namespaces.hh" RecursorControlChannel::RecursorControlChannel() { diff -Nru pdns-recursor-3.3/win32_utility.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/win32_utility.cc --- pdns-recursor-3.3/win32_utility.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/win32_utility.cc 2012-07-08 18:20:53.000000000 +0000 @@ -364,6 +364,12 @@ return true; } +// Marks the socket to be closed on exec(). +// No-op on Windows. +bool Utility::setCloseOnExec(sock_t sock) +{ + return true; +} // Sleeps for a number of seconds. unsigned int Utility::sleep( unsigned int seconds ) diff -Nru pdns-recursor-3.3/zoneparser-tng.cc pdns-recursor-3.5.pre.20120708.2673~crass~precise/zoneparser-tng.cc --- pdns-recursor-3.3/zoneparser-tng.cc 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/zoneparser-tng.cc 2012-07-08 18:20:53.000000000 +0000 @@ -371,17 +371,25 @@ case QType::MX: stringtok(recparts, rr.content); if(recparts.size()==2) { - recparts[1] = toCanonic(d_zonename, recparts[1]); + recparts[1] = stripDot(toCanonic(d_zonename, recparts[1])); rr.content=recparts[0]+" "+recparts[1]; } break; + + case QType::SRV: + stringtok(recparts, rr.content); + if(recparts.size()==4) { + recparts[3] = stripDot(toCanonic(d_zonename, recparts[3])); + rr.content=recparts[0]+" "+recparts[1]+" "+recparts[2]+" "+recparts[3]; + } + break; + case QType::NS: case QType::CNAME: case QType::PTR: - case QType::SRV: case QType::AFSDB: - rr.content=toCanonic(d_zonename, rr.content); + rr.content=stripDot(toCanonic(d_zonename, rr.content)); break; case QType::SOA: diff -Nru pdns-recursor-3.3/zoneparser-tng.hh pdns-recursor-3.5.pre.20120708.2673~crass~precise/zoneparser-tng.hh --- pdns-recursor-3.3/zoneparser-tng.hh 2011-01-22 14:45:29.000000000 +0000 +++ pdns-recursor-3.5.pre.20120708.2673~crass~precise/zoneparser-tng.hh 2012-07-08 18:20:53.000000000 +0000 @@ -23,7 +23,7 @@ #include #include -using namespace std; +#include "namespaces.hh" class ZoneParserTNG { @@ -57,7 +57,7 @@ string d_filename; int d_lineno; }; - stack d_filestates; + std::stack d_filestates; }; #endif