base-golang/pkg/cidr/calc.go
2024-07-23 10:23:43 +08:00

120 lines
2.3 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
})
}