Go语言如何获取网卡信息

 更新时间:2025年07月08日 09:27:08   作者:苏打呀  
Go语言中net和pcap包提供网络接口信息获取函数,如Interfaces()和FindAllDevs(),通过匹配IP地址关联不同接口数据,用于网络监控与分析

net

网络接口

函数

func Interfaces() ([]Interface, error) {}
  • 返回系统网络接口的列表
func InterfaceAddrs() ([]Addr, error) {}
  • 返回一个系统单播接口地址的列表
  • 该列表无法标识关联的接口
  • 用Interfaces和Interface.Addrs获取更详细信息
func InterfaceByIndex(index int) (*Interface, error) {}
  • 返回索引对应的接口
func InterfaceByName(name string) (*Interface, error) {}
  • 返回名字对应的接口

类型

Interface

包含:索引(Index),MTU,名字(Name),硬件地址(HardwareAddr),标志位(up | broadcast | multicast)信息

Windows下的例子:

{Index:13 MTU:1500 Name:以太网 HardwareAddr:b8:85:84:bb:6a:36 Flags:up|broadcast|multicast}{Index:1 MTU:-1 Name:Loopback Pseudo-Interface 1 HardwareAddr: Flags:up|loopback|multicast}

type Interface struct {
	Index        int          // positive integer that starts at one, zero is never used
	MTU          int          // maximum transmission unit
	Name         string       // e.g., "en0", "lo0", "eth0.100"
	HardwareAddr HardwareAddr // IEEE MAC-48, EUI-48 and EUI-64 form
	Flags        Flags        // e.g., FlagUp, FlagLoopback, FlagMulticast
}
  • Addr
  • 代表一个网络端点地址

示例:

  • String():“192.0.2.1:25”, “[2001:db8::1]:80”, “127.0.0.1/8”
  • Network():“tcp”, “udp”, “ip+net”
type Addr interface {
	Network() string // name of the network (for example, "tcp", "udp", "ip+net")
	String() string  // string form of address (for example, )
}

syscall

网络接口

原本是go 1.5之前interface_windows.go下的源码,后来被移除了。

func getAdapterList() (*syscall.IpAdapterInfo, error) {
	b := make([]byte, 1000)
	l := uint32(len(b))
	a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
	err := syscall.GetAdaptersInfo(a, &l)
	if err == syscall.ERROR_BUFFER_OVERFLOW {
		b = make([]byte, l)
		a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
		err = syscall.GetAdaptersInfo(a, &l)
	}
	if err != nil {
		return nil, os.NewSyscallError("GetAdaptersInfo", err)
	}
	return a, nil
}

getAdapterList()

返回一个*syscall.IpAdapterInfo链表,通过Next指向下一个网卡。

字段名解释类型示例
Index索引uint3213
AdapterName适配器ID[]uint8{5C9384EF-DEBA-43A6-AE6A-5D10C952C481}
Description描述[]uint8Intel® Ethernet Connection (7) I219-LM
DhcpEnabledDHCP状态uint321
IpAddressListip链表syscall.IpAddrString{IpAddress:“192.168.13.31”, IpMask:“255.255.255.0”}
GatewayList网关链表syscall.IpAddrString{IpAddress:“192.168.13.1”, IpMask:“255.255.255.255”}
DhcpServerDHCP服务器链表syscall.IpAddrString{IpAddress:“192.168.13.254”, IpMask:“255.255.255.255”}
type IpAdapterInfo struct {
	Next                *IpAdapterInfo
	ComboIndex          uint32
	AdapterName         [MAX_ADAPTER_NAME_LENGTH + 4]byte
	Description         [MAX_ADAPTER_DESCRIPTION_LENGTH + 4]byte
	AddressLength       uint32
	Address             [MAX_ADAPTER_ADDRESS_LENGTH]byte
	Index               uint32
	Type                uint32
	DhcpEnabled         uint32
	CurrentIpAddress    *IpAddrString
	IpAddressList       IpAddrString
	GatewayList         IpAddrString
	DhcpServer          IpAddrString
	HaveWins            bool
	PrimaryWinsServer   IpAddrString
	SecondaryWinsServer IpAddrString
	LeaseObtained       int64
	LeaseExpires        int64
}

