diff options
author | rsc <devnull@localhost> | 2005-12-27 04:30:05 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2005-12-27 04:30:05 +0000 |
commit | 3e0d8fb3ea83b2b65a6425c65beda887140f9349 (patch) | |
tree | ce1579f6999c0e4adad35b75c498ddc714b40c1e /src/cmd/ndb/convDNS2M.c | |
parent | cff43a06f21a674b2b16e72f8853aac5fd24f48d (diff) | |
download | plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.tar.gz plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.tar.bz2 plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.zip |
add dns
Diffstat (limited to 'src/cmd/ndb/convDNS2M.c')
-rwxr-xr-x | src/cmd/ndb/convDNS2M.c | 380 |
1 files changed, 380 insertions, 0 deletions
diff --git a/src/cmd/ndb/convDNS2M.c b/src/cmd/ndb/convDNS2M.c new file mode 100755 index 00000000..5ee6cadb --- /dev/null +++ b/src/cmd/ndb/convDNS2M.c @@ -0,0 +1,380 @@ +#include <u.h> +#include <libc.h> +#include <ip.h> +#include <bio.h> +#include <ndb.h> +#include "dns.h" + +/* + * a dictionary of domain names for packing messages + */ +enum +{ + Ndict= 64, +}; +typedef struct Dict Dict; +struct Dict +{ + struct { + ushort offset; /* pointer to packed name in message */ + char *name; /* pointer to unpacked name in buf */ + } x[Ndict]; + int n; /* size of dictionary */ + uchar *start; /* start of packed message */ + char buf[4*1024]; /* buffer for unpacked names */ + char *ep; /* first free char in buf */ +}; + +#define NAME(x) p = pname(p, ep, x, dp) +#define SYMBOL(x) p = psym(p, ep, x) +#define STRING(x) p = pstr(p, ep, x) +#define BYTES(x, n) p = pbytes(p, ep, x, n) +#define USHORT(x) p = pushort(p, ep, x) +#define UCHAR(x) p = puchar(p, ep, x) +#define ULONG(x) p = pulong(p, ep, x) +#define V4ADDR(x) p = pv4addr(p, ep, x) +#define V6ADDR(x) p = pv6addr(p, ep, x) + +static uchar* +psym(uchar *p, uchar *ep, char *np) +{ + int n; + + n = strlen(np); + if(n >= Strlen) /* DNS maximum length string */ + n = Strlen - 1; + if(ep - p < n+1) /* see if it fits in the buffer */ + return ep+1; + *p++ = n; + memcpy(p, np, n); + return p + n; +} + +static uchar* +pstr(uchar *p, uchar *ep, char *np) +{ + int n; + + n = strlen(np); + if(n >= Strlen) /* DNS maximum length string */ + n = Strlen - 1; + if(ep - p < n+1) /* see if it fits in the buffer */ + return ep+1; + *p++ = n; + memcpy(p, np, n); + return p + n; +} + +static uchar* +pbytes(uchar *p, uchar *ep, uchar *np, int n) +{ + if(ep - p < n) + return ep+1; + memcpy(p, np, n); + return p + n; +} + +static uchar* +puchar(uchar *p, uchar *ep, int val) +{ + if(ep - p < 1) + return ep+1; + *p++ = val; + return p; +} + +static uchar* +pushort(uchar *p, uchar *ep, int val) +{ + if(ep - p < 2) + return ep+1; + *p++ = val>>8; + *p++ = val; + return p; +} + +static uchar* +pulong(uchar *p, uchar *ep, int val) +{ + if(ep - p < 4) + return ep+1; + *p++ = val>>24; + *p++ = val>>16; + *p++ = val>>8; + *p++ = val; + return p; +} + +static uchar* +pv4addr(uchar *p, uchar *ep, char *name) +{ + uchar ip[IPaddrlen]; + + if(ep - p < 4) + return ep+1; + parseip(ip, name); + v6tov4(p, ip); + return p + 4; + +} + +static uchar* +pv6addr(uchar *p, uchar *ep, char *name) +{ + if(ep - p < IPaddrlen) + return ep+1; + parseip(p, name); + return p + IPaddrlen; + +} + +static uchar* +pname(uchar *p, uchar *ep, char *np, Dict *dp) +{ + char *cp; + int i; + char *last; /* last component packed */ + + if(strlen(np) >= Domlen) /* make sure we don't exceed DNS limits */ + return ep+1; + + last = 0; + while(*np){ + /* look through every component in the dictionary for a match */ + for(i = 0; i < dp->n; i++){ + if(strcmp(np, dp->x[i].name) == 0){ + if(ep - p < 2) + return ep+1; + *p++ = (dp->x[i].offset>>8) | 0xc0; + *p++ = dp->x[i].offset; + return p; + } + } + + /* if there's room, enter this name in dictionary */ + if(dp->n < Ndict){ + if(last){ + /* the whole name is already in dp->buf */ + last = strchr(last, '.') + 1; + dp->x[dp->n].name = last; + dp->x[dp->n].offset = p - dp->start; + dp->n++; + } else { + /* add to dp->buf */ + i = strlen(np); + if(dp->ep + i + 1 < &dp->buf[sizeof(dp->buf)]){ + strcpy(dp->ep, np); + dp->x[dp->n].name = dp->ep; + last = dp->ep; + dp->x[dp->n].offset = p - dp->start; + dp->ep += i + 1; + dp->n++; + } + } + } + + /* put next component into message */ + cp = strchr(np, '.'); + if(cp == 0){ + i = strlen(np); + cp = np + i; /* point to null terminator */ + } else { + i = cp - np; + cp++; /* point past '.' */ + } + if(ep-p < i+1) + return ep+1; + *p++ = i; /* count of chars in label */ + memcpy(p, np, i); + np = cp; + p += i; + } + + if(p >= ep) + return ep+1; + *p++ = 0; /* add top level domain */ + + return p; +} + +static uchar* +convRR2M(RR *rp, uchar *p, uchar *ep, Dict *dp) +{ + uchar *lp, *data; + int len, ttl; + Txt *t; + + NAME(rp->owner->name); + USHORT(rp->type); + USHORT(rp->owner->class); + + /* egregious overuse of ttl (it's absolute time in the cache) */ + if(rp->db) + ttl = rp->ttl; + else + ttl = rp->ttl - now; + if(ttl < 0) + ttl = 0; + ULONG(ttl); + + lp = p; /* leave room for the rdata length */ + p += 2; + data = p; + + if(data >= ep) + return p+1; + + switch(rp->type){ + case Thinfo: + SYMBOL(rp->cpu->name); + SYMBOL(rp->os->name); + break; + case Tcname: + case Tmb: + case Tmd: + case Tmf: + case Tns: + NAME(rp->host->name); + break; + case Tmg: + case Tmr: + NAME(rp->mb->name); + break; + case Tminfo: + NAME(rp->rmb->name); + NAME(rp->mb->name); + break; + case Tmx: + USHORT(rp->pref); + NAME(rp->host->name); + break; + case Ta: + V4ADDR(rp->ip->name); + break; + case Taaaa: + V6ADDR(rp->ip->name); + break; + case Tptr: + NAME(rp->ptr->name); + break; + case Tsoa: + NAME(rp->host->name); + NAME(rp->rmb->name); + ULONG(rp->soa->serial); + ULONG(rp->soa->refresh); + ULONG(rp->soa->retry); + ULONG(rp->soa->expire); + ULONG(rp->soa->minttl); + break; + case Ttxt: + for(t = rp->txt; t != nil; t = t->next) + STRING(t->p); + break; + case Tnull: + BYTES(rp->null->data, rp->null->dlen); + break; + case Trp: + NAME(rp->rmb->name); + NAME(rp->rp->name); + break; + case Tkey: + USHORT(rp->key->flags); + UCHAR(rp->key->proto); + UCHAR(rp->key->alg); + BYTES(rp->key->data, rp->key->dlen); + break; + case Tsig: + USHORT(rp->sig->type); + UCHAR(rp->sig->alg); + UCHAR(rp->sig->labels); + ULONG(rp->sig->ttl); + ULONG(rp->sig->exp); + ULONG(rp->sig->incep); + USHORT(rp->sig->tag); + NAME(rp->sig->signer->name); + BYTES(rp->sig->data, rp->sig->dlen); + break; + case Tcert: + USHORT(rp->cert->type); + USHORT(rp->cert->tag); + UCHAR(rp->cert->alg); + BYTES(rp->cert->data, rp->cert->dlen); + break; + } + + /* stuff in the rdata section length */ + len = p - data; + *lp++ = len >> 8; + *lp = len; + + return p; +} + +static uchar* +convQ2M(RR *rp, uchar *p, uchar *ep, Dict *dp) +{ + NAME(rp->owner->name); + USHORT(rp->type); + USHORT(rp->owner->class); + return p; +} + +static uchar* +rrloop(RR *rp, int *countp, uchar *p, uchar *ep, Dict *dp, int quest) +{ + uchar *np; + + *countp = 0; + for(; rp && p < ep; rp = rp->next){ + if(quest) + np = convQ2M(rp, p, ep, dp); + else + np = convRR2M(rp, p, ep, dp); + if(np > ep) + break; + p = np; + (*countp)++; + } + return p; +} + +/* + * convert into a message + */ +int +convDNS2M(DNSmsg *m, uchar *buf, int len) +{ + uchar *p, *ep, *np; + Dict d; + + d.n = 0; + d.start = buf; + d.ep = d.buf; + memset(buf, 0, len); + m->qdcount = m->ancount = m->nscount = m->arcount = 0; + + /* first pack in the RR's so we can get real counts */ + p = buf + 12; + ep = buf + len; + p = rrloop(m->qd, &m->qdcount, p, ep, &d, 1); + p = rrloop(m->an, &m->ancount, p, ep, &d, 0); + p = rrloop(m->ns, &m->nscount, p, ep, &d, 0); + p = rrloop(m->ar, &m->arcount, p, ep, &d, 0); + if(p > ep) + return -1; + + /* now pack the rest */ + np = p; + p = buf; + ep = buf + len; + USHORT(m->id); + USHORT(m->flags); + USHORT(m->qdcount); + USHORT(m->ancount); + USHORT(m->nscount); + USHORT(m->arcount); + if(p > ep) + return -1; + + return np - buf; +} |