Browse Source

Imported Upstream version 3.5.2

tags/upstream/4.3.0
Matthijs Möhlmann 7 years ago
parent
commit
a5cf5214fe
91 changed files with 5634 additions and 1086 deletions
  1. +21
    -22
      COPYING
  2. +5
    -4
      Makefile
  3. +0
    -5
      README
  4. +16
    -6
      aeskey.c
  5. +1
    -1
      ahuexception.hh
  6. +1
    -0
      arguments.cc
  7. +2
    -2
      arguments.hh
  8. +16
    -9
      base32.cc
  9. +3
    -2
      base64.cc
  10. +4
    -4
      cachecleaner.hh
  11. +1
    -1
      config.h
  12. +11
    -0
      contrib/systemd-pdns-recursor.service
  13. +1
    -1
      devpollmplexer.cc
  14. +73
    -2
      dns.cc
  15. +47
    -13
      dns.hh
  16. +6
    -0
      dns_random.cc
  17. +475
    -0
      dnslabeltext.cc
  18. +45
    -23
      dnsparser.cc
  19. +30
    -19
      dnsparser.hh
  20. +47
    -54
      dnsrecords.cc
  21. +24
    -5
      dnsrecords.hh
  22. +28
    -31
      dnswriter.cc
  23. +14
    -4
      dnswriter.hh
  24. +1
    -1
      epollmplexer.cc
  25. +821
    -0
      ext/rapidjson/include/rapidjson/document.h
  26. +46
    -0
      ext/rapidjson/include/rapidjson/filestream.h
  27. +54
    -0
      ext/rapidjson/include/rapidjson/internal/pow10.h
  28. +82
    -0
      ext/rapidjson/include/rapidjson/internal/stack.h
  29. +24
    -0
      ext/rapidjson/include/rapidjson/internal/strfunc.h
  30. +156
    -0
      ext/rapidjson/include/rapidjson/prettywriter.h
  31. +525
    -0
      ext/rapidjson/include/rapidjson/rapidjson.h
  32. +683
    -0
      ext/rapidjson/include/rapidjson/reader.h
  33. +49
    -0
      ext/rapidjson/include/rapidjson/stringbuffer.h
  34. +241
    -0
      ext/rapidjson/include/rapidjson/writer.h
  35. +47
    -15
      iputils.hh
  36. +119
    -0
      json.cc
  37. +26
    -0
      json.hh
  38. +163
    -0
      json_ws.cc
  39. +33
    -0
      json_ws.hh
  40. +1
    -1
      kqueuemplexer.cc
  41. +9
    -1
      logger.cc
  42. +3
    -2
      logger.hh
  43. +128
    -130
      lua-pdns.cc
  44. +6
    -6
      lua-pdns.hh
  45. +173
    -0
      lua-recursor.cc
  46. +21
    -0
      lua-recursor.hh
  47. +1
    -1
      lwres.cc
  48. +1
    -1
      lwres.hh
  49. +118
    -32
      misc.cc
  50. +68
    -29
      misc.hh
  51. +19
    -9
      mtasker.cc
  52. +9
    -2
      mtasker.hh
  53. +30
    -0
      namespaces.hh
  54. +85
    -50
      nsecrecords.cc
  55. +8
    -0
      pdns-recursor.init.d
  56. +1
    -1
      pdns_hw.cc
  57. +14
    -5
      pdns_recursor.1
  58. +205
    -105
      pdns_recursor.cc
  59. +1
    -1
      portsmplexer.cc
  60. +66
    -0
      powerdns-example-script.lua
  61. +16
    -151
      qtype.cc
  62. +65
    -16
      qtype.hh
  63. +37
    -31
      rcpgenerator.cc
  64. +4
    -4
      rcpgenerator.hh
  65. +5
    -3
      rec_channel.cc
  66. +1
    -0
      rec_channel.hh
  67. +125
    -19
      rec_channel_rec.cc
  68. +14
    -5
      rec_control.1
  69. +14
    -8
      rec_control.cc
  70. +36
    -2
      recpacketcache.cc
  71. +2
    -0
      recpacketcache.hh
  72. +59
    -13
      recursor_cache.cc
  73. +5
    -4
      recursor_cache.hh
  74. +12
    -3
      reczones.cc
  75. +1
    -1
      selectmplexer.cc
  76. +1
    -1
      sillyrecords.cc
  77. +3
    -1
      sstuff.hh
  78. +213
    -179
      syncres.cc
  79. +52
    -28
      syncres.hh
  80. +1
    -1
      sysdeps/Darwin.inc
  81. +1
    -1
      sysdeps/FreeBSD.inc
  82. +1
    -1
      sysdeps/Linux.inc
  83. +4
    -0
      sysdeps/SunOS.inc
  84. +18
    -4
      unix_utility.cc
  85. +4
    -1
      utility.hh
  86. +1
    -1
      win32_logger.cc
  87. +2
    -2
      win32_mtasker.cc
  88. +1
    -1
      win32_rec_channel.cc
  89. +6
    -0
      win32_utility.cc
  90. +20
    -3
      zoneparser-tng.cc
  91. +2
    -2
      zoneparser-tng.hh

