]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
Prepare for being able to verify the DNS query
authorhno <>
Tue, 10 May 2005 14:23:06 +0000 (14:23 +0000)
committerhno <>
Tue, 10 May 2005 14:23:06 +0000 (14:23 +0000)
Instead of just returning the decoded resource records when decoding
a DNS response, return the whole decoded message (header + query +
response).

Next step is to actually verify the query, and then to allow for VC
operation on truncated messages.

include/rfc1035.h
lib/rfc1035.c
src/dns_internal.cc

index 2a93ef7b180775f4c1fdd0e3a665419d1857e795..718a7ed81bfb576c7dff7648035acc5ed6780569 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: rfc1035.h,v 1.12 2005/05/09 02:32:09 hno Exp $
+ * $Id: rfc1035.h,v 1.13 2005/05/10 08:23:06 hno Exp $
  *
  * AUTHOR: Duane Wessels
  *
@@ -56,6 +56,30 @@ struct _rfc1035_rr {
     unsigned short rdlength;
     char *rdata;
 };
+typedef struct _rfc1035_query rfc1035_query;
+struct _rfc1035_query {
+    char name[RFC1035_MAXHOSTNAMESZ];
+    unsigned short qtype;
+    unsigned short qclass;
+};
+typedef struct _rfc1035_message rfc1035_message;
+struct _rfc1035_message {
+    unsigned short id;
+    unsigned int qr:1;
+    unsigned int opcode:4;
+    unsigned int aa:1;
+    unsigned int tc:1;
+    unsigned int rd:1;
+    unsigned int ra:1;
+    unsigned int rcode:4;
+    unsigned short qdcount;
+    unsigned short ancount;
+    unsigned short nscount;
+    unsigned short arcount;
+    rfc1035_query *query;
+    rfc1035_rr *answer;
+};
+
 SQUIDCEXTERN ssize_t rfc1035BuildAQuery(const char *hostname,
     char *buf,
     size_t sz,
@@ -65,11 +89,10 @@ SQUIDCEXTERN ssize_t rfc1035BuildPTRQuery(const struct IN_ADDR,
     size_t sz,
     unsigned short qid);
 SQUIDCEXTERN void rfc1035SetQueryID(char *, unsigned short qid);
-SQUIDCEXTERN int rfc1035AnswersUnpack(const char *buf,
+SQUIDCEXTERN int rfc1035MessageUnpack(const char *buf,
     size_t sz,
-    rfc1035_rr ** records,
-    unsigned short *id);
-SQUIDCEXTERN void rfc1035RRDestroy(rfc1035_rr * rr, int n);
+    rfc1035_message ** answer);
+SQUIDCEXTERN void rfc1035MessageDestroy(rfc1035_message * message);
 SQUIDCEXTERN int rfc1035_errno;
 SQUIDCEXTERN const char *rfc1035_error_message;
 
index 9dcc231028849c002b263f328c9767f97c12cf66..5abaca1796bb0ab1bac8a188df39ae96475874a3 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: rfc1035.c,v 1.41 2005/05/09 02:32:09 hno Exp $
+ * $Id: rfc1035.c,v 1.42 2005/05/10 08:23:07 hno Exp $
  *
  * Low level DNS protocol routines
  * AUTHOR: Duane Wessels
@@ -40,6 +40,7 @@
  */
 
 #include "config.h"
+#include "util.h"
 
 #if HAVE_STDIO_H
 #include <stdio.h>
 #endif
 
 
-typedef struct _rfc1035_header rfc1035_header;
 
 int rfc1035_errno;
 const char *rfc1035_error_message;
-struct _rfc1035_header {
-    unsigned short id;
-    unsigned int qr:1;
-    unsigned int opcode:4;
-    unsigned int aa:1;
-    unsigned int tc:1;
-    unsigned int rd:1;
-    unsigned int ra:1;
-    unsigned int rcode:4;
-    unsigned short qdcount;
-    unsigned short ancount;
-    unsigned short nscount;
-    unsigned short arcount;
-};
 
 /*
  * rfc1035HeaderPack()
@@ -108,7 +94,7 @@ struct _rfc1035_header {
  * Returns number of octets packed (should always be 12)
  */
 static off_t
-rfc1035HeaderPack(char *buf, size_t sz, rfc1035_header * hdr)
+rfc1035HeaderPack(char *buf, size_t sz, rfc1035_message * hdr)
 {
     off_t off = 0;
     unsigned short s;
@@ -181,14 +167,14 @@ static off_t
 rfc1035NamePack(char *buf, size_t sz, const char *name)
 {
     off_t off = 0;
-    char *copy = strdup(name);
+    char *copy = xstrdup(name);
     char *t;
     /*
      * NOTE: use of strtok here makes names like foo....com valid.
      */
     for (t = strtok(copy, "."); t; t = strtok(NULL, "."))
        off += rfc1035LabelPack(buf + off, sz - off, t);
-    free(copy);
+    xfree(copy);
     off += rfc1035LabelPack(buf + off, sz - off, NULL);
     assert(off <= sz);
     return off;
@@ -223,8 +209,8 @@ rfc1035QuestionPack(char *buf,
 /*
  * rfc1035HeaderUnpack()
  * 
- * Unpacks a RFC1035 message header buffer into a rfc1035_header
- * structure.
+ * Unpacks a RFC1035 message header buffer into the header fields
+ * of the rfc1035_message structure.
  *
  * Updates the buffer offset, which is the same as number of
  * octects unpacked since the header starts at offset 0.
@@ -232,7 +218,7 @@ rfc1035QuestionPack(char *buf,
  * Returns 0 (success) or 1 (error)
  */
 static int
-rfc1035HeaderUnpack(const char *buf, size_t sz, off_t * off, rfc1035_header * h)
+rfc1035HeaderUnpack(const char *buf, size_t sz, off_t * off, rfc1035_message * h)
 {
     unsigned short s;
     unsigned short t;
@@ -405,7 +391,7 @@ rfc1035RRUnpack(const char *buf, size_t sz, off_t * off, rfc1035_rr * RR)
     RR->rdlength = rdlength;
     switch (RR->type) {
     case RFC1035_TYPE_PTR:
-       RR->rdata = malloc(RFC1035_MAXHOSTNAMESZ);
+       RR->rdata = xmalloc(RFC1035_MAXHOSTNAMESZ);
        rdata_off = *off;
        RR->rdlength = 0; /* Filled in by rfc1035NameUnpack */
        if (rfc1035NameUnpack(buf, sz, &rdata_off, &RR->rdlength, RR->rdata, RFC1035_MAXHOSTNAMESZ, 0))
@@ -417,14 +403,14 @@ rfc1035RRUnpack(const char *buf, size_t sz, off_t * off, rfc1035_rr * RR)
             * the RDATA area.
             */
            RFC1035_UNPACK_DEBUG;
-            free(RR->rdata);
+            xfree(RR->rdata);
            memset(RR, '\0', sizeof(*RR));
            return 1;
        }
        break;
     case RFC1035_TYPE_A:
     default:
-       RR->rdata = malloc(rdlength);
+       RR->rdata = xmalloc(rdlength);
        memcpy(RR->rdata, buf + (*off), rdlength);
        break;
     }
@@ -470,7 +456,7 @@ rfc1035SetErrno(int n)
     }
 }
 
-void
+static void
 rfc1035RRDestroy(rfc1035_rr * rr, int n)
 {
     if (rr == NULL)
@@ -478,13 +464,59 @@ rfc1035RRDestroy(rfc1035_rr * rr, int n)
     assert(n > 0);
     while (n--) {
        if (rr[n].rdata)
-           free(rr[n].rdata);
+           xfree(rr[n].rdata);
+    }
+    xfree(rr);
+}
+
+/*
+ * rfc1035QueryUnpack()
+ * 
+ * Unpacks a RFC1035 Query Record into 'query' from a message buffer.
+ *
+ * Updates the new message buffer offset.
+ *
+ * Returns 0 (success) or 1 (error)
+ */
+static int
+rfc1035QueryUnpack(const char *buf, size_t sz, off_t * off, rfc1035_query * query)
+{
+    unsigned short s;
+    if (rfc1035NameUnpack(buf, sz, off, NULL, query->name, RFC1035_MAXHOSTNAMESZ, 0)) {
+       RFC1035_UNPACK_DEBUG;
+       memset(query, '\0', sizeof(*query));
+       return 1;
     }
-    free(rr);
+    if (*off + 4 > sz) {
+       RFC1035_UNPACK_DEBUG;
+       memset(query, '\0', sizeof(*query));
+       return 1;
+    }
+    memcpy(&s, buf + *off, 2);
+    *off += 2;
+    buf+=2;
+    query->qtype = ntohs(s);
+    memcpy(&s, buf + *off, 2);
+    *off += 2;
+    buf+=2;
+    query->qtype = ntohs(s);
+    return 0;
+}
+
+void
+rfc1035MessageDestroy(rfc1035_message *msg)
+{
+    if (!msg)
+       return;
+    if (msg->query)
+       xfree(msg->query);
+    if (msg->answer)
+       rfc1035RRDestroy(msg->answer, msg->ancount);
+    xfree(msg);
 }
 
 /*
- * rfc1035AnswersUnpack()
+ * rfc1035MessageUnpack()
  *
  * Takes the contents of a DNS reply and fills in an array
  * of resource record structures.  The records array is allocated
@@ -495,60 +527,53 @@ rfc1035RRDestroy(rfc1035_rr * rr, int n)
  */
 
 int
-rfc1035AnswersUnpack(const char *buf,
+rfc1035MessageUnpack(const char *buf,
     size_t sz,
-    rfc1035_rr ** records,
-    unsigned short *id)
+    rfc1035_message ** answer)
 {
     off_t off = 0;
-    int l;
     int i;
     int nr = 0;
-    rfc1035_header hdr;
+    rfc1035_message *msg;
     rfc1035_rr *recs;
-    memset(&hdr, '\0', sizeof(hdr));
-    if (rfc1035HeaderUnpack(buf + off, sz - off, &off, &hdr)) {
+    rfc1035_query *querys;
+    msg = xcalloc(1, sizeof(*msg));
+    if (rfc1035HeaderUnpack(buf + off, sz - off, &off, msg)) {
        RFC1035_UNPACK_DEBUG;
        rfc1035SetErrno(rfc1035_unpack_error);
+       xfree(msg);
        return -rfc1035_unpack_error;
     }
-    *id = hdr.id;
     rfc1035_errno = 0;
     rfc1035_error_message = NULL;
-    if (hdr.rcode) {
+    if (msg->rcode) {
        RFC1035_UNPACK_DEBUG;
-       rfc1035SetErrno((int) hdr.rcode);
+       rfc1035SetErrno((int) msg->rcode);
+       xfree(msg);
        return -rfc1035_errno;
     }
-    i = (int) hdr.qdcount;
-    /* skip question */
-    while (i--) {
-       do {
-           l = (int) (unsigned char) *(buf + off);
-           off++;
-           if (l > 191) {      /* compression */
-               off++;
-               break;
-           } else if (l > RFC1035_MAXLABELSZ) {
-               /* illegal combination of compression bits */
-               RFC1035_UNPACK_DEBUG;
-               rfc1035SetErrno(rfc1035_unpack_error);
-               return -rfc1035_unpack_error;
-           } else {
-               off += l;
-           }
-       } while (l > 0);        /* a zero-length label terminates */
-       off += 4;               /* qtype, qclass */
-       if (off > sz) {
+    i = (int) msg->qdcount;
+    if (i != 1) {
+       /* This can not be an answer to our queries.. */
+       RFC1035_UNPACK_DEBUG;
+       rfc1035SetErrno(rfc1035_unpack_error);
+       xfree(msg);
+       return -rfc1035_unpack_error;
+    }
+    querys = msg->query = xcalloc((int)msg->qdcount, sizeof(*querys));
+    for (i = 0; i < (int)msg->qdcount; i++) {
+       if (rfc1035QueryUnpack(buf, sz, &off, &querys[i])) {
            RFC1035_UNPACK_DEBUG;
            rfc1035SetErrno(rfc1035_unpack_error);
+           rfc1035MessageDestroy(msg);
            return -rfc1035_unpack_error;
        }
     }
-    if (hdr.ancount == 0)
+    *answer = msg;
+    if (msg->ancount == 0)
        return 0;
-    recs = calloc((int)hdr.ancount, sizeof(*recs));
-    for (i = 0; i < (int)hdr.ancount; i++) {
+    recs = msg->answer = xcalloc((int)msg->ancount, sizeof(*recs));
+    for (i = 0; i < (int)msg->ancount; i++) {
        if (off >= sz) {        /* corrupt packet */
            RFC1035_UNPACK_DEBUG;
            break;
@@ -564,11 +589,11 @@ rfc1035AnswersUnpack(const char *buf,
         * we expected to unpack some answers (ancount != 0), but
         * didn't actually get any.
         */
-       free(recs);
+       rfc1035MessageDestroy(msg);
+       *answer = NULL;
        rfc1035SetErrno(rfc1035_unpack_error);
        return -rfc1035_unpack_error;
     }
-    *records = recs;
     return nr;
 }
 
@@ -585,7 +610,7 @@ rfc1035AnswersUnpack(const char *buf,
 ssize_t
 rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qid)
 {
-    static rfc1035_header h;
+    static rfc1035_message h;
     size_t offset = 0;
     memset(&h, '\0', sizeof(h));
     h.id = qid;
@@ -616,7 +641,7 @@ rfc1035BuildAQuery(const char *hostname, char *buf, size_t sz, unsigned short qi
 ssize_t
 rfc1035BuildPTRQuery(const struct IN_ADDR addr, char *buf, size_t sz, unsigned short qid)
 {
-    static rfc1035_header h;
+    static rfc1035_message h;
     size_t offset = 0;
     static char rev[32];
     unsigned int i;
index c6470982fe60457456446bb61b7315c3ff7fc9e0..ecbaf9fec9118ddd505b554f6ed9768482aadddf 100644 (file)
@@ -1,6 +1,6 @@
 
 /*
- * $Id: dns_internal.cc,v 1.72 2005/05/09 16:33:55 hno Exp $
+ * $Id: dns_internal.cc,v 1.73 2005/05/10 08:23:07 hno Exp $
  *
  * DEBUG: section 78    DNS lookups; interacts with lib/rfc1035.c
  * AUTHOR: Duane Wessels
@@ -599,26 +599,27 @@ static void
 idnsGrokReply(const char *buf, size_t sz)
 {
     int n;
-    rfc1035_rr *answers = NULL;
-    unsigned short rid;
+    rfc1035_message *message = NULL;
     idns_query *q;
 
-    n = rfc1035AnswersUnpack(buf,
+    n = rfc1035MessageUnpack(buf,
                              sz,
-                             &answers,
-                             &rid);
-    debug(78, 3) ("idnsGrokReply: ID %#hx, %d answers\n", rid, n);
+                             &message);
 
-    if (n == -15 /* rfc1035_unpack_error */ ) {
+    if (message == NULL) {
         debug(78, 1) ("idnsGrokReply: Malformed DNS response\n");
         return;
     }
 
-    q = idnsFindQuery(rid);
+    debug(78, 3) ("idnsGrokReply: ID %#hx, %d answers\n", message->id, n);
+
+    q = idnsFindQuery(message->id);
+
+    /* FIXME: We should also verify the query to match ours */
 
     if (q == NULL) {
         debug(78, 3) ("idnsGrokReply: Late response\n");
-        rfc1035RRDestroy(answers, n);
+        rfc1035MessageDestroy(message);
         return;
     }
 
@@ -627,7 +628,7 @@ idnsGrokReply(const char *buf, size_t sz)
     q->error = NULL;
 
     if (n < 0) {
-        debug(78, 3) ("idnsGrokReply: error %d\n", rfc1035_errno);
+        debug(78, 3) ("idnsGrokReply: error %s (%d)\n", rfc1035_error_message, rfc1035_errno);
 
         q->error = rfc1035_error_message;
         q->rcode = -n;
@@ -638,7 +639,7 @@ idnsGrokReply(const char *buf, size_t sz)
              * unable to process this query due to a problem with
              * the name server."
              */
-            assert(NULL == answers);
+            rfc1035MessageDestroy(message);
             q->start_t = current_time;
             q->id = idnsQueryID();
             rfc1035SetQueryID(q->buf, q->id);
@@ -647,8 +648,8 @@ idnsGrokReply(const char *buf, size_t sz)
         }
     }
 
-    idnsCallback(q, answers, n, q->error);
-    rfc1035RRDestroy(answers, n);
+    idnsCallback(q, message->answer, n, q->error);
+    rfc1035MessageDestroy(message);
 
     memFree(q, MEM_IDNS_QUERY);
 }