Go - calculate the cidr below one bit of the cidr provided

Viewed 62

Ask

How do you calculate the cidr below one bit of the cidr provided?

Given:

a network CIDR : (192.168.0.0/16)

wanted result

192.168.0.0/17, 192.168.128.0/17

Using packages such as the default net package and github.com/brotherpowers/ipsubnet, github.com/seancfoley/ipaddress-go/ipaddr did not get the desired results.

2 Answers

To split a network in two, increment the length of the prefix by one. That gives you the lower half. To compute the second half, increment the network part by one (error handling omitted for brevity):

package main

import (
    "fmt"
    "math/big"
    "net/netip"
)

func main() {
    p := netip.MustParsePrefix("192.168.0.0/16")
    lo, hi := split(p)
    fmt.Println(lo, hi) // 192.168.0.0/17 192.168.128.0/17
}

func split(p netip.Prefix) (lo, hi netip.Prefix) {
    p = p.Masked()
    lo, _ = p.Addr().Prefix(p.Bits() + 1)

    delta := big.NewInt(1)
    delta.Lsh(delta, uint(lo.Addr().BitLen()-lo.Bits()))

    n := new(big.Int).SetBytes(lo.Addr().AsSlice())
    n.Add(n, delta)

    hiIP, _ := netip.AddrFromSlice(n.Bytes())
    hi = netip.PrefixFrom(hiIP, lo.Bits())

    return lo, hi
}

https://go.dev/play/p/0HLqUK0RmVC

"Using packages such as the default net package and github.com/brotherpowers/ipsubnet, github.com/seancfoley/ipaddress-go/ipaddr did not get the desired results."

Here is how to do it with github.com/seancfoley/ipaddress-go/ipaddr (note this code also works with IPv6 and any change in prefix length):

package main

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

func main() {
    cidr := ipaddr.NewIPAddressString("192.168.0.0/16").GetAddress()
    for i := cidr.AdjustPrefixLen(1).PrefixBlockIterator(); i.HasNext(); {
        fmt.Println(i.Next())
    }
}

Output:

192.168.0.0/17
192.168.128.0/17
Related