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;
}
|