Files
alpine-router/network/overlap.go
2026-04-15 11:38:26 +03:00

87 lines
1.7 KiB
Go

package network
import (
"fmt"
"net"
)
type SubnetOverlap struct {
Interface string `json:"interface"`
Subnet string `json:"subnet"`
Label string `json:"label,omitempty"`
}
func parseIPNet(ipStr, maskStr string) (*net.IPNet, error) {
ip := net.ParseIP(ipStr)
if ip == nil {
return nil, fmt.Errorf("invalid IP: %s", ipStr)
}
ip = ip.To4()
if ip == nil {
return nil, fmt.Errorf("invalid IPv4: %s", ipStr)
}
mask := ipMaskFromString(maskStr)
if mask == nil {
return nil, fmt.Errorf("invalid netmask: %s", maskStr)
}
return &net.IPNet{IP: ip.Mask(mask), Mask: mask}, nil
}
func ipMaskFromString(maskStr string) net.IPMask {
m := net.ParseIP(maskStr)
if m != nil {
if m4 := m.To4(); m4 != nil {
return net.IPMask(m4)
}
}
return nil
}
func subnetsOverlap(a, b *net.IPNet) bool {
return a.Contains(b.IP) || b.Contains(a.IP)
}
func CheckOverlap(newIP, newMask, excludeIface string, existing []SubnetOverlap) []SubnetOverlap {
newNet, err := parseIPNet(newIP, newMask)
if err != nil {
return nil
}
var result []SubnetOverlap
for _, s := range existing {
if s.Interface == excludeIface {
continue
}
parts, err := parseSubnetStr(s.Subnet)
if err != nil {
continue
}
existingNet, err := parseIPNet(parts[0], parts[1])
if err != nil {
continue
}
if subnetsOverlap(newNet, existingNet) {
result = append(result, s)
}
}
return result
}
func ParseSubnet(ipStr, maskStr string) (string, error) {
n, err := parseIPNet(ipStr, maskStr)
if err != nil {
return "", err
}
return n.String(), nil
}
func parseSubnetStr(s string) ([2]string, error) {
for i := len(s) - 1; i >= 0; i-- {
if s[i] == '/' {
return [2]string{s[:i], s[i+1:]}, nil
}
}
return [2]string{}, fmt.Errorf("invalid subnet format: %s", s)
}