first commit
This commit is contained in:
		
							
								
								
									
										119
									
								
								pkg/cidr/calc.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										119
									
								
								pkg/cidr/calc.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,119 @@
 | 
			
		||||
package cidr
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"bytes"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math"
 | 
			
		||||
	"net"
 | 
			
		||||
	"sort"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// SuperNetting 合并网段
 | 
			
		||||
func SuperNetting(ns []string) (*cidr, error) {
 | 
			
		||||
	num := len(ns)
 | 
			
		||||
	if num < 1 || (num&(num-1)) != 0 {
 | 
			
		||||
		return nil, fmt.Errorf("子网数量必须是2的次方")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	mask := ""
 | 
			
		||||
	var cidrs []*cidr
 | 
			
		||||
	for _, n := range ns {
 | 
			
		||||
		// 检查子网CIDR有效性
 | 
			
		||||
		c, err := ParseCIDR(n)
 | 
			
		||||
		if err != nil {
 | 
			
		||||
			return nil, fmt.Errorf("网段%v格式错误", n)
 | 
			
		||||
		}
 | 
			
		||||
		cidrs = append(cidrs, c)
 | 
			
		||||
 | 
			
		||||
		// TODO 暂只考虑相同子网掩码的网段合并
 | 
			
		||||
		if len(mask) == 0 {
 | 
			
		||||
			mask = c.Mask()
 | 
			
		||||
		} else if c.Mask() != mask {
 | 
			
		||||
			return nil, fmt.Errorf("子网掩码不一致")
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
	AscSortCIDRs(cidrs)
 | 
			
		||||
 | 
			
		||||
	// 检查网段是否连续
 | 
			
		||||
	var network net.IP
 | 
			
		||||
	for _, c := range cidrs {
 | 
			
		||||
		if len(network) > 0 {
 | 
			
		||||
			if !network.Equal(c.ipNet.IP) {
 | 
			
		||||
				return nil, fmt.Errorf("必须是连续的网段")
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		network = net.ParseIP(c.Broadcast())
 | 
			
		||||
		IncrIP(network)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	// 子网掩码左移,得到共同的父网段
 | 
			
		||||
	c := cidrs[0]
 | 
			
		||||
	ones, bits := c.MaskSize()
 | 
			
		||||
	ones = ones - int(math.Log2(float64(num)))
 | 
			
		||||
	c.ipNet.Mask = net.CIDRMask(ones, bits)
 | 
			
		||||
	c.ipNet.IP.Mask(c.ipNet.Mask)
 | 
			
		||||
 | 
			
		||||
	return c, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IncrIP IP地址自增
 | 
			
		||||
func IncrIP(ip net.IP) {
 | 
			
		||||
	for i := len(ip) - 1; i >= 0; i-- {
 | 
			
		||||
		ip[i]++
 | 
			
		||||
		if ip[i] > 0 {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DecrIP IP地址自减
 | 
			
		||||
func DecrIP(ip net.IP) {
 | 
			
		||||
	length := len(ip)
 | 
			
		||||
	for i := length - 1; i >= 0; i-- {
 | 
			
		||||
		ip[length-1]--
 | 
			
		||||
		if ip[length-1] < 0xFF {
 | 
			
		||||
			break
 | 
			
		||||
		}
 | 
			
		||||
		for j := 1; j < length; j++ {
 | 
			
		||||
			ip[length-j-1]--
 | 
			
		||||
			if ip[length-j-1] < 0xFF {
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Compare 比较IP大小 a等于b,返回0; a大于b,返回+1; a小于b,返回-1
 | 
			
		||||
func Compare(a, b net.IP) int {
 | 
			
		||||
	return bytes.Compare(a, b)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// AscSortCIDRs 升序
 | 
			
		||||
func AscSortCIDRs(cs []*cidr) {
 | 
			
		||||
	sort.Slice(cs, func(i, j int) bool {
 | 
			
		||||
		if n := bytes.Compare(cs[i].ipNet.IP, cs[j].ipNet.IP); n != 0 {
 | 
			
		||||
			return n < 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if n := bytes.Compare(cs[i].ipNet.Mask, cs[j].ipNet.Mask); n != 0 {
 | 
			
		||||
			return n < 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return false
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// DescSortCIDRs 降序
 | 
			
		||||
func DescSortCIDRs(cs []*cidr) {
 | 
			
		||||
	sort.Slice(cs, func(i, j int) bool {
 | 
			
		||||
		if n := bytes.Compare(cs[i].ipNet.IP, cs[j].ipNet.IP); n != 0 {
 | 
			
		||||
			return n >= 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if n := bytes.Compare(cs[i].ipNet.Mask, cs[j].ipNet.Mask); n != 0 {
 | 
			
		||||
			return n >= 0
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return false
 | 
			
		||||
	})
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										194
									
								
								pkg/cidr/ip.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										194
									
								
								pkg/cidr/ip.go
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,194 @@
 | 
			
		||||
package cidr
 | 
			
		||||
 | 
			
		||||
import (
 | 
			
		||||
	"encoding/hex"
 | 
			
		||||
	"fmt"
 | 
			
		||||
	"math"
 | 
			
		||||
	"math/big"
 | 
			
		||||
	"net"
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
// 裂解子网的方式
 | 
			
		||||
const (
 | 
			
		||||
	MethodSubnetNum = 0 // 基于子网数量
 | 
			
		||||
	MethodHostNum   = 1 // 基于主机数量
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
var _ CIDR = (*cidr)(nil)
 | 
			
		||||
 | 
			
		||||
type CIDR interface {
 | 
			
		||||
	CIDR() string
 | 
			
		||||
	IP() string
 | 
			
		||||
	Network() string
 | 
			
		||||
	Broadcast() string
 | 
			
		||||
	Mask() string
 | 
			
		||||
	MaskSize() (int, int)
 | 
			
		||||
	IPRange() (string, string)
 | 
			
		||||
	IPCount() *big.Int
 | 
			
		||||
 | 
			
		||||
	IsIPv4() bool
 | 
			
		||||
	IsIPv6() bool
 | 
			
		||||
 | 
			
		||||
	Equal(string) bool
 | 
			
		||||
	Contains(string) bool
 | 
			
		||||
	ForEachIP(func(string) error) error
 | 
			
		||||
	ForEachIPBeginWith(string, func(string) error) error
 | 
			
		||||
	SubNetting(method, num int) ([]*cidr, error)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
type cidr struct {
 | 
			
		||||
	ip    net.IP
 | 
			
		||||
	ipNet *net.IPNet
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ParseCIDR 解析CIDR网段
 | 
			
		||||
func ParseCIDR(s string) (*cidr, error) {
 | 
			
		||||
	i, n, err := net.ParseCIDR(s)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return nil, err
 | 
			
		||||
	}
 | 
			
		||||
	return &cidr{ip: i, ipNet: n}, nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Equal 判断网段是否相等
 | 
			
		||||
func (c *cidr) Equal(ns string) bool {
 | 
			
		||||
	c2, err := ParseCIDR(ns)
 | 
			
		||||
	if err != nil {
 | 
			
		||||
		return false
 | 
			
		||||
	}
 | 
			
		||||
	return c.ipNet.IP.Equal(c2.ipNet.IP) /* && c.ipNet.IP.Equal(c2.ip) */
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsIPv4 判断是否IPv4
 | 
			
		||||
func (c *cidr) IsIPv4() bool {
 | 
			
		||||
	_, bits := c.ipNet.Mask.Size()
 | 
			
		||||
	return bits/8 == net.IPv4len
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IsIPv6 判断是否IPv6
 | 
			
		||||
func (c *cidr) IsIPv6() bool {
 | 
			
		||||
	_, bits := c.ipNet.Mask.Size()
 | 
			
		||||
	return bits/8 == net.IPv6len
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Contains 判断IP是否包含在网段中
 | 
			
		||||
func (c *cidr) Contains(ip string) bool {
 | 
			
		||||
	return c.ipNet.Contains(net.ParseIP(ip))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// CIDR 根据子网掩码长度校准后的CIDR
 | 
			
		||||
func (c *cidr) CIDR() string {
 | 
			
		||||
	return c.ipNet.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IP CIDR字符串中的IP部分
 | 
			
		||||
func (c *cidr) IP() string {
 | 
			
		||||
	return c.ip.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Network 网络号
 | 
			
		||||
func (c *cidr) Network() string {
 | 
			
		||||
	return c.ipNet.IP.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// MaskSize 子网掩码位数
 | 
			
		||||
func (c *cidr) MaskSize() (ones, bits int) {
 | 
			
		||||
	ones, bits = c.ipNet.Mask.Size()
 | 
			
		||||
	return
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Mask 子网掩码
 | 
			
		||||
func (c *cidr) Mask() string {
 | 
			
		||||
	mask, _ := hex.DecodeString(c.ipNet.Mask.String())
 | 
			
		||||
	return net.IP([]byte(mask)).String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Broadcast 广播地址(网段最后一个IP)
 | 
			
		||||
func (c *cidr) Broadcast() string {
 | 
			
		||||
	mask := c.ipNet.Mask
 | 
			
		||||
	bcst := make(net.IP, len(c.ipNet.IP))
 | 
			
		||||
	copy(bcst, c.ipNet.IP)
 | 
			
		||||
	for i := 0; i < len(mask); i++ {
 | 
			
		||||
		ipIdx := len(bcst) - i - 1
 | 
			
		||||
		bcst[ipIdx] = c.ipNet.IP[ipIdx] | ^mask[len(mask)-i-1]
 | 
			
		||||
	}
 | 
			
		||||
	return bcst.String()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IPRange 起始IP、结束IP
 | 
			
		||||
func (c *cidr) IPRange() (start, end string) {
 | 
			
		||||
	return c.Network(), c.Broadcast()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// IPCount IP数量
 | 
			
		||||
func (c *cidr) IPCount() *big.Int {
 | 
			
		||||
	ones, bits := c.ipNet.Mask.Size()
 | 
			
		||||
	return big.NewInt(0).Lsh(big.NewInt(1), uint(bits-ones))
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ForEachIP 遍历网段下所有IP
 | 
			
		||||
func (c *cidr) ForEachIP(iterator func(ip string) error) error {
 | 
			
		||||
	next := make(net.IP, len(c.ipNet.IP))
 | 
			
		||||
	copy(next, c.ipNet.IP)
 | 
			
		||||
	for c.ipNet.Contains(next) {
 | 
			
		||||
		if err := iterator(next.String()); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		IncrIP(next)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// ForEachIPBeginWith 从指定IP开始遍历网段下后续的IP
 | 
			
		||||
func (c *cidr) ForEachIPBeginWith(beginIP string, iterator func(ip string) error) error {
 | 
			
		||||
	next := net.ParseIP(beginIP)
 | 
			
		||||
	for c.ipNet.Contains(next) {
 | 
			
		||||
		if err := iterator(next.String()); err != nil {
 | 
			
		||||
			return err
 | 
			
		||||
		}
 | 
			
		||||
		IncrIP(next)
 | 
			
		||||
	}
 | 
			
		||||
	return nil
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// SubNetting 裂解网段
 | 
			
		||||
func (c *cidr) SubNetting(method, num int) ([]*cidr, error) {
 | 
			
		||||
	if num < 1 || (num&(num-1)) != 0 {
 | 
			
		||||
		return nil, fmt.Errorf("裂解数量必须是2的次方")
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	newOnes := int(math.Log2(float64(num)))
 | 
			
		||||
	ones, bits := c.MaskSize()
 | 
			
		||||
	switch method {
 | 
			
		||||
	default:
 | 
			
		||||
		return nil, fmt.Errorf("不支持的裂解方式")
 | 
			
		||||
	case MethodSubnetNum:
 | 
			
		||||
		newOnes = ones + newOnes
 | 
			
		||||
		// 如果子网的掩码长度大于父网段的长度,则无法裂解
 | 
			
		||||
		if newOnes > bits {
 | 
			
		||||
			return nil, nil
 | 
			
		||||
		}
 | 
			
		||||
	case MethodHostNum:
 | 
			
		||||
		newOnes = bits - newOnes
 | 
			
		||||
		// 如果子网的掩码长度小于等于父网段的掩码长度,则无法裂解
 | 
			
		||||
		if newOnes <= ones {
 | 
			
		||||
			return nil, nil
 | 
			
		||||
		}
 | 
			
		||||
		// 主机数量转换为子网数量
 | 
			
		||||
		num = int(math.Pow(float64(2), float64(newOnes-ones)))
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var cidrs []*cidr
 | 
			
		||||
	network := make(net.IP, len(c.ipNet.IP))
 | 
			
		||||
	copy(network, c.ipNet.IP)
 | 
			
		||||
	for i := 0; i < num; i++ {
 | 
			
		||||
		cidr, _ := ParseCIDR(fmt.Sprintf("%v/%v", network.String(), newOnes))
 | 
			
		||||
		cidrs = append(cidrs, cidr)
 | 
			
		||||
 | 
			
		||||
		// 广播地址的下一个IP即为下一段的网络号
 | 
			
		||||
		network = net.ParseIP(cidr.Broadcast())
 | 
			
		||||
		IncrIP(network)
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	return cidrs, nil
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user