【golang】syscall 获取本机网卡IP、网关,可以通过IP地址来进行路由选择(多网卡)

在这里插入图片描述

package main

import (
	"fmt"
	"syscall"
	"net"
	"unsafe"
	"sort"
)

type rtInfo struct {
	Dst net.IPNet
	Gateway, PrefSrc net.IP
	OutputIface uint32
	Priority uint32
}

type routeSlice []*rtInfo

type router struct {
	ifaces []net.Interface
	addrs []net.IP
	v4 routeSlice
}

func getRouteInfo() (*router, error) {
	rtr := &router{}

	tab, err := syscall.NetlinkRIB(syscall.RTM_GETROUTE, syscall.AF_INET)
	if err != nil {
		return nil, err	
	}

	msgs, err := syscall.ParseNetlinkMessage(tab)
	if err != nil {
		return nil, err	
	}

	for _, m := range msgs {
		switch m.Header.Type {
			case syscall.NLMSG_DONE:
				break	
			case syscall.RTM_NEWROUTE:
				rtmsg := (*syscall.RtMsg)(unsafe.Pointer(&m.Data[0]))
				attrs, err := syscall.ParseNetlinkRouteAttr(&m)		
				if err != nil {
					return nil, err
				}
				routeInfo := rtInfo{}
				rtr.v4 = append(rtr.v4, &routeInfo)
				for _, attr:= range attrs {
					switch attr.Attr.Type {
					case syscall.RTA_DST:
						routeInfo.Dst.IP = net.IP(attr.Value)
						routeInfo.Dst.Mask = net.CIDRMask(int(rtmsg.Dst_len), len(attr.Value)*8)
					case syscall.RTA_GATEWAY:
						routeInfo.Gateway = net.IPv4(attr.Value[0], attr.Value[1], attr.Value[2], attr.Value[3])
					case syscall.RTA_OIF:
						routeInfo.OutputIface = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
					case syscall.RTA_PRIORITY:
						routeInfo.Priority = *(*uint32)(unsafe.Pointer(&attr.Value[0]))
					case syscall.RTA_PREFSRC:
						routeInfo.PrefSrc = net.IPv4(attr.Value[0], attr.Value[1], attr.Value[2], attr.Value[3])
					}
				}
		}			
	}
	
	sort.Slice(rtr.v4, func(i, j int) bool {
		return rtr.v4[i].Priority < rtr.v4[j].Priority
	})

	ifaces, err := net.Interfaces()
	if err != nil {
		return nil, err
	}

	for i, iface := range ifaces {
		
		if i != iface.Index - 1 {
			break
		}

		if iface.Flags & net.FlagUp == 0{
			continue
		}
		rtr.ifaces = append(rtr.ifaces, iface)
		ifaceAddrs, err := iface.Addrs()
		if err != nil {
			return nil, err
		}
		var addrs net.IP
		for _, addr := range ifaceAddrs {
			if inet, ok := addr.(*net.IPNet); ok {
				if v4 := inet.IP.To4(); v4 != nil {
					if addrs == nil {
						addrs = v4
					}
				}
			}
		}
		rtr.addrs = append(rtr.addrs, addrs)
	}
	return rtr, nil
}


func main() {
	newRoute, err := getRouteInfo()
	if err != nil {
		fmt.Println(err)
		return 
	}

	fmt.Println("**************************************")
	fmt.Printf("%-15v %-15v %-15v\n", "interfaceName", "gateway", "ip")
	for _, rt := range newRoute.v4 { 
		if rt.Gateway != nil {
			fmt.Printf("%-15v %-15v %-15v\n", newRoute.ifaces[rt.OutputIface - 1].Name, rt.Gateway.String(), newRoute.addrs[rt.OutputIface - 1])
		}
	}
	fmt.Println("**************************************")

	newRoute.getRoute(net.ParseIP("192.168.2.100"))
	newRoute.getRoute(net.ParseIP("10.10.100.100"))
	newRoute.getRoute(net.ParseIP("172.1.2.100"))
}

