I want to list no. of subnets in a network, I have sample working code in python but require it in golang.
NETWORK="192.168.0.0/16"
subnet_prefix=22
net = ipaddress.ip_network(NETWORK)
for subnet in net.subnets(new_prefix=subnet_prefix):
net = ipaddress.ip_interface(subnet)
print(net)
192.168.0.0/22 192.168.4.0/22 192.168.8.0/22 192.168.12.0/22 192.168.16.0/22 192.168.20.0/22 192.168.24.0/22 192.168.28.0/22 192.168.32.0/22 192.168.36.0/22 192.168.40.0/22 192.168.44.0/22 192.168.48.0/22 192.168.52.0/22 192.168.56.0/22 192.168.60.0/22 192.168.64.0/22 192.168.68.0/22 192.168.72.0/22 192.168.76.0/22 192.168.80.0/22 192.168.84.0/22 192.168.88.0/22 192.168.92.0/22 192.168.96.0/22 192.168.100.0/22 192.168.104.0/22 192.168.108.0/22 192.168.112.0/22 192.168.116.0/22 192.168.120.0/22 192.168.124.0/22 192.168.128.0/22 192.168.132.0/22 192.168.136.0/22 192.168.140.0/22 192.168.144.0/22 192.168.148.0/22 192.168.152.0/22 192.168.156.0/22 192.168.160.0/22 192.168.164.0/22 192.168.168.0/22 192.168.172.0/22 192.168.176.0/22 192.168.180.0/22 192.168.184.0/22 192.168.188.0/22 192.168.192.0/22 192.168.196.0/22 192.168.200.0/22 192.168.204.0/22 192.168.208.0/22 192.168.212.0/22 192.168.216.0/22 192.168.220.0/22 192.168.224.0/22 192.168.228.0/22 192.168.232.0/22 192.168.236.0/22 192.168.240.0/22 192.168.244.0/22 192.168.248.0/22 192.168.252.0/22
The function I wrote generates all the subnets of given subnetMaskSize
that can be created inside a given netCIDR
. Network and subnets are in all in CIDR notation.
E.g.:
func Runner() {
fmt.Println(GenSubnetsInNetwork("192.168.0.0/24", 26))
}
=== RUN TestRunner/run_me
[192.168.0.0/26 192.168.0.64/26 192.168.0.128/26 192.168.0.192/26] <nil>
--- PASS: TestRunner (0.00s)
I chose arithmetic operations hence it's easier to understand(for better performance use bitwise operations).
The function calculates some facts about the given network and subnetMask, then it generates all the subnet CIDRs.
func GenSubnetsInNetwork(netCIDR string, subnetMaskSize int) ([]string, error) {
ip, ipNet, err := net.ParseCIDR(netCIDR)
if err != nil {
return nil, err
}
if !ip.Equal(ipNet.IP) {
return nil, errors.New("netCIDR is not a valid network address")
}
netMaskSize, _ := ipNet.Mask.Size()
if netMaskSize > int(subnetMaskSize) {
return nil, errors.New("subnetMaskSize must be greater or equal than netMaskSize")
}
totalSubnetsInNetwork := math.Pow(2, float64(subnetMaskSize)-float64(netMaskSize))
totalHostsInSubnet := math.Pow(2, 32-float64(subnetMaskSize))
subnetIntAddresses := make([]uint32, int(totalSubnetsInNetwork))
// first subnet address is same as the network address
subnetIntAddresses[0] = ip2int(ip.To4())
for i := 1; i < int(totalSubnetsInNetwork); i++ {
subnetIntAddresses[i] = subnetIntAddresses[i-1] + uint32(totalHostsInSubnet)
}
subnetCIDRs := make([]string, 0)
for _, sia := range subnetIntAddresses {
subnetCIDRs = append(
subnetCIDRs,
int2ip(sia).String()+"/"+strconv.Itoa(int(subnetMaskSize)),
)
}
return subnetCIDRs, nil
}
func ip2int(ip net.IP) uint32 {
if len(ip) == 16 {
panic("cannot convert IPv6 into uint32")
}
return binary.BigEndian.Uint32(ip)
}
func int2ip(nn uint32) net.IP {
ip := make(net.IP, 4)
binary.BigEndian.PutUint32(ip, nn)
return ip
}