Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include "u.h"
2
#include "lib.h"
3
#include "dat.h"
4
#include "fns.h"
5
#include "error.h"
6
#include "ip.h"
7
 
8
#include "devip.h"
9
 
10
void	csclose(Chan*);
11
long	csread(Chan*, void*, long, vlong);
12
long	cswrite(Chan*, void*, long, vlong);
13
 
14
void osipinit(void);
15
 
16
enum
17
{
18
	Qtopdir		= 1,	/* top level directory */
19
	Qcs,
20
	Qprotodir,		/* directory for a protocol */
21
	Qclonus,
22
	Qconvdir,		/* directory for a conversation */
23
	Qdata,
24
	Qctl,
25
	Qstatus,
26
	Qremote,
27
	Qlocal,
28
	Qlisten,
29
 
30
	MAXPROTO	= 4
31
};
32
#define TYPE(x) 	((int)((x).path & 0xf))
33
#define CONV(x) 	((int)(((x).path >> 4)&0xfff))
34
#define PROTO(x) 	((int)(((x).path >> 16)&0xff))
35
#define QID(p, c, y) 	(((p)<<16) | ((c)<<4) | (y))
36
#define ipzero(x)	memset(x, 0, IPaddrlen)
37
 
38
typedef struct Proto	Proto;
39
typedef struct Conv	Conv;
40
struct Conv
41
{
42
	int	x;
43
	Ref	r;
44
	int	sfd;
45
	int	perm;
46
	char	owner[KNAMELEN];
47
	char*	state;
48
	uchar	laddr[IPaddrlen];
49
	ushort	lport;
50
	uchar	raddr[IPaddrlen];
51
	ushort	rport;
52
	int	restricted;
53
	char	cerr[KNAMELEN];
54
	Proto*	p;
55
};
56
 
57
struct Proto
58
{
59
	Lock	l;
60
	int	x;
61
	int	stype;
62
	char	name[KNAMELEN];
63
	int	nc;
64
	int	maxconv;
65
	Conv**	conv;
66
	Qid	qid;
67
};
68
 
69
static	int	np;
70
static	Proto	proto[MAXPROTO];
71
 
72
static	Conv*	protoclone(Proto*, char*, int);
73
static	void	setladdr(Conv*);
74
 
75
int
76
ipgen(Chan *c, char *nname, Dirtab *d, int nd, int s, Dir *dp)
77
{
78
	Qid q;
79
	Conv *cv;
80
	char *p;
81
 
82
	USED(nname);
83
	q.vers = 0;
84
	q.type = 0;
85
	switch(TYPE(c->qid)) {
86
	case Qtopdir:
87
		if(s >= 1+np)
88
			return -1;
89
 
90
		if(s == 0){
91
			q.path = QID(s, 0, Qcs);
92
			devdir(c, q, "cs", 0, "network", 0666, dp);
93
		}else{
94
			s--;
95
			q.path = QID(s, 0, Qprotodir);
96
			q.type = QTDIR;
97
			devdir(c, q, proto[s].name, 0, "network", DMDIR|0555, dp);
98
		}
99
		return 1;
100
	case Qprotodir:
101
		if(s < proto[PROTO(c->qid)].nc) {
102
			cv = proto[PROTO(c->qid)].conv[s];
103
			sprint(up->genbuf, "%d", s);
104
			q.path = QID(PROTO(c->qid), s, Qconvdir);
105
			q.type = QTDIR;
106
			devdir(c, q, up->genbuf, 0, cv->owner, DMDIR|0555, dp);
107
			return 1;
108
		}
109
		s -= proto[PROTO(c->qid)].nc;
110
		switch(s) {
111
		default:
112
			return -1;
113
		case 0:
114
			p = "clone";
115
			q.path = QID(PROTO(c->qid), 0, Qclonus);
116
			break;
117
		}
118
		devdir(c, q, p, 0, "network", 0555, dp);
119
		return 1;
120
	case Qconvdir:
121
		cv = proto[PROTO(c->qid)].conv[CONV(c->qid)];
122
		switch(s) {
123
		default:
124
			return -1;
125
		case 0:
126
			q.path = QID(PROTO(c->qid), CONV(c->qid), Qdata);
127
			devdir(c, q, "data", 0, cv->owner, cv->perm, dp);
128
			return 1;
129
		case 1:
130
			q.path = QID(PROTO(c->qid), CONV(c->qid), Qctl);
131
			devdir(c, q, "ctl", 0, cv->owner, cv->perm, dp);
132
			return 1;
133
		case 2:
134
			p = "status";
135
			q.path = QID(PROTO(c->qid), CONV(c->qid), Qstatus);
136
			break;
137
		case 3:
138
			p = "remote";
139
			q.path = QID(PROTO(c->qid), CONV(c->qid), Qremote);
140
			break;
141
		case 4:
142
			p = "local";
143
			q.path = QID(PROTO(c->qid), CONV(c->qid), Qlocal);
144
			break;
145
		case 5:
146
			p = "listen";
147
			q.path = QID(PROTO(c->qid), CONV(c->qid), Qlisten);
148
			break;
149
		}
150
		devdir(c, q, p, 0, cv->owner, 0444, dp);
151
		return 1;
152
	}
153
	return -1;
154
}
155
 
