commit 7e36b43bba16df64a08c13358ba2a70ae9001770 from: Russ Cox date: Thu Jul 24 15:03:42 2008 UTC snoopy: add support for DNS packets commit - 6f61477d2607eb7df816aae3e2e94fb1697554c8 commit + 7e36b43bba16df64a08c13358ba2a70ae9001770 blob - /dev/null blob + 144a494972b10c4261c3979ea040fce4120a5493 (mode 644) --- /dev/null +++ src/cmd/ip/snoopy/dns.c @@ -0,0 +1,429 @@ +#include +#include +#include +#include "dat.h" +#include "protos.h" + +enum +{ + /* RR types */ + Ta= 1, + Tns= 2, + Tmd= 3, + Tmf= 4, + Tcname= 5, + Tsoa= 6, + Tmb= 7, + Tmg= 8, + Tmr= 9, + Tnull= 10, + Twks= 11, + Tptr= 12, + Thinfo= 13, + Tminfo= 14, + Tmx= 15, + Ttxt= 16, + Trp= 17, + Tsig= 24, + Tkey= 25, + Taaaa= 28, + Tcert= 37, + + /* query types (all RR types are also queries) */ + Tixfr= 251, /* incremental zone transfer */ + Taxfr= 252, /* zone transfer */ + Tmailb= 253, /* { Tmb, Tmg, Tmr } */ + Tall= 255, /* all records */ + + /* classes */ + Csym= 0, /* internal symbols */ + Cin= 1, /* internet */ + Ccs, /* CSNET (obsolete) */ + Cch, /* Chaos net */ + Chs, /* Hesiod (?) */ + + /* class queries (all class types are also queries) */ + Call= 255, /* all classes */ + + /* opcodes */ + Oquery= 0<<11, /* normal query */ + Oinverse= 1<<11, /* inverse query */ + Ostatus= 2<<11, /* status request */ + Onotify= 4<<11, /* notify slaves of updates */ + Omask= 0xf<<11, /* mask for opcode */ + + /* response codes */ + Rok= 0, + Rformat= 1, /* format error */ + Rserver= 2, /* server failure (e.g. no answer from something) */ + Rname= 3, /* bad name */ + Runimplimented= 4, /* unimplemented */ + Rrefused= 5, /* we don't like you */ + Rmask= 0xf, /* mask for response */ + Rtimeout= 0x10, /* timeout sending (for internal use only) */ + + /* bits in flag word (other than opcode and response) */ + Fresp= 1<<15, /* message is a response */ + Fauth= 1<<10, /* true if an authoritative response */ + Ftrunc= 1<<9, /* truncated message */ + Frecurse= 1<<8, /* request recursion */ + Fcanrec= 1<<7, /* server can recurse */ +}; + +typedef struct Hdr Hdr; +struct Hdr +{ + uchar id[2]; + uchar flags[2]; + uchar qdcount[2]; + uchar ancount[2]; + uchar nscount[2]; + uchar arcount[2]; +}; + + +static char* +getstr(uchar **pp, int *len, uchar *ep) +{ + uchar *p; + int n; + + p = *pp; + n = *p++; + if(p+n > ep) + return nil; + *len = n; + *pp = p+n; + return (char*)p; +} + +static char* +getname(uchar **pp, uchar *bp, uchar *ep) +{ + static char buf[2][512]; + static int toggle; + char *tostart, *to; + char *toend; + int len, off, pointer, n; + uchar *p; + + to = buf[toggle^=1]; + toend = to+sizeof buf[0]; + tostart = to; + p = *pp; + len = 0; + pointer = 0; + while(p < ep && *p){ + if((*p & 0xc0) == 0xc0){ + /* pointer to another spot in message */ + if(pointer == 0) + *pp = p + 2; + if(pointer++ > 10) + return nil; + off = ((p[0]<<8) + p[1]) & 0x3ff; + p = bp + off; + if(p >= ep) + return nil; + n = 0; + continue; + } + n = *p++; + if(to+n >= toend || p+n > ep) + return nil; + memmove(to, p, n); + to += n; + p += n; + if(*p){ + if(to >= toend) + return nil; + *to++ = '.'; + } + } + if(to >= toend || p >= ep) + return nil; + *to = 0; + if(!pointer) + *pp = ++p; + return tostart; +} + +static char* +tname(int type) +{ + static char buf[20]; + + switch(type){ + case Ta: + return "a"; + case Tns: + return "ns"; + case Tmd: + return "md"; + case Tmf: + return "mf"; + case Tcname: + return "cname"; + case Tsoa: + return "soa"; + case Tmb: + return "mb"; + case Tmg: + return "mg"; + case Tmr: + return "mr"; + case Tnull: + return "null"; + case Twks: + return "wks"; + case Tptr: + return "ptr"; + case Thinfo: + return "hinfo"; + case Tminfo: + return "minfo"; + case Tmx: + return "mx"; + case Ttxt: + return "txt"; + case Trp: + return "rp"; + case Tsig: + return "sig"; + case Tkey: + return "key"; + case Taaaa: + return "aaaa"; + case Tcert: + return "cert"; + case Tixfr: + return "ixfr"; + case Taxfr: + return "axfr"; + case Tmailb: + return "mailb"; + case Tall: + return "all"; + } + snprint(buf, sizeof buf, "%d", type); + return buf; +} + +static char* +cname(int class) +{ + static char buf[40]; + + if(class == Cin) + return ""; + + snprint(buf, sizeof buf, "class=%d", class); + return buf; +} + +#define PR(name, len) utfnlen(name, len), name + +extern int sflag; + +static int +p_seprint(Msg *m) +{ + int i, pref; + Hdr *h; + uchar *p, *ep; + int an, ns, ar, rlen; + char *name, *prefix; + int len1, len2; + char *sym1, *sym2, *sep; + int type; + static int first = 1; + + if(first){ + first = 0; + quotefmtinstall(); + } + + if(m->pe - m->ps < sizeof(Hdr)) + return -1; + h = (Hdr*)m->ps; + m->pr = nil; + + m->p = seprint(m->p, m->e, "id=%d flags=%04ux %d/%d/%d/%d", + NetS(h->id), NetS(h->flags), + NetS(h->qdcount), NetS(h->ancount), + NetS(h->nscount), NetS(h->arcount)); + sep = ")\n\t"; + if(sflag) + sep = ") "; + p = m->ps + sizeof(Hdr); + for(i=0; iqdcount); i++){ + name = getname(&p, m->ps, m->pe); + if(name == nil || p+4 > m->pe) + goto error; + m->p = seprint(m->p, m->e, "%sq=(%q %s%s", + sep, name, tname(NetS(p)), cname(NetS(p+2))); + p += 4; + } + + an = NetS(h->ancount); + ns = NetS(h->nscount); + ar = NetS(h->arcount); + while(an+ns+ar > 0){ + if(an > 0){ + prefix = "an"; + an--; + }else if(ns > 0){ + prefix = "ns"; + ns--; + }else{ + prefix = "ar"; + ar--; + } + name = getname(&p, m->ps, m->pe); + if(name == nil || p+10 > m->pe) + goto error; + type = NetS(p); + rlen = NetS(p+8); + ep = p+10+rlen; + if(ep > m->pe) + goto error; + m->p = seprint(m->p, m->e, "%s%s=(%q %s%s | ttl=%lud", + sep, prefix, name, tname(type), cname(NetS(p+2)), NetL(p+4), rlen); + p += 10; + switch(type){ + default: + p = ep; + break; + case Thinfo: + sym1 = getstr(&p, &len1, ep); + if(sym1 == nil) + goto error; + sym2 = getstr(&p, &len2, ep); + if(sym2 == nil) + goto error; + m->p = seprint(m->p, m->e, " cpu=%.*s os=%.*s", + PR(sym1, len1), + PR(sym2, len2)); + break; + case Tcname: + case Tmb: + case Tmd: + case Tmf: + case Tns: + case Tmg: + case Tmr: + case Tptr: + sym1 = getname(&p, m->ps, m->pe); + if(sym1 == nil) + goto error; + m->p = seprint(m->p, m->e, " %q", sym1); + break; + case Tminfo: + sym1 = getname(&p, m->ps, m->pe); + if(sym1 == nil) + goto error; + sym2 = getname(&p, m->ps, m->pe); + if(sym2 == nil) + goto error; + m->p = seprint(m->p, m->e, " %q %q", sym1, sym2); + break; + case Tmx: + if(p+2 >= ep) + goto error; + pref = NetS(p); + p += 2; + sym1 = getname(&p, m->ps, m->pe); + if(sym1 == nil) + goto error; + break; + case Ta: + if(p+4 > ep) + goto error; + m->p = seprint(m->p, m->e, " %V", p); + p += 4; + break; + case Taaaa: + if(p+16 > ep) + goto error; + m->p = seprint(m->p, m->e, " %I", p); + p += 16; + break; + case Tsoa: + sym1 = getname(&p, m->ps, m->pe); + if(sym1 == nil) + goto error; + sym2 = getname(&p, m->ps, m->pe); + if(sym2 == nil) + goto error; + if(p+20 > ep) + goto error; + m->p = seprint(m->p, m->e, " host=%q rmb=%q serial=%lud refresh=%lud retry=%lud expire=%lud minttl=%lud", + sym1, sym2, NetL(p), NetL(p+4), + NetL(p+8), NetL(p+12), NetL(p+16)); + break; + case Ttxt: + while(p < ep){ + sym1 = getstr(&p, &len1, ep); + if(sym1 == nil) + goto error; + m->p = seprint(m->p, m->e, " %.*q", PR(sym1, len1)); + } + break; + case Tnull: + m->p = seprint(m->p, m->e, " %.*H", rlen, p); + p += rlen; + break; + case Trp: + sym1 = getname(&p, m->ps, m->pe); + if(sym1 == nil) + goto error; + sym2 = getname(&p, m->ps, m->pe); + if(sym2 == nil) + goto error; + m->p = seprint(m->p, m->e, " rmb=%q rp=%q", sym1, sym2); + break; + case Tkey: + if(rlen < 4) + goto error; + m->p = seprint(m->p, m->e, " flags=%04ux proto=%d alg=%d %.*H", + NetS(p), p[3], p[4], rlen-4, p+4); + p += rlen; + break; + + case Tsig: + if(rlen < 18) + goto error; + m->p = seprint(m->p, m->e, " type=%d alg=%d labels=%d ttl=%lud exp=%lud incep=%lud tag=%d %.*H", + NetS(p), p[3], p[4], NetL(p+4), NetL(p+8), NetL(p+12), NetS(p+16), + rlen-18, p+18); + p += rlen; + break; + + case Tcert: + if(rlen < 5) + goto error; + m->p = seprint(m->p, m->e, " type=%d tag=%d alg=%d %.*H", + NetS(p), NetS(p+2), p[4], rlen-5, p+5); + p += rlen; + break; + } + if(p != ep) + goto error; + } + return 0; + +error: + m->p = seprint(m->p, m->e, " packet error!"); + return 0; +} + +Proto dns = +{ + "dns", + nil, + nil, + p_seprint, + nil, + nil, + nil, + defaultframer +};