PageRenderTime 53ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/kern/devip.c

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