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