mirror of
https://github.com/40t/go-sniffer.git
synced 2025-08-08 05:30:34 +08:00
implementl get user and database
Signed-off-by: zhuhuijun <zhuhuijunzhj@gmail.com>
This commit is contained in:
74
vendor/github.com/google/gopacket/pcap/defs_windows_386.go
generated
vendored
Normal file
74
vendor/github.com/google/gopacket/pcap/defs_windows_386.go
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
// Copyright 2019 The GoPacket Authors. 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.
|
||||
|
||||
// This file contains necessary structs/constants generated from libpcap headers with cgo -godefs
|
||||
// generated with: generate_defs.exe
|
||||
// DO NOT MODIFY
|
||||
|
||||
package pcap
|
||||
|
||||
import "syscall"
|
||||
|
||||
const errorBufferSize = 0x100
|
||||
|
||||
const (
|
||||
pcapErrorNotActivated = -0x3
|
||||
pcapErrorActivated = -0x4
|
||||
pcapWarningPromisc = 0x2
|
||||
pcapErrorNoSuchDevice = -0x5
|
||||
pcapErrorDenied = -0x8
|
||||
pcapErrorNotUp = -0x9
|
||||
pcapError = -0x1
|
||||
pcapWarning = 0x1
|
||||
pcapDIN = 0x1
|
||||
pcapDOUT = 0x2
|
||||
pcapDINOUT = 0x0
|
||||
pcapNetmaskUnknown = 0xffffffff
|
||||
pcapTstampPrecisionMicro = 0x0
|
||||
pcapTstampPrecisionNano = 0x1
|
||||
)
|
||||
|
||||
type timeval struct {
|
||||
Sec int32
|
||||
Usec int32
|
||||
}
|
||||
type pcapPkthdr struct {
|
||||
Ts timeval
|
||||
Caplen uint32
|
||||
Len uint32
|
||||
}
|
||||
type pcapTPtr uintptr
|
||||
type pcapBpfInstruction struct {
|
||||
Code uint16
|
||||
Jt uint8
|
||||
Jf uint8
|
||||
K uint32
|
||||
}
|
||||
type pcapBpfProgram struct {
|
||||
Len uint32
|
||||
Insns *pcapBpfInstruction
|
||||
}
|
||||
type pcapStats struct {
|
||||
Recv uint32
|
||||
Drop uint32
|
||||
Ifdrop uint32
|
||||
}
|
||||
type pcapCint int32
|
||||
type pcapIf struct {
|
||||
Next *pcapIf
|
||||
Name *int8
|
||||
Description *int8
|
||||
Addresses *pcapAddr
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
type pcapAddr struct {
|
||||
Next *pcapAddr
|
||||
Addr *syscall.RawSockaddr
|
||||
Netmask *syscall.RawSockaddr
|
||||
Broadaddr *syscall.RawSockaddr
|
||||
Dstaddr *syscall.RawSockaddr
|
||||
}
|
76
vendor/github.com/google/gopacket/pcap/defs_windows_amd64.go
generated
vendored
Normal file
76
vendor/github.com/google/gopacket/pcap/defs_windows_amd64.go
generated
vendored
Normal file
@@ -0,0 +1,76 @@
|
||||
// Copyright 2019 The GoPacket Authors. 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.
|
||||
|
||||
// This file contains necessary structs/constants generated from libpcap headers with cgo -godefs
|
||||
// generated with: generate_defs.exe
|
||||
// DO NOT MODIFY
|
||||
|
||||
package pcap
|
||||
|
||||
import "syscall"
|
||||
|
||||
const errorBufferSize = 0x100
|
||||
|
||||
const (
|
||||
pcapErrorNotActivated = -0x3
|
||||
pcapErrorActivated = -0x4
|
||||
pcapWarningPromisc = 0x2
|
||||
pcapErrorNoSuchDevice = -0x5
|
||||
pcapErrorDenied = -0x8
|
||||
pcapErrorNotUp = -0x9
|
||||
pcapError = -0x1
|
||||
pcapWarning = 0x1
|
||||
pcapDIN = 0x1
|
||||
pcapDOUT = 0x2
|
||||
pcapDINOUT = 0x0
|
||||
pcapNetmaskUnknown = 0xffffffff
|
||||
pcapTstampPrecisionMicro = 0x0
|
||||
pcapTstampPrecisionNano = 0x1
|
||||
)
|
||||
|
||||
type timeval struct {
|
||||
Sec int32
|
||||
Usec int32
|
||||
}
|
||||
type pcapPkthdr struct {
|
||||
Ts timeval
|
||||
Caplen uint32
|
||||
Len uint32
|
||||
}
|
||||
type pcapTPtr uintptr
|
||||
type pcapBpfInstruction struct {
|
||||
Code uint16
|
||||
Jt uint8
|
||||
Jf uint8
|
||||
K uint32
|
||||
}
|
||||
type pcapBpfProgram struct {
|
||||
Len uint32
|
||||
Pad_cgo_0 [4]byte
|
||||
Insns *pcapBpfInstruction
|
||||
}
|
||||
type pcapStats struct {
|
||||
Recv uint32
|
||||
Drop uint32
|
||||
Ifdrop uint32
|
||||
}
|
||||
type pcapCint int32
|
||||
type pcapIf struct {
|
||||
Next *pcapIf
|
||||
Name *int8
|
||||
Description *int8
|
||||
Addresses *pcapAddr
|
||||
Flags uint32
|
||||
Pad_cgo_0 [4]byte
|
||||
}
|
||||
|
||||
type pcapAddr struct {
|
||||
Next *pcapAddr
|
||||
Addr *syscall.RawSockaddr
|
||||
Netmask *syscall.RawSockaddr
|
||||
Broadaddr *syscall.RawSockaddr
|
||||
Dstaddr *syscall.RawSockaddr
|
||||
}
|
112
vendor/github.com/google/gopacket/pcap/doc.go
generated
vendored
Normal file
112
vendor/github.com/google/gopacket/pcap/doc.go
generated
vendored
Normal file
@@ -0,0 +1,112 @@
|
||||
// Copyright 2012 Google, Inc. 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 allows users of gopacket to read packets off the wire or from
|
||||
pcap files.
|
||||
|
||||
This package is meant to be used with its parent,
|
||||
http://github.com/google/gopacket, although it can also be used independently
|
||||
if you just want to get packet data from the wire.
|
||||
|
||||
Depending on libpcap version, os support, or file timestamp resolution,
|
||||
nanosecond resolution is used for the internal timestamps. Returned timestamps
|
||||
are always scaled to nanosecond resolution due to the usage of time.Time.
|
||||
libpcap must be at least version 1.5 to support nanosecond timestamps. OpenLive
|
||||
supports only microsecond resolution.
|
||||
|
||||
Reading PCAP Files
|
||||
|
||||
The following code can be used to read in data from a pcap file.
|
||||
|
||||
if handle, err := pcap.OpenOffline("/path/to/my/file"); err != nil {
|
||||
panic(err)
|
||||
} else {
|
||||
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
|
||||
for packet := range packetSource.Packets() {
|
||||
handlePacket(packet) // Do something with a packet here.
|
||||
}
|
||||
}
|
||||
|
||||
Reading Live Packets
|
||||
|
||||
The following code can be used to read in data from a live device, in this case
|
||||
"eth0". Be aware, that OpenLive only supports microsecond resolution.
|
||||
|
||||
if handle, err := pcap.OpenLive("eth0", 1600, true, pcap.BlockForever); err != nil {
|
||||
panic(err)
|
||||
} else if err := handle.SetBPFFilter("tcp and port 80"); err != nil { // optional
|
||||
panic(err)
|
||||
} else {
|
||||
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
|
||||
for packet := range packetSource.Packets() {
|
||||
handlePacket(packet) // Do something with a packet here.
|
||||
}
|
||||
}
|
||||
|
||||
Inactive Handles
|
||||
|
||||
Newer PCAP functionality requires the concept of an 'inactive' PCAP handle.
|
||||
Instead of constantly adding new arguments to pcap_open_live, users now call
|
||||
pcap_create to create a handle, set it up with a bunch of optional function
|
||||
calls, then call pcap_activate to activate it. This library mirrors that
|
||||
mechanism, for those that want to expose/use these new features:
|
||||
|
||||
inactive, err := pcap.NewInactiveHandle(deviceName)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer inactive.CleanUp()
|
||||
|
||||
// Call various functions on inactive to set it up the way you'd like:
|
||||
if err = inactive.SetTimeout(time.Minute); err != nil {
|
||||
log.Fatal(err)
|
||||
} else if err = inactive.SetTimestampSource("foo"); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
// Finally, create the actual handle by calling Activate:
|
||||
handle, err := inactive.Activate() // after this, inactive is no longer valid
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
defer handle.Close()
|
||||
|
||||
// Now use your handle as you see fit.
|
||||
|
||||
PCAP Timeouts
|
||||
|
||||
pcap.OpenLive and pcap.SetTimeout both take timeouts.
|
||||
If you don't care about timeouts, just pass in BlockForever,
|
||||
which should do what you expect with minimal fuss.
|
||||
|
||||
A timeout of 0 is not recommended. Some platforms, like Macs
|
||||
(http://www.manpages.info/macosx/pcap.3.html) say:
|
||||
The read timeout is used to arrange that the read not necessarily return
|
||||
immediately when a packet is seen, but that it wait for some amount of time
|
||||
to allow more packets to arrive and to read multiple packets from the OS
|
||||
kernel in one operation.
|
||||
This means that if you only capture one packet, the kernel might decide to wait
|
||||
'timeout' for more packets to batch with it before returning. A timeout of
|
||||
0, then, means 'wait forever for more packets', which is... not good.
|
||||
|
||||
To get around this, we've introduced the following behavior: if a negative
|
||||
timeout is passed in, we set the positive timeout in the handle, then loop
|
||||
internally in ReadPacketData/ZeroCopyReadPacketData when we see timeout
|
||||
errors.
|
||||
|
||||
PCAP File Writing
|
||||
|
||||
This package does not implement PCAP file writing. However, gopacket/pcapgo
|
||||
does! Look there if you'd like to write PCAP files.
|
||||
|
||||
Note For Windows Users
|
||||
|
||||
gopacket can use winpcap or npcap. If both are installed at the same time,
|
||||
npcap is preferred. Make sure the right windows service is loaded (npcap for npcap
|
||||
and npf for winpcap).
|
||||
*/
|
||||
package pcap
|
876
vendor/github.com/google/gopacket/pcap/pcap.go
generated
vendored
Normal file
876
vendor/github.com/google/gopacket/pcap/pcap.go
generated
vendored
Normal file
@@ -0,0 +1,876 @@
|
||||
// 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)
|
||||
}
|
707
vendor/github.com/google/gopacket/pcap/pcap_unix.go
generated
vendored
Normal file
707
vendor/github.com/google/gopacket/pcap/pcap_unix.go
generated
vendored
Normal file
@@ -0,0 +1,707 @@
|
||||
// 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.
|
||||
//
|
||||
// +build !windows
|
||||
|
||||
package pcap
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"os"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
|
||||
"github.com/google/gopacket/layers"
|
||||
)
|
||||
|
||||
/*
|
||||
#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
|
||||
#include <stdlib.h>
|
||||
#include <pcap.h>
|
||||
#include <stdint.h>
|
||||
#include <poll.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
|
||||
#define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12
|
||||
|
||||
int pcap_set_immediate_mode(pcap_t *p, int mode) {
|
||||
return PCAP_ERROR;
|
||||
}
|
||||
|
||||
// libpcap version < v1.5 doesn't have timestamp precision (everything is microsecond)
|
||||
//
|
||||
// This means *_tstamp_* functions and macros are missing. Therefore, we emulate these
|
||||
// functions here and pretend the setting the precision works. This is actually the way
|
||||
// the pcap_open_offline_with_tstamp_precision works, because it doesn't return an error
|
||||
// if it was not possible to set the precision, which depends on support by the given file.
|
||||
// => The rest of the functions always pretend as if they could set nano precision and
|
||||
// verify the actual precision with pcap_get_tstamp_precision, which is emulated for <v1.5
|
||||
// to always return micro resolution.
|
||||
|
||||
#define PCAP_TSTAMP_PRECISION_MICRO 0
|
||||
#define PCAP_TSTAMP_PRECISION_NANO 1
|
||||
|
||||
pcap_t *pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
|
||||
char *errbuf) {
|
||||
return pcap_open_offline(fname, errbuf);
|
||||
}
|
||||
|
||||
pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
|
||||
char *errbuf) {
|
||||
return pcap_fopen_offline(fp, errbuf);
|
||||
}
|
||||
|
||||
int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision) {
|
||||
if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO)
|
||||
return 0;
|
||||
return PCAP_ERROR_TSTAMP_PRECISION_NOTSUP;
|
||||
}
|
||||
|
||||
int pcap_get_tstamp_precision(pcap_t *p) {
|
||||
return PCAP_TSTAMP_PRECISION_MICRO;
|
||||
}
|
||||
|
||||
#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
|
||||
|
||||
// Windows, Macs, and Linux all use different time types. Joy.
|
||||
#ifdef __APPLE__
|
||||
#define gopacket_time_secs_t __darwin_time_t
|
||||
#define gopacket_time_usecs_t __darwin_suseconds_t
|
||||
#elif __ANDROID__
|
||||
#define gopacket_time_secs_t __kernel_time_t
|
||||
#define gopacket_time_usecs_t __kernel_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
|
||||
|
||||
// The things we do to avoid pointers escaping to the heap...
|
||||
// According to https://github.com/the-tcpdump-group/libpcap/blob/1131a7c26c6f4d4772e4a2beeaf7212f4dea74ac/pcap.c#L398-L406 ,
|
||||
// the return value of pcap_next_ex could be greater than 1 for success.
|
||||
// Let's just make it 1 if it comes bigger than 1.
|
||||
int pcap_next_ex_escaping(pcap_t *p, uintptr_t pkt_hdr, uintptr_t pkt_data) {
|
||||
int ex = pcap_next_ex(p, (struct pcap_pkthdr**)(pkt_hdr), (const u_char**)(pkt_data));
|
||||
if (ex > 1) {
|
||||
ex = 1;
|
||||
}
|
||||
return ex;
|
||||
}
|
||||
|
||||
int pcap_offline_filter_escaping(struct bpf_program *fp, uintptr_t pkt_hdr, uintptr_t pkt) {
|
||||
return pcap_offline_filter(fp, (struct pcap_pkthdr*)(pkt_hdr), (const u_char*)(pkt));
|
||||
}
|
||||
|
||||
// pcap_wait returns when the next packet is available or the timeout expires.
|
||||
// Since it uses pcap_get_selectable_fd, it will not work in Windows.
|
||||
int pcap_wait(pcap_t *p, int msec) {
|
||||
struct pollfd fds[1];
|
||||
int fd;
|
||||
|
||||
fd = pcap_get_selectable_fd(p);
|
||||
if(fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
fds[0].fd = fd;
|
||||
fds[0].events = POLLIN;
|
||||
|
||||
if(msec != 0) {
|
||||
return poll(fds, 1, msec);
|
||||
}
|
||||
|
||||
// block indefinitely if no timeout provided
|
||||
return poll(fds, 1, -1);
|
||||
}
|
||||
|
||||
*/
|
||||
import "C"
|
||||
|
||||
const errorBufferSize = C.PCAP_ERRBUF_SIZE
|
||||
|
||||
const (
|
||||
pcapErrorNotActivated = C.PCAP_ERROR_NOT_ACTIVATED
|
||||
pcapErrorActivated = C.PCAP_ERROR_ACTIVATED
|
||||
pcapWarningPromisc = C.PCAP_WARNING_PROMISC_NOTSUP
|
||||
pcapErrorNoSuchDevice = C.PCAP_ERROR_NO_SUCH_DEVICE
|
||||
pcapErrorDenied = C.PCAP_ERROR_PERM_DENIED
|
||||
pcapErrorNotUp = C.PCAP_ERROR_IFACE_NOT_UP
|
||||
pcapWarning = C.PCAP_WARNING
|
||||
pcapError = C.PCAP_ERROR
|
||||
pcapDIN = C.PCAP_D_IN
|
||||
pcapDOUT = C.PCAP_D_OUT
|
||||
pcapDINOUT = C.PCAP_D_INOUT
|
||||
pcapNetmaskUnknown = C.PCAP_NETMASK_UNKNOWN
|
||||
pcapTstampPrecisionMicro = C.PCAP_TSTAMP_PRECISION_MICRO
|
||||
pcapTstampPrecisionNano = C.PCAP_TSTAMP_PRECISION_NANO
|
||||
)
|
||||
|
||||
type pcapPkthdr C.struct_pcap_pkthdr
|
||||
type pcapTPtr *C.struct_pcap
|
||||
type pcapBpfProgram C.struct_bpf_program
|
||||
|
||||
func (h *pcapPkthdr) getSec() int64 {
|
||||
return int64(h.ts.tv_sec)
|
||||
}
|
||||
|
||||
func (h *pcapPkthdr) getUsec() int64 {
|
||||
return int64(h.ts.tv_usec)
|
||||
}
|
||||
|
||||
func (h *pcapPkthdr) getLen() int {
|
||||
return int(h.len)
|
||||
}
|
||||
|
||||
func (h *pcapPkthdr) getCaplen() int {
|
||||
return int(h.caplen)
|
||||
}
|
||||
|
||||
func pcapGetTstampPrecision(cptr pcapTPtr) int {
|
||||
return int(C.pcap_get_tstamp_precision(cptr))
|
||||
}
|
||||
|
||||
func pcapSetTstampPrecision(cptr pcapTPtr, precision int) error {
|
||||
ret := C.pcap_set_tstamp_precision(cptr, C.int(precision))
|
||||
if ret < 0 {
|
||||
return errors.New(C.GoString(C.pcap_geterr(cptr)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func statusError(status C.int) error {
|
||||
return errors.New(C.GoString(C.pcap_statustostr(status)))
|
||||
}
|
||||
|
||||
func pcapOpenLive(device string, snaplen int, pro int, timeout int) (*Handle, error) {
|
||||
buf := (*C.char)(C.calloc(errorBufferSize, 1))
|
||||
defer C.free(unsafe.Pointer(buf))
|
||||
|
||||
dev := C.CString(device)
|
||||
defer C.free(unsafe.Pointer(dev))
|
||||
|
||||
cptr := C.pcap_open_live(dev, C.int(snaplen), C.int(pro), C.int(timeout), buf)
|
||||
if cptr == nil {
|
||||
return nil, errors.New(C.GoString(buf))
|
||||
}
|
||||
return &Handle{cptr: cptr}, nil
|
||||
}
|
||||
|
||||
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_with_tstamp_precision(cf, C.PCAP_TSTAMP_PRECISION_NANO, buf)
|
||||
if cptr == nil {
|
||||
return nil, errors.New(C.GoString(buf))
|
||||
}
|
||||
return &Handle{cptr: cptr}, nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapClose() {
|
||||
if p.cptr != nil {
|
||||
C.pcap_close(p.cptr)
|
||||
}
|
||||
p.cptr = nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapGeterr() error {
|
||||
return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
|
||||
}
|
||||
|
||||
func (p *Handle) pcapStats() (*Stats, error) {
|
||||
var cstats C.struct_pcap_stat
|
||||
if C.pcap_stats(p.cptr, &cstats) < 0 {
|
||||
return nil, p.pcapGeterr()
|
||||
}
|
||||
return &Stats{
|
||||
PacketsReceived: int(cstats.ps_recv),
|
||||
PacketsDropped: int(cstats.ps_drop),
|
||||
PacketsIfDropped: int(cstats.ps_ifdrop),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// for libpcap < 1.8 pcap_compile is NOT thread-safe, so protect it.
|
||||
var pcapCompileMu sync.Mutex
|
||||
|
||||
func (p *Handle) pcapCompile(expr string, maskp uint32) (pcapBpfProgram, error) {
|
||||
var bpf pcapBpfProgram
|
||||
cexpr := C.CString(expr)
|
||||
defer C.free(unsafe.Pointer(cexpr))
|
||||
|
||||
pcapCompileMu.Lock()
|
||||
defer pcapCompileMu.Unlock()
|
||||
if C.pcap_compile(p.cptr, (*C.struct_bpf_program)(&bpf), cexpr, 1, C.bpf_u_int32(maskp)) < 0 {
|
||||
return bpf, p.pcapGeterr()
|
||||
}
|
||||
return bpf, nil
|
||||
}
|
||||
|
||||
func (p pcapBpfProgram) free() {
|
||||
C.pcap_freecode((*C.struct_bpf_program)(&p))
|
||||
}
|
||||
|
||||
func (p pcapBpfProgram) toBPFInstruction() []BPFInstruction {
|
||||
bpfInsn := (*[bpfInstructionBufferSize]C.struct_bpf_insn)(unsafe.Pointer(p.bf_insns))[0:p.bf_len:p.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
|
||||
}
|
||||
|
||||
func pcapBpfProgramFromInstructions(bpfInstructions []BPFInstruction) pcapBpfProgram {
|
||||
var bpf pcapBpfProgram
|
||||
bpf.bf_len = C.u_int(len(bpfInstructions))
|
||||
cbpfInsns := C.calloc(C.size_t(len(bpfInstructions)), C.size_t(unsafe.Sizeof(bpfInstructions[0])))
|
||||
gbpfInsns := (*[bpfInstructionBufferSize]C.struct_bpf_insn)(cbpfInsns)
|
||||
|
||||
for i, v := range bpfInstructions {
|
||||
gbpfInsns[i].code = C.u_short(v.Code)
|
||||
gbpfInsns[i].jt = C.u_char(v.Jt)
|
||||
gbpfInsns[i].jf = C.u_char(v.Jf)
|
||||
gbpfInsns[i].k = C.bpf_u_int32(v.K)
|
||||
}
|
||||
|
||||
bpf.bf_insns = (*C.struct_bpf_insn)(cbpfInsns)
|
||||
return bpf
|
||||
}
|
||||
|
||||
func pcapLookupnet(device string) (netp, maskp uint32, err error) {
|
||||
errorBuf := (*C.char)(C.calloc(errorBufferSize, 1))
|
||||
defer C.free(unsafe.Pointer(errorBuf))
|
||||
dev := C.CString(device)
|
||||
defer C.free(unsafe.Pointer(dev))
|
||||
if C.pcap_lookupnet(
|
||||
dev,
|
||||
(*C.bpf_u_int32)(unsafe.Pointer(&netp)),
|
||||
(*C.bpf_u_int32)(unsafe.Pointer(&maskp)),
|
||||
errorBuf,
|
||||
) < 0 {
|
||||
return 0, 0, errors.New(C.GoString(errorBuf))
|
||||
// We can't lookup the network, but that could be because the interface
|
||||
// doesn't have an IPv4.
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *BPF) pcapOfflineFilter(ci gopacket.CaptureInfo, data []byte) bool {
|
||||
hdr := (*C.struct_pcap_pkthdr)(&b.hdr)
|
||||
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_escaping((*C.struct_bpf_program)(&b.bpf.bpf),
|
||||
C.uintptr_t(uintptr(unsafe.Pointer(hdr))),
|
||||
C.uintptr_t(uintptr(unsafe.Pointer(dataptr)))) != 0
|
||||
}
|
||||
|
||||
func (p *Handle) pcapSetfilter(bpf pcapBpfProgram) error {
|
||||
if C.pcap_setfilter(p.cptr, (*C.struct_bpf_program)(&bpf)) < 0 {
|
||||
return p.pcapGeterr()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapListDatalinks() (datalinks []Datalink, err error) {
|
||||
var dltbuf *C.int
|
||||
|
||||
n := int(C.pcap_list_datalinks(p.cptr, &dltbuf))
|
||||
if n < 0 {
|
||||
return nil, p.pcapGeterr()
|
||||
}
|
||||
|
||||
defer C.pcap_free_datalinks(dltbuf)
|
||||
|
||||
datalinks = make([]Datalink, n)
|
||||
|
||||
dltArray := (*[1 << 28]C.int)(unsafe.Pointer(dltbuf))
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
datalinks[i].Name = pcapDatalinkValToName(int((*dltArray)[i]))
|
||||
datalinks[i].Description = pcapDatalinkValToDescription(int((*dltArray)[i]))
|
||||
}
|
||||
|
||||
return datalinks, nil
|
||||
}
|
||||
|
||||
func pcapOpenDead(linkType layers.LinkType, captureLength int) (*Handle, error) {
|
||||
cptr := C.pcap_open_dead(C.int(linkType), C.int(captureLength))
|
||||
if cptr == nil {
|
||||
return nil, errors.New("error opening dead capture")
|
||||
}
|
||||
|
||||
return &Handle{cptr: cptr}, nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapNextPacketEx() NextError {
|
||||
// This horrible magic allows us to pass a ptr-to-ptr to pcap_next_ex
|
||||
// without causing that ptr-to-ptr to itself be allocated on the heap.
|
||||
// Since Handle itself survives through the duration of the pcap_next_ex
|
||||
// call, this should be perfectly safe for GC stuff, etc.
|
||||
|
||||
return NextError(C.pcap_next_ex_escaping(p.cptr, C.uintptr_t(uintptr(unsafe.Pointer(&p.pkthdr))), C.uintptr_t(uintptr(unsafe.Pointer(&p.bufptr)))))
|
||||
}
|
||||
|
||||
func (p *Handle) pcapDatalink() layers.LinkType {
|
||||
return layers.LinkType(C.pcap_datalink(p.cptr))
|
||||
}
|
||||
|
||||
func (p *Handle) pcapSetDatalink(dlt layers.LinkType) error {
|
||||
if C.pcap_set_datalink(p.cptr, C.int(dlt)) < 0 {
|
||||
return p.pcapGeterr()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func pcapDatalinkValToName(dlt int) string {
|
||||
return C.GoString(C.pcap_datalink_val_to_name(C.int(dlt)))
|
||||
}
|
||||
|
||||
func pcapDatalinkValToDescription(dlt int) string {
|
||||
return C.GoString(C.pcap_datalink_val_to_description(C.int(dlt)))
|
||||
}
|
||||
|
||||
func pcapDatalinkNameToVal(name string) int {
|
||||
cptr := C.CString(name)
|
||||
defer C.free(unsafe.Pointer(cptr))
|
||||
return int(C.pcap_datalink_name_to_val(cptr))
|
||||
}
|
||||
|
||||
func pcapLibVersion() string {
|
||||
return C.GoString(C.pcap_lib_version())
|
||||
}
|
||||
|
||||
func (p *Handle) isOpen() bool {
|
||||
return p.cptr != nil
|
||||
}
|
||||
|
||||
type pcapDevices struct {
|
||||
all, cur *C.pcap_if_t
|
||||
}
|
||||
|
||||
func (p pcapDevices) free() {
|
||||
C.pcap_freealldevs((*C.pcap_if_t)(p.all))
|
||||
}
|
||||
|
||||
func (p *pcapDevices) next() bool {
|
||||
if p.cur == nil {
|
||||
p.cur = p.all
|
||||
if p.cur == nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
if p.cur.next == nil {
|
||||
return false
|
||||
}
|
||||
p.cur = p.cur.next
|
||||
return true
|
||||
}
|
||||
|
||||
func (p pcapDevices) name() string {
|
||||
return C.GoString(p.cur.name)
|
||||
}
|
||||
|
||||
func (p pcapDevices) description() string {
|
||||
return C.GoString(p.cur.description)
|
||||
}
|
||||
|
||||
func (p pcapDevices) flags() uint32 {
|
||||
return uint32(p.cur.flags)
|
||||
}
|
||||
|
||||
type pcapAddresses struct {
|
||||
all, cur *C.pcap_addr_t
|
||||
}
|
||||
|
||||
func (p *pcapAddresses) next() bool {
|
||||
if p.cur == nil {
|
||||
p.cur = p.all
|
||||
if p.cur == nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
if p.cur.next == nil {
|
||||
return false
|
||||
}
|
||||
p.cur = p.cur.next
|
||||
return true
|
||||
}
|
||||
|
||||
func (p pcapAddresses) addr() *syscall.RawSockaddr {
|
||||
return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.addr))
|
||||
}
|
||||
|
||||
func (p pcapAddresses) netmask() *syscall.RawSockaddr {
|
||||
return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.netmask))
|
||||
}
|
||||
|
||||
func (p pcapAddresses) broadaddr() *syscall.RawSockaddr {
|
||||
return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.broadaddr))
|
||||
}
|
||||
|
||||
func (p pcapAddresses) dstaddr() *syscall.RawSockaddr {
|
||||
return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.dstaddr))
|
||||
}
|
||||
|
||||
func (p pcapDevices) addresses() pcapAddresses {
|
||||
return pcapAddresses{all: p.cur.addresses}
|
||||
}
|
||||
|
||||
func pcapFindAllDevs() (pcapDevices, error) {
|
||||
var buf *C.char
|
||||
buf = (*C.char)(C.calloc(errorBufferSize, 1))
|
||||
defer C.free(unsafe.Pointer(buf))
|
||||
var alldevsp pcapDevices
|
||||
|
||||
if C.pcap_findalldevs((**C.pcap_if_t)(&alldevsp.all), buf) < 0 {
|
||||
return pcapDevices{}, errors.New(C.GoString(buf))
|
||||
}
|
||||
return alldevsp, nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapSendpacket(data []byte) error {
|
||||
if C.pcap_sendpacket(p.cptr, (*C.u_char)(&data[0]), (C.int)(len(data))) < 0 {
|
||||
return p.pcapGeterr()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapSetdirection(direction Direction) error {
|
||||
if status := C.pcap_setdirection(p.cptr, (C.pcap_direction_t)(direction)); status < 0 {
|
||||
return statusError(status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapSnapshot() int {
|
||||
return int(C.pcap_snapshot(p.cptr))
|
||||
}
|
||||
|
||||
func (t TimestampSource) pcapTstampTypeValToName() string {
|
||||
return C.GoString(C.pcap_tstamp_type_val_to_name(C.int(t)))
|
||||
}
|
||||
|
||||
func pcapTstampTypeNameToVal(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 (p *InactiveHandle) pcapGeterr() error {
|
||||
return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapActivate() (*Handle, activateError) {
|
||||
ret := activateError(C.pcap_activate(p.cptr))
|
||||
if ret != aeNoError {
|
||||
return nil, ret
|
||||
}
|
||||
h := &Handle{
|
||||
cptr: p.cptr,
|
||||
}
|
||||
p.cptr = nil
|
||||
return h, ret
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapClose() {
|
||||
if p.cptr != nil {
|
||||
C.pcap_close(p.cptr)
|
||||
}
|
||||
}
|
||||
|
||||
func pcapCreate(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))
|
||||
|
||||
cptr := C.pcap_create(dev, buf)
|
||||
if cptr == nil {
|
||||
return nil, errors.New(C.GoString(buf))
|
||||
}
|
||||
return &InactiveHandle{cptr: cptr}, nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetSnaplen(snaplen int) error {
|
||||
if status := C.pcap_set_snaplen(p.cptr, C.int(snaplen)); status < 0 {
|
||||
return statusError(status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetPromisc(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
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetTimeout(timeout time.Duration) error {
|
||||
if status := C.pcap_set_timeout(p.cptr, C.int(timeoutMillis(timeout))); status < 0 {
|
||||
return statusError(status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapListTstampTypes() (out []TimestampSource) {
|
||||
var types *C.int
|
||||
n := int(C.pcap_list_tstamp_types(p.cptr, &types))
|
||||
if n < 0 {
|
||||
return // public interface doesn't have error :(
|
||||
}
|
||||
defer C.pcap_free_tstamp_types(types)
|
||||
typesArray := (*[1 << 28]C.int)(unsafe.Pointer(types))
|
||||
for i := 0; i < n; i++ {
|
||||
out = append(out, TimestampSource((*typesArray)[i]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetTstampType(t TimestampSource) error {
|
||||
if status := C.pcap_set_tstamp_type(p.cptr, C.int(t)); status < 0 {
|
||||
return statusError(status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetRfmon(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
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetBufferSize(bufferSize int) error {
|
||||
if status := C.pcap_set_buffer_size(p.cptr, C.int(bufferSize)); status < 0 {
|
||||
return statusError(status)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetImmediateMode(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
|
||||
}
|
||||
|
||||
func (p *Handle) setNonBlocking() error {
|
||||
buf := (*C.char)(C.calloc(errorBufferSize, 1))
|
||||
defer C.free(unsafe.Pointer(buf))
|
||||
|
||||
// Change the device to non-blocking, we'll use pcap_wait to wait until the
|
||||
// handle is ready to read.
|
||||
if v := C.pcap_setnonblock(p.cptr, 1, buf); v < -1 {
|
||||
return errors.New(C.GoString(buf))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// waitForPacket waits for a packet or for the timeout to expire.
|
||||
func (p *Handle) waitForPacket() {
|
||||
// According to pcap_get_selectable_fd() man page, there are some cases where it will
|
||||
// return a file descriptor, but a simple call of select() or poll() will not indicate
|
||||
// that the descriptor is readable until a full buffer's worth of packets is received,
|
||||
// so the call must have a timeout less than *or equal* to the packet buffer timeout.
|
||||
// The packet buffer timeout is set to timeoutMillis(p.timeout) in pcapOpenLive(),
|
||||
// so we should be fine to use it here too.
|
||||
C.pcap_wait(p.cptr, C.int(timeoutMillis(p.timeout)))
|
||||
}
|
||||
|
||||
// openOfflineFile returns contents of input file as a *Handle.
|
||||
func openOfflineFile(file *os.File) (handle *Handle, err error) {
|
||||
buf := (*C.char)(C.calloc(errorBufferSize, 1))
|
||||
defer C.free(unsafe.Pointer(buf))
|
||||
cmode := C.CString("rb")
|
||||
defer C.free(unsafe.Pointer(cmode))
|
||||
cf := C.fdopen(C.int(file.Fd()), cmode)
|
||||
|
||||
cptr := C.pcap_fopen_offline_with_tstamp_precision(cf, C.PCAP_TSTAMP_PRECISION_NANO, buf)
|
||||
if cptr == nil {
|
||||
return nil, errors.New(C.GoString(buf))
|
||||
}
|
||||
return &Handle{cptr: cptr}, nil
|
||||
}
|
898
vendor/github.com/google/gopacket/pcap/pcap_windows.go
generated
vendored
Normal file
898
vendor/github.com/google/gopacket/pcap/pcap_windows.go
generated
vendored
Normal file
@@ -0,0 +1,898 @@
|
||||
// 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"
|
||||
"os"
|
||||
"runtime"
|
||||
"sync"
|
||||
"syscall"
|
||||
"time"
|
||||
"unsafe"
|
||||
|
||||
"github.com/google/gopacket"
|
||||
"github.com/google/gopacket/layers"
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
var pcapLoaded = false
|
||||
|
||||
const npcapPath = "\\Npcap"
|
||||
|
||||
func initDllPath(kernel32 syscall.Handle) {
|
||||
setDllDirectory, err := syscall.GetProcAddress(kernel32, "SetDllDirectoryA")
|
||||
if err != nil {
|
||||
// we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
|
||||
return
|
||||
}
|
||||
getSystemDirectory, err := syscall.GetProcAddress(kernel32, "GetSystemDirectoryA")
|
||||
if err != nil {
|
||||
// we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
|
||||
return
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
r, _, _ := syscall.Syscall(getSystemDirectory, 2, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
|
||||
if r == 0 || r > 4096-uintptr(len(npcapPath))-1 {
|
||||
// we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
|
||||
return
|
||||
}
|
||||
copy(buf[r:], npcapPath)
|
||||
_, _, _ = syscall.Syscall(setDllDirectory, 1, uintptr(unsafe.Pointer(&buf[0])), 0, 0)
|
||||
// ignore errors here - we just fallback to load wpcap.dll from default locations
|
||||
}
|
||||
|
||||
// loadedDllPath will hold the full pathname of the loaded wpcap.dll after init if possible
|
||||
var loadedDllPath = "wpcap.dll"
|
||||
|
||||
func initLoadedDllPath(kernel32 syscall.Handle) {
|
||||
getModuleFileName, err := syscall.GetProcAddress(kernel32, "GetModuleFileNameA")
|
||||
if err != nil {
|
||||
// we can't get the filename of the loaded module in this case - just leave default of wpcap.dll
|
||||
return
|
||||
}
|
||||
buf := make([]byte, 4096)
|
||||
r, _, _ := syscall.Syscall(getModuleFileName, 3, uintptr(wpcapHandle), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
|
||||
if r == 0 {
|
||||
// we can't get the filename of the loaded module in this case - just leave default of wpcap.dll
|
||||
return
|
||||
}
|
||||
loadedDllPath = string(buf[:int(r)])
|
||||
}
|
||||
|
||||
func mustLoad(fun string) uintptr {
|
||||
addr, err := windows.GetProcAddress(wpcapHandle, fun)
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("Couldn't load function %s from %s", fun, loadedDllPath))
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
func mightLoad(fun string) uintptr {
|
||||
addr, err := windows.GetProcAddress(wpcapHandle, fun)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return addr
|
||||
}
|
||||
|
||||
func byteSliceToString(bval []byte) string {
|
||||
for i := range bval {
|
||||
if bval[i] == 0 {
|
||||
return string(bval[:i])
|
||||
}
|
||||
}
|
||||
return string(bval[:])
|
||||
}
|
||||
|
||||
// bytePtrToString returns a string copied from pointer to a null terminated byte array
|
||||
// WARNING: ONLY SAFE WITH IF r POINTS TO C MEMORY!
|
||||
// govet will complain about this function for the reason stated above
|
||||
func bytePtrToString(r uintptr) string {
|
||||
if r == 0 {
|
||||
return ""
|
||||
}
|
||||
bval := (*[1 << 30]byte)(unsafe.Pointer(r))
|
||||
return byteSliceToString(bval[:])
|
||||
}
|
||||
|
||||
var wpcapHandle windows.Handle
|
||||
var msvcrtHandle syscall.Handle
|
||||
var (
|
||||
callocPtr,
|
||||
pcapStrerrorPtr,
|
||||
pcapStatustostrPtr,
|
||||
pcapOpenLivePtr,
|
||||
pcapOpenOfflinePtr,
|
||||
pcapClosePtr,
|
||||
pcapGeterrPtr,
|
||||
pcapStatsPtr,
|
||||
pcapCompilePtr,
|
||||
pcapFreecodePtr,
|
||||
pcapLookupnetPtr,
|
||||
pcapOfflineFilterPtr,
|
||||
pcapSetfilterPtr,
|
||||
pcapListDatalinksPtr,
|
||||
pcapFreeDatalinksPtr,
|
||||
pcapDatalinkValToNamePtr,
|
||||
pcapDatalinkValToDescriptionPtr,
|
||||
pcapOpenDeadPtr,
|
||||
pcapNextExPtr,
|
||||
pcapDatalinkPtr,
|
||||
pcapSetDatalinkPtr,
|
||||
pcapDatalinkNameToValPtr,
|
||||
pcapLibVersionPtr,
|
||||
pcapFreealldevsPtr,
|
||||
pcapFindalldevsPtr,
|
||||
pcapSendpacketPtr,
|
||||
pcapSetdirectionPtr,
|
||||
pcapSnapshotPtr,
|
||||
pcapTstampTypeValToNamePtr,
|
||||
pcapTstampTypeNameToValPtr,
|
||||
pcapListTstampTypesPtr,
|
||||
pcapFreeTstampTypesPtr,
|
||||
pcapSetTstampTypePtr,
|
||||
pcapGetTstampPrecisionPtr,
|
||||
pcapSetTstampPrecisionPtr,
|
||||
pcapOpenOfflineWithTstampPrecisionPtr,
|
||||
pcapHOpenOfflineWithTstampPrecisionPtr,
|
||||
pcapActivatePtr,
|
||||
pcapCreatePtr,
|
||||
pcapSetSnaplenPtr,
|
||||
pcapSetPromiscPtr,
|
||||
pcapSetTimeoutPtr,
|
||||
pcapCanSetRfmonPtr,
|
||||
pcapSetRfmonPtr,
|
||||
pcapSetBufferSizePtr,
|
||||
pcapSetImmediateModePtr,
|
||||
pcapHopenOfflinePtr uintptr
|
||||
)
|
||||
|
||||
func init() {
|
||||
LoadWinPCAP()
|
||||
}
|
||||
|
||||
// LoadWinPCAP attempts to dynamically load the wpcap DLL and resolve necessary functions
|
||||
func LoadWinPCAP() error {
|
||||
if pcapLoaded {
|
||||
return nil
|
||||
}
|
||||
|
||||
kernel32, err := syscall.LoadLibrary("kernel32.dll")
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't load kernel32.dll")
|
||||
}
|
||||
defer syscall.FreeLibrary(kernel32)
|
||||
|
||||
initDllPath(kernel32)
|
||||
|
||||
if haveSearch, _ := syscall.GetProcAddress(kernel32, "AddDllDirectory"); haveSearch != 0 {
|
||||
// if AddDllDirectory is present, we can use LOAD_LIBRARY_* stuff with LoadLibraryEx to avoid wpcap.dll hijacking
|
||||
// see: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx
|
||||
const LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400
|
||||
const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
|
||||
wpcapHandle, err = windows.LoadLibraryEx("wpcap.dll", 0, LOAD_LIBRARY_SEARCH_USER_DIRS|LOAD_LIBRARY_SEARCH_SYSTEM32)
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't load wpcap.dll")
|
||||
}
|
||||
} else {
|
||||
// otherwise fall back to load it with the unsafe search cause by SetDllDirectory
|
||||
wpcapHandle, err = windows.LoadLibrary("wpcap.dll")
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't load wpcap.dll")
|
||||
}
|
||||
}
|
||||
initLoadedDllPath(kernel32)
|
||||
msvcrtHandle, err = syscall.LoadLibrary("msvcrt.dll")
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't load msvcrt.dll")
|
||||
}
|
||||
callocPtr, err = syscall.GetProcAddress(msvcrtHandle, "calloc")
|
||||
if err != nil {
|
||||
return fmt.Errorf("couldn't get calloc function")
|
||||
}
|
||||
|
||||
pcapStrerrorPtr = mustLoad("pcap_strerror")
|
||||
pcapStatustostrPtr = mightLoad("pcap_statustostr") // not available on winpcap
|
||||
pcapOpenLivePtr = mustLoad("pcap_open_live")
|
||||
pcapOpenOfflinePtr = mustLoad("pcap_open_offline")
|
||||
pcapClosePtr = mustLoad("pcap_close")
|
||||
pcapGeterrPtr = mustLoad("pcap_geterr")
|
||||
pcapStatsPtr = mustLoad("pcap_stats")
|
||||
pcapCompilePtr = mustLoad("pcap_compile")
|
||||
pcapFreecodePtr = mustLoad("pcap_freecode")
|
||||
pcapLookupnetPtr = mustLoad("pcap_lookupnet")
|
||||
pcapOfflineFilterPtr = mustLoad("pcap_offline_filter")
|
||||
pcapSetfilterPtr = mustLoad("pcap_setfilter")
|
||||
pcapListDatalinksPtr = mustLoad("pcap_list_datalinks")
|
||||
pcapFreeDatalinksPtr = mustLoad("pcap_free_datalinks")
|
||||
pcapDatalinkValToNamePtr = mustLoad("pcap_datalink_val_to_name")
|
||||
pcapDatalinkValToDescriptionPtr = mustLoad("pcap_datalink_val_to_description")
|
||||
pcapOpenDeadPtr = mustLoad("pcap_open_dead")
|
||||
pcapNextExPtr = mustLoad("pcap_next_ex")
|
||||
pcapDatalinkPtr = mustLoad("pcap_datalink")
|
||||
pcapSetDatalinkPtr = mustLoad("pcap_set_datalink")
|
||||
pcapDatalinkNameToValPtr = mustLoad("pcap_datalink_name_to_val")
|
||||
pcapLibVersionPtr = mustLoad("pcap_lib_version")
|
||||
pcapFreealldevsPtr = mustLoad("pcap_freealldevs")
|
||||
pcapFindalldevsPtr = mustLoad("pcap_findalldevs")
|
||||
pcapSendpacketPtr = mustLoad("pcap_sendpacket")
|
||||
pcapSetdirectionPtr = mustLoad("pcap_setdirection")
|
||||
pcapSnapshotPtr = mustLoad("pcap_snapshot")
|
||||
//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
|
||||
pcapTstampTypeValToNamePtr = mightLoad("pcap_tstamp_type_val_to_name")
|
||||
pcapTstampTypeNameToValPtr = mightLoad("pcap_tstamp_type_name_to_val")
|
||||
pcapListTstampTypesPtr = mightLoad("pcap_list_tstamp_types")
|
||||
pcapFreeTstampTypesPtr = mightLoad("pcap_free_tstamp_types")
|
||||
pcapSetTstampTypePtr = mightLoad("pcap_set_tstamp_type")
|
||||
pcapGetTstampPrecisionPtr = mightLoad("pcap_get_tstamp_precision")
|
||||
pcapSetTstampPrecisionPtr = mightLoad("pcap_set_tstamp_precision")
|
||||
pcapOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_open_offline_with_tstamp_precision")
|
||||
pcapHOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_hopen_offline_with_tstamp_precision")
|
||||
pcapActivatePtr = mustLoad("pcap_activate")
|
||||
pcapCreatePtr = mustLoad("pcap_create")
|
||||
pcapSetSnaplenPtr = mustLoad("pcap_set_snaplen")
|
||||
pcapSetPromiscPtr = mustLoad("pcap_set_promisc")
|
||||
pcapSetTimeoutPtr = mustLoad("pcap_set_timeout")
|
||||
//winpcap does not support rfmon
|
||||
pcapCanSetRfmonPtr = mightLoad("pcap_can_set_rfmon")
|
||||
pcapSetRfmonPtr = mightLoad("pcap_set_rfmon")
|
||||
pcapSetBufferSizePtr = mustLoad("pcap_set_buffer_size")
|
||||
//libpcap <1.5 does not have pcap_set_immediate_mode
|
||||
pcapSetImmediateModePtr = mightLoad("pcap_set_immediate_mode")
|
||||
pcapHopenOfflinePtr = mustLoad("pcap_hopen_offline")
|
||||
|
||||
pcapLoaded = true
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h *pcapPkthdr) getSec() int64 {
|
||||
return int64(h.Ts.Sec)
|
||||
}
|
||||
|
||||
func (h *pcapPkthdr) getUsec() int64 {
|
||||
return int64(h.Ts.Usec)
|
||||
}
|
||||
|
||||
func (h *pcapPkthdr) getLen() int {
|
||||
return int(h.Len)
|
||||
}
|
||||
|
||||
func (h *pcapPkthdr) getCaplen() int {
|
||||
return int(h.Caplen)
|
||||
}
|
||||
|
||||
func statusError(status pcapCint) error {
|
||||
var ret uintptr
|
||||
if pcapStatustostrPtr == 0 {
|
||||
ret, _, _ = syscall.Syscall(pcapStrerrorPtr, 1, uintptr(status), 0, 0)
|
||||
} else {
|
||||
ret, _, _ = syscall.Syscall(pcapStatustostrPtr, 1, uintptr(status), 0, 0)
|
||||
}
|
||||
return errors.New(bytePtrToString(ret))
|
||||
}
|
||||
|
||||
func pcapGetTstampPrecision(cptr pcapTPtr) int {
|
||||
if pcapGetTstampPrecisionPtr == 0 {
|
||||
return pcapTstampPrecisionMicro
|
||||
}
|
||||
ret, _, _ := syscall.Syscall(pcapGetTstampPrecisionPtr, 1, uintptr(cptr), 0, 0)
|
||||
return int(pcapCint(ret))
|
||||
}
|
||||
|
||||
func pcapSetTstampPrecision(cptr pcapTPtr, precision int) error {
|
||||
if pcapSetTstampPrecisionPtr == 0 {
|
||||
return errors.New("Not supported")
|
||||
}
|
||||
ret, _, _ := syscall.Syscall(pcapSetTstampPrecisionPtr, 2, uintptr(cptr), uintptr(precision), 0)
|
||||
if pcapCint(ret) < 0 {
|
||||
return errors.New("Not supported")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func pcapOpenLive(device string, snaplen int, pro int, timeout int) (*Handle, error) {
|
||||
err := LoadWinPCAP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := make([]byte, errorBufferSize)
|
||||
dev, err := syscall.BytePtrFromString(device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cptr, _, _ := syscall.Syscall6(pcapOpenLivePtr, 5, uintptr(unsafe.Pointer(dev)), uintptr(snaplen), uintptr(pro), uintptr(timeout), uintptr(unsafe.Pointer(&buf[0])), 0)
|
||||
|
||||
if cptr == 0 {
|
||||
return nil, errors.New(byteSliceToString(buf))
|
||||
}
|
||||
return &Handle{cptr: pcapTPtr(cptr)}, nil
|
||||
}
|
||||
|
||||
func openOffline(file string) (handle *Handle, err error) {
|
||||
err = LoadWinPCAP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := make([]byte, errorBufferSize)
|
||||
f, err := syscall.BytePtrFromString(file)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var cptr uintptr
|
||||
if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
|
||||
cptr, _, _ = syscall.Syscall(pcapOpenOfflinePtr, 2, uintptr(unsafe.Pointer(f)), uintptr(unsafe.Pointer(&buf[0])), 0)
|
||||
} else {
|
||||
cptr, _, _ = syscall.Syscall(pcapOpenOfflineWithTstampPrecisionPtr, 3, uintptr(unsafe.Pointer(f)), uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
|
||||
}
|
||||
|
||||
if cptr == 0 {
|
||||
return nil, errors.New(byteSliceToString(buf))
|
||||
}
|
||||
|
||||
h := &Handle{cptr: pcapTPtr(cptr)}
|
||||
return h, nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapClose() {
|
||||
if p.cptr != 0 {
|
||||
_, _, _ = syscall.Syscall(pcapClosePtr, 1, uintptr(p.cptr), 0, 0)
|
||||
}
|
||||
p.cptr = 0
|
||||
}
|
||||
|
||||
func (p *Handle) pcapGeterr() error {
|
||||
ret, _, _ := syscall.Syscall(pcapGeterrPtr, 1, uintptr(p.cptr), 0, 0)
|
||||
return errors.New(bytePtrToString(ret))
|
||||
}
|
||||
|
||||
func (p *Handle) pcapStats() (*Stats, error) {
|
||||
var cstats pcapStats
|
||||
ret, _, _ := syscall.Syscall(pcapStatsPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&cstats)), 0)
|
||||
if pcapCint(ret) < 0 {
|
||||
return nil, p.pcapGeterr()
|
||||
}
|
||||
return &Stats{
|
||||
PacketsReceived: int(cstats.Recv),
|
||||
PacketsDropped: int(cstats.Drop),
|
||||
PacketsIfDropped: int(cstats.Ifdrop),
|
||||
}, nil
|
||||
}
|
||||
|
||||
// for libpcap < 1.8 pcap_compile is NOT thread-safe, so protect it.
|
||||
var pcapCompileMu sync.Mutex
|
||||
|
||||
func (p *Handle) pcapCompile(expr string, maskp uint32) (pcapBpfProgram, error) {
|
||||
var bpf pcapBpfProgram
|
||||
cexpr, err := syscall.BytePtrFromString(expr)
|
||||
if err != nil {
|
||||
return pcapBpfProgram{}, err
|
||||
}
|
||||
pcapCompileMu.Lock()
|
||||
defer pcapCompileMu.Unlock()
|
||||
res, _, _ := syscall.Syscall6(pcapCompilePtr, 5, uintptr(p.cptr), uintptr(unsafe.Pointer(&bpf)), uintptr(unsafe.Pointer(cexpr)), uintptr(1), uintptr(maskp), 0)
|
||||
if pcapCint(res) < 0 {
|
||||
return bpf, p.pcapGeterr()
|
||||
}
|
||||
return bpf, nil
|
||||
}
|
||||
|
||||
func (p pcapBpfProgram) free() {
|
||||
_, _, _ = syscall.Syscall(pcapFreecodePtr, 1, uintptr(unsafe.Pointer(&p)), 0, 0)
|
||||
}
|
||||
|
||||
func (p pcapBpfProgram) toBPFInstruction() []BPFInstruction {
|
||||
bpfInsn := (*[bpfInstructionBufferSize]pcapBpfInstruction)(unsafe.Pointer(p.Insns))[0:p.Len:p.Len]
|
||||
bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
|
||||
|
||||
for i, v := range bpfInsn {
|
||||
bpfInstruction[i].Code = v.Code
|
||||
bpfInstruction[i].Jt = v.Jt
|
||||
bpfInstruction[i].Jf = v.Jf
|
||||
bpfInstruction[i].K = v.K
|
||||
}
|
||||
return bpfInstruction
|
||||
}
|
||||
|
||||
func pcapBpfProgramFromInstructions(bpfInstructions []BPFInstruction) pcapBpfProgram {
|
||||
var bpf pcapBpfProgram
|
||||
bpf.Len = uint32(len(bpfInstructions))
|
||||
cbpfInsns, _, _ := syscall.Syscall(callocPtr, 2, uintptr(len(bpfInstructions)), uintptr(unsafe.Sizeof(bpfInstructions[0])), 0)
|
||||
gbpfInsns := (*[bpfInstructionBufferSize]pcapBpfInstruction)(unsafe.Pointer(cbpfInsns))
|
||||
|
||||
for i, v := range bpfInstructions {
|
||||
gbpfInsns[i].Code = v.Code
|
||||
gbpfInsns[i].Jt = v.Jt
|
||||
gbpfInsns[i].Jf = v.Jf
|
||||
gbpfInsns[i].K = v.K
|
||||
}
|
||||
|
||||
bpf.Insns = (*pcapBpfInstruction)(unsafe.Pointer(cbpfInsns))
|
||||
return bpf
|
||||
}
|
||||
|
||||
func pcapLookupnet(device string) (netp, maskp uint32, err error) {
|
||||
err = LoadWinPCAP()
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
|
||||
buf := make([]byte, errorBufferSize)
|
||||
dev, err := syscall.BytePtrFromString(device)
|
||||
if err != nil {
|
||||
return 0, 0, err
|
||||
}
|
||||
e, _, _ := syscall.Syscall6(pcapLookupnetPtr, 4, uintptr(unsafe.Pointer(dev)), uintptr(unsafe.Pointer(&netp)), uintptr(unsafe.Pointer(&maskp)), uintptr(unsafe.Pointer(&buf[0])), 0, 0)
|
||||
if pcapCint(e) < 0 {
|
||||
return 0, 0, errors.New(byteSliceToString(buf))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (b *BPF) pcapOfflineFilter(ci gopacket.CaptureInfo, data []byte) bool {
|
||||
var hdr pcapPkthdr
|
||||
hdr.Ts.Sec = int32(ci.Timestamp.Unix())
|
||||
hdr.Ts.Usec = int32(ci.Timestamp.Nanosecond() / 1000)
|
||||
hdr.Caplen = uint32(len(data)) // Trust actual length over ci.Length.
|
||||
hdr.Len = uint32(ci.Length)
|
||||
e, _, _ := syscall.Syscall(pcapOfflineFilterPtr, 3, uintptr(unsafe.Pointer(&b.bpf.bpf)), uintptr(unsafe.Pointer(&hdr)), uintptr(unsafe.Pointer(&data[0])))
|
||||
return e != 0
|
||||
}
|
||||
|
||||
func (p *Handle) pcapSetfilter(bpf pcapBpfProgram) error {
|
||||
e, _, _ := syscall.Syscall(pcapSetfilterPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&bpf)), 0)
|
||||
if pcapCint(e) < 0 {
|
||||
return p.pcapGeterr()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapListDatalinks() (datalinks []Datalink, err error) {
|
||||
var dltbuf *pcapCint
|
||||
ret, _, _ := syscall.Syscall(pcapListDatalinksPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&dltbuf)), 0)
|
||||
|
||||
n := int(pcapCint(ret))
|
||||
|
||||
if n < 0 {
|
||||
return nil, p.pcapGeterr()
|
||||
}
|
||||
defer syscall.Syscall(pcapFreeDatalinksPtr, 1, uintptr(unsafe.Pointer(dltbuf)), 0, 0)
|
||||
|
||||
datalinks = make([]Datalink, n)
|
||||
|
||||
dltArray := (*[1 << 28]pcapCint)(unsafe.Pointer(dltbuf))
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
datalinks[i].Name = pcapDatalinkValToName(int((*dltArray)[i]))
|
||||
datalinks[i].Description = pcapDatalinkValToDescription(int((*dltArray)[i]))
|
||||
}
|
||||
|
||||
return datalinks, nil
|
||||
}
|
||||
|
||||
func pcapOpenDead(linkType layers.LinkType, captureLength int) (*Handle, error) {
|
||||
err := LoadWinPCAP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
cptr, _, _ := syscall.Syscall(pcapOpenDeadPtr, 2, uintptr(linkType), uintptr(captureLength), 0)
|
||||
if cptr == 0 {
|
||||
return nil, errors.New("error opening dead capture")
|
||||
}
|
||||
|
||||
return &Handle{cptr: pcapTPtr(cptr)}, nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapNextPacketEx() NextError {
|
||||
r, _, _ := syscall.Syscall(pcapNextExPtr, 3, uintptr(p.cptr), uintptr(unsafe.Pointer(&p.pkthdr)), uintptr(unsafe.Pointer(&p.bufptr)))
|
||||
ret := pcapCint(r)
|
||||
// According to https://github.com/the-tcpdump-group/libpcap/blob/1131a7c26c6f4d4772e4a2beeaf7212f4dea74ac/pcap.c#L398-L406 ,
|
||||
// the return value of pcap_next_ex could be greater than 1 for success.
|
||||
// Let's just make it 1 if it comes bigger than 1.
|
||||
if ret > 1 {
|
||||
ret = 1
|
||||
}
|
||||
return NextError(ret)
|
||||
}
|
||||
|
||||
func (p *Handle) pcapDatalink() layers.LinkType {
|
||||
ret, _, _ := syscall.Syscall(pcapDatalinkPtr, 1, uintptr(p.cptr), 0, 0)
|
||||
return layers.LinkType(ret)
|
||||
}
|
||||
|
||||
func (p *Handle) pcapSetDatalink(dlt layers.LinkType) error {
|
||||
ret, _, _ := syscall.Syscall(pcapSetDatalinkPtr, 2, uintptr(p.cptr), uintptr(dlt), 0)
|
||||
if pcapCint(ret) < 0 {
|
||||
return p.pcapGeterr()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func pcapDatalinkValToName(dlt int) string {
|
||||
err := LoadWinPCAP()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ret, _, _ := syscall.Syscall(pcapDatalinkValToNamePtr, 1, uintptr(dlt), 0, 0)
|
||||
return bytePtrToString(ret)
|
||||
}
|
||||
|
||||
func pcapDatalinkValToDescription(dlt int) string {
|
||||
err := LoadWinPCAP()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ret, _, _ := syscall.Syscall(pcapDatalinkValToDescriptionPtr, 1, uintptr(dlt), 0, 0)
|
||||
return bytePtrToString(ret)
|
||||
}
|
||||
|
||||
func pcapDatalinkNameToVal(name string) int {
|
||||
err := LoadWinPCAP()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cptr, err := syscall.BytePtrFromString(name)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
ret, _, _ := syscall.Syscall(pcapDatalinkNameToValPtr, 1, uintptr(unsafe.Pointer(cptr)), 0, 0)
|
||||
return int(pcapCint(ret))
|
||||
}
|
||||
|
||||
func pcapLibVersion() string {
|
||||
err := LoadWinPCAP()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
ret, _, _ := syscall.Syscall(pcapLibVersionPtr, 0, 0, 0, 0)
|
||||
return bytePtrToString(ret)
|
||||
}
|
||||
|
||||
func (p *Handle) isOpen() bool {
|
||||
return p.cptr != 0
|
||||
}
|
||||
|
||||
type pcapDevices struct {
|
||||
all, cur *pcapIf
|
||||
}
|
||||
|
||||
func (p pcapDevices) free() {
|
||||
syscall.Syscall(pcapFreealldevsPtr, 1, uintptr(unsafe.Pointer(p.all)), 0, 0)
|
||||
}
|
||||
|
||||
func (p *pcapDevices) next() bool {
|
||||
if p.cur == nil {
|
||||
p.cur = p.all
|
||||
if p.cur == nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
if p.cur.Next == nil {
|
||||
return false
|
||||
}
|
||||
p.cur = p.cur.Next
|
||||
return true
|
||||
}
|
||||
|
||||
func (p pcapDevices) name() string {
|
||||
return bytePtrToString(uintptr(unsafe.Pointer(p.cur.Name)))
|
||||
}
|
||||
|
||||
func (p pcapDevices) description() string {
|
||||
return bytePtrToString(uintptr(unsafe.Pointer(p.cur.Description)))
|
||||
}
|
||||
|
||||
func (p pcapDevices) flags() uint32 {
|
||||
return p.cur.Flags
|
||||
}
|
||||
|
||||
type pcapAddresses struct {
|
||||
all, cur *pcapAddr
|
||||
}
|
||||
|
||||
func (p *pcapAddresses) next() bool {
|
||||
if p.cur == nil {
|
||||
p.cur = p.all
|
||||
if p.cur == nil {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
if p.cur.Next == nil {
|
||||
return false
|
||||
}
|
||||
p.cur = p.cur.Next
|
||||
return true
|
||||
}
|
||||
|
||||
func (p pcapAddresses) addr() *syscall.RawSockaddr {
|
||||
return p.cur.Addr
|
||||
}
|
||||
|
||||
func (p pcapAddresses) netmask() *syscall.RawSockaddr {
|
||||
return p.cur.Netmask
|
||||
}
|
||||
|
||||
func (p pcapAddresses) broadaddr() *syscall.RawSockaddr {
|
||||
return p.cur.Broadaddr
|
||||
}
|
||||
|
||||
func (p pcapAddresses) dstaddr() *syscall.RawSockaddr {
|
||||
return p.cur.Dstaddr
|
||||
}
|
||||
|
||||
func (p pcapDevices) addresses() pcapAddresses {
|
||||
return pcapAddresses{all: p.cur.Addresses}
|
||||
}
|
||||
|
||||
func pcapFindAllDevs() (pcapDevices, error) {
|
||||
var alldevsp pcapDevices
|
||||
err := LoadWinPCAP()
|
||||
if err != nil {
|
||||
return alldevsp, err
|
||||
}
|
||||
|
||||
buf := make([]byte, errorBufferSize)
|
||||
|
||||
ret, _, _ := syscall.Syscall(pcapFindalldevsPtr, 2, uintptr(unsafe.Pointer(&alldevsp.all)), uintptr(unsafe.Pointer(&buf[0])), 0)
|
||||
|
||||
if pcapCint(ret) < 0 {
|
||||
return pcapDevices{}, errors.New(byteSliceToString(buf))
|
||||
}
|
||||
return alldevsp, nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapSendpacket(data []byte) error {
|
||||
ret, _, _ := syscall.Syscall(pcapSendpacketPtr, 3, uintptr(p.cptr), uintptr(unsafe.Pointer(&data[0])), uintptr(len(data)))
|
||||
if pcapCint(ret) < 0 {
|
||||
return p.pcapGeterr()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapSetdirection(direction Direction) error {
|
||||
status, _, _ := syscall.Syscall(pcapSetdirectionPtr, 2, uintptr(p.cptr), uintptr(direction), 0)
|
||||
if pcapCint(status) < 0 {
|
||||
return statusError(pcapCint(status))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Handle) pcapSnapshot() int {
|
||||
ret, _, _ := syscall.Syscall(pcapSnapshotPtr, 1, uintptr(p.cptr), 0, 0)
|
||||
return int(pcapCint(ret))
|
||||
}
|
||||
|
||||
func (t TimestampSource) pcapTstampTypeValToName() string {
|
||||
err := LoadWinPCAP()
|
||||
if err != nil {
|
||||
return err.Error()
|
||||
}
|
||||
|
||||
//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
|
||||
if pcapTstampTypeValToNamePtr == 0 {
|
||||
return "pcap timestamp types not supported"
|
||||
}
|
||||
ret, _, _ := syscall.Syscall(pcapTstampTypeValToNamePtr, 1, uintptr(t), 0, 0)
|
||||
return bytePtrToString(ret)
|
||||
}
|
||||
|
||||
func pcapTstampTypeNameToVal(s string) (TimestampSource, error) {
|
||||
err := LoadWinPCAP()
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
|
||||
if pcapTstampTypeNameToValPtr == 0 {
|
||||
return 0, statusError(pcapCint(pcapError))
|
||||
}
|
||||
cs, err := syscall.BytePtrFromString(s)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
ret, _, _ := syscall.Syscall(pcapTstampTypeNameToValPtr, 1, uintptr(unsafe.Pointer(cs)), 0, 0)
|
||||
t := pcapCint(ret)
|
||||
if t < 0 {
|
||||
return 0, statusError(pcapCint(t))
|
||||
}
|
||||
return TimestampSource(t), nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapGeterr() error {
|
||||
ret, _, _ := syscall.Syscall(pcapGeterrPtr, 1, uintptr(p.cptr), 0, 0)
|
||||
return errors.New(bytePtrToString(ret))
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapActivate() (*Handle, activateError) {
|
||||
r, _, _ := syscall.Syscall(pcapActivatePtr, 1, uintptr(p.cptr), 0, 0)
|
||||
ret := activateError(pcapCint(r))
|
||||
if ret != aeNoError {
|
||||
return nil, ret
|
||||
}
|
||||
h := &Handle{
|
||||
cptr: p.cptr,
|
||||
}
|
||||
p.cptr = 0
|
||||
return h, ret
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapClose() {
|
||||
if p.cptr != 0 {
|
||||
_, _, _ = syscall.Syscall(pcapClosePtr, 1, uintptr(p.cptr), 0, 0)
|
||||
}
|
||||
p.cptr = 0
|
||||
}
|
||||
|
||||
func pcapCreate(device string) (*InactiveHandle, error) {
|
||||
err := LoadWinPCAP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := make([]byte, errorBufferSize)
|
||||
dev, err := syscall.BytePtrFromString(device)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
cptr, _, _ := syscall.Syscall(pcapCreatePtr, 2, uintptr(unsafe.Pointer(dev)), uintptr(unsafe.Pointer(&buf[0])), 0)
|
||||
if cptr == 0 {
|
||||
return nil, errors.New(byteSliceToString(buf))
|
||||
}
|
||||
return &InactiveHandle{cptr: pcapTPtr(cptr)}, nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetSnaplen(snaplen int) error {
|
||||
status, _, _ := syscall.Syscall(pcapSetSnaplenPtr, 2, uintptr(p.cptr), uintptr(snaplen), 0)
|
||||
if pcapCint(status) < 0 {
|
||||
return statusError(pcapCint(status))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetPromisc(promisc bool) error {
|
||||
var pro uintptr
|
||||
if promisc {
|
||||
pro = 1
|
||||
}
|
||||
status, _, _ := syscall.Syscall(pcapSetPromiscPtr, 2, uintptr(p.cptr), pro, 0)
|
||||
if pcapCint(status) < 0 {
|
||||
return statusError(pcapCint(status))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetTimeout(timeout time.Duration) error {
|
||||
status, _, _ := syscall.Syscall(pcapSetTimeoutPtr, 2, uintptr(p.cptr), uintptr(timeoutMillis(timeout)), 0)
|
||||
|
||||
if pcapCint(status) < 0 {
|
||||
return statusError(pcapCint(status))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapListTstampTypes() (out []TimestampSource) {
|
||||
//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
|
||||
if pcapListTstampTypesPtr == 0 {
|
||||
return
|
||||
}
|
||||
var types *pcapCint
|
||||
ret, _, _ := syscall.Syscall(pcapListTstampTypesPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&types)), 0)
|
||||
n := int(pcapCint(ret))
|
||||
if n < 0 {
|
||||
return // public interface doesn't have error :(
|
||||
}
|
||||
defer syscall.Syscall(pcapFreeTstampTypesPtr, 1, uintptr(unsafe.Pointer(types)), 0, 0)
|
||||
typesArray := (*[1 << 28]pcapCint)(unsafe.Pointer(types))
|
||||
for i := 0; i < n; i++ {
|
||||
out = append(out, TimestampSource((*typesArray)[i]))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetTstampType(t TimestampSource) error {
|
||||
//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
|
||||
if pcapSetTstampTypePtr == 0 {
|
||||
return statusError(pcapError)
|
||||
}
|
||||
status, _, _ := syscall.Syscall(pcapSetTstampTypePtr, 2, uintptr(p.cptr), uintptr(t), 0)
|
||||
if pcapCint(status) < 0 {
|
||||
return statusError(pcapCint(status))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetRfmon(monitor bool) error {
|
||||
//winpcap does not support rfmon
|
||||
if pcapCanSetRfmonPtr == 0 {
|
||||
return CannotSetRFMon
|
||||
}
|
||||
var mon uintptr
|
||||
if monitor {
|
||||
mon = 1
|
||||
}
|
||||
canset, _, _ := syscall.Syscall(pcapCanSetRfmonPtr, 1, uintptr(p.cptr), 0, 0)
|
||||
switch canset {
|
||||
case 0:
|
||||
return CannotSetRFMon
|
||||
case 1:
|
||||
// success
|
||||
default:
|
||||
return statusError(pcapCint(canset))
|
||||
}
|
||||
status, _, _ := syscall.Syscall(pcapSetRfmonPtr, 2, uintptr(p.cptr), mon, 0)
|
||||
if status != 0 {
|
||||
return statusError(pcapCint(status))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetBufferSize(bufferSize int) error {
|
||||
status, _, _ := syscall.Syscall(pcapSetBufferSizePtr, 2, uintptr(p.cptr), uintptr(bufferSize), 0)
|
||||
if pcapCint(status) < 0 {
|
||||
return statusError(pcapCint(status))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *InactiveHandle) pcapSetImmediateMode(mode bool) error {
|
||||
//libpcap <1.5 does not have pcap_set_immediate_mode
|
||||
if pcapSetImmediateModePtr == 0 {
|
||||
return statusError(pcapError)
|
||||
}
|
||||
var md uintptr
|
||||
if mode {
|
||||
md = 1
|
||||
}
|
||||
status, _, _ := syscall.Syscall(pcapSetImmediateModePtr, 2, uintptr(p.cptr), md, 0)
|
||||
if pcapCint(status) < 0 {
|
||||
return statusError(pcapCint(status))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (p *Handle) setNonBlocking() error {
|
||||
// do nothing
|
||||
return nil
|
||||
}
|
||||
|
||||
// waitForPacket waits for a packet or for the timeout to expire.
|
||||
func (p *Handle) waitForPacket() {
|
||||
// can't use select() so instead just switch goroutines
|
||||
runtime.Gosched()
|
||||
}
|
||||
|
||||
// openOfflineFile returns contents of input file as a *Handle.
|
||||
func openOfflineFile(file *os.File) (handle *Handle, err error) {
|
||||
err = LoadWinPCAP()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
buf := make([]byte, errorBufferSize)
|
||||
cf := file.Fd()
|
||||
|
||||
var cptr uintptr
|
||||
if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
|
||||
cptr, _, _ = syscall.Syscall(pcapHopenOfflinePtr, 2, cf, uintptr(unsafe.Pointer(&buf[0])), 0)
|
||||
} else {
|
||||
cptr, _, _ = syscall.Syscall(pcapHOpenOfflineWithTstampPrecisionPtr, 3, cf, uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
|
||||
}
|
||||
|
||||
if cptr == 0 {
|
||||
return nil, errors.New(byteSliceToString(buf))
|
||||
}
|
||||
return &Handle{cptr: pcapTPtr(cptr)}, nil
|
||||
}
|
BIN
vendor/github.com/google/gopacket/pcap/test_dns.pcap
generated
vendored
Normal file
BIN
vendor/github.com/google/gopacket/pcap/test_dns.pcap
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/github.com/google/gopacket/pcap/test_ethernet.pcap
generated
vendored
Normal file
BIN
vendor/github.com/google/gopacket/pcap/test_ethernet.pcap
generated
vendored
Normal file
Binary file not shown.
BIN
vendor/github.com/google/gopacket/pcap/test_loopback.pcap
generated
vendored
Normal file
BIN
vendor/github.com/google/gopacket/pcap/test_loopback.pcap
generated
vendored
Normal file
Binary file not shown.
Reference in New Issue
Block a user