Golang IP address conversion

IP address conversion with golang

Finding an IP network's broadcast IP

The following function calculates the broadcast IP for both IPv4 and IPv6 networks:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
func subnetBroadcastIP(ipnet net.IPNet) (net.IP, error) {
    byteIp := []byte(ipnet.IP)                // []byte representation of IP
    byteMask := []byte(ipnet.Mask)            // []byte representation of mask
    byteTargetIp := make([]byte, len(byteIp)) // []byte holding target IP
    for k, _ := range byteIp {
        // mask will give us all fixed bits of the subnet (for the given byte)
        // inverted mask will give us all moving bits of the subnet (for the given byte)
        invertedMask := byteMask[k] ^ 0xff // inverted mask byte

        // broadcastIP = networkIP added to the inverted mask
        byteTargetIp[k] = byteIp[k]&byteMask[k] | invertedMask
    }

    return net.IP(byteTargetIp), nil
}

In order to understand the aforementioned example better, here is a longer version (the if / else block is useless and hence removed):

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
func subnetBroadcastIP(ipnet net.IPNet) (net.IP, error) {
    // ipv4
    if ipnet.IP.To4() != nil {
        // ip address in uint32
        ipBits := binary.BigEndian.Uint32(ipnet.IP.To4())

        // mask will give us all fixed bits of the subnet
        maskBits := binary.BigEndian.Uint32(ipnet.Mask)

        // inverted mask will give us all moving bits of the subnet
        invertedMaskBits := maskBits ^ 0xffffffff // xor the mask

        // network ip
        networkIpBits := ipBits & maskBits

        // broadcastIP = networkIP added to the inverted mask
        broadcastIpBits := networkIpBits | invertedMaskBits

        broadcastIp := make(net.IP, 4)
        binary.BigEndian.PutUint32(broadcastIp, broadcastIpBits)
        return broadcastIp, nil
    }
    // ipv6
    // this conversion is actually easier, follows the same principle as above
    byteIp := []byte(ipnet.IP)                // []byte representation of IP
    byteMask := []byte(ipnet.Mask)            // []byte representation of mask
    byteTargetIp := make([]byte, len(byteIp)) // []byte holding target IP
    for k, _ := range byteIp {
        invertedMask := byteMask[k] ^ 0xff // inverted mask byte
        byteTargetIp[k] = byteIp[k]&byteMask[k] | invertedMask
    }

    return net.IP(byteTargetIp), nil
}

Finding all IPs in a subnet

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
func subnetIPs(ipnet net.IPNet) ([]net.IP, error) {
        var ipList []net.IP
        ip := ipnet.IP
        for ; ipnet.Contains(ip); ip = incIP(ip) {
                ipList = append(ipList, ip) 
        }

        return ipList, nil 
}

func incIP(ip net.IP) net.IP {
        // allocate a new IP
        newIp := make(net.IP, len(ip))
        copy(newIp, ip) 

        byteIp := []byte(newIp)
        l := len(byteIp)
        var i int 
        for k, _ := range byteIp {
                // start with the rightmost index first
                // increment it
                // if the index is < 256, then no overflow happened and we increment and break
                // else, continue to the next field in the byte
                i = l - 1 - k 
                if byteIp[i] < 0xff {
                        byteIp[i]++
                        break
                } else {
                        byteIp[i] = 0 
                }
        }
        return net.IP(byteIp)
}