+ 21
- 22
COPYING View File

@@ -1,12 +1,12 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
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
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Preamble
Preamble

The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
@@ -15,7 +15,7 @@ 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
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.

When we speak of free software, we are referring to freedom, not
@@ -55,8 +55,8 @@ 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
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License applies to any program or other work which contains
@@ -110,7 +110,7 @@ above, provided that you also meet all of these conditions:
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
@@ -168,7 +168,7 @@ 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
@@ -225,7 +225,7 @@ 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
@@ -255,7 +255,7 @@ 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
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
@@ -277,9 +277,9 @@ 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
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
@@ -303,17 +303,16 @@ the "copyright" line and a pointer to where the full notice is found.
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

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 Street, Fifth Floor, Boston, MA 02110-1301 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 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.
@@ -336,5 +335,5 @@ necessary. Here is a sample; alter the names:
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.
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

+ 5
- 4
Makefile View File

@@ -3,7 +3,7 @@ SBINDIR=/usr/sbin/
BINDIR=/usr/bin/
CONFIGDIR="/etc/powerdns/"
OPTFLAGS?=-O3
CXXFLAGS:= $(CXXFLAGS) -Wall $(OPTFLAGS) $(PROFILEFLAGS) $(ARCHFLAGS) -pthread
CXXFLAGS:= $(CXXFLAGS) -Iext/rapidjson/include -Wall $(OPTFLAGS) $(PROFILEFLAGS) $(ARCHFLAGS) -pthread
CFLAGS:=$(CFLAGS) -Wall $(OPTFLAGS) $(PROFILEFLAGS) $(ARCHFLAGS) -pthread
LDFLAGS:=$(LDFLAGS) $(ARCHFLAGS) -pthread

@@ -18,8 +18,9 @@ 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 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 json.o json_ws.o

REC_CONTROL_OBJECTS=rec_channel.o rec_control.o arguments.o misc.o \
unix_utility.o logger.o qtype.o
@@ -32,7 +33,7 @@ all: message pdns_recursor rec_control

ifeq ($(LUA), 1)
LUALIBS=$(LUA_LIBS_CONFIG)
CXXFLAGS+=$(LUA_CPPFLAGS_CONFIG) -DPDNS_ENABLE_LUA
CXXFLAGS+=$(LUA_CPPFLAGS_CONFIG) -DPDNS_ENABLE_LUA -DHAVE_LUA
endif




+ 0
- 5
README View File

@@ -87,8 +87,3 @@ 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

+ 16
- 6
aeskey.c View File