156
static void
157
newproto(char *name, int type, int maxconv)
158
{
159
	int l;
160
	Proto *p;
161
 
162
	if(np >= MAXPROTO) {
163
		print("no %s: increase MAXPROTO", name);
164
		return;
165
	}
166
 
167
	p = &proto[np];
168
	strcpy(p->name, name);
169
	p->stype = type;
170
	p->qid.path = QID(np, 0, Qprotodir);
171
	p->qid.type = QTDIR;
172
	p->x = np++;
173
	p->maxconv = maxconv;
174
	l = sizeof(Conv*)*(p->maxconv+1);
175
	p->conv = mallocz(l, 1);
176
	if(p->conv == 0)
177
		panic("no memory");
178
}
179
 
180
void
181
ipinit(void)
182
{
183
	osipinit();
184
 
185
	newproto("udp", S_UDP, 10);
186
	newproto("tcp", S_TCP, 30);
187
 
188
	fmtinstall('I', eipfmt);
189
	fmtinstall('E', eipfmt);
190
 
191
}
192
 
193
Chan *
194
ipattach(char *spec)
195
{
196
	Chan *c;
197
 
198
	c = devattach('I', spec);
199
	c->qid.path = QID(0, 0, Qtopdir);
200
	c->qid.type = QTDIR;
201
	c->qid.vers = 0;
202
	return c;
203
}
204
 
205
static Walkqid*
206
ipwalk(Chan *c, Chan *nc, char **name, int nname)
207
{
208
	return devwalk(c, nc, name, nname, 0, 0, ipgen);
209
}
210
 
211
int
212
ipstat(Chan *c, uchar *dp, int n)
213
{
214
	return devstat(c, dp, n, 0, 0, ipgen);
215
}
216
 
