window下无npcap驱动导致golang获取网卡失败问题
目录
window下无npcap驱动导致golang获取网卡失败问题
一、起源
使用golang语言开发了一个网络安全检测的小工具,其中抓取报文模块使用的是google的gopacket包。
开发完成后编译打包成exe可执行文件,本机可以运行,结果一切正常。安装到另一台window10的时候,结果可以运行但是报错结束了。
经过debug定位发现获取网络接口的协程不能正常工作。
二、查看pcap源码
// github.com\google\gopacket\pcap\pcap.go pcap.FindAllDevs()
// 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 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
}
加载kernel32.dll、wpcap.dll、msvcrt.dll依赖库
// LoadWinPCAP attempts to dynamically load the wpcap DLL and resolve necessary functions
func LoadWinPCAP() error {
if pcapLoaded { //默认false,已经加载直接返回nil
return nil
}
kernel32, err := syscall.LoadLibrary("kernel32.dll") //调用windows syscall API动态链接kernel32.dll
if err != nil {
return fmt.Errorf("couldn't load kernel32.dll")
}
defer syscall.FreeLibrary(kernel32)
initDllPath(kernel32) //检查dll path是否存在并init
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
}
三、查看环境
通过阅读pcap的源码,知道需要有至少kernel32.dll、wpcap.dll、msvcrt.dll依赖库才可以工作。
在window10上搜索这几个dll依赖库,发现kernel32.dll、msvcrt.dll是存在的,而且不同的应用程序也有自己的dll,搜索出来比较多。
但是wpcap.dll没有找到。
接下来考虑安装wpcap.dll,由于开发环境中安装了Wireshark抓包软件,而通过安装预置条件软件Npcap把wpcap.dll安装解压。
了解到windows X下有两种选择,一种是比较推荐的Npcap,另一种是Npcap的前身WinPcap,对于window10也有单独的Win10Pcap。
对应的官网下载链接和使用手册如下
Npcap https://nmap.org/npcap/ https://nmap.org/npcap/guide/
WinPcap https://www.winpcap.org/ https://www.winpcap.org/docs/default.htm
Win10Pcap http://www.win10pcap.org/ http://www.win10pcap.org/howto/
四、安装Npcap
Npcap本身是开源项目,后来由Nmap项目维护,笔者还发现有Npcap的OEM版本,支持更多的特性,比如静默安装等等。
https://nmap.org/npcap/
可以下载最新的安装版本,现在是Npcap 1.50 installer for Windows 7/2008R2, 8/2012, 8.1/2012R2, 10/2016, 2019 (x86 and x64)。几乎支持windowX。
如下是安装Npcap的过程。
安装完成后,我们发现C盘下多了目录C:\Program Files\Npcap,里面有一些批处理脚本和组件的安装包,然后C:\Windows\System32\Npcap目录也是新增的,有dll链接库文件。
五、运行demo程序
现在dll都是存在的,而且安装了NPF(网络数据包过滤器)。代码层面不做任何变动立即执行,发现有结果输出。
demo程序可以正常工作,问题解决。
六、获取网卡的各个源码对比
1、golang自身的net库
package main
import (
"fmt"
"net"
"time"
)
func main() {
ifcs, err := net.Interfaces()
if err != nil {
fmt.Println(err)
return
}
for k, v := range ifcs {
fmt.Printf("%d:%+v\n", k, v)
}
time.Sleep(time.Hour)
}
输出
0:{Index:4 MTU:1500 Name:本地连接* 1 HardwareAddr:5c:c5:d4:xx:xx:xx Flags:broadcast|multicast}
1:{Index:2 MTU:1500 Name:WLAN HardwareAddr:5c:c5:d4:xx:xx:xx Flags:up|broadcast|multicast}
2:{Index:1 MTU:-1 Name:Loopback Pseudo-Interface 1 HardwareAddr: Flags:up|loopback|multicast}
3:{Index:6 MTU:1280 Name:isatap.mshome.net HardwareAddr:00:00:00:00:00:00:00:e0 Flags:pointtopoint|multicast}
4:{Index:8 MTU:1280 Name:Teredo Tunneling Pseudo-Interface HardwareAddr:00:00:00:00:00:00:00:e0 Flags:up|pointtopoint|multicast}
2、google的pcap库
package main
import (
"fmt"
"time"
"github.com/google/gopacket/pcap"
)
func main() {
ifcs, err := pcap.FindAllDevs()
if err != nil {
fmt.Println(err)
return
}
for k, v := range ifcs {
fmt.Printf("%d:%+v\n", k, v)
}
time.Sleep(time.Hour)
}
输出
0:{Name:\Device\NPF_{060xxxxx-7683-xxxx-BB7F-xxxxxxxxxxxx} Description:Intel(R) Wireless-N 7260 Flags:30 Addresses:[{IP:fe80::e9ab:7a6e:32ce:6529 Netmask:ffffffffffffffff0000000000000000 Broadaddr:fe80::ffff:ffff:ffff:ffff P2P:<nil>} {IP:192.168.137.121 Netmask:00ffffff Broadaddr:255.168.137.121 P2P:<nil>}]}
1:{Name:\Device\NPF_{8BFxxxxx-F154-xxxx-8ADB-xxxxxxxxxxxx} Description:Microsoft Wi-Fi Direct Virtual Adapter Flags:46 Addresses:[{IP:fe80::413:2b2e:5d2f:887e Netmask:ffffffffffffffff0000000000000000 Broadaddr:fe80::ffff:ffff:ffff:ffff P2P:<nil>} {IP:169.254.136.126 Netmask:0000ffff Broadaddr:255.255.136.126 P2P:<nil>}]}
2:{Name:\Device\NPF_Loopback Description:Adapter for loopback traffic capture Flags:55 Addresses:[]}
3、windows扩展库
package main
import (
"fmt"
"time"
"golang.zx2c4.com/wireguard/windows/tunnel/winipcfg"
)
func main() {
ifcs, err := winipcfg.GetAdaptersAddresses(0, 0x10)
if err != nil {
fmt.Println(err)
return
}
for k, v := range ifcs {
fmt.Printf("%d:%+v\n", k, v)
}
time.Sleep(time.Hour)
}
输出
0:&{Length:448 IfIndex:4 Next:0xc00016xxxx adapterName:0xc00016xxxx FirstUnicastAddress:0xc00016xxxx FirstAnycastAddress:<nil> FirstMulticastAddress:0xc00016xxxx FirstDNSServerAddress:0xc00016xxxx dnsSuffix:0xc00016xxxx description:0xc00016xxxx friendlyName:0xc00016xxxx physicalAddress:[92 197 0 0 0 0 0 0] physicalAddressLength:6 Flags:453 MTU:1500 IfType:71 OperStatus:2 IPv6IfIndex:4 ZoneIndices:[4 4 4 4 1 1 1 1 1 1 1 1 1 1 0 1] FirstPrefix:0xc00016xxxx TransmitLinkSpeed:18446744073709551615 ReceiveLinkSpeed:18446744073709551615 FirstWINSServerAddress:<nil> FirstGatewayAddress:<nil> Ipv4Metric:5 Ipv6Metric:5 LUID:19985000000000000 DHCPv4Server:{Sockaddr:<nil> SockaddrLength:0} CompartmentID:1 NetworkGUID:{6BBxxxxx-2706-xxxx-9BBE-806xxxxxxxxx} ConnectionType:1 TunnelType:0 DHCPv6Server:{Sockaddr:<nil> SockaddrLength:0} dhcpv6ClientDUID:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] dhcpv6ClientDUIDLength:0 DHCPv6IAID:0 FirstDNSSuffix:<nil>}
1:&{Length:448 IfIndex:2 Next:0xc00016xxxx adapterName:0xc00016xxxx FirstUnicastAddress:0xc00016xxxx FirstAnycastAddress:<nil> FirstMulticastAddress:0xc00016xxxx FirstDNSServerAddress:0xc00016xxxx dnsSuffix:0xc00016xxxx description:0xc00016xxxx friendlyName:0xc00016xxxx physicalAddress:[92 197 0 0 0 0 0 0] physicalAddressLength:6 Flags:453 MTU:1500 IfType:71 OperStatus:1 IPv6IfIndex:2 ZoneIndices:[2 2 2 2 1 1 1 1 1 1 1 1 1 1 0 1] FirstPrefix:0xc00016xxxx TransmitLinkSpeed:144400000 ReceiveLinkSpeed:144400000 FirstWINSServerAddress:<nil> FirstGatewayAddress:<nil> Ipv4Metric:25 Ipv6Metric:25 LUID:19985000000000000 DHCPv4Server:{Sockaddr:0xc0001xxxxx SockaddrLength:16} CompartmentID:1 NetworkGUID:{6BBxxxxx-2706-xxxx-9BBE-806xxxxxxxxx} ConnectionType:1 TunnelType:0 DHCPv6Server:{Sockaddr:<nil> SockaddrLength:0} dhcpv6ClientDUID:[0 1 0 1 40 92 58 221 92 197 212 132 171 227 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] dhcpv6ClientDUIDLength:14 DHCPv6IAID:39634388 FirstDNSSuffix:<nil>}
2:&{Length:448 IfIndex:1 Next:0xc00016xxxx adapterName:0xc00016xxxx FirstUnicastAddress:0xc00016xxxx FirstAnycastAddress:<nil> FirstMulticastAddress:0xc00016xxxx FirstDNSServerAddress:0xc00016xxxx dnsSuffix:0xc00016xxxx description:0xc00016xxxx friendlyName:0xc00016xxxx physicalAddress:[0 0 0 0 0 0 0 0] physicalAddressLength:0 Flags:385 MTU:4294967295 IfType:24 OperStatus:1 IPv6IfIndex:1 ZoneIndices:[1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 1] FirstPrefix:0xc00016xxxx TransmitLinkSpeed:1073741824 ReceiveLinkSpeed:1073741824 FirstWINSServerAddress:<nil> FirstGatewayAddress:<nil> Ipv4Metric:50 Ipv6Metric:50 LUID:6755000000000000 DHCPv4Server:{Sockaddr:<nil> SockaddrLength:0} CompartmentID:1 NetworkGUID:{6BBxxxxx-2706-xxxx-9BBE-806xxxxxxxxx} ConnectionType:1 TunnelType:0 DHCPv6Server:{Sockaddr:<nil> SockaddrLength:0} dhcpv6ClientDUID:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] dhcpv6ClientDUIDLength:0 DHCPv6IAID:0 FirstDNSSuffix:<nil>}
3:&{Length:448 IfIndex:6 Next:0xc00016xxxx adapterName:0xc00016xxxx FirstUnicastAddress:0xc00016xxxx FirstAnycastAddress:<nil> FirstMulticastAddress:0xc00016xxxx FirstDNSServerAddress:0xc00016xxxx dnsSuffix:0xc00016xxxx description:0xc00016xxxx friendlyName:0xc00016xxxx physicalAddress:[0 0 0 0 0 0 0 0] physicalAddressLength:8 Flags:273 MTU:1280 IfType:131 OperStatus:2 IPv6IfIndex:6 ZoneIndices:[6 6 6 6 1 1 1 1 1 1 1 1 1 1 0 1] FirstPrefix:0xc00016xxxx TransmitLinkSpeed:100000 ReceiveLinkSpeed:100000 FirstWINSServerAddress:<nil> FirstGatewayAddress:<nil> Ipv4Metric:0 Ipv6Metric:50 LUID:36873000000000000 DHCPv4Server:{Sockaddr:<nil> SockaddrLength:0} CompartmentID:1 NetworkGUID:{6BBxxxxx-2706-xxxx-9BBE-806xxxxxxxxx} ConnectionType:1 TunnelType:13 DHCPv6Server:{Sockaddr:<nil> SockaddrLength:0} dhcpv6ClientDUID:[0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] dhcpv6ClientDUIDLength:0 DHCPv6IAID:0 FirstDNSSuffix:<nil>}
4:&{Length:448 IfIndex:8 Next:<nil> adapterName:0xc00016xxxx FirstUnicastAddress:0xc00016xxxx FirstAnycastAddress:<nil> FirstMulticastAddress:0xc00016xxxx FirstDNSServerAddress:<nil> dnsSuffix:0xc00016xxxx description:0xc00016xxxx friendlyName:0xc00016xxxx physicalAddress:[0 0 0 0 0 0 0 0] physicalAddressLength:8 Flags:272 MTU:1280 IfType:131 OperStatus:1 IPv6IfIndex:8 ZoneIndices:[8 8 8 8 1 1 1 1 1 1 1 1 1 1 0 1] FirstPrefix:0xc00016xxxx TransmitLinkSpeed:100000 ReceiveLinkSpeed:100000 FirstWINSServerAddress:<nil> FirstGatewayAddress:<nil> Ipv4Metric:0 Ipv6Metric:50 LUID:36873000000000000 DHCPv4Server:{Sockaddr:<nil> SockaddrLength:0} CompartmentID:1 NetworkGUID:{6BBxxxxx-2706-xxxx-9BBE-806xxxxxxxxx} ConnectionType:1 TunnelType:14 DHCPv6Server:{Sockaddr:<nil> SockaddrLength:0} dhcpv6ClientDUID:[0 1 0 1 40 92 58 221 92 197 212 132 171 227 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] dhcpv6ClientDUIDLength:14 DHCPv6IAID:268435456 FirstDNSSuffix:<nil>}