github.com/gopacket/gopacket@v1.1.0/pcap/pcap_windows.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  package pcap
     9  
    10  import (
    11  	"errors"
    12  	"fmt"
    13  	"os"
    14  	"runtime"
    15  	"sync"
    16  	"syscall"
    17  	"time"
    18  	"unsafe"
    19  
    20  	"github.com/gopacket/gopacket"
    21  	"github.com/gopacket/gopacket/layers"
    22  	"golang.org/x/sys/windows"
    23  )
    24  
    25  var pcapLoaded = false
    26  
    27  const npcapPath = "\\Npcap"
    28  
    29  func initDllPath(kernel32 syscall.Handle) {
    30  	setDllDirectory, err := syscall.GetProcAddress(kernel32, "SetDllDirectoryA")
    31  	if err != nil {
    32  		// we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
    33  		return
    34  	}
    35  	getSystemDirectory, err := syscall.GetProcAddress(kernel32, "GetSystemDirectoryA")
    36  	if err != nil {
    37  		// we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
    38  		return
    39  	}
    40  	buf := make([]byte, 4096)
    41  	r, _, _ := syscall.Syscall(getSystemDirectory, 2, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
    42  	if r == 0 || r > 4096-uintptr(len(npcapPath))-1 {
    43  		// we can't do anything since SetDllDirectoryA is missing - fall back to use first wpcap.dll we encounter
    44  		return
    45  	}
    46  	copy(buf[r:], npcapPath)
    47  	_, _, _ = syscall.Syscall(setDllDirectory, 1, uintptr(unsafe.Pointer(&buf[0])), 0, 0)
    48  	// ignore errors here - we just fallback to load wpcap.dll from default locations
    49  }
    50  
    51  // loadedDllPath will hold the full pathname of the loaded wpcap.dll after init if possible
    52  var loadedDllPath = "wpcap.dll"
    53  
    54  func initLoadedDllPath(kernel32 syscall.Handle) {
    55  	getModuleFileName, err := syscall.GetProcAddress(kernel32, "GetModuleFileNameA")
    56  	if err != nil {
    57  		// we can't get the filename of the loaded module in this case - just leave default of wpcap.dll
    58  		return
    59  	}
    60  	buf := make([]byte, 4096)
    61  	r, _, _ := syscall.Syscall(getModuleFileName, 3, uintptr(wpcapHandle), uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)))
    62  	if r == 0 {
    63  		// we can't get the filename of the loaded module in this case - just leave default of wpcap.dll
    64  		return
    65  	}
    66  	loadedDllPath = string(buf[:int(r)])
    67  }
    68  
    69  func mustLoad(fun string) uintptr {
    70  	addr, err := windows.GetProcAddress(wpcapHandle, fun)
    71  	if err != nil {
    72  		panic(fmt.Sprintf("Couldn't load function %s from %s", fun, loadedDllPath))
    73  	}
    74  	return addr
    75  }
    76  
    77  func mightLoad(fun string) uintptr {
    78  	addr, err := windows.GetProcAddress(wpcapHandle, fun)
    79  	if err != nil {
    80  		return 0
    81  	}
    82  	return addr
    83  }
    84  
    85  func byteSliceToString(bval []byte) string {
    86  	for i := range bval {
    87  		if bval[i] == 0 {
    88  			return string(bval[:i])
    89  		}
    90  	}
    91  	return string(bval[:])
    92  }
    93  
    94  // bytePtrToString returns a string copied from pointer to a null terminated byte array
    95  // WARNING: ONLY SAFE WITH IF r POINTS TO C MEMORY!
    96  // govet will complain about this function for the reason stated above
    97  func bytePtrToString(r uintptr) string {
    98  	if r == 0 {
    99  		return ""
   100  	}
   101  	bval := (*[1 << 30]byte)(unsafe.Pointer(r))
   102  	return byteSliceToString(bval[:])
   103  }
   104  
   105  var wpcapHandle windows.Handle
   106  var msvcrtHandle syscall.Handle
   107  var (
   108  	callocPtr,
   109  	pcapStrerrorPtr,
   110  	pcapStatustostrPtr,
   111  	pcapOpenLivePtr,
   112  	pcapOpenOfflinePtr,
   113  	pcapClosePtr,
   114  	pcapGeterrPtr,
   115  	pcapStatsPtr,
   116  	pcapCompilePtr,
   117  	pcapFreecodePtr,
   118  	pcapLookupnetPtr,
   119  	pcapOfflineFilterPtr,
   120  	pcapSetfilterPtr,
   121  	pcapListDatalinksPtr,
   122  	pcapFreeDatalinksPtr,
   123  	pcapDatalinkValToNamePtr,
   124  	pcapDatalinkValToDescriptionPtr,
   125  	pcapOpenDeadPtr,
   126  	pcapNextExPtr,
   127  	pcapDatalinkPtr,
   128  	pcapSetDatalinkPtr,
   129  	pcapDatalinkNameToValPtr,
   130  	pcapLibVersionPtr,
   131  	pcapFreealldevsPtr,
   132  	pcapFindalldevsPtr,
   133  	pcapSendpacketPtr,
   134  	pcapSetdirectionPtr,
   135  	pcapSnapshotPtr,
   136  	pcapTstampTypeValToNamePtr,
   137  	pcapTstampTypeNameToValPtr,
   138  	pcapListTstampTypesPtr,
   139  	pcapFreeTstampTypesPtr,
   140  	pcapSetTstampTypePtr,
   141  	pcapGetTstampPrecisionPtr,
   142  	pcapSetTstampPrecisionPtr,
   143  	pcapOpenOfflineWithTstampPrecisionPtr,
   144  	pcapHOpenOfflineWithTstampPrecisionPtr,
   145  	pcapActivatePtr,
   146  	pcapCreatePtr,
   147  	pcapSetSnaplenPtr,
   148  	pcapSetPromiscPtr,
   149  	pcapSetTimeoutPtr,
   150  	pcapCanSetRfmonPtr,
   151  	pcapSetRfmonPtr,
   152  	pcapSetBufferSizePtr,
   153  	pcapSetImmediateModePtr,
   154  	pcapHopenOfflinePtr uintptr
   155  )
   156  
   157  func init() {
   158  	LoadWinPCAP()
   159  }
   160  
   161  // LoadWinPCAP attempts to dynamically load the wpcap DLL and resolve necessary functions
   162  func LoadWinPCAP() error {
   163  	if pcapLoaded {
   164  		return nil
   165  	}
   166  
   167  	kernel32, err := syscall.LoadLibrary("kernel32.dll")
   168  	if err != nil {
   169  		return fmt.Errorf("couldn't load kernel32.dll")
   170  	}
   171  	defer syscall.FreeLibrary(kernel32)
   172  
   173  	initDllPath(kernel32)
   174  
   175  	if haveSearch, _ := syscall.GetProcAddress(kernel32, "AddDllDirectory"); haveSearch != 0 {
   176  		// if AddDllDirectory is present, we can use LOAD_LIBRARY_* stuff with LoadLibraryEx to avoid wpcap.dll hijacking
   177  		// see: https://msdn.microsoft.com/en-us/library/ff919712%28VS.85%29.aspx
   178  		const LOAD_LIBRARY_SEARCH_USER_DIRS = 0x00000400
   179  		const LOAD_LIBRARY_SEARCH_SYSTEM32 = 0x00000800
   180  		wpcapHandle, err = windows.LoadLibraryEx("wpcap.dll", 0, LOAD_LIBRARY_SEARCH_USER_DIRS|LOAD_LIBRARY_SEARCH_SYSTEM32)
   181  		if err != nil {
   182  			return fmt.Errorf("couldn't load wpcap.dll")
   183  		}
   184  	} else {
   185  		// otherwise fall back to load it with the unsafe search cause by SetDllDirectory
   186  		wpcapHandle, err = windows.LoadLibrary("wpcap.dll")
   187  		if err != nil {
   188  			return fmt.Errorf("couldn't load wpcap.dll")
   189  		}
   190  	}
   191  	initLoadedDllPath(kernel32)
   192  	msvcrtHandle, err = syscall.LoadLibrary("msvcrt.dll")
   193  	if err != nil {
   194  		return fmt.Errorf("couldn't load msvcrt.dll")
   195  	}
   196  	callocPtr, err = syscall.GetProcAddress(msvcrtHandle, "calloc")
   197  	if err != nil {
   198  		return fmt.Errorf("couldn't get calloc function")
   199  	}
   200  
   201  	pcapStrerrorPtr = mustLoad("pcap_strerror")
   202  	pcapStatustostrPtr = mightLoad("pcap_statustostr") // not available on winpcap
   203  	pcapOpenLivePtr = mustLoad("pcap_open_live")
   204  	pcapOpenOfflinePtr = mustLoad("pcap_open_offline")
   205  	pcapClosePtr = mustLoad("pcap_close")
   206  	pcapGeterrPtr = mustLoad("pcap_geterr")
   207  	pcapStatsPtr = mustLoad("pcap_stats")
   208  	pcapCompilePtr = mustLoad("pcap_compile")
   209  	pcapFreecodePtr = mustLoad("pcap_freecode")
   210  	pcapLookupnetPtr = mustLoad("pcap_lookupnet")
   211  	pcapOfflineFilterPtr = mustLoad("pcap_offline_filter")
   212  	pcapSetfilterPtr = mustLoad("pcap_setfilter")
   213  	pcapListDatalinksPtr = mustLoad("pcap_list_datalinks")
   214  	pcapFreeDatalinksPtr = mustLoad("pcap_free_datalinks")
   215  	pcapDatalinkValToNamePtr = mustLoad("pcap_datalink_val_to_name")
   216  	pcapDatalinkValToDescriptionPtr = mustLoad("pcap_datalink_val_to_description")
   217  	pcapOpenDeadPtr = mustLoad("pcap_open_dead")
   218  	pcapNextExPtr = mustLoad("pcap_next_ex")
   219  	pcapDatalinkPtr = mustLoad("pcap_datalink")
   220  	pcapSetDatalinkPtr = mustLoad("pcap_set_datalink")
   221  	pcapDatalinkNameToValPtr = mustLoad("pcap_datalink_name_to_val")
   222  	pcapLibVersionPtr = mustLoad("pcap_lib_version")
   223  	pcapFreealldevsPtr = mustLoad("pcap_freealldevs")
   224  	pcapFindalldevsPtr = mustLoad("pcap_findalldevs")
   225  	pcapSendpacketPtr = mustLoad("pcap_sendpacket")
   226  	pcapSetdirectionPtr = mustLoad("pcap_setdirection")
   227  	pcapSnapshotPtr = mustLoad("pcap_snapshot")
   228  	//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
   229  	pcapTstampTypeValToNamePtr = mightLoad("pcap_tstamp_type_val_to_name")
   230  	pcapTstampTypeNameToValPtr = mightLoad("pcap_tstamp_type_name_to_val")
   231  	pcapListTstampTypesPtr = mightLoad("pcap_list_tstamp_types")
   232  	pcapFreeTstampTypesPtr = mightLoad("pcap_free_tstamp_types")
   233  	pcapSetTstampTypePtr = mightLoad("pcap_set_tstamp_type")
   234  	pcapGetTstampPrecisionPtr = mightLoad("pcap_get_tstamp_precision")
   235  	pcapSetTstampPrecisionPtr = mightLoad("pcap_set_tstamp_precision")
   236  	pcapOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_open_offline_with_tstamp_precision")
   237  	pcapHOpenOfflineWithTstampPrecisionPtr = mightLoad("pcap_hopen_offline_with_tstamp_precision")
   238  	pcapActivatePtr = mustLoad("pcap_activate")
   239  	pcapCreatePtr = mustLoad("pcap_create")
   240  	pcapSetSnaplenPtr = mustLoad("pcap_set_snaplen")
   241  	pcapSetPromiscPtr = mustLoad("pcap_set_promisc")
   242  	pcapSetTimeoutPtr = mustLoad("pcap_set_timeout")
   243  	//winpcap does not support rfmon
   244  	pcapCanSetRfmonPtr = mightLoad("pcap_can_set_rfmon")
   245  	pcapSetRfmonPtr = mightLoad("pcap_set_rfmon")
   246  	pcapSetBufferSizePtr = mustLoad("pcap_set_buffer_size")
   247  	//libpcap <1.5 does not have pcap_set_immediate_mode
   248  	pcapSetImmediateModePtr = mightLoad("pcap_set_immediate_mode")
   249  	pcapHopenOfflinePtr = mustLoad("pcap_hopen_offline")
   250  
   251  	pcapLoaded = true
   252  	return nil
   253  }
   254  
   255  func (h *pcapPkthdr) getSec() int64 {
   256  	return int64(h.Ts.Sec)
   257  }
   258  
   259  func (h *pcapPkthdr) getUsec() int64 {
   260  	return int64(h.Ts.Usec)
   261  }
   262  
   263  func (h *pcapPkthdr) getLen() int {
   264  	return int(h.Len)
   265  }
   266  
   267  func (h *pcapPkthdr) getCaplen() int {
   268  	return int(h.Caplen)
   269  }
   270  
   271  func statusError(status pcapCint) error {
   272  	var ret uintptr
   273  	if pcapStatustostrPtr == 0 {
   274  		ret, _, _ = syscall.Syscall(pcapStrerrorPtr, 1, uintptr(status), 0, 0)
   275  	} else {
   276  		ret, _, _ = syscall.Syscall(pcapStatustostrPtr, 1, uintptr(status), 0, 0)
   277  	}
   278  	return errors.New(bytePtrToString(ret))
   279  }
   280  
   281  func pcapGetTstampPrecision(cptr pcapTPtr) int {
   282  	if pcapGetTstampPrecisionPtr == 0 {
   283  		return pcapTstampPrecisionMicro
   284  	}
   285  	ret, _, _ := syscall.Syscall(pcapGetTstampPrecisionPtr, 1, uintptr(cptr), 0, 0)
   286  	return int(pcapCint(ret))
   287  }
   288  
   289  func pcapSetTstampPrecision(cptr pcapTPtr, precision int) error {
   290  	if pcapSetTstampPrecisionPtr == 0 {
   291  		return errors.New("Not supported")
   292  	}
   293  	ret, _, _ := syscall.Syscall(pcapSetTstampPrecisionPtr, 2, uintptr(cptr), uintptr(precision), 0)
   294  	if pcapCint(ret) < 0 {
   295  		return errors.New("Not supported")
   296  	}
   297  	return nil
   298  }
   299  
   300  func pcapOpenLive(device string, snaplen int, pro int, timeout int) (*Handle, error) {
   301  	err := LoadWinPCAP()
   302  	if err != nil {
   303  		return nil, err
   304  	}
   305  
   306  	buf := make([]byte, errorBufferSize)
   307  	dev, err := syscall.BytePtrFromString(device)
   308  	if err != nil {
   309  		return nil, err
   310  	}
   311  
   312  	cptr, _, _ := syscall.Syscall6(pcapOpenLivePtr, 5, uintptr(unsafe.Pointer(dev)), uintptr(snaplen), uintptr(pro), uintptr(timeout), uintptr(unsafe.Pointer(&buf[0])), 0)
   313  
   314  	if cptr == 0 {
   315  		return nil, errors.New(byteSliceToString(buf))
   316  	}
   317  	return &Handle{cptr: pcapTPtr(cptr)}, nil
   318  }
   319  
   320  func openOffline(file string) (handle *Handle, err error) {
   321  	err = LoadWinPCAP()
   322  	if err != nil {
   323  		return nil, err
   324  	}
   325  
   326  	buf := make([]byte, errorBufferSize)
   327  	f, err := syscall.BytePtrFromString(file)
   328  	if err != nil {
   329  		return nil, err
   330  	}
   331  
   332  	var cptr uintptr
   333  	if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
   334  		cptr, _, _ = syscall.Syscall(pcapOpenOfflinePtr, 2, uintptr(unsafe.Pointer(f)), uintptr(unsafe.Pointer(&buf[0])), 0)
   335  	} else {
   336  		cptr, _, _ = syscall.Syscall(pcapOpenOfflineWithTstampPrecisionPtr, 3, uintptr(unsafe.Pointer(f)), uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
   337  	}
   338  
   339  	if cptr == 0 {
   340  		return nil, errors.New(byteSliceToString(buf))
   341  	}
   342  
   343  	h := &Handle{cptr: pcapTPtr(cptr)}
   344  	return h, nil
   345  }
   346  
   347  func (p *Handle) pcapClose() {
   348  	if p.cptr != 0 {
   349  		_, _, _ = syscall.Syscall(pcapClosePtr, 1, uintptr(p.cptr), 0, 0)
   350  	}
   351  	p.cptr = 0
   352  }
   353  
   354  func (p *Handle) pcapGeterr() error {
   355  	ret, _, _ := syscall.Syscall(pcapGeterrPtr, 1, uintptr(p.cptr), 0, 0)
   356  	return errors.New(bytePtrToString(ret))
   357  }
   358  
   359  func (p *Handle) pcapStats() (*Stats, error) {
   360  	var cstats pcapStats
   361  	ret, _, _ := syscall.Syscall(pcapStatsPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&cstats)), 0)
   362  	if pcapCint(ret) < 0 {
   363  		return nil, p.pcapGeterr()
   364  	}
   365  	return &Stats{
   366  		PacketsReceived:  int(cstats.Recv),
   367  		PacketsDropped:   int(cstats.Drop),
   368  		PacketsIfDropped: int(cstats.Ifdrop),
   369  	}, nil
   370  }
   371  
   372  // for libpcap < 1.8 pcap_compile is NOT thread-safe, so protect it.
   373  var pcapCompileMu sync.Mutex
   374  
   375  func (p *Handle) pcapCompile(expr string, maskp uint32) (pcapBpfProgram, error) {
   376  	var bpf pcapBpfProgram
   377  	cexpr, err := syscall.BytePtrFromString(expr)
   378  	if err != nil {
   379  		return pcapBpfProgram{}, err
   380  	}
   381  	pcapCompileMu.Lock()
   382  	defer pcapCompileMu.Unlock()
   383  	res, _, _ := syscall.Syscall6(pcapCompilePtr, 5, uintptr(p.cptr), uintptr(unsafe.Pointer(&bpf)), uintptr(unsafe.Pointer(cexpr)), uintptr(1), uintptr(maskp), 0)
   384  	if pcapCint(res) < 0 {
   385  		return bpf, p.pcapGeterr()
   386  	}
   387  	return bpf, nil
   388  }
   389  
   390  func (p pcapBpfProgram) free() {
   391  	_, _, _ = syscall.Syscall(pcapFreecodePtr, 1, uintptr(unsafe.Pointer(&p)), 0, 0)
   392  }
   393  
   394  func (p pcapBpfProgram) toBPFInstruction() []BPFInstruction {
   395  	bpfInsn := (*[bpfInstructionBufferSize]pcapBpfInstruction)(unsafe.Pointer(p.Insns))[0:p.Len:p.Len]
   396  	bpfInstruction := make([]BPFInstruction, len(bpfInsn), len(bpfInsn))
   397  
   398  	for i, v := range bpfInsn {
   399  		bpfInstruction[i].Code = v.Code
   400  		bpfInstruction[i].Jt = v.Jt
   401  		bpfInstruction[i].Jf = v.Jf
   402  		bpfInstruction[i].K = v.K
   403  	}
   404  	return bpfInstruction
   405  }
   406  
   407  func pcapBpfProgramFromInstructions(bpfInstructions []BPFInstruction) pcapBpfProgram {
   408  	var bpf pcapBpfProgram
   409  	bpf.Len = uint32(len(bpfInstructions))
   410  	cbpfInsns, _, _ := syscall.Syscall(callocPtr, 2, uintptr(len(bpfInstructions)), uintptr(unsafe.Sizeof(bpfInstructions[0])), 0)
   411  	gbpfInsns := (*[bpfInstructionBufferSize]pcapBpfInstruction)(unsafe.Pointer(cbpfInsns))
   412  
   413  	for i, v := range bpfInstructions {
   414  		gbpfInsns[i].Code = v.Code
   415  		gbpfInsns[i].Jt = v.Jt
   416  		gbpfInsns[i].Jf = v.Jf
   417  		gbpfInsns[i].K = v.K
   418  	}
   419  
   420  	bpf.Insns = (*pcapBpfInstruction)(unsafe.Pointer(cbpfInsns))
   421  	return bpf
   422  }
   423  
   424  func pcapLookupnet(device string) (netp, maskp uint32, err error) {
   425  	err = LoadWinPCAP()
   426  	if err != nil {
   427  		return 0, 0, err
   428  	}
   429  
   430  	buf := make([]byte, errorBufferSize)
   431  	dev, err := syscall.BytePtrFromString(device)
   432  	if err != nil {
   433  		return 0, 0, err
   434  	}
   435  	e, _, _ := syscall.Syscall6(pcapLookupnetPtr, 4, uintptr(unsafe.Pointer(dev)), uintptr(unsafe.Pointer(&netp)), uintptr(unsafe.Pointer(&maskp)), uintptr(unsafe.Pointer(&buf[0])), 0, 0)
   436  	if pcapCint(e) < 0 {
   437  		return 0, 0, errors.New(byteSliceToString(buf))
   438  	}
   439  	return
   440  }
   441  
   442  func (b *BPF) pcapOfflineFilter(ci gopacket.CaptureInfo, data []byte) bool {
   443  	var hdr pcapPkthdr
   444  	hdr.Ts.Sec = int32(ci.Timestamp.Unix())
   445  	hdr.Ts.Usec = int32(ci.Timestamp.Nanosecond() / 1000)
   446  	hdr.Caplen = uint32(len(data)) // Trust actual length over ci.Length.
   447  	hdr.Len = uint32(ci.Length)
   448  	e, _, _ := syscall.Syscall(pcapOfflineFilterPtr, 3, uintptr(unsafe.Pointer(&b.bpf.bpf)), uintptr(unsafe.Pointer(&hdr)), uintptr(unsafe.Pointer(&data[0])))
   449  	return e != 0
   450  }
   451  
   452  func (p *Handle) pcapSetfilter(bpf pcapBpfProgram) error {
   453  	e, _, _ := syscall.Syscall(pcapSetfilterPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&bpf)), 0)
   454  	if pcapCint(e) < 0 {
   455  		return p.pcapGeterr()
   456  	}
   457  	return nil
   458  }
   459  
   460  func (p *Handle) pcapListDatalinks() (datalinks []Datalink, err error) {
   461  	var dltbuf *pcapCint
   462  	ret, _, _ := syscall.Syscall(pcapListDatalinksPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&dltbuf)), 0)
   463  
   464  	n := int(pcapCint(ret))
   465  
   466  	if n < 0 {
   467  		return nil, p.pcapGeterr()
   468  	}
   469  	defer syscall.Syscall(pcapFreeDatalinksPtr, 1, uintptr(unsafe.Pointer(dltbuf)), 0, 0)
   470  
   471  	datalinks = make([]Datalink, n)
   472  
   473  	dltArray := (*[1 << 28]pcapCint)(unsafe.Pointer(dltbuf))
   474  
   475  	for i := 0; i < n; i++ {
   476  		datalinks[i].Name = pcapDatalinkValToName(int((*dltArray)[i]))
   477  		datalinks[i].Description = pcapDatalinkValToDescription(int((*dltArray)[i]))
   478  	}
   479  
   480  	return datalinks, nil
   481  }
   482  
   483  func pcapOpenDead(linkType layers.LinkType, captureLength int) (*Handle, error) {
   484  	err := LoadWinPCAP()
   485  	if err != nil {
   486  		return nil, err
   487  	}
   488  
   489  	cptr, _, _ := syscall.Syscall(pcapOpenDeadPtr, 2, uintptr(linkType), uintptr(captureLength), 0)
   490  	if cptr == 0 {
   491  		return nil, errors.New("error opening dead capture")
   492  	}
   493  
   494  	return &Handle{cptr: pcapTPtr(cptr)}, nil
   495  }
   496  
   497  func (p *Handle) pcapNextPacketEx() NextError {
   498  	r, _, _ := syscall.Syscall(pcapNextExPtr, 3, uintptr(p.cptr), uintptr(unsafe.Pointer(&p.pkthdr)), uintptr(unsafe.Pointer(&p.bufptr)))
   499  	ret := pcapCint(r)
   500  	// According to https://github.com/the-tcpdump-group/libpcap/blob/1131a7c26c6f4d4772e4a2beeaf7212f4dea74ac/pcap.c#L398-L406 ,
   501  	// the return value of pcap_next_ex could be greater than 1 for success.
   502  	// Let's just make it 1 if it comes bigger than 1.
   503  	if ret > 1 {
   504  		ret = 1
   505  	}
   506  	return NextError(ret)
   507  }
   508  
   509  func (p *Handle) pcapDatalink() layers.LinkType {
   510  	ret, _, _ := syscall.Syscall(pcapDatalinkPtr, 1, uintptr(p.cptr), 0, 0)
   511  	return layers.LinkType(ret)
   512  }
   513  
   514  func (p *Handle) pcapSetDatalink(dlt layers.LinkType) error {
   515  	ret, _, _ := syscall.Syscall(pcapSetDatalinkPtr, 2, uintptr(p.cptr), uintptr(dlt), 0)
   516  	if pcapCint(ret) < 0 {
   517  		return p.pcapGeterr()
   518  	}
   519  	return nil
   520  }
   521  
   522  func pcapDatalinkValToName(dlt int) string {
   523  	err := LoadWinPCAP()
   524  	if err != nil {
   525  		panic(err)
   526  	}
   527  	ret, _, _ := syscall.Syscall(pcapDatalinkValToNamePtr, 1, uintptr(dlt), 0, 0)
   528  	return bytePtrToString(ret)
   529  }
   530  
   531  func pcapDatalinkValToDescription(dlt int) string {
   532  	err := LoadWinPCAP()
   533  	if err != nil {
   534  		panic(err)
   535  	}
   536  	ret, _, _ := syscall.Syscall(pcapDatalinkValToDescriptionPtr, 1, uintptr(dlt), 0, 0)
   537  	return bytePtrToString(ret)
   538  }
   539  
   540  func pcapDatalinkNameToVal(name string) int {
   541  	err := LoadWinPCAP()
   542  	if err != nil {
   543  		panic(err)
   544  	}
   545  	cptr, err := syscall.BytePtrFromString(name)
   546  	if err != nil {
   547  		return 0
   548  	}
   549  	ret, _, _ := syscall.Syscall(pcapDatalinkNameToValPtr, 1, uintptr(unsafe.Pointer(cptr)), 0, 0)
   550  	return int(pcapCint(ret))
   551  }
   552  
   553  func pcapLibVersion() string {
   554  	err := LoadWinPCAP()
   555  	if err != nil {
   556  		panic(err)
   557  	}
   558  	ret, _, _ := syscall.Syscall(pcapLibVersionPtr, 0, 0, 0, 0)
   559  	return bytePtrToString(ret)
   560  }
   561  
   562  func (p *Handle) isOpen() bool {
   563  	return p.cptr != 0
   564  }
   565  
   566  type pcapDevices struct {
   567  	all, cur *pcapIf
   568  }
   569  
   570  func (p pcapDevices) free() {
   571  	syscall.Syscall(pcapFreealldevsPtr, 1, uintptr(unsafe.Pointer(p.all)), 0, 0)
   572  }
   573  
   574  func (p *pcapDevices) next() bool {
   575  	if p.cur == nil {
   576  		p.cur = p.all
   577  		if p.cur == nil {
   578  			return false
   579  		}
   580  		return true
   581  	}
   582  	if p.cur.Next == nil {
   583  		return false
   584  	}
   585  	p.cur = p.cur.Next
   586  	return true
   587  }
   588  
   589  func (p pcapDevices) name() string {
   590  	return bytePtrToString(uintptr(unsafe.Pointer(p.cur.Name)))
   591  }
   592  
   593  func (p pcapDevices) description() string {
   594  	return bytePtrToString(uintptr(unsafe.Pointer(p.cur.Description)))
   595  }
   596  
   597  func (p pcapDevices) flags() uint32 {
   598  	return p.cur.Flags
   599  }
   600  
   601  type pcapAddresses struct {
   602  	all, cur *pcapAddr
   603  }
   604  
   605  func (p *pcapAddresses) next() bool {
   606  	if p.cur == nil {
   607  		p.cur = p.all
   608  		if p.cur == nil {
   609  			return false
   610  		}
   611  		return true
   612  	}
   613  	if p.cur.Next == nil {
   614  		return false
   615  	}
   616  	p.cur = p.cur.Next
   617  	return true
   618  }
   619  
   620  func (p pcapAddresses) addr() *syscall.RawSockaddr {
   621  	return p.cur.Addr
   622  }
   623  
   624  func (p pcapAddresses) netmask() *syscall.RawSockaddr {
   625  	return p.cur.Netmask
   626  }
   627  
   628  func (p pcapAddresses) broadaddr() *syscall.RawSockaddr {
   629  	return p.cur.Broadaddr
   630  }
   631  
   632  func (p pcapAddresses) dstaddr() *syscall.RawSockaddr {
   633  	return p.cur.Dstaddr
   634  }
   635  
   636  func (p pcapDevices) addresses() pcapAddresses {
   637  	return pcapAddresses{all: p.cur.Addresses}
   638  }
   639  
   640  func pcapFindAllDevs() (pcapDevices, error) {
   641  	var alldevsp pcapDevices
   642  	err := LoadWinPCAP()
   643  	if err != nil {
   644  		return alldevsp, err
   645  	}
   646  
   647  	buf := make([]byte, errorBufferSize)
   648  
   649  	ret, _, _ := syscall.Syscall(pcapFindalldevsPtr, 2, uintptr(unsafe.Pointer(&alldevsp.all)), uintptr(unsafe.Pointer(&buf[0])), 0)
   650  
   651  	if pcapCint(ret) < 0 {
   652  		return pcapDevices{}, errors.New(byteSliceToString(buf))
   653  	}
   654  	return alldevsp, nil
   655  }
   656  
   657  func (p *Handle) pcapSendpacket(data []byte) error {
   658  	ret, _, _ := syscall.Syscall(pcapSendpacketPtr, 3, uintptr(p.cptr), uintptr(unsafe.Pointer(&data[0])), uintptr(len(data)))
   659  	if pcapCint(ret) < 0 {
   660  		return p.pcapGeterr()
   661  	}
   662  	return nil
   663  }
   664  
   665  func (p *Handle) pcapSetdirection(direction Direction) error {
   666  	status, _, _ := syscall.Syscall(pcapSetdirectionPtr, 2, uintptr(p.cptr), uintptr(direction), 0)
   667  	if pcapCint(status) < 0 {
   668  		return statusError(pcapCint(status))
   669  	}
   670  	return nil
   671  }
   672  
   673  func (p *Handle) pcapSnapshot() int {
   674  	ret, _, _ := syscall.Syscall(pcapSnapshotPtr, 1, uintptr(p.cptr), 0, 0)
   675  	return int(pcapCint(ret))
   676  }
   677  
   678  func (t TimestampSource) pcapTstampTypeValToName() string {
   679  	err := LoadWinPCAP()
   680  	if err != nil {
   681  		return err.Error()
   682  	}
   683  
   684  	//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
   685  	if pcapTstampTypeValToNamePtr == 0 {
   686  		return "pcap timestamp types not supported"
   687  	}
   688  	ret, _, _ := syscall.Syscall(pcapTstampTypeValToNamePtr, 1, uintptr(t), 0, 0)
   689  	return bytePtrToString(ret)
   690  }
   691  
   692  func pcapTstampTypeNameToVal(s string) (TimestampSource, error) {
   693  	err := LoadWinPCAP()
   694  	if err != nil {
   695  		return 0, err
   696  	}
   697  
   698  	//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
   699  	if pcapTstampTypeNameToValPtr == 0 {
   700  		return 0, statusError(pcapCint(pcapError))
   701  	}
   702  	cs, err := syscall.BytePtrFromString(s)
   703  	if err != nil {
   704  		return 0, err
   705  	}
   706  	ret, _, _ := syscall.Syscall(pcapTstampTypeNameToValPtr, 1, uintptr(unsafe.Pointer(cs)), 0, 0)
   707  	t := pcapCint(ret)
   708  	if t < 0 {
   709  		return 0, statusError(pcapCint(t))
   710  	}
   711  	return TimestampSource(t), nil
   712  }
   713  
   714  func (p *InactiveHandle) pcapGeterr() error {
   715  	ret, _, _ := syscall.Syscall(pcapGeterrPtr, 1, uintptr(p.cptr), 0, 0)
   716  	return errors.New(bytePtrToString(ret))
   717  }
   718  
   719  func (p *InactiveHandle) pcapActivate() (*Handle, activateError) {
   720  	r, _, _ := syscall.Syscall(pcapActivatePtr, 1, uintptr(p.cptr), 0, 0)
   721  	ret := activateError(pcapCint(r))
   722  	if ret != aeNoError {
   723  		return nil, ret
   724  	}
   725  	h := &Handle{
   726  		cptr: p.cptr,
   727  	}
   728  	p.cptr = 0
   729  	return h, ret
   730  }
   731  
   732  func (p *InactiveHandle) pcapClose() {
   733  	if p.cptr != 0 {
   734  		_, _, _ = syscall.Syscall(pcapClosePtr, 1, uintptr(p.cptr), 0, 0)
   735  	}
   736  	p.cptr = 0
   737  }
   738  
   739  func pcapCreate(device string) (*InactiveHandle, error) {
   740  	err := LoadWinPCAP()
   741  	if err != nil {
   742  		return nil, err
   743  	}
   744  
   745  	buf := make([]byte, errorBufferSize)
   746  	dev, err := syscall.BytePtrFromString(device)
   747  	if err != nil {
   748  		return nil, err
   749  	}
   750  	cptr, _, _ := syscall.Syscall(pcapCreatePtr, 2, uintptr(unsafe.Pointer(dev)), uintptr(unsafe.Pointer(&buf[0])), 0)
   751  	if cptr == 0 {
   752  		return nil, errors.New(byteSliceToString(buf))
   753  	}
   754  	return &InactiveHandle{cptr: pcapTPtr(cptr)}, nil
   755  }
   756  
   757  func (p *InactiveHandle) pcapSetSnaplen(snaplen int) error {
   758  	status, _, _ := syscall.Syscall(pcapSetSnaplenPtr, 2, uintptr(p.cptr), uintptr(snaplen), 0)
   759  	if pcapCint(status) < 0 {
   760  		return statusError(pcapCint(status))
   761  	}
   762  	return nil
   763  }
   764  
   765  func (p *InactiveHandle) pcapSetPromisc(promisc bool) error {
   766  	var pro uintptr
   767  	if promisc {
   768  		pro = 1
   769  	}
   770  	status, _, _ := syscall.Syscall(pcapSetPromiscPtr, 2, uintptr(p.cptr), pro, 0)
   771  	if pcapCint(status) < 0 {
   772  		return statusError(pcapCint(status))
   773  	}
   774  	return nil
   775  }
   776  
   777  func (p *InactiveHandle) pcapSetTimeout(timeout time.Duration) error {
   778  	status, _, _ := syscall.Syscall(pcapSetTimeoutPtr, 2, uintptr(p.cptr), uintptr(timeoutMillis(timeout)), 0)
   779  
   780  	if pcapCint(status) < 0 {
   781  		return statusError(pcapCint(status))
   782  	}
   783  	return nil
   784  }
   785  
   786  func (p *InactiveHandle) pcapListTstampTypes() (out []TimestampSource) {
   787  	//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
   788  	if pcapListTstampTypesPtr == 0 {
   789  		return
   790  	}
   791  	var types *pcapCint
   792  	ret, _, _ := syscall.Syscall(pcapListTstampTypesPtr, 2, uintptr(p.cptr), uintptr(unsafe.Pointer(&types)), 0)
   793  	n := int(pcapCint(ret))
   794  	if n < 0 {
   795  		return // public interface doesn't have error :(
   796  	}
   797  	defer syscall.Syscall(pcapFreeTstampTypesPtr, 1, uintptr(unsafe.Pointer(types)), 0, 0)
   798  	typesArray := (*[1 << 28]pcapCint)(unsafe.Pointer(types))
   799  	for i := 0; i < n; i++ {
   800  		out = append(out, TimestampSource((*typesArray)[i]))
   801  	}
   802  	return
   803  }
   804  
   805  func (p *InactiveHandle) pcapSetTstampType(t TimestampSource) error {
   806  	//libpcap <1.2 doesn't have pcap_*_tstamp_* functions
   807  	if pcapSetTstampTypePtr == 0 {
   808  		return statusError(pcapError)
   809  	}
   810  	status, _, _ := syscall.Syscall(pcapSetTstampTypePtr, 2, uintptr(p.cptr), uintptr(t), 0)
   811  	if pcapCint(status) < 0 {
   812  		return statusError(pcapCint(status))
   813  	}
   814  	return nil
   815  }
   816  
   817  func (p *InactiveHandle) pcapSetRfmon(monitor bool) error {
   818  	//winpcap does not support rfmon
   819  	if pcapCanSetRfmonPtr == 0 {
   820  		return CannotSetRFMon
   821  	}
   822  	var mon uintptr
   823  	if monitor {
   824  		mon = 1
   825  	}
   826  	canset, _, _ := syscall.Syscall(pcapCanSetRfmonPtr, 1, uintptr(p.cptr), 0, 0)
   827  	switch canset {
   828  	case 0:
   829  		return CannotSetRFMon
   830  	case 1:
   831  		// success
   832  	default:
   833  		return statusError(pcapCint(canset))
   834  	}
   835  	status, _, _ := syscall.Syscall(pcapSetRfmonPtr, 2, uintptr(p.cptr), mon, 0)
   836  	if status != 0 {
   837  		return statusError(pcapCint(status))
   838  	}
   839  	return nil
   840  }
   841  
   842  func (p *InactiveHandle) pcapSetBufferSize(bufferSize int) error {
   843  	status, _, _ := syscall.Syscall(pcapSetBufferSizePtr, 2, uintptr(p.cptr), uintptr(bufferSize), 0)
   844  	if pcapCint(status) < 0 {
   845  		return statusError(pcapCint(status))
   846  	}
   847  	return nil
   848  }
   849  
   850  func (p *InactiveHandle) pcapSetImmediateMode(mode bool) error {
   851  	//libpcap <1.5 does not have pcap_set_immediate_mode
   852  	if pcapSetImmediateModePtr == 0 {
   853  		return statusError(pcapError)
   854  	}
   855  	var md uintptr
   856  	if mode {
   857  		md = 1
   858  	}
   859  	status, _, _ := syscall.Syscall(pcapSetImmediateModePtr, 2, uintptr(p.cptr), md, 0)
   860  	if pcapCint(status) < 0 {
   861  		return statusError(pcapCint(status))
   862  	}
   863  	return nil
   864  }
   865  
   866  func (p *Handle) setNonBlocking() error {
   867  	// do nothing
   868  	return nil
   869  }
   870  
   871  // waitForPacket waits for a packet or for the timeout to expire.
   872  func (p *Handle) waitForPacket() {
   873  	// can't use select() so instead just switch goroutines
   874  	runtime.Gosched()
   875  }
   876  
   877  // openOfflineFile returns contents of input file as a *Handle.
   878  func openOfflineFile(file *os.File) (handle *Handle, err error) {
   879  	err = LoadWinPCAP()
   880  	if err != nil {
   881  		return nil, err
   882  	}
   883  
   884  	buf := make([]byte, errorBufferSize)
   885  	cf := file.Fd()
   886  
   887  	var cptr uintptr
   888  	if pcapOpenOfflineWithTstampPrecisionPtr == 0 {
   889  		cptr, _, _ = syscall.Syscall(pcapHopenOfflinePtr, 2, cf, uintptr(unsafe.Pointer(&buf[0])), 0)
   890  	} else {
   891  		cptr, _, _ = syscall.Syscall(pcapHOpenOfflineWithTstampPrecisionPtr, 3, cf, uintptr(pcapTstampPrecisionNano), uintptr(unsafe.Pointer(&buf[0])))
   892  	}
   893  
   894  	if cptr == 0 {
   895  		return nil, errors.New(byteSliceToString(buf))
   896  	}
   897  	return &Handle{cptr: pcapTPtr(cptr)}, nil
   898  }