Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
877 lines (770 sloc) 25.7 KB
// 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
}
// bpfFilter keeps C.struct_bpf_program separate from BPF.orig which might be a pointer to go memory.
// This is a workaround for https://github.com/golang/go/issues/32970 which will be fixed in go1.14.
// (type conversion is in pcap_unix.go pcapOfflineFilter)
type bpfFilter struct {
bpf pcapBpfProgram // takes a finalizer, not overriden by outsiders
}
// BPF is a compiled filter program, useful for offline packet matching.
type BPF struct {
orig string
bpf *bpfFilter
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)
aeError = activateError(pcapError)
)
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())
case aeError:
return fmt.Sprintf("Error: %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, bpf: new(bpfFilter)}
var err error
bpf.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: new(bpfFilter)}
bpf.bpf.bpf, err = bpfInstructionFilter(bpfInstructions)
if err != nil {
return nil, err
}
runtime.SetFinalizer(bpf, destroyBPF)
return bpf, nil
}
func destroyBPF(bpf *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 || err == aeError {
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)
}
You can’t perform that action at this time.