217
Chan *
218
ipopen(Chan *c, int omode)
219
{
220
	Proto *p;
221
	uchar raddr[IPaddrlen];
222
	ushort rport;
223
	int perm, sfd;
224
	Conv *cv, *lcv;
225
 
226
	omode &= 3;
227
	perm = 0;
228
	switch(omode) {
229
	case OREAD:
230
		perm = 4;
231
		break;
232
	case OWRITE:
233
		perm = 2;
234
		break;
235
	case ORDWR:
236
		perm = 6;
237
		break;
238
	}
239
 
240
	switch(TYPE(c->qid)) {
241
	default:
242
		break;
243
	case Qtopdir:
244
	case Qprotodir:
245
	case Qconvdir:
246
	case Qstatus:
247
	case Qremote:
248
	case Qlocal:
249
		if(omode != OREAD)
250
			error(Eperm);
251
		break;
252
	case Qclonus:
253
		p = &proto[PROTO(c->qid)];
254
		cv = protoclone(p, up->user, -1);
255
		if(cv == 0)
256
			error(Enodev);
257
		c->qid.path = QID(p->x, cv->x, Qctl);
258
		c->qid.vers = 0;
259
		break;
260
	case Qdata:
261
	case Qctl:
262
		p = &proto[PROTO(c->qid)];
263
		lock(&p->l);
264
		cv = p->conv[CONV(c->qid)];
265
		lock(&cv->r.lk);
266
		if((perm & (cv->perm>>6)) != perm) {
267
			if(strcmp(up->user, cv->owner) != 0 ||
268
		 	  (perm & cv->perm) != perm) {
269
				unlock(&cv->r.lk);
270
				unlock(&p->l);
271
				error(Eperm);
272
			}
273
		}
274
		cv->r.ref++;
275
		if(cv->r.ref == 1) {
276
			memmove(cv->owner, up->user, KNAMELEN);
277
			cv->perm = 0660;
278
		}
279
		unlock(&cv->r.lk);
280
		unlock(&p->l);
281
		break;
282
	case Qlisten:
283
		p = &proto[PROTO(c->qid)];
284
		lcv = p->conv[CONV(c->qid)];
285
		sfd = so_accept(lcv->sfd, raddr, &rport);
286
		cv = protoclone(p, up->user, sfd);
287
		if(cv == 0) {
288
			close(sfd);
289
			error(Enodev);
290
		}
291
		ipmove(cv->raddr, raddr);
292
		cv->rport = rport;
293
		setladdr(cv);
294
		cv->state = "Established";
295
		c->qid.path = QID(p->x, cv->x, Qctl);
296
		break;
297
	}
298
	c->mode = openmode(omode);
299
	c->flag |= COPEN;
300
	c->offset = 0;
301
	return c;
302
}
303
 
304
void
305
ipclose(Chan *c)
306
{
307
	Conv *cc;
308
 
309
	switch(TYPE(c->qid)) {
310
	case Qcs:
311
		csclose(c);
312
		break;
313
	case Qdata:
314
	case Qctl:
315
		if((c->flag & COPEN) == 0)
316
			break;
317
		cc = proto[PROTO(c->qid)].conv[CONV(c->qid)];
318
		if(decref(&cc->r) != 0)
319
			break;
320
		strcpy(cc->owner, "network");
321
		cc->perm = 0666;
322
		cc->state = "Closed";
323
		ipzero(cc->laddr);
324
		ipzero(cc->raddr);
325
		cc->lport = 0;
326
		cc->rport = 0;
327
		close(cc->sfd);
328
		break;
329
	}
330
}
331
 
332
long
333
ipread(Chan *ch, void *a, long n, vlong offset)
334
{
335
	int r;
336
	Conv *c;
337
	Proto *x;
338
	uchar ip[IPaddrlen];
339
	char buf[128], *p;
340
 
341
/*print("ipread %s %lux\n", c2name(ch), (long)ch->qid.path);*/
342
	p = a;
343
	switch(TYPE(ch->qid)) {
344
	default:
345
		error(Eperm);
346
	case Qcs:
347
		return csread(ch, a, n, offset);
348
	case Qprotodir:
349
	case Qtopdir:
350
	case Qconvdir:
351
		return devdirread(ch, a, n, 0, 0, ipgen);
352
	case Qctl:
353
		sprint(buf, "%d", CONV(ch->qid));
354
		return readstr(offset, p, n, buf);
355
	case Qremote:
356
		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
357
		ipmove(ip, c->raddr);
358
		sprint(buf, "%I!%d\n", ip, c->rport);
359
		return readstr(offset, p, n, buf);
360
	case Qlocal:
361
		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
362
		ipmove(ip, c->laddr);
363
		sprint(buf, "%I!%d\n", ip, c->lport);
364
		return readstr(offset, p, n, buf);
365
	case Qstatus:
366
		x = &proto[PROTO(ch->qid)];
367
		c = x->conv[CONV(ch->qid)];
368
		sprint(buf, "%s/%d %d %s \n",
369
			c->p->name, c->x, c->r.ref, c->state);
370
		return readstr(offset, p, n, buf);
371
	case Qdata:
372
		c = proto[PROTO(ch->qid)].conv[CONV(ch->qid)];
373
		r = so_recv(c->sfd, a, n, 0);
374
		if(r < 0){
375
			oserrstr();
376
			nexterror();
377
		}
378
		return r;
379
	}
380
}
381
 
