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