@@ -406,8 +406,10 @@ AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1])
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));
ss[4] = word_in(key, 4);
cx->ks[v(48,(4))] = ff(ss[4]);
ss[5] = word_in(key, 5);
cx->ks[v(48,(5))] = ff(ss[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);
@@ -486,6 +488,7 @@ AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1])
ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \
}
#if 0
AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1])
{ uint_32t ss[9];
#if defined( d_vars )
@@ -497,10 +500,14 @@ AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1])
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));
ss[4] = word_in(key, 4);
cx->ks[v(56,(4))] = ff(ss[4]);
ss[4] = word_in(key, 5);
cx->ks[v(56,(5))] = ff(ss[5]);
ss[4] = word_in(key, 6);
cx->ks[v(56,(6))] = ff(ss[6]);
ss[4] = word_in(key, 7);
cx->ks[v(56,(7))] = ff(ss[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);
@@ -530,11 +537,13 @@ AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1])
#endif
return EXIT_SUCCESS;
}
#endif
#endif
#if defined( AES_VAR )
#if 0
AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1])
{
switch(key_len)
@@ -545,6 +554,7 @@ AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ct
default: return EXIT_FAILURE;
}
}
#endif
#endif


+ 1
- 1
ahuexception.hh View File

@@ -22,7 +22,7 @@

#include<string>

using namespace std;
#include "namespaces.hh"

//! Generic Exception thrown
class AhuException


+ 1
- 0
arguments.cc View File

@@ -327,6 +327,7 @@ const vector<string>&ArgvMap::getCommands()

void ArgvMap::parse(int &argc, char **argv, bool lax)
{
d_cmds.clear();
for(int n=1;n<argc;n++) {
parseOne(argv[n],"",lax);
}


+ 2
- 2
arguments.hh View File

@@ -32,7 +32,7 @@
# include <grp.h>
#endif

using namespace std;
#include "namespaces.hh"

typedef AhuException ArgException;

@@ -94,7 +94,7 @@ public:
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); //<!< return value interprepted as octal number
mode_t asMode(const string &var); //<!< return value interpreted as octal number
uid_t asUid(const string &var); //!< return user id, resolves if necessary
gid_t asGid(const string &var); //!< return group id, resolves if necessary
#endif


+ 16
- 9
base32.cc View File

@@ -5,19 +5,26 @@
#include <stdlib.h>
#include <iostream>
#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)
/* NOTE: length should not exceed 8; all callers inside PowerDNS only pass length=5 though */
unsigned char extract_bits(const char *s, int start, int length)
{
uint32_t x;
unsigned char cl, cc, cr;
uint16_t x;
unsigned char cl, cc;

if(!length)
return 0;

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)));
if(start / 8 < (start + length-1)/8)
cc = s[start / 8 + 1];
else
cc = 0;

x = (uint16_t) (cl << 8 | cc);
x = x >> (16 - (length + (start % 8)));
x = (x & (0xffff >> (16 - length)));
return (x);
}
@@ -112,7 +119,7 @@ string fromBase32Hex(const std::string& input)
toWrite = 0;
}
}
ret.append(block, (7+toWrite*5)/8); // round up
ret.append(block, (toWrite*5)/8);

return ret;
}


+ 3
- 2
base64.cc View File

@@ -109,7 +109,7 @@ int B64Decode(const std::string& strInput, std::string& strOutput)
// 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 @@ int B64Decode(const std::string& strInput, std::string& strOutput)
// Decode a character
if(strInput.at(iInNum)=='=')
pad++;

while(isspace(strInput.at(iInNum)))
iInNum++;
cChar = B64Decode1(strInput.at(iInNum++));

} // if


+ 4
- 4
cachecleaner.hh View File

