Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <ip.h>
4 #include <bio.h>
5 #include <fcall.h>
6 #include <libsec.h>
7 #include "dat.h"
8 #include "protos.h"
9 #include "y.tab.h"
11 int Cflag;
12 int pflag;
13 int Nflag;
14 int sflag;
15 int tiflag;
16 int toflag;
18 char *prom = "promiscuous";
20 enum
21 {
22 Pktlen= 64*1024,
23 Blen= 16*1024
24 };
26 Filter *filter;
27 Proto *root;
28 Biobuf out;
29 vlong starttime, pkttime;
30 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(int);
42 struct pcap_pkthdr {
43 u64int ts; /* time stamp */
44 u32int caplen; /* length of portion present */
45 u32int len; /* length this packet (off wire) */
46 };
49 void
50 printusage(void)
51 {
52 fprint(2, "usage: %s [-CDdpst] [-N n] [-f filter] [-h first-header] path\n", argv0);
53 fprint(2, " for protocol help: %s -? [proto]\n", argv0);
54 }
56 void
57 usage(void)
58 {
59 printusage();
60 exits("usage");
61 }
63 void
64 main(int argc, char **argv)
65 {
66 uchar *pkt;
67 char *buf, *file, *p, *e;
68 int fd;
69 int n;
71 Binit(&out, 1, OWRITE);
73 fmtinstall('E', eipfmt);
74 fmtinstall('V', eipfmt);
75 fmtinstall('I', eipfmt);
76 fmtinstall('H', encodefmt);
77 fmtinstall('F', fcallfmt);
79 pkt = malloc(Pktlen+16);
80 pkt += 16;
81 buf = malloc(Blen);
82 e = buf+Blen-1;
84 pflag = 1;
85 Nflag = 32;
86 sflag = 0;
88 mkprotograph();
90 ARGBEGIN{
91 default:
92 usage();
93 case '?':
94 printusage();
95 printhelp(ARGF());
96 exits(0);
97 break;
98 case 'N':
99 p = EARGF(usage());
100 Nflag = atoi(p);
101 break;
102 case 'f':
103 p = EARGF(usage());
104 yyinit(p);
105 yyparse();
106 break;
107 case 's':
108 sflag = 1;
109 break;
110 case 'h':
111 p = EARGF(usage());
112 root = findproto(p);
113 if(root == nil)
114 sysfatal("unknown protocol: %s", p);
115 break;
116 case 'd':
117 toflag = 1;
118 break;
119 case 'D':
120 toflag = 1;
121 pcap = 1;
122 break;
123 case 't':
124 tiflag = 1;
125 break;
126 case 'T':
127 tiflag = 1;
128 pcap = 1;
129 break;
130 case 'C':
131 Cflag = 1;
132 break;
133 case 'p':
134 pflag = 0;
135 break;
136 }ARGEND;
138 if(argc > 1)
139 usage();
141 if(argc == 0)
142 file = nil;
143 else
144 file = argv[0];
146 if(tiflag){
147 if(file == nil)
148 sysfatal("must specify file with -t");
149 fd = open(file, OREAD);
150 if(fd < 0)
151 sysfatal("opening %s: %r", file);
152 }else{
153 fd = opendevice(file, pflag);
154 if(fd < 0)
155 sysfatal("opening device %s: %r", file);
157 if(root == nil)
158 root = &ether;
160 if(pcap)
161 pcaphdr(fd);
163 filter = compile(filter);
165 if(tiflag){
166 /* read a trace file */
167 for(;;){
168 if(pcap){
169 struct pcap_pkthdr *goo;
170 n = read(fd, pkt, 16);
171 if(n != 16)
172 break;
173 goo = (struct pcap_pkthdr*)pkt;
174 pkttime = goo->ts;
175 n = goo->caplen;
176 }else{
177 n = read(fd, pkt, 10);
178 if(n != 10)
179 break;
180 pkttime = NetL(pkt+2);
181 pkttime = (pkttime<<32) | NetL(pkt+6);
182 if(starttime == 0LL)
183 starttime = pkttime;
184 n = NetS(pkt);
186 if(readn(fd, pkt, n) != n)
187 break;
188 if(filterpkt(filter, pkt, pkt+n, root, 1))
189 if(toflag)
190 tracepkt(pkt, n);
191 else
192 printpkt(buf, e, pkt, pkt+n);
194 } else {
195 /* read a real time stream */
196 starttime = nsec();
197 for(;;){
198 n = root->framer(fd, pkt, Pktlen);
199 if(n <= 0)
200 break;
201 pkttime = nsec();
202 if(filterpkt(filter, pkt, pkt+n, root, 1))
203 if(toflag)
204 tracepkt(pkt, n);
205 else
206 printpkt(buf, e, pkt, pkt+n);
211 /* create a new filter node */
212 Filter*
213 newfilter(void)
215 Filter *f;
217 f = mallocz(sizeof(*f), 1);
218 if(f == nil)
219 sysfatal("newfilter: %r");
220 return f;
223 /*
224 * apply filter to packet
225 */
226 int
227 _filterpkt(Filter *f, Msg *m)
229 Msg ma;
231 if(f == nil)
232 return 1;
234 switch(f->op){
235 case '!':
236 return !_filterpkt(f->l, m);
237 case LAND:
238 ma = *m;
239 return _filterpkt(f->l, &ma) && _filterpkt(f->r, m);
240 case LOR:
241 ma = *m;
242 return _filterpkt(f->l, &ma) || _filterpkt(f->r, m);
243 case WORD:
244 if(m->needroot){
245 if(m->pr != f->pr)
246 return 0;
247 m->needroot = 0;
248 }else{
249 if(m->pr && (m->pr->filter==nil || !(m->pr->filter)(f, m)))
250 return 0;
252 if(f->l == nil)
253 return 1;
254 m->pr = f->pr;
255 return _filterpkt(f->l, m);
257 sysfatal("internal error: filterpkt op: %d", f->op);
258 return 0;
260 int
261 filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot)
263 Msg m;
265 if(f == nil)
266 return 1;
268 m.needroot = needroot;
269 m.ps = ps;
270 m.pe = pe;
271 m.pr = pr;
272 return _filterpkt(f, &m);
275 /*
276 * from the Unix world
277 */
278 #define PCAP_VERSION_MAJOR 2
279 #define PCAP_VERSION_MINOR 4
280 #define TCPDUMP_MAGIC 0xa1b2c3d4
282 struct pcap_file_header {
283 u32int magic;
284 u16int version_major;
285 u16int version_minor;
286 s32int thiszone; /* gmt to local correction */
287 u32int sigfigs; /* accuracy of timestamps */
288 u32int snaplen; /* max length saved portion of each pkt */
289 u32int linktype; /* data link type (DLT_*) */
290 };
292 /*
293 * pcap trace header
294 */
295 void
296 pcaphdr(int fd)
298 if(tiflag){
299 struct pcap_file_header hdr;
301 if(readn(fd, &hdr, sizeof hdr) != sizeof hdr)
302 sysfatal("short header");
303 if(hdr.magic != TCPDUMP_MAGIC)
304 sysfatal("packet header %ux != %ux", hdr.magic, TCPDUMP_MAGIC);
305 if(hdr.version_major != PCAP_VERSION_MAJOR || hdr.version_minor != PCAP_VERSION_MINOR)
306 sysfatal("version %d.%d != %d.%d", hdr.version_major, hdr.version_minor, PCAP_VERSION_MAJOR, PCAP_VERSION_MINOR);
307 if(hdr.linktype != 1)
308 sysfatal("unknown linktype %d != 1 (ethernet)", hdr.linktype);
310 if(toflag){
311 struct pcap_file_header hdr;
313 hdr.magic = TCPDUMP_MAGIC;
314 hdr.version_major = PCAP_VERSION_MAJOR;
315 hdr.version_minor = PCAP_VERSION_MINOR;
317 hdr.thiszone = 0;
318 hdr.snaplen = 1500;
319 hdr.sigfigs = 0;
320 hdr.linktype = 1;
322 write(1, &hdr, sizeof(hdr));
326 /*
327 * write out a packet trace
328 */
329 void
330 tracepkt(uchar *ps, int len)
332 struct pcap_pkthdr *goo;
334 if(pcap){
335 goo = (struct pcap_pkthdr*)(ps-16);
336 goo->ts = pkttime;
337 goo->caplen = len;
338 goo->len = len;
339 write(1, goo, len+16);
340 } else {
341 hnputs(ps-10, len);
342 hnputl(ps-8, pkttime>>32);
343 hnputl(ps-4, pkttime);
344 write(1, ps-10, len+10);
348 /*
349 * format and print a packet
350 */
351 void
352 printpkt(char *p, char *e, uchar *ps, uchar *pe)
354 Msg m;
355 ulong dt;
357 dt = (pkttime-starttime)/1000000LL;
358 m.p = seprint(p, e, "%6.6uld ms ", dt);
359 m.ps = ps;
360 m.pe = pe;
361 m.e = e;
362 m.pr = root;
363 while(m.p < m.e){
364 if(!sflag)
365 m.p = seprint(m.p, m.e, "\n\t");
366 m.p = seprint(m.p, m.e, "%s(", m.pr->name);
367 if((*m.pr->seprint)(&m) < 0){
368 m.p = seprint(m.p, m.e, "TOO SHORT");
369 m.ps = m.pe;
371 m.p = seprint(m.p, m.e, ")");
372 if(m.pr == nil || m.ps >= m.pe)
373 break;
375 *m.p++ = '\n';
377 if(write(1, p, m.p - p) < 0)
378 sysfatal("stdout: %r");
381 Proto **xprotos;
382 int nprotos;
384 /* look up a protocol by its name */
385 Proto*
386 findproto(char *name)
388 int i;
390 for(i = 0; i < nprotos; i++)
391 if(strcmp(xprotos[i]->name, name) == 0)
392 return xprotos[i];
393 return nil;
396 /*
397 * add an undefined protocol to protos[]
398 */
399 Proto*
400 addproto(char *name)
402 Proto *pr;
404 xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*));
405 pr = malloc(sizeof *pr);
406 *pr = dump;
407 pr->name = name;
408 xprotos[nprotos++] = pr;
409 return pr;
412 /*
413 * build a graph of protocols, this could easily be circular. This
414 * links together all the multiplexing in the protocol modules.
415 */
416 void
417 mkprotograph(void)
419 Proto **l;
420 Proto *pr;
421 Mux *m;
423 /* copy protos into a reallocable area */
424 for(nprotos = 0; protos[nprotos] != nil; nprotos++)
426 xprotos = malloc(nprotos*sizeof(Proto*));
427 memmove(xprotos, protos, nprotos*sizeof(Proto*));
429 for(l = protos; *l != nil; l++){
430 pr = *l;
431 for(m = pr->mux; m != nil && m->name != nil; m++){
432 m->pr = findproto(m->name);
433 if(m->pr == nil)
434 m->pr = addproto(m->name);
439 /*
440 * add in a protocol node
441 */
442 static Filter*
443 addnode(Filter *f, Proto *pr)
445 Filter *nf;
446 nf = newfilter();
447 nf->pr = pr;
448 nf->s = pr->name;
449 nf->l = f;
450 nf->op = WORD;
451 return nf;
454 /*
455 * recurse through the protocol graph adding missing nodes
456 * to the filter if we reach the filter's protocol
457 */
458 static Filter*
459 _fillin(Filter *f, Proto *last, int depth)
461 Mux *m;
462 Filter *nf;
464 if(depth-- <= 0)
465 return nil;
467 for(m = last->mux; m != nil && m->name != nil; m++){
468 if(m->pr == nil)
469 continue;
470 if(f->pr == m->pr)
471 return f;
472 nf = _fillin(f, m->pr, depth);
473 if(nf != nil)
474 return addnode(nf, m->pr);
476 return nil;
479 static Filter*
480 fillin(Filter *f, Proto *last)
482 int i;
483 Filter *nf;
485 /* hack to make sure top level node is the root */
486 if(last == nil){
487 if(f->pr == root)
488 return f;
489 f = fillin(f, root);
490 if(f == nil)
491 return nil;
492 return addnode(f, root);
495 /* breadth first search though the protocol graph */
496 nf = f;
497 for(i = 1; i < 20; i++){
498 nf = _fillin(f, last, i);
499 if(nf != nil)
500 break;
502 return nf;
505 /*
506 * massage tree so that all paths from the root to a leaf
507 * contain a filter node for each header.
509 * also, set f->pr where possible
510 */
511 Filter*
512 complete(Filter *f, Proto *last)
514 Proto *pr;
516 if(f == nil)
517 return f;
519 /* do a depth first traversal of the filter tree */
520 switch(f->op){
521 case '!':
522 f->l = complete(f->l, last);
523 break;
524 case LAND:
525 case LOR:
526 f->l = complete(f->l, last);
527 f->r = complete(f->r, last);
528 break;
529 case '=':
530 break;
531 case WORD:
532 pr = findproto(f->s);
533 f->pr = pr;
534 if(pr == nil){
535 if(f->l != nil){
536 fprint(2, "%s unknown proto, ignoring params\n",
537 f->s);
538 f->l = nil;
540 } else {
541 f->l = complete(f->l, pr);
542 f = fillin(f, last);
543 if(f == nil)
544 sysfatal("internal error: can't get to %s", pr->name);
546 break;
548 return f;
551 /*
552 * merge common nodes under | and & moving the merged node
553 * above the | or &.
555 * do some constant foldong, e.g. `true & x' becomes x and
556 * 'true | x' becomes true.
557 */
558 static int changed;
560 static Filter*
561 _optimize(Filter *f)
563 Filter *l;
565 if(f == nil)
566 return f;
568 switch(f->op){
569 case '!':
570 /* is child also a not */
571 if(f->l->op == '!'){
572 changed = 1;
573 return f->l->l;
575 break;
576 case LOR:
577 /* are two children the same protocol? */
578 if(f->l->op != f->r->op || f->r->op != WORD
579 || f->l->pr != f->r->pr || f->l->pr == nil)
580 break; /* no optimization */
582 changed = 1;
584 /* constant folding */
585 /* if either child is childless, just return that */
586 if(f->l->l == nil)
587 return f->l;
588 else if(f->r->l == nil)
589 return f->r;
591 /* move the common node up, thow away one node */
592 l = f->l;
593 f->l = l->l;
594 f->r = f->r->l;
595 l->l = f;
596 return l;
597 case LAND:
598 /* are two children the same protocol? */
599 if(f->l->op != f->r->op || f->r->op != WORD
600 || f->l->pr != f->r->pr || f->l->pr == nil)
601 break; /* no optimization */
603 changed = 1;
605 /* constant folding */
606 /* if either child is childless, ignore it */
607 if(f->l->l == nil)
608 return f->r;
609 else if(f->r->l == nil)
610 return f->l;
612 /* move the common node up, thow away one node */
613 l = f->l;
614 f->l = _optimize(l->l);
615 f->r = _optimize(f->r->l);
616 l->l = f;
617 return l;
619 f->l = _optimize(f->l);
620 f->r = _optimize(f->r);
621 return f;
624 Filter*
625 optimize(Filter *f)
627 do{
628 changed = 0;
629 f = _optimize(f);
630 }while(changed);
632 return f;
635 /*
636 * find any top level nodes that aren't the root
637 */
638 int
639 findbogus(Filter *f)
641 int rv;
643 if(f->op != WORD){
644 rv = findbogus(f->l);
645 if(f->r)
646 rv |= findbogus(f->r);
647 return rv;
648 } else if(f->pr != root){
649 fprint(2, "bad top-level protocol: %s\n", f->s);
650 return 1;
652 return 0;
655 /*
656 * compile the filter
657 */
658 static void
659 _compile(Filter *f, Proto *last)
661 if(f == nil)
662 return;
664 switch(f->op){
665 case '!':
666 _compile(f->l, last);
667 break;
668 case LOR:
669 case LAND:
670 _compile(f->l, last);
671 _compile(f->r, last);
672 break;
673 case WORD:
674 if(last != nil){
675 if(last->compile == nil)
676 sysfatal("unknown %s subprotocol: %s", f->pr->name, f->s);
677 (*last->compile)(f);
679 if(f->l)
680 _compile(f->l, f->pr);
681 break;
682 case '=':
683 if(last == nil)
684 sysfatal("internal error: compilewalk: badly formed tree");
686 if(last->compile == nil)
687 sysfatal("unknown %s field: %s", f->pr->name, f->s);
688 (*last->compile)(f);
689 break;
690 default:
691 sysfatal("internal error: compilewalk op: %d", f->op);
695 Filter*
696 compile(Filter *f)
698 if(f == nil)
699 return f;
701 /* fill in the missing header filters */
702 f = complete(f, nil);
704 /* constant folding */
705 f = optimize(f);
706 if(!toflag)
707 printfilter(f, "after optimize");
709 /* protocol specific compilations */
710 _compile(f, nil);
712 /* at this point, the root had better be the root proto */
713 if(findbogus(f)){
714 fprint(2, "bogus filter\n");
715 exits("bad filter");
718 return f;
721 /*
722 * parse a byte array
723 */
724 int
725 parseba(uchar *to, char *from)
727 char nip[4];
728 char *p;
729 int i;
731 p = from;
732 for(i = 0; i < 16; i++){
733 if(*p == 0)
734 return -1;
735 nip[0] = *p++;
736 if(*p == 0)
737 return -1;
738 nip[1] = *p++;
739 nip[2] = 0;
740 to[i] = strtoul(nip, 0, 16);
742 return i;
745 /*
746 * compile WORD = WORD, becomes a single node with a subop
747 */
748 void
749 compile_cmp(char *proto, Filter *f, Field *fld)
751 uchar x[IPaddrlen];
753 if(f->op != '=')
754 sysfatal("internal error: compile_cmp %s: not a cmp", proto);
756 for(; fld->name != nil; fld++){
757 if(strcmp(f->l->s, fld->name) == 0){
758 f->op = WORD;
759 f->subop = fld->subop;
760 switch(fld->ftype){
761 case Fnum:
762 f->ulv = atoi(f->r->s);
763 break;
764 case Fether:
765 parseether(f->a, f->r->s);
766 break;
767 case Fv4ip:
768 f->ulv = parseip(x, f->r->s);
769 break;
770 case Fv6ip:
771 parseip(f->a, f->r->s);
772 break;
773 case Fba:
774 parseba(f->a, f->r->s);
775 break;
776 default:
777 sysfatal("internal error: compile_cmp %s: %d",
778 proto, fld->ftype);
780 f->l = f->r = nil;
781 return;
784 sysfatal("unknown %s field in: %s = %s", proto, f->l->s, f->r->s);
787 void
788 _pf(Filter *f)
790 char *s;
792 if(f == nil)
793 return;
795 s = nil;
796 switch(f->op){
797 case '!':
798 fprint(2, "!");
799 _pf(f->l);
800 break;
801 case WORD:
802 fprint(2, "%s", f->s);
803 if(f->l != nil){
804 fprint(2, "(");
805 _pf(f->l);
806 fprint(2, ")");
808 break;
809 case LAND:
810 s = "&&";
811 goto print;
812 case LOR:
813 s = "||";
814 goto print;
815 case '=':
816 print:
817 _pf(f->l);
818 if(s)
819 fprint(2, " %s ", s);
820 else
821 fprint(2, " %c ", f->op);
822 _pf(f->r);
823 break;
824 default:
825 fprint(2, "???");
826 break;
830 void
831 printfilter(Filter *f, char *tag)
833 fprint(2, "%s: ", tag);
834 _pf(f);
835 fprint(2, "\n");
838 void
839 cat(void)
841 char buf[1024];
842 int n;
844 while((n = read(0, buf, sizeof buf)) > 0)
845 write(1, buf, n);
848 static int fd1 = -1;
849 void
850 startmc(void)
852 int p[2];
854 if(fd1 == -1)
855 fd1 = dup(1, -1);
857 if(pipe(p) < 0)
858 return;
859 switch(fork()){
860 case -1:
861 return;
862 default:
863 close(p[0]);
864 dup(p[1], 1);
865 if(p[1] != 1)
866 close(p[1]);
867 return;
868 case 0:
869 close(p[1]);
870 dup(p[0], 0);
871 if(p[0] != 0)
872 close(p[0]);
873 execl("/bin/mc", "mc", nil);
874 cat();
875 _exits(0);
879 void
880 stopmc(void)
882 close(1);
883 dup(fd1, 1);
884 waitpid();
887 void
888 printhelp(char *name)
890 int len;
891 Proto *pr, **l;
892 Mux *m;
893 Field *f;
894 char fmt[40];
896 if(name == nil){
897 print("protocols:\n");
898 startmc();
899 for(l=protos; (pr=*l) != nil; l++)
900 print(" %s\n", pr->name);
901 stopmc();
902 return;
905 pr = findproto(name);
906 if(pr == nil){
907 print("unknown protocol %s\n", name);
908 return;
911 if(pr->field){
912 print("%s's filter attributes:\n", pr->name);
913 len = 0;
914 for(f=pr->field; f->name; f++)
915 if(len < strlen(f->name))
916 len = strlen(f->name);
917 startmc();
918 for(f=pr->field; f->name; f++)
919 print(" %-*s - %s\n", len, f->name, f->help);
920 stopmc();
922 if(pr->mux){
923 print("%s's subprotos:\n", pr->name);
924 startmc();
925 snprint(fmt, sizeof fmt, " %s %%s\n", pr->valfmt);
926 for(m=pr->mux; m->name != nil; m++)
927 print(fmt, m->val, m->name);
928 stopmc();
932 /*
933 * demultiplex to next prototol header
934 */
935 void
936 demux(Mux *mx, ulong val1, ulong val2, Msg *m, Proto *def)
938 m->pr = def;
939 for(mx = mx; mx->name != nil; mx++){
940 if(val1 == mx->val || val2 == mx->val){
941 m->pr = mx->pr;
942 break;
947 /*
948 * default framer just assumes the input packet is
949 * a single read
950 */
951 int
952 defaultframer(int fd, uchar *pkt, int pktlen)
954 return read(fd, pkt, pktlen);