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