1 Star 0 Fork 0

zhangjungang/beats

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
pcap.go 23.94 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835
// Copyright 2012 Google, Inc. All rights reserved.
// Copyright 2009-2011 Andreas Krennmair. All rights reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree.
package pcap
/*
#cgo linux LDFLAGS: -lpcap
#cgo freebsd LDFLAGS: -lpcap
#cgo darwin LDFLAGS: -lpcap
#cgo windows CFLAGS: -I C:/WpdPack/Include
#cgo windows,386 LDFLAGS: -L C:/WpdPack/Lib -lwpcap
#cgo windows,amd64 LDFLAGS: -L C:/WpdPack/Lib/x64 -lwpcap
#include <stdlib.h>
#include <pcap.h>
// Some old versions of pcap don't define this constant.
#ifndef PCAP_NETMASK_UNKNOWN
#define PCAP_NETMASK_UNKNOWN 0xffffffff
#endif
// libpcap doesn't actually export its version in a #define-guardable way,
// so we have to use other defined things to differentiate versions.
// We assume at least libpcap v1.1 at the moment.
// See http://upstream-tracker.org/versions/libpcap.html
#ifndef PCAP_ERROR_TSTAMP_PRECISION_NOTSUP // < v1.5
int pcap_set_immediate_mode(pcap_t *p, int mode) {
return PCAP_ERROR;
}
#ifndef PCAP_TSTAMP_HOST // < v1.2
int pcap_set_tstamp_type(pcap_t* p, int t) { return -1; }
int pcap_list_tstamp_types(pcap_t* p, int** t) { return 0; }
void pcap_free_tstamp_types(int *tstamp_types) {}
const char* pcap_tstamp_type_val_to_name(int t) {
return "pcap timestamp types not supported";
}
int pcap_tstamp_type_name_to_val(const char* t) {
return PCAP_ERROR;
}
#endif // < v1.2
#endif // < v1.5
#ifndef PCAP_ERROR_PROMISC_PERM_DENIED
#define PCAP_ERROR_PROMISC_PERM_DENIED -11
#endif
// WinPcap doesn't export a pcap_statustostr, so use the less-specific
// pcap_strerror. Note that linking against something like cygwin libpcap
// may result is less-specific error messages.
#ifdef WIN32
#define pcap_statustostr pcap_strerror
// WinPcap also doesn't export pcap_can_set_rfmon and pcap_set_rfmon,
// as those are handled by separate libraries (airpcap).
// https://www.winpcap.org/docs/docs_412/html/group__wpcapfunc.html
// Stub out those functions here, returning values that indicate rfmon
// setting is unavailable/unsuccessful.
int pcap_can_set_rfmon(pcap_t *p) {
return 0;
}
int pcap_set_rfmon(pcap_t *p, int rfmon) {
return PCAP_ERROR;
}
#endif
// Windows, Macs, and Linux all use different time types. Joy.
#ifdef WIN32
#define gopacket_time_secs_t long
#define gopacket_time_usecs_t long
#elif __APPLE__
#define gopacket_time_secs_t __darwin_time_t
#define gopacket_time_usecs_t __darwin_suseconds_t
#elif __GLIBC__
#define gopacket_time_secs_t __time_t
#define gopacket_time_usecs_t __suseconds_t
#else
#define gopacket_time_secs_t time_t
#define gopacket_time_usecs_t suseconds_t
#endif
*/
import "C"
import (
"errors"
"fmt"
"io"
"net"
"reflect"
"runtime"
"strconv"
"sync"
"syscall"
"time"
"unsafe"
"github.com/tsg/gopacket"
"github.com/tsg/gopacket/layers"
)
const errorBufferSize = 256
// Handle provides a connection to a pcap handle, allowing users to read packets
// off the wire (Next), inject packets onto the wire (Inject), and
// perform a number of other functions to affect and understand packet output.
//
// Handles are already pcap_activate'd
type Handle struct {
// cptr is the handle for the actual pcap C object.
cptr *C.pcap_t
blockForever bool
device string
mu sync.Mutex
// Since pointers to these objects are passed into a C function, if
// they're declared locally then the Go compiler thinks they may have
// escaped into C-land, so it allocates them on the heap. This causes a
// huge memory hit, so to handle that we store them here instead.
pkthdr *C.struct_pcap_pkthdr
buf_ptr *C.u_char
}
// Stats contains statistics on how many packets were handled by a pcap handle,
// and what was done with those packets.
type Stats struct {
PacketsReceived int
PacketsDropped int
PacketsIfDropped int
}
// Interface describes a single network interface on a machine.
type Interface struct {
Name string
Description string
Addresses []InterfaceAddress
// TODO: add more elements
}
// Datalink describes the datalink
type Datalink struct {
Name string
Description string
}
// InterfaceAddress describes an address associated with an Interface.
// Currently, it's IPv4/6 specific.
type InterfaceAddress struct {
IP net.IP
Netmask net.IPMask // Netmask may be nil if we were unable to retrieve it.
// TODO: add broadcast + PtP dst ?
}
// BPF is a compiled filter program, useful for offline packet matching.
type BPF struct {
orig string
bpf _Ctype_struct_bpf_program // takes a finalizer, not overriden by outsiders
}
// BlockForever, when passed into OpenLive/SetTimeout, causes it to block forever
// waiting for packets, while still returning incoming packets to userland relatively
// quickly.
const BlockForever = -time.Millisecond * 10
func timeoutMillis(timeout time.Duration) C.int {
// Flip sign if necessary. See package docs on timeout for reasoning behind this.
if timeout < 0 {
timeout *= -1
}
// Round up
if timeout != 0 && timeout < time.Millisecond {
timeout = time.Millisecond
}
return C.int(timeout / time.Millisecond)
}
// OpenLive opens a device and returns a *Handle.
// It takes as arguments the name of the device ("eth0"), the maximum size to
// read for each packet (snaplen), whether to put the interface in promiscuous
// mode, and a timeout.
//
// See the package documentation for important details regarding 'timeout'.
func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error) {
buf := (*C.char)(C.calloc(errorBufferSize, 1))
defer C.free(unsafe.Pointer(buf))
var pro C.int
if promisc {
pro = 1
}
p := &Handle{}
p.blockForever = timeout < 0
p.device = device
dev := C.CString(device)
defer C.free(unsafe.Pointer(dev))
p.cptr = C.pcap_open_live(dev, C.int(snaplen), pro, timeoutMillis(timeout), buf)
if p.cptr == nil {
return nil, errors.New(C.GoString(buf))
}
return p, nil
}
// OpenOffline opens a file and returns its contents as a *Handle.
func OpenOffline(file string) (handle *Handle, err error) {
buf := (*C.char)(C.calloc(errorBufferSize, 1))
defer C.free(unsafe.Pointer(buf))
cf := C.CString(file)
defer C.free(unsafe.Pointer(cf))
cptr := C.pcap_open_offline(cf, buf)
if cptr == nil {
return nil, errors.New(C.GoString(buf))
}
return &Handle{cptr: cptr}, nil
}
// OpenDead creates a Pcap handle without having it attached to a device
// or to a file. It is typically used when just using the pcap package
// for compiling BPF code.
func OpenDead(linktype layers.LinkType, snaplen int32) (handle *Handle, _ error) {
cptr := C.pcap_open_dead(C.int(linktype), C.int(snaplen))
if cptr == nil {
return nil, errors.New("pcap_open_dead failed")
}
return &Handle{cptr: cptr}, nil
}
// NextError is the return code from a call to Next.
type NextError int32
// NextError implements the error interface.
func (n NextError) Error() string {
switch n {
case NextErrorOk:
return "OK"
case NextErrorTimeoutExpired:
return "Timeout Expired"
case NextErrorReadError:
return "Read Error"
case NextErrorNoMorePackets:
return "No More Packets In File"
case NextErrorNotActivated:
return "Not Activated"
}
return strconv.Itoa(int(n))
}
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
)
// NextError returns the next packet read from the pcap handle, along with an error
// code associated with that packet. If the packet is read successfully, the
// returned error is nil.
func (p *Handle) ReadPacketData() (data []byte, ci gopacket.CaptureInfo, err error) {
p.mu.Lock()
err = p.getNextBufPtrLocked(&ci)
if err == nil {
data = C.GoBytes(unsafe.Pointer(p.buf_ptr), C.int(ci.CaptureLength))
}
p.mu.Unlock()
return
}
type activateError C.int
const (
aeNoError = 0
aeActivated = C.PCAP_ERROR_ACTIVATED
aePromisc = C.PCAP_WARNING_PROMISC_NOTSUP
aeNoSuchDevice = C.PCAP_ERROR_NO_SUCH_DEVICE
aeDenied = C.PCAP_ERROR_PERM_DENIED
aeNotUp = C.PCAP_ERROR_IFACE_NOT_UP
)
func (a activateError) Error() string {
switch a {
case aeNoError:
return "No Error"
case aeActivated:
return "Already Activated"
case aePromisc:
return "Cannot set as promisc"
case aeNoSuchDevice:
return "No Such Device"
case aeDenied:
return "Permission Denied"
case aeNotUp:
return "Interface Not Up"
default:
return fmt.Sprintf("unknown activated error: %d", a)
}
}
// getNextBufPtrLocked is shared code for ReadPacketData and
// ZeroCopyReadPacketData.
func (p *Handle) getNextBufPtrLocked(ci *gopacket.CaptureInfo) error {
var result NextError
for {
result = NextError(C.pcap_next_ex(p.cptr, &p.pkthdr, &p.buf_ptr))
if p.blockForever && result == NextErrorTimeoutExpired {
continue
}
break
}
if result != NextErrorOk {
if result == NextErrorNoMorePackets {
return io.EOF
} else {
return result
}
}
ci.Timestamp = time.Unix(int64(p.pkthdr.ts.tv_sec),
int64(p.pkthdr.ts.tv_usec)*1000) // convert micros to nanos
ci.CaptureLength = int(p.pkthdr.caplen)
ci.Length = int(p.pkthdr.len)
return nil
}
// 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.buf_ptr))
slice.Len = ci.CaptureLength
slice.Cap = ci.CaptureLength
}
p.mu.Unlock()
return
}
// Close closes the underlying pcap handle.
func (p *Handle) Close() {
C.pcap_close(p.cptr)
}
// Error returns the current error associated with a pcap handle (pcap_geterr).
func (p *Handle) Error() error {
return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
}
// Stats returns statistics on the underlying pcap handle.
func (p *Handle) Stats() (stat *Stats, err error) {
var cstats _Ctype_struct_pcap_stat
if -1 == C.pcap_stats(p.cptr, &cstats) {
return nil, p.Error()
}
return &Stats{
PacketsReceived: int(cstats.ps_recv),
PacketsDropped: int(cstats.ps_drop),
PacketsIfDropped: int(cstats.ps_ifdrop),
}, nil
}
// Obtains a list of all possible data link types supported for an interface.
func (p *Handle) ListDataLinks() (datalinks []Datalink, err error) {
var dlt_buf *C.int
n := int(C.pcap_list_datalinks(p.cptr, &dlt_buf))
if -1 == n {
return nil, p.Error()
}
defer C.pcap_free_datalinks(dlt_buf)
datalinks = make([]Datalink, n)
dltArray := (*[100]C.int)(unsafe.Pointer(dlt_buf))
for i := 0; i < n; i++ {
expr := C.pcap_datalink_val_to_name((*dltArray)[i])
datalinks[i].Name = C.GoString(expr)
expr = C.pcap_datalink_val_to_description((*dltArray)[i])
datalinks[i].Description = C.GoString(expr)
}
return datalinks, nil
}
// SetBPFFilter compiles and sets a BPF filter for the pcap handle.
func (p *Handle) SetBPFFilter(expr string) (err error) {
errorBuf := (*C.char)(C.calloc(errorBufferSize, 1))
defer C.free(unsafe.Pointer(errorBuf))
var netp uint32
var maskp uint32
// Only do the lookup on network interfaces.
// No device indicates we're handling a pcap file.
if len(p.device) > 0 {
dev := C.CString(p.device)
defer C.free(unsafe.Pointer(dev))
if -1 == C.pcap_lookupnet(
dev,
(*C.bpf_u_int32)(unsafe.Pointer(&netp)),
(*C.bpf_u_int32)(unsafe.Pointer(&maskp)),
errorBuf,
) {
// We can't lookup the network, but that could be because the interface
// doesn't have an IPv4.
}
}
var bpf _Ctype_struct_bpf_program
cexpr := C.CString(expr)
defer C.free(unsafe.Pointer(cexpr))
if -1 == C.pcap_compile(p.cptr, &bpf, cexpr, 1, C.bpf_u_int32(maskp)) {
return p.Error()
}
if -1 == C.pcap_setfilter(p.cptr, &bpf) {
C.pcap_freecode(&bpf)
return p.Error()
}
C.pcap_freecode(&bpf)
return 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}
cexpr := C.CString(expr)
defer C.free(unsafe.Pointer(cexpr))
if C.pcap_compile(p.cptr, &bpf.bpf, cexpr /* optimize */, 1, C.PCAP_NETMASK_UNKNOWN) != 0 {
return nil, p.Error()
}
runtime.SetFinalizer(bpf, destroyBPF)
return bpf, nil
}
func destroyBPF(bpf *BPF) {
C.pcap_freecode(&bpf.bpf)
}
// String returns the original string this BPF filter was compiled from.
func (b *BPF) String() string {
return b.orig
}
// BPF returns the compiled BPF program.
func (b *BPF) BPF() _Ctype_struct_bpf_program {
return b.bpf
}
// Matches returns true if the given packet data matches this filter.
func (b *BPF) Matches(ci gopacket.CaptureInfo, data []byte) bool {
var hdr C.struct_pcap_pkthdr
hdr.ts.tv_sec = C.gopacket_time_secs_t(ci.Timestamp.Unix())
hdr.ts.tv_usec = C.gopacket_time_usecs_t(ci.Timestamp.Nanosecond() / 1000)
hdr.caplen = C.bpf_u_int32(len(data)) // Trust actual length over ci.Length.
hdr.len = C.bpf_u_int32(ci.Length)
dataptr := (*C.u_char)(unsafe.Pointer(&data[0]))
return C.pcap_offline_filter(&b.bpf, &hdr, dataptr) != 0
}
// Version returns pcap_lib_version.
func Version() string {
return C.GoString(C.pcap_lib_version())
}
// LinkType returns pcap_datalink, as a layers.LinkType.
func (p *Handle) LinkType() layers.LinkType {
return layers.LinkType(C.pcap_datalink(p.cptr))
}
// SetLinkType calls pcap_set_datalink on the pcap handle.
func (p *Handle) SetLinkType(dlt layers.LinkType) error {
if -1 == C.pcap_set_datalink(p.cptr, C.int(dlt)) {
return p.Error()
}
return nil
}
// FindAllDevs attempts to enumerate all interfaces on the current machine.
func FindAllDevs() (ifs []Interface, err error) {
var buf *C.char
buf = (*C.char)(C.calloc(errorBufferSize, 1))
defer C.free(unsafe.Pointer(buf))
var alldevsp *C.pcap_if_t
if -1 == C.pcap_findalldevs((**C.pcap_if_t)(&alldevsp), buf) {
return nil, errors.New(C.GoString(buf))
}
defer C.pcap_freealldevs((*C.pcap_if_t)(alldevsp))
dev := alldevsp
var i uint32
for i = 0; dev != nil; dev = (*C.pcap_if_t)(dev.next) {
i++
}
ifs = make([]Interface, i)
dev = alldevsp
for j := uint32(0); dev != nil; dev = (*C.pcap_if_t)(dev.next) {
var iface Interface
iface.Name = C.GoString(dev.name)
iface.Description = C.GoString(dev.description)
iface.Addresses = findalladdresses(dev.addresses)
// TODO: add more elements
ifs[j] = iface
j++
}
return
}
func findalladdresses(addresses *_Ctype_struct_pcap_addr) (retval []InterfaceAddress) {
// TODO - make it support more than IPv4 and IPv6?
retval = make([]InterfaceAddress, 0, 1)
for curaddr := addresses; curaddr != nil; curaddr = (*_Ctype_struct_pcap_addr)(curaddr.next) {
var a InterfaceAddress
var err error
if a.IP, err = sockaddr_to_IP((*syscall.RawSockaddr)(unsafe.Pointer(curaddr.addr))); err != nil {
continue
}
if a.Netmask, err = sockaddr_to_IP((*syscall.RawSockaddr)(unsafe.Pointer(curaddr.netmask))); err != nil {
// If we got an IP address but we can't get a netmask, just return the IP
// address.
a.Netmask = nil
}
retval = append(retval, a)
}
return
}
func sockaddr_to_IP(rsa *syscall.RawSockaddr) (IP []byte, err error) {
switch rsa.Family {
case syscall.AF_INET:
pp := (*syscall.RawSockaddrInet4)(unsafe.Pointer(rsa))
IP = make([]byte, 4)
for i := 0; i < len(IP); i++ {
IP[i] = pp.Addr[i]
}
return
case syscall.AF_INET6:
pp := (*syscall.RawSockaddrInet6)(unsafe.Pointer(rsa))
IP = make([]byte, 16)
for i := 0; i < len(IP); i++ {
IP[i] = pp.Addr[i]
}
return
}
err = errors.New("Unsupported address type")
return
}
// WritePacketData calls pcap_sendpacket, injecting the given data into the pcap handle.
func (p *Handle) WritePacketData(data []byte) (err error) {
if -1 == C.pcap_sendpacket(p.cptr, (*C.u_char)(&data[0]), (C.int)(len(data))) {
err = p.Error()
}
return
}
// Direction is used by Handle.SetDirection.
type Direction uint8
const (
DirectionIn Direction = C.PCAP_D_IN
DirectionOut Direction = C.PCAP_D_OUT
DirectionInOut Direction = C.PCAP_D_INOUT
)
// SetDirection sets the direction for which packets will be captured.
func (p *Handle) SetDirection(direction Direction) error {
if direction != DirectionIn && direction != DirectionOut && direction != DirectionInOut {
return fmt.Errorf("Invalid direction: %v", direction)
}
if status := C.pcap_setdirection(p.cptr, (C.pcap_direction_t)(direction)); status < 0 {
return statusError(status)
}
return nil
}
// TimestampSource tells PCAP which type of timestamp to use for packets.
type TimestampSource C.int
// String returns the timestamp type as a human-readable string.
func (t TimestampSource) String() string {
return C.GoString(C.pcap_tstamp_type_val_to_name(C.int(t)))
}
// TimestampSourceFromString translates a string into a timestamp type, case
// insensitive.
func TimestampSourceFromString(s string) (TimestampSource, error) {
t := C.pcap_tstamp_type_name_to_val(C.CString(s))
if t < 0 {
return 0, statusError(t)
}
return TimestampSource(t), nil
}
func statusError(status C.int) error {
return errors.New(C.GoString(C.pcap_statustostr(status)))
}
// InactiveHandle allows you to call pre-pcap_activate functions on your pcap
// handle to set it up just the way you'd like.
type InactiveHandle struct {
// cptr is the handle for the actual pcap C object.
cptr *C.pcap_t
device string
blockForever bool
}
// Activate activates the handle. The current InactiveHandle becomes invalid
// and all future function calls on it will fail.
func (p *InactiveHandle) Activate() (*Handle, error) {
err := activateError(C.pcap_activate(p.cptr))
if err != aeNoError {
return nil, err
}
h := &Handle{cptr: p.cptr, device: p.device, blockForever: p.blockForever}
p.cptr = nil
return h, nil
}
// CleanUp cleans up any stuff left over from a successful or failed building
// of a handle.
func (p *InactiveHandle) CleanUp() {
if p.cptr != nil {
C.pcap_close(p.cptr)
}
}
// NewInactiveHandle creates a new InactiveHandle, which wraps an un-activated PCAP handle.
// Callers of NewInactiveHandle should immediately defer 'CleanUp', as in:
// inactive := NewInactiveHandle("eth0")
// defer inactive.CleanUp()
func NewInactiveHandle(device string) (*InactiveHandle, error) {
buf := (*C.char)(C.calloc(errorBufferSize, 1))
defer C.free(unsafe.Pointer(buf))
dev := C.CString(device)
defer C.free(unsafe.Pointer(dev))
// This copies a bunch of the pcap_open_live implementation from pcap.c:
cptr := C.pcap_create(dev, buf)
if cptr == nil {
return nil, errors.New(C.GoString(buf))
}
return &InactiveHandle{cptr: cptr, device: device}, nil
}
// SetSnapLen sets the snap length (max bytes per packet to capture).
func (p *InactiveHandle) SetSnapLen(snaplen int) error {
if status := C.pcap_set_snaplen(p.cptr, C.int(snaplen)); status < 0 {
return statusError(status)
}
return nil
}
// SetPromisc sets the handle to either be promiscuous (capture packets
// unrelated to this host) or not.
func (p *InactiveHandle) SetPromisc(promisc bool) error {
var pro C.int
if promisc {
pro = 1
}
if status := C.pcap_set_promisc(p.cptr, pro); status < 0 {
return statusError(status)
}
return nil
}
// SetTimeout sets the read timeout for the handle.
//
// See the package documentation for important details regarding 'timeout'.
func (p *InactiveHandle) SetTimeout(timeout time.Duration) error {
p.blockForever = timeout < 0
if status := C.pcap_set_timeout(p.cptr, timeoutMillis(timeout)); status < 0 {
return statusError(status)
}
return nil
}
// SupportedTimestamps returns a list of supported timstamp types for this
// handle.
func (p *InactiveHandle) SupportedTimestamps() (out []TimestampSource) {
var types *C.int
n := int(C.pcap_list_tstamp_types(p.cptr, &types))
defer C.pcap_free_tstamp_types(types)
typesArray := (*[100]C.int)(unsafe.Pointer(types))
for i := 0; i < n; i++ {
out = append(out, TimestampSource((*typesArray)[i]))
}
return
}
// SetTimestampSource sets the type of timestamp generator PCAP uses when
// attaching timestamps to packets.
func (p *InactiveHandle) SetTimestampSource(t TimestampSource) error {
if status := C.pcap_set_tstamp_type(p.cptr, C.int(t)); status < 0 {
return statusError(status)
}
return nil
}
// CannotSetRFMon is returned by SetRFMon if the handle does not allow
// setting RFMon because pcap_can_set_rfmon returns 0.
var CannotSetRFMon = errors.New("Cannot set rfmon for this handle")
// SetRFMon turns on radio monitoring mode, similar to promiscuous mode but for
// wireless networks. If this mode is enabled, the interface will not need to
// associate with an access point before it can receive traffic.
func (p *InactiveHandle) SetRFMon(monitor bool) error {
var mon C.int
if monitor {
mon = 1
}
switch canset := C.pcap_can_set_rfmon(p.cptr); canset {
case 0:
return CannotSetRFMon
case 1:
// success
default:
return statusError(canset)
}
if status := C.pcap_set_rfmon(p.cptr, mon); status != 0 {
return statusError(status)
}
return nil
}
// SetBufferSize sets the buffer size (in bytes) of the handle.
func (p *InactiveHandle) SetBufferSize(bufferSize int) error {
if status := C.pcap_set_buffer_size(p.cptr, C.int(bufferSize)); status < 0 {
return statusError(status)
}
return nil
}
// SetImmediateMode sets (or unsets) the immediate mode of the
// handle. In immediate mode, packets are delivered to the application
// as soon as they arrive. In other words, this overrides SetTimeout.
func (p *InactiveHandle) SetImmediateMode(mode bool) error {
var md C.int
if mode {
md = 1
}
if status := C.pcap_set_immediate_mode(p.cptr, md); status < 0 {
return statusError(status)
}
return nil
}
// Dumper can be used to write packet data to a file.
type Dumper struct {
h *Handle
cptr *C.pcap_dumper_t
}
// Returns a Dumper read to write packets from the given pcap
// handler in the file given as parameter.
func (h *Handle) NewDumper(file string) (dumper *Dumper, err error) {
cf := C.CString(file)
defer C.free(unsafe.Pointer(cf))
cptr, err := C.pcap_dump_open(h.cptr, cf)
if err != nil {
return
}
if cptr == nil {
return nil, fmt.Errorf("Failed to open file: %s", file)
}
return &Dumper{h: h, cptr: cptr}, nil
}
// Writes a packet to the file. The return values of ReadPacketData
// can be passed to this function as arguments.
func (d *Dumper) WritePacketData(data []byte, ci gopacket.CaptureInfo) (err error) {
var pkthdr _Ctype_struct_pcap_pkthdr
pkthdr.caplen = C.bpf_u_int32(ci.CaptureLength)
pkthdr.len = C.bpf_u_int32(ci.Length)
pkthdr.ts.tv_sec = C.gopacket_time_secs_t(ci.Timestamp.Unix())
pkthdr.ts.tv_usec = C.gopacket_time_usecs_t(ci.Timestamp.Nanosecond() / 1000)
// pcap_dump takes a u_char pointer to the dumper as first argument
dumper_ptr := (*C.u_char)(unsafe.Pointer(d.cptr))
// trick to get a pointer to the underling slice
ptr := (*C.u_char)(unsafe.Pointer(&data[0]))
_, err = C.pcap_dump(dumper_ptr, &pkthdr, ptr)
return
}
// Flushes the underling file to disk.
func (d *Dumper) Flush() (err error) {
n, err := C.pcap_dump_flush(d.cptr)
if err != nil {
return err
}
if n != 0 {
return fmt.Errorf("pcap_dump_flush failed: %d", n)
}
return
}
// Closes the underling file.
func (d *Dumper) Close() (err error) {
_, err = C.pcap_dump_close(d.cptr)
if err != nil {
return err
}
return
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/zhangjungang/beats.git
git@gitee.com:zhangjungang/beats.git
zhangjungang
beats
beats
v1.0.0-beta2

搜索帮助