commit 17b19538a48c036dbdc8817d233c0086f327485c from: Russ Cox date: Thu Jul 24 15:04:02 2008 UTC snoopy: add support for wireless monitor mode packets commit - 7e36b43bba16df64a08c13358ba2a70ae9001770 commit + 17b19538a48c036dbdc8817d233c0086f327485c blob - 49734a789c4507c028aa92fb851a722ab7913a54 blob + ba3e446da5a9fdec1d0336f64256d50a9df8b022 --- src/cmd/ip/snoopy/dat.h +++ src/cmd/ip/snoopy/dat.h @@ -6,8 +6,11 @@ typedef struct Proto Proto; #define NetS(x) ((((uchar*)x)[0]<<8) | ((uchar*)x)[1]) #define Net3(x) ((((uchar*)x)[0]<<16) | (((uchar*)x)[1]<<8) | ((uchar*)x)[2]) -#define NetL(x) ((((uchar*)x)[0]<<24) | (((uchar*)x)[1]<<16) | (((uchar*)x)[2]<<8) | ((uchar*)x)[3]) +#define NetL(x) (((ulong)((((uchar*)x)[0]<<24) | (((uchar*)x)[1]<<16) | (((uchar*)x)[2]<<8) | ((uchar*)x)[3]))&0xFFFFFFFFU) +#define LittleS(x) ((((uchar*)x)[1]<<8) | ((uchar*)x)[0]) +#define LittleL(x) (((ulong)((((uchar*)x)[3]<<24) | (((uchar*)x)[2]<<16) | (((uchar*)x)[1]<<8) | ((uchar*)x)[0]))&0xFFFFFFFFU) + /* * one per protocol module */ blob - /dev/null blob + bbc21986ff98e74cfc5ff55a813d5ea53199b9cb (mode 644) --- /dev/null +++ src/cmd/ip/snoopy/llc.c @@ -0,0 +1,173 @@ +/* + * LLC. Only enough to dispatch to SNAP and IP. + */ + +#include +#include +#include +#include "dat.h" +#include "protos.h" + +enum +{ + UFmt = 3, + Gsap = 1, + IG = 1, + SFmt = 1, + UPoll = 0x10, + IsPoll = 0x100, + XidFi = 0x81, + + SapNull = 0, + SapGlobal = 0xff, + Sap8021BI = 0x02, + Sap8021BG = 0x03, + SapSNA = 0x04, + SapIP = 0x06, + SapProwayNM = 0x0e, + Sap8021D = 0x42, + SapRS511 = 0x4e, + SapISO8208 = 0x7e, + SapProway = 0x8e, + SapSnap = 0xaa, + SapIpx = 0xe0, + SapNetbeui = 0xf0, + SapIsons = 0xfe, +}; + +static Mux p_mux[] = +{ +// Linux gives llc -> snap not llc -> ip. +// If we don't tell snoopy about llc -> ip, then the default patterns +// like snoopy -h radiotap -f dns work better. +// { "ip", SapIP }, + { "snap", SapSnap }, + { 0 } +}; + +typedef struct Hdr Hdr; +struct Hdr +{ + uchar dsap; + uchar ssap; + uchar dsapf; + uchar ssapf; + ushort ctl; + uchar isu; + int hdrlen; +}; + +static int +unpackhdr(uchar *p, uchar *ep, Hdr *h) +{ + if(p+3 > ep) + return -1; + h->dsapf = p[0]; + h->dsap = h->dsapf & ~IG; + h->ssapf = p[1]; + h->ssap = h->ssapf & ~Gsap; + h->ctl = p[2]; + h->hdrlen = 3; + if((h->ctl&UFmt) == UFmt) + h->isu = 1; + else{ + if(p+4 > ep) + return -1; + h->hdrlen = 4; + h->ctl = LittleS(p+2); + } + return 0; +} + +enum +{ + Ossap, + Odsap, + Ot, +}; + +static Field p_fields[] = +{ + { "ssap", Fnum, Ossap, "ssap" }, + { "dsap", Fnum, Odsap, "dsap" }, + { 0 } +}; + +static void +p_compile(Filter *f) +{ + Mux *m; + + if(f->op == '='){ + compile_cmp(llc.name, f, p_fields); + return; + } + for(m = p_mux; m->name != nil; m++){ + if(strcmp(f->s, m->name) == 0){ + f->pr = m->pr; + f->ulv = m->val; + f->subop = Ot; + return; + } + } + sysfatal("unknown llc field or protocol: %s", f->s); +} + +static int +p_filter(Filter *f, Msg *m) +{ + Hdr h; + + memset(&h, 0, sizeof h); + if(unpackhdr(m->ps, m->pe, &h) < 0) + return 0; + m->ps += h.hdrlen; + + switch(f->subop){ + case Ossap: + return f->ulv == h.ssap; + case Odsap: + return f->ulv == h.dsap; + case Ot: + return f->ulv == h.ssap && f->ulv == h.dsap; + } + return 0; +} + +static int +p_seprint(Msg *m) +{ + Hdr h; + + memset(&h, 0, sizeof h); + if(unpackhdr(m->ps, m->pe, &h) < 0) + return -1; + + m->pr = &dump; + m->p = seprint(m->p, m->e, "ssap=%02x dsap=%02x ctl=%04x", h.ssap, h.dsap, h.ctl); + m->ps += h.hdrlen; + m->pr = &dump; + if(h.ssap == h.dsap){ + switch(h.ssap){ + case SapIP: + m->pr = &ip; + break; + case SapSnap: + m->pr = &snap; + break; + } + } + return 0; +} + +Proto llc = +{ + "llc", + p_compile, + p_filter, + p_seprint, + p_mux, + nil, + nil, + defaultframer +}; blob - ddd66a7b2ff076022404b26eede0ed5598790da4 blob + 4797f12c2b058415521a926ac5dc28ed8e5b8db7 --- src/cmd/ip/snoopy/mkfile +++ src/cmd/ip/snoopy/mkfile @@ -27,6 +27,11 @@ PROTOS=\ ppp_ipcp\ pppoe_sess\ pppoe_disc\ + dns\ + p80211\ + llc\ + radiotap\ + snap\ POBJS=${PROTOS:%=%.$O} blob - /dev/null blob + 92ed8aba2fdcabeaa201d0505ae78c7887e312f6 (mode 644) --- /dev/null +++ src/cmd/ip/snoopy/p80211.c @@ -0,0 +1,367 @@ +/* + * IEEE 802.11. + */ + +#include +#include +#include +#include "dat.h" +#include "protos.h" + +enum +{ + Tmgmt = 0, + Tctl, + Tdata, + + CtlPoll = 0xA, + CtlRts, + CtlCts, + CtlAck, + CtlCfEnd, + CtlCfEndAck, + + Data = 0, + DataCfAck, + DataCfPoll, + DataCfAckPoll, + Nodata, + NodataCfAck, + NodataCfPoll, + NodataCfAckPoll, + + FlagTods = 0x1, + FlagFromds = 0x2, + FlagMoreflag = 0x4, + FlagRetry = 0x8, + FlagPowerMgmt = 0x10, + FlagMoreData = 0x20, + FlagWep = 0x40, + FlagOrder = 0x80, + + ProtoNone = 0, + ProtoLlc, +}; + +static Mux p_mux[] = +{ + { "llc", ProtoLlc }, + { 0 } +}; + +typedef struct Hdr Hdr; +struct Hdr +{ + uchar vers; + uchar type; + uchar subtype; + uchar flags; + ushort dur; + uchar aid; + uchar ra[6]; + uchar ta[6]; + uchar bssid[6]; + uchar sa[6]; + uchar da[6]; + ushort seq; + int proto; + int hdrlen; +}; + +static int +unpackhdr(uchar *p, uchar *ep, Hdr *h) +{ + if(p+2 > ep) + return -1; + h->vers = p[0]&3; + if(h->vers != 0){ + h->hdrlen = 2; + return -1; + } + h->type = (p[0]>>2)&3; + h->subtype = (p[0]>>4)&15; + h->flags = p[1]; + h->hdrlen = 2; + + if(h->vers != 0) + return 0; + + switch(h->type){ + case Tmgmt: + // fc dur da sa bssid seq + if(p+2+2+6+6+6+2 > ep) + return -1; + h->hdrlen = 24; + h->dur = LittleS(p+2); + memmove(h->da, p+4, 6); + memmove(h->sa, p+10, 6); + memmove(h->bssid, p+16, 6); + h->seq = LittleS(p+22); + break; + + case Tctl: + switch(h->subtype){ + case CtlPoll: + // fc aid bssid ta + if(p+2+2+6+6 > ep) + return -1; + h->hdrlen = 16; + h->aid = LittleS(p+2); + memmove(h->bssid, p+4, 6); + memmove(h->ta, p+10, 6); + break; + + case CtlRts: + // fc dur ra ta + if(p+2+2+6+6 > ep) + return -1; + h->hdrlen = 16; + h->dur = LittleS(p+2); + memmove(h->ra, p+4, 6); + memmove(h->ta, p+10, 6); + break; + + case CtlCts: + case CtlAck: + // fc dur ra + if(p+2+2+6 > ep) + return -1; + h->hdrlen = 10; + h->dur = LittleS(p+2); + memmove(h->ra, p+4, 6); + break; + + case CtlCfEnd: + case CtlCfEndAck: + // fc dur ra bssid + if(p+2+2+6+6 > ep) + return -1; + h->hdrlen = 16; + h->dur = LittleS(p+2); + memmove(h->ra, p+4, 6); + memmove(h->bssid, p+10, 6); + break; + } + break; + + case Tdata: + if(p+24 > ep) + return -1; + h->hdrlen = 24; + h->dur = LittleS(p+2); // ??? maybe + // Also, what is at p+22? + + switch(h->flags&(FlagFromds|FlagTods)){ + case 0: + memmove(h->da, p+4, 6); + memmove(h->sa, p+10, 6); + memmove(h->bssid, p+16, 6); + break; + case FlagFromds: + memmove(h->da, p+4, 6); + memmove(h->bssid, p+10, 6); + memmove(h->sa, p+16, 6); + break; + case FlagTods: + memmove(h->bssid, p+4, 6); + memmove(h->sa, p+10, 6); + memmove(h->da, p+16, 6); + break; + case FlagFromds|FlagTods: + if(p+30 > ep) + return -1; + h->hdrlen = 30; + memmove(h->ra, p+4, 6); + memmove(h->ta, p+10, 6); + memmove(h->da, p+16, 6); + memmove(h->sa, p+24, 6); // 24 sic + break; + } + p += h->hdrlen; + h->proto = ProtoNone; + if(!(h->flags&FlagWep)) + h->proto = ProtoLlc; + break; + } + return 0; +} + +enum +{ + Os, + Od, + Ot, + Or, + Obssid, + Oa, + Opr, +}; + +static Field p_fields[] = +{ + { "s", Fether, Os, "source address" }, + { "d", Fether, Od, "destination address" }, + { "t", Fether, Ot, "transmit address" }, + { "r", Fether, Or, "receive address" }, + { "bssid", Fether, Obssid, "bssid address" }, + { "a", Fether, Oa, "any address" }, + { "sd", Fether, Oa, "source|destination address" }, + { 0 } +}; + +static void +p_compile(Filter *f) +{ + Mux *m; + + if(f->op == '='){ + compile_cmp(p80211.name, f, p_fields); + return; + } + if(strcmp(f->s, "mgmt") == 0){ + f->pr = &p80211; + f->ulv = Tmgmt; + f->subop = Ot; + return; + } + if(strcmp(f->s, "ctl") == 0){ + f->pr = &p80211; + f->ulv = Tctl; + f->subop = Ot; + return; + } + if(strcmp(f->s, "data") == 0){ + f->pr = &p80211; + f->ulv = Tdata; + f->subop = Ot; + return; + } + for(m = p_mux; m->name != nil; m++){ + if(strcmp(f->s, m->name) == 0){ + f->pr = m->pr; + f->ulv = m->val; + f->subop = Opr; + return; + } + } + sysfatal("unknown 802.11 field or protocol: %s", f->s); +} + +static int +p_filter(Filter *f, Msg *m) +{ + Hdr h; + + memset(&h, 0, sizeof h); + if(unpackhdr(m->ps, m->pe, &h) < 0) + return 0; + m->ps += h.hdrlen; + + switch(f->subop){ + case Os: + return memcmp(h.sa, f->a, 6) == 0; + case Od: + return memcmp(h.da, f->a, 6) == 0; + case Ot: + return memcmp(h.ta, f->a, 6) == 0; + case Or: + return memcmp(h.ra, f->a, 6) == 0; + case Obssid: + return memcmp(h.bssid, f->a, 6) == 0; + case Oa: + return memcmp(h.sa, f->a, 6) == 0 + || memcmp(h.da, f->a, 6) == 0 + || memcmp(h.ta, f->a, 6) == 0 + || memcmp(h.ra, f->a, 6) == 0 + || memcmp(h.bssid, f->a, 6) == 0; + case Opr: + return h.proto == f->ulv; + } + return 0; +} + +static int +p_seprint(Msg *m) +{ + Hdr h; + + memset(&h, 0, sizeof h); + if(unpackhdr(m->ps, m->pe, &h) < 0) + return -1; + + m->pr = &dump; + m->p = seprint(m->p, m->e, "fc=%02x flags=%02x ", m->ps[0], m->ps[1]); + switch(h.type){ + case Tmgmt: + m->p = seprint(m->p, m->e, "mgmt dur=%d d=%E s=%E bssid=%E seq=%d", + h.dur, h.da, h.sa, h.bssid, h.seq); + break; + case Tctl: + switch(h.subtype){ + case CtlPoll: + m->p = seprint(m->p, m->e, "ctl poll aid=%d bssid=%E t=%E", + h.aid, h.bssid, h.ta); + break; + case CtlRts: + m->p = seprint(m->p, m->e, "ctl rts dur=%d r=%E t=%E", + h.dur, h.ra, h.ta); + break; + case CtlCts: + m->p = seprint(m->p, m->e, "ctl cts dur=%d r=%E", + h.dur, h.ra); + break; + case CtlAck: + m->p = seprint(m->p, m->e, "ctl ack dur=%d r=%E", + h.dur, h.ra); + break; + case CtlCfEnd: + m->p = seprint(m->p, m->e, "ctl cf end dur=%d r=%E bssid=%E", + h.dur, h.ra, h.bssid); + break; + case CtlCfEndAck: + m->p = seprint(m->p, m->e, "ctl cf end ack dur=%d r=%E bssid=%E", + h.dur, h.ra, h.bssid); + break; + default: + m->p = seprint(m->p, m->e, "ctl %.*H", m->ps, h.hdrlen); + break; + } + break; + case Tdata: + switch(h.flags&(FlagFromds|FlagTods)){ + case 0: + m->p = seprint(m->p, m->e, "data d=%E s=%E bssid=%E", + h.da, h.sa, h.bssid); + break; + case FlagFromds: + m->p = seprint(m->p, m->e, "data fds d=%E bssid=%E s=%E", + h.da, h.bssid, h.sa); + break; + case FlagTods: + m->p = seprint(m->p, m->e, "data tds bssid=%E s=%E d=%E", + h.bssid, h.sa, h.da); + break; + case FlagFromds|FlagTods: + m->p = seprint(m->p, m->e, "data fds tds r=%E t=%E d=%E s=%E", + h.ra, h.ta, h.da, h.sa); + break; + } + if(!(h.flags&FlagWep)) + m->pr = &llc; + break; + } + m->ps += h.hdrlen; + return 0; +} + +Proto p80211 = +{ + "802.11", + p_compile, + p_filter, + p_seprint, + p_mux, + nil, + nil, + defaultframer +}; blob - 4503f7f0ce041dada115d5e7d4195eef88eae90d blob + 69d6030b74b71aa39bdb9274c58a1b19b5159951 --- src/cmd/ip/snoopy/protos.c +++ src/cmd/ip/snoopy/protos.c @@ -29,5 +29,10 @@ Proto *protos[] = &ppp_ipcp, &pppoe_sess, &pppoe_disc, + &dns, + &p80211, + &llc, + &radiotap, + &snap, 0 }; blob - 501b59eca62012d72238a9a15948aa4649317a17 blob + c826736bd83faf02a5abcdc970fd62b7c21deef5 --- src/cmd/ip/snoopy/protos.h +++ src/cmd/ip/snoopy/protos.h @@ -23,3 +23,8 @@ extern Proto ppp_chap; extern Proto ppp_ipcp; extern Proto pppoe_sess; extern Proto pppoe_disc; +extern Proto dns; +extern Proto p80211; +extern Proto llc; +extern Proto radiotap; +extern Proto snap; blob - /dev/null blob + 889dc8ab49f89b31ae15777df7196424a9b02b08 (mode 644) --- /dev/null +++ src/cmd/ip/snoopy/radiotap.c @@ -0,0 +1,117 @@ +/* + * Radio tap as exported by BSD and Linux. + * The wireless ethernet devices return this format on Linux + * when running in monitor mode. + * + * TODO: Automatically determine whether the ethernet + * device is radio or ether, so that -h is not needed. + */ + +#include +#include +#include +#include "dat.h" +#include "protos.h" + +static Mux p_mux[] = +{ + { "802.11", 0 }, + { 0 } +}; + +typedef struct Hdr Hdr; +struct Hdr +{ + uchar vers; + uchar pad; + ushort len; + ulong present; +}; + +static int +unpackhdr(uchar *p, uchar *ep, Hdr *h) +{ + if(p+sizeof(Hdr) > ep) + return -1; + h->vers = p[0]; + h->pad = p[1]; + h->len = LittleS(p+2); + h->present = LittleL(p+4); + // can be more present fields if 0x80000000 is set in each along the chain. + if(p+h->len > ep) + return -1; + return 0; +} + +enum +{ + Ot, +}; + +static Field p_fields[] = +{ + { 0 } +}; + +static void +p_compile(Filter *f) +{ + Mux *m; + + if(f->op == '='){ + compile_cmp(radiotap.name, f, p_fields); + return; + } + for(m = p_mux; m->name != nil; m++){ + if(strcmp(f->s, m->name) == 0){ + f->pr = m->pr; + f->ulv = m->val; + f->subop = Ot; + return; + } + } + sysfatal("unknown radiotap field or protocol: %s", f->s); +} + +static int +p_filter(Filter *f, Msg *m) +{ + Hdr h; + + memset(&h, 0, sizeof h); + if(unpackhdr(m->ps, m->pe, &h) < 0) + return 0; + m->ps += h.len; + switch(f->subop){ + case Ot: + return 1; + } + return 0; +} + +static int +p_seprint(Msg *m) +{ + Hdr h; + + memset(&h, 0, sizeof h); + if(unpackhdr(m->ps, m->pe, &h) < 0) + return -1; + + m->p = seprint(m->p, m->e, "%.*H", h.len, m->ps); + m->ps += h.len; + m->pr = &p80211; + return 0; +} + +Proto radiotap = +{ + "radiotap", + p_compile, + p_filter, + p_seprint, + p_mux, + nil, + nil, + defaultframer +}; blob - fc68d6f341b4e0bcd748025c0b194cb09617fc4b blob + 3d81f33d3ff2dc551e77a753ee4314707a5b6615 --- src/cmd/ip/snoopy/udp.c +++ src/cmd/ip/snoopy/udp.c @@ -41,6 +41,7 @@ static Mux p_mux[] = { {"bootp", 67, }, {"ninep", 6346, }, /* tvs */ + {"dns", 53 }, {"rtp", ANYPORT, }, {"rtcp", ANYPORT, }, {0} blob - /dev/null blob + 1854d1d64df90115f79690fa96f99de205658b59 (mode 644) --- /dev/null +++ src/cmd/ip/snoopy/snap.c @@ -0,0 +1,112 @@ +/* + * SNAP. + */ + +#include +#include +#include +#include "dat.h" +#include "protos.h" + +enum +{ + Oorg, + Oet, + + OuiEther = 0, + OuiCisco = 0xc, + OuiCisco90 = 0xf8, + OuiRfc2684 = 0x80c2, + OuiAppletalk = 0x80007, +}; + +static Mux p_mux[] = +{ + {"ip", 0x0800, } , + {"arp", 0x0806, } , + {"rarp", 0x0806, } , + {"ip6", 0x86dd, } , + {"pppoe_disc", 0x8863, }, + {"pppoe_sess", 0x8864, }, + {"eapol", 0x888e, }, + { 0 } +}; + +typedef struct Hdr Hdr; +struct Hdr +{ + uchar org[3]; + uchar et[2]; +}; + +static Field p_fields[] = +{ + { "org", Fnum, Oorg, "org" }, + { "et", Fnum, Oet, "et" }, + { 0 } +}; + +static void +p_compile(Filter *f) +{ + Mux *m; + + if(f->op == '='){ + compile_cmp(snap.name, f, p_fields); + return; + } + for(m = p_mux; m->name != nil; m++){ + if(strcmp(f->s, m->name) == 0){ + f->pr = m->pr; + f->ulv = m->val; + f->subop = Oet; + return; + } + } + sysfatal("unknown snap field or protocol: %s", f->s); +} + +static int +p_filter(Filter *f, Msg *m) +{ + Hdr *h; + + if(m->pe - m->ps < sizeof(Hdr)) + return 0; + h = (Hdr*)m->ps; + m->ps += 5; + switch(f->subop){ + case Oorg: + return f->ulv == Net3(h->org); + case Oet: + return f->ulv == NetS(h->et); + } + return 0; +} + +static int +p_seprint(Msg *m) +{ + Hdr *h; + + if(m->pe - m->ps < sizeof(Hdr)) + return 0; + h = (Hdr*)m->ps; + m->ps += 5; + demux(p_mux, NetS(h->et), NetS(h->et), m, &dump); + + m->p = seprint(m->p, m->e, "org=%06x et=%04x", Net3(h->org), NetS(h->et)); + return 0; +} + +Proto snap = +{ + "snap", + p_compile, + p_filter, + p_seprint, + p_mux, + nil, + nil, + defaultframer +};