382
static void
383
setladdr(Conv *c)
384
{
385
	so_getsockname(c->sfd, c->laddr, &c->lport);
386
}
387
 
388
static void
389
setlport(Conv *c)
390
{
391
	if(c->restricted == 0 && c->lport == 0)
392
		return;
393
 
394
	if(c->sfd == -1)
395
		c->sfd = so_socket(c->p->stype, c->laddr);
396
 
397
	so_bind(c->sfd, c->restricted, c->lport, c->laddr);
398
}
399
 
400
static void
401
setladdrport(Conv *c, char *str)
402
{
403
	char *p;
404
	uchar addr[IPaddrlen];
405
 
406
	p = strchr(str, '!');
407
	if(p == 0) {
408
		p = str;
409
		ipzero(c->laddr);
410
	}
411
	else {
412
		*p++ = 0;
413
		parseip(addr, str);
414
		ipmove(c->laddr, addr);
415
	}
416
	if(*p == '*')
417
		c->lport = 0;
418
	else
419
		c->lport = atoi(p);
420
 
421
	setlport(c);
422
}
423
 
424
static char*
425
setraddrport(Conv *c, char *str)
426
{
427
	char *p;
428
	uchar addr[IPaddrlen];
429
 
430
	p = strchr(str, '!');
431
	if(p == 0)
432
		return "malformed address";
433
	*p++ = 0;
434
	parseip(addr, str);
435
	ipmove(c->raddr, addr);
436
	c->rport = atoi(p);
437
	p = strchr(p, '!');
438
	if(p) {
439
		if(strcmp(p, "!r") == 0)
440
			c->restricted = 1;
441
	}
442
	return 0;
443
}
444
 
445
long
446
ipwrite(Chan *ch, void *a, long n, vlong offset)
447
{
448
	Conv *c;
449
	Proto *x;
450
	int r, nf;
451
	char *p, *fields[3], buf[128];
452
 
453
	switch(TYPE(ch->qid)) {
454
	default:
455
		error(Eperm);
456
	case Qcs:
457
		return cswrite(ch, a, n, offset);
458
	case Qctl:
459
		x = &proto[PROTO(ch->qid)];
460
		c = x->conv[CONV(ch->qid)];
461
		if(n > sizeof(buf)-1)
462
			n = sizeof(buf)-1;
463
		memmove(buf, a, n);
464
		buf[n] = '\0';
465
 
466
		nf = tokenize(buf, fields, 3);
467
		if(strcmp(fields[0], "connect") == 0){
468
			switch(nf) {
469
			default:
470
				error("bad args to connect");
471
			case 2:
472
				p = setraddrport(c, fields[1]);
473
				if(p != 0)
474
					error(p);
475
				break;
476
			case 3:
477
				p = setraddrport(c, fields[1]);
478
				if(p != 0)
479
					error(p);
480
				c->lport = atoi(fields[2]);
481
				setlport(c);
482
				break;
483
			}
484
			if(c->sfd == -1)
485
				c->sfd = so_socket(c->p->stype, c->raddr);
486
			so_connect(c->sfd, c->raddr, c->rport);
487
			setladdr(c);
488
			c->state = "Established";
489
			return n;
490
		}
491
		if(strcmp(fields[0], "announce") == 0) {
492
			switch(nf){
493
			default:
494
				error("bad args to announce");
495
			case 2:
496
				setladdrport(c, fields[1]);
497
				break;
498
			}
499
			so_listen(c->sfd);
500
			c->state = "Announced";
501
			return n;
502
		}
503
		if(strcmp(fields[0], "bind") == 0){
504
			switch(nf){
505
			default:
506
				error("bad args to bind");
507
			case 2:
508
				c->lport = atoi(fields[1]);
509
				break;
510
			}
511
			setlport(c);
512
			return n;
513
		}
514
		error("bad control message");
515
	case Qdata:
516
		x = &proto[PROTO(ch->qid)];
517
		c = x->conv[CONV(ch->qid)];
518
		r = so_send(c->sfd, a, n, 0);
519
		if(r < 0){
520
			oserrstr();
521
			nexterror();
522
		}
523
		return r;
524
	}
525
	return n;
526
}
527
 
