如何从本地接口获取所有地址和掩码?

Posted

技术标签:

【中文标题】如何从本地接口获取所有地址和掩码?【英文标题】:How to get all addresses and masks from local interfaces in go? 【发布时间】:2014-06-25 03:08:09 【问题描述】:

如何从 golang 的本地接口获取所有地址和掩码?

我需要与每个 IP 地址一起配置的实际网络掩码。

此代码在 Windows 7 中不显示网络掩码:

package main

import (
    "fmt"
    "log"
    "net"
)

func localAddresses() 
    ifaces, err := net.Interfaces()
    if err != nil 
        log.Print(fmt.Errorf("localAddresses: %v\n", err.Error()))
        return
    
    for _, i := range ifaces 
        addrs, err := i.Addrs()
        if err != nil 
            log.Print(fmt.Errorf("localAddresses: %v\n", err.Error()))
            continue
        
        for _, a := range addrs 
            log.Printf("%v %v\n", i.Name, a)
        
    


func main() 
    localAddresses()

更新:此问题已在 Go 中修复:https://github.com/golang/go/issues/5395

【问题讨论】:

【参考方案1】:

net.Interface 可能有多种类型的地址。 Addr 只是一个可能包含net.IPAddr 的接口。但是通过类型断言或类型切换,您可以访问实际的地址类型:

package main

import (
    "fmt"
    "net"
)

func localAddresses() 
    ifaces, err := net.Interfaces()
    if err != nil 
        fmt.Print(fmt.Errorf("localAddresses: %+v\n", err.Error()))
        return
    
    for _, i := range ifaces 
        addrs, err := i.Addrs()
        if err != nil 
            fmt.Print(fmt.Errorf("localAddresses: %+v\n", err.Error()))
            continue
        
        for _, a := range addrs 
            switch v := a.(type) 
            case *net.IPAddr:
                fmt.Printf("%v : %s (%s)\n", i.Name, v, v.IP.DefaultMask())
            

        
    


func main() 
    localAddresses()

编辑

不幸的是,net 包没有返回地址的掩码。因此,您将不得不执行 net 包所做的低级系统调用。下面的代码是一个例子,但仍然需要解析ip和掩码:

package main

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

func getAdapterList() (*syscall.IpAdapterInfo, error) 
    b := make([]byte, 1000)
    l := uint32(len(b))
    a := (*syscall.IpAdapterInfo)(unsafe.Pointer(&b[0]))
    // TODO(mikio): GetAdaptersInfo returns IP_ADAPTER_INFO that
    // contains IPv4 address list only. We should use another API
    // for fetching IPv6 stuff from the kernel.
    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 
    ifaces, err := net.Interfaces()
    if err != nil 
        return err
    

    aList, err := getAdapterList()
    if err != nil 
        return err
    

    for _, ifi := range ifaces 
        for ai := aList; ai != nil; ai = ai.Next 
            index := ai.Index

            if ifi.Index == int(index) 
                ipl := &ai.IpAddressList
                for ; ipl != nil; ipl = ipl.Next 

                    fmt.Printf("%s: %s (%s)\n", ifi.Name, ipl.IpAddress, ipl.IpMask)
                
            
        
    
    return err


func main() 
    err := localAddresses()
    if err != nil 
        panic(err)
    

从 interface_windows.go 中无耻地借用了一些代码。甚至 cmets 也完好无损

【讨论】:

我需要实际的掩码,而不是有类的默认值。我看到 net.IPNet 类型提供了 net.IPNet.Mask。有没有办法将地址读取为 net.IPNet? 查看net 包的文档/源代码,我看到他们只提供IP。因此,您需要做的是改用 syscall 包。我会更新我的答案。 不错!但是它只显示一个接口的地址/掩码。固定在这里:play.golang.org/p/kJ0P7HnvDE 请更新答案然后我接受它!谢谢。 @Everton 啊,是的。我看到了我的错误。我已经用你的错误修复更新了代码。欢迎:) syscall.IpAdapterInfo 在 Go 1.5 上有一些问题,它将在 Go 1.6 中修复。参考github.com/golang/go/issues/12551【参考方案2】:

我正在修改@ANisus 答案并获取所有接口和掩码(在 Windows 10 和 WSL 上测试(Microsoft Ubuntu 16.04.5 LTS):

package main

import (
    "fmt"
    "net"
)

func localAddresses() 
    ifaces, err := net.Interfaces()
    if err != nil 
        fmt.Print(fmt.Errorf("localAddresses: %+v\n", err.Error()))
        return
    
    for _, i := range ifaces 
        addrs, err := i.Addrs()
        if err != nil 
            fmt.Print(fmt.Errorf("localAddresses: %+v\n", err.Error()))
            continue
        
        for _, a := range addrs 
            switch v := a.(type) 
            case *net.IPAddr:
                fmt.Printf("%v : %s (%s)\n", i.Name, v, v.IP.DefaultMask())

            case *net.IPNet:
                fmt.Printf("%v : %s [%v/%v]\n", i.Name, v, v.IP, v.Mask)
            

        
    


func main() 
    localAddresses()

【讨论】:

【参考方案3】:

这应该会给你正在寻找的ipnet

ip, ipnet, err := net.ParseCIDR(a.String())

【讨论】:

【参考方案4】:

我知道这篇文章适用于 Windows 7,但如果您使用 Mac OS X,希望这对您有所帮助。

只需致电GetNetMask("en0")

func GetNetMask(deviceName string) string 
    switch runtime.GOOS 
    case "darwin":
        cmd := exec.Command("ipconfig", "getoption", deviceName, "subnet_mask")
        out, err := cmd.CombinedOutput()
        if err != nil 
            return ""
        

        nm := strings.Replace(string(out), "\n", "", -1)
        log.Println("netmask=", nm, " OS=", runtime.GOOS)
        return nm
    default:
        return ""
    
    return ""

【讨论】:

以上是关于如何从本地接口获取所有地址和掩码?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用算术和掩码舍入地址?

在 Python 中从 IP 地址和掩码长度获取 IP 掩码

华为机试真题详解JAVA实现—识别有效的IP地址和掩码并进行分类统计

识别有效的IP地址和掩码并进行分类统计

华为机试HJ18:识别有效的IP地址和掩码并进行分类统计

如何划分子网,确定子网和掩码的位数?