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