]> granicus.if.org Git - pdns/commitdiff
interim commit to get it out of the way
authorBert Hubert <bert.hubert@netherlabs.nl>
Mon, 27 Dec 2010 21:01:55 +0000 (21:01 +0000)
committerBert Hubert <bert.hubert@netherlabs.nl>
Mon, 27 Dec 2010 21:01:55 +0000 (21:01 +0000)
git-svn-id: svn://svn.powerdns.com/pdns/trunk/pdns@1762 d19b8d6e-7fed-0310-83ef-9ca221ded41b

pdns/dnslabel.cc
pdns/dnslabel.hh

index a3ef293d9e3aae55e414c84c271594816eb68fc9..7c5259d2138503940cb07a374eca7ffe2007253c 100644 (file)
@@ -114,6 +114,13 @@ int DNSLabel::validateConsume(const char* raw, unsigned int maxLen)
                if(p > (const unsigned char*)raw + maxLen) // beyond the end
                        return -1;
                        
+               cerr<<(int)*p<<endl;
+               if(*p >= 0xc0 && p + 1 < (const unsigned char*)raw + maxLen) {
+                       unsigned int offset=(*p & ~0xc0) * 0xff + *(p+1);
+                       ++p;
+                       cerr<<"Wants to refer to offset "<<offset<<endl;
+                       return -1;
+               }
                if(*p > 64) // label length too long, or a compression pointer
                        return -1;
                
@@ -143,7 +150,6 @@ string DNSLabel::human() const
                ++p;
                ret.append(p, (int)labelLen);
                
-               
                if(!labelLen)
                        break;
                ret.append(1, '.');
@@ -174,9 +180,25 @@ string DNSLabel::binary() const
        return std::string(getStart(), getLength());
 }
 
-void DNSLabel::expandCapacity()
+static unsigned int roundUpToNextPowerOfTwo(unsigned int x)
 {
-       d_capacity *= 2;
+       x--;
+  x |= x >> 1;  // handle  2 bit numbers
+  x |= x >> 2;  // handle  4 bit numbers
+  x |= x >> 4;  // handle  8 bit numbers
+  x |= x >> 8;  // handle 16 bit numbers
+  x |= x >> 16; // handle 32 bit numbers
+  x++;
+  return x;
+}
+void DNSLabel::expandCapacity(unsigned int len)
+{
+       if(!len)
+               d_capacity *= 2;
+       else {
+               d_capacity = roundUpToNextPowerOfTwo(d_capacity + len);
+       }
        char *newStorage = new char[d_capacity];
        memcpy(newStorage, d_storage, d_fulllen);
        delete[] d_storage;
@@ -192,6 +214,58 @@ DNSLabel DNSLabel::createFromBuffer(const char* raw, unsigned int* len)
        return DNSLabel(raw, result);
 }
 
+void DNSLabel::chaseLabel(const char* raw, const char* beginPacket, unsigned int packetLength, unsigned int* len, bool updateLen)
+{
+       const unsigned char* p = (const unsigned char*) raw;
+
+       for(;;) {
+               if(p > (const unsigned char*)beginPacket + packetLength) // beyond the end
+                       throw std::range_error("label begins beyond end of packet");
+                       
+               if(*p >= 0xc0 && p + 1 < (const unsigned char*)beginPacket + packetLength) {
+                       unsigned int offset=(*p & ~0xc0) * 256 + *(p+1);
+                       if(offset < 12)
+                               throw std::range_error("compression pointer to before beginning of content");
+                       offset -= 12;
+                       cerr<<"new offset: "<<offset<<endl;
+                       if((const unsigned char*)beginPacket + offset >= p) {
+                               throw std::runtime_error("looping or forward compression pointer");
+                       }
+                               
+                       p+=2;
+                       if(updateLen) {
+                               *len = (p - (const unsigned char*)raw);
+                       }
+                       
+                       chaseLabel(beginPacket + offset, beginPacket, packetLength, len, false);
+                       return;
+               }
+               if(*p > 64) // label length too long, or a compression pointer
+                       throw std::range_error("label too long");
+               
+               if(!*p) { // final label, setbytes consumed
+                       appendChar(0);
+                       if(updateLen)
+                               *len = 1 + (p - (const unsigned char*)raw);
+                       return;
+               }
+               appendChar(*p);
+               appendRange((const char*)p+1, *p);
+               p += *p + 1;
+       }
+        // we should not get here, but if we do, it's bad
+}
+
+DNSLabel::DNSLabel(const char* raw, const char* beginPacket, unsigned int packetLength, unsigned int* len)
+{
+       init();
+       if(!*len) {
+               throw std::range_error("void label"); // shortest ok label is: '\x00'
+       }
+
+       chaseLabel(raw, beginPacket, packetLength, len, true);
+}
+
 #if 0
 void endsOn(const DNSLabel& first, const DNSLabel& second)
 {
index 06c73e196bcc542019d841a98989d05fc95ea946..7300f517eed8d62b947b0c652bec12ee3dd16276 100644 (file)
@@ -51,6 +51,7 @@ class DNSLabel
                explicit DNSLabel(const std::string& human);
                DNSLabel(const char* raw, unsigned int length);
                DNSLabel(const DNSLabel& rhs);
+               DNSLabel(const char* raw, const char* beginPacket, unsigned int packetLength, unsigned int* len);
                DNSLabel();
                ~DNSLabel();
                string human() const;
@@ -87,5 +88,14 @@ class DNSLabel
                                expandCapacity();
                        d_storage[d_fulllen++]= c;
                }
-               void expandCapacity();
+               void appendRange(const char* ptr, unsigned int len)
+               {
+                       if(d_fulllen + len > d_capacity)
+                               expandCapacity(len);
+                       memcpy(d_storage + d_fulllen, ptr, len);
+                       d_fulllen += len;
+               }
+
+               void expandCapacity(unsigned int len=0);
+               void chaseLabel(const char* raw, const char* beginPacket, unsigned int packetLength, unsigned int* len, bool updateLen);
 };