528
static Conv*
529
protoclone(Proto *p, char *user, int nfd)
530
{
531
	Conv *c, **pp, **ep;
532
 
533
	c = 0;
534
	lock(&p->l);
535
	if(waserror()) {
536
		unlock(&p->l);
537
		nexterror();
538
	}
539
	ep = &p->conv[p->maxconv];
540
	for(pp = p->conv; pp < ep; pp++) {
541
		c = *pp;
542
		if(c == 0) {
543
			c = mallocz(sizeof(Conv), 1);
544
			if(c == 0)
545
				error(Enomem);
546
			lock(&c->r.lk);
547
			c->r.ref = 1;
548
			c->p = p;
549
			c->x = pp - p->conv;
550
			p->nc++;
551
			*pp = c;
552
			break;
553
		}
554
		lock(&c->r.lk);
555
		if(c->r.ref == 0) {
556
			c->r.ref++;
557
			break;
558
		}
559
		unlock(&c->r.lk);
560
	}
561
	if(pp >= ep) {
562
		unlock(&p->l);
563
		poperror();
564
		return 0;
565
	}
566
 
567
	strcpy(c->owner, user);
568
	c->perm = 0660;
569
	c->state = "Closed";
570
	c->restricted = 0;
571
	ipzero(c->laddr);
572
	ipzero(c->raddr);
573
	c->lport = 0;
574
	c->rport = 0;
575
	c->sfd = nfd;
576
 
577
	unlock(&c->r.lk);
578
	unlock(&p->l);
579
	poperror();
580
	return c;
581
}
582
 
583
void
584
csclose(Chan *c)
585
{
586
	free(c->aux);
587
}
588
 
589
long
590
csread(Chan *c, void *a, long n, vlong offset)
591
{
592
	if(c->aux == nil)
593
		return 0;
594
	return readstr(offset, a, n, c->aux);
595
}
596
 
