File: dns.cc

package info (click to toggle)
pdns-recursor 3.2-4
  • links: PTS
  • area: main
  • in suites: squeeze
  • size: 1,088 kB
  • ctags: 2,390
  • sloc: cpp: 12,551; ansic: 2,587; sh: 510; makefile: 133
file content (119 lines) | stat: -rw-r--r-- 3,427 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include "dns.hh"
#include "misc.hh"
#include <stdexcept>
#include <iostream>
#include <boost/algorithm/string.hpp>

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] == '\\')
      break;
  
  if( n == labellen) {
    ret.append(begin, labellen);
    return;
  }
  string label(begin, labellen);
  boost::replace_all(label, "\\",  "\\\\");
  boost::replace_all(label, ".",  "\\.");
  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");
  }
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) 
    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<<endl;
    
    int result=0;
    unsigned int n;
    for(n = 0; n < aLabelLen && n < bLabelLen; ++n) 
      if((result = aSafe[aPos + n] - bSafe[bPos +n]))
        break;
    // cerr<<"Done loop, result="<<result<<", n = "<<n<<", aLabelLen="<<aLabelLen<<", bLabelLen="<<bLabelLen<<endl;
    if(result < 0)
      return true;
    if(result > 0)
      return false;
    if(n == aLabelLen && n != bLabelLen)
      return true; // a is shorter, shortest wins
    if(n != aLabelLen && n == bLabelLen)
      return false; // a is longer
    //~ cerr<<"did not return\n";
    aPos += aLabelLen; bPos += bLabelLen;
  } while(aLabelLen && bLabelLen);
  
  if(aLabelLen || bLabelLen) //
    throw runtime_error("Error in label comparison routing, should not happen");
      
  uint16_t aQtype = aSafe[aPos]*256 + aSafe[aPos + 1];
  uint16_t bQtype = bSafe[bPos]*256 + bSafe[bPos + 1];
  return aQtype < bQtype;
}


string questionExpand(const char* packet, uint16_t len, uint16_t& type)
{
  type=0;
  string ret;
  if(len < 12) 
    throw runtime_error("Error parsing question in incoming packet: packet too short");
    
  const unsigned char* end = (const unsigned char*)packet+len;
  const unsigned char* pos = (const unsigned char*)packet+12;
  unsigned char labellen;
  
  if(!*pos)
    ret.assign(1, '.');
  
  while((labellen=*pos++) && pos < end) { // "scan and copy"
    if(pos + labellen > 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: '"<<ret<<"'"<<endl;
  return ret;
}