xref: /plan9-contrib/sys/src/cmd/aquarela/nbnsconv.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include <u.h>
2*8ccd4a63SDavid du Colombier #include <libc.h>
3*8ccd4a63SDavid du Colombier #include <ip.h>
4*8ccd4a63SDavid du Colombier #include <thread.h>
5*8ccd4a63SDavid du Colombier #include "netbios.h"
6*8ccd4a63SDavid du Colombier 
7*8ccd4a63SDavid du Colombier void
nbnsmessagequestionfree(NbnsMessageQuestion ** qp)8*8ccd4a63SDavid du Colombier nbnsmessagequestionfree(NbnsMessageQuestion **qp)
9*8ccd4a63SDavid du Colombier {
10*8ccd4a63SDavid du Colombier 	NbnsMessageQuestion *q = *qp;
11*8ccd4a63SDavid du Colombier 	if (q) {
12*8ccd4a63SDavid du Colombier 		free(q);
13*8ccd4a63SDavid du Colombier 		*qp = nil;
14*8ccd4a63SDavid du Colombier 	}
15*8ccd4a63SDavid du Colombier }
16*8ccd4a63SDavid du Colombier 
17*8ccd4a63SDavid du Colombier void
nbnsmessageresourcefree(NbnsMessageResource ** rp)18*8ccd4a63SDavid du Colombier nbnsmessageresourcefree(NbnsMessageResource **rp)
19*8ccd4a63SDavid du Colombier {
20*8ccd4a63SDavid du Colombier 	NbnsMessageResource *r = *rp;
21*8ccd4a63SDavid du Colombier 	if (r) {
22*8ccd4a63SDavid du Colombier 		free(r->rdata);
23*8ccd4a63SDavid du Colombier 		free(r);
24*8ccd4a63SDavid du Colombier 		*rp = nil;
25*8ccd4a63SDavid du Colombier 	}
26*8ccd4a63SDavid du Colombier }
27*8ccd4a63SDavid du Colombier 
28*8ccd4a63SDavid du Colombier static void
questionfree(NbnsMessageQuestion ** qp)29*8ccd4a63SDavid du Colombier questionfree(NbnsMessageQuestion **qp)
30*8ccd4a63SDavid du Colombier {
31*8ccd4a63SDavid du Colombier 	while (*qp) {
32*8ccd4a63SDavid du Colombier 		NbnsMessageQuestion *next = (*qp)->next;
33*8ccd4a63SDavid du Colombier 		nbnsmessagequestionfree(qp);
34*8ccd4a63SDavid du Colombier 		*qp = next;
35*8ccd4a63SDavid du Colombier 	}
36*8ccd4a63SDavid du Colombier }
37*8ccd4a63SDavid du Colombier 
38*8ccd4a63SDavid du Colombier static void
resourcefree(NbnsMessageResource ** rp)39*8ccd4a63SDavid du Colombier resourcefree(NbnsMessageResource **rp)
40*8ccd4a63SDavid du Colombier {
41*8ccd4a63SDavid du Colombier 	while (*rp) {
42*8ccd4a63SDavid du Colombier 		NbnsMessageResource *next = (*rp)->next;
43*8ccd4a63SDavid du Colombier 		nbnsmessageresourcefree(rp);
44*8ccd4a63SDavid du Colombier 		*rp = next;
45*8ccd4a63SDavid du Colombier 	}
46*8ccd4a63SDavid du Colombier }
47*8ccd4a63SDavid du Colombier 
48*8ccd4a63SDavid du Colombier void
nbnsmessagefree(NbnsMessage ** sp)49*8ccd4a63SDavid du Colombier nbnsmessagefree(NbnsMessage **sp)
50*8ccd4a63SDavid du Colombier {
51*8ccd4a63SDavid du Colombier 	NbnsMessage *s = *sp;
52*8ccd4a63SDavid du Colombier 	if (s) {
53*8ccd4a63SDavid du Colombier 		questionfree(&s->q);
54*8ccd4a63SDavid du Colombier 		resourcefree(&s->an);
55*8ccd4a63SDavid du Colombier 		resourcefree(&s->ns);
56*8ccd4a63SDavid du Colombier 		resourcefree(&s->ar);
57*8ccd4a63SDavid du Colombier 		free(s);
58*8ccd4a63SDavid du Colombier 		*sp = nil;
59*8ccd4a63SDavid du Colombier 	}
60*8ccd4a63SDavid du Colombier }
61*8ccd4a63SDavid du Colombier 
62*8ccd4a63SDavid du Colombier void
nbnsmessageaddquestion(NbnsMessage * s,NbnsMessageQuestion * q)63*8ccd4a63SDavid du Colombier nbnsmessageaddquestion(NbnsMessage *s, NbnsMessageQuestion *q)
64*8ccd4a63SDavid du Colombier {
65*8ccd4a63SDavid du Colombier 	NbnsMessageQuestion **qp;
66*8ccd4a63SDavid du Colombier 	for (qp = &s->q; *qp; qp = &(*qp)->next)
67*8ccd4a63SDavid du Colombier 		;
68*8ccd4a63SDavid du Colombier 	*qp = q;
69*8ccd4a63SDavid du Colombier }
70*8ccd4a63SDavid du Colombier 
71*8ccd4a63SDavid du Colombier NbnsMessageQuestion *
nbnsmessagequestionnew(NbName name,ushort type,ushort class)72*8ccd4a63SDavid du Colombier nbnsmessagequestionnew(NbName name, ushort type, ushort class)
73*8ccd4a63SDavid du Colombier {
74*8ccd4a63SDavid du Colombier 	NbnsMessageQuestion *q;
75*8ccd4a63SDavid du Colombier 	q = mallocz(sizeof(*q), 1);
76*8ccd4a63SDavid du Colombier 	if (q == nil)
77*8ccd4a63SDavid du Colombier 		return nil;
78*8ccd4a63SDavid du Colombier 	nbnamecpy(q->name, name);
79*8ccd4a63SDavid du Colombier 	q->type = type;
80*8ccd4a63SDavid du Colombier 	q->class = class;
81*8ccd4a63SDavid du Colombier 	return q;
82*8ccd4a63SDavid du Colombier }
83*8ccd4a63SDavid du Colombier 
84*8ccd4a63SDavid du Colombier NbnsMessageResource *
nbnsmessageresourcenew(NbName name,ushort type,ushort class,ulong ttl,int rdlength,uchar * rdata)85*8ccd4a63SDavid du Colombier nbnsmessageresourcenew(NbName name, ushort type, ushort class, ulong ttl, int rdlength, uchar *rdata)
86*8ccd4a63SDavid du Colombier {
87*8ccd4a63SDavid du Colombier 	NbnsMessageResource *r;
88*8ccd4a63SDavid du Colombier 	r= mallocz(sizeof(*r), 1);
89*8ccd4a63SDavid du Colombier 	if (r == nil)
90*8ccd4a63SDavid du Colombier 		return nil;
91*8ccd4a63SDavid du Colombier 	nbnamecpy(r->name, name);
92*8ccd4a63SDavid du Colombier 	r->type = type;
93*8ccd4a63SDavid du Colombier 	r->class = class;
94*8ccd4a63SDavid du Colombier 	r->ttl = ttl;
95*8ccd4a63SDavid du Colombier 	r->rdlength = rdlength;
96*8ccd4a63SDavid du Colombier 	if (rdlength) {
97*8ccd4a63SDavid du Colombier 		r->rdata = malloc(rdlength);
98*8ccd4a63SDavid du Colombier 		if (r->rdata == nil) {
99*8ccd4a63SDavid du Colombier 			free(r);
100*8ccd4a63SDavid du Colombier 			return nil;
101*8ccd4a63SDavid du Colombier 		}
102*8ccd4a63SDavid du Colombier 		memcpy(r->rdata, rdata, rdlength);
103*8ccd4a63SDavid du Colombier 	}
104*8ccd4a63SDavid du Colombier 	return r;
105*8ccd4a63SDavid du Colombier }
106*8ccd4a63SDavid du Colombier 
107*8ccd4a63SDavid du Colombier void
nbnsmessageaddresource(NbnsMessageResource ** rp,NbnsMessageResource * r)108*8ccd4a63SDavid du Colombier nbnsmessageaddresource(NbnsMessageResource **rp, NbnsMessageResource *r)
109*8ccd4a63SDavid du Colombier {
110*8ccd4a63SDavid du Colombier 	for (; *rp; rp = &(*rp)->next)
111*8ccd4a63SDavid du Colombier 		;
112*8ccd4a63SDavid du Colombier 	*rp = r;
113*8ccd4a63SDavid du Colombier }
114*8ccd4a63SDavid du Colombier 
115*8ccd4a63SDavid du Colombier NbnsMessage *
nbnsmessagenew(void)116*8ccd4a63SDavid du Colombier nbnsmessagenew(void)
117*8ccd4a63SDavid du Colombier {
118*8ccd4a63SDavid du Colombier 	return mallocz(sizeof(NbnsMessage), 1);
119*8ccd4a63SDavid du Colombier }
120*8ccd4a63SDavid du Colombier 
121*8ccd4a63SDavid du Colombier static int
resourcedecode(NbnsMessageResource ** headp,int count,uchar * ap,uchar * pp,uchar * ep)122*8ccd4a63SDavid du Colombier resourcedecode(NbnsMessageResource **headp, int count, uchar *ap, uchar *pp, uchar *ep)
123*8ccd4a63SDavid du Colombier {
124*8ccd4a63SDavid du Colombier 	uchar *p = pp;
125*8ccd4a63SDavid du Colombier 	int i;
126*8ccd4a63SDavid du Colombier 	for (i = 0; i < count; i++) {
127*8ccd4a63SDavid du Colombier 		int n;
128*8ccd4a63SDavid du Colombier 		NbnsMessageResource *r, **rp;
129*8ccd4a63SDavid du Colombier 		r = mallocz(sizeof(NbnsMessageResource), 1);
130*8ccd4a63SDavid du Colombier 		if (r == nil)
131*8ccd4a63SDavid du Colombier 			return -1;
132*8ccd4a63SDavid du Colombier 		for (rp = headp; *rp; rp = &(*rp)->next)
133*8ccd4a63SDavid du Colombier 			;
134*8ccd4a63SDavid du Colombier 		*rp = r;
135*8ccd4a63SDavid du Colombier 		n = nbnamedecode(ap, p, ep, r->name);
136*8ccd4a63SDavid du Colombier 		if (n == 0)
137*8ccd4a63SDavid du Colombier 			return -1;
138*8ccd4a63SDavid du Colombier 		p += n;
139*8ccd4a63SDavid du Colombier 		if (p + 10 > ep)
140*8ccd4a63SDavid du Colombier 			return -1;
141*8ccd4a63SDavid du Colombier 		r->type = nhgets(p); p += 2;
142*8ccd4a63SDavid du Colombier 		r->class = nhgets(p); p += 2;
143*8ccd4a63SDavid du Colombier 		r->ttl = nhgetl(p); p += 4;
144*8ccd4a63SDavid du Colombier 		r->rdlength = nhgets(p); p += 2;
145*8ccd4a63SDavid du Colombier //print("rdlength %d\n", r->rdlength);
146*8ccd4a63SDavid du Colombier 		if (r->rdlength) {
147*8ccd4a63SDavid du Colombier 			if (p + r->rdlength > ep)
148*8ccd4a63SDavid du Colombier 				return -1;
149*8ccd4a63SDavid du Colombier 			r->rdata = malloc(r->rdlength);
150*8ccd4a63SDavid du Colombier 			if (r == nil)
151*8ccd4a63SDavid du Colombier 				return -1;
152*8ccd4a63SDavid du Colombier 			memcpy(r->rdata, p, r->rdlength);
153*8ccd4a63SDavid du Colombier 			p += r->rdlength;
154*8ccd4a63SDavid du Colombier 		}
155*8ccd4a63SDavid du Colombier 	}
156*8ccd4a63SDavid du Colombier 	return p - pp;
157*8ccd4a63SDavid du Colombier }
158*8ccd4a63SDavid du Colombier 
159*8ccd4a63SDavid du Colombier NbnsMessage *
nbnsconvM2S(uchar * ap,int nap)160*8ccd4a63SDavid du Colombier nbnsconvM2S(uchar *ap, int nap)
161*8ccd4a63SDavid du Colombier {
162*8ccd4a63SDavid du Colombier 	uchar *p, *ep;
163*8ccd4a63SDavid du Colombier 	ushort qdcount, ancount, nscount, arcount, ctrl;
164*8ccd4a63SDavid du Colombier 	int i;
165*8ccd4a63SDavid du Colombier 	NbnsMessage *s;
166*8ccd4a63SDavid du Colombier 	int n;
167*8ccd4a63SDavid du Colombier 
168*8ccd4a63SDavid du Colombier 	if (nap < 12)
169*8ccd4a63SDavid du Colombier 		return nil;
170*8ccd4a63SDavid du Colombier 	p = ap;
171*8ccd4a63SDavid du Colombier 	ep = ap + nap;
172*8ccd4a63SDavid du Colombier 	s = nbnsmessagenew();
173*8ccd4a63SDavid du Colombier 	if (s == nil)
174*8ccd4a63SDavid du Colombier 		return nil;
175*8ccd4a63SDavid du Colombier 	s->id = nhgets(p); p+= 2;
176*8ccd4a63SDavid du Colombier 	ctrl = nhgets(p); p += 2;
177*8ccd4a63SDavid du Colombier 	qdcount = nhgets(p); p += 2;
178*8ccd4a63SDavid du Colombier 	ancount = nhgets(p); p += 2;
179*8ccd4a63SDavid du Colombier 	nscount = nhgets(p); p += 2;
180*8ccd4a63SDavid du Colombier 	arcount = nhgets(p); p += 2;
181*8ccd4a63SDavid du Colombier 	s->response = (ctrl & NbnsResponse) != 0;
182*8ccd4a63SDavid du Colombier 	s->opcode = (ctrl >> NbnsOpShift) & NbnsOpMask;
183*8ccd4a63SDavid du Colombier 	s->broadcast = (ctrl & NbnsFlagBroadcast) != 0;
184*8ccd4a63SDavid du Colombier 	s->recursionavailable = (ctrl & NbnsFlagRecursionAvailable) != 0;
185*8ccd4a63SDavid du Colombier 	s->recursiondesired = (ctrl & NbnsFlagRecursionDesired) != 0;
186*8ccd4a63SDavid du Colombier 	s->truncation = (ctrl & NbnsFlagTruncation) != 0;
187*8ccd4a63SDavid du Colombier 	s->authoritativeanswer = (ctrl & NbnsFlagAuthoritativeAnswer) != 0;
188*8ccd4a63SDavid du Colombier 	s->rcode = s->response ? (ctrl & NbnsRcodeMask) : 0;
189*8ccd4a63SDavid du Colombier 	for (i = 0; i < qdcount; i++) {
190*8ccd4a63SDavid du Colombier 		int n;
191*8ccd4a63SDavid du Colombier 		NbName nbname;
192*8ccd4a63SDavid du Colombier 		NbnsMessageQuestion *q;
193*8ccd4a63SDavid du Colombier 		ushort type, class;
194*8ccd4a63SDavid du Colombier 		n = nbnamedecode(ap, p, ep, nbname);
195*8ccd4a63SDavid du Colombier 		if (n == 0)
196*8ccd4a63SDavid du Colombier 			goto fail;
197*8ccd4a63SDavid du Colombier 		p += n;
198*8ccd4a63SDavid du Colombier 		if (p + 4 > ep)
199*8ccd4a63SDavid du Colombier 			goto fail;
200*8ccd4a63SDavid du Colombier 		type = nhgets(p); p += 2;
201*8ccd4a63SDavid du Colombier 		class = nhgets(p); p += 2;
202*8ccd4a63SDavid du Colombier 		q = nbnsmessagequestionnew(nbname, type, class);
203*8ccd4a63SDavid du Colombier 		if (q == nil)
204*8ccd4a63SDavid du Colombier 			goto fail;
205*8ccd4a63SDavid du Colombier 		nbnsmessageaddquestion(s, q);
206*8ccd4a63SDavid du Colombier 	}
207*8ccd4a63SDavid du Colombier 	n = resourcedecode(&s->an, ancount, ap, p, ep);
208*8ccd4a63SDavid du Colombier 	if (n < 0)
209*8ccd4a63SDavid du Colombier 		goto fail;
210*8ccd4a63SDavid du Colombier 	p += n;
211*8ccd4a63SDavid du Colombier 	n = resourcedecode(&s->ns, nscount, ap, p, ep);
212*8ccd4a63SDavid du Colombier 	if (n < 0)
213*8ccd4a63SDavid du Colombier 		goto fail;
214*8ccd4a63SDavid du Colombier 	p += n;
215*8ccd4a63SDavid du Colombier 	n = resourcedecode(&s->ar, arcount, ap, p, ep);
216*8ccd4a63SDavid du Colombier 	if (n < 0)
217*8ccd4a63SDavid du Colombier 		goto fail;
218*8ccd4a63SDavid du Colombier //print("arcount %d\n", arcount);
219*8ccd4a63SDavid du Colombier 	return s;
220*8ccd4a63SDavid du Colombier fail:
221*8ccd4a63SDavid du Colombier 	nbnsmessagefree(&s);
222*8ccd4a63SDavid du Colombier 	return nil;
223*8ccd4a63SDavid du Colombier }
224*8ccd4a63SDavid du Colombier 
225*8ccd4a63SDavid du Colombier static int
resourceencode(NbnsMessageResource * r,uchar * ap,uchar * ep)226*8ccd4a63SDavid du Colombier resourceencode(NbnsMessageResource *r, uchar *ap, uchar *ep)
227*8ccd4a63SDavid du Colombier {
228*8ccd4a63SDavid du Colombier 	uchar *p = ap;
229*8ccd4a63SDavid du Colombier 	for (; r; r = r->next) {
230*8ccd4a63SDavid du Colombier 		int n = nbnameencode(p, ep, r->name);
231*8ccd4a63SDavid du Colombier 		if (n == 0)
232*8ccd4a63SDavid du Colombier 			return -1;
233*8ccd4a63SDavid du Colombier 		p += n;
234*8ccd4a63SDavid du Colombier 		if (p + 10 > ep)
235*8ccd4a63SDavid du Colombier 			return -1;
236*8ccd4a63SDavid du Colombier 		hnputs(p, r->type); p += 2;
237*8ccd4a63SDavid du Colombier 		hnputs(p, r->class); p += 2;
238*8ccd4a63SDavid du Colombier 		hnputl(p, r->ttl); p += 4;
239*8ccd4a63SDavid du Colombier 		hnputs(p, r->rdlength); p += 2;
240*8ccd4a63SDavid du Colombier 		if (p + r->rdlength > ep)
241*8ccd4a63SDavid du Colombier 			return -1;
242*8ccd4a63SDavid du Colombier 		memcpy(p, r->rdata, r->rdlength);
243*8ccd4a63SDavid du Colombier 		p += r->rdlength;
244*8ccd4a63SDavid du Colombier 	}
245*8ccd4a63SDavid du Colombier 	return p - ap;
246*8ccd4a63SDavid du Colombier }
247*8ccd4a63SDavid du Colombier 
248*8ccd4a63SDavid du Colombier int
nbnsconvS2M(NbnsMessage * s,uchar * ap,int nap)249*8ccd4a63SDavid du Colombier nbnsconvS2M(NbnsMessage *s, uchar *ap, int nap)
250*8ccd4a63SDavid du Colombier {
251*8ccd4a63SDavid du Colombier 	uchar *p = ap;
252*8ccd4a63SDavid du Colombier 	uchar *ep = ap + nap;
253*8ccd4a63SDavid du Colombier 	ushort ctrl;
254*8ccd4a63SDavid du Colombier 	NbnsMessageQuestion *q;
255*8ccd4a63SDavid du Colombier 	NbnsMessageResource *r;
256*8ccd4a63SDavid du Colombier 	int k;
257*8ccd4a63SDavid du Colombier 	int n;
258*8ccd4a63SDavid du Colombier 
259*8ccd4a63SDavid du Colombier 	if (p + 12 > ep)
260*8ccd4a63SDavid du Colombier 		return 0;
261*8ccd4a63SDavid du Colombier 	hnputs(p, s->id); p+= 2;
262*8ccd4a63SDavid du Colombier 	ctrl = (s->opcode & NbnsOpMask) << NbnsOpShift;
263*8ccd4a63SDavid du Colombier 	if (s->response) {
264*8ccd4a63SDavid du Colombier 		ctrl |= s->rcode & NbnsRcodeMask;
265*8ccd4a63SDavid du Colombier 		ctrl |= NbnsResponse;
266*8ccd4a63SDavid du Colombier 	}
267*8ccd4a63SDavid du Colombier 	if (s->broadcast)
268*8ccd4a63SDavid du Colombier 		ctrl |= NbnsFlagBroadcast;
269*8ccd4a63SDavid du Colombier 	if (s->recursionavailable)
270*8ccd4a63SDavid du Colombier 		ctrl |= NbnsFlagRecursionAvailable;
271*8ccd4a63SDavid du Colombier 	if (s->recursiondesired)
272*8ccd4a63SDavid du Colombier 		ctrl |= NbnsFlagRecursionDesired;
273*8ccd4a63SDavid du Colombier 	if (s->truncation)
274*8ccd4a63SDavid du Colombier 		ctrl |= NbnsFlagTruncation;
275*8ccd4a63SDavid du Colombier 	if (s->authoritativeanswer)
276*8ccd4a63SDavid du Colombier 		ctrl |= NbnsFlagAuthoritativeAnswer;
277*8ccd4a63SDavid du Colombier 	hnputs(p, ctrl); p += 2;
278*8ccd4a63SDavid du Colombier 	for (q = s->q, k = 0; q; k++, q = q->next)
279*8ccd4a63SDavid du Colombier 		;
280*8ccd4a63SDavid du Colombier 	hnputs(p, k); p += 2;
281*8ccd4a63SDavid du Colombier 	for (r = s->an, k = 0; r; k++, r = r->next)
282*8ccd4a63SDavid du Colombier 		;
283*8ccd4a63SDavid du Colombier 	hnputs(p, k); p += 2;
284*8ccd4a63SDavid du Colombier 	for (r = s->ns, k = 0; r; k++, r = r->next)
285*8ccd4a63SDavid du Colombier 		;
286*8ccd4a63SDavid du Colombier 	hnputs(p, k); p += 2;
287*8ccd4a63SDavid du Colombier 	for (r = s->ar, k = 0; r; k++, r = r->next)
288*8ccd4a63SDavid du Colombier 		;
289*8ccd4a63SDavid du Colombier 	hnputs(p, k); p += 2;
290*8ccd4a63SDavid du Colombier 	for (q = s->q; q; q = q->next) {
291*8ccd4a63SDavid du Colombier 		int n = nbnameencode(p, ep, q->name);
292*8ccd4a63SDavid du Colombier 		if (n == 0)
293*8ccd4a63SDavid du Colombier 			return 0;
294*8ccd4a63SDavid du Colombier 		p += n;
295*8ccd4a63SDavid du Colombier 		if (p + 4 > ep)
296*8ccd4a63SDavid du Colombier 			return 0;
297*8ccd4a63SDavid du Colombier 		hnputs(p, q->type); p += 2;
298*8ccd4a63SDavid du Colombier 		hnputs(p, q->class); p += 2;
299*8ccd4a63SDavid du Colombier 	}
300*8ccd4a63SDavid du Colombier 	n = resourceencode(s->an, p, ep);
301*8ccd4a63SDavid du Colombier 	if (n < 0)
302*8ccd4a63SDavid du Colombier 		return 0;
303*8ccd4a63SDavid du Colombier 	p += n;
304*8ccd4a63SDavid du Colombier 	n = resourceencode(s->ns, p, ep);
305*8ccd4a63SDavid du Colombier 	if (n < 0)
306*8ccd4a63SDavid du Colombier 		return 0;
307*8ccd4a63SDavid du Colombier 	p += n;
308*8ccd4a63SDavid du Colombier 	n = resourceencode(s->ar, p, ep);
309*8ccd4a63SDavid du Colombier 	if (n < 0)
310*8ccd4a63SDavid du Colombier 		return 0;
311*8ccd4a63SDavid du Colombier 	p += n;
312*8ccd4a63SDavid du Colombier 	return p - ap;
313*8ccd4a63SDavid du Colombier }
314*8ccd4a63SDavid du Colombier 
315