18 char *prom = "promiscuous";
29 vlong starttime, pkttime;
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);
45 fprint(2, "usage: %s [-CDdpst] [-N n] [-f filter] [-h first-header] path\n", argv0);
46 fprint(2, " for protocol help: %s -? [proto]\n", argv0);
57 main(int argc, char **argv)
60 char *buf, *file, *p, *e;
64 Binit(&out, 1, OWRITE);
66 fmtinstall('E', eipfmt);
67 fmtinstall('V', eipfmt);
68 fmtinstall('I', eipfmt);
69 fmtinstall('H', encodefmt);
70 fmtinstall('F', fcallfmt);
72 pkt = malloc(Pktlen+16);
107 sysfatal("unknown protocol: %s", p);
140 sysfatal("must specify file with -t");
141 fd = open(file, OREAD);
143 sysfatal("opening %s: %r", file);
145 fd = opendevice(file, pflag);
147 sysfatal("opening device %s: %r", file);
152 filter = compile(filter);
155 /* read a trace file */
157 n = read(fd, pkt, 10);
160 pkttime = NetL(pkt+2);
161 pkttime = (pkttime<<32) | NetL(pkt+6);
165 if(readn(fd, pkt, n) != n)
167 if(filterpkt(filter, pkt, pkt+n, root, 1))
171 printpkt(buf, e, pkt, pkt+n);
174 /* read a real time stream */
177 n = root->framer(fd, pkt, Pktlen);
181 if(filterpkt(filter, pkt, pkt+n, root, 1))
185 printpkt(buf, e, pkt, pkt+n);
190 /* create a new filter node */
196 f = mallocz(sizeof(*f), 1);
198 sysfatal("newfilter: %r");
203 * apply filter to packet
206 _filterpkt(Filter *f, Msg *m)
215 return !_filterpkt(f->l, m);
218 return _filterpkt(f->l, &ma) && _filterpkt(f->r, m);
221 return _filterpkt(f->l, &ma) || _filterpkt(f->r, m);
228 if(m->pr && (m->pr->filter==nil || !(m->pr->filter)(f, m)))
234 return _filterpkt(f->l, m);
236 sysfatal("internal error: filterpkt op: %d", f->op);
240 filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot)
247 m.needroot = needroot;
251 return _filterpkt(f, &m);
255 * from the Unix world
257 #define PCAP_VERSION_MAJOR 2
258 #define PCAP_VERSION_MINOR 4
259 #define TCPDUMP_MAGIC 0xa1b2c3d4
261 struct pcap_file_header {
263 ushort version_major;
264 ushort version_minor;
265 long thiszone; /* gmt to local correction */
266 ulong sigfigs; /* accuracy of timestamps */
267 ulong snaplen; /* max length saved portion of each pkt */
268 ulong linktype; /* data link type (DLT_*) */
272 uvlong ts; /* time stamp */
273 ulong caplen; /* length of portion present */
274 ulong len; /* length this packet (off wire) */
283 struct pcap_file_header hdr;
285 hdr.magic = TCPDUMP_MAGIC;
286 hdr.version_major = PCAP_VERSION_MAJOR;
287 hdr.version_minor = PCAP_VERSION_MINOR;
294 write(1, &hdr, sizeof(hdr));
298 * write out a packet trace
301 tracepkt(uchar *ps, int len)
303 struct pcap_pkthdr *goo;
306 goo = (struct pcap_pkthdr*)(ps-16);
310 write(1, goo, len+16);
313 hnputl(ps-8, pkttime>>32);
314 hnputl(ps-4, pkttime);
315 write(1, ps-10, len+10);
320 * format and print a packet
323 printpkt(char *p, char *e, uchar *ps, uchar *pe)
328 dt = (pkttime-starttime)/1000000LL;
329 m.p = seprint(p, e, "%6.6uld ms ", dt);
336 m.p = seprint(m.p, m.e, "\n\t");
337 m.p = seprint(m.p, m.e, "%s(", m.pr->name);
338 if((*m.pr->seprint)(&m) < 0){
339 m.p = seprint(m.p, m.e, "TOO SHORT");
342 m.p = seprint(m.p, m.e, ")");
343 if(m.pr == nil || m.ps >= m.pe)
348 if(write(1, p, m.p - p) < 0)
349 sysfatal("stdout: %r");
355 /* look up a protocol by its name */
357 findproto(char *name)
361 for(i = 0; i < nprotos; i++)
362 if(strcmp(xprotos[i]->name, name) == 0)
368 * add an undefined protocol to protos[]
375 xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*));
376 pr = malloc(sizeof *pr);
379 xprotos[nprotos++] = pr;
384 * build a graph of protocols, this could easily be circular. This
385 * links together all the multiplexing in the protocol modules.
394 /* copy protos into a reallocable area */
395 for(nprotos = 0; protos[nprotos] != nil; nprotos++)
397 xprotos = malloc(nprotos*sizeof(Proto*));
398 memmove(xprotos, protos, nprotos*sizeof(Proto*));
400 for(l = protos; *l != nil; l++){
402 for(m = pr->mux; m != nil && m->name != nil; m++){
403 m->pr = findproto(m->name);
405 m->pr = addproto(m->name);
411 * add in a protocol node
414 addnode(Filter *f, Proto *pr)
426 * recurse through the protocol graph adding missing nodes
427 * to the filter if we reach the filter's protocol
430 _fillin(Filter *f, Proto *last, int depth)
438 for(m = last->mux; m != nil && m->name != nil; m++){
443 nf = _fillin(f, m->pr, depth);
445 return addnode(nf, m->pr);
451 fillin(Filter *f, Proto *last)
456 /* hack to make sure top level node is the root */
463 return addnode(f, root);
466 /* breadth first search though the protocol graph */
468 for(i = 1; i < 20; i++){
469 nf = _fillin(f, last, i);
477 * massage tree so that all paths from the root to a leaf
478 * contain a filter node for each header.
480 * also, set f->pr where possible
483 complete(Filter *f, Proto *last)
490 /* do a depth first traversal of the filter tree */
493 f->l = complete(f->l, last);
497 f->l = complete(f->l, last);
498 f->r = complete(f->r, last);
503 pr = findproto(f->s);
507 fprint(2, "%s unknown proto, ignoring params\n",
512 f->l = complete(f->l, pr);
515 sysfatal("internal error: can't get to %s", pr->name);
523 * merge common nodes under | and & moving the merged node
526 * do some constant foldong, e.g. `true & x' becomes x and
527 * 'true | x' becomes true.
541 /* is child also a not */
548 /* are two children the same protocol? */
549 if(f->l->op != f->r->op || f->r->op != WORD
550 || f->l->pr != f->r->pr || f->l->pr == nil)
551 break; /* no optimization */
555 /* constant folding */
556 /* if either child is childless, just return that */
559 else if(f->r->l == nil)
562 /* move the common node up, thow away one node */
569 /* are two children the same protocol? */
570 if(f->l->op != f->r->op || f->r->op != WORD
571 || f->l->pr != f->r->pr || f->l->pr == nil)
572 break; /* no optimization */
576 /* constant folding */
577 /* if either child is childless, ignore it */
580 else if(f->r->l == nil)
583 /* move the common node up, thow away one node */
585 f->l = _optimize(l->l);
586 f->r = _optimize(f->r->l);
590 f->l = _optimize(f->l);
591 f->r = _optimize(f->r);
607 * find any top level nodes that aren't the root
615 rv = findbogus(f->l);
617 rv |= findbogus(f->r);
619 } else if(f->pr != root){
620 fprint(2, "bad top-level protocol: %s\n", f->s);
630 _compile(Filter *f, Proto *last)
637 _compile(f->l, last);
641 _compile(f->l, last);
642 _compile(f->r, last);
646 if(last->compile == nil)
647 sysfatal("unknown %s subprotocol: %s", f->pr->name, f->s);
651 _compile(f->l, f->pr);
655 sysfatal("internal error: compilewalk: badly formed tree");
657 if(last->compile == nil)
658 sysfatal("unknown %s field: %s", f->pr->name, f->s);
662 sysfatal("internal error: compilewalk op: %d", f->op);
672 /* fill in the missing header filters */
673 f = complete(f, nil);
675 /* constant folding */
678 printfilter(f, "after optimize");
680 /* protocol specific compilations */
683 /* at this point, the root had better be the root proto */
685 fprint(2, "bogus filter\n");
696 parseba(uchar *to, char *from)
703 for(i = 0; i < 16; i++){
711 to[i] = strtoul(nip, 0, 16);
717 * compile WORD = WORD, becomes a single node with a subop
720 compile_cmp(char *proto, Filter *f, Field *fld)
725 sysfatal("internal error: compile_cmp %s: not a cmp", proto);
727 for(; fld->name != nil; fld++){
728 if(strcmp(f->l->s, fld->name) == 0){
730 f->subop = fld->subop;
733 f->ulv = atoi(f->r->s);
736 parseether(f->a, f->r->s);
739 f->ulv = parseip(x, f->r->s);
742 parseip(f->a, f->r->s);
745 parseba(f->a, f->r->s);
748 sysfatal("internal error: compile_cmp %s: %d",
755 sysfatal("unknown %s field in: %s = %s", proto, f->l->s, f->r->s);
773 fprint(2, "%s", f->s);
790 fprint(2, " %s ", s);
792 fprint(2, " %c ", f->op);
802 printfilter(Filter *f, char *tag)
804 fprint(2, "%s: ", tag);
815 while((n = read(0, buf, sizeof buf)) > 0)
844 execl("/bin/mc", "mc", nil);
859 printhelp(char *name)
868 print("protocols:\n");
870 for(l=protos; (pr=*l) != nil; l++)
871 print(" %s\n", pr->name);
876 pr = findproto(name);
878 print("unknown protocol %s\n", name);
883 print("%s's filter attributes:\n", pr->name);
885 for(f=pr->field; f->name; f++)
886 if(len < strlen(f->name))
887 len = strlen(f->name);
889 for(f=pr->field; f->name; f++)
890 print(" %-*s - %s\n", len, f->name, f->help);
894 print("%s's subprotos:\n", pr->name);
896 snprint(fmt, sizeof fmt, " %s %%s\n", pr->valfmt);
897 for(m=pr->mux; m->name != nil; m++)
898 print(fmt, m->val, m->name);
904 * demultiplex to next prototol header
907 demux(Mux *mx, ulong val1, ulong val2, Msg *m, Proto *def)
910 for(mx = mx; mx->name != nil; mx++){
911 if(val1 == mx->val || val2 == mx->val){
919 * default framer just assumes the input packet is
923 defaultframer(int fd, uchar *pkt, int pktlen)
925 return read(fd, pkt, pktlen);