plan9port

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

convM2DNS.c (7257B)


      1 #include <u.h>
      2 #include <libc.h>
      3 #include <ip.h>
      4 #include <bio.h>
      5 #include <ndb.h>
      6 #include "dns.h"
      7 
      8 typedef struct Scan	Scan;
      9 struct Scan
     10 {
     11 	uchar	*base;
     12 	uchar	*p;
     13 	uchar	*ep;
     14 	char	*err;
     15 };
     16 
     17 #define NAME(x)		gname(x, sp)
     18 #define SYMBOL(x)	(x = gsym(sp))
     19 #define STRING(x)	(x = gstr(sp))
     20 #define USHORT(x)	(x = gshort(sp))
     21 #define ULONG(x)	(x = glong(sp))
     22 #define UCHAR(x)	(x = gchar(sp))
     23 #define V4ADDR(x)	(x = gv4addr(sp))
     24 #define V6ADDR(x)	(x = gv6addr(sp))
     25 #define BYTES(x, y)	(y = gbytes(sp, &x, len - (sp->p - data)))
     26 
     27 static char *toolong = "too long";
     28 
     29 /*
     30  *  get a ushort/ulong
     31  */
     32 static ushort
     33 gchar(Scan *sp)
     34 {
     35 	ushort x;
     36 
     37 	if(sp->err)
     38 		return 0;
     39 	if(sp->ep - sp->p < 1){
     40 		sp->err = toolong;
     41 		return 0;
     42 	}
     43 	x = sp->p[0];
     44 	sp->p += 1;
     45 	return x;
     46 }
     47 static ushort
     48 gshort(Scan *sp)
     49 {
     50 	ushort x;
     51 
     52 	if(sp->err)
     53 		return 0;
     54 	if(sp->ep - sp->p < 2){
     55 		sp->err = toolong;
     56 		return 0;
     57 	}
     58 	x = (sp->p[0]<<8) | sp->p[1];
     59 	sp->p += 2;
     60 	return x;
     61 }
     62 static ulong
     63 glong(Scan *sp)
     64 {
     65 	ulong x;
     66 
     67 	if(sp->err)
     68 		return 0;
     69 	if(sp->ep - sp->p < 4){
     70 		sp->err = toolong;
     71 		return 0;
     72 	}
     73 	x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3];
     74 	sp->p += 4;
     75 	return x;
     76 }
     77 
     78 /*
     79  *  get an ip address
     80  */
     81 static DN*
     82 gv4addr(Scan *sp)
     83 {
     84 	char addr[32];
     85 
     86 	if(sp->err)
     87 		return 0;
     88 	if(sp->ep - sp->p < 4){
     89 		sp->err = toolong;
     90 		return 0;
     91 	}
     92 	snprint(addr, sizeof(addr), "%V", sp->p);
     93 	sp->p += 4;
     94 
     95 	return dnlookup(addr, Cin, 1);
     96 }
     97 static DN*
     98 gv6addr(Scan *sp)
     99 {
    100 	char addr[64];
    101 
    102 	if(sp->err)
    103 		return 0;
    104 	if(sp->ep - sp->p < IPaddrlen){
    105 		sp->err = toolong;
    106 		return 0;
    107 	}
    108 	snprint(addr, sizeof(addr), "%I", sp->p);
    109 	sp->p += IPaddrlen;
    110 
    111 	return dnlookup(addr, Cin, 1);
    112 }
    113 
    114 /*
    115  *  get a string.  make it an internal symbol.
    116  */
    117 static DN*
    118 gsym(Scan *sp)
    119 {
    120 	int n;
    121 	char sym[Strlen+1];
    122 
    123 	if(sp->err)
    124 		return 0;
    125 	n = *(sp->p++);
    126 	if(sp->p+n > sp->ep){
    127 		sp->err = toolong;
    128 		return 0;
    129 	}
    130 
    131 	if(n > Strlen){
    132 		sp->err = "illegal string";
    133 		return 0;
    134 	}
    135 	strncpy(sym, (char*)sp->p, n);
    136 	sym[n] = 0;
    137 	sp->p += n;
    138 
    139 	return dnlookup(sym, Csym, 1);
    140 }
    141 
    142 /*
    143  *  get a string.  don't make it an internal symbol.
    144  */
    145 static Txt*
    146 gstr(Scan *sp)
    147 {
    148 	int n;
    149 	char sym[Strlen+1];
    150 	Txt *t;
    151 
    152 	if(sp->err)
    153 		return 0;
    154 	n = *(sp->p++);
    155 	if(sp->p+n > sp->ep){
    156 		sp->err = toolong;
    157 		return 0;
    158 	}
    159 
    160 	if(n > Strlen){
    161 		sp->err = "illegal string";
    162 		return 0;
    163 	}
    164 	strncpy(sym, (char*)sp->p, n);
    165 	sym[n] = 0;
    166 	sp->p += n;
    167 
    168 	t = emalloc(sizeof(*t));
    169 	t->next = nil;
    170 	t->p = estrdup(sym);
    171 	return t;
    172 }
    173 
    174 /*
    175  *  get a sequence of bytes
    176  */
    177 static int
    178 gbytes(Scan *sp, uchar **p, int n)
    179 {
    180 	if(sp->err)
    181 		return 0;
    182 	if(sp->p+n > sp->ep || n < 0){
    183 		sp->err = toolong;
    184 		return 0;
    185 	}
    186 	*p = emalloc(n);
    187 	memmove(*p, sp->p, n);
    188 	sp->p += n;
    189 
    190 	return n;
    191 }
    192 
    193 /*
    194  *  get a domain name.  'to' must point to a buffer at least Domlen+1 long.
    195  */
    196 static char*
    197 gname(char *to, Scan *sp)
    198 {
    199 	int len, off;
    200 	int pointer;
    201 	int n;
    202 	char *tostart;
    203 	char *toend;
    204 	uchar *p;
    205 
    206 	tostart = to;
    207 	if(sp->err)
    208 		goto err;
    209 	pointer = 0;
    210 	p = sp->p;
    211 	toend = to + Domlen;
    212 	for(len = 0; *p; len += pointer ? 0 : (n+1)){
    213 		if((*p & 0xc0) == 0xc0){
    214 			/* pointer to other spot in message */
    215 			if(pointer++ > 10){
    216 				sp->err = "pointer loop";
    217 				goto err;
    218 			}
    219 			off = ((p[0]<<8) + p[1]) & 0x3ff;
    220 			p = sp->base + off;
    221 			if(p >= sp->ep){
    222 				sp->err = "bad pointer";
    223 				goto err;
    224 			}
    225 			n = 0;
    226 			continue;
    227 		}
    228 		n = *p++;
    229 		if(len + n < Domlen - 1){
    230 			if(to + n > toend){
    231 				sp->err = toolong;
    232 				goto err;
    233 			}
    234 			memmove(to, p, n);
    235 			to += n;
    236 		}
    237 		p += n;
    238 		if(*p){
    239 			if(to >= toend){
    240 				sp->err = toolong;
    241 				goto err;
    242 			}
    243 			*to++ = '.';
    244 		}
    245 	}
    246 	*to = 0;
    247 	if(pointer)
    248 		sp->p += len + 2;	/* + 2 for pointer */
    249 	else
    250 		sp->p += len + 1;	/* + 1 for the null domain */
    251 	return tostart;
    252 err:
    253 	*tostart = 0;
    254 	return tostart;
    255 }
    256 
    257 /*
    258  *  convert the next RR from a message
    259  */
    260 static RR*
    261 convM2RR(Scan *sp)
    262 {
    263 	RR *rp;
    264 	int type;
    265 	int class;
    266 	uchar *data;
    267 	int len;
    268 	char dname[Domlen+1];
    269 	Txt *t, **l;
    270 
    271 retry:
    272 	NAME(dname);
    273 	USHORT(type);
    274 	USHORT(class);
    275 
    276 	rp = rralloc(type);
    277 	rp->owner = dnlookup(dname, class, 1);
    278 	rp->type = type;
    279 
    280 	ULONG(rp->ttl);
    281 	rp->ttl += now;
    282 	USHORT(len);
    283 	data = sp->p;
    284 
    285 	if(sp->p + len > sp->ep)
    286 		sp->err = toolong;
    287 	if(sp->err){
    288 		rrfree(rp);
    289 		return 0;
    290 	}
    291 
    292 	switch(type){
    293 	default:
    294 		/* unknown type, just ignore it */
    295 		sp->p = data + len;
    296 		rrfree(rp);
    297 		goto retry;
    298 	case Thinfo:
    299 		SYMBOL(rp->cpu);
    300 		SYMBOL(rp->os);
    301 		break;
    302 	case Tcname:
    303 	case Tmb:
    304 	case Tmd:
    305 	case Tmf:
    306 	case Tns:
    307 		rp->host = dnlookup(NAME(dname), Cin, 1);
    308 		break;
    309 	case Tmg:
    310 	case Tmr:
    311 		rp->mb = dnlookup(NAME(dname), Cin, 1);
    312 		break;
    313 	case Tminfo:
    314 		rp->rmb = dnlookup(NAME(dname), Cin, 1);
    315 		rp->mb = dnlookup(NAME(dname), Cin, 1);
    316 		break;
    317 	case Tmx:
    318 		USHORT(rp->pref);
    319 		rp->host = dnlookup(NAME(dname), Cin, 1);
    320 		break;
    321 	case Ta:
    322 		V4ADDR(rp->ip);
    323 		break;
    324 	case Taaaa:
    325 		V6ADDR(rp->ip);
    326 		break;
    327 	case Tptr:
    328 		rp->ptr = dnlookup(NAME(dname), Cin, 1);
    329 		break;
    330 	case Tsoa:
    331 		rp->host = dnlookup(NAME(dname), Cin, 1);
    332 		rp->rmb = dnlookup(NAME(dname), Cin, 1);
    333 		ULONG(rp->soa->serial);
    334 		ULONG(rp->soa->refresh);
    335 		ULONG(rp->soa->retry);
    336 		ULONG(rp->soa->expire);
    337 		ULONG(rp->soa->minttl);
    338 		break;
    339 	case Ttxt:
    340 		l = &rp->txt;
    341 		*l = nil;
    342 		while(sp->p-data < len){
    343 			STRING(t);
    344 			*l = t;
    345 			l = &t->next;
    346 		}
    347 		break;
    348 	case Tnull:
    349 		BYTES(rp->null->data, rp->null->dlen);
    350 		break;
    351 	case Trp:
    352 		rp->rmb = dnlookup(NAME(dname), Cin, 1);
    353 		rp->rp = dnlookup(NAME(dname), Cin, 1);
    354 		break;
    355 	case Tkey:
    356 		USHORT(rp->key->flags);
    357 		UCHAR(rp->key->proto);
    358 		UCHAR(rp->key->alg);
    359 		BYTES(rp->key->data, rp->key->dlen);
    360 		break;
    361 	case Tsig:
    362 		USHORT(rp->sig->type);
    363 		UCHAR(rp->sig->alg);
    364 		UCHAR(rp->sig->labels);
    365 		ULONG(rp->sig->ttl);
    366 		ULONG(rp->sig->exp);
    367 		ULONG(rp->sig->incep);
    368 		USHORT(rp->sig->tag);
    369 		rp->sig->signer = dnlookup(NAME(dname), Cin, 1);
    370 		BYTES(rp->sig->data, rp->sig->dlen);
    371 		break;
    372 	case Tcert:
    373 		USHORT(rp->cert->type);
    374 		USHORT(rp->cert->tag);
    375 		UCHAR(rp->cert->alg);
    376 		BYTES(rp->cert->data, rp->cert->dlen);
    377 		break;
    378 	}
    379 	if(sp->p - data != len)
    380 		sp->err = "bad RR len";
    381 	return rp;
    382 }
    383 
    384 /*
    385  *  convert the next question from a message
    386  */
    387 static RR*
    388 convM2Q(Scan *sp)
    389 {
    390 	char dname[Domlen+1];
    391 	int type;
    392 	int class;
    393 	RR *rp;
    394 
    395 	NAME(dname);
    396 	USHORT(type);
    397 	USHORT(class);
    398 	if(sp->err)
    399 		return 0;
    400 
    401 	rp = rralloc(type);
    402 	rp->owner = dnlookup(dname, class, 1);
    403 
    404 	return rp;
    405 }
    406 
    407 static RR*
    408 rrloop(Scan *sp, int count, int quest)
    409 {
    410 	int i;
    411 	RR *first, *rp, **l;
    412 
    413 	if(sp->err)
    414 		return 0;
    415 	l = &first;
    416 	first = 0;
    417 	for(i = 0; i < count; i++){
    418 		rp = quest ? convM2Q(sp) : convM2RR(sp);
    419 		if(rp == 0)
    420 			break;
    421 		if(sp->err){
    422 			rrfree(rp);
    423 			break;
    424 		}
    425 		*l = rp;
    426 		l = &rp->next;
    427 	}
    428 	return first;
    429 }
    430 
    431 /*
    432  *  convert the next DNS from a message stream
    433  */
    434 char*
    435 convM2DNS(uchar *buf, int len, DNSmsg *m)
    436 {
    437 	Scan scan;
    438 	Scan *sp;
    439 	char *err;
    440 
    441 	scan.base = buf;
    442 	scan.p = buf;
    443 	scan.ep = buf + len;
    444 	scan.err = 0;
    445 	sp = &scan;
    446 	memset(m, 0, sizeof(DNSmsg));
    447 	USHORT(m->id);
    448 	USHORT(m->flags);
    449 	USHORT(m->qdcount);
    450 	USHORT(m->ancount);
    451 	USHORT(m->nscount);
    452 	USHORT(m->arcount);
    453 	m->qd = rrloop(sp, m->qdcount, 1);
    454 	m->an = rrloop(sp, m->ancount, 0);
    455 	m->ns = rrloop(sp, m->nscount, 0);
    456 	err = scan.err;				/* live with bad ar's */
    457 	m->ar = rrloop(sp, m->arcount, 0);
    458 	return err;
    459 }