[已解决] Golang中使用Gopacket/pcap处理Windows设备名称的问题
[已解决] Golang中使用Gopacket/pcap处理Windows设备名称的问题 编辑:帖子已完全重写。
我仍然想感谢GoLangBridge创建并培育了这个社区。
我已经简化了我的代码(技术上主要是从John Leon在GopherCon 2016的演讲中借鉴了代码,并做了一个小改动,使用net包来获取接口)。
现在它只尝试打开接口并捕获一个数据包。
package main
import (
"fmt"
"log"
"net"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/pcap"
)
var (
snapshotLength int32 = 65535
promiscuous bool = false
timeout time.Duration = -1 * time.Second
err error
handle *pcap.Handle
)
func main() {
device, err := net.InterfaceByName("Ethernet")
fmt.Println(device)
// 打开设备
handle, err = pcap.OpenLive(device.Name, snapshotLength, promiscuous, timeout)
if err != nil {
log.Fatal("OpenLive Call: ", err)
}
defer handle.Close()
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
// 获取下一个数据包
packet, err := packetSource.NextPacket()
if err != nil {
log.Fatal(err)
}
fmt.Println(packet)
}
这是我的输出。 &{5 1500 Ethernet 00:d8:61:33:8e:84 up|broadcast|multicast} 2019/10/20 14:24:19 OpenLive Call: Ethernet: Error opening adapter: The system cannot find the device specified. (20) exit status 1
Go版本:1.13.3 npcap版本:0.9983(Wireshark目前与此安装配合工作正常) Windows 10
以管理员身份运行Powershell和cmd。
看起来我的问题出在npcap或Windows上,但我卡住了。有没有进一步排查此问题的建议?
更多关于[已解决] Golang中使用Gopacket/pcap处理Windows设备名称的问题的实战教程也可以访问 https://www.itying.com/category-94-b0.html
问题已解决。我保留此内容而非编辑,以防有人遇到同样的问题并搜索到此结果。考虑到我搜索时找到的信息很少,这很有可能。
问题出在我尝试使用的设备名称上。
第一个问题,我将作为bug上报,即net.Interfaces()使用显示名称作为Name属性。这可能是故意的。如果是这样,那么bug就在arpscan.go示例中(https://github.com/google/gopacket/blob/master/examples/arpscan/arpscan.go),该示例在使用pcap.OpenLive()初始化句柄时,将此属性用作设备名称。
第二个问题是,Windows是一个糟糕的操作系统,它没有提供任何方法(至少我没找到)来获取实际的接口名称。PowerShell的get-netadapter命令接近目标。
get-netadapter | where {$_.Name -eq "Ethernet"} | Select-Object -Property *
其中"Ethernet"是我关心的适配器的显示名称,它给出了:
DeviceName : \Device{13044533-0543-4AF5-9E3C-85EBBC7C04BB}
以及其他一些包含GUID的属性。
然而,这并不是我们需要的名称。
ipconfig本应提供,但毫无用处。
getmac /fo csv /v
给了我:
\Device\Tcpip_{13044533-0543-4AF5-9E3C-85EBBC7C04BB}
仍然不对。
老实说,我仍然不知道从每台Windows机器上获取实际设备名称的一致方法,但我注意到我查看过的其他一些系统的名称格式是:
\Device\NPF_{13044533-0543-4AF5-9E3C-85EBBC7C04BB}
(注意NPF_,它在我查看的这台系统上的任何地方都没有出现)
所以,在绝望中,我尝试了一下。这就是今天在我正在使用的这台电脑上对我有效的方法。
不幸的是,如果没有办法从诸如net.Interfaces()、net.InterfaceByName()或net.InterfaceByIndex()之类的东西中获取这个名称,就很难构建一个能在非为其量身定制的机器上运行的程序。
我归咎于Windows,但我希望谷歌能给我们提供绕过它的工具。
更多关于[已解决] Golang中使用Gopacket/pcap处理Windows设备名称的问题的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html
问题在于Windows设备名称的格式。在Windows上,pcap.OpenLive()需要的是npcap的设备名称格式,而不是标准的网络接口名称。
以下是修正后的代码:
package main
import (
"fmt"
"log"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/pcap"
)
var (
snapshotLength int32 = 65535
promiscuous bool = false
timeout time.Duration = -1 * time.Second
)
func main() {
// 获取所有网络设备
devices, err := pcap.FindAllDevs()
if err != nil {
log.Fatal("FindAllDevs error:", err)
}
// 查找名为"Ethernet"的设备
var deviceName string
for _, device := range devices {
if device.Name == "\\Device\\NPF_{你的设备GUID}" || device.Description == "Ethernet" {
deviceName = device.Name
fmt.Printf("Found device: %s (Description: %s)\n", device.Name, device.Description)
break
}
}
if deviceName == "" {
// 列出所有可用设备供参考
fmt.Println("Available devices:")
for _, device := range devices {
fmt.Printf("Name: %s, Description: %s\n", device.Name, device.Description)
}
log.Fatal("Device 'Ethernet' not found")
}
// 打开设备 - 使用pcap返回的设备名称
handle, err := pcap.OpenLive(deviceName, snapshotLength, promiscuous, timeout)
if err != nil {
log.Fatal("OpenLive error:", err)
}
defer handle.Close()
fmt.Printf("Successfully opened device: %s\n", deviceName)
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
// 设置超时,避免无限等待
timeoutChan := time.After(5 * time.Second)
select {
case packet := <-packetSource.Packets():
fmt.Printf("Captured packet: %v\n", packet)
case <-timeoutChan:
fmt.Println("Timeout: No packet captured within 5 seconds")
}
}
或者,更简单的版本,直接使用pcap查找设备:
package main
import (
"fmt"
"log"
"strings"
"time"
"github.com/google/gopacket"
"github.com/google/gopacket/pcap"
)
func main() {
// 获取所有设备
devices, err := pcap.FindAllDevs()
if err != nil {
log.Fatal(err)
}
// 查找包含"Ethernet"描述的接口
var targetDevice pcap.Interface
for _, device := range devices {
if strings.Contains(strings.ToLower(device.Description), "ethernet") {
targetDevice = device
break
}
}
if targetDevice.Name == "" {
log.Fatal("Ethernet device not found")
}
// 使用pcap的设备名称打开
handle, err := pcap.OpenLive(targetDevice.Name, 65535, false, -1*time.Second)
if err != nil {
log.Fatal(err)
}
defer handle.Close()
fmt.Printf("Listening on %s (%s)\n", targetDevice.Description, targetDevice.Name)
packetSource := gopacket.NewPacketSource(handle, handle.LinkType())
for packet := range packetSource.Packets() {
fmt.Println(packet)
break // 只捕获一个包
}
}
关键点:
- Windows上npcap的设备名称格式为
\Device\NPF_{GUID},不是简单的Ethernet - 使用
pcap.FindAllDevs()获取正确的设备名称 - 通过设备描述(Description)来匹配"Ethernet",然后使用返回的Name字段
运行代码前,先查看实际的设备名称:
devices, _ := pcap.FindAllDevs()
for _, d := range devices {
fmt.Printf("Name: %s, Description: %s\n", d.Name, d.Description)
}

