tsnoopy: add support for wireless monitor mode packets - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
commit 17b19538a48c036dbdc8817d233c0086f327485c
parent 7e36b43bba16df64a08c13358ba2a70ae9001770
Author: Russ Cox 
Date:   Thu, 24 Jul 2008 08:04:02 -0700

snoopy: add support for wireless monitor mode packets

Diffstat:
  M src/cmd/ip/snoopy/dat.h             |       5 ++++-
  A src/cmd/ip/snoopy/llc.c             |     173 +++++++++++++++++++++++++++++++
  M src/cmd/ip/snoopy/mkfile            |       5 +++++
  A src/cmd/ip/snoopy/p80211.c          |     367 ++++++++++++++++++++++++++++++
  M src/cmd/ip/snoopy/protos.c          |       5 +++++
  M src/cmd/ip/snoopy/protos.h          |       5 +++++
  A src/cmd/ip/snoopy/radiotap.c        |     117 +++++++++++++++++++++++++++++++
  A src/cmd/ip/snoopy/snap.c            |     112 +++++++++++++++++++++++++++++++
  M src/cmd/ip/snoopy/udp.c             |       1 +

9 files changed, 789 insertions(+), 1 deletion(-)
---
diff --git a/src/cmd/ip/snoopy/dat.h b/src/cmd/ip/snoopy/dat.h
t@@ -6,7 +6,10 @@ 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
diff --git a/src/cmd/ip/snoopy/llc.c b/src/cmd/ip/snoopy/llc.c
t@@ -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
+};
diff --git a/src/cmd/ip/snoopy/mkfile b/src/cmd/ip/snoopy/mkfile
t@@ -27,6 +27,11 @@ PROTOS=\
         ppp_ipcp\
         pppoe_sess\
         pppoe_disc\
+        dns\
+        p80211\
+        llc\
+        radiotap\
+        snap\
 
 POBJS=${PROTOS:%=%.$O}
 
diff --git a/src/cmd/ip/snoopy/p80211.c b/src/cmd/ip/snoopy/p80211.c
t@@ -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
+};
diff --git a/src/cmd/ip/snoopy/protos.c b/src/cmd/ip/snoopy/protos.c
t@@ -29,5 +29,10 @@ Proto *protos[] =
         &ppp_ipcp,
         &pppoe_sess,
         &pppoe_disc,
+        &dns,
+        &p80211,
+        &llc,
+        &radiotap,
+        &snap,
         0
 };
diff --git a/src/cmd/ip/snoopy/protos.h b/src/cmd/ip/snoopy/protos.h
t@@ -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;
diff --git a/src/cmd/ip/snoopy/radiotap.c b/src/cmd/ip/snoopy/radiotap.c
t@@ -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
+};
diff --git a/src/cmd/ip/snoopy/snap.c b/src/cmd/ip/snoopy/snap.c
t@@ -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
+};
diff --git a/src/cmd/ip/snoopy/udp.c b/src/cmd/ip/snoopy/udp.c
t@@ -41,6 +41,7 @@ static Mux p_mux[] =
 {
         {"bootp",        67, },
         {"ninep",        6346, },        /* tvs */
+        {"dns", 53 },
         {"rtp",                ANYPORT, },
         {"rtcp",        ANYPORT, },
         {0}