开发者

Go语言如何获取网卡信息

目录
  • net
    • 网络接口
      • 函数
      • 类型
  • syscall
    • 网络接口
    • github.com/google/gopacket/pcap
      • 网络接口
        • 函数
        • 类型
      • 处理网络流
        • 函数
    • 获取网卡信息的各种方法测试
      • 问题
        • 总结

          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&http://www.devze.comrdquo;, “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 列表)信息

          示例:

          Go语言如何获取网卡信息

          type Interface struct {
          	Name        string
          	Description string
          	Flagsjs       uint32
          	Addrhttp://www.devze.comesses   []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。

          总结

          以上为个人经验,希望能给大家一个参考,也希望大家多多支持编程客栈(www.devze.com)。

          0

          上一篇:

          下一篇:

          精彩评论

          暂无评论...
          验证码 换一张
          取 消

          最新开发

          开发排行榜