如何使用golang列出网络中的子网?

huangapple go评论76阅读模式
英文:

How to list subnets in a network using golang?

问题

我想要列出一个网络中子网的数量,我有一个在Python中的示例工作代码,但我需要将其转换为Golang。

package main

import (
	"fmt"
	"net"
)

func main() {
	NETWORK := "192.168.0.0/16"
	subnet_prefix := 22
	_, network, _ := net.ParseCIDR(NETWORK)
	for subnet := network; subnet != nil; subnet = nextSubnet(subnet, subnet_prefix) {
		fmt.Println(subnet)
	}
}

func nextSubnet(subnet *net.IPNet, prefixLen int) *net.IPNet {
	ip := subnet.IP
	mask := net.CIDRMask(prefixLen, 32)
	nextIP := make(net.IP, len(ip))
	copy(nextIP, ip)
	for i := len(ip) - 1; i >= 0; i-- {
		nextIP[i]++
		if nextIP[i] > ip[i] {
			break
		}
	}
	return &net.IPNet{
		IP:   nextIP,
		Mask: mask,
	}
}

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

英文:

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

答案1

得分: 3

我写的这个函数生成给定subnetMaskSize下可以在给定netCIDR内创建的所有子网。网络和子网都使用CIDR表示法。

例如:

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)

我选择了算术运算,因为这样更容易理解(为了提高性能,可以使用位运算)。

该函数计算给定网络和子网掩码的一些信息,然后生成所有子网的CIDR。

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不是有效的网络地址")
	}
	netMaskSize, _ := ipNet.Mask.Size()
	if netMaskSize > int(subnetMaskSize) {
		return nil, errors.New("subnetMaskSize必须大于或等于netMaskSize")
	}

	totalSubnetsInNetwork := math.Pow(2, float64(subnetMaskSize)-float64(netMaskSize))
	totalHostsInSubnet := math.Pow(2, 32-float64(subnetMaskSize))
	subnetIntAddresses := make([]uint32, int(totalSubnetsInNetwork))
	// 第一个子网地址与网络地址相同
	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("无法将IPv6转换为uint32")
	}
	return binary.BigEndian.Uint32(ip)
}
func int2ip(nn uint32) net.IP {
	ip := make(net.IP, 4)
	binary.BigEndian.PutUint32(ip, nn)
	return ip
}
英文:

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(&quot;192.168.0.0/24&quot;, 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] &lt;nil&gt;
--- 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(&quot;netCIDR is not a valid network address&quot;)
	}
	netMaskSize, _ := ipNet.Mask.Size()
	if netMaskSize &gt; int(subnetMaskSize) {
		return nil, errors.New(&quot;subnetMaskSize must be greater or equal than netMaskSize&quot;)
	}

	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 &lt; int(totalSubnetsInNetwork); i++ {
		subnetIntAddresses[i] = subnetIntAddresses[i-1] + uint32(totalHostsInSubnet)
	}

	subnetCIDRs := make([]string, 0)
	for _, sia := range subnetIntAddresses {
		subnetCIDRs = append(
			subnetCIDRs,
			int2ip(sia).String()+&quot;/&quot;+strconv.Itoa(int(subnetMaskSize)),
		)
	}
	return subnetCIDRs, nil
}

func ip2int(ip net.IP) uint32 {
	if len(ip) == 16 {
		panic(&quot;cannot convert IPv6 into uint32&quot;)
	}
	return binary.BigEndian.Uint32(ip)
}
func int2ip(nn uint32) net.IP {
	ip := make(net.IP, 4)
	binary.BigEndian.PutUint32(ip, nn)
	return ip
}

答案2

得分: 1

选定的答案对于IPv4很有效,但我需要一个可以处理IPv4和IPv6的函数。以下是我想出的解决方案:

package main

import (
	"fmt"
	"net"

	netaddr "github.com/dspinhirne/netaddr-go"
)

func breakIntoSubnets(network string, newCidr uint) ([]string, error) {
	ip, _, err := net.ParseCIDR(network)
	if err != nil {
		fmt.Println("错误:", err)
		return nil, err
	}

	if ip.To4() != nil {
		newCidr = 21
		parsedNetwork, err := netaddr.ParseIPv4Net(network)
		if err != nil {
			fmt.Printf("使用netaddr解析网络(%s)时出错", network)
			return nil, err
		}
		subnets := make([]string, 0)
		for i := 0; i <= int(parsedNetwork.SubnetCount(newCidr)); i++ {
			subnet := parsedNetwork.NthSubnet(newCidr, uint32(i))
			if subnet == nil {
				return subnets, nil
			}
			subnets = append(subnets, subnet.String())
		}

		return subnets, nil
	} else {
		newCidr = 40
		parsedNetwork, err := netaddr.ParseIPv6Net(network)
		if err != nil {
			fmt.Printf("使用netaddr解析网络(%s)时出错", network)
			return nil, err
		}
		subnets := make([]string, 0)
		for i := 0; i <= int(parsedNetwork.SubnetCount(newCidr)); i++ {
			subnet := parsedNetwork.NthSubnet(newCidr, uint64(i))
			if subnet == nil {
				return subnets, nil
			}
			subnets = append(subnets, subnet.String())
		}

		return subnets, nil
	}

}