597
static struct
598
{
599
	char *name;
600
	uint num;
601
} tab[] = {
602
	"cs", 1,
603
	"echo", 7,
604
	"discard", 9,
605
	"systat", 11,
606
	"daytime", 13,
607
	"netstat", 15,
608
	"chargen", 19,
609
	"ftp-data", 20,
610
	"ftp", 21,
611
	"ssh", 22,
612
	"telnet", 23,
613
	"smtp", 25,
614
	"time", 37,
615
	"whois", 43,
616
	"dns", 53,
617
	"domain", 53,
618
	"uucp", 64,
619
	"gopher", 70,
620
	"rje", 77,
621
	"finger", 79,
622
	"http", 80,
623
	"link", 87,
624
	"supdup", 95,
625
	"hostnames", 101,
626
	"iso-tsap", 102,
627
	"x400", 103,
628
	"x400-snd", 104,
629
	"csnet-ns", 105,
630
	"pop-2", 109,
631
	"pop3", 110,
632
	"portmap", 111,
633
	"uucp-path", 117,
634
	"nntp", 119,
635
	"netbios", 139,
636
	"imap4", 143,
637
	"NeWS", 144,
638
	"print-srv", 170,
639
	"z39.50", 210,
640
	"fsb", 400,
641
	"sysmon", 401,
642
	"proxy", 402,
643
	"proxyd", 404,
644
	"https", 443,
645
	"cifs", 445,
646
	"ssmtp", 465,
647
	"rexec", 512,
648
	"login", 513,
649
	"shell", 514,
650
	"printer", 515,
651
	"courier", 530,
652
	"cscan", 531,
653
	"uucp", 540,
654
	"snntp", 563,
655
	"9fs", 564,
656
	"whoami", 565,
657
	"guard", 566,
658
	"ticket", 567,
659
	"dlsftp", 666,
660
	"fmclient", 729,
661
	"imaps", 993,
662
	"pop3s", 995,
663
	"ingreslock", 1524,
664
	"pptp", 1723,
665
	"nfs", 2049,
666
	"webster", 2627,
667
	"weather", 3000,
668
	"secstore", 5356,
669
	"Xdisplay", 6000,
670
	"styx", 6666,
671
	"mpeg", 6667,
672
	"rstyx", 6668,
673
	"infdb", 6669,
674
	"infsigner", 6671,
675
	"infcsigner", 6672,
676
	"inflogin", 6673,
677
	"bandt", 7330,
678
	"face", 32000,
679
	"dhashgate", 11978,
680
	"exportfs", 17007,
681
	"rexexec", 17009,
682
	"ncpu", 17010,
683
	"cpu", 17013,
684
	"glenglenda1", 17020,
685
	"glenglenda2", 17021,
686
	"glenglenda3", 17022,
687
	"glenglenda4", 17023,
688
	"glenglenda5", 17024,
689
	"glenglenda6", 17025,
690
	"glenglenda7", 17026,
691
	"glenglenda8", 17027,
692
	"glenglenda9", 17028,
693
	"glenglenda10", 17029,
694
	"flyboy", 17032,
695
	"dlsftp", 17033,
696
	"venti", 17034,
697
	"wiki", 17035,
698
	"vica", 17036,
699
 
700
};
701
 
702
static int
703
lookupport(char *s)
704
{
705
	int i;
706
	char buf[10], *p;
707
 
708
	i = strtol(s, &p, 0);
709
	if(*s && *p == 0)
710
		return i;
711
 
712
	i = so_getservbyname(s, "tcp", buf);
713
	if(i != -1)
714
		return atoi(buf);
715
	for(i=0; tab[i].name; i++)
716
		if(strcmp(s, tab[i].name) == 0)
717
			return tab[i].num;
718
	return 0;
719
}
720
 
721
static int
722
lookuphost(char *s, uchar *to)
723
{
724
	ipzero(to);
725
	if(parseip(to, s) != -1)
726
		return 0;
727
	if((s = hostlookup(s)) == nil)
728
		return -1;
729
	parseip(to, s);
730
	free(s);
731
	return 0;
732
}
733
 
734
long
735
cswrite(Chan *c, void *a, long n, vlong offset)
736
{
737
	char *f[4];
738
	char *s, *ns;
739
	uchar ip[IPaddrlen];
740
	int nf, port;
741
 
742
	s = malloc(n+1);
743
	if(s == nil)
744
		error(Enomem);
745
	if(waserror()){
746
		free(s);
747
		nexterror();
748
	}
749
	memmove(s, a, n);
750
	s[n] = 0;
751
	nf = getfields(s, f, nelem(f), 0, "!");
752
	if(nf != 3)
753
		error("can't translate");
754
 
755
	port = lookupport(f[2]);
756
	if(port <= 0)
757
		error("no translation for port found");
758
 
759
	if(lookuphost(f[1], ip) < 0)
760
		error("no translation for host found");
761
 
762
	ns = smprint("/net/%s/clone %I!%d", f[0], ip, port);
763
	if(ns == nil)
764
		error(Enomem);
765
	free(c->aux);
766
	c->aux = ns;
767
	poperror();
768
	free(s);
769
	return n;
770
}
771
 
772
Dev ipdevtab = 
773
{
774
	'I',
775
	"ip",
776
 
777
	devreset,
778
	ipinit,
779
	devshutdown,
780
	ipattach,
781
	ipwalk,
782
	ipstat,
783
	ipopen,
784
	devcreate,
785
	ipclose,
786
	ipread,
787
	devbread,
788
	ipwrite,
789
	devbwrite,
790
	devremove,
791
	devwstat,
792
};
793