main.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964
  1. /*
  2. * snoopy - network sniffer
  3. */
  4. #include <u.h>
  5. #include <libc.h>
  6. #include <ip.h>
  7. #include <bio.h>
  8. #include <fcall.h>
  9. #include <libsec.h>
  10. #include <ndb.h>
  11. #include "dat.h"
  12. #include "protos.h"
  13. #include "y.tab.h"
  14. int Cflag;
  15. int pflag;
  16. int Nflag;
  17. int Mflag;
  18. int sflag;
  19. int tiflag;
  20. int toflag;
  21. char *prom = "promiscuous";
  22. enum
  23. {
  24. Pktlen= 64*1024,
  25. Blen= 16*1024,
  26. };
  27. Filter *filter;
  28. Proto *root;
  29. Biobuf out;
  30. vlong starttime, pkttime;
  31. int pcap;
  32. int filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int);
  33. void printpkt(char *p, char *e, uchar *ps, uchar *pe);
  34. void mkprotograph(void);
  35. Proto* findproto(char *name);
  36. Filter* compile(Filter *f);
  37. void printfilter(Filter *f, char *tag);
  38. void printhelp(char*);
  39. void tracepkt(uchar*, int);
  40. void pcaphdr(void);
  41. void
  42. printusage(void)
  43. {
  44. fprint(2, "usage: %s [-CDdpst] [-N n] [-f filter] [-h first-header] path\n", argv0);
  45. fprint(2, " for protocol help: %s -? [proto]\n", argv0);
  46. }
  47. void
  48. usage(void)
  49. {
  50. printusage();
  51. exits("usage");
  52. }
  53. void
  54. main(int argc, char **argv)
  55. {
  56. uchar *pkt;
  57. char *buf, *file, *p, *e;
  58. int fd, cfd;
  59. int n;
  60. Binit(&out, 1, OWRITE);
  61. fmtinstall('E', eipfmt);
  62. fmtinstall('V', eipfmt);
  63. fmtinstall('I', eipfmt);
  64. fmtinstall('H', encodefmt);
  65. fmtinstall('F', fcallfmt);
  66. pkt = malloc(Pktlen+16);
  67. pkt += 16;
  68. buf = malloc(Blen);
  69. e = buf+Blen-1;
  70. pflag = 1;
  71. Nflag = 32;
  72. sflag = 0;
  73. mkprotograph();
  74. ARGBEGIN{
  75. default:
  76. usage();
  77. case '?':
  78. printusage();
  79. printhelp(ARGF());
  80. exits(0);
  81. break;
  82. case 'M':
  83. p = EARGF(usage());
  84. Mflag = atoi(p);
  85. break;
  86. case 'N':
  87. p = EARGF(usage());
  88. Nflag = atoi(p);
  89. break;
  90. case 'f':
  91. p = EARGF(usage());
  92. yyinit(p);
  93. yyparse();
  94. break;
  95. case 's':
  96. sflag = 1;
  97. break;
  98. case 'h':
  99. p = EARGF(usage());
  100. root = findproto(p);
  101. if(root == nil)
  102. sysfatal("unknown protocol: %s", p);
  103. break;
  104. case 'd':
  105. toflag = 1;
  106. break;
  107. case 'D':
  108. toflag = 1;
  109. pcap = 1;
  110. break;
  111. case 't':
  112. tiflag = 1;
  113. break;
  114. case 'C':
  115. Cflag = 1;
  116. break;
  117. case 'p':
  118. pflag = 0;
  119. break;
  120. }ARGEND;
  121. if(pcap)
  122. pcaphdr();
  123. if(argc == 0){
  124. file = "/net/ether0";
  125. if(root != nil)
  126. root = &ether;
  127. } else
  128. file = argv[0];
  129. if((!tiflag) && strstr(file, "ether")){
  130. if(root == nil)
  131. root = &ether;
  132. snprint(buf, Blen, "%s!-1", file);
  133. fd = dial(buf, 0, 0, &cfd);
  134. if(fd < 0)
  135. sysfatal("dialing %s", buf);
  136. if(pflag && fprint(cfd, prom, strlen(prom)) < 0)
  137. sysfatal("setting %s", prom);
  138. } else if((!tiflag) && strstr(file, "ipifc")){
  139. if(root == nil)
  140. root = &ip;
  141. snprint(buf, Blen, "%s/snoop", file);
  142. fd = open(buf, OREAD);
  143. if(fd < 0)
  144. sysfatal("opening %s: %r", buf);
  145. } else {
  146. if(root == nil)
  147. root = &ether;
  148. fd = open(file, OREAD);
  149. if(fd < 0)
  150. sysfatal("opening %s: %r", file);
  151. }
  152. filter = compile(filter);
  153. if(tiflag){
  154. /* read a trace file */
  155. for(;;){
  156. n = read(fd, pkt, 10);
  157. if(n != 10)
  158. break;
  159. pkttime = NetL(pkt+2);
  160. pkttime = (pkttime<<32) | NetL(pkt+6);
  161. if(starttime == 0LL)
  162. starttime = pkttime;
  163. n = NetS(pkt);
  164. if(readn(fd, pkt, n) != n)
  165. break;
  166. if(filterpkt(filter, pkt, pkt+n, root, 1))
  167. if(toflag)
  168. tracepkt(pkt, n);
  169. else
  170. printpkt(buf, e, pkt, pkt+n);
  171. }
  172. } else {
  173. /* read a real time stream */
  174. starttime = nsec();
  175. for(;;){
  176. n = root->framer(fd, pkt, Pktlen);
  177. if(n <= 0)
  178. break;
  179. pkttime = nsec();
  180. if(filterpkt(filter, pkt, pkt+n, root, 1))
  181. if(toflag)
  182. tracepkt(pkt, n);
  183. else
  184. printpkt(buf, e, pkt, pkt+n);
  185. }
  186. }
  187. }
  188. /* create a new filter node */
  189. Filter*
  190. newfilter(void)
  191. {
  192. Filter *f;
  193. f = mallocz(sizeof(*f), 1);
  194. if(f == nil)
  195. sysfatal("newfilter: %r");
  196. return f;
  197. }
  198. /*
  199. * apply filter to packet
  200. */
  201. int
  202. _filterpkt(Filter *f, Msg *m)
  203. {
  204. Msg ma;
  205. if(f == nil)
  206. return 1;
  207. switch(f->op){
  208. case '!':
  209. return !_filterpkt(f->l, m);
  210. case LAND:
  211. ma = *m;
  212. return _filterpkt(f->l, &ma) && _filterpkt(f->r, m);
  213. case LOR:
  214. ma = *m;
  215. return _filterpkt(f->l, &ma) || _filterpkt(f->r, m);
  216. case WORD:
  217. if(m->needroot){
  218. if(m->pr != f->pr)
  219. return 0;
  220. m->needroot = 0;
  221. }else{
  222. if(m->pr && (m->pr->filter==nil || !(m->pr->filter)(f, m)))
  223. return 0;
  224. }
  225. if(f->l == nil)
  226. return 1;
  227. m->pr = f->pr;
  228. return _filterpkt(f->l, m);
  229. }
  230. sysfatal("internal error: filterpkt op: %d", f->op);
  231. return 0;
  232. }
  233. int
  234. filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot)
  235. {
  236. Msg m;
  237. if(f == nil)
  238. return 1;
  239. m.needroot = needroot;
  240. m.ps = ps;
  241. m.pe = pe;
  242. m.pr = pr;
  243. return _filterpkt(f, &m);
  244. }
  245. /*
  246. * from the Unix world
  247. */
  248. #define PCAP_VERSION_MAJOR 2
  249. #define PCAP_VERSION_MINOR 4
  250. #define TCPDUMP_MAGIC 0xa1b2c3d4
  251. struct pcap_file_header {
  252. ulong magic;
  253. ushort version_major;
  254. ushort version_minor;
  255. long thiszone; /* gmt to local correction */
  256. ulong sigfigs; /* accuracy of timestamps */
  257. ulong snaplen; /* max length saved portion of each pkt */
  258. ulong linktype; /* data link type (DLT_*) */
  259. };
  260. struct pcap_pkthdr {
  261. uvlong ts; /* time stamp */
  262. ulong caplen; /* length of portion present */
  263. ulong len; /* length this packet (off wire) */
  264. };
  265. /*
  266. * pcap trace header
  267. */
  268. void
  269. pcaphdr(void)
  270. {
  271. struct pcap_file_header hdr;
  272. hdr.magic = TCPDUMP_MAGIC;
  273. hdr.version_major = PCAP_VERSION_MAJOR;
  274. hdr.version_minor = PCAP_VERSION_MINOR;
  275. hdr.thiszone = 0;
  276. hdr.snaplen = 1500;
  277. hdr.sigfigs = 0;
  278. hdr.linktype = 1;
  279. write(1, &hdr, sizeof(hdr));
  280. }
  281. /*
  282. * write out a packet trace
  283. */
  284. void
  285. tracepkt(uchar *ps, int len)
  286. {
  287. struct pcap_pkthdr *goo;
  288. if(Mflag && len > Mflag)
  289. len = Mflag;
  290. if(pcap){
  291. goo = (struct pcap_pkthdr*)(ps-16);
  292. goo->ts = pkttime;
  293. goo->caplen = len;
  294. goo->len = len;
  295. write(1, goo, len+16);
  296. } else {
  297. hnputs(ps-10, len);
  298. hnputl(ps-8, pkttime>>32);
  299. hnputl(ps-4, pkttime);
  300. write(1, ps-10, len+10);
  301. }
  302. }
  303. /*
  304. * format and print a packet
  305. */
  306. void
  307. printpkt(char *p, char *e, uchar *ps, uchar *pe)
  308. {
  309. Msg m;
  310. ulong dt;
  311. dt = (pkttime-starttime)/1000000LL;
  312. m.p = seprint(p, e, "%6.6uld ms ", dt);
  313. m.ps = ps;
  314. m.pe = pe;
  315. m.e = e;
  316. m.pr = root;
  317. while(m.p < m.e){
  318. if(!sflag)
  319. m.p = seprint(m.p, m.e, "\n\t");
  320. m.p = seprint(m.p, m.e, "%s(", m.pr->name);
  321. if((*m.pr->seprint)(&m) < 0){
  322. m.p = seprint(m.p, m.e, "TOO SHORT");
  323. m.ps = m.pe;
  324. }
  325. m.p = seprint(m.p, m.e, ")");
  326. if(m.pr == nil || m.ps >= m.pe)
  327. break;
  328. }
  329. *m.p++ = '\n';
  330. if(write(1, p, m.p - p) < 0)
  331. sysfatal("stdout: %r");
  332. }
  333. Proto **xprotos;
  334. int nprotos;
  335. /* look up a protocol by its name */
  336. Proto*
  337. findproto(char *name)
  338. {
  339. int i;
  340. for(i = 0; i < nprotos; i++)
  341. if(strcmp(xprotos[i]->name, name) == 0)
  342. return xprotos[i];
  343. return nil;
  344. }
  345. /*
  346. * add an undefined protocol to protos[]
  347. */
  348. Proto*
  349. addproto(char *name)
  350. {
  351. Proto *pr;
  352. xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*));
  353. pr = malloc(sizeof *pr);
  354. *pr = dump;
  355. pr->name = name;
  356. xprotos[nprotos++] = pr;
  357. return pr;
  358. }
  359. /*
  360. * build a graph of protocols, this could easily be circular. This
  361. * links together all the multiplexing in the protocol modules.
  362. */
  363. void
  364. mkprotograph(void)
  365. {
  366. Proto **l;
  367. Proto *pr;
  368. Mux *m;
  369. /* copy protos into a reallocable area */
  370. for(nprotos = 0; protos[nprotos] != nil; nprotos++)
  371. ;
  372. xprotos = malloc(nprotos*sizeof(Proto*));
  373. memmove(xprotos, protos, nprotos*sizeof(Proto*));
  374. for(l = protos; *l != nil; l++){
  375. pr = *l;
  376. for(m = pr->mux; m != nil && m->name != nil; m++){
  377. m->pr = findproto(m->name);
  378. if(m->pr == nil)
  379. m->pr = addproto(m->name);
  380. }
  381. }
  382. }
  383. /*
  384. * add in a protocol node
  385. */
  386. static Filter*
  387. addnode(Filter *f, Proto *pr)
  388. {
  389. Filter *nf;
  390. nf = newfilter();
  391. nf->pr = pr;
  392. nf->s = pr->name;
  393. nf->l = f;
  394. nf->op = WORD;
  395. return nf;
  396. }
  397. /*
  398. * recurse through the protocol graph adding missing nodes
  399. * to the filter if we reach the filter's protocol
  400. */
  401. static Filter*
  402. _fillin(Filter *f, Proto *last, int depth)
  403. {
  404. Mux *m;
  405. Filter *nf;
  406. if(depth-- <= 0)
  407. return nil;
  408. for(m = last->mux; m != nil && m->name != nil; m++){
  409. if(m->pr == nil)
  410. continue;
  411. if(f->pr == m->pr)
  412. return f;
  413. nf = _fillin(f, m->pr, depth);
  414. if(nf != nil)
  415. return addnode(nf, m->pr);
  416. }
  417. return nil;
  418. }
  419. static Filter*
  420. fillin(Filter *f, Proto *last)
  421. {
  422. int i;
  423. Filter *nf;
  424. /* hack to make sure top level node is the root */
  425. if(last == nil){
  426. if(f->pr == root)
  427. return f;
  428. f = fillin(f, root);
  429. if(f == nil)
  430. return nil;
  431. return addnode(f, root);
  432. }
  433. /* breadth first search though the protocol graph */
  434. nf = f;
  435. for(i = 1; i < 20; i++){
  436. nf = _fillin(f, last, i);
  437. if(nf != nil)
  438. break;
  439. }
  440. return nf;
  441. }
  442. /*
  443. * massage tree so that all paths from the root to a leaf
  444. * contain a filter node for each header.
  445. *
  446. * also, set f->pr where possible
  447. */
  448. Filter*
  449. complete(Filter *f, Proto *last)
  450. {
  451. Proto *pr;
  452. if(f == nil)
  453. return f;
  454. /* do a depth first traversal of the filter tree */
  455. switch(f->op){
  456. case '!':
  457. f->l = complete(f->l, last);
  458. break;
  459. case LAND:
  460. case LOR:
  461. f->l = complete(f->l, last);
  462. f->r = complete(f->r, last);
  463. break;
  464. case '=':
  465. break;
  466. case WORD:
  467. pr = findproto(f->s);
  468. f->pr = pr;
  469. if(pr == nil){
  470. if(f->l != nil){
  471. fprint(2, "%s unknown proto, ignoring params\n",
  472. f->s);
  473. f->l = nil;
  474. }
  475. } else {
  476. f->l = complete(f->l, pr);
  477. f = fillin(f, last);
  478. if(f == nil)
  479. sysfatal("internal error: can't get to %s", pr->name);
  480. }
  481. break;
  482. }
  483. return f;
  484. }
  485. /*
  486. * merge common nodes under | and & moving the merged node
  487. * above the | or &.
  488. *
  489. * do some constant foldong, e.g. `true & x' becomes x and
  490. * 'true | x' becomes true.
  491. */
  492. static int changed;
  493. static Filter*
  494. _optimize(Filter *f)
  495. {
  496. Filter *l;
  497. if(f == nil)
  498. return f;
  499. switch(f->op){
  500. case '!':
  501. /* is child also a not */
  502. if(f->l->op == '!'){
  503. changed = 1;
  504. return f->l->l;
  505. }
  506. break;
  507. case LOR:
  508. /* are two children the same protocol? */
  509. if(f->l->op != f->r->op || f->r->op != WORD
  510. || f->l->pr != f->r->pr || f->l->pr == nil)
  511. break; /* no optimization */
  512. changed = 1;
  513. /* constant folding */
  514. /* if either child is childless, just return that */
  515. if(f->l->l == nil)
  516. return f->l;
  517. else if(f->r->l == nil)
  518. return f->r;
  519. /* move the common node up, thow away one node */
  520. l = f->l;
  521. f->l = l->l;
  522. f->r = f->r->l;
  523. l->l = f;
  524. return l;
  525. case LAND:
  526. /* are two children the same protocol? */
  527. if(f->l->op != f->r->op || f->r->op != WORD
  528. || f->l->pr != f->r->pr || f->l->pr == nil)
  529. break; /* no optimization */
  530. changed = 1;
  531. /* constant folding */
  532. /* if either child is childless, ignore it */
  533. if(f->l->l == nil)
  534. return f->r;
  535. else if(f->r->l == nil)
  536. return f->l;
  537. /* move the common node up, thow away one node */
  538. l = f->l;
  539. f->l = _optimize(l->l);
  540. f->r = _optimize(f->r->l);
  541. l->l = f;
  542. return l;
  543. }
  544. f->l = _optimize(f->l);
  545. f->r = _optimize(f->r);
  546. return f;
  547. }
  548. Filter*
  549. optimize(Filter *f)
  550. {
  551. do{
  552. changed = 0;
  553. f = _optimize(f);
  554. }while(changed);
  555. return f;
  556. }
  557. /*
  558. * find any top level nodes that aren't the root
  559. */
  560. int
  561. findbogus(Filter *f)
  562. {
  563. int rv;
  564. if(f->op != WORD){
  565. rv = findbogus(f->l);
  566. if(f->r)
  567. rv |= findbogus(f->r);
  568. return rv;
  569. } else if(f->pr != root){
  570. fprint(2, "bad top-level protocol: %s\n", f->s);
  571. return 1;
  572. }
  573. return 0;
  574. }
  575. /*
  576. * compile the filter
  577. */
  578. static void
  579. _compile(Filter *f, Proto *last)
  580. {
  581. if(f == nil)
  582. return;
  583. switch(f->op){
  584. case '!':
  585. _compile(f->l, last);
  586. break;
  587. case LOR:
  588. case LAND:
  589. _compile(f->l, last);
  590. _compile(f->r, last);
  591. break;
  592. case WORD:
  593. if(last != nil){
  594. if(last->compile == nil)
  595. sysfatal("unknown %s subprotocol: %s", f->pr->name, f->s);
  596. (*last->compile)(f);
  597. }
  598. if(f->l)
  599. _compile(f->l, f->pr);
  600. break;
  601. case '=':
  602. if(last == nil)
  603. sysfatal("internal error: compilewalk: badly formed tree");
  604. if(last->compile == nil)
  605. sysfatal("unknown %s field: %s", f->pr->name, f->s);
  606. (*last->compile)(f);
  607. break;
  608. default:
  609. sysfatal("internal error: compilewalk op: %d", f->op);
  610. }
  611. }
  612. Filter*
  613. compile(Filter *f)
  614. {
  615. if(f == nil)
  616. return f;
  617. /* fill in the missing header filters */
  618. f = complete(f, nil);
  619. /* constant folding */
  620. f = optimize(f);
  621. if(!toflag)
  622. printfilter(f, "after optimize");
  623. /* protocol specific compilations */
  624. _compile(f, nil);
  625. /* at this point, the root had better be the root proto */
  626. if(findbogus(f)){
  627. fprint(2, "bogus filter\n");
  628. exits("bad filter");
  629. }
  630. return f;
  631. }
  632. /*
  633. * parse a byte array
  634. */
  635. int
  636. parseba(uchar *to, char *from)
  637. {
  638. char nip[4];
  639. char *p;
  640. int i;
  641. p = from;
  642. for(i = 0; i < 16; i++){
  643. if(*p == 0)
  644. return -1;
  645. nip[0] = *p++;
  646. if(*p == 0)
  647. return -1;
  648. nip[1] = *p++;
  649. nip[2] = 0;
  650. to[i] = strtoul(nip, 0, 16);
  651. }
  652. return i;
  653. }
  654. /*
  655. * compile WORD = WORD, becomes a single node with a subop
  656. */
  657. void
  658. compile_cmp(char *proto, Filter *f, Field *fld)
  659. {
  660. uchar x[IPaddrlen];
  661. char *v;
  662. if(f->op != '=')
  663. sysfatal("internal error: compile_cmp %s: not a cmp", proto);
  664. for(; fld->name != nil; fld++){
  665. if(strcmp(f->l->s, fld->name) == 0){
  666. f->op = WORD;
  667. f->subop = fld->subop;
  668. switch(fld->ftype){
  669. case Fnum:
  670. f->ulv = atoi(f->r->s);
  671. break;
  672. case Fether:
  673. v = csgetvalue(nil, "sys", (char*)f->r->s,
  674. "ether", 0);
  675. if(v){
  676. parseether(f->a, v);
  677. free(v);
  678. } else
  679. parseether(f->a, f->r->s);
  680. break;
  681. case Fv4ip:
  682. v = csgetvalue(nil, "sys", (char*)f->r->s,
  683. "ip", 0);
  684. if(v){
  685. f->ulv = parseip(x, v);
  686. free(v);
  687. }else
  688. f->ulv = parseip(x, f->r->s);
  689. break;
  690. case Fv6ip:
  691. v = csgetvalue(nil, "sys", (char*)f->r->s,
  692. "ipv6", 0);
  693. if(v){
  694. parseip(f->a, v);
  695. free(v);
  696. }else
  697. parseip(f->a, f->r->s);
  698. break;
  699. case Fba:
  700. parseba(f->a, f->r->s);
  701. break;
  702. default:
  703. sysfatal("internal error: compile_cmp %s: %d",
  704. proto, fld->ftype);
  705. }
  706. f->l = f->r = nil;
  707. return;
  708. }
  709. }
  710. sysfatal("unknown %s field in: %s = %s", proto, f->l->s, f->r->s);
  711. }
  712. void
  713. _pf(Filter *f)
  714. {
  715. char *s;
  716. if(f == nil)
  717. return;
  718. s = nil;
  719. switch(f->op){
  720. case '!':
  721. fprint(2, "!");
  722. _pf(f->l);
  723. break;
  724. case WORD:
  725. fprint(2, "%s", f->s);
  726. if(f->l != nil){
  727. fprint(2, "(");
  728. _pf(f->l);
  729. fprint(2, ")");
  730. }
  731. break;
  732. case LAND:
  733. s = "&&";
  734. goto print;
  735. case LOR:
  736. s = "||";
  737. goto print;
  738. case '=':
  739. print:
  740. _pf(f->l);
  741. if(s)
  742. fprint(2, " %s ", s);
  743. else
  744. fprint(2, " %c ", f->op);
  745. _pf(f->r);
  746. break;
  747. default:
  748. fprint(2, "???");
  749. break;
  750. }
  751. }
  752. void
  753. printfilter(Filter *f, char *tag)
  754. {
  755. fprint(2, "%s: ", tag);
  756. _pf(f);
  757. fprint(2, "\n");
  758. }
  759. void
  760. cat(void)
  761. {
  762. char buf[1024];
  763. int n;
  764. while((n = read(0, buf, sizeof buf)) > 0)
  765. write(1, buf, n);
  766. }
  767. static int fd1 = -1;
  768. void
  769. startmc(void)
  770. {
  771. int p[2];
  772. if(fd1 == -1)
  773. fd1 = dup(1, -1);
  774. if(pipe(p) < 0)
  775. return;
  776. switch(fork()){
  777. case -1:
  778. return;
  779. default:
  780. close(p[0]);
  781. dup(p[1], 1);
  782. if(p[1] != 1)
  783. close(p[1]);
  784. return;
  785. case 0:
  786. close(p[1]);
  787. dup(p[0], 0);
  788. if(p[0] != 0)
  789. close(p[0]);
  790. execl("/bin/mc", "mc", nil);
  791. cat();
  792. _exits(0);
  793. }
  794. }
  795. void
  796. stopmc(void)
  797. {
  798. close(1);
  799. dup(fd1, 1);
  800. waitpid();
  801. }
  802. void
  803. printhelp(char *name)
  804. {
  805. int len;
  806. Proto *pr, **l;
  807. Mux *m;
  808. Field *f;
  809. char fmt[40];
  810. if(name == nil){
  811. print("protocols:\n");
  812. startmc();
  813. for(l=protos; (pr=*l) != nil; l++)
  814. print(" %s\n", pr->name);
  815. stopmc();
  816. return;
  817. }
  818. pr = findproto(name);
  819. if(pr == nil){
  820. print("unknown protocol %s\n", name);
  821. return;
  822. }
  823. if(pr->field){
  824. print("%s's filter attributes:\n", pr->name);
  825. len = 0;
  826. for(f=pr->field; f->name; f++)
  827. if(len < strlen(f->name))
  828. len = strlen(f->name);
  829. startmc();
  830. for(f=pr->field; f->name; f++)
  831. print(" %-*s - %s\n", len, f->name, f->help);
  832. stopmc();
  833. }
  834. if(pr->mux){
  835. print("%s's subprotos:\n", pr->name);
  836. startmc();
  837. snprint(fmt, sizeof fmt, " %s %%s\n", pr->valfmt);
  838. for(m=pr->mux; m->name != nil; m++)
  839. print(fmt, m->val, m->name);
  840. stopmc();
  841. }
  842. }
  843. /*
  844. * demultiplex to next prototol header
  845. */
  846. void
  847. demux(Mux *mx, ulong val1, ulong val2, Msg *m, Proto *def)
  848. {
  849. m->pr = def;
  850. for(mx = mx; mx->name != nil; mx++){
  851. if(val1 == mx->val || val2 == mx->val){
  852. m->pr = mx->pr;
  853. break;
  854. }
  855. }
  856. }
  857. /*
  858. * default framer just assumes the input packet is
  859. * a single read
  860. */
  861. int
  862. defaultframer(int fd, uchar *pkt, int pktlen)
  863. {
  864. return read(fd, pkt, pktlen);
  865. }