]> git.ipfire.org Git - thirdparty/squid.git/commitdiff
adding rfc1035.c - DNS
authorwessels <>
Wed, 14 Apr 1999 03:17:11 +0000 (03:17 +0000)
committerwessels <>
Wed, 14 Apr 1999 03:17:11 +0000 (03:17 +0000)
lib/Makefile.in
lib/rfc1035.c [new file with mode: 0644]

index 49c9b4a7c3d43895c5c711e2f981fc301b71c314..aa6763beded6aded33ac4d57f12660c3a614e14d 100644 (file)
@@ -1,5 +1,5 @@
 #
-#  $Id: Makefile.in,v 1.41 1999/04/07 19:48:57 wessels Exp $
+#  $Id: Makefile.in,v 1.42 1999/04/13 21:17:11 wessels Exp $
 #
 prefix         = @prefix@
 top_srcdir     = @top_srcdir@
@@ -23,6 +23,7 @@ AR_R          = @AR_R@
 INCLUDE                = -I../include -I$(top_srcdir)/include
 UTILOBJS       = rfc1123.o \
                  rfc1738.o \
+                 rfc1035.o \
                  util.o \
                  getfullhostname.o \
                  base64.o \
diff --git a/lib/rfc1035.c b/lib/rfc1035.c
new file mode 100644 (file)
index 0000000..fc02d63
--- /dev/null
@@ -0,0 +1,488 @@
+#include "config.h"
+
+#if HAVE_STDIO_H
+#include <stdio.h>
+#endif
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+#if HAVE_MEMORY_H
+#include <memory.h>
+#endif
+#if HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#if HAVE_ASSERT_H
+#include <assert.h>
+#endif
+#if HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#if HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#define RFC1035_TYPE_A 1
+#define RFC1035_CLASS_IN 1
+
+#define RFC1035_MAXLABELSZ 63
+#define RFC1035_MAXHOSTNAMESZ 128
+
+typedef struct _rfc1305_header rfc1305_header;
+typedef struct _rfc1305_rr rfc1305_rr;
+
+int rfc1035_errno;
+
+struct _rfc1305_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;
+};
+
+struct _rfc1305_rr {
+    char name[RFC1035_MAXHOSTNAMESZ];
+    unsigned short type;
+    unsigned short class;
+    unsigned int ttl;
+    unsigned short rdlength;
+    char *rdata;
+};
+
+/*
+ * rfc1035HeaderPack()
+ * 
+ * Packs a rfc1305_header structure into a buffer.
+ * Returns number of octets packed (should always be 12)
+ */
+static off_t
+rfc1035HeaderPack(char *buf, size_t sz, rfc1305_header * hdr)
+{
+    off_t off = 0;
+    unsigned short s;
+    unsigned short t;
+    assert(sz >= 12);
+    s = htons(hdr->id);
+    memcpy(buf + off, &s, sizeof(s));
+    off += sizeof(s);
+    t = 0;
+    t |= hdr->qr << 15;
+    t |= (hdr->opcode << 11);
+    t |= (hdr->aa << 10);
+    t |= (hdr->tc << 9);
+    t |= (hdr->rd << 8);
+    t |= (hdr->ra << 7);
+    t |= hdr->rcode;
+    s = htons(t);
+    memcpy(buf + off, &s, sizeof(s));
+    off += sizeof(s);
+    s = htons(hdr->qdcount);
+    memcpy(buf + off, &s, sizeof(s));
+    off += sizeof(s);
+    s = htons(hdr->ancount);
+    memcpy(buf + off, &s, sizeof(s));
+    off += sizeof(s);
+    s = htons(hdr->nscount);
+    memcpy(buf + off, &s, sizeof(s));
+    off += sizeof(s);
+    s = htons(hdr->arcount);
+    memcpy(buf + off, &s, sizeof(s));
+    off += sizeof(s);
+    assert(off == 12);
+    return off;
+}
+
+/*
+ * rfc1035LabelPack()
+ * 
+ * Packs a label into a buffer.  The format of
+ * a label is one octet specifying the number of character
+ * bytes to follow.  Labels must be smaller than 64 octets.
+ * Returns number of octets packed.
+ */
+static off_t
+rfc1035LabelPack(char *buf, size_t sz, const char *label)
+{
+    off_t off = 0;
+    size_t len = label ? strlen(label) : 0;
+    if (label)
+       assert(!strchr(label, '.'));
+    if (len > RFC1035_MAXLABELSZ)
+       len = RFC1035_MAXLABELSZ;
+    assert(sz >= len + 1);
+    *(buf + off) = (char) len;
+    off++;
+    memcpy(buf + off, label, len);
+    off += len;
+    return off;
+}
+
+/*
+ * rfc1035NamePack()
+ * 
+ * Packs a name into a buffer.  Names are packed as a
+ * sequence of labels, terminated with NULL label.
+ * Note message compression is not supported here.
+ * Returns number of octets packed.
+ */
+off_t
+rfc1035NamePack(char *buf, size_t sz, const char *name)
+{
+    off_t off = 0;
+    char *copy = strdup(name);
+    char *t;
+    for (t = strtok(copy, "."); t; t = strtok(NULL, "."))
+       off += rfc1035LabelPack(buf + off, sz - off, t);
+    free(copy);
+    off += rfc1035LabelPack(buf + off, sz - off, NULL);
+    assert(off <= sz);
+    return off;
+}
+
+/*
+ * rfc1035QuestionPack()
+ * 
+ * Packs a QUESTION section of a message.
+ * Returns number of octets packed.
+ */
+static off_t
+rfc1035QuestionPack(char *buf,
+    size_t sz,
+    const char *name,
+    unsigned short type,
+    unsigned short class)
+{
+    off_t off = 0;
+    unsigned short s;
+    off += rfc1035NamePack(buf + off, sz - off, name);
+    s = htons(type);
+    memcpy(buf + off, &s, sizeof(s));
+    off += sizeof(s);
+    s = htons(class);
+    memcpy(buf + off, &s, sizeof(s));
+    off += sizeof(s);
+    assert(off <= sz);
+    return off;
+}
+
+/*
+ * rfc1035HeaderUnpack()
+ * 
+ * Unpacks a RFC1035 message header buffer into a rfc1305_header
+ * structure.
+ * Returns the new buffer offset, which is the same as number of
+ * octects unpacked since the header starts at offset 0.
+ */
+static off_t
+rfc1035HeaderUnpack(const char *buf, size_t sz, rfc1305_header * h)
+{
+    unsigned short s;
+    unsigned short t;
+    off_t off = 0;
+    assert(sz >= 12);
+    memcpy(&s, buf + off, sizeof(s));
+    off += sizeof(s);
+    h->id = ntohs(s);
+    memcpy(&s, buf + off, sizeof(s));
+    off += sizeof(s);
+    t = ntohs(s);
+    h->qr = (t >> 15) & 0x01;
+    h->opcode = (t >> 11) & 0x0F;
+    h->aa = (t >> 10) & 0x01;
+    h->tc = (t >> 8) & 0x01;
+    h->rd = (t >> 8) & 0x01;
+    h->ra = (t >> 7) & 0x01;
+    h->rcode = t & 0x0F;
+    memcpy(&s, buf + off, sizeof(s));
+    off += sizeof(s);
+    h->qdcount = ntohs(s);
+    memcpy(&s, buf + off, sizeof(s));
+    off += sizeof(s);
+    h->ancount = ntohs(s);
+    memcpy(&s, buf + off, sizeof(s));
+    off += sizeof(s);
+    h->nscount = ntohs(s);
+    memcpy(&s, buf + off, sizeof(s));
+    off += sizeof(s);
+    h->arcount = ntohs(s);
+    assert(off == 12);
+    return off;
+}
+
+/*
+ * rfc1035NameUnpack()
+ * 
+ * Unpacks a Name in a message buffer into a char*.
+ * Note 'buf' points to the beginning of the whole message,
+ * 'off' points to the spot where the Name begins, and 'sz'
+ * is the size of the whole message.  'name' must be allocated
+ * by the caller.
+ *
+ * Supports the RFC1035 message compression through recursion.
+ *
+ * Returns the new buffer offset.
+ */
+static off_t
+rfc1035NameUnpack(const char *buf, size_t sz, off_t off, char *name, size_t ns)
+{
+    off_t no = 0;
+    unsigned char c;
+    size_t len;
+    assert(ns > 0);
+    do {
+       c = *(buf + off);
+       if (c > RFC1035_MAXLABELSZ) {
+           /* fucking compression */
+           unsigned short s;
+           off_t ptr;
+           memcpy(&s, buf + off, sizeof(s));
+           s = ntohs(s);
+           off += sizeof(s);
+           ptr = s & 0x3FFF;
+           (void) rfc1035NameUnpack(buf, sz, ptr, name + no, ns - no);
+           return off;
+       } else {
+           off++;
+           len = (size_t) c;
+           if (len == 0)
+               break;
+           if (len > (ns-1))
+               len = ns-1;
+           memcpy(name + no, buf + off, len);
+           off += len;
+           no += len;
+           *(name + (no++)) = '.';
+       }
+    } while (c > 0);
+    *(name + no - 1) = '\0';
+    assert(no <= ns);
+    return off;
+}
+
+/*
+ * rfc1035RRUnpack()
+ * 
+ * Unpacks a RFC1035 Resource Record into 'RR' from a message buffer.
+ * The caller must free RR->rdata!
+ * Returns the new message buffer offset.
+ */
+static off_t
+rfc1035RRUnpack(const char *buf, size_t sz, off_t off, rfc1305_rr * RR)
+{
+    unsigned short s;
+    unsigned int i;
+    off = rfc1035NameUnpack(buf, sz, off, RR->name, RFC1035_MAXHOSTNAMESZ);
+    memcpy(&s, buf + off, sizeof(s));
+    off += sizeof(s);
+    RR->type = ntohs(s);
+    memcpy(&s, buf + off, sizeof(s));
+    off += sizeof(s);
+    RR->class = ntohs(s);
+    memcpy(&i, buf + off, sizeof(i));
+    off += sizeof(i);
+    RR->ttl = ntohl(i);
+    memcpy(&s, buf + off, sizeof(s));
+    off += sizeof(s);
+    RR->rdlength = ntohs(s);
+    RR->rdata = malloc(RR->rdlength);
+    memcpy(RR->rdata, buf + off, RR->rdlength);
+    off += RR->rdlength;
+    assert(off <= sz);
+    return off;
+}
+
+int
+rfc1035ARecordsUnpack(const char *buf,
+       size_t sz,
+       struct in_addr *addrs,
+       int naddrs,
+       char *name,
+       size_t namelen,
+       unsigned short *id,
+       time_t * ttl)
+{
+    off_t off = 0;
+    int l;
+    int i;
+    int na = 0;
+    rfc1305_header hdr;
+    memset(&hdr, '\0', sizeof(hdr));
+    off = rfc1035HeaderUnpack(buf + off, sz - off, &hdr);
+    *id = hdr.id;
+    if (hdr.rcode) {
+       rfc1035_errno = (int) hdr.rcode;
+       return -rfc1035_errno;
+    }
+    i = (int) hdr.qdcount;
+    /* skip question */
+    while (i--) {
+       do {
+           l = (int) *(buf + off);
+           off++;
+           if (l > RFC1035_MAXLABELSZ) {       /* compression */
+               off++;
+               break;
+           } else {
+               off += l;
+           }
+       } while (l > 0);
+       off += 4;               /* qtype, qclass */
+       assert(off <= sz);
+    }
+    i = (int) hdr.ancount;
+    while (i--) {
+       rfc1305_rr RR;
+       memset(&RR, '\0', sizeof(RR));
+       off = rfc1035RRUnpack(buf, sz, off, &RR);
+       if (RR.type != RFC1035_TYPE_A) {
+           free(RR.rdata);
+           RR.rdata = NULL;
+           continue;
+       }
+       if (na == 0) {
+           strncpy(name, RR.name, namelen);
+           *ttl = (time_t) RR.ttl;
+       }
+       memcpy(&addrs[na].s_addr, RR.rdata, 4);
+       free(RR.rdata);
+       RR.rdata = NULL;
+       assert(off <= sz);
+       if (++na == naddrs)
+           break;
+    }
+    return na;
+}
+
+/*
+ * rfc1035BuildQuery()
+ * 
+ * Builds a message buffer with a QUESTION to lookup A records
+ * for a hostname.  Caller must allocate 'buf' which should
+ * probably be at least 512 octets.  The 'szp' initially
+ * specifies the size of the buffer, on return it contains
+ * the size of the message (i.e. how much to write).
+ * Return value is the query ID.
+ */
+unsigned short
+rfc1035BuildQuery(const char *hostname, char *buf, size_t * szp)
+{
+    static unsigned short id = 0x0001;
+    static rfc1305_header h;
+    off_t offset = 0;
+    size_t sz = *szp;
+    memset(&h, '\0', sizeof(h));
+    h.id = id;
+    h.qr = 0;
+    h.rd = 1;
+    h.opcode = 0;              /* QUERY */
+    h.qdcount = (unsigned int) 1;
+    offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
+    offset += rfc1035QuestionPack(buf + offset,
+       sz - offset,
+       hostname,
+       RFC1035_TYPE_A,
+       RFC1035_CLASS_IN);
+    assert(offset <= sz);
+    *szp = (size_t) offset;
+    return id++;
+}
+
+#if DRIVER
+int
+main(int argc, char *argv[])
+{
+    rfc1305_header h;
+    char input[512];
+    char buf[512];
+    char rbuf[512];
+    size_t sz = 512;
+    unsigned short sid;
+    off_t offset = 0;
+    int s;
+    int rl;
+    struct sockaddr_in S;
+    setbuf(stdout, NULL);
+    setbuf(stderr, NULL);
+    s = socket(PF_INET, SOCK_DGRAM, 0);
+    if (s < 0) {
+       perror("socket");
+       return 1;
+    }
+    while (fgets(input, 512, stdin)) {
+       strtok(input, "\r\n");
+       memset(buf, '\0', 512);
+       memset(&h, '\0', sizeof(h));
+       offset = 0;
+       h.id = sid = (unsigned short) 0x1234;
+       h.qr = 0;
+       h.rd = 1;
+       h.opcode = 0;
+       h.qdcount = (unsigned int) 1;
+       offset += rfc1035HeaderPack(buf + offset, sz - offset, &h);
+       offset += rfc1035QuestionPack(buf + offset,
+           sz - offset,
+           input,
+           RFC1035_TYPE_A,
+           RFC1035_CLASS_IN);
+       memset(&S, '\0', sizeof(S));
+       S.sin_family = AF_INET;
+       S.sin_port = htons(53);
+       S.sin_addr.s_addr = inet_addr("128.117.28.219");
+       sendto(s, buf, (size_t) offset, 0, (struct sockaddr *) &S, sizeof(S));
+       do {
+           fd_set R;
+           struct timeval to;
+           FD_ZERO(&R);
+           FD_SET(s, &R);
+           to.tv_sec = 10;
+           to.tv_usec = 0;
+           rl = select(s+1, &R, NULL, NULL, &to);
+       } while(0);
+           if (rl < 1) {
+                   printf("TIMEOUT\n");
+                   continue;
+           }
+       memset(rbuf, '\0', 512);
+       rl = recv(s, rbuf, 512, 0);
+       {
+           unsigned short rid;
+           int i;
+           int n;
+           struct in_addr addrs[10];
+           time_t ttl = 0;
+           char rname[RFC1035_MAXHOSTNAMESZ];
+           n = rfc1035ARecordsUnpack(rbuf,
+               rl,
+               addrs, 10,
+               rname, RFC1035_MAXHOSTNAMESZ,
+               &rid,
+               &ttl);
+           if (rid != sid) {
+               printf("ERROR, ID mismatch (%#hx, %#hx)\n", sid, rid);
+           } else if (n < 0) {
+               printf("ERROR %d\n", rfc1035_errno);
+           } else {
+               printf("name\t%s, %d A records\n", rname, n);
+               printf("ttl\t%d\n", (int) ttl);
+               for (i = 0; i < n; i++)
+                   printf("addr %d\t%s\n", i, inet_ntoa(addrs[i]));
+           }
+       }
+    }
+    return 0;
+}
+#endif