@@ -11,14 +11,14 @@ template <typename T> void pruneCollection(T& collection, unsigned int maxCached
unsigned int cacheSize=collection.size();

if(maxCached && cacheSize > maxCached) {
if(cacheSize > maxCached) {
toTrim = cacheSize - maxCached;
}

// cout<<"Need to trim "<<toTrim<<" from cache to meet target!\n";

typedef typename T::template nth_index<1>::type sequence_t;
sequence_t& sidx=collection.get<1>();
sequence_t& sidx=collection.template get<1>();

unsigned int tried=0, lookAt, erased=0;

@@ -62,8 +62,8 @@ template <typename T> void pruneCollection(T& collection, unsigned int maxCached
template <typename T> 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);
sequence_t& sidx=collection.template get<1>();
typename sequence_t::iterator si=collection.template project<1>(iter);
if(front)
sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue
else


+ 1
- 1
config.h View File

@@ -1,4 +1,4 @@
#define SYSCONFDIR "/etc/powerdns/"
#define LOCALSTATEDIR "/var/run/"
#define VERSION "3.3"
#define VERSION "3.5.2"
#define RECURSOR

+ 11
- 0
contrib/systemd-pdns-recursor.service View File

@@ -0,0 +1,11 @@
[Unit]
Description=PowerDNS recursing nameserver
After=network.target

[Service]
Type=forking
ExecStart=/usr/sbin/pdns_recursor --daemon
PrivateTmp=true

[Install]
WantedBy=multi-user.target

+ 1
- 1
devpollmplexer.cc View File

@@ -8,7 +8,7 @@
#include "syncres.hh"

#include "namespaces.hh"
using namespace std;
#include "namespaces.hh"

class DevPollFDMultiplexer : public FDMultiplexer
{


+ 73
- 2
dns.cc View File

@@ -1,5 +1,6 @@
#include "dns.hh"
#include "misc.hh"
#include "arguments.hh"
#include <stdexcept>
#include <iostream>
#include <boost/algorithm/string.hpp>
@@ -9,7 +10,7 @@ static void appendEscapedLabel(string& ret, const char* begin, unsigned char lab
{
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 @@ static void appendEscapedLabel(string& ret, const char* begin, unsigned char lab
string label(begin, labellen);
boost::replace_all(label, "\\", "\\\\");
boost::replace_all(label, ".", "\\.");
boost::replace_all(label, " ", "\\032");
ret.append(label);
}

@@ -48,7 +50,7 @@ private:
//! 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,72 @@ string questionExpand(const char* packet, uint16_t len, uint16_t& type)
// cerr << "returning: '"<<ret<<"'"<<endl;
return ret;
}

void fillSOAData(const string &content, SOAData &data)
{
// content consists of fields separated by spaces:
// nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]

// fill out data with some plausible defaults:
// 10800 3600 604800 3600
vector<string>parts;
stringtok(parts,content);
int pleft=parts.size();

// cout<<"'"<<content<<"'"<<endl;

if(pleft)
data.nameserver=parts[0];

if(pleft>1)
data.hostmaster=attodot(parts[1]); // ahu@ds9a.nl -> ahu.ds9a.nl, piet.puk@ds9a.nl -> piet\.puk.ds9a.nl

data.serial = pleft > 2 ? strtoul(parts[2].c_str(), NULL, 10) : 0;

data.refresh = pleft > 3 ? atoi(parts[3].c_str())
: ::arg().asNum("soa-refresh-default");

data.retry = pleft > 4 ? atoi(parts[4].c_str())
: ::arg().asNum("soa-retry-default");

data.expire = pleft > 5 ? atoi(parts[5].c_str())
: ::arg().asNum("soa-expire-default");

data.default_ttl = pleft > 6 ?atoi(parts[6].c_str())
: ::arg().asNum("soa-minimum-ttl");
}

string serializeSOAData(const SOAData &d)
{
ostringstream o;
// nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
o<<d.nameserver<<" "<< d.hostmaster <<" "<< d.serial <<" "<< d.refresh << " "<< d.retry << " "<< d.expire << " "<< d.default_ttl;

return o.str();
}
// the functions below update the 'arcount' and 'ancount', plus they serialize themselves to the stringbuffer

string& attodot(string &str)
{
if(str.find_first_of("@")==string::npos)
return str;

for (unsigned int i = 0; i < str.length(); i++)
{
if (str[i] == '@') {
str[i] = '.';
break;
} else if (str[i] == '.') {
str.insert(i++, "\\");
}
}
return str;
}

string strrcode(unsigned char rcode)
{
static const char* rcodes[]={"No Error", "FormErr", "SERVFAIL", "NXDOMAIN", "NotImp", "Refused", "", "", "", "Not Auth"};
if((rcode < sizeof(rcodes) / sizeof(*rcodes)) && *rcodes[rcode])
return rcodes[rcode];
return "Err#"+lexical_cast<string>((int)rcode);
}

+ 47
- 13
dns.hh View File

@@ -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$
/* (C) 2002 POWERDNS.COM BV */
#ifndef DNS_HH
#define DNS_HH
@@ -25,6 +25,10 @@
#include <boost/tuple/tuple_comparison.hpp>
#include <boost/multi_index/key_extractors.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/serialization/string.hpp>
#include <boost/serialization/version.hpp>


#include "utility.hh"
#include "qtype.hh"
#include <time.h>
@@ -33,6 +37,8 @@ class DNSBackend;

struct SOAData
{
SOAData() : scopeMask(0) {};

string qname;
string nameserver;
string hostmaster;
@@ -44,13 +50,14 @@ struct SOAData
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 +70,9 @@ public:
class DNSResourceRecord
{
public:
DNSResourceRecord() : qclass(1), priority(0), d_place(ANSWER) {};
DNSResourceRecord() : qclass(1), priority(0), signttl(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,14 +80,32 @@ public:
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
uint32_t signttl; //!< If non-zero, use this TTL as original TTL in the RRSIG
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<class Archive>
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 +115,6 @@ public:
return(content < b.content);
return false;
}

private:
string escape(const string &str) const;
};

#ifdef _MSC_VER
@@ -163,8 +182,15 @@ enum {
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 +202,7 @@ enum {
#ifdef WIN32
#define BYTE_ORDER 1
#define LITTLE_ENDIAN 1
#elif __FreeBSD__ || __APPLE__
#elif __FreeBSD__ || __APPLE__ || __OpenBSD__
#include <machine/endian.h>
#elif __linux__
# include <endian.h>
@@ -253,4 +279,12 @@ struct dnsheader {
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

+ 6
- 0
dns_random.cc View File

@@ -13,6 +13,8 @@ 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();
@@ -24,6 +26,8 @@ void dns_random_init(const char data[16])
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<uint32_t>::max()));
}

@@ -50,6 +54,8 @@ static void counterIncrement(unsigned char* counter)

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;


+ 475
- 0
dnslabeltext.cc View File

@@ -0,0 +1,475 @@

#line 1 "dnslabeltext.rl"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>
#include <string>
#include "namespaces.hh"


namespace {
void appendSplit(vector<string>& ret, string& segment, char c)
{
if(segment.size()>254) {
ret.push_back(segment);
segment.clear();
}
segment.append(1, c);
}
}

vector<string> 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, 9, 11, 13, 19,
23
};

static const char _dnstext_trans_keys[] = {
34, 34, 92, 9, 10, 32, 126, 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, 0, 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, 9, 11, 13, 18,
22
};

static const char _dnstext_trans_targs[] = {
2, 0, 7, 3, 2, 2, 0, 4,
2, 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, 7,
5, 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<string> 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<string> res=dnstext(blah);
cerr<<res.size()<<" segments"<<endl;
cerr<<res[0]<<endl;
}
#endif

+ 45
- 23
dnsparser.cc View File

@@ -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
@@ -20,6 +20,7 @@
#include "dnswriter.hh"
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>

#include "namespaces.hh"

@@ -100,8 +101,6 @@ static const string EncodeDNSLabel(const string& input)
}
}
ret.append(1, 0);
// cerr<<"Asked to encode '"<<input<<"', returning: '"<<makeHexDump(ret)<<endl;
// cerr<<"parts length: "<<parts.size()<<endl;
return ret;
}

@@ -171,27 +170,31 @@ DNSRecordContent* DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass,
return i->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 +267,7 @@ void MOADNSParser::init(const char *packet, unsigned int len)
}
#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 +320,7 @@ void PacketReader::copyRecord(vector<unsigned char>& dest, uint16_t len)
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;
@@ -386,14 +389,23 @@ string PacketReader::getLabel(unsigned int recurs)
static string txtEscape(const string &name)
{
string ret;
char ebuf[5];

for(string::const_iterator i=name.begin();i!=name.end();++i)
if(*i=='"' || *i=='\\'){
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((unsigned char) *i > 127) {
snprintf(ebuf, sizeof(ebuf), "\\%03u", (unsigned char)*i);
ret += ebuf;
}
else if(*i=='"' || *i=='\\'){
ret += '\\';
ret += *i;
}
else
ret += *i;
}
return ret;
}

