plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

dns.c (7924B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <ip.h>
      4 #include "dat.h"
      5 #include "protos.h"
      6 
      7 enum
      8 {
      9 	/* RR types */
     10 	Ta=	1,
     11 	Tns=	2,
     12 	Tmd=	3,
     13 	Tmf=	4,
     14 	Tcname=	5,
     15 	Tsoa=	6,
     16 	Tmb=	7,
     17 	Tmg=	8,
     18 	Tmr=	9,
     19 	Tnull=	10,
     20 	Twks=	11,
     21 	Tptr=	12,
     22 	Thinfo=	13,
     23 	Tminfo=	14,
     24 	Tmx=	15,
     25 	Ttxt=	16,
     26 	Trp=	17,
     27 	Tsig=	24,
     28 	Tkey=	25,
     29 	Taaaa=	28,
     30 	Tcert=	37,
     31 
     32 	/* query types (all RR types are also queries) */
     33 	Tixfr=	251,	/* incremental zone transfer */
     34 	Taxfr=	252,	/* zone transfer */
     35 	Tmailb=	253,	/* { Tmb, Tmg, Tmr } */
     36 	Tall=	255,	/* all records */
     37 
     38 	/* classes */
     39 	Csym=	0,	/* internal symbols */
     40 	Cin=	1,	/* internet */
     41 	Ccs,		/* CSNET (obsolete) */
     42 	Cch,		/* Chaos net */
     43 	Chs,		/* Hesiod (?) */
     44 
     45 	/* class queries (all class types are also queries) */
     46 	Call=	255,	/* all classes */
     47 
     48 	/* opcodes */
     49 	Oquery=		0<<11,		/* normal query */
     50 	Oinverse=	1<<11,		/* inverse query */
     51 	Ostatus=	2<<11,		/* status request */
     52 	Onotify=	4<<11,		/* notify slaves of updates */
     53 	Omask=		0xf<<11,	/* mask for opcode */
     54 
     55 	/* response codes */
     56 	Rok=		0,
     57 	Rformat=	1,	/* format error */
     58 	Rserver=	2,	/* server failure (e.g. no answer from something) */
     59 	Rname=		3,	/* bad name */
     60 	Runimplimented=	4,	/* unimplemented */
     61 	Rrefused=	5,	/* we don't like you */
     62 	Rmask=		0xf,	/* mask for response */
     63 	Rtimeout=	0x10,	/* timeout sending (for internal use only) */
     64 
     65 	/* bits in flag word (other than opcode and response) */
     66 	Fresp=		1<<15,	/* message is a response */
     67 	Fauth=		1<<10,	/* true if an authoritative response */
     68 	Ftrunc=		1<<9,	/* truncated message */
     69 	Frecurse=	1<<8,	/* request recursion */
     70 	Fcanrec=	1<<7,	/* server can recurse */
     71 };
     72 
     73 typedef struct Hdr	Hdr;
     74 struct Hdr
     75 {
     76 	uchar	id[2];
     77 	uchar	flags[2];
     78 	uchar	qdcount[2];
     79 	uchar	ancount[2];
     80 	uchar	nscount[2];
     81 	uchar	arcount[2];
     82 };
     83 
     84 
     85 static char*
     86 getstr(uchar **pp, int *len, uchar *ep)
     87 {
     88 	uchar *p;
     89 	int n;
     90 
     91 	p = *pp;
     92 	n = *p++;
     93 	if(p+n > ep)
     94 		return nil;
     95 	*len = n;
     96 	*pp = p+n;
     97 	return (char*)p;
     98 }
     99 
    100 static char*
    101 getname(uchar **pp, uchar *bp, uchar *ep)
    102 {
    103 	static char buf[2][512];
    104 	static int toggle;
    105 	char *tostart, *to;
    106 	char *toend;
    107 	int len, off, pointer, n;
    108 	uchar *p;
    109 
    110 	to = buf[toggle^=1];
    111 	toend = to+sizeof buf[0];
    112 	tostart = to;
    113 	p = *pp;
    114 	len = 0;
    115 	pointer = 0;
    116 	while(p < ep && *p){
    117 		if((*p & 0xc0) == 0xc0){
    118 			/* pointer to another spot in message */
    119 			if(pointer == 0)
    120 				*pp = p + 2;
    121 			if(pointer++ > 10)
    122 				return nil;
    123 			off = ((p[0]<<8) + p[1]) & 0x3ff;
    124 			p = bp + off;
    125 			if(p >= ep)
    126 				return nil;
    127 			n = 0;
    128 			continue;
    129 		}
    130 		n = *p++;
    131 		if(to+n >= toend || p+n > ep)
    132 			return nil;
    133 		memmove(to, p, n);
    134 		to += n;
    135 		p += n;
    136 		if(*p){
    137 			if(to >= toend)
    138 				return nil;
    139 			*to++ = '.';
    140 		}
    141 	}
    142 	if(to >= toend || p >= ep)
    143 		return nil;
    144 	*to = 0;
    145 	if(!pointer)
    146 		*pp = ++p;
    147 	return tostart;
    148 }
    149 
    150 static char*
    151 tname(int type)
    152 {
    153 	static char buf[20];
    154 
    155 	switch(type){
    156 	case Ta:
    157 		return "a";
    158 	case Tns:
    159 		return "ns";
    160 	case Tmd:
    161 		return "md";
    162 	case Tmf:
    163 		return "mf";
    164 	case Tcname:
    165 		return "cname";
    166 	case Tsoa:
    167 		return "soa";
    168 	case Tmb:
    169 		return "mb";
    170 	case Tmg:
    171 		return "mg";
    172 	case Tmr:
    173 		return "mr";
    174 	case Tnull:
    175 		return "null";
    176 	case Twks:
    177 		return "wks";
    178 	case Tptr:
    179 		return "ptr";
    180 	case Thinfo:
    181 		return "hinfo";
    182 	case Tminfo:
    183 		return "minfo";
    184 	case Tmx:
    185 		return "mx";
    186 	case Ttxt:
    187 		return "txt";
    188 	case Trp:
    189 		return "rp";
    190 	case Tsig:
    191 		return "sig";
    192 	case Tkey:
    193 		return "key";
    194 	case Taaaa:
    195 		return "aaaa";
    196 	case Tcert:
    197 		return "cert";
    198 	case Tixfr:
    199 		return "ixfr";
    200 	case Taxfr:
    201 		return "axfr";
    202 	case Tmailb:
    203 		return "mailb";
    204 	case Tall:
    205 		return "all";
    206 	}
    207 	snprint(buf, sizeof buf, "%d", type);
    208 	return buf;
    209 }
    210 
    211 static char*
    212 cname(int class)
    213 {
    214 	static char buf[40];
    215 
    216 	if(class == Cin)
    217 		return "";
    218 
    219 	snprint(buf, sizeof buf, "class=%d", class);
    220 	return buf;
    221 }
    222 
    223 #define PR(name, len) utfnlen(name, len), name
    224 
    225 extern int sflag;
    226 
    227 static int
    228 p_seprint(Msg *m)
    229 {
    230 	int i, pref;
    231 	Hdr *h;
    232 	uchar *p, *ep;
    233 	int an, ns, ar, rlen;
    234 	char *name, *prefix;
    235 	int len1, len2;
    236 	char *sym1, *sym2, *sep;
    237 	int type;
    238 	static int first = 1;
    239 
    240 	if(first){
    241 		first = 0;
    242 		quotefmtinstall();
    243 	}
    244 
    245 	if(m->pe - m->ps < sizeof(Hdr))
    246 		return -1;
    247 	h = (Hdr*)m->ps;
    248 	m->pr = nil;
    249 
    250 	m->p = seprint(m->p, m->e, "id=%d flags=%04ux %d/%d/%d/%d",
    251 			NetS(h->id), NetS(h->flags),
    252 			NetS(h->qdcount), NetS(h->ancount),
    253 			NetS(h->nscount), NetS(h->arcount));
    254 	sep = ")\n\t";
    255 	if(sflag)
    256 		sep = ") ";
    257 	p = m->ps + sizeof(Hdr);
    258 	for(i=0; i<NetS(h->qdcount); i++){
    259 		name = getname(&p, m->ps, m->pe);
    260 		if(name == nil || p+4 > m->pe)
    261 			goto error;
    262 		m->p = seprint(m->p, m->e, "%sq=(%q %s%s",
    263 			sep, name, tname(NetS(p)), cname(NetS(p+2)));
    264 		p += 4;
    265 	}
    266 
    267 	an = NetS(h->ancount);
    268 	ns = NetS(h->nscount);
    269 	ar = NetS(h->arcount);
    270 	while(an+ns+ar > 0){
    271 		if(an > 0){
    272 			prefix = "an";
    273 			an--;
    274 		}else if(ns > 0){
    275 			prefix = "ns";
    276 			ns--;
    277 		}else{
    278 			prefix = "ar";
    279 			ar--;
    280 		}
    281 		name = getname(&p, m->ps, m->pe);
    282 		if(name == nil || p+10 > m->pe)
    283 			goto error;
    284 		type = NetS(p);
    285 		rlen = NetS(p+8);
    286 		ep = p+10+rlen;
    287 		if(ep > m->pe)
    288 			goto error;
    289 		m->p = seprint(m->p, m->e, "%s%s=(%q %s%s | ttl=%lud",
    290 			sep, prefix, name, tname(type), cname(NetS(p+2)), NetL(p+4), rlen);
    291 		p += 10;
    292 		switch(type){
    293 		default:
    294 			p = ep;
    295 			break;
    296 		case Thinfo:
    297 			sym1 = getstr(&p, &len1, ep);
    298 			if(sym1 == nil)
    299 				goto error;
    300 			sym2 = getstr(&p, &len2, ep);
    301 			if(sym2 == nil)
    302 				goto error;
    303 			m->p = seprint(m->p, m->e, " cpu=%.*s os=%.*s",
    304 				PR(sym1, len1),
    305 				PR(sym2, len2));
    306 			break;
    307 		case Tcname:
    308 		case Tmb:
    309 		case Tmd:
    310 		case Tmf:
    311 		case Tns:
    312 		case Tmg:
    313 		case Tmr:
    314 		case Tptr:
    315 			sym1 = getname(&p, m->ps, m->pe);
    316 			if(sym1 == nil)
    317 				goto error;
    318 			m->p = seprint(m->p, m->e, " %q", sym1);
    319 			break;
    320 		case Tminfo:
    321 			sym1 = getname(&p, m->ps, m->pe);
    322 			if(sym1 == nil)
    323 				goto error;
    324 			sym2 = getname(&p, m->ps, m->pe);
    325 			if(sym2 == nil)
    326 				goto error;
    327 			m->p = seprint(m->p, m->e, " %q %q", sym1, sym2);
    328 			break;
    329 		case Tmx:
    330 			if(p+2 >= ep)
    331 				goto error;
    332 			pref = NetS(p);
    333 			p += 2;
    334 			sym1 = getname(&p, m->ps, m->pe);
    335 			if(sym1 == nil)
    336 				goto error;
    337 			break;
    338 		case Ta:
    339 			if(p+4 > ep)
    340 				goto error;
    341 			m->p = seprint(m->p, m->e, " %V", p);
    342 			p += 4;
    343 			break;
    344 		case Taaaa:
    345 			if(p+16 > ep)
    346 				goto error;
    347 			m->p = seprint(m->p, m->e, " %I", p);
    348 			p += 16;
    349 			break;
    350 		case Tsoa:
    351 			sym1 = getname(&p, m->ps, m->pe);
    352 			if(sym1 == nil)
    353 				goto error;
    354 			sym2 = getname(&p, m->ps, m->pe);
    355 			if(sym2 == nil)
    356 				goto error;
    357 			if(p+20 > ep)
    358 				goto error;
    359 			m->p = seprint(m->p, m->e, " host=%q rmb=%q serial=%lud refresh=%lud retry=%lud expire=%lud minttl=%lud",
    360 				sym1, sym2, NetL(p), NetL(p+4),
    361 				NetL(p+8), NetL(p+12), NetL(p+16));
    362 			break;
    363 		case Ttxt:
    364 			while(p < ep){
    365 				sym1 = getstr(&p, &len1, ep);
    366 				if(sym1 == nil)
    367 					goto error;
    368 				m->p = seprint(m->p, m->e, " %.*q", PR(sym1, len1));
    369 			}
    370 			break;
    371 		case Tnull:
    372 			m->p = seprint(m->p, m->e, " %.*H", rlen, p);
    373 			p += rlen;
    374 			break;
    375 		case Trp:
    376 			sym1 = getname(&p, m->ps, m->pe);
    377 			if(sym1 == nil)
    378 				goto error;
    379 			sym2 = getname(&p, m->ps, m->pe);
    380 			if(sym2 == nil)
    381 				goto error;
    382 			m->p = seprint(m->p, m->e, " rmb=%q rp=%q", sym1, sym2);
    383 			break;
    384 		case Tkey:
    385 			if(rlen < 4)
    386 				goto error;
    387 			m->p = seprint(m->p, m->e, " flags=%04ux proto=%d alg=%d %.*H",
    388 				NetS(p), p[3], p[4], rlen-4, p+4);
    389 			p += rlen;
    390 			break;
    391 
    392 		case Tsig:
    393 			if(rlen < 18)
    394 				goto error;
    395 			m->p = seprint(m->p, m->e, " type=%d alg=%d labels=%d ttl=%lud exp=%lud incep=%lud tag=%d %.*H",
    396 				NetS(p), p[3], p[4], NetL(p+4), NetL(p+8), NetL(p+12), NetS(p+16),
    397 				rlen-18, p+18);
    398 			p += rlen;
    399 			break;
    400 
    401 		case Tcert:
    402 			if(rlen < 5)
    403 				goto error;
    404 			m->p = seprint(m->p, m->e, " type=%d tag=%d alg=%d %.*H",
    405 				NetS(p), NetS(p+2), p[4], rlen-5, p+5);
    406 			p += rlen;
    407 			break;
    408 		}
    409 		if(p != ep)
    410 			goto error;
    411 	}
    412 	return 0;
    413 
    414 error:
    415 	m->p = seprint(m->p, m->e, " packet error!");
    416 	return 0;
    417 }
    418 
    419 Proto dns =
    420 {
    421 	"dns",
    422 	nil,
    423 	nil,
    424 	p_seprint,
    425 	nil,
    426 	nil,
    427 	nil,
    428 	defaultframer
    429 };