123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- #include <u.h>
- #include <libc.h>
- #include <ip.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 STRING(x) p = pstring(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*
- pstring(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;
- 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:
- STRING(rp->cpu->name);
- STRING(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:
- STRING(rp->txt->name);
- break;
- case Tnull:
- BYTES(rp->null->data, rp->null->dlen);
- break;
- case Trp:
- NAME(rp->rmb->name);
- NAME(rp->txt->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;
- }
|