ODPM 266: Go-libmemif + 2 examples.
[govpp.git] / vendor / github.com / google / gopacket / pcap / pcap.go
diff --git a/vendor/github.com/google/gopacket/pcap/pcap.go b/vendor/github.com/google/gopacket/pcap/pcap.go
new file mode 100644 (file)
index 0000000..1ecdf03
--- /dev/null
@@ -0,0 +1,1005 @@
+// Copyright 2012 Google, Inc. All rights reserved.
+// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree.
+
+package pcap
+
+/*
+#cgo solaris LDFLAGS: -L /opt/local/lib -lpcap
+#cgo linux LDFLAGS: -lpcap
+#cgo dragonfly LDFLAGS: -lpcap
+#cgo freebsd LDFLAGS: -lpcap
+#cgo openbsd LDFLAGS: -lpcap
+#cgo netbsd LDFLAGS: -lpcap
+#cgo darwin LDFLAGS: -lpcap
+#cgo windows CFLAGS: -I C:/WpdPack/Include
+#cgo windows,386 LDFLAGS: -L C:/WpdPack/Lib -lwpcap
+#cgo windows,amd64 LDFLAGS: -L C:/WpdPack/Lib/x64 -lwpcap
+#include <stdlib.h>
+#include <pcap.h>
+
+// Some old versions of pcap don't define this constant.
+#ifndef PCAP_NETMASK_UNKNOWN
+#define PCAP_NETMASK_UNKNOWN 0xffffffff
+#endif
+
+// libpcap doesn't actually export its version in a #define-guardable way,
+// so we have to use other defined things to differentiate versions.
+// We assume at least libpcap v1.1 at the moment.
+// See http://upstream-tracker.org/versions/libpcap.html
+
+#ifndef PCAP_ERROR_TSTAMP_PRECISION_NOTSUP  // < v1.5
+
+int pcap_set_immediate_mode(pcap_t *p, int mode) {
+  return PCAP_ERROR;
+}
+
+#ifndef PCAP_TSTAMP_HOST  // < v1.2
+
+int pcap_set_tstamp_type(pcap_t* p, int t) { return -1; }
+int pcap_list_tstamp_types(pcap_t* p, int** t) { return 0; }
+void pcap_free_tstamp_types(int *tstamp_types) {}
+const char* pcap_tstamp_type_val_to_name(int t) {
+       return "pcap timestamp types not supported";
+}
+int pcap_tstamp_type_name_to_val(const char* t) {
+       return PCAP_ERROR;
+}
+
+#endif  // < v1.2
+#endif  // < v1.5
+
+#ifndef PCAP_ERROR_PROMISC_PERM_DENIED
+#define PCAP_ERROR_PROMISC_PERM_DENIED -11
+#endif
+
+// WinPcap doesn't export a pcap_statustostr, so use the less-specific
+// pcap_strerror.  Note that linking against something like cygwin libpcap
+// may result is less-specific error messages.
+#ifdef WIN32
+#define pcap_statustostr pcap_strerror
+
+// WinPcap also doesn't export pcap_can_set_rfmon and pcap_set_rfmon,
+// as those are handled by separate libraries (airpcap).
+// https://www.winpcap.org/docs/docs_412/html/group__wpcapfunc.html
+// Stub out those functions here, returning values that indicate rfmon
+// setting is unavailable/unsuccessful.
+int pcap_can_set_rfmon(pcap_t *p) {
+       return 0;
+}
+
+int pcap_set_rfmon(pcap_t *p, int rfmon) {
+       return PCAP_ERROR;
+}
+#endif
+
+// Windows, Macs, and Linux all use different time types.  Joy.
+#ifdef WIN32
+#define gopacket_time_secs_t long
+#define gopacket_time_usecs_t long
+#elif __APPLE__
+#define gopacket_time_secs_t __darwin_time_t
+#define gopacket_time_usecs_t __darwin_suseconds_t
+#elif __GLIBC__
+#define gopacket_time_secs_t __time_t
+#define gopacket_time_usecs_t __suseconds_t
+#else  // Some form of linux/bsd/etc...
+#include <sys/param.h>
+#ifdef __OpenBSD__
+#define gopacket_time_secs_t u_int32_t
+#define gopacket_time_usecs_t u_int32_t
+#else
+#define gopacket_time_secs_t time_t
+#define gopacket_time_usecs_t suseconds_t
+#endif
+#endif
+*/
+import "C"
+
+import (
+       "errors"
+       "fmt"
+       "io"
+       "net"
+       "reflect"
+       "runtime"
+       "strconv"
+       "sync"
+       "sync/atomic"
+       "syscall"
+       "time"
+       "unsafe"
+
+       "github.com/google/gopacket"
+       "github.com/google/gopacket/layers"
+)
+
+const errorBufferSize = 256
+
+// MaxBpfInstructions is the maximum number of BPF instructions supported (BPF_MAXINSNS),
+// taken from Linux kernel: include/uapi/linux/bpf_common.h
+//
+// https://github.com/torvalds/linux/blob/master/include/uapi/linux/bpf_common.h
+const MaxBpfInstructions = 4096
+
+// 8 bytes per instruction, max 4096 instructions
+const bpfInstructionBufferSize = 8 * MaxBpfInstructions
+
+// Handle provides a connection to a pcap handle, allowing users to read packets
+// off the wire (Next), inject packets onto the wire (Inject), and
+// perform a number of other functions to affect and understand packet output.
+//
+// Handles are already pcap_activate'd
+type Handle struct {
+       // cptr is the handle for the actual pcap C object.
+       cptr        *C.pcap_t
+       timeout     time.Duration
+       device      string
+       deviceIndex int
+       mu          sync.Mutex
+       closeMu     sync.Mutex
+       // stop is set to a non-zero value by Handle.Close to signal to
+       // getNextBufPtrLocked to stop trying to read packets
+       stop uint64
+
+       // Since pointers to these objects are passed into a C function, if
+       // they're declared locally then the Go compiler thinks they may have
+       // escaped into C-land, so it allocates them on the heap.  This causes a
+       // huge memory hit, so to handle that we store them here instead.
+       pkthdr *C.struct_pcap_pkthdr
+       bufptr *C.u_char
+}
+
+// Stats contains statistics on how many packets were handled by a pcap handle,
+// and what was done with those packets.
+type Stats struct {
+       PacketsReceived  int
+       PacketsDropped   int
+       PacketsIfDropped int
+}
+
+// Interface describes a single network interface on a machine.
+type Interface struct {
+       Name        string
+       Description string
+       Addresses   []InterfaceAddress
+       // TODO: add more elements
+}
+
+// Datalink describes the datalink
+type Datalink struct {
+       Name        string
+       Description string
+}
+
+// InterfaceAddress describes an address associated with an Interface.
+// Currently, it's IPv4/6 specific.
+type InterfaceAddress struct {
+       IP      net.IP
+       Netmask net.IPMask // Netmask may be nil if we were unable to retrieve it.
+       // TODO: add broadcast + PtP dst ?
+}
+
+// BPF is a compiled filter program, useful for offline packet matching.
+type BPF struct {
+       orig string
+       bpf  _Ctype_struct_bpf_program // takes a finalizer, not overriden by outsiders
+}
+
+// BPFInstruction is a byte encoded structure holding a BPF instruction
+type BPFInstruction struct {
+       Code uint16
+       Jt   uint8
+       Jf   uint8
+       K    uint32
+}
+
+// BlockForever causes it to block forever waiting for packets, when passed
+// into SetTimeout or OpenLive, while still returning incoming packets to userland relatively
+// quickly.
+const BlockForever = -time.Millisecond * 10
+
+func timeoutMillis(timeout time.Duration) C.int {
+       // Flip sign if necessary.  See package docs on timeout for reasoning behind this.
+       if timeout < 0 {
+               timeout *= -1
+       }
+       // Round up
+       if timeout != 0 && timeout < time.Millisecond {
+               timeout = time.Millisecond
+       }
+       return C.int(timeout / time.Millisecond)
+}
+
+// OpenLive opens a device and returns a *Handle.
+// It takes as arguments the name of the device ("eth0"), the maximum size to
+// read for each packet (snaplen), whether to put the interface in promiscuous
+// mode, and a timeout.
+//
+// See the package documentation for important details regarding 'timeout'.
+func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error) {
+       buf := (*C.char)(C.calloc(errorBufferSize, 1))
+       defer C.free(unsafe.Pointer(buf))
+
+       var pro C.int
+       if promisc {
+               pro = 1
+       }
+       p := &Handle{timeout: timeout, device: device}
+
+       ifc, err := net.InterfaceByName(device)
+       if err != nil {
+               // The device wasn't found in the OS, but could be "any"
+               // Set index to 0
+               p.deviceIndex = 0
+       } else {
+               p.deviceIndex = ifc.Index
+       }
+
+       dev := C.CString(device)
+       defer C.free(unsafe.Pointer(dev))
+
+       p.cptr = C.pcap_open_live(dev, C.int(snaplen), pro, timeoutMillis(timeout), buf)
+       if p.cptr == nil {
+               return nil, errors.New(C.GoString(buf))
+       }
+
+       if err := p.openLive(); err != nil {
+               C.pcap_close(p.cptr)
+               return nil, err
+       }
+
+       return p, nil
+}
+
+// OpenOffline opens a file and returns its contents as a *Handle.
+func OpenOffline(file string) (handle *Handle, err error) {
+       buf := (*C.char)(C.calloc(errorBufferSize, 1))
+       defer C.free(unsafe.Pointer(buf))
+       cf := C.CString(file)
+       defer C.free(unsafe.Pointer(cf))
+
+       cptr := C.pcap_open_offline(cf, buf)
+       if cptr == nil {
+               return nil, errors.New(C.GoString(buf))
+       }
+       return &Handle{cptr: cptr}, nil
+}
+
+// NextError is the return code from a call to Next.
+type NextError int32
+
+// NextError implements the error interface.
+func (n NextError) Error() string {
+       switch n {
+       case NextErrorOk:
+               return "OK"
+       case NextErrorTimeoutExpired:
+               return "Timeout Expired"
+       case NextErrorReadError:
+               return "Read Error"
+       case NextErrorNoMorePackets:
+               return "No More Packets In File"
+       case NextErrorNotActivated:
+               return "Not Activated"
+       }
+       return strconv.Itoa(int(n))
+}
+
+// NextError values.
+const (
+       NextErrorOk             NextError = 1
+       NextErrorTimeoutExpired NextError = 0
+       NextErrorReadError      NextError = -1
+       // NextErrorNoMorePackets is returned when reading from a file (OpenOffline) and
+       // EOF is reached.  When this happens, Next() returns io.EOF instead of this.
+       NextErrorNoMorePackets NextError = -2
+       NextErrorNotActivated  NextError = -3
+)
+
+// ReadPacketData returns the next packet read from the pcap handle, along with an error
+// code associated with that packet.  If the packet is read successfully, the
+// returned error is nil.
+func (p *Handle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
+       p.mu.Lock()
+       err = p.getNextBufPtrLocked(&ci)
+       if err == nil {
+               data = C.GoBytes(unsafe.Pointer(p.bufptr), C.int(ci.CaptureLength))
+       }
+       p.mu.Unlock()
+       if err == NextErrorTimeoutExpired {
+               runtime.Gosched()
+       }
+       return
+}
+
+type activateError C.int
+
+const (
+       aeNoError      = 0
+       aeActivated    = C.PCAP_ERROR_ACTIVATED
+       aePromisc      = C.PCAP_WARNING_PROMISC_NOTSUP
+       aeNoSuchDevice = C.PCAP_ERROR_NO_SUCH_DEVICE
+       aeDenied       = C.PCAP_ERROR_PERM_DENIED
+       aeNotUp        = C.PCAP_ERROR_IFACE_NOT_UP
+)
+
+func (a activateError) Error() string {
+       switch a {
+       case aeNoError:
+               return "No Error"
+       case aeActivated:
+               return "Already Activated"
+       case aePromisc:
+               return "Cannot set as promisc"
+       case aeNoSuchDevice:
+               return "No Such Device"
+       case aeDenied:
+               return "Permission Denied"
+       case aeNotUp:
+               return "Interface Not Up"
+       default:
+               return fmt.Sprintf("unknown activated error: %d", a)
+       }
+}
+
+// getNextBufPtrLocked is shared code for ReadPacketData and
+// ZeroCopyReadPacketData.
+func (p *Handle) getNextBufPtrLocked(ci *gopacket.CaptureInfo) error {
+       if p.cptr == nil {
+               return io.EOF
+       }
+
+       for atomic.LoadUint64(&p.stop) == 0 {
+               // try to read a packet if one is immediately available
+               result := NextError(C.pcap_next_ex(p.cptr, &p.pkthdr, &p.bufptr))
+
+               switch result {
+               case NextErrorOk:
+                       // got a packet, set capture info and return
+                       sec := int64(p.pkthdr.ts.tv_sec)
+                       // convert micros to nanos
+                       nanos := int64(p.pkthdr.ts.tv_usec) * 1000
+
+                       ci.Timestamp = time.Unix(sec, nanos)
+                       ci.CaptureLength = int(p.pkthdr.caplen)
+                       ci.Length = int(p.pkthdr.len)
+                       ci.InterfaceIndex = p.deviceIndex
+
+                       return nil
+               case NextErrorNoMorePackets:
+                       // no more packets, return EOF rather than libpcap-specific error
+                       return io.EOF
+               case NextErrorTimeoutExpired:
+                       // Negative timeout means to loop forever, instead of actually returning
+                       // the timeout error.
+                       if p.timeout < 0 {
+                               // must have had a timeout... wait before trying again
+                               p.waitForPacket()
+                               continue
+                       }
+               default:
+                       return result
+               }
+       }
+
+       // stop must be set
+       return io.EOF
+}
+
+// ZeroCopyReadPacketData reads the next packet off the wire, and returns its data.
+// The slice returned by ZeroCopyReadPacketData points to bytes owned by the
+// the Handle.  Each call to ZeroCopyReadPacketData invalidates any data previously
+// returned by ZeroCopyReadPacketData.  Care must be taken not to keep pointers
+// to old bytes when using ZeroCopyReadPacketData... if you need to keep data past
+// the next time you call ZeroCopyReadPacketData, use ReadPacketData, which copies
+// the bytes into a new buffer for you.
+//  data1, _, _ := handle.ZeroCopyReadPacketData()
+//  // do everything you want with data1 here, copying bytes out of it if you'd like to keep them around.
+//  data2, _, _ := handle.ZeroCopyReadPacketData()  // invalidates bytes in data1
+func (p *Handle) ZeroCopyReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
+       p.mu.Lock()
+       err = p.getNextBufPtrLocked(&ci)
+       if err == nil {
+               slice := (*reflect.SliceHeader)(unsafe.Pointer(&data))
+               slice.Data = uintptr(unsafe.Pointer(p.bufptr))
+               slice.Len = ci.CaptureLength
+               slice.Cap = ci.CaptureLength
+       }
+       p.mu.Unlock()
+       if err == NextErrorTimeoutExpired {
+               runtime.Gosched()
+       }
+       return
+}
+
+// Close closes the underlying pcap handle.
+func (p *Handle) Close() {
+       p.closeMu.Lock()
+       defer p.closeMu.Unlock()
+
+       if p.cptr == nil {
+               return
+       }
+
+       atomic.StoreUint64(&p.stop, 1)
+
+       // wait for packet reader to stop
+       p.mu.Lock()
+       defer p.mu.Unlock()
+
+       C.pcap_close(p.cptr)
+       p.cptr = nil
+}
+
+// Error returns the current error associated with a pcap handle (pcap_geterr).
+func (p *Handle) Error() error {
+       return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
+}
+
+// Stats returns statistics on the underlying pcap handle.
+func (p *Handle) Stats() (stat *Stats, err error) {
+       var cstats _Ctype_struct_pcap_stat
+       if -1 == C.pcap_stats(p.cptr, &cstats) {
+               return nil, p.Error()
+       }
+       return &Stats{
+               PacketsReceived:  int(cstats.ps_recv),
+               PacketsDropped:   int(cstats.ps_drop),
+               PacketsIfDropped: int(cstats.ps_ifdrop),
+       }, nil
+}
+
+// ListDataLinks obtains a list of all possible data link types supported for an interface.
+func (p *Handle) ListDataLinks() (datalinks []Datalink, err error) {
+       var dltbuf *C.int
+
+       n := int(C.pcap_list_datalinks(p.cptr, &dltbuf))
+       if -1 == n {
+               return nil, p.Error()
+       }
+
+       defer C.pcap_free_datalinks(dltbuf)
+
+       datalinks = make([]Datalink, n)
+
+       dltArray := (*[100]C.int)(unsafe.Pointer(dltbuf))
+
+       for i := 0; i < n; i++ {
+               expr := C.pcap_datalink_val_to_name((*dltArray)[i])
+               datalinks[i].Name = C.GoString(expr)
+
+               expr = C.pcap_datalink_val_to_description((*dltArray)[i])
+               datalinks[i].Description = C.GoString(expr)
+       }
+
+       return datalinks, nil
+}
+
+// pcap_compile is NOT thread-safe, so protect it.
+var pcapCompileMu sync.Mutex
+
+// compileBPFFilter always returns an allocated _Ctype_struct_bpf_program
+// It is the callers responsibility to free the memory again, e.g.
+//
+//    C.pcap_freecode(&bpf)
+//
+func (p *Handle) compileBPFFilter(expr string) (_Ctype_struct_bpf_program, error) {
+       errorBuf := (*C.char)(C.calloc(errorBufferSize, 1))
+       defer C.free(unsafe.Pointer(errorBuf))
+
+       var netp uint32
+       var maskp uint32
+
+       // Only do the lookup on network interfaces.
+       // No device indicates we're handling a pcap file.
+       if len(p.device) > 0 {
+               dev := C.CString(p.device)
+               defer C.free(unsafe.Pointer(dev))
+               if -1 == C.pcap_lookupnet(
+                       dev,
+                       (*C.bpf_u_int32)(unsafe.Pointer(&netp)),
+                       (*C.bpf_u_int32)(unsafe.Pointer(&maskp)),
+                       errorBuf,
+               ) {
+                       // We can't lookup the network, but that could be because the interface
+                       // doesn't have an IPv4.
+               }
+       }
+
+       var bpf _Ctype_struct_bpf_program
+       cexpr := C.CString(expr)
+       defer C.free(unsafe.Pointer(cexpr))
+
+       pcapCompileMu.Lock()
+       defer pcapCompileMu.Unlock()
+       if -1 == C.pcap_compile(p.cptr, &bpf, cexpr, 1, C.bpf_u_int32(maskp)) {
+               return bpf, p.Error()
+       }
+
+       return bpf, nil
+}
+
+// CompileBPFFilter compiles and returns a BPF filter with given a link type and capture length.
+func CompileBPFFilter(linkType layers.LinkType, captureLength int, expr string) ([]BPFInstruction, error) {
+       cptr := C.pcap_open_dead(C.int(linkType), C.int(captureLength))
+       if cptr == nil {
+               return nil, errors.New("error opening dead capture")
+       }
+
+       h := Handle{cptr: cptr}
+       defer h.Close()
+       return h.CompileBPFFilter(expr)
+}
+
+// CompileBPFFilter compiles and returns a BPF filter for the pcap handle.
+func (p *Handle) CompileBPFFilter(expr string) ([]BPFInstruction, error) {
+       bpf, err := p.compileBPFFilter(expr)
+       defer C.pcap_freecode(&bpf)
+       if err != nil {
+               return nil, err
+       }
+
+       bpfInsn := (*[bpfInstructionBufferSize]_Ctype_struct_bpf_insn)(unsafe.Pointer(bpf.bf_insns))[0:bpf.bf_len:bpf.bf_len]
+       bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
+
+       for i, v := range bpfInsn {
+               bpfInstruction[i].Code = uint16(v.code)
+               bpfInstruction[i].Jt = uint8(v.jt)
+               bpfInstruction[i].Jf = uint8(v.jf)
+               bpfInstruction[i].K = uint32(v.k)
+       }
+
+       return bpfInstruction, nil
+}
+
+// SetBPFFilter compiles and sets a BPF filter for the pcap handle.
+func (p *Handle) SetBPFFilter(expr string) (err error) {
+       bpf, err := p.compileBPFFilter(expr)
+       defer C.pcap_freecode(&bpf)
+       if err != nil {
+               return err
+       }
+
+       if -1 == C.pcap_setfilter(p.cptr, &bpf) {
+               return p.Error()
+       }
+
+       return nil
+}
+
+// SetBPFInstructionFilter may be used to apply a filter in BPF asm byte code format.
+//
+// Simplest way to generate BPF asm byte code is with tcpdump:
+//     tcpdump -dd 'udp'
+//
+// The output may be used directly to add a filter, e.g.:
+//     bpfInstructions := []pcap.BpfInstruction{
+//                     {0x28, 0, 0, 0x0000000c},
+//                     {0x15, 0, 9, 0x00000800},
+//                     {0x30, 0, 0, 0x00000017},
+//                     {0x15, 0, 7, 0x00000006},
+//                     {0x28, 0, 0, 0x00000014},
+//                     {0x45, 5, 0, 0x00001fff},
+//                     {0xb1, 0, 0, 0x0000000e},
+//                     {0x50, 0, 0, 0x0000001b},
+//                     {0x54, 0, 0, 0x00000012},
+//                     {0x15, 0, 1, 0x00000012},
+//                     {0x6, 0, 0, 0x0000ffff},
+//                     {0x6, 0, 0, 0x00000000},
+//             }
+//
+// An other posibility is to write the bpf code in bpf asm.
+// Documentation: https://www.kernel.org/doc/Documentation/networking/filter.txt
+//
+// To compile the code use bpf_asm from
+// https://github.com/torvalds/linux/tree/master/tools/net
+//
+// The following command may be used to convert bpf_asm output to c/go struct, usable for SetBPFFilterByte:
+// bpf_asm -c tcp.bpf
+func (p *Handle) SetBPFInstructionFilter(bpfInstructions []BPFInstruction) (err error) {
+       bpf, err := bpfInstructionFilter(bpfInstructions)
+       if err != nil {
+               return err
+       }
+
+       if -1 == C.pcap_setfilter(p.cptr, &bpf) {
+               C.pcap_freecode(&bpf)
+               return p.Error()
+       }
+
+       C.pcap_freecode(&bpf)
+
+       return nil
+}
+func bpfInstructionFilter(bpfInstructions []BPFInstruction) (bpf _Ctype_struct_bpf_program, err error) {
+       if len(bpfInstructions) < 1 {
+               return bpf, errors.New("bpfInstructions must not be empty")
+       }
+
+       if len(bpfInstructions) > MaxBpfInstructions {
+               return bpf, fmt.Errorf("bpfInstructions must not be larger than %d", MaxBpfInstructions)
+       }
+
+       bpf.bf_len = C.u_int(len(bpfInstructions))
+       cbpfInsns := C.calloc(C.size_t(len(bpfInstructions)), C.size_t(unsafe.Sizeof(bpfInstructions[0])))
+
+       copy((*[bpfInstructionBufferSize]BPFInstruction)(cbpfInsns)[0:len(bpfInstructions)], bpfInstructions)
+       bpf.bf_insns = (*_Ctype_struct_bpf_insn)(cbpfInsns)
+
+       return
+}
+
+// NewBPF compiles the given string into a new filter program.
+//
+// BPF filters need to be created from activated handles, because they need to
+// know the underlying link type to correctly compile their offsets.
+func (p *Handle) NewBPF(expr string) (*BPF, error) {
+       bpf := &BPF{orig: expr}
+       cexpr := C.CString(expr)
+       defer C.free(unsafe.Pointer(cexpr))
+
+       pcapCompileMu.Lock()
+       defer pcapCompileMu.Unlock()
+       if C.pcap_compile(p.cptr, &bpf.bpf, cexpr /* optimize */, 1, C.PCAP_NETMASK_UNKNOWN) != 0 {
+               return nil, p.Error()
+       }
+
+       runtime.SetFinalizer(bpf, destroyBPF)
+       return bpf, nil
+}
+
+// NewBPFInstructionFilter sets the given BPFInstructions as new filter program.
+//
+// More details see func SetBPFInstructionFilter
+//
+// BPF filters need to be created from activated handles, because they need to
+// know the underlying link type to correctly compile their offsets.
+func (p *Handle) NewBPFInstructionFilter(bpfInstructions []BPFInstruction) (*BPF, error) {
+       var err error
+       bpf := &BPF{orig: "BPF Instruction Filter"}
+
+       bpf.bpf, err = bpfInstructionFilter(bpfInstructions)
+       if err != nil {
+               return nil, err
+       }
+
+       runtime.SetFinalizer(bpf, destroyBPF)
+       return bpf, nil
+}
+func destroyBPF(bpf *BPF) {
+       C.pcap_freecode(&bpf.bpf)
+}
+
+// String returns the original string this BPF filter was compiled from.
+func (b *BPF) String() string {
+       return b.orig
+}
+
+// Matches returns true if the given packet data matches this filter.
+func (b *BPF) Matches(ci gopacket.CaptureInfo, data []byte) bool {
+       var hdr C.struct_pcap_pkthdr
+       hdr.ts.tv_sec = C.gopacket_time_secs_t(ci.Timestamp.Unix())
+       hdr.ts.tv_usec = C.gopacket_time_usecs_t(ci.Timestamp.Nanosecond() / 1000)
+       hdr.caplen = C.bpf_u_int32(len(data)) // Trust actual length over ci.Length.
+       hdr.len = C.bpf_u_int32(ci.Length)
+       dataptr := (*C.u_char)(unsafe.Pointer(&data[0]))
+       return C.pcap_offline_filter(&b.bpf, &hdr, dataptr) != 0
+}
+
+// Version returns pcap_lib_version.
+func Version() string {
+       return C.GoString(C.pcap_lib_version())
+}
+
+// LinkType returns pcap_datalink, as a layers.LinkType.
+func (p *Handle) LinkType() layers.LinkType {
+       return layers.LinkType(C.pcap_datalink(p.cptr))
+}
+
+// SetLinkType calls pcap_set_datalink on the pcap handle.
+func (p *Handle) SetLinkType(dlt layers.LinkType) error {
+       if -1 == C.pcap_set_datalink(p.cptr, C.int(dlt)) {
+               return p.Error()
+       }
+       return nil
+}
+
+// FindAllDevs attempts to enumerate all interfaces on the current machine.
+func FindAllDevs() (ifs []Interface, err error) {
+       var buf *C.char
+       buf = (*C.char)(C.calloc(errorBufferSize, 1))
+       defer C.free(unsafe.Pointer(buf))
+       var alldevsp *C.pcap_if_t
+
+       if -1 == C.pcap_findalldevs((**C.pcap_if_t)(&alldevsp), buf) {
+               return nil, errors.New(C.GoString(buf))
+       }
+       defer C.pcap_freealldevs((*C.pcap_if_t)(alldevsp))
+       dev := alldevsp
+       var i uint32
+       for i = 0; dev != nil; dev = (*C.pcap_if_t)(dev.next) {
+               i++
+       }
+       ifs = make([]Interface, i)
+       dev = alldevsp
+       for j := uint32(0); dev != nil; dev = (*C.pcap_if_t)(dev.next) {
+               var iface Interface
+               iface.Name = C.GoString(dev.name)
+               iface.Description = C.GoString(dev.description)
+               iface.Addresses = findalladdresses(dev.addresses)
+               // TODO: add more elements
+               ifs[j] = iface
+               j++
+       }
+       return
+}
+
+func findalladdresses(addresses *_Ctype_struct_pcap_addr) (retval []InterfaceAddress) {
+       // TODO - make it support more than IPv4 and IPv6?
+       retval = make([]InterfaceAddress, 0, 1)
+       for curaddr := addresses; curaddr != nil; curaddr = (*_Ctype_struct_pcap_addr)(curaddr.next) {
+               // Strangely, it appears that in some cases, we get a pcap address back from
+               // pcap_findalldevs with a nil .addr.  It appears that we can skip over
+               // these.
+               if curaddr.addr == nil {
+                       continue
+               }
+               var a InterfaceAddress
+               var err error
+               if a.IP, err = sockaddrToIP((*syscall.RawSockaddr)(unsafe.Pointer(curaddr.addr))); err != nil {
+                       continue
+               }
+               // To be safe, we'll also check for netmask.
+               if curaddr.netmask == nil {
+                       continue
+               }
+               if a.Netmask, err = sockaddrToIP((*syscall.RawSockaddr)(unsafe.Pointer(curaddr.netmask))); err != nil {
+                       // If we got an IP address but we can't get a netmask, just return the IP
+                       // address.
+                       a.Netmask = nil
+               }
+               retval = append(retval, a)
+       }
+       return
+}
+
+func sockaddrToIP(rsa *syscall.RawSockaddr) (IP []byte, err error) {
+       switch rsa.Family {
+       case syscall.AF_INET:
+               pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa))
+               IP = make([]byte, 4)
+               for i := 0; i < len(IP); i++ {
+                       IP[i] = pp.Addr[i]
+               }
+               return
+       case syscall.AF_INET6:
+               pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa))
+               IP = make([]byte, 16)
+               for i := 0; i < len(IP); i++ {
+                       IP[i] = pp.Addr[i]
+               }
+               return
+       }
+       err = errors.New("Unsupported address type")
+       return
+}
+
+// WritePacketData calls pcap_sendpacket, injecting the given data into the pcap handle.
+func (p *Handle) WritePacketData(data []byte) (err error) {
+       if -1 == C.pcap_sendpacket(p.cptr, (*C.u_char)(&data[0]), (C.int)(len(data))) {
+               err = p.Error()
+       }
+       return
+}
+
+// Direction is used by Handle.SetDirection.
+type Direction uint8
+
+// Direction values for Handle.SetDirection.
+const (
+       DirectionIn    Direction = C.PCAP_D_IN
+       DirectionOut   Direction = C.PCAP_D_OUT
+       DirectionInOut Direction = C.PCAP_D_INOUT
+)
+
+// SetDirection sets the direction for which packets will be captured.
+func (p *Handle) SetDirection(direction Direction) error {
+       if direction != DirectionIn && direction != DirectionOut && direction != DirectionInOut {
+               return fmt.Errorf("Invalid direction: %v", direction)
+       }
+       if status := C.pcap_setdirection(p.cptr, (C.pcap_direction_t)(direction)); status < 0 {
+               return statusError(status)
+       }
+       return nil
+}
+
+// TimestampSource tells PCAP which type of timestamp to use for packets.
+type TimestampSource C.int
+
+// String returns the timestamp type as a human-readable string.
+func (t TimestampSource) String() string {
+       return C.GoString(C.pcap_tstamp_type_val_to_name(C.int(t)))
+}
+
+// TimestampSourceFromString translates a string into a timestamp type, case
+// insensitive.
+func TimestampSourceFromString(s string) (TimestampSource, error) {
+       cs := C.CString(s)
+       defer C.free(unsafe.Pointer(cs))
+       t := C.pcap_tstamp_type_name_to_val(cs)
+       if t < 0 {
+               return 0, statusError(t)
+       }
+       return TimestampSource(t), nil
+}
+
+func statusError(status C.int) error {
+       return errors.New(C.GoString(C.pcap_statustostr(status)))
+}
+
+// InactiveHandle allows you to call pre-pcap_activate functions on your pcap
+// handle to set it up just the way you'd like.
+type InactiveHandle struct {
+       // cptr is the handle for the actual pcap C object.
+       cptr        *C.pcap_t
+       device      string
+       deviceIndex int
+       timeout     time.Duration
+}
+
+// Activate activates the handle.  The current InactiveHandle becomes invalid
+// and all future function calls on it will fail.
+func (p *InactiveHandle) Activate() (*Handle, error) {
+       err := activateError(C.pcap_activate(p.cptr))
+       if err != aeNoError {
+               return nil, err
+       }
+       h := &Handle{
+               cptr:        p.cptr,
+               timeout:     p.timeout,
+               device:      p.device,
+               deviceIndex: p.deviceIndex,
+       }
+       p.cptr = nil
+       return h, nil
+}
+
+// CleanUp cleans up any stuff left over from a successful or failed building
+// of a handle.
+func (p *InactiveHandle) CleanUp() {
+       if p.cptr != nil {
+               C.pcap_close(p.cptr)
+       }
+}
+
+// NewInactiveHandle creates a new InactiveHandle, which wraps an un-activated PCAP handle.
+// Callers of NewInactiveHandle should immediately defer 'CleanUp', as in:
+//   inactive := NewInactiveHandle("eth0")
+//   defer inactive.CleanUp()
+func NewInactiveHandle(device string) (*InactiveHandle, error) {
+       buf := (*C.char)(C.calloc(errorBufferSize, 1))
+       defer C.free(unsafe.Pointer(buf))
+       dev := C.CString(device)
+       defer C.free(unsafe.Pointer(dev))
+
+       // Try to get the interface index, but iy could be something like "any"
+       // in which case use 0, which doesn't exist in nature
+       deviceIndex := 0
+       ifc, err := net.InterfaceByName(device)
+       if err == nil {
+               deviceIndex = ifc.Index
+       }
+
+       // This copies a bunch of the pcap_open_live implementation from pcap.c:
+       cptr := C.pcap_create(dev, buf)
+       if cptr == nil {
+               return nil, errors.New(C.GoString(buf))
+       }
+       return &InactiveHandle{cptr: cptr, device: device, deviceIndex: deviceIndex}, nil
+}
+
+// SetSnapLen sets the snap length (max bytes per packet to capture).
+func (p *InactiveHandle) SetSnapLen(snaplen int) error {
+       if status := C.pcap_set_snaplen(p.cptr, C.int(snaplen)); status < 0 {
+               return statusError(status)
+       }
+       return nil
+}
+
+// SetPromisc sets the handle to either be promiscuous (capture packets
+// unrelated to this host) or not.
+func (p *InactiveHandle) SetPromisc(promisc bool) error {
+       var pro C.int
+       if promisc {
+               pro = 1
+       }
+       if status := C.pcap_set_promisc(p.cptr, pro); status < 0 {
+               return statusError(status)
+       }
+       return nil
+}
+
+// SetTimeout sets the read timeout for the handle.
+//
+// See the package documentation for important details regarding 'timeout'.
+func (p *InactiveHandle) SetTimeout(timeout time.Duration) error {
+       if status := C.pcap_set_timeout(p.cptr, timeoutMillis(timeout)); status < 0 {
+               return statusError(status)
+       }
+       p.timeout = timeout
+       return nil
+}
+
+// SupportedTimestamps returns a list of supported timstamp types for this
+// handle.
+func (p *InactiveHandle) SupportedTimestamps() (out []TimestampSource) {
+       var types *C.int
+       n := int(C.pcap_list_tstamp_types(p.cptr, &types))
+       defer C.pcap_free_tstamp_types(types)
+       typesArray := (*[100]C.int)(unsafe.Pointer(types))
+       for i := 0; i < n; i++ {
+               out = append(out, TimestampSource((*typesArray)[i]))
+       }
+       return
+}
+
+// SetTimestampSource sets the type of timestamp generator PCAP uses when
+// attaching timestamps to packets.
+func (p *InactiveHandle) SetTimestampSource(t TimestampSource) error {
+       if status := C.pcap_set_tstamp_type(p.cptr, C.int(t)); status < 0 {
+               return statusError(status)
+       }
+       return nil
+}
+
+// CannotSetRFMon is returned by SetRFMon if the handle does not allow
+// setting RFMon because pcap_can_set_rfmon returns 0.
+var CannotSetRFMon = errors.New("Cannot set rfmon for this handle")
+
+// SetRFMon turns on radio monitoring mode, similar to promiscuous mode but for
+// wireless networks.  If this mode is enabled, the interface will not need to
+// associate with an access point before it can receive traffic.
+func (p *InactiveHandle) SetRFMon(monitor bool) error {
+       var mon C.int
+       if monitor {
+               mon = 1
+       }
+       switch canset := C.pcap_can_set_rfmon(p.cptr); canset {
+       case 0:
+               return CannotSetRFMon
+       case 1:
+               // success
+       default:
+               return statusError(canset)
+       }
+       if status := C.pcap_set_rfmon(p.cptr, mon); status != 0 {
+               return statusError(status)
+       }
+       return nil
+}
+
+// SetBufferSize sets the buffer size (in bytes) of the handle.
+func (p *InactiveHandle) SetBufferSize(bufferSize int) error {
+       if status := C.pcap_set_buffer_size(p.cptr, C.int(bufferSize)); status < 0 {
+               return statusError(status)
+       }
+       return nil
+}
+
+// SetImmediateMode sets (or unsets) the immediate mode of the
+// handle. In immediate mode, packets are delivered to the application
+// as soon as they arrive.  In other words, this overrides SetTimeout.
+func (p *InactiveHandle) SetImmediateMode(mode bool) error {
+       var md C.int
+       if mode {
+               md = 1
+       }
+       if status := C.pcap_set_immediate_mode(p.cptr, md); status < 0 {
+               return statusError(status)
+       }
+       return nil
+}