1
0
mirror of https://github.com/charlienet/go-mixed.git synced 2025-07-17 16:12:42 +08:00
Files
go-mixed/ip_range/ip_range.go
2022-11-18 16:53:59 +08:00

125 lines
2.2 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 iprange
import (
"fmt"
"net/netip"
"regexp"
"strconv"
"strings"
)
var maskPattern = regexp.MustCompile(`\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b`)
type IpRange struct {
segments []ipSegment
}
type ipSegment interface {
Contains(netip.Addr) bool
}
type singleIp struct {
ip netip.Addr
}
func (i *singleIp) Contains(ip netip.Addr) bool {
return i.ip.Compare(ip) == 0
}
type prefixSegments struct {
prefix netip.Prefix
}
func (i *prefixSegments) Contains(ip netip.Addr) bool {
return i.prefix.Contains(ip)
}
type rangeSegment struct {
start netip.Addr
end netip.Addr
}
func (r *rangeSegment) Contains(ip netip.Addr) bool {
return ip.Compare(r.start) >= 0 && ip.Compare(r.end) <= 0
}
// NewRange IP范围判断支持以下规则:
// 单IP地址如 192.168.100.2
// IP范围, 如 192.168.100.120-192.168.100.150
// 掩码模式,如 192.168.2.0/24
func NewRange(ip ...string) (*IpRange, error) {
seg := make([]ipSegment, 0, len(ip))
for _, i := range ip {
if s, err := createSegment(i); err != nil {
return nil, err
} else {
seg = append(seg, s)
}
}
return &IpRange{segments: seg}, nil
}
func (r *IpRange) Contains(ip string) bool {
addr, err := netip.ParseAddr(ip)
if err != nil {
return false
}
for _, v := range r.segments {
if v.Contains(addr) {
return true
}
}
return false
}
func createSegment(ip string) (ipSegment, error) {
switch {
case strings.Contains(ip, "-"):
ips := strings.Split(ip, "-")
if len(ips) != 2 {
return nil, fmt.Errorf("IP范围定义错误:%s", ip)
}
start, err := netip.ParseAddr(ips[0])
if err != nil {
return nil, err
}
end, err := netip.ParseAddr(ips[1])
if err != nil {
return nil, err
}
return &rangeSegment{
start: start,
end: end,
}, nil
case strings.Contains(ip, "/"):
sec := strings.Split(ip, "/")
ip := sec[0]
mask := sec[1]
if maskPattern.MatchString(mask) {
mask = strconv.Itoa(MaskToBits(mask))
}
if prefix, err := netip.ParsePrefix(ip + "/" + mask); err != nil {
return nil, err
} else {
return &prefixSegments{prefix: prefix}, nil
}
default:
i, err := netip.ParseAddr(ip)
if err != nil {
return nil, fmt.Errorf("格式错误, 不是有效的IP地址:%s", ip)
}
return &singleIp{ip: i}, nil
}
}