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