main.c (16062B)
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" 10 11 int Cflag; 12 int pflag; 13 int Nflag; 14 int sflag; 15 int tiflag; 16 int toflag; 17 18 char *prom = "promiscuous"; 19 20 enum 21 { 22 Pktlen= 64*1024, 23 Blen= 16*1024 24 }; 25 26 Filter *filter; 27 Proto *root; 28 Biobuf out; 29 vlong starttime, pkttime; 30 int pcap; 31 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); 41 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 }; 47 48 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 } 55 56 void 57 usage(void) 58 { 59 printusage(); 60 exits("usage"); 61 } 62 63 void 64 main(int argc, char **argv) 65 { 66 uchar *pkt; 67 char *buf, *file, *p, *e; 68 int fd; 69 int n; 70 71 Binit(&out, 1, OWRITE); 72 73 fmtinstall('E', eipfmt); 74 fmtinstall('V', eipfmt); 75 fmtinstall('I', eipfmt); 76 fmtinstall('H', encodefmt); 77 fmtinstall('F', fcallfmt); 78 79 pkt = malloc(Pktlen+16); 80 pkt += 16; 81 buf = malloc(Blen); 82 e = buf+Blen-1; 83 84 pflag = 1; 85 Nflag = 32; 86 sflag = 0; 87 88 mkprotograph(); 89 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; 137 138 if(argc > 1) 139 usage(); 140 141 if(argc == 0) 142 file = nil; 143 else 144 file = argv[0]; 145 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); 156 } 157 if(root == nil) 158 root = ðer; 159 160 if(pcap) 161 pcaphdr(fd); 162 163 filter = compile(filter); 164 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); 185 } 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); 193 } 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); 207 } 208 } 209 } 210 211 /* create a new filter node */ 212 Filter* 213 newfilter(void) 214 { 215 Filter *f; 216 217 f = mallocz(sizeof(*f), 1); 218 if(f == nil) 219 sysfatal("newfilter: %r"); 220 return f; 221 } 222 223 /* 224 * apply filter to packet 225 */ 226 int 227 _filterpkt(Filter *f, Msg *m) 228 { 229 Msg ma; 230 231 if(f == nil) 232 return 1; 233 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; 251 } 252 if(f->l == nil) 253 return 1; 254 m->pr = f->pr; 255 return _filterpkt(f->l, m); 256 } 257 sysfatal("internal error: filterpkt op: %d", f->op); 258 return 0; 259 } 260 int 261 filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot) 262 { 263 Msg m; 264 265 if(f == nil) 266 return 1; 267 268 m.needroot = needroot; 269 m.ps = ps; 270 m.pe = pe; 271 m.pr = pr; 272 return _filterpkt(f, &m); 273 } 274 275 /* 276 * from the Unix world 277 */ 278 #define PCAP_VERSION_MAJOR 2 279 #define PCAP_VERSION_MINOR 4 280 #define TCPDUMP_MAGIC 0xa1b2c3d4 281 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 }; 291 292 /* 293 * pcap trace header 294 */ 295 void 296 pcaphdr(int fd) 297 { 298 if(tiflag){ 299 struct pcap_file_header hdr; 300 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); 309 } 310 if(toflag){ 311 struct pcap_file_header hdr; 312 313 hdr.magic = TCPDUMP_MAGIC; 314 hdr.version_major = PCAP_VERSION_MAJOR; 315 hdr.version_minor = PCAP_VERSION_MINOR; 316 317 hdr.thiszone = 0; 318 hdr.snaplen = 1500; 319 hdr.sigfigs = 0; 320 hdr.linktype = 1; 321 322 write(1, &hdr, sizeof(hdr)); 323 } 324 } 325 326 /* 327 * write out a packet trace 328 */ 329 void 330 tracepkt(uchar *ps, int len) 331 { 332 struct pcap_pkthdr *goo; 333 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); 345 } 346 } 347 348 /* 349 * format and print a packet 350 */ 351 void 352 printpkt(char *p, char *e, uchar *ps, uchar *pe) 353 { 354 Msg m; 355 ulong dt; 356 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; 370 } 371 m.p = seprint(m.p, m.e, ")"); 372 if(m.pr == nil || m.ps >= m.pe) 373 break; 374 } 375 *m.p++ = '\n'; 376 377 if(write(1, p, m.p - p) < 0) 378 sysfatal("stdout: %r"); 379 } 380 381 Proto **xprotos; 382 int nprotos; 383 384 /* look up a protocol by its name */ 385 Proto* 386 findproto(char *name) 387 { 388 int i; 389 390 for(i = 0; i < nprotos; i++) 391 if(strcmp(xprotos[i]->name, name) == 0) 392 return xprotos[i]; 393 return nil; 394 } 395 396 /* 397 * add an undefined protocol to protos[] 398 */ 399 Proto* 400 addproto(char *name) 401 { 402 Proto *pr; 403 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; 410 } 411 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) 418 { 419 Proto **l; 420 Proto *pr; 421 Mux *m; 422 423 /* copy protos into a reallocable area */ 424 for(nprotos = 0; protos[nprotos] != nil; nprotos++) 425 ; 426 xprotos = malloc(nprotos*sizeof(Proto*)); 427 memmove(xprotos, protos, nprotos*sizeof(Proto*)); 428 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); 435 } 436 } 437 } 438 439 /* 440 * add in a protocol node 441 */ 442 static Filter* 443 addnode(Filter *f, Proto *pr) 444 { 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; 452 } 453 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) 460 { 461 Mux *m; 462 Filter *nf; 463 464 if(depth-- <= 0) 465 return nil; 466 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); 475 } 476 return nil; 477 } 478 479 static Filter* 480 fillin(Filter *f, Proto *last) 481 { 482 int i; 483 Filter *nf; 484 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); 493 } 494 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; 501 } 502 return nf; 503 } 504 505 /* 506 * massage tree so that all paths from the root to a leaf 507 * contain a filter node for each header. 508 * 509 * also, set f->pr where possible 510 */ 511 Filter* 512 complete(Filter *f, Proto *last) 513 { 514 Proto *pr; 515 516 if(f == nil) 517 return f; 518 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; 539 } 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); 545 } 546 break; 547 } 548 return f; 549 } 550 551 /* 552 * merge common nodes under | and & moving the merged node 553 * above the | or &. 554 * 555 * do some constant foldong, e.g. `true & x' becomes x and 556 * 'true | x' becomes true. 557 */ 558 static int changed; 559 560 static Filter* 561 _optimize(Filter *f) 562 { 563 Filter *l; 564 565 if(f == nil) 566 return f; 567 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; 574 } 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 */ 581 582 changed = 1; 583 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; 590 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 */ 602 603 changed = 1; 604 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; 611 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; 618 } 619 f->l = _optimize(f->l); 620 f->r = _optimize(f->r); 621 return f; 622 } 623 624 Filter* 625 optimize(Filter *f) 626 { 627 do{ 628 changed = 0; 629 f = _optimize(f); 630 }while(changed); 631 632 return f; 633 } 634 635 /* 636 * find any top level nodes that aren't the root 637 */ 638 int 639 findbogus(Filter *f) 640 { 641 int rv; 642 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; 651 } 652 return 0; 653 } 654 655 /* 656 * compile the filter 657 */ 658 static void 659 _compile(Filter *f, Proto *last) 660 { 661 if(f == nil) 662 return; 663 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); 678 } 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"); 685 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); 692 } 693 } 694 695 Filter* 696 compile(Filter *f) 697 { 698 if(f == nil) 699 return f; 700 701 /* fill in the missing header filters */ 702 f = complete(f, nil); 703 704 /* constant folding */ 705 f = optimize(f); 706 if(!toflag) 707 printfilter(f, "after optimize"); 708 709 /* protocol specific compilations */ 710 _compile(f, nil); 711 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"); 716 } 717 718 return f; 719 } 720 721 /* 722 * parse a byte array 723 */ 724 int 725 parseba(uchar *to, char *from) 726 { 727 char nip[4]; 728 char *p; 729 int i; 730 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); 741 } 742 return i; 743 } 744 745 /* 746 * compile WORD = WORD, becomes a single node with a subop 747 */ 748 void 749 compile_cmp(char *proto, Filter *f, Field *fld) 750 { 751 uchar x[IPaddrlen]; 752 753 if(f->op != '=') 754 sysfatal("internal error: compile_cmp %s: not a cmp", proto); 755 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); 779 } 780 f->l = f->r = nil; 781 return; 782 } 783 } 784 sysfatal("unknown %s field in: %s = %s", proto, f->l->s, f->r->s); 785 } 786 787 void 788 _pf(Filter *f) 789 { 790 char *s; 791 792 if(f == nil) 793 return; 794 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, ")"); 807 } 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; 827 } 828 } 829 830 void 831 printfilter(Filter *f, char *tag) 832 { 833 fprint(2, "%s: ", tag); 834 _pf(f); 835 fprint(2, "\n"); 836 } 837 838 void 839 cat(void) 840 { 841 char buf[1024]; 842 int n; 843 844 while((n = read(0, buf, sizeof buf)) > 0) 845 write(1, buf, n); 846 } 847 848 static int fd1 = -1; 849 void 850 startmc(void) 851 { 852 int p[2]; 853 854 if(fd1 == -1) 855 fd1 = dup(1, -1); 856 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); 876 } 877 } 878 879 void 880 stopmc(void) 881 { 882 close(1); 883 dup(fd1, 1); 884 waitpid(); 885 } 886 887 void 888 printhelp(char *name) 889 { 890 int len; 891 Proto *pr, **l; 892 Mux *m; 893 Field *f; 894 char fmt[40]; 895 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; 903 } 904 905 pr = findproto(name); 906 if(pr == nil){ 907 print("unknown protocol %s\n", name); 908 return; 909 } 910 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(); 921 } 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(); 929 } 930 } 931 932 /* 933 * demultiplex to next prototol header 934 */ 935 void 936 demux(Mux *mx, ulong val1, ulong val2, Msg *m, Proto *def) 937 { 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; 943 } 944 } 945 } 946 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) 953 { 954 return read(fd, pkt, pktlen); 955 }