/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * snoopy - network sniffer */#include <u.h>#include <libc.h>#include <ip.h>#include <bio.h>#include <fcall.h>#include <libsec.h>#include <ndb.h>#include "dat.h"#include "protos.h"#include "y.tab.h" int Cflag;int pflag;int Nflag;int Mflag;int sflag;int tiflag;int toflag; char *prom = "promiscuous"; enum{ Pktlen= 64*1024, Blen= 16*1024,}; Filter *filter;Proto *root;Biobuf out;vlong starttime, pkttime;int pcap; int filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int);void printpkt(char *p, char *e, uchar *ps, uchar *pe);void mkprotograph(void);Proto* findproto(char *name);Filter* compile(Filter *f);void printfilter(Filter *f, char *tag);void printhelp(char*);void tracepkt(uchar*, int);void pcaphdr(void); voidprintusage(void){ fprint(2, "usage: %s [-CDdpst] [-N n] [-f filter] [-h first-header] path\n", argv0); fprint(2, " for protocol help: %s -? [proto]\n", argv0);} voidusage(void){ printusage(); exits("usage");} voidmain(int argc, char **argv){ uchar *pkt; char *buf, *file, *p, *e; int fd, cfd; int n; Binit(&out, 1, OWRITE); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('I', eipfmt); fmtinstall('H', encodefmt); fmtinstall('F', fcallfmt); pkt = malloc(Pktlen+16); pkt += 16; buf = malloc(Blen); e = buf+Blen-1; pflag = 1; Nflag = 32; sflag = 0; mkprotograph(); ARGBEGIN{ default: usage(); case '?': printusage(); printhelp(ARGF()); exits(0); break; case 'M': p = EARGF(usage()); Mflag = atoi(p); break; case 'N': p = EARGF(usage()); Nflag = atoi(p); break; case 'f': p = EARGF(usage()); yyinit(p); yyparse(); break; case 's': sflag = 1; break; case 'h': p = EARGF(usage()); root = findproto(p); if(root == nil) sysfatal("unknown protocol: %s", p); break; case 'd': toflag = 1; break; case 'D': toflag = 1; pcap = 1; break; case 't': tiflag = 1; break; case 'C': Cflag = 1; break; case 'p': pflag = 0; break; }ARGEND; if(pcap) pcaphdr(); if(argc == 0){ file = "/net/ether0"; if(root != nil) root = ðer; } else file = argv[0]; if((!tiflag) && strstr(file, "ether")){ if(root == nil) root = ðer; snprint(buf, Blen, "%s!-1", file); fd = dial(buf, 0, 0, &cfd); if(fd < 0) sysfatal("dialing %s: %r", buf); if(pflag && fprint(cfd, prom, strlen(prom)) < 0) sysfatal("setting %s", prom); } else if((!tiflag) && strstr(file, "ipifc")){ if(root == nil) root = &ip; snprint(buf, Blen, "%s/snoop", file); fd = open(buf, OREAD); if(fd < 0) sysfatal("opening %s: %r", buf); } else { if(root == nil) root = ðer; fd = open(file, OREAD); if(fd < 0) sysfatal("opening %s: %r", file); } filter = compile(filter); if(tiflag){ /* read a trace file */ for(;;){ n = read(fd, pkt, 10); if(n != 10) break; pkttime = NetL(pkt+2); pkttime = (pkttime<<32) | NetL(pkt+6); if(starttime == 0LL) starttime = pkttime; n = NetS(pkt); if(readn(fd, pkt, n) != n) break; if(filterpkt(filter, pkt, pkt+n, root, 1)) if(toflag) tracepkt(pkt, n); else printpkt(buf, e, pkt, pkt+n); } } else { /* read a real time stream */ starttime = nsec(); for(;;){ n = root->framer(fd, pkt, Pktlen); if(n <= 0) break; pkttime = nsec(); if(filterpkt(filter, pkt, pkt+n, root, 1)) if(toflag) tracepkt(pkt, n); else printpkt(buf, e, pkt, pkt+n); } }} /* create a new filter node */Filter*newfilter(void){ Filter *f; f = mallocz(sizeof(*f), 1); if(f == nil) sysfatal("newfilter: %r"); return f;} /* * apply filter to packet */int_filterpkt(Filter *f, Msg *m){ Msg ma; if(f == nil) return 1; switch(f->op){ case '!': return !_filterpkt(f->l, m); case LAND: ma = *m; return _filterpkt(f->l, &ma) && _filterpkt(f->r, m); case LOR: ma = *m; return _filterpkt(f->l, &ma) || _filterpkt(f->r, m); case WORD: if(m->needroot){ if(m->pr != f->pr) return 0; m->needroot = 0; }else{ if(m->pr && (m->pr->filter==nil || !(m->pr->filter)(f, m))) return 0; } if(f->l == nil) return 1; m->pr = f->pr; return _filterpkt(f->l, m); } sysfatal("internal error: filterpkt op: %d", f->op); return 0;}intfilterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot){ Msg m; if(f == nil) return 1; m.needroot = needroot; m.ps = ps; m.pe = pe; m.pr = pr; return _filterpkt(f, &m);} /* * from the Unix world */#define PCAP_VERSION_MAJOR 2#define PCAP_VERSION_MINOR 4#define TCPDUMP_MAGIC 0xa1b2c3d4 struct pcap_file_header { ulong magic; ushort version_major; ushort version_minor; long thiszone; /* gmt to local correction */ ulong sigfigs; /* accuracy of timestamps */ ulong snaplen; /* max length saved portion of each pkt */ ulong linktype; /* data link type (DLT_*) */}; struct pcap_pkthdr { uvlong ts; /* time stamp */ ulong caplen; /* length of portion present */ ulong len; /* length this packet (off wire) */}; /* * pcap trace header */voidpcaphdr(void){ struct pcap_file_header hdr; hdr.magic = TCPDUMP_MAGIC; hdr.version_major = PCAP_VERSION_MAJOR; hdr.version_minor = PCAP_VERSION_MINOR; hdr.thiszone = 0; hdr.snaplen = 1500; hdr.sigfigs = 0; hdr.linktype = 1; write(1, &hdr, sizeof(hdr));} /* * write out a packet trace */voidtracepkt(uchar *ps, int len){ struct pcap_pkthdr *goo; if(Mflag && len > Mflag) len = Mflag; if(pcap){ goo = (struct pcap_pkthdr*)(ps-16); goo->ts = pkttime; goo->caplen = len; goo->len = len; write(1, goo, len+16); } else { hnputs(ps-10, len); hnputl(ps-8, pkttime>>32); hnputl(ps-4, pkttime); write(1, ps-10, len+10); }} /* * format and print a packet */voidprintpkt(char *p, char *e, uchar *ps, uchar *pe){ Msg m; ulong dt; dt = (pkttime-starttime)/1000000LL; m.p = seprint(p, e, "%6.6uld ms ", dt); m.ps = ps; m.pe = pe; m.e = e; m.pr = root; while(m.p < m.e){ if(!sflag) m.p = seprint(m.p, m.e, "\n\t"); m.p = seprint(m.p, m.e, "%s(", m.pr->name); if((*m.pr->seprint)(&m) < 0){ m.p = seprint(m.p, m.e, "TOO SHORT"); m.ps = m.pe; } m.p = seprint(m.p, m.e, ")"); if(m.pr == nil || m.ps >= m.pe) break; } *m.p++ = '\n'; if(write(1, p, m.p - p) < 0) sysfatal("stdout: %r");} Proto **xprotos;int nprotos; /* look up a protocol by its name */Proto*findproto(char *name){ int i; for(i = 0; i < nprotos; i++) if(strcmp(xprotos[i]->name, name) == 0) return xprotos[i]; return nil;} /* * add an undefined protocol to protos[] */Proto*addproto(char *name){ Proto *pr; xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*)); pr = malloc(sizeof *pr); *pr = dump; pr->name = name; xprotos[nprotos++] = pr; return pr;} /* * build a graph of protocols, this could easily be circular. This * links together all the multiplexing in the protocol modules. */voidmkprotograph(void){ Proto **l; Proto *pr; Mux *m; /* copy protos into a reallocable area */ for(nprotos = 0; protos[nprotos] != nil; nprotos++) ; xprotos = malloc(nprotos*sizeof(Proto*)); memmove(xprotos, protos, nprotos*sizeof(Proto*)); for(l = protos; *l != nil; l++){ pr = *l; for(m = pr->mux; m != nil && m->name != nil; m++){ m->pr = findproto(m->name); if(m->pr == nil) m->pr = addproto(m->name); } }} /* * add in a protocol node */static Filter*addnode(Filter *f, Proto *pr){ Filter *nf; nf = newfilter(); nf->pr = pr; nf->s = pr->name; nf->l = f; nf->op = WORD; return nf;} /* * recurse through the protocol graph adding missing nodes * to the filter if we reach the filter's protocol */static Filter*_fillin(Filter *f, Proto *last, int depth){ Mux *m; Filter *nf; if(depth-- <= 0) return nil; for(m = last->mux; m != nil && m->name != nil; m++){ if(m->pr == nil) continue; if(f->pr == m->pr) return f; nf = _fillin(f, m->pr, depth); if(nf != nil) return addnode(nf, m->pr); } return nil;} static Filter*fillin(Filter *f, Proto *last){ int i; Filter *nf; /* hack to make sure top level node is the root */ if(last == nil){ if(f->pr == root) return f; f = fillin(f, root); if(f == nil) return nil; return addnode(f, root); } /* breadth first search though the protocol graph */ nf = f; for(i = 1; i < 20; i++){ nf = _fillin(f, last, i); if(nf != nil) break; }Lines 1–500 of 973. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ /* * snoopy - network sniffer */ #include <u.h> #include <libc.h> #include <ip.h> #include <bio.h> #include <fcall.h> #include <libsec.h> #include <ndb.h> #include "dat.h" #include "protos.h" #include "y.tab.h" int Cflag; int pflag; int Nflag; int Mflag; int sflag; int tiflag; int toflag; char *prom = "promiscuous"; enum { Pktlen= 64*1024, Blen= 16*1024, }; Filter *filter; Proto *root; Biobuf out; vlong starttime, pkttime; int pcap; int filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int); void printpkt(char *p, char *e, uchar *ps, uchar *pe); void mkprotograph(void); Proto* findproto(char *name); Filter* compile(Filter *f); void printfilter(Filter *f, char *tag); void printhelp(char*); void tracepkt(uchar*, int); void pcaphdr(void); void printusage(void) { fprint(2, "usage: %s [-CDdpst] [-N n] [-f filter] [-h first-header] path\n", argv0); fprint(2, " for protocol help: %s -? [proto]\n", argv0); } void usage(void) { printusage(); exits("usage"); } void main(int argc, char **argv) { uchar *pkt; char *buf, *file, *p, *e; int fd, cfd; int n; Binit(&out, 1, OWRITE); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('I', eipfmt); fmtinstall('H', encodefmt); fmtinstall('F', fcallfmt); pkt = malloc(Pktlen+16); pkt += 16; buf = malloc(Blen); e = buf+Blen-1; pflag = 1; Nflag = 32; sflag = 0; mkprotograph(); ARGBEGIN{ default: usage(); case '?': printusage(); printhelp(ARGF()); exits(0); break; case 'M': p = EARGF(usage()); Mflag = atoi(p); break; case 'N': p = EARGF(usage()); Nflag = atoi(p); break; case 'f': p = EARGF(usage()); yyinit(p); yyparse(); break; case 's': sflag = 1; break; case 'h': p = EARGF(usage()); root = findproto(p); if(root == nil) sysfatal("unknown protocol: %s", p); break; case 'd': toflag = 1; break; case 'D': toflag = 1; pcap = 1; break; case 't': tiflag = 1; break; case 'C': Cflag = 1; break; case 'p': pflag = 0; break; }ARGEND; if(pcap) pcaphdr(); if(argc == 0){ file = "/net/ether0"; if(root != nil) root = ðer; } else file = argv[0]; if((!tiflag) && strstr(file, "ether")){ if(root == nil) root = ðer; snprint(buf, Blen, "%s!-1", file); fd = dial(buf, 0, 0, &cfd); if(fd < 0) sysfatal("dialing %s: %r", buf); if(pflag && fprint(cfd, prom, strlen(prom)) < 0) sysfatal("setting %s", prom); } else if((!tiflag) && strstr(file, "ipifc")){ if(root == nil) root = &ip; snprint(buf, Blen, "%s/snoop", file); fd = open(buf, OREAD); if(fd < 0) sysfatal("opening %s: %r", buf); } else { if(root == nil) root = ðer; fd = open(file, OREAD); if(fd < 0) sysfatal("opening %s: %r", file); } filter = compile(filter); if(tiflag){ /* read a trace file */ for(;;){ n = read(fd, pkt, 10); if(n != 10) break; pkttime = NetL(pkt+2); pkttime = (pkttime<<32) | NetL(pkt+6); if(starttime == 0LL) starttime = pkttime; n = NetS(pkt); if(readn(fd, pkt, n) != n) break; if(filterpkt(filter, pkt, pkt+n, root, 1)) if(toflag) tracepkt(pkt, n); else printpkt(buf, e, pkt, pkt+n); } } else { /* read a real time stream */ starttime = nsec(); for(;;){ n = root->framer(fd, pkt, Pktlen); if(n <= 0) break; pkttime = nsec(); if(filterpkt(filter, pkt, pkt+n, root, 1)) if(toflag) tracepkt(pkt, n); else printpkt(buf, e, pkt, pkt+n); } } } /* create a new filter node */ Filter* newfilter(void) { Filter *f; f = mallocz(sizeof(*f), 1); if(f == nil) sysfatal("newfilter: %r"); return f; } /* * apply filter to packet */ int _filterpkt(Filter *f, Msg *m) { Msg ma; if(f == nil) return 1; switch(f->op){ case '!': return !_filterpkt(f->l, m); case LAND: ma = *m; return _filterpkt(f->l, &ma) && _filterpkt(f->r, m); case LOR: ma = *m; return _filterpkt(f->l, &ma) || _filterpkt(f->r, m); case WORD: if(m->needroot){ if(m->pr != f->pr) return 0; m->needroot = 0; }else{ if(m->pr && (m->pr->filter==nil || !(m->pr->filter)(f, m))) return 0; } if(f->l == nil) return 1; m->pr = f->pr; return _filterpkt(f->l, m); } sysfatal("internal error: filterpkt op: %d", f->op); return 0; } int filterpkt(Filter *f, uchar *ps, uchar *pe, Proto *pr, int needroot) { Msg m; if(f == nil) return 1; m.needroot = needroot; m.ps = ps; m.pe = pe; m.pr = pr; return _filterpkt(f, &m); } /* * from the Unix world */ #define PCAP_VERSION_MAJOR 2 #define PCAP_VERSION_MINOR 4 #define TCPDUMP_MAGIC 0xa1b2c3d4 struct pcap_file_header { ulong magic; ushort version_major; ushort version_minor; long thiszone; /* gmt to local correction */ ulong sigfigs; /* accuracy of timestamps */ ulong snaplen; /* max length saved portion of each pkt */ ulong linktype; /* data link type (DLT_*) */ }; struct pcap_pkthdr { uvlong ts; /* time stamp */ ulong caplen; /* length of portion present */ ulong len; /* length this packet (off wire) */ }; /* * pcap trace header */ void pcaphdr(void) { struct pcap_file_header hdr; hdr.magic = TCPDUMP_MAGIC; hdr.version_major = PCAP_VERSION_MAJOR; hdr.version_minor = PCAP_VERSION_MINOR; hdr.thiszone = 0; hdr.snaplen = 1500; hdr.sigfigs = 0; hdr.linktype = 1; write(1, &hdr, sizeof(hdr)); } /* * write out a packet trace */ void tracepkt(uchar *ps, int len) { struct pcap_pkthdr *goo; if(Mflag && len > Mflag) len = Mflag; if(pcap){ goo = (struct pcap_pkthdr*)(ps-16); goo->ts = pkttime; goo->caplen = len; goo->len = len; write(1, goo, len+16); } else { hnputs(ps-10, len); hnputl(ps-8, pkttime>>32); hnputl(ps-4, pkttime); write(1, ps-10, len+10); } } /* * format and print a packet */ void printpkt(char *p, char *e, uchar *ps, uchar *pe) { Msg m; ulong dt; dt = (pkttime-starttime)/1000000LL; m.p = seprint(p, e, "%6.6uld ms ", dt); m.ps = ps; m.pe = pe; m.e = e; m.pr = root; while(m.p < m.e){ if(!sflag) m.p = seprint(m.p, m.e, "\n\t"); m.p = seprint(m.p, m.e, "%s(", m.pr->name); if((*m.pr->seprint)(&m) < 0){ m.p = seprint(m.p, m.e, "TOO SHORT"); m.ps = m.pe; } m.p = seprint(m.p, m.e, ")"); if(m.pr == nil || m.ps >= m.pe) break; } *m.p++ = '\n'; if(write(1, p, m.p - p) < 0) sysfatal("stdout: %r"); } Proto **xprotos; int nprotos; /* look up a protocol by its name */ Proto* findproto(char *name) { int i; for(i = 0; i < nprotos; i++) if(strcmp(xprotos[i]->name, name) == 0) return xprotos[i]; return nil; } /* * add an undefined protocol to protos[] */ Proto* addproto(char *name) { Proto *pr; xprotos = realloc(xprotos, (nprotos+1)*sizeof(Proto*)); pr = malloc(sizeof *pr); *pr = dump; pr->name = name; xprotos[nprotos++] = pr; return pr; } /* * build a graph of protocols, this could easily be circular. This * links together all the multiplexing in the protocol modules. */ void mkprotograph(void) { Proto **l; Proto *pr; Mux *m; /* copy protos into a reallocable area */ for(nprotos = 0; protos[nprotos] != nil; nprotos++) ; xprotos = malloc(nprotos*sizeof(Proto*)); memmove(xprotos, protos, nprotos*sizeof(Proto*)); for(l = protos; *l != nil; l++){ pr = *l; for(m = pr->mux; m != nil && m->name != nil; m++){ m->pr = findproto(m->name); if(m->pr == nil) m->pr = addproto(m->name); } } } /* * add in a protocol node */ static Filter* addnode(Filter *f, Proto *pr) { Filter *nf; nf = newfilter(); nf->pr = pr; nf->s = pr->name; nf->l = f; nf->op = WORD; return nf; } /* * recurse through the protocol graph adding missing nodes * to the filter if we reach the filter's protocol */ static Filter* _fillin(Filter *f, Proto *last, int depth) { Mux *m; Filter *nf; if(depth-- <= 0) return nil; for(m = last->mux; m != nil && m->name != nil; m++){ if(m->pr == nil) continue; if(f->pr == m->pr) return f; nf = _fillin(f, m->pr, depth); if(nf != nil) return addnode(nf, m->pr); } return nil; } static Filter* fillin(Filter *f, Proto *last) { int i; Filter *nf; /* hack to make sure top level node is the root */ if(last == nil){ if(f->pr == root) return f; f = fillin(f, root); if(f == nil) return nil; return addnode(f, root); } /* breadth first search though the protocol graph */ nf = f; for(i = 1; i < 20; i++){ nf = _fillin(f, last, i); if(nf != nil) break; }