func (r *router)getRoute(dst net.IP) {
	for _, rt := range r.v4 { 
		if rt.Dst.IP != nil && !rt.Dst.Contains(dst) {
			continue
		}
		fmt.Printf("%-15v : ", dst.String())
		if rt.PrefSrc == nil {
			fmt.Println(r.ifaces[rt.OutputIface - 1].Name, rt.Gateway.String(), r.addrs[rt.OutputIface - 1].String())
		} else {
			fmt.Println(r.ifaces[rt.OutputIface - 1].Name, rt.Gateway.String(), rt.PrefSrc.String())
		}
		return
	}
}
### 回答1: 如果要用Go语言获取网卡IP,可以使用net.InterfaceAddrs函数。下面是一个示例代码:ifaces, err := net.InterfaceAddrs() if err != nil { log.Fatal(err) } for _, a := range ifaces { fmt.Println(a) } ### 回答2: 使用Golang获取网卡IP网关的代码示例如下: ```go package main import ( "fmt" "net" ) func main() { interfaces, err := net.Interfaces() if err != nil { fmt.Println("Failed to get network interfaces:", err) return } for _, iface := range interfaces { addrs, err := iface.Addrs() if err != nil { fmt.Println("Failed to get addresses for interface", iface.Name, ":", err) continue } for _, addr := range addrs { ipNet, ok := addr.(*net.IPNet) if !ok { continue } // Check if it's an IPv4 address if ipNet.IP.To4() != nil { fmt.Println("IPv4 address:", ipNet.IP) // Get the associated network interface's default gateway if defaultRoute, err := net.InterfaceByName(iface.Name); err == nil { routes, err := defaultRoute.Addrs() if err != nil { fmt.Println("Failed to get default gateway for interface", iface.Name, ":", err) continue } for _, route := range routes { gateway, ok := route.(*net.IPNet) if !ok { continue } if !gateway.IP.IsLoopback() && gateway.IP.To4() != nil { fmt.Println("Default gateway:", gateway.IP) } } } } } } } ``` 这段代码通过使用`net.Interfaces()`函数获取所有的网络接口,然后遍历每个接口的地址。对于IPv4地址,它会打印出来,并通过`net.InterfaceByName()`函数获取关联网络接口的默认网关。然后,它遍历这些网关,并打印出IPv4格式的默认网关地址。 希望这可以帮助你获取网卡IP网关。 ### 回答3: 要获取网卡IP网关,在Golang中可以使用`net`和`os/exec`包来实现。以下是一个代码示例: ```go package main import ( "fmt" "net" "os/exec" "strings" ) func main() { // 获取所有网卡信息 interfaces, err := net.Interfaces() if err != nil { fmt.Println("获取网卡信息失败:", err) return } // 遍历网卡信息 for _, iface := range interfaces { // 排除回环接口和无效接口 if iface.Flags&net.FlagLoopback != 0 || iface.Flags&net.FlagUp == 0 { continue } // 获取网卡IP地址 addrs, err := iface.Addrs() if err != nil { fmt.Println("获取网卡IP失败:", err) return } // 遍历IP地址 for _, addr := range addrs { ipnet, ok := addr.(*net.IPNet) if ok && !ipnet.IP.IsLoopback() && ipnet.IP.To4() != nil { fmt.Printf("网卡%d的IP地址:%s\n", iface.Index, ipnet.IP.String()) } } // 获取网卡网关 output, err := exec.Command("netstat", "-nr").Output() if err != nil { fmt.Println("执行netstat命令失败:", err) return } // 解析输出结果 lines := strings.Split(string(output), "\n") for _, line := range lines { fields := strings.Fields(line) if len(fields) > 1 && fields[0] == "0.0.0.0" { fmt.Printf("网卡%d的网关:%s\n", iface.Index, fields[1]) break } } } } ``` 这个代码会遍历所有的网卡获取每个网卡IP地址,并使用`netstat`命令来获取网卡网关。最后打印出每个网卡IP地址网关。请注意,在Windows系统和Linux系统中,`netstat`命令的输出格式可能不同,需要根据实际情况修改解析代码。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值