From: hno <> Date: Tue, 10 May 2005 14:23:06 +0000 (+0000) Subject: Prepare for being able to verify the DNS query X-Git-Tag: SQUID_3_0_PRE4~756 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ec7bade04f7b628796e5c59491aff618c4764b31;p=thirdparty%2Fsquid.git Prepare for being able to verify the DNS query 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. --- diff --git a/include/rfc1035.h b/include/rfc1035.h index 2a93ef7b18..718a7ed81b 100644 --- a/include/rfc1035.h +++ b/include/rfc1035.h @@ -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; diff --git a/lib/rfc1035.c b/lib/rfc1035.c index 9dcc231028..5abaca1796 100644 --- a/lib/rfc1035.c +++ b/lib/rfc1035.c @@ -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 @@ -82,24 +83,9 @@ #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; diff --git a/src/dns_internal.cc b/src/dns_internal.cc index c6470982fe..ecbaf9fec9 100644 --- a/src/dns_internal.cc +++ b/src/dns_internal.cc @@ -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); }