blob: 144a494972b10c4261c3979ea040fce4120a5493 [file] [log] [blame]
#include <u.h>
#include <libc.h>
#include <ip.h>
#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; i<NetS(h->qdcount); 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
};