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/convM2DNS.c | |
parent | cff43a06f21a674b2b16e72f8853aac5fd24f48d (diff) | |
download | plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.tar.gz plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.tar.bz2 plan9port-3e0d8fb3ea83b2b65a6425c65beda887140f9349.zip |
add dns
Diffstat (limited to 'src/cmd/ndb/convM2DNS.c')
-rwxr-xr-x | src/cmd/ndb/convM2DNS.c | 460 |
1 files changed, 460 insertions, 0 deletions
diff --git a/src/cmd/ndb/convM2DNS.c b/src/cmd/ndb/convM2DNS.c new file mode 100755 index 00000000..47b35616 --- /dev/null +++ b/src/cmd/ndb/convM2DNS.c @@ -0,0 +1,460 @@ +#include <u.h> +#include <libc.h> +#include <ip.h> +#include <bio.h> +#include <ndb.h> +#include "dns.h" + +typedef struct Scan Scan; +struct Scan +{ + uchar *base; + uchar *p; + uchar *ep; + char *err; +}; + +#define NAME(x) gname(x, sp) +#define SYMBOL(x) (x = gsym(sp)) +#define STRING(x) (x = gstr(sp)) +#define USHORT(x) (x = gshort(sp)) +#define ULONG(x) (x = glong(sp)) +#define UCHAR(x) (x = gchar(sp)) +#define V4ADDR(x) (x = gv4addr(sp)) +#define V6ADDR(x) (x = gv6addr(sp)) +#define BYTES(x, y) (y = gbytes(sp, &x, len - (sp->p - data))) + +static char *toolong = "too long"; + +/* + * get a ushort/ulong + */ +static ushort +gchar(Scan *sp) +{ + ushort x; + + if(sp->err) + return 0; + if(sp->ep - sp->p < 1){ + sp->err = toolong; + return 0; + } + x = sp->p[0]; + sp->p += 1; + return x; +} +static ushort +gshort(Scan *sp) +{ + ushort x; + + if(sp->err) + return 0; + if(sp->ep - sp->p < 2){ + sp->err = toolong; + return 0; + } + x = (sp->p[0]<<8) | sp->p[1]; + sp->p += 2; + return x; +} +static ulong +glong(Scan *sp) +{ + ulong x; + + if(sp->err) + return 0; + if(sp->ep - sp->p < 4){ + sp->err = toolong; + return 0; + } + x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3]; + sp->p += 4; + return x; +} + +/* + * get an ip address + */ +static DN* +gv4addr(Scan *sp) +{ + char addr[32]; + + if(sp->err) + return 0; + if(sp->ep - sp->p < 4){ + sp->err = toolong; + return 0; + } + snprint(addr, sizeof(addr), "%V", sp->p); + sp->p += 4; + + return dnlookup(addr, Cin, 1); +} +static DN* +gv6addr(Scan *sp) +{ + char addr[64]; + + if(sp->err) + return 0; + if(sp->ep - sp->p < IPaddrlen){ + sp->err = toolong; + return 0; + } + snprint(addr, sizeof(addr), "%I", sp->p); + sp->p += IPaddrlen; + + return dnlookup(addr, Cin, 1); +} + +/* + * get a string. make it an internal symbol. + */ +static DN* +gsym(Scan *sp) +{ + int n; + char sym[Strlen+1]; + + if(sp->err) + return 0; + n = *(sp->p++); + if(sp->p+n > sp->ep){ + sp->err = toolong; + return 0; + } + + if(n > Strlen){ + sp->err = "illegal string"; + return 0; + } + strncpy(sym, (char*)sp->p, n); + sym[n] = 0; + sp->p += n; + + return dnlookup(sym, Csym, 1); +} + +/* + * get a string. don't make it an internal symbol. + */ +static Txt* +gstr(Scan *sp) +{ + int n; + char sym[Strlen+1]; + Txt *t; + + if(sp->err) + return 0; + n = *(sp->p++); + if(sp->p+n > sp->ep){ + sp->err = toolong; + return 0; + } + + if(n > Strlen){ + sp->err = "illegal string"; + return 0; + } + strncpy(sym, (char*)sp->p, n); + sym[n] = 0; + sp->p += n; + + t = emalloc(sizeof(*t)); + t->next = nil; + t->p = estrdup(sym); + return t; +} + +/* + * get a sequence of bytes + */ +static int +gbytes(Scan *sp, uchar **p, int n) +{ + if(sp->err) + return 0; + if(sp->p+n > sp->ep || n < 0){ + sp->err = toolong; + return 0; + } + *p = emalloc(n); + memmove(*p, sp->p, n); + sp->p += n; + + return n; +} + +/* + * get a domain name. 'to' must point to a buffer at least Domlen+1 long. + */ +static char* +gname(char *to, Scan *sp) +{ + int len, off; + int pointer; + int n; + char *tostart; + char *toend; + uchar *p; + + tostart = to; + if(sp->err) + goto err; + pointer = 0; + p = sp->p; + toend = to + Domlen; + for(len = 0; *p; len += pointer ? 0 : (n+1)){ + if((*p & 0xc0) == 0xc0){ + /* pointer to other spot in message */ + if(pointer++ > 10){ + sp->err = "pointer loop"; + goto err; + } + off = ((p[0]<<8) + p[1]) & 0x3ff; + p = sp->base + off; + if(p >= sp->ep){ + sp->err = "bad pointer"; + goto err; + } + n = 0; + continue; + } + n = *p++; + if(len + n < Domlen - 1){ + if(to + n > toend){ + sp->err = toolong; + goto err; + } + memmove(to, p, n); + to += n; + } + p += n; + if(*p){ + if(to >= toend){ + sp->err = toolong; + goto err; + } + *to++ = '.'; + } + } + *to = 0; + if(pointer) + sp->p += len + 2; /* + 2 for pointer */ + else + sp->p += len + 1; /* + 1 for the null domain */ + return tostart; +err: + *tostart = 0; + return tostart; +} + +/* + * convert the next RR from a message + */ +static RR* +convM2RR(Scan *sp) +{ + RR *rp; + int type; + int class; + uchar *data; + int len; + char dname[Domlen+1]; + Txt *t, **l; + +retry: + NAME(dname); + USHORT(type); + USHORT(class); + + rp = rralloc(type); + rp->owner = dnlookup(dname, class, 1); + rp->type = type; + + ULONG(rp->ttl); + rp->ttl += now; + USHORT(len); + data = sp->p; + + if(sp->p + len > sp->ep) + sp->err = toolong; + if(sp->err){ + rrfree(rp); + return 0; + } + + switch(type){ + default: + /* unknown type, just ignore it */ + sp->p = data + len; + rrfree(rp); + goto retry; + case Thinfo: + SYMBOL(rp->cpu); + SYMBOL(rp->os); + break; + case Tcname: + case Tmb: + case Tmd: + case Tmf: + case Tns: + rp->host = dnlookup(NAME(dname), Cin, 1); + break; + case Tmg: + case Tmr: + rp->mb = dnlookup(NAME(dname), Cin, 1); + break; + case Tminfo: + rp->rmb = dnlookup(NAME(dname), Cin, 1); + rp->mb = dnlookup(NAME(dname), Cin, 1); + break; + case Tmx: + USHORT(rp->pref); + rp->host = dnlookup(NAME(dname), Cin, 1); + break; + case Ta: + V4ADDR(rp->ip); + break; + case Taaaa: + V6ADDR(rp->ip); + break; + case Tptr: + rp->ptr = dnlookup(NAME(dname), Cin, 1); + break; + case Tsoa: + rp->host = dnlookup(NAME(dname), Cin, 1); + rp->rmb = dnlookup(NAME(dname), Cin, 1); + ULONG(rp->soa->serial); + ULONG(rp->soa->refresh); + ULONG(rp->soa->retry); + ULONG(rp->soa->expire); + ULONG(rp->soa->minttl); + break; + case Ttxt: + l = &rp->txt; + *l = nil; + while(sp->p-data < len){ + STRING(t); + *l = t; + l = &t->next; + } + break; + case Tnull: + BYTES(rp->null->data, rp->null->dlen); + break; + case Trp: + rp->rmb = dnlookup(NAME(dname), Cin, 1); + rp->rp = dnlookup(NAME(dname), Cin, 1); + 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); + rp->sig->signer = dnlookup(NAME(dname), Cin, 1); + 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; + } + if(sp->p - data != len) + sp->err = "bad RR len"; + return rp; +} + +/* + * convert the next question from a message + */ +static RR* +convM2Q(Scan *sp) +{ + char dname[Domlen+1]; + int type; + int class; + RR *rp; + + NAME(dname); + USHORT(type); + USHORT(class); + if(sp->err) + return 0; + + rp = rralloc(type); + rp->owner = dnlookup(dname, class, 1); + + return rp; +} + +static RR* +rrloop(Scan *sp, int count, int quest) +{ + int i; + static char errbuf[64]; + RR *first, *rp, **l; + + if(sp->err) + return 0; + l = &first; + first = 0; + for(i = 0; i < count; i++){ + rp = quest ? convM2Q(sp) : convM2RR(sp); + if(rp == 0) + break; + if(sp->err){ + rrfree(rp); + break; + } + *l = rp; + l = &rp->next; + } + return first; +} + +/* + * convert the next DNS from a message stream + */ +char* +convM2DNS(uchar *buf, int len, DNSmsg *m) +{ + Scan scan; + Scan *sp; + char *err; + + scan.base = buf; + scan.p = buf; + scan.ep = buf + len; + scan.err = 0; + sp = &scan; + memset(m, 0, sizeof(DNSmsg)); + USHORT(m->id); + USHORT(m->flags); + USHORT(m->qdcount); + USHORT(m->ancount); + USHORT(m->nscount); + USHORT(m->arcount); + m->qd = rrloop(sp, m->qdcount, 1); + m->an = rrloop(sp, m->ancount, 0); + m->ns = rrloop(sp, m->nscount, 0); + err = scan.err; /* live with bad ar's */ + m->ar = rrloop(sp, m->arcount, 0); + return err; +} |