Committing vendored dependencies and generated protos
Change-Id: I349c149b513d9de7d9f60bde2c954a939da2fc54
diff --git a/vendor/github.com/google/gopacket/pcap/pcap.go b/vendor/github.com/google/gopacket/pcap/pcap.go
new file mode 100644
index 0000000..6a4ef63
--- /dev/null
+++ b/vendor/github.com/google/gopacket/pcap/pcap.go
@@ -0,0 +1,866 @@
+// 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
+
+import (
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "reflect"
+ "runtime"
+ "strconv"
+ "sync"
+ "sync/atomic"
+ "syscall"
+ "time"
+ "unsafe"
+
+ "github.com/google/gopacket"
+ "github.com/google/gopacket/layers"
+)
+
+// ErrNotActive is returned if handle is not activated
+const ErrNotActive = pcapErrorNotActivated
+
+// 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 {
+ // stop is set to a non-zero value by Handle.Close to signal to
+ // getNextBufPtrLocked to stop trying to read packets
+ // This must be the first entry to ensure alignment for sync.atomic
+ stop uint64
+ // cptr is the handle for the actual pcap C object.
+ cptr pcapTPtr
+ timeout time.Duration
+ device string
+ deviceIndex int
+ mu sync.Mutex
+ closeMu sync.Mutex
+ nanoSecsFactor int64
+
+ // 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 *pcapPkthdr
+ bufptr *uint8
+}
+
+// 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
+ Flags uint32
+ Addresses []InterfaceAddress
+}
+
+// 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.
+ Broadaddr net.IP // Broadcast address for this IP may be nil
+ P2P net.IP // P2P destination address for this IP may be nil
+}
+
+// BPF is a compiled filter program, useful for offline packet matching.
+type BPF struct {
+ orig string
+ bpf pcapBpfProgram // takes a finalizer, not overriden by outsiders
+ hdr pcapPkthdr // allocate on the heap to enable optimizations
+}
+
+// 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) 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 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. Warning: this function supports only microsecond timestamps.
+// For nanosecond resolution use an InactiveHandle.
+//
+// See the package documentation for important details regarding 'timeout'.
+func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error) {
+ var pro int
+ if promisc {
+ pro = 1
+ }
+
+ p, err := pcapOpenLive(device, int(snaplen), pro, timeoutMillis(timeout))
+ if err != nil {
+ return nil, err
+ }
+ p.timeout = timeout
+ p.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
+ }
+
+ p.nanoSecsFactor = 1000
+
+ // Only set the PCAP handle into non-blocking mode if we have a timeout
+ // greater than zero. If the user wants to block forever, we'll let libpcap
+ // handle that.
+ if p.timeout > 0 {
+ if err := p.setNonBlocking(); err != nil {
+ p.pcapClose()
+ return nil, err
+ }
+ }
+
+ return p, nil
+}
+
+// OpenOffline opens a file and returns its contents as a *Handle. Depending on libpcap support and
+// on the timestamp resolution used in the file, nanosecond or microsecond resolution is used
+// internally. All returned timestamps are scaled to nanosecond resolution. Resolution() can be used
+// to query the actual resolution used.
+func OpenOffline(file string) (handle *Handle, err error) {
+ handle, err = openOffline(file)
+ if err != nil {
+ return
+ }
+ if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
+ handle.nanoSecsFactor = 1
+ } else {
+ handle.nanoSecsFactor = 1000
+ }
+ return
+}
+
+// OpenOfflineFile returns contents of input file as a *Handle. Depending on libpcap support and
+// on the timestamp resolution used in the file, nanosecond or microsecond resolution is used
+// internally. All returned timestamps are scaled to nanosecond resolution. Resolution() can be used
+// to query the actual resolution used.
+func OpenOfflineFile(file *os.File) (handle *Handle, err error) {
+ handle, err = openOfflineFile(file)
+ if err != nil {
+ return
+ }
+ if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
+ handle.nanoSecsFactor = 1
+ } else {
+ handle.nanoSecsFactor = 1000
+ }
+ return
+}
+
+// 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 = make([]byte, ci.CaptureLength)
+ copy(data, (*(*[1 << 30]byte)(unsafe.Pointer(p.bufptr)))[:])
+ }
+ p.mu.Unlock()
+ if err == NextErrorTimeoutExpired {
+ runtime.Gosched()
+ }
+ return
+}
+
+type activateError int
+
+const (
+ aeNoError = activateError(0)
+ aeActivated = activateError(pcapErrorActivated)
+ aePromisc = activateError(pcapWarningPromisc)
+ aeNoSuchDevice = activateError(pcapErrorNoSuchDevice)
+ aeDenied = activateError(pcapErrorDenied)
+ aeNotUp = activateError(pcapErrorNotUp)
+ aeWarning = activateError(pcapWarning)
+)
+
+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"
+ case aeWarning:
+ return fmt.Sprintf("Warning: %v", activateErrMsg.Error())
+ 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.isOpen() {
+ return io.EOF
+ }
+
+ // set after we have call waitForPacket for the first time
+ var waited bool
+
+ for atomic.LoadUint64(&p.stop) == 0 {
+ // try to read a packet if one is immediately available
+ result := p.pcapNextPacketEx()
+
+ switch result {
+ case NextErrorOk:
+ sec := p.pkthdr.getSec()
+ // convert micros to nanos
+ nanos := int64(p.pkthdr.getUsec()) * p.nanoSecsFactor
+
+ ci.Timestamp = time.Unix(sec, nanos)
+ ci.CaptureLength = p.pkthdr.getCaplen()
+ ci.Length = p.pkthdr.getLen()
+ ci.InterfaceIndex = p.deviceIndex
+
+ return nil
+ case NextErrorNoMorePackets:
+ // no more packets, return EOF rather than libpcap-specific error
+ return io.EOF
+ case NextErrorTimeoutExpired:
+ // we've already waited for a packet and we're supposed to time out
+ //
+ // we should never actually hit this if we were passed BlockForever
+ // since we should block on C.pcap_next_ex until there's a packet
+ // to read.
+ if waited && p.timeout > 0 {
+ return result
+ }
+
+ // wait for packet before trying again
+ p.waitForPacket()
+ waited = true
+ 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.isOpen() {
+ return
+ }
+
+ atomic.StoreUint64(&p.stop, 1)
+
+ // wait for packet reader to stop
+ p.mu.Lock()
+ defer p.mu.Unlock()
+
+ p.pcapClose()
+}
+
+// Error returns the current error associated with a pcap handle (pcap_geterr).
+func (p *Handle) Error() error {
+ return p.pcapGeterr()
+}
+
+// Stats returns statistics on the underlying pcap handle.
+func (p *Handle) Stats() (stat *Stats, err error) {
+ return p.pcapStats()
+}
+
+// ListDataLinks obtains a list of all possible data link types supported for an interface.
+func (p *Handle) ListDataLinks() (datalinks []Datalink, err error) {
+ return p.pcapListDatalinks()
+}
+
+// compileBPFFilter always returns an allocated C.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) (pcapBpfProgram, error) {
+ var maskp = uint32(pcapNetmaskUnknown)
+
+ // Only do the lookup on network interfaces.
+ // No device indicates we're handling a pcap file.
+ if len(p.device) > 0 {
+ var err error
+ _, maskp, err = pcapLookupnet(p.device)
+ if err != nil {
+ // We can't lookup the network, but that could be because the interface
+ // doesn't have an IPv4.
+ maskp = uint32(pcapNetmaskUnknown)
+ }
+ }
+
+ return p.pcapCompile(expr, maskp)
+}
+
+// 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) {
+ h, err := pcapOpenDead(linkType, captureLength)
+ if err != nil {
+ return nil, err
+ }
+ 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 bpf.free()
+ if err != nil {
+ return nil, err
+ }
+
+ return bpf.toBPFInstruction(), 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 bpf.free()
+ if err != nil {
+ return err
+ }
+
+ return p.pcapSetfilter(bpf)
+}
+
+// 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
+ }
+ defer bpf.free()
+
+ return p.pcapSetfilter(bpf)
+}
+
+func bpfInstructionFilter(bpfInstructions []BPFInstruction) (bpf pcapBpfProgram, 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)
+ }
+
+ return pcapBpfProgramFromInstructions(bpfInstructions), nil
+}
+
+// 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}
+
+ var err error
+ bpf.bpf, err = p.pcapCompile(expr, pcapNetmaskUnknown)
+ if err != nil {
+ return nil, err
+ }
+
+ runtime.SetFinalizer(bpf, destroyBPF)
+ return bpf, nil
+}
+
+// NewBPF allows to create a BPF without requiring an existing handle.
+// This allows to match packets obtained from a-non GoPacket capture source
+// to be matched.
+//
+// buf := make([]byte, MaxFrameSize)
+// bpfi, _ := pcap.NewBPF(layers.LinkTypeEthernet, MaxFrameSize, "icmp")
+// n, _ := someIO.Read(buf)
+// ci := gopacket.CaptureInfo{CaptureLength: n, Length: n}
+// if bpfi.Matches(ci, buf) {
+// doSomething()
+// }
+func NewBPF(linkType layers.LinkType, captureLength int, expr string) (*BPF, error) {
+ h, err := pcapOpenDead(linkType, captureLength)
+ if err != nil {
+ return nil, err
+ }
+ defer h.Close()
+ return h.NewBPF(expr)
+}
+
+// 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) {
+ bpf.bpf.free()
+}
+
+// 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 {
+ return b.pcapOfflineFilter(ci, data)
+}
+
+// Version returns pcap_lib_version.
+func Version() string {
+ return pcapLibVersion()
+}
+
+// LinkType returns pcap_datalink, as a layers.LinkType.
+func (p *Handle) LinkType() layers.LinkType {
+ return p.pcapDatalink()
+}
+
+// SetLinkType calls pcap_set_datalink on the pcap handle.
+func (p *Handle) SetLinkType(dlt layers.LinkType) error {
+ return p.pcapSetDatalink(dlt)
+}
+
+// DatalinkValToName returns pcap_datalink_val_to_name as string
+func DatalinkValToName(dlt int) string {
+ return pcapDatalinkValToName(dlt)
+}
+
+// DatalinkValToDescription returns pcap_datalink_val_to_description as string
+func DatalinkValToDescription(dlt int) string {
+ return pcapDatalinkValToDescription(dlt)
+}
+
+// DatalinkNameToVal returns pcap_datalink_name_to_val as int
+func DatalinkNameToVal(name string) int {
+ return pcapDatalinkNameToVal(name)
+}
+
+// FindAllDevs attempts to enumerate all interfaces on the current machine.
+func FindAllDevs() (ifs []Interface, err error) {
+ alldevsp, err := pcapFindAllDevs()
+ if err != nil {
+ return nil, err
+ }
+ defer alldevsp.free()
+
+ for alldevsp.next() {
+ var iface Interface
+ iface.Name = alldevsp.name()
+ iface.Description = alldevsp.description()
+ iface.Addresses = findalladdresses(alldevsp.addresses())
+ iface.Flags = alldevsp.flags()
+ ifs = append(ifs, iface)
+ }
+ return
+}
+
+func findalladdresses(addresses pcapAddresses) (retval []InterfaceAddress) {
+ // TODO - make it support more than IPv4 and IPv6?
+ retval = make([]InterfaceAddress, 0, 1)
+ for addresses.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 addresses.addr() == nil {
+ continue
+ }
+ var a InterfaceAddress
+ var err error
+ if a.IP, err = sockaddrToIP(addresses.addr()); err != nil {
+ continue
+ }
+ // To be safe, we'll also check for netmask.
+ if addresses.netmask() == nil {
+ continue
+ }
+ if a.Netmask, err = sockaddrToIP(addresses.netmask()); err != nil {
+ // If we got an IP address but we can't get a netmask, just return the IP
+ // address.
+ a.Netmask = nil
+ }
+ if a.Broadaddr, err = sockaddrToIP(addresses.broadaddr()); err != nil {
+ a.Broadaddr = nil
+ }
+ if a.P2P, err = sockaddrToIP(addresses.dstaddr()); err != nil {
+ a.P2P = nil
+ }
+ retval = append(retval, a)
+ }
+ return
+}
+
+func sockaddrToIP(rsa *syscall.RawSockaddr) (IP []byte, err error) {
+ if rsa == nil {
+ err = errors.New("Value not set")
+ return
+ }
+ 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) {
+ return p.pcapSendpacket(data)
+}
+
+// Direction is used by Handle.SetDirection.
+type Direction uint8
+
+// Direction values for Handle.SetDirection.
+const (
+ DirectionIn = Direction(pcapDIN)
+ DirectionOut = Direction(pcapDOUT)
+ DirectionInOut = Direction(pcapDINOUT)
+)
+
+// 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)
+ }
+ return p.pcapSetdirection(direction)
+}
+
+// SnapLen returns the snapshot length
+func (p *Handle) SnapLen() int {
+ return p.pcapSnapshot()
+}
+
+// Resolution returns the timestamp resolution of acquired timestamps before scaling to NanosecondTimestampResolution.
+func (p *Handle) Resolution() gopacket.TimestampResolution {
+ if p.nanoSecsFactor == 1 {
+ return gopacket.TimestampResolutionMicrosecond
+ }
+ return gopacket.TimestampResolutionNanosecond
+}
+
+// TimestampSource tells PCAP which type of timestamp to use for packets.
+type TimestampSource int
+
+// String returns the timestamp type as a human-readable string.
+func (t TimestampSource) String() string {
+ return t.pcapTstampTypeValToName()
+}
+
+// TimestampSourceFromString translates a string into a timestamp type, case
+// insensitive.
+func TimestampSourceFromString(s string) (TimestampSource, error) {
+ return pcapTstampTypeNameToVal(s)
+}
+
+// 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 pcapTPtr
+ device string
+ deviceIndex int
+ timeout time.Duration
+}
+
+// holds the err messoge in case activation returned a Warning
+var activateErrMsg error
+
+// Error returns the current error associated with a pcap handle (pcap_geterr).
+func (p *InactiveHandle) Error() error {
+ return p.pcapGeterr()
+}
+
+// Activate activates the handle. The current InactiveHandle becomes invalid
+// and all future function calls on it will fail.
+func (p *InactiveHandle) Activate() (*Handle, error) {
+ // ignore error with set_tstamp_precision, since the actual precision is queried later anyway
+ pcapSetTstampPrecision(p.cptr, pcapTstampPrecisionNano)
+ handle, err := p.pcapActivate()
+ if err != aeNoError {
+ if err == aeWarning {
+ activateErrMsg = p.Error()
+ }
+ return nil, err
+ }
+ handle.timeout = p.timeout
+ if p.timeout > 0 {
+ if err := handle.setNonBlocking(); err != nil {
+ handle.pcapClose()
+ return nil, err
+ }
+ }
+ handle.device = p.device
+ handle.deviceIndex = p.deviceIndex
+ if pcapGetTstampPrecision(handle.cptr) == pcapTstampPrecisionNano {
+ handle.nanoSecsFactor = 1
+ } else {
+ handle.nanoSecsFactor = 1000
+ }
+ return handle, nil
+}
+
+// CleanUp cleans up any stuff left over from a successful or failed building
+// of a handle.
+func (p *InactiveHandle) CleanUp() {
+ p.pcapClose()
+}
+
+// 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) {
+ // 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:
+ handle, err := pcapCreate(device)
+ if err != nil {
+ return nil, err
+ }
+ handle.device = device
+ handle.deviceIndex = deviceIndex
+ return handle, nil
+}
+
+// SetSnapLen sets the snap length (max bytes per packet to capture).
+func (p *InactiveHandle) SetSnapLen(snaplen int) error {
+ return p.pcapSetSnaplen(snaplen)
+}
+
+// SetPromisc sets the handle to either be promiscuous (capture packets
+// unrelated to this host) or not.
+func (p *InactiveHandle) SetPromisc(promisc bool) error {
+ return p.pcapSetPromisc(promisc)
+}
+
+// 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 {
+ err := p.pcapSetTimeout(timeout)
+ if err != nil {
+ return err
+ }
+ p.timeout = timeout
+ return nil
+}
+
+// SupportedTimestamps returns a list of supported timstamp types for this
+// handle.
+func (p *InactiveHandle) SupportedTimestamps() (out []TimestampSource) {
+ return p.pcapListTstampTypes()
+}
+
+// SetTimestampSource sets the type of timestamp generator PCAP uses when
+// attaching timestamps to packets.
+func (p *InactiveHandle) SetTimestampSource(t TimestampSource) error {
+ return p.pcapSetTstampType(t)
+}
+
+// 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 {
+ return p.pcapSetRfmon(monitor)
+}
+
+// SetBufferSize sets the buffer size (in bytes) of the handle.
+func (p *InactiveHandle) SetBufferSize(bufferSize int) error {
+ return p.pcapSetBufferSize(bufferSize)
+}
+
+// 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 {
+ return p.pcapSetImmediateMode(mode)
+}