func main() {
	subnets, err := breakIntoSubnets("2601:9000::/20", 48)

	if err != nil {
		fmt.Printf("错误:%v", err)
	}

	for _, subnet := range subnets {
		fmt.Println(subnet)
	}
}

希望对你有帮助!

英文:

The chosen answer works well for ipv4 but I needed a function that can handle both ipv4 and ipv6. Here is what I came up with;

package main
import (
&quot;fmt&quot;
&quot;net&quot;
netaddr &quot;github.com/dspinhirne/netaddr-go&quot;
)
func breakIntoSubnets(network string, newCidr uint) ([]string, error) {
ip, _, err := net.ParseCIDR(network)
if err != nil {
fmt.Println(&quot;Error:&quot;, err)
return nil, err
}
if ip.To4() != nil {
newCidr = 21
parsedNetwork, err := netaddr.ParseIPv4Net(network)
if err != nil {
fmt.Printf(&quot;Error parsing network (%s) with netaddrr&quot;, network)
return nil, err
}
subnets := make([]string, 0)
for i := 0; i &lt;= int(parsedNetwork.SubnetCount(newCidr)); i++ {
subnet := parsedNetwork.NthSubnet(newCidr, uint32(i))
if subnet == nil {
return subnets, nil
}
subnets = append(subnets, subnet.String())
}
return subnets, nil
} else {
newCidr = 40
parsedNetwork, err := netaddr.ParseIPv6Net(network)
if err != nil {
fmt.Printf(&quot;Error parsing network (%s) with netaddrr&quot;, network)
return nil, err
}
subnets := make([]string, 0)
for i := 0; i &lt;= int(parsedNetwork.SubnetCount(newCidr)); i++ {
subnet := parsedNetwork.NthSubnet(newCidr, uint64(i))
if subnet == nil {
return subnets, nil
}
subnets = append(subnets, subnet.String())
}
return subnets, nil
}
}
func main() {
subnets, err := breakIntoSubnets(&quot;2601:9000::/20&quot;, 48)
if err != nil {
fmt.Printf(&quot;Error: %v&quot;, err)
}
for _, subnet := range subnets {
fmt.Println(subnet)
}
}

答案3

得分: 0

这只是一段使用ipaddress-go库的几行代码,不需要为IPv4和IPv6维护单独的代码。免责声明:我是该库的项目经理。

package main

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

func main() {
	listSubnets("192.168.0.0/16", 22)
	listSubnets("2001:db8::1a20/124", 126)
}

func listSubnets(original string, newPrefix int) {
	subnet := ipaddr.NewIPAddressString(original).GetAddress()
	iterator := subnet.SetPrefixLen(newPrefix).PrefixIterator()
	for iterator.HasNext() {
		fmt.Print(iterator.Next(), " ")
	}
	fmt.Println()
}

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

2001:db8::1a20/126 2001:db8::1a24/126 2001:db8::1a28/126 2001:db8::1a2c/126

英文:

This is just a few lines of code with the ipaddress-go library, and doesn't require maintaining separate code for IPv4 vs IPv6. Disclaimer: I am the project manager of the library.

package main

import (
	&quot;fmt&quot;
	&quot;github.com/seancfoley/ipaddress-go/ipaddr&quot;
)

func main() {
	listSubnets(&quot;192.168.0.0/16&quot;, 22)
	listSubnets(&quot;2001:db8::1a20/124&quot;, 126)
}

func listSubnets(original string, newPrefix int) {
	subnet := ipaddr.NewIPAddressString(original).GetAddress()
	iterator := subnet.SetPrefixLen(newPrefix).PrefixIterator()
	for iterator.HasNext() {
		fmt.Print(iterator.Next(), &quot; &quot;)
	}
	fmt.Println()
}

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

2001:db8::1a20/126 2001:db8::1a24/126 2001:db8::1a28/126 2001:db8::1a2c/126

huangapple
  • 本文由 发表于 2023年3月28日 15:29:30
  • 转载请务必保留本文链接:https://go.coder-hub.com/75863444.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定