]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Bug #1136: Internal DNS sometimes truncates host names in reverse (PTR)
authorserassio <>
Sun, 23 Jan 2005 21:59:06 +0000 (21:59 +0000)
committerserassio <>
Sun, 23 Jan 2005 21:59:06 +0000 (21:59 +0000)
lookups

Compressed hostnames was not dealt with proper, only saving the data of
the initial string + 2 bytes.

lib/rfc1035.c

index 05db4762fab7f968f91510d0149da2b72de4c08b..44180b9dafcddef809b482d2d0d98502f756dd09 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: rfc1035.c,v 1.34 2005/01/23 14:55:45 serassio Exp $
+ * $Id: rfc1035.c,v 1.35 2005/01/23 14:59:06 serassio Exp $
  *
  * Low level DNS protocol routines
  * AUTHOR: Duane Wessels
@@ -299,7 +299,7 @@ rfc1035HeaderUnpack(const char *buf, size_t sz, off_t * off, rfc1035_header * h)
  * Returns 0 (success) or 1 (error)
  */
 static int
-rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns, int rdepth)
+rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, unsigned short *rdlength, char *name, size_t ns, int rdepth)
 {
     off_t no = 0;
     unsigned char c;
@@ -324,7 +324,7 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
            /* Make sure the pointer is inside this message */
            if (ptr >= sz)
                return 1;
-           return rfc1035NameUnpack(buf, sz, &ptr, name + no, ns - no, rdepth + 1);
+           return rfc1035NameUnpack(buf, sz, &ptr, rdlength, name + no, ns - no, rdepth + 1);
        } else if (c > RFC1035_MAXLABELSZ) {
            /*
             * "(The 10 and 01 combinations are reserved for future use.)"
@@ -343,6 +343,8 @@ rfc1035NameUnpack(const char *buf, size_t sz, off_t * off, char *name, size_t ns
            (*off) += len;
            no += len;
            *(name + (no++)) = '.';
+           if (rdlength)
+               *rdlength += len + 1;
        }
     } while (c > 0 && no < ns);
     if (no)
@@ -369,8 +371,9 @@ rfc1035RRUnpack(const char *buf, size_t sz, off_t * off, rfc1035_rr * RR)
 {
     unsigned short s;
     unsigned int i;
+    unsigned short rdlength;
     off_t rdata_off;
-    if (rfc1035NameUnpack(buf, sz, off, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) {
+    if (rfc1035NameUnpack(buf, sz, off, NULL, RR->name, RFC1035_MAXHOSTNAMESZ, 0)) {
        RFC1035_UNPACK_DEBUG;
        memset(RR, '\0', sizeof(*RR));
        return 1;
@@ -395,7 +398,8 @@ rfc1035RRUnpack(const char *buf, size_t sz, off_t * off, rfc1035_rr * RR)
     RR->ttl = ntohl(i);
     memcpy(&s, buf + (*off), sizeof(s));
     (*off) += sizeof(s);
-    if ((*off) + ntohs(s) > sz) {
+    rdlength = ntohs(s);
+    if ((*off) + rdlength > sz) {
        /*
         * We got a truncated packet.  'dnscache' truncates UDP
         * replies at 512 octets, as per RFC 1035.
@@ -404,31 +408,33 @@ rfc1035RRUnpack(const char *buf, size_t sz, off_t * off, rfc1035_rr * RR)
        memset(RR, '\0', sizeof(*RR));
        return 1;
     }
-    RR->rdlength = ntohs(s);
+    RR->rdlength = rdlength;
     switch (RR->type) {
     case RFC1035_TYPE_PTR:
        RR->rdata = malloc(RFC1035_MAXHOSTNAMESZ);
        rdata_off = *off;
-       if (rfc1035NameUnpack(buf, sz, &rdata_off, RR->rdata, RFC1035_MAXHOSTNAMESZ, 0))
+       RR->rdlength = 0; /* Filled in by rfc1035NameUnpack */
+       if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength, RR->rdata, RFC1035_MAXHOSTNAMESZ, 0))
            return 1;
-       if (rdata_off != ((*off) + RR->rdlength)) {
+       if (rdata_off != ((*off) + rdlength)) {
            /*
             * This probably doesn't happen for valid packets, but
             * I want to make sure that NameUnpack doesn't go beyond
             * the RDATA area.
             */
            RFC1035_UNPACK_DEBUG;
+            free(RR->rdata);
            memset(RR, '\0', sizeof(*RR));
            return 1;
        }
        break;
     case RFC1035_TYPE_A:
     default:
-       RR->rdata = malloc(RR->rdlength);
-       memcpy(RR->rdata, buf + (*off), RR->rdlength);
+       RR->rdata = malloc(rdlength);
+       memcpy(RR->rdata, buf + (*off), rdlength);
        break;
     }
-    (*off) += RR->rdlength;
+    (*off) += rdlength;
     assert((*off) <= sz);
     return 0;
 }