github.com/google/gopacket/pcap

网络接口

函数

func FindAllDevs() (ifs []Interface, err error) {}
  • 返回Interface列表

类型

  • Interface
  • 描述了机器上一个单独的网络接口
  • 包含:名字(Name),描述,标志位,地址(InterfaceAddress 列表)信息

示例:

type Interface struct {
	Name        string
	Description string
	Flags       uint32
	Addresses   []InterfaceAddress
}
type InterfaceAddress struct {
	IP        net.IP
	Netmask   net.IPMask // Netmask may be nil if we were unable to retrieve it.
	Broadaddr net.IP     // Broadcast address for this IP may be nil
	P2P       net.IP     // P2P destination address for this IP may be nil
}

处理网络流

函数

func OpenLive(device string, snaplen int32, promisc bool, timeout time.Duration) (handle *Handle, _ error) {}
func OpenOffline(file string) (handle *Handle, err error) {}
func OpenOfflineFile(file *os.File) (handle *Handle, err error) {}

获取网卡信息的各种方法测试

package main

import (
	"fmt"
	"github.com/google/gopacket/pcap"
	"log"
	"net"
	"os"
	"syscall"
	"unsafe"
)

func getAdapterList() (*syscall.IpAdapterInfo, error) {
	b := make([]byte, 1000)
	l := uint32(len(b))
	a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
	err := syscall.GetAdaptersInfo(a, &l)
	if err == syscall.ERROR_BUFFER_OVERFLOW {
		b = make([]byte, l)
		a = (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
		err = syscall.GetAdaptersInfo(a, &l)
	}
	if err != nil {
		return nil, os.NewSyscallError("GetAdaptersInfo", err)
	}
	return a, nil
}

func localAddresses() error {
	fmt.Println("测试net.Interfaces()\n")
	ifaces, err := net.Interfaces()
	if err != nil {
		return err
	}
	for _, iface := range ifaces {
		fmt.Printf("%+v\n", iface)
	}
	fmt.Println()

	fmt.Println("测试net.InterfaceAddrs()")
	addrs, err := net.InterfaceAddrs()
	if err != nil {
		return err
	}
	for _, addr := range addrs {
		fmt.Printf("\n%+v\n", addr.String())
		fmt.Printf("%+v\n", addr.Network())
	}
	fmt.Println()
	//net.InterfaceByIndex()
	//net.InterfaceByName()
	//for _, addr := range addrs {
	//	fmt.Printf("%T", addr)
	//	// 这个网络地址是IP地址: ipv4, ipv6
	//	ipNet1, isIpNet1 := addr.(*net.IPNet)
	//	fmt.Println(ipNet1)
	//	fmt.Println(isIpNet1)
	//	if ipNet, isIpNet := addr.(*net.IPNet); isIpNet && !ipNet.IP.IsLoopback() {
	//		// 跳过IPV6
	//		if ipNet.IP.To4() != nil {
	//			ipv4 := ipNet.IP.String() // 192.168.1.1
	//			fmt.Println(ipv4)
	//		}
	//	}
	//}

	fmt.Println("测试基于syscall的getAdapterList()")
	aList, err := getAdapterList()
	if err != nil {
		return err
	}
	for ai := aList; ai != nil; ai = ai.Next {
		fmt.Printf("\nIndex:\t%v\n", ai.Index)
		fmt.Printf("AdapterName:\t%s\n", &ai.AdapterName)
		fmt.Printf("Description:\t%s\n", &ai.Description)
		fmt.Printf("Address:\t%s\n", &ai.Address)
		ipl := &ai.IpAddressList
		gwl := &ai.GatewayList
		dhcpl := &ai.DhcpServer
		for ; ipl != nil; ipl = ipl.Next {
			fmt.Printf("IpAddress:\t%s\n", ipl.IpAddress)
			fmt.Printf("IpMask:\t%s\n", ipl.IpMask)
			fmt.Printf("GatewayIp:\t%s\n", gwl.IpAddress)
			fmt.Printf("DHCPServerIp:\t%s\n", dhcpl.IpAddress)
		}
	}
	fmt.Println()

	return err
}

func main() {
	if e := localAddresses(); e != nil {
		fmt.Println(e)
	}

	fmt.Println("测试pcap.FindAllDevs()")
	// Find all devices
	devices, err := pcap.FindAllDevs()
	if err != nil {
		log.Fatal(err)
	}
	// Print device information
	for _, device := range devices {
		fmt.Println("\nName: ", device.Name)
		fmt.Println("Description: ", device.Description)
		fmt.Println("Devices Flags: ", device.Flags)
		fmt.Println("Devices addresses: ")
		for _, address := range device.Addresses {
			fmt.Println("- IP address: ", address.IP)
			fmt.Println("- Subnet mask: ", address.Netmask)
			fmt.Println("- Broadaddr: ", address.Broadaddr)
		}
	}
}

问题

如何关联各种信息?

比如关联pcap.Interfacenet.Interface,参考:How to associate pcap.Interface with net.Interface?,有个人提出了一个解决方案,by matching the IP addresses of the interfaces with those of the devices

总结

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • Golang中interface的基本用法详解

    Golang中interface的基本用法详解

    Go 中接口也是一个使用得非常频繁的特性,好的软件设计往往离不开接口的使用,比如依赖倒置原则(通过抽象出接口,分离了具体实现与实际使用的耦合)。 今天,就让我们来了解一下 Go 中接口的一些基本用法
    2023-01-01
  • 利用dep代替go get获取私有库的方法教程

    利用dep代替go get获取私有库的方法教程

    go get 从指定源上面下载或者更新指定的代码和依赖,并对他们进行编译和安装,但go get功能比较差,所以下面这篇文章主要给大家介绍了关于利用dep代替go get获取私有库的相关资料,需要的朋友可以参考借鉴,下面来一起看看吧。
    2017-11-11
  • Golang内存泄漏场景以及解决方案详析

    Golang内存泄漏场景以及解决方案详析

    golang中内存泄露的发现与排查一直是来是go开发者头疼的一件事,下面这篇文章主要给大家介绍了关于Golang内存泄漏场景以及解决的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2023-01-01
  • Goland编辑器设置选择范围背景色的操作

    Goland编辑器设置选择范围背景色的操作

    这篇文章主要介绍了Goland编辑器设置选择范围背景色的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-12-12
  • go语言日志记录库简单使用方法实例分析

    go语言日志记录库简单使用方法实例分析

    这篇文章主要介绍了go语言日志记录库简单使用方法,实例分析了Go语言日志记录的操作的技巧,需要的朋友可以参考下
    2015-03-03
  • go语言中os包的用法实战大全

    go语言中os包的用法实战大全

    Go在os中提供了文件的基本操作,包括通常意义的打开、创建、读写等操作,除此以外为了追求便捷以及性能上,Go还在io/ioutil以及bufio提供一些其他函数供开发者使用,这篇文章主要给大家介绍了关于go语言中os包用法的相关资料,需要的朋友可以参考下
    2024-02-02
  • go语言睡眠排序算法实例分析

    go语言睡眠排序算法实例分析

    这篇文章主要介绍了go语言睡眠排序算法,实例分析了睡眠排序算法的原理与实现技巧,需要的朋友可以参考下
    2015-03-03
  • 谈谈对Golang IO读写的困惑

    谈谈对Golang IO读写的困惑

    这篇文章主要介绍了谈谈对Golang IO读写的困惑,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-08-08
  • Go编写定时器与定时任务详解(附第三方库gocron用法)

    Go编写定时器与定时任务详解(附第三方库gocron用法)

    当需要每天执行定时任务的时候就需要定时器来处理了,周期任务,倒计时任务,定点任务等,下面这篇文章主要给大家介绍了关于Go编写定时器与定时任务的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
    2022-07-07
  • Go语言实现的最简单数独解法

    Go语言实现的最简单数独解法

    前面给大家介绍过使用javascript实现的简单的数独解法,小伙伴们都非常喜欢,今天我们再来分享一则go语言实现的简单的数独解法,有需要的小伙伴来参考下。
    2015-03-03

最新评论