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
ipgen(Chan * c,char * nname,Dirtab * d,int nd,int s,Dir * dp)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
newproto(char * name,int type,int maxconv)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
ipinit(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 *
ipattach(char * spec)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*
ipwalk(Chan * c,Chan * nc,char ** name,int nname)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
ipstat(Chan * c,uchar * dp,int n)212 ipstat(Chan *c, uchar *dp, int n)
213 {
214 return devstat(c, dp, n, 0, 0, ipgen);
215 }
216
217 Chan *
ipopen(Chan * c,int omode)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
ipclose(Chan * c)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
ipread(Chan * ch,void * a,long n,vlong offset)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
setladdr(Conv * c)383 setladdr(Conv *c)
384 {
385 so_getsockname(c->sfd, c->laddr, &c->lport);
386 }
387
388 static void
setlport(Conv * c)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
setladdrport(Conv * c,char * str)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*
setraddrport(Conv * c,char * str)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
ipwrite(Chan * ch,void * a,long n,vlong offset)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*
protoclone(Proto * p,char * user,int nfd)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
csclose(Chan * c)584 csclose(Chan *c)
585 {
586 free(c->aux);
587 }
588
589 long
csread(Chan * c,void * a,long n,vlong offset)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 0
700 };
701
702 static int
lookupport(char * s)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
lookuphost(char * s,uchar * to)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
cswrite(Chan * c,void * a,long n,vlong offset)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
794