@@ -425,7 +437,7 @@ string PacketReader::getText(bool multi)

void PacketReader::getLabelFromContent(const vector<uint8_t>& content, uint16_t& frompos, string& ret, int recurs)
{
if(recurs > 10)
if(recurs > 1000) // the forward reference-check below should make this test 100% obsolete
throw MOADNSException("Loop");

for(;;) {
@@ -439,15 +451,24 @@ void PacketReader::getLabelFromContent(const vector<uint8_t>& content, uint16_t&
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: "<<offset<<endl;

if(offset >= frompos-2)
throw MOADNSException("forward reference during label decompression");
return getLabelFromContent(content, offset, ret, ++recurs);
}
else {
// 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 +477,7 @@ void PacketReader::getLabelFromContent(const vector<uint8_t>& content, uint16_t&

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 +497,7 @@ void PacketReader::xfrBlob(string& blob, int length)
}


void PacketReader::xfrHexBlob(string& blob)
void PacketReader::xfrHexBlob(string& blob, bool keepReading)
{
xfrBlob(blob);
}
@@ -574,7 +595,7 @@ private:
{
d_notyouroffset += by;
if(d_notyouroffset > d_packet.length())
throw range_error("dns packet out of range: "+lexical_cast<string>(d_notyouroffset) +" > "
throw std::out_of_range("dns packet out of range: "+lexical_cast<string>(d_notyouroffset) +" > "
+ lexical_cast<string>(d_packet.length()) );
}
std::string& d_packet;
@@ -587,16 +608,17 @@ private:
// 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
}


+ 30
- 19
dnsparser.hh View File

@@ -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 @@ class PacketReader
{
public:
PacketReader(const vector<uint8_t>& 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 @@ public:

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<unsigned char>&content, uint16_t& pos);
static void getLabelFromContent(const vector<uint8_t>& content, uint16_t& frompos, string& ret, int recurs);
@@ -135,7 +137,7 @@ public:

private:
uint16_t d_startrecordpos; // needed for getBlob later on
uint16_t d_recordlen; // dito
uint16_t d_recordlen; // ditto
const vector<uint8_t>& d_content;
};

@@ -150,7 +152,7 @@ public:
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<uint8_t> packet;
string empty;
@@ -158,6 +160,9 @@ public:
if(canonic)
pw.setCanonic(true);

if(lowerCase)
pw.setLowercase(true);

pw.startRecord(qname, d_qtype);
this->toPacket(pw);
pw.commit();
@@ -184,7 +189,8 @@ public:
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 @@ public:

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<string>(num);
t2namemap_t::const_iterator iter = getT2Namemap().find(make_pair(classnum, num));
if(iter == getT2Namemap().end())
return "TYPE" + lexical_cast<string>(num);
// throw runtime_error("Unknown DNS type with numerical id "+lexical_cast<string>(num));
return getNamemap()[make_pair(classnum,num)];
return iter->second;
}

explicit DNSRecordContent(uint16_t type) : d_qtype(type)
@@ -229,10 +239,11 @@ public:
protected:
typedef std::map<std::pair<uint16_t, uint16_t>, makerfunc_t* > typemap_t;
typedef std::map<std::pair<uint16_t, uint16_t>, zmakerfunc_t* > zmakermap_t;
typedef std::map<std::pair<uint16_t, uint16_t>, string > namemap_t;
typedef std::map<std::pair<uint16_t, uint16_t>, string > t2namemap_t;
typedef std::map<string, std::pair<uint16_t, uint16_t> > 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 @@ public:
dnsheader d_header;
string d_qname;
uint16_t d_qclass, d_qtype;
uint8_t d_rcode;
//uint8_t d_rcode;

typedef vector<pair<DNSRecord, uint16_t > > answers_t;


+ 47
- 54
dnsrecords.cc View File

@@ -18,6 +18,7 @@

#include "utility.hh"
#include "dnsrecords.hh"
#include <boost/foreach.hpp>

boilerplate_conv(A, ns_t_a, conv.xfrIP(d_ip));

@@ -61,7 +62,7 @@ public:
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 @@ void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options)
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 @@ boilerplate_conv(CERT, 37,
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 @@ 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);
@@ -274,35 +291,6 @@ uint16_t DNSKEYRecordContent::getTag()
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 @@ 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() &&
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<OPTRecordContent*>(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<OPTRecordContent*>(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 @@ void reportOtherTypes()
NSECRecordContent::report();
NSEC3RecordContent::report();
NSEC3PARAMRecordContent::report();
TLSARecordContent::report();
DLVRecordContent::report();
DNSRecordContent::regist(0xff, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG");
OPTRecordContent::report();
}


+ 24
- 5
dnsrecords.hh View File

@@ -26,7 +26,7 @@
#include <set>
#include <bitset>

using namespace std;
#include "namespaces.hh"
#include "namespaces.hh"

#define includeboilerplate(RNAME) RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr); \
@@ -231,15 +231,11 @@ public:
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 @@ public:
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 @@ private:
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:


+ 28
- 31
dnswriter.cc View File

@@ -1,12 +1,11 @@
#include "dnswriter.hh"
#include "misc.hh"
#include "dnsparser.hh"
#include <boost/tokenizer.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/foreach.hpp>
#include <limits.h>

DNSPacketWriter::DNSPacketWriter(vector<uint8_t>& 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::addOpt(int udpsize, int extRCode, int Z, const vector<pair
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 @@ 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)
{
using boost::escaped_list_separator;
using boost::tokenizer;

escaped_list_separator<char> sep('\\', ' ' , '"');
tokenizer<escaped_list_separator<char> > tok(text, sep);

tokenizer<escaped_list_separator<char> >::iterator beg=tok.begin();

if(beg==tok.end()) {
if(text.empty()) {
d_record.push_back(0);
return;
}
vector<string> 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 @@ bool labeltokUnescape(labelparts_t& parts, const string& label)
}

// 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 @@ void DNSPacketWriter::xfrLabel(const string& label, bool compress)
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 @@ void DNSPacketWriter::xfrLabel(const string& label, bool compress)
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");
@@ -254,7 +250,10 @@ void DNSPacketWriter::xfrLabel(const string& label, bool compress)
pos+=(part.size())+1;
}
else {
d_record.push_back((char)(i->second - i->first));
char labelsize=(char)(i->second - i->first);
if(!labelsize) // empty label in the middle of name
throw MOADNSException("DNSPacketWriter::xfrLabel() found empty label in the middle of name");
d_record.push_back(labelsize);
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);
@@ -269,22 +268,20 @@ void DNSPacketWriter::xfrLabel(const string& label, bool compress)
void DNSPacketWriter::xfrBlob(const string& blob, int )
{
const uint8_t* ptr=reinterpret_cast<const uint8_t*>(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();
}


+ 14
- 4
dnswriter.hh View File

@@ -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 @@ public:
*/
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 @@ public:
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 @@ public:
d_canonic=val;
}

void setLowercase(bool val)
{
d_lowerCase=val;
}
vector <uint8_t>& getContent()
{
return d_content;
}

private:
vector <uint8_t>& d_content;
vector <uint8_t> d_record;
@@ -113,9 +122,10 @@ private:
uint16_t d_sor;
uint16_t d_rollbackmarker; // start of last complete packet, for rollback
Place d_recordplace;
bool d_canonic;