123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866 |
- // 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)
- }
|