3

I am trying to get the IP address and subnet mask by

ifaces, err := net.Interfaces()
for _, iface := range ifaces{
        localip, _ = iface.Addrs()
}

However, I am looking forward to get the subnet as something like 255.255.255.0 rather than /24. How can I get that? If there are no modules that can do this, what is the logic to do this as a program?

scott
  • 1,557
  • 3
  • 15
  • 31

6 Answers6

4
func main() {
    ifaces, err := net.Interfaces()
    if err != nil {
        panic(err)
    }
    for _, iface := range ifaces {
        addrs, _ := iface.Addrs()
        for _, addr := range addrs {
            cidr := addr.String()
            mask, err := mask(cidr)
            if err != nil {
                fmt.Println("extracting mask failed:", err)
            }
            i, err := mtoi(mask)
            if err != nil {
                fmt.Println("creating uint16 from mask failed:", err)
            }
            fmt.Printf("CIDR: %s\tMask: %d\n", cidr, i)
        }
    }
}

// Extracts IP mask from CIDR address.
func mask(cidr string) (net.IPMask, error) {
    _, ip, err := net.ParseCIDR(cidr)
    return ip.Mask, err
}

// Converts IP mask to 16 bit unsigned integer.
func mtoi(mask net.IPMask) (uint16, error) {
    var i uint16
    buf := bytes.NewReader(mask)
    err := binary.Read(buf, binary.BigEndian, &i)
    return i, err
}
kopiczko
  • 3,018
  • 1
  • 17
  • 24
  • Could you kindly explain this as an inline comment? – scott Jan 08 '16 at 10:24
  • I just extracted two functions to make the code cleaner. Notice that `net.Mask` is defined as `type IPMask []byte` so it may be more useful in this form. – kopiczko Jan 08 '16 at 10:51
3

Converting netmask to type "IP" before printing does the trick:

func mask_print(ipnet *net.IPNet){
  fmt.Println("%v", net.IP(ipnet.Mask))      
}
Kosdex
  • 31
  • 1
2

Borrowed from some stackoverflow post itself, using logical operators.

mask = (0xFFFFFFFF << (32 - 24)) & 0xFFFFFFFF; //24 is the netmask
var dmask uint64
dmask = 32
localmask := make([]uint64, 0, 4)
for i := 1; i <= 4; i++{
    tmp := mask >> (dmask - 8) & 0xFF
    localmask = append(localmask, tmp)
    dmask -= 8
}

fmt.Println(localmask)
nohup
  • 3,105
  • 3
  • 27
  • 52
1

You could implement a function like:

func parseMask(ipaddr string) (mask string, err error) {
    removeExtra := regexp.MustCompile("^(.*[\\/])")
    asd := ipaddr[len(ipaddr)-3:]
    findSubnet := removeExtra.ReplaceAll([]byte(asd), []byte(""))
    subnet, err := strconv.ParseInt(string(findSubnet), 10, 64)
    if err != nil {
        return "", errors.New("Parse Mask: Error parsing mask")
    }
    var buff bytes.Buffer
    for i := 0; i < int(subnet); i++ {
        buff.WriteString("1")
    }
    for i := subnet; i < 32; i++ {
        buff.WriteString("0")
    }
    masker := buff.String()
    a, _ := strconv.ParseUint(masker[:8], 2, 64)
    b, _ := strconv.ParseUint(masker[8:16], 2, 64)
    c, _ := strconv.ParseUint(masker[16:24], 2, 64)
    d, _ := strconv.ParseUint(masker[24:32], 2, 64)
    resultMask := fmt.Sprintf("%v.%v.%v.%v", a, b, c, d)
    return resultMask, nil
}

and then call it:

func main() {
    ifaces, _ := net.Interfaces()
    for _, iface := range ifaces {
        localip, _ := iface.Addrs()
        for _, ip := range localip {
            done, _ := parseMask(ip.String())
            log.Println(done) // 255.255.255.0
        }
    }
}
Datsik
  • 14,453
  • 14
  • 80
  • 121
0

Following function that i wrote works for ipv4:

func NetMaskToString(mask int) (netmaskstring string) {
var binarystring string

for ii := 1; ii <= mask; ii++ {
    binarystring = binarystring + "1"
}
for ii := 1; ii <= (32 - mask); ii++ {
    binarystring = binarystring + "0"
}
oct1 := binarystring[0:8]
oct2 := binarystring[8:16]
oct3 := binarystring[16:24]
oct4 := binarystring[24:]

ii1, _ := strconv.ParseInt(oct1, 2, 64)
ii2, _ := strconv.ParseInt(oct2, 2, 64)
ii3, _ := strconv.ParseInt(oct3, 2, 64)
ii4, _ := strconv.ParseInt(oct4, 2, 64)
netmaskstring = strconv.Itoa(int(ii1)) + "." + strconv.Itoa(int(ii2)) + "." + strconv.Itoa(int(ii3)) + "." + strconv.Itoa(int(ii4))
return

}

VikasPushkar
  • 392
  • 3
  • 18
0

There are a couple of options. You can do a type assertion to *net.IPNet from which you can grab the mask, as shown. Or you can parse the given CIDR address. The parse can be done with the IPAddress Go library as shown, or by using net.ParseCIDR to get a *net.IPNet from which you can grab the mask. Disclaimer: I am the project manager for IPAddress.

package main

import (
    "fmt"
    "github.com/seancfoley/ipaddress-go/ipaddr"
    "net"
)

func main() {
    ifaces, _ := net.Interfaces()
    var localips []net.Addr
    for _, iface := range ifaces {
        addrs, _ := iface.Addrs()
        localips = append(localips, addrs...)
    }
    for _, localip := range localips {
        fmt.Println("for the IP", localip)

        // one way is to type assert
        ipnet := localip.(*net.IPNet)
        maskBytes := net.IP(ipnet.Mask)
        fmt.Println("\tcasted mask is", maskBytes)

        // another way is to parse the string
        cidrStr := localip.String()
        maskAddr := ipaddr.NewIPAddressString(cidrStr).GetAddress().
            GetNetworkMask() // add .GetNetIP() for net.IP
        fmt.Println("\tparsed mask is", maskAddr)
    }
}

Sample output:

for the IP 127.0.0.1/8
        casted mask is 255.0.0.0
        parsed mask is 255.0.0.0
for the IP ::1/128
        casted mask is ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
        parsed mask is ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff
for the IP fe80::1/64
        casted mask is ffff:ffff:ffff:ffff::
        parsed mask is ffff:ffff:ffff:ffff::
for the IP fe80::10ba:1591:f2b5:cfc7/64
        casted mask is ffff:ffff:ffff:ffff::
        parsed mask is ffff:ffff:ffff:ffff::
for the IP 192.168.1.165/24
        casted mask is 255.255.255.0
        parsed mask is 255.255.255.0
for the IP 9.211.112.150/19
        casted mask is 255.255.224.0
        parsed mask is 255.255.224.0
Sean F
  • 4,344
  • 16
  • 30