Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to get all addresses and masks from local interfaces in go?

How can I get all addresses and masks from local interfaces in golang?

I need the actual network mask configured along with every IP address.

This code does not show the network masks in 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()
}

UPDATE: This issue has been fixed in Go: https://github.com/golang/go/issues/5395

like image 803
Everton Avatar asked May 07 '14 22:05

Everton


People also ask

How do I view the contents of a network configuration file?

The configuration files for network interfaces are located in the /etc/sysconfig/network-scripts/ directory. The scripts used to activate and deactivate these network interfaces are also located here.

Can 2 NIC with same IP address?

You won't "give both ports the same IP address" since there will only be one "port" visible to give an IP address to. Save this answer. Show activity on this post. Each "LAN port", or NIC, must have a unique IP address.


4 Answers

There are multiply types of addresses that a net.Interface might have. The Addr is just an interface which may contain a net.IPAddr. But with a type assertion or type switch you can access the actual address type:

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()
}

Edit

Unfortunately the net package doesn't return the Mask of the address. So, you will have to do the low level syscalls that the net package does. The code below is an example, but parsing of the ip and the mask still needs to be done:

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)
    }
}

Some code shamelessly borrowed from interface_windows.go. Even comments are left intact

like image 76
ANisus Avatar answered Oct 30 '22 02:10

ANisus


I'm modifying @ANisus answer and get all interfaces & masks (tested on Windows 10 & WSL in it (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()
}
like image 27
AJIOB Avatar answered Oct 30 '22 01:10

AJIOB


This should give you the ipnet you're looking for.

ip, ipnet, err := net.ParseCIDR(a.String())
like image 38
Marlon Bailey Avatar answered Oct 30 '22 01:10

Marlon Bailey


I know this post for Windows 7, but if you use Mac OS X hope this could help you.

Just Call 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 ""
}
like image 1
Evan Lin Avatar answered Oct 30 '22 03:10

Evan Lin