github.com/gopacket/gopacket@v1.1.0/pcap/pcap_unix.go (about)

     1  // Copyright 2012 Google, Inc. All rights reserved.
     2  // Copyright 2009-2011 Andreas Krennmair. All rights reserved.
     3  //
     4  // Use of this source code is governed by a BSD-style license
     5  // that can be found in the LICENSE file in the root of the source
     6  // tree.
     7  //
     8  //go:build !windows
     9  // +build !windows
    10  
    11  package pcap
    12  
    13  import (
    14  	"errors"
    15  	"os"
    16  	"sync"
    17  	"syscall"
    18  	"time"
    19  	"unsafe"
    20  
    21  	"github.com/gopacket/gopacket"
    22  
    23  	"github.com/gopacket/gopacket/layers"
    24  )
    25  
    26  /*
    27  #cgo solaris LDFLAGS: -L /opt/local/lib -lpcap
    28  #cgo linux LDFLAGS: -lpcap
    29  #cgo dragonfly LDFLAGS: -lpcap
    30  #cgo freebsd LDFLAGS: -lpcap
    31  #cgo openbsd LDFLAGS: -lpcap
    32  #cgo netbsd LDFLAGS: -lpcap
    33  #cgo darwin LDFLAGS: -lpcap
    34  #include <stdlib.h>
    35  #include <pcap.h>
    36  #include <stdint.h>
    37  #include <poll.h>
    38  
    39  // Some old versions of pcap don't define this constant.
    40  #ifndef PCAP_NETMASK_UNKNOWN
    41  #define PCAP_NETMASK_UNKNOWN 0xffffffff
    42  #endif
    43  
    44  // libpcap doesn't actually export its version in a #define-guardable way,
    45  // so we have to use other defined things to differentiate versions.
    46  // We assume at least libpcap v1.1 at the moment.
    47  // See http://upstream-tracker.org/versions/libpcap.html
    48  
    49  #ifndef PCAP_ERROR_TSTAMP_PRECISION_NOTSUP  // < v1.5
    50  #define PCAP_ERROR_TSTAMP_PRECISION_NOTSUP -12
    51  
    52  int pcap_set_immediate_mode(pcap_t *p, int mode) {
    53    return PCAP_ERROR;
    54  }
    55  
    56  //  libpcap version < v1.5 doesn't have timestamp precision (everything is microsecond)
    57  //
    58  //  This means *_tstamp_* functions and macros are missing. Therefore, we emulate these
    59  //  functions here and pretend the setting the precision works. This is actually the way
    60  //  the pcap_open_offline_with_tstamp_precision works, because it doesn't return an error
    61  //  if it was not possible to set the precision, which depends on support by the given file.
    62  //  => The rest of the functions always pretend as if they could set nano precision and
    63  //  verify the actual precision with pcap_get_tstamp_precision, which is emulated for <v1.5
    64  //  to always return micro resolution.
    65  
    66  #define PCAP_TSTAMP_PRECISION_MICRO	0
    67  #define PCAP_TSTAMP_PRECISION_NANO	1
    68  
    69  pcap_t *pcap_open_offline_with_tstamp_precision(const char *fname, u_int precision,
    70    char *errbuf) {
    71    return pcap_open_offline(fname, errbuf);
    72  }
    73  
    74  pcap_t *pcap_fopen_offline_with_tstamp_precision(FILE *fp, u_int precision,
    75    char *errbuf) {
    76    return pcap_fopen_offline(fp, errbuf);
    77  }
    78  
    79  int pcap_set_tstamp_precision(pcap_t *p, int tstamp_precision) {
    80    if (tstamp_precision == PCAP_TSTAMP_PRECISION_MICRO)
    81      return 0;
    82    return PCAP_ERROR_TSTAMP_PRECISION_NOTSUP;
    83  }
    84  
    85  int pcap_get_tstamp_precision(pcap_t *p) {
    86    return PCAP_TSTAMP_PRECISION_MICRO;
    87  }
    88  
    89  #ifndef PCAP_TSTAMP_HOST  // < v1.2
    90  
    91  int pcap_set_tstamp_type(pcap_t* p, int t) { return -1; }
    92  int pcap_list_tstamp_types(pcap_t* p, int** t) { return 0; }
    93  void pcap_free_tstamp_types(int *tstamp_types) {}
    94  const char* pcap_tstamp_type_val_to_name(int t) {
    95  	return "pcap timestamp types not supported";
    96  }
    97  int pcap_tstamp_type_name_to_val(const char* t) {
    98  	return PCAP_ERROR;
    99  }
   100  
   101  #endif  // < v1.2
   102  #endif  // < v1.5
   103  
   104  #ifndef PCAP_ERROR_PROMISC_PERM_DENIED
   105  #define PCAP_ERROR_PROMISC_PERM_DENIED -11
   106  #endif
   107  
   108  // Windows, Macs, and Linux all use different time types.  Joy.
   109  #ifdef __APPLE__
   110  #define gopacket_time_secs_t __darwin_time_t
   111  #define gopacket_time_usecs_t __darwin_suseconds_t
   112  #elif __ANDROID__
   113  #define gopacket_time_secs_t __kernel_time_t
   114  #define gopacket_time_usecs_t __kernel_suseconds_t
   115  #elif __GLIBC__
   116  #define gopacket_time_secs_t __time_t
   117  #define gopacket_time_usecs_t __suseconds_t
   118  #else  // Some form of linux/bsd/etc...
   119  #include <sys/param.h>
   120  #ifdef __OpenBSD__
   121  #define gopacket_time_secs_t u_int32_t
   122  #define gopacket_time_usecs_t u_int32_t
   123  #else
   124  #define gopacket_time_secs_t time_t
   125  #define gopacket_time_usecs_t suseconds_t
   126  #endif
   127  #endif
   128  
   129  // The things we do to avoid pointers escaping to the heap...
   130  // According to https://github.com/the-tcpdump-group/libpcap/blob/1131a7c26c6f4d4772e4a2beeaf7212f4dea74ac/pcap.c#L398-L406 ,
   131  // the return value of pcap_next_ex could be greater than 1 for success.
   132  // Let's just make it 1 if it comes bigger than 1.
   133  int pcap_next_ex_escaping(pcap_t *p, uintptr_t pkt_hdr, uintptr_t pkt_data) {
   134    int ex = pcap_next_ex(p, (struct pcap_pkthdr**)(pkt_hdr), (const u_char**)(pkt_data));
   135    if (ex > 1) {
   136      ex = 1;
   137    }
   138    return ex;
   139  }
   140  
   141  int pcap_offline_filter_escaping(struct bpf_program *fp, uintptr_t pkt_hdr, uintptr_t pkt) {
   142  	return pcap_offline_filter(fp, (struct pcap_pkthdr*)(pkt_hdr), (const u_char*)(pkt));
   143  }
   144  
   145  // pcap_wait returns when the next packet is available or the timeout expires.
   146  // Since it uses pcap_get_selectable_fd, it will not work in Windows.
   147  int pcap_wait(pcap_t *p, int msec) {
   148  	struct pollfd fds[1];
   149  	int fd;
   150  
   151  	fd = pcap_get_selectable_fd(p);
   152  	if(fd < 0) {
   153  		return fd;
   154  	}
   155  
   156  	fds[0].fd = fd;
   157  	fds[0].events = POLLIN;
   158  
   159  	if(msec != 0) {
   160  		return poll(fds, 1, msec);
   161  	}
   162  
   163  	// block indefinitely if no timeout provided
   164  	return poll(fds, 1, -1);
   165  }
   166  
   167  */
   168  import "C"
   169  
   170  const errorBufferSize = C.PCAP_ERRBUF_SIZE
   171  
   172  const (
   173  	pcapErrorNotActivated    = C.PCAP_ERROR_NOT_ACTIVATED
   174  	pcapErrorActivated       = C.PCAP_ERROR_ACTIVATED
   175  	pcapWarningPromisc       = C.PCAP_WARNING_PROMISC_NOTSUP
   176  	pcapErrorNoSuchDevice    = C.PCAP_ERROR_NO_SUCH_DEVICE
   177  	pcapErrorDenied          = C.PCAP_ERROR_PERM_DENIED
   178  	pcapErrorNotUp           = C.PCAP_ERROR_IFACE_NOT_UP
   179  	pcapWarning              = C.PCAP_WARNING
   180  	pcapError                = C.PCAP_ERROR
   181  	pcapDIN                  = C.PCAP_D_IN
   182  	pcapDOUT                 = C.PCAP_D_OUT
   183  	pcapDINOUT               = C.PCAP_D_INOUT
   184  	pcapNetmaskUnknown       = C.PCAP_NETMASK_UNKNOWN
   185  	pcapTstampPrecisionMicro = C.PCAP_TSTAMP_PRECISION_MICRO
   186  	pcapTstampPrecisionNano  = C.PCAP_TSTAMP_PRECISION_NANO
   187  )
   188  
   189  type pcapPkthdr C.struct_pcap_pkthdr
   190  type pcapTPtr *C.struct_pcap
   191  type pcapBpfProgram C.struct_bpf_program
   192  
   193  func (h *pcapPkthdr) getSec() int64 {
   194  	return int64(h.ts.tv_sec)
   195  }
   196  
   197  func (h *pcapPkthdr) getUsec() int64 {
   198  	return int64(h.ts.tv_usec)
   199  }
   200  
   201  func (h *pcapPkthdr) getLen() int {
   202  	return int(h.len)
   203  }
   204  
   205  func (h *pcapPkthdr) getCaplen() int {
   206  	return int(h.caplen)
   207  }
   208  
   209  func pcapGetTstampPrecision(cptr pcapTPtr) int {
   210  	return int(C.pcap_get_tstamp_precision(cptr))
   211  }
   212  
   213  func pcapSetTstampPrecision(cptr pcapTPtr, precision int) error {
   214  	ret := C.pcap_set_tstamp_precision(cptr, C.int(precision))
   215  	if ret < 0 {
   216  		return errors.New(C.GoString(C.pcap_geterr(cptr)))
   217  	}
   218  	return nil
   219  }
   220  
   221  func statusError(status C.int) error {
   222  	return errors.New(C.GoString(C.pcap_statustostr(status)))
   223  }
   224  
   225  func pcapOpenLive(device string, snaplen int, pro int, timeout int) (*Handle, error) {
   226  	buf := (*C.char)(C.calloc(errorBufferSize, 1))
   227  	defer C.free(unsafe.Pointer(buf))
   228  
   229  	dev := C.CString(device)
   230  	defer C.free(unsafe.Pointer(dev))
   231  
   232  	cptr := C.pcap_open_live(dev, C.int(snaplen), C.int(pro), C.int(timeout), buf)
   233  	if cptr == nil {
   234  		return nil, errors.New(C.GoString(buf))
   235  	}
   236  	return &Handle{cptr: cptr}, nil
   237  }
   238  
   239  func openOffline(file string) (handle *Handle, err error) {
   240  	buf := (*C.char)(C.calloc(errorBufferSize, 1))
   241  	defer C.free(unsafe.Pointer(buf))
   242  	cf := C.CString(file)
   243  	defer C.free(unsafe.Pointer(cf))
   244  
   245  	cptr := C.pcap_open_offline_with_tstamp_precision(cf, C.PCAP_TSTAMP_PRECISION_NANO, buf)
   246  	if cptr == nil {
   247  		return nil, errors.New(C.GoString(buf))
   248  	}
   249  	return &Handle{cptr: cptr}, nil
   250  }
   251  
   252  func (p *Handle) pcapClose() {
   253  	if p.cptr != nil {
   254  		C.pcap_close(p.cptr)
   255  	}
   256  	p.cptr = nil
   257  }
   258  
   259  func (p *Handle) pcapGeterr() error {
   260  	return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
   261  }
   262  
   263  func (p *Handle) pcapStats() (*Stats, error) {
   264  	var cstats C.struct_pcap_stat
   265  	if C.pcap_stats(p.cptr, &cstats) < 0 {
   266  		return nil, p.pcapGeterr()
   267  	}
   268  	return &Stats{
   269  		PacketsReceived:  int(cstats.ps_recv),
   270  		PacketsDropped:   int(cstats.ps_drop),
   271  		PacketsIfDropped: int(cstats.ps_ifdrop),
   272  	}, nil
   273  }
   274  
   275  // for libpcap < 1.8 pcap_compile is NOT thread-safe, so protect it.
   276  var pcapCompileMu sync.Mutex
   277  
   278  func (p *Handle) pcapCompile(expr string, maskp uint32) (pcapBpfProgram, error) {
   279  	var bpf pcapBpfProgram
   280  	cexpr := C.CString(expr)
   281  	defer C.free(unsafe.Pointer(cexpr))
   282  
   283  	pcapCompileMu.Lock()
   284  	defer pcapCompileMu.Unlock()
   285  	if C.pcap_compile(p.cptr, (*C.struct_bpf_program)(&bpf), cexpr, 1, C.bpf_u_int32(maskp)) < 0 {
   286  		return bpf, p.pcapGeterr()
   287  	}
   288  	return bpf, nil
   289  }
   290  
   291  func (p pcapBpfProgram) free() {
   292  	C.pcap_freecode((*C.struct_bpf_program)(&p))
   293  }
   294  
   295  func (p pcapBpfProgram) toBPFInstruction() []BPFInstruction {
   296  	bpfInsn := (*[bpfInstructionBufferSize]C.struct_bpf_insn)(unsafe.Pointer(p.bf_insns))[0:p.bf_len:p.bf_len]
   297  	bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
   298  
   299  	for i, v := range bpfInsn {
   300  		bpfInstruction[i].Code = uint16(v.code)
   301  		bpfInstruction[i].Jt = uint8(v.jt)
   302  		bpfInstruction[i].Jf = uint8(v.jf)
   303  		bpfInstruction[i].K = uint32(v.k)
   304  	}
   305  	return bpfInstruction
   306  }
   307  
   308  func pcapBpfProgramFromInstructions(bpfInstructions []BPFInstruction) pcapBpfProgram {
   309  	var bpf pcapBpfProgram
   310  	bpf.bf_len = C.u_int(len(bpfInstructions))
   311  	cbpfInsns := C.calloc(C.size_t(len(bpfInstructions)), C.size_t(unsafe.Sizeof(bpfInstructions[0])))
   312  	gbpfInsns := (*[bpfInstructionBufferSize]C.struct_bpf_insn)(cbpfInsns)
   313  
   314  	for i, v := range bpfInstructions {
   315  		gbpfInsns[i].code = C.u_short(v.Code)
   316  		gbpfInsns[i].jt = C.u_char(v.Jt)
   317  		gbpfInsns[i].jf = C.u_char(v.Jf)
   318  		gbpfInsns[i].k = C.bpf_u_int32(v.K)
   319  	}
   320  
   321  	bpf.bf_insns = (*C.struct_bpf_insn)(cbpfInsns)
   322  	return bpf
   323  }
   324  
   325  func pcapLookupnet(device string) (netp, maskp uint32, err error) {
   326  	errorBuf := (*C.char)(C.calloc(errorBufferSize, 1))
   327  	defer C.free(unsafe.Pointer(errorBuf))
   328  	dev := C.CString(device)
   329  	defer C.free(unsafe.Pointer(dev))
   330  	if C.pcap_lookupnet(
   331  		dev,
   332  		(*C.bpf_u_int32)(unsafe.Pointer(&netp)),
   333  		(*C.bpf_u_int32)(unsafe.Pointer(&maskp)),
   334  		errorBuf,
   335  	) < 0 {
   336  		return 0, 0, errors.New(C.GoString(errorBuf))
   337  		// We can't lookup the network, but that could be because the interface
   338  		// doesn't have an IPv4.
   339  	}
   340  	return
   341  }
   342  
   343  func (b *BPF) pcapOfflineFilter(ci gopacket.CaptureInfo, data []byte) bool {
   344  	hdr := (*C.struct_pcap_pkthdr)(&b.hdr)
   345  	hdr.ts.tv_sec = C.gopacket_time_secs_t(ci.Timestamp.Unix())
   346  	hdr.ts.tv_usec = C.gopacket_time_usecs_t(ci.Timestamp.Nanosecond() / 1000)
   347  	hdr.caplen = C.bpf_u_int32(len(data)) // Trust actual length over ci.Length.
   348  	hdr.len = C.bpf_u_int32(ci.Length)
   349  	dataptr := (*C.u_char)(unsafe.Pointer(&data[0]))
   350  	return C.pcap_offline_filter_escaping((*C.struct_bpf_program)(&b.bpf.bpf),
   351  		C.uintptr_t(uintptr(unsafe.Pointer(hdr))),
   352  		C.uintptr_t(uintptr(unsafe.Pointer(dataptr)))) != 0
   353  }
   354  
   355  func (p *Handle) pcapSetfilter(bpf pcapBpfProgram) error {
   356  	if C.pcap_setfilter(p.cptr, (*C.struct_bpf_program)(&bpf)) < 0 {
   357  		return p.pcapGeterr()
   358  	}
   359  	return nil
   360  }
   361  
   362  func (p *Handle) pcapListDatalinks() (datalinks []Datalink, err error) {
   363  	var dltbuf *C.int
   364  
   365  	n := int(C.pcap_list_datalinks(p.cptr, &dltbuf))
   366  	if n < 0 {
   367  		return nil, p.pcapGeterr()
   368  	}
   369  
   370  	defer C.pcap_free_datalinks(dltbuf)
   371  
   372  	datalinks = make([]Datalink, n)
   373  
   374  	dltArray := (*[1 << 28]C.int)(unsafe.Pointer(dltbuf))
   375  
   376  	for i := 0; i < n; i++ {
   377  		datalinks[i].Name = pcapDatalinkValToName(int((*dltArray)[i]))
   378  		datalinks[i].Description = pcapDatalinkValToDescription(int((*dltArray)[i]))
   379  	}
   380  
   381  	return datalinks, nil
   382  }
   383  
   384  func pcapOpenDead(linkType layers.LinkType, captureLength int) (*Handle, error) {
   385  	cptr := C.pcap_open_dead(C.int(linkType), C.int(captureLength))
   386  	if cptr == nil {
   387  		return nil, errors.New("error opening dead capture")
   388  	}
   389  
   390  	return &Handle{cptr: cptr}, nil
   391  }
   392  
   393  func (p *Handle) pcapNextPacketEx() NextError {
   394  	// This horrible magic allows us to pass a ptr-to-ptr to pcap_next_ex
   395  	// without causing that ptr-to-ptr to itself be allocated on the heap.
   396  	// Since Handle itself survives through the duration of the pcap_next_ex
   397  	// call, this should be perfectly safe for GC stuff, etc.
   398  
   399  	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)))))
   400  }
   401  
   402  func (p *Handle) pcapDatalink() layers.LinkType {
   403  	return layers.LinkType(C.pcap_datalink(p.cptr))
   404  }
   405  
   406  func (p *Handle) pcapSetDatalink(dlt layers.LinkType) error {
   407  	if C.pcap_set_datalink(p.cptr, C.int(dlt)) < 0 {
   408  		return p.pcapGeterr()
   409  	}
   410  	return nil
   411  }
   412  
   413  func pcapDatalinkValToName(dlt int) string {
   414  	return C.GoString(C.pcap_datalink_val_to_name(C.int(dlt)))
   415  }
   416  
   417  func pcapDatalinkValToDescription(dlt int) string {
   418  	return C.GoString(C.pcap_datalink_val_to_description(C.int(dlt)))
   419  }
   420  
   421  func pcapDatalinkNameToVal(name string) int {
   422  	cptr := C.CString(name)
   423  	defer C.free(unsafe.Pointer(cptr))
   424  	return int(C.pcap_datalink_name_to_val(cptr))
   425  }
   426  
   427  func pcapLibVersion() string {
   428  	return C.GoString(C.pcap_lib_version())
   429  }
   430  
   431  func (p *Handle) isOpen() bool {
   432  	return p.cptr != nil
   433  }
   434  
   435  type pcapDevices struct {
   436  	all, cur *C.pcap_if_t
   437  }
   438  
   439  func (p pcapDevices) free() {
   440  	C.pcap_freealldevs((*C.pcap_if_t)(p.all))
   441  }
   442  
   443  func (p *pcapDevices) next() bool {
   444  	if p.cur == nil {
   445  		p.cur = p.all
   446  		if p.cur == nil {
   447  			return false
   448  		}
   449  		return true
   450  	}
   451  	if p.cur.next == nil {
   452  		return false
   453  	}
   454  	p.cur = p.cur.next
   455  	return true
   456  }
   457  
   458  func (p pcapDevices) name() string {
   459  	return C.GoString(p.cur.name)
   460  }
   461  
   462  func (p pcapDevices) description() string {
   463  	return C.GoString(p.cur.description)
   464  }
   465  
   466  func (p pcapDevices) flags() uint32 {
   467  	return uint32(p.cur.flags)
   468  }
   469  
   470  type pcapAddresses struct {
   471  	all, cur *C.pcap_addr_t
   472  }
   473  
   474  func (p *pcapAddresses) next() bool {
   475  	if p.cur == nil {
   476  		p.cur = p.all
   477  		if p.cur == nil {
   478  			return false
   479  		}
   480  		return true
   481  	}
   482  	if p.cur.next == nil {
   483  		return false
   484  	}
   485  	p.cur = p.cur.next
   486  	return true
   487  }
   488  
   489  func (p pcapAddresses) addr() *syscall.RawSockaddr {
   490  	return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.addr))
   491  }
   492  
   493  func (p pcapAddresses) netmask() *syscall.RawSockaddr {
   494  	return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.netmask))
   495  }
   496  
   497  func (p pcapAddresses) broadaddr() *syscall.RawSockaddr {
   498  	return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.broadaddr))
   499  }
   500  
   501  func (p pcapAddresses) dstaddr() *syscall.RawSockaddr {
   502  	return (*syscall.RawSockaddr)(unsafe.Pointer(p.cur.dstaddr))
   503  }
   504  
   505  func (p pcapDevices) addresses() pcapAddresses {
   506  	return pcapAddresses{all: p.cur.addresses}
   507  }
   508  
   509  func pcapFindAllDevs() (pcapDevices, error) {
   510  	var buf *C.char
   511  	buf = (*C.char)(C.calloc(errorBufferSize, 1))
   512  	defer C.free(unsafe.Pointer(buf))
   513  	var alldevsp pcapDevices
   514  
   515  	if C.pcap_findalldevs((**C.pcap_if_t)(&alldevsp.all), buf) < 0 {
   516  		return pcapDevices{}, errors.New(C.GoString(buf))
   517  	}
   518  	return alldevsp, nil
   519  }
   520  
   521  func (p *Handle) pcapSendpacket(data []byte) error {
   522  	if C.pcap_sendpacket(p.cptr, (*C.u_char)(&data[0]), (C.int)(len(data))) < 0 {
   523  		return p.pcapGeterr()
   524  	}
   525  	return nil
   526  }
   527  
   528  func (p *Handle) pcapSetdirection(direction Direction) error {
   529  	if status := C.pcap_setdirection(p.cptr, (C.pcap_direction_t)(direction)); status < 0 {
   530  		return statusError(status)
   531  	}
   532  	return nil
   533  }
   534  
   535  func (p *Handle) pcapSnapshot() int {
   536  	return int(C.pcap_snapshot(p.cptr))
   537  }
   538  
   539  func (t TimestampSource) pcapTstampTypeValToName() string {
   540  	return C.GoString(C.pcap_tstamp_type_val_to_name(C.int(t)))
   541  }
   542  
   543  func pcapTstampTypeNameToVal(s string) (TimestampSource, error) {
   544  	cs := C.CString(s)
   545  	defer C.free(unsafe.Pointer(cs))
   546  	t := C.pcap_tstamp_type_name_to_val(cs)
   547  	if t < 0 {
   548  		return 0, statusError(t)
   549  	}
   550  	return TimestampSource(t), nil
   551  }
   552  
   553  func (p *InactiveHandle) pcapGeterr() error {
   554  	return errors.New(C.GoString(C.pcap_geterr(p.cptr)))
   555  }
   556  
   557  func (p *InactiveHandle) pcapActivate() (*Handle, activateError) {
   558  	ret := activateError(C.pcap_activate(p.cptr))
   559  	if ret != aeNoError {
   560  		return nil, ret
   561  	}
   562  	h := &Handle{
   563  		cptr: p.cptr,
   564  	}
   565  	p.cptr = nil
   566  	return h, ret
   567  }
   568  
   569  func (p *InactiveHandle) pcapClose() {
   570  	if p.cptr != nil {
   571  		C.pcap_close(p.cptr)
   572  	}
   573  }
   574  
   575  func pcapCreate(device string) (*InactiveHandle, error) {
   576  	buf := (*C.char)(C.calloc(errorBufferSize, 1))
   577  	defer C.free(unsafe.Pointer(buf))
   578  	dev := C.CString(device)
   579  	defer C.free(unsafe.Pointer(dev))
   580  
   581  	cptr := C.pcap_create(dev, buf)
   582  	if cptr == nil {
   583  		return nil, errors.New(C.GoString(buf))
   584  	}
   585  	return &InactiveHandle{cptr: cptr}, nil
   586  }
   587  
   588  func (p *InactiveHandle) pcapSetSnaplen(snaplen int) error {
   589  	if status := C.pcap_set_snaplen(p.cptr, C.int(snaplen)); status < 0 {
   590  		return statusError(status)
   591  	}
   592  	return nil
   593  }
   594  
   595  func (p *InactiveHandle) pcapSetPromisc(promisc bool) error {
   596  	var pro C.int
   597  	if promisc {
   598  		pro = 1
   599  	}
   600  	if status := C.pcap_set_promisc(p.cptr, pro); status < 0 {
   601  		return statusError(status)
   602  	}
   603  	return nil
   604  }
   605  
   606  func (p *InactiveHandle) pcapSetTimeout(timeout time.Duration) error {
   607  	if status := C.pcap_set_timeout(p.cptr, C.int(timeoutMillis(timeout))); status < 0 {
   608  		return statusError(status)
   609  	}
   610  	return nil
   611  }
   612  
   613  func (p *InactiveHandle) pcapListTstampTypes() (out []TimestampSource) {
   614  	var types *C.int
   615  	n := int(C.pcap_list_tstamp_types(p.cptr, &types))
   616  	if n < 0 {
   617  		return // public interface doesn't have error :(
   618  	}
   619  	defer C.pcap_free_tstamp_types(types)
   620  	typesArray := (*[1 << 28]C.int)(unsafe.Pointer(types))
   621  	for i := 0; i < n; i++ {
   622  		out = append(out, TimestampSource((*typesArray)[i]))
   623  	}
   624  	return
   625  }
   626  
   627  func (p *InactiveHandle) pcapSetTstampType(t TimestampSource) error {
   628  	if status := C.pcap_set_tstamp_type(p.cptr, C.int(t)); status < 0 {
   629  		return statusError(status)
   630  	}
   631  	return nil
   632  }
   633  
   634  func (p *InactiveHandle) pcapSetRfmon(monitor bool) error {
   635  	var mon C.int
   636  	if monitor {
   637  		mon = 1
   638  	}
   639  	switch canset := C.pcap_can_set_rfmon(p.cptr); canset {
   640  	case 0:
   641  		return CannotSetRFMon
   642  	case 1:
   643  		// success
   644  	default:
   645  		return statusError(canset)
   646  	}
   647  	if status := C.pcap_set_rfmon(p.cptr, mon); status != 0 {
   648  		return statusError(status)
   649  	}
   650  	return nil
   651  }
   652  
   653  func (p *InactiveHandle) pcapSetBufferSize(bufferSize int) error {
   654  	if status := C.pcap_set_buffer_size(p.cptr, C.int(bufferSize)); status < 0 {
   655  		return statusError(status)
   656  	}
   657  	return nil
   658  }
   659  
   660  func (p *InactiveHandle) pcapSetImmediateMode(mode bool) error {
   661  	var md C.int
   662  	if mode {
   663  		md = 1
   664  	}
   665  	if status := C.pcap_set_immediate_mode(p.cptr, md); status < 0 {
   666  		return statusError(status)
   667  	}
   668  	return nil
   669  }
   670  
   671  func (p *Handle) setNonBlocking() error {
   672  	buf := (*C.char)(C.calloc(errorBufferSize, 1))
   673  	defer C.free(unsafe.Pointer(buf))
   674  
   675  	// Change the device to non-blocking, we'll use pcap_wait to wait until the
   676  	// handle is ready to read.
   677  	if v := C.pcap_setnonblock(p.cptr, 1, buf); v < -1 {
   678  		return errors.New(C.GoString(buf))
   679  	}
   680  
   681  	return nil
   682  }
   683  
   684  // waitForPacket waits for a packet or for the timeout to expire.
   685  func (p *Handle) waitForPacket() {
   686  	// According to pcap_get_selectable_fd() man page, there are some cases where it will
   687  	// return a file descriptor, but a simple call of select() or poll() will not indicate
   688  	// that the descriptor is readable until a full buffer's worth of packets is received,
   689  	// so the call must have a timeout less than *or equal* to the packet buffer timeout.
   690  	// The packet buffer timeout is set to timeoutMillis(p.timeout) in pcapOpenLive(),
   691  	// so we should be fine to use it here too.
   692  	C.pcap_wait(p.cptr, C.int(timeoutMillis(p.timeout)))
   693  }
   694  
   695  // openOfflineFile returns contents of input file as a *Handle.
   696  func openOfflineFile(file *os.File) (handle *Handle, err error) {
   697  	buf := (*C.char)(C.calloc(errorBufferSize, 1))
   698  	defer C.free(unsafe.Pointer(buf))
   699  	cmode := C.CString("rb")
   700  	defer C.free(unsafe.Pointer(cmode))
   701  	cf := C.fdopen(C.int(file.Fd()), cmode)
   702  
   703  	cptr := C.pcap_fopen_offline_with_tstamp_precision(cf, C.PCAP_TSTAMP_PRECISION_NANO, buf)
   704  	if cptr == nil {
   705  		return nil, errors.New(C.GoString(buf))
   706  	}
   707  	return &Handle{cptr: cptr}, nil
   708  }