xref: /plan9/sys/src/cmd/ndb/convM2DNS.c (revision 3e12c5d1bb89fc02707907988834ef147769ddaf)
1*3e12c5d1SDavid du Colombier #include <u.h>
2*3e12c5d1SDavid du Colombier #include <libc.h>
3*3e12c5d1SDavid du Colombier #include "dns.h"
4*3e12c5d1SDavid du Colombier 
5*3e12c5d1SDavid du Colombier typedef struct Scan	Scan;
6*3e12c5d1SDavid du Colombier struct Scan
7*3e12c5d1SDavid du Colombier {
8*3e12c5d1SDavid du Colombier 	uchar	*base;
9*3e12c5d1SDavid du Colombier 	uchar	*p;
10*3e12c5d1SDavid du Colombier 	uchar	*ep;
11*3e12c5d1SDavid du Colombier 	char	*err;
12*3e12c5d1SDavid du Colombier };
13*3e12c5d1SDavid du Colombier 
14*3e12c5d1SDavid du Colombier #define NAME(x)		gname(x, sp)
15*3e12c5d1SDavid du Colombier #define STRING(x)	(x = gstr(sp))
16*3e12c5d1SDavid du Colombier #define USHORT(x)	(x = gshort(sp))
17*3e12c5d1SDavid du Colombier #define ULONG(x)	(x = glong(sp))
18*3e12c5d1SDavid du Colombier #define ADDR(x)		(x = gaddr(sp))
19*3e12c5d1SDavid du Colombier 
20*3e12c5d1SDavid du Colombier static char *toolong = "too long";
21*3e12c5d1SDavid du Colombier 
22*3e12c5d1SDavid du Colombier /*
23*3e12c5d1SDavid du Colombier  *  get a ushort/ulong
24*3e12c5d1SDavid du Colombier  */
25*3e12c5d1SDavid du Colombier static ushort
26*3e12c5d1SDavid du Colombier gshort(Scan *sp)
27*3e12c5d1SDavid du Colombier {
28*3e12c5d1SDavid du Colombier 	ushort x;
29*3e12c5d1SDavid du Colombier 
30*3e12c5d1SDavid du Colombier 	if(sp->err)
31*3e12c5d1SDavid du Colombier 		return 0;
32*3e12c5d1SDavid du Colombier 	if(sp->ep - sp->p < 2){
33*3e12c5d1SDavid du Colombier 		sp->err = toolong;
34*3e12c5d1SDavid du Colombier 		return 0;
35*3e12c5d1SDavid du Colombier 	}
36*3e12c5d1SDavid du Colombier 	x = (sp->p[0]<<8) | sp->p[1];
37*3e12c5d1SDavid du Colombier 	sp->p += 2;
38*3e12c5d1SDavid du Colombier 	return x;
39*3e12c5d1SDavid du Colombier }
40*3e12c5d1SDavid du Colombier static ulong
41*3e12c5d1SDavid du Colombier glong(Scan *sp)
42*3e12c5d1SDavid du Colombier {
43*3e12c5d1SDavid du Colombier 	ulong x;
44*3e12c5d1SDavid du Colombier 
45*3e12c5d1SDavid du Colombier 	if(sp->err)
46*3e12c5d1SDavid du Colombier 		return 0;
47*3e12c5d1SDavid du Colombier 	if(sp->ep - sp->p < 4){
48*3e12c5d1SDavid du Colombier 		sp->err = toolong;
49*3e12c5d1SDavid du Colombier 		return 0;
50*3e12c5d1SDavid du Colombier 	}
51*3e12c5d1SDavid du Colombier 	x = (sp->p[0]<<24) | (sp->p[1]<<16) | (sp->p[2]<<8) | sp->p[3];
52*3e12c5d1SDavid du Colombier 	sp->p += 4;
53*3e12c5d1SDavid du Colombier 	return x;
54*3e12c5d1SDavid du Colombier }
55*3e12c5d1SDavid du Colombier 
56*3e12c5d1SDavid du Colombier /*
57*3e12c5d1SDavid du Colombier  *  get an ip address
58*3e12c5d1SDavid du Colombier  */
59*3e12c5d1SDavid du Colombier static DN*
60*3e12c5d1SDavid du Colombier gaddr(Scan *sp)
61*3e12c5d1SDavid du Colombier {
62*3e12c5d1SDavid du Colombier 	char addr[32];
63*3e12c5d1SDavid du Colombier 
64*3e12c5d1SDavid du Colombier 	if(sp->err)
65*3e12c5d1SDavid du Colombier 		return 0;
66*3e12c5d1SDavid du Colombier 	if(sp->ep - sp->p < 4){
67*3e12c5d1SDavid du Colombier 		sp->err = toolong;
68*3e12c5d1SDavid du Colombier 		return 0;
69*3e12c5d1SDavid du Colombier 	}
70*3e12c5d1SDavid du Colombier 	sprint(addr, "%I", sp->p);
71*3e12c5d1SDavid du Colombier 	sp->p += 4;
72*3e12c5d1SDavid du Colombier 
73*3e12c5d1SDavid du Colombier 	return dnlookup(addr, Cin, 1);
74*3e12c5d1SDavid du Colombier }
75*3e12c5d1SDavid du Colombier 
76*3e12c5d1SDavid du Colombier /*
77*3e12c5d1SDavid du Colombier  *  get a string.  make it an internal symbol.
78*3e12c5d1SDavid du Colombier  */
79*3e12c5d1SDavid du Colombier static DN*
80*3e12c5d1SDavid du Colombier gstr(Scan *sp)
81*3e12c5d1SDavid du Colombier {
82*3e12c5d1SDavid du Colombier 	int n;
83*3e12c5d1SDavid du Colombier 	char sym[Strlen+1];
84*3e12c5d1SDavid du Colombier 
85*3e12c5d1SDavid du Colombier 	if(sp->err)
86*3e12c5d1SDavid du Colombier 		return 0;
87*3e12c5d1SDavid du Colombier 	n = *(sp->p++);
88*3e12c5d1SDavid du Colombier 	if(sp->p+n > sp->ep){
89*3e12c5d1SDavid du Colombier 		sp->err = toolong;
90*3e12c5d1SDavid du Colombier 		return 0;
91*3e12c5d1SDavid du Colombier 	}
92*3e12c5d1SDavid du Colombier 
93*3e12c5d1SDavid du Colombier 	if(n > Strlen){
94*3e12c5d1SDavid du Colombier 		sp->err = "illegal string";
95*3e12c5d1SDavid du Colombier 		return 0;
96*3e12c5d1SDavid du Colombier 	}
97*3e12c5d1SDavid du Colombier 	strncpy(sym, (char*)sp->p, n);
98*3e12c5d1SDavid du Colombier 	sym[n] = 0;
99*3e12c5d1SDavid du Colombier 	sp->p += n;
100*3e12c5d1SDavid du Colombier 
101*3e12c5d1SDavid du Colombier 	return dnlookup(sym, Csym, 1);
102*3e12c5d1SDavid du Colombier }
103*3e12c5d1SDavid du Colombier 
104*3e12c5d1SDavid du Colombier /*
105*3e12c5d1SDavid du Colombier  *  get a domain name.  'to' must point to a buffer at least Domlen+1 long.
106*3e12c5d1SDavid du Colombier  */
107*3e12c5d1SDavid du Colombier static char*
108*3e12c5d1SDavid du Colombier gname(char *to, Scan *sp)
109*3e12c5d1SDavid du Colombier {
110*3e12c5d1SDavid du Colombier 	int len, off;
111*3e12c5d1SDavid du Colombier 	int pointer;
112*3e12c5d1SDavid du Colombier 	int n;
113*3e12c5d1SDavid du Colombier 	char *tostart;
114*3e12c5d1SDavid du Colombier 	char *toend;
115*3e12c5d1SDavid du Colombier 	uchar *p;
116*3e12c5d1SDavid du Colombier 
117*3e12c5d1SDavid du Colombier 	tostart = to;
118*3e12c5d1SDavid du Colombier 	if(sp->err)
119*3e12c5d1SDavid du Colombier 		goto err;
120*3e12c5d1SDavid du Colombier 	pointer = 0;
121*3e12c5d1SDavid du Colombier 	p = sp->p;
122*3e12c5d1SDavid du Colombier 	toend = to + Domlen;
123*3e12c5d1SDavid du Colombier 	for(len = 0; *p; len += pointer ? 0 : (n+1)){
124*3e12c5d1SDavid du Colombier 		if((*p & 0xc0) == 0xc0){
125*3e12c5d1SDavid du Colombier 			/* pointer to other spot in message */
126*3e12c5d1SDavid du Colombier 			if(pointer++ > 10){
127*3e12c5d1SDavid du Colombier 				sp->err = "pointer loop";
128*3e12c5d1SDavid du Colombier 				goto err;
129*3e12c5d1SDavid du Colombier 			}
130*3e12c5d1SDavid du Colombier 			off = ((p[0]<<8) + p[1]) & 0x3ff;
131*3e12c5d1SDavid du Colombier 			p = sp->base + off;
132*3e12c5d1SDavid du Colombier 			if(p >= sp->ep){
133*3e12c5d1SDavid du Colombier 				sp->err = "bad pointer";
134*3e12c5d1SDavid du Colombier 				goto err;
135*3e12c5d1SDavid du Colombier 			}
136*3e12c5d1SDavid du Colombier 			n = 0;
137*3e12c5d1SDavid du Colombier 			continue;
138*3e12c5d1SDavid du Colombier 		}
139*3e12c5d1SDavid du Colombier 		n = *p++;
140*3e12c5d1SDavid du Colombier 		if(len + n < Domlen - 1){
141*3e12c5d1SDavid du Colombier 			if(to + n > toend){
142*3e12c5d1SDavid du Colombier 				sp->err = toolong;
143*3e12c5d1SDavid du Colombier 				goto err;
144*3e12c5d1SDavid du Colombier 			}
145*3e12c5d1SDavid du Colombier 			memmove(to, p, n);
146*3e12c5d1SDavid du Colombier 			to += n;
147*3e12c5d1SDavid du Colombier 		}
148*3e12c5d1SDavid du Colombier 		p += n;
149*3e12c5d1SDavid du Colombier 		if(*p){
150*3e12c5d1SDavid du Colombier 			if(to >= toend){
151*3e12c5d1SDavid du Colombier 				sp->err = toolong;
152*3e12c5d1SDavid du Colombier 				goto err;
153*3e12c5d1SDavid du Colombier 			}
154*3e12c5d1SDavid du Colombier 			*to++ = '.';
155*3e12c5d1SDavid du Colombier 		}
156*3e12c5d1SDavid du Colombier 	}
157*3e12c5d1SDavid du Colombier 	*to = 0;
158*3e12c5d1SDavid du Colombier 	if(pointer)
159*3e12c5d1SDavid du Colombier 		sp->p += len + 2;	/* + 2 for pointer */
160*3e12c5d1SDavid du Colombier 	else
161*3e12c5d1SDavid du Colombier 		sp->p += len + 1;	/* + 1 for the null domain */
162*3e12c5d1SDavid du Colombier 	return tostart;
163*3e12c5d1SDavid du Colombier err:
164*3e12c5d1SDavid du Colombier 	*tostart = 0;
165*3e12c5d1SDavid du Colombier 	return tostart;
166*3e12c5d1SDavid du Colombier }
167*3e12c5d1SDavid du Colombier 
168*3e12c5d1SDavid du Colombier /*
169*3e12c5d1SDavid du Colombier  *  convert the next RR from a message
170*3e12c5d1SDavid du Colombier  */
171*3e12c5d1SDavid du Colombier static RR*
172*3e12c5d1SDavid du Colombier convM2RR(Scan *sp)
173*3e12c5d1SDavid du Colombier {
174*3e12c5d1SDavid du Colombier 	RR *rp;
175*3e12c5d1SDavid du Colombier 	int type;
176*3e12c5d1SDavid du Colombier 	int class;
177*3e12c5d1SDavid du Colombier 	uchar *data;
178*3e12c5d1SDavid du Colombier 	int len;
179*3e12c5d1SDavid du Colombier 	char dname[Domlen+1];
180*3e12c5d1SDavid du Colombier 
181*3e12c5d1SDavid du Colombier 	NAME(dname);
182*3e12c5d1SDavid du Colombier 	USHORT(type);
183*3e12c5d1SDavid du Colombier 	USHORT(class);
184*3e12c5d1SDavid du Colombier 
185*3e12c5d1SDavid du Colombier 	rp = rralloc(type);
186*3e12c5d1SDavid du Colombier 	rp->owner = dnlookup(dname, class, 1);
187*3e12c5d1SDavid du Colombier 	rp->type = type;
188*3e12c5d1SDavid du Colombier 
189*3e12c5d1SDavid du Colombier 	ULONG(rp->ttl);
190*3e12c5d1SDavid du Colombier 	USHORT(len);
191*3e12c5d1SDavid du Colombier 	data = sp->p;
192*3e12c5d1SDavid du Colombier 	switch(type){
193*3e12c5d1SDavid du Colombier 	case Thinfo:
194*3e12c5d1SDavid du Colombier 		STRING(rp->cpu);
195*3e12c5d1SDavid du Colombier 		STRING(rp->os);
196*3e12c5d1SDavid du Colombier 		break;
197*3e12c5d1SDavid du Colombier 	case Tcname:
198*3e12c5d1SDavid du Colombier 	case Tmb:
199*3e12c5d1SDavid du Colombier 	case Tmd:
200*3e12c5d1SDavid du Colombier 	case Tmf:
201*3e12c5d1SDavid du Colombier 	case Tns:
202*3e12c5d1SDavid du Colombier 		rp->host = dnlookup(NAME(dname), Cin, 1);
203*3e12c5d1SDavid du Colombier 		break;
204*3e12c5d1SDavid du Colombier 	case Tmg:
205*3e12c5d1SDavid du Colombier 	case Tmr:
206*3e12c5d1SDavid du Colombier 		rp->mb = dnlookup(NAME(dname), Cin, 1);
207*3e12c5d1SDavid du Colombier 		break;
208*3e12c5d1SDavid du Colombier 	case Tminfo:
209*3e12c5d1SDavid du Colombier 		rp->rmb = dnlookup(NAME(dname), Cin, 1);
210*3e12c5d1SDavid du Colombier 		rp->mb = dnlookup(NAME(dname), Cin, 1);
211*3e12c5d1SDavid du Colombier 		break;
212*3e12c5d1SDavid du Colombier 	case Tmx:
213*3e12c5d1SDavid du Colombier 		USHORT(rp->pref);
214*3e12c5d1SDavid du Colombier 		rp->host = dnlookup(NAME(dname), Cin, 1);
215*3e12c5d1SDavid du Colombier 		break;
216*3e12c5d1SDavid du Colombier 	case Ta:
217*3e12c5d1SDavid du Colombier 		ADDR(rp->ip);
218*3e12c5d1SDavid du Colombier 		break;
219*3e12c5d1SDavid du Colombier 	case Tptr:
220*3e12c5d1SDavid du Colombier 		rp->ptr = dnlookup(NAME(dname), Cin, 1);
221*3e12c5d1SDavid du Colombier 		break;
222*3e12c5d1SDavid du Colombier 	case Tsoa:
223*3e12c5d1SDavid du Colombier 		rp->host = dnlookup(NAME(dname), Cin, 1);
224*3e12c5d1SDavid du Colombier 		rp->rmb = dnlookup(NAME(dname), Cin, 1);
225*3e12c5d1SDavid du Colombier 		ULONG(rp->soa->serial);
226*3e12c5d1SDavid du Colombier 		ULONG(rp->soa->refresh);
227*3e12c5d1SDavid du Colombier 		ULONG(rp->soa->retry);
228*3e12c5d1SDavid du Colombier 		ULONG(rp->soa->expire);
229*3e12c5d1SDavid du Colombier 		ULONG(rp->soa->minttl);
230*3e12c5d1SDavid du Colombier 		break;
231*3e12c5d1SDavid du Colombier 	}
232*3e12c5d1SDavid du Colombier 	if(sp->p - data != len)
233*3e12c5d1SDavid du Colombier 		sp->err = "bad RR len";
234*3e12c5d1SDavid du Colombier 	return rp;
235*3e12c5d1SDavid du Colombier }
236*3e12c5d1SDavid du Colombier 
237*3e12c5d1SDavid du Colombier /*
238*3e12c5d1SDavid du Colombier  *  convert the next question from a message
239*3e12c5d1SDavid du Colombier  */
240*3e12c5d1SDavid du Colombier static RR*
241*3e12c5d1SDavid du Colombier convM2Q(Scan *sp)
242*3e12c5d1SDavid du Colombier {
243*3e12c5d1SDavid du Colombier 	char dname[Domlen+1];
244*3e12c5d1SDavid du Colombier 	int type;
245*3e12c5d1SDavid du Colombier 	int class;
246*3e12c5d1SDavid du Colombier 	RR *rp;
247*3e12c5d1SDavid du Colombier 
248*3e12c5d1SDavid du Colombier 	NAME(dname);
249*3e12c5d1SDavid du Colombier 	USHORT(type);
250*3e12c5d1SDavid du Colombier 	USHORT(class);
251*3e12c5d1SDavid du Colombier 	if(sp->err)
252*3e12c5d1SDavid du Colombier 		return 0;
253*3e12c5d1SDavid du Colombier 
254*3e12c5d1SDavid du Colombier 	rp = rralloc(type);
255*3e12c5d1SDavid du Colombier 	rp->owner = dnlookup(dname, class, 1);
256*3e12c5d1SDavid du Colombier 
257*3e12c5d1SDavid du Colombier 	return rp;
258*3e12c5d1SDavid du Colombier }
259*3e12c5d1SDavid du Colombier 
260*3e12c5d1SDavid du Colombier static RR*
261*3e12c5d1SDavid du Colombier rrloop(Scan *sp, int count, int quest)
262*3e12c5d1SDavid du Colombier {
263*3e12c5d1SDavid du Colombier 	int i;
264*3e12c5d1SDavid du Colombier 	static char errbuf[64];
265*3e12c5d1SDavid du Colombier 	RR *first, *rp, **l;
266*3e12c5d1SDavid du Colombier 
267*3e12c5d1SDavid du Colombier 	if(sp->err)
268*3e12c5d1SDavid du Colombier 		return 0;
269*3e12c5d1SDavid du Colombier 	l = &first;
270*3e12c5d1SDavid du Colombier 	first = 0;
271*3e12c5d1SDavid du Colombier 	for(i = 0; i < count; i++){
272*3e12c5d1SDavid du Colombier 		rp = quest ? convM2Q(sp) : convM2RR(sp);
273*3e12c5d1SDavid du Colombier 		if(sp->err){
274*3e12c5d1SDavid du Colombier 			rrfree(rp);
275*3e12c5d1SDavid du Colombier 			break;
276*3e12c5d1SDavid du Colombier 		}
277*3e12c5d1SDavid du Colombier 		*l = rp;
278*3e12c5d1SDavid du Colombier 		l = &rp->next;
279*3e12c5d1SDavid du Colombier 	}
280*3e12c5d1SDavid du Colombier 	return first;
281*3e12c5d1SDavid du Colombier }
282*3e12c5d1SDavid du Colombier 
283*3e12c5d1SDavid du Colombier /*
284*3e12c5d1SDavid du Colombier  *  convert the next DNS from a message stream
285*3e12c5d1SDavid du Colombier  */
286*3e12c5d1SDavid du Colombier char*
287*3e12c5d1SDavid du Colombier convM2DNS(uchar *buf, int len, DNSmsg *m)
288*3e12c5d1SDavid du Colombier {
289*3e12c5d1SDavid du Colombier 	Scan scan;
290*3e12c5d1SDavid du Colombier 	Scan *sp;
291*3e12c5d1SDavid du Colombier 
292*3e12c5d1SDavid du Colombier 	scan.base = buf;
293*3e12c5d1SDavid du Colombier 	scan.p = buf;
294*3e12c5d1SDavid du Colombier 	scan.ep = buf + len;
295*3e12c5d1SDavid du Colombier 	scan.err = 0;
296*3e12c5d1SDavid du Colombier 	sp = &scan;
297*3e12c5d1SDavid du Colombier 	memset(m, 0, sizeof(DNSmsg));
298*3e12c5d1SDavid du Colombier 	USHORT(m->id);
299*3e12c5d1SDavid du Colombier 	USHORT(m->flags);
300*3e12c5d1SDavid du Colombier 	USHORT(m->qdcount);
301*3e12c5d1SDavid du Colombier 	USHORT(m->ancount);
302*3e12c5d1SDavid du Colombier 	USHORT(m->nscount);
303*3e12c5d1SDavid du Colombier 	USHORT(m->arcount);
304*3e12c5d1SDavid du Colombier 	m->qd = rrloop(sp, m->qdcount, 1);
305*3e12c5d1SDavid du Colombier 	m->an = rrloop(sp, m->ancount, 0);
306*3e12c5d1SDavid du Colombier 	m->ns = rrloop(sp, m->nscount, 0);
307*3e12c5d1SDavid du Colombier 	m->ar = rrloop(sp, m->arcount, 0);
308*3e12c5d1SDavid du Colombier 	return scan.err;
309*3e12c5d1SDavid du Colombier }
310