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 0 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 794