-
Notifications
You must be signed in to change notification settings - Fork 3
/
ip_range.go
147 lines (127 loc) · 3.29 KB
/
ip_range.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
package shared
import (
"bytes"
"errors"
"github.com/iwind/TeaGo/utils/string"
"net"
"regexp"
"strings"
)
// IPRangeType IP Range类型
type IPRangeType = int
const (
IPRangeTypeRange IPRangeType = 1
IPRangeTypeCIDR IPRangeType = 2
IPRangeTypeAll IPRangeType = 3
IPRangeTypeWildcard IPRangeType = 4 // 通配符,可以使用*
)
// IPRangeConfig IP Range
type IPRangeConfig struct {
Id string `yaml:"id" json:"id"`
Type IPRangeType `yaml:"type" json:"type"`
Param string `yaml:"param" json:"param"`
CIDR string `yaml:"cidr" json:"cidr"`
IPFrom string `yaml:"ipFrom" json:"ipFrom"`
IPTo string `yaml:"ipTo" json:"ipTo"`
cidr *net.IPNet
ipFrom net.IP
ipTo net.IP
reg *regexp.Regexp
}
// NewIPRangeConfig 获取新对象
func NewIPRangeConfig() *IPRangeConfig {
return &IPRangeConfig{
Id: stringutil.Rand(16),
}
}
// ParseIPRange 从字符串中分析
func ParseIPRange(s string) (*IPRangeConfig, error) {
if len(s) == 0 {
return nil, errors.New("invalid ip range")
}
ipRange := &IPRangeConfig{}
if s == "*" || s == "all" || s == "ALL" || s == "0.0.0.0" {
ipRange.Type = IPRangeTypeAll
return ipRange, nil
}
if strings.Contains(s, "/") {
ipRange.Type = IPRangeTypeCIDR
ipRange.CIDR = strings.Replace(s, " ", "", -1)
} else if strings.Contains(s, "-") {
ipRange.Type = IPRangeTypeRange
pieces := strings.SplitN(s, "-", 2)
ipRange.IPFrom = strings.TrimSpace(pieces[0])
ipRange.IPTo = strings.TrimSpace(pieces[1])
} else if strings.Contains(s, ",") {
ipRange.Type = IPRangeTypeRange
pieces := strings.SplitN(s, ",", 2)
ipRange.IPFrom = strings.TrimSpace(pieces[0])
ipRange.IPTo = strings.TrimSpace(pieces[1])
} else if strings.Contains(s, "*") {
ipRange.Type = IPRangeTypeWildcard
s = "^" + strings.Replace(regexp.QuoteMeta(s), `\*`, `\d+`, -1) + "$"
ipRange.reg = regexp.MustCompile(s)
} else {
ipRange.Type = IPRangeTypeRange
ipRange.IPFrom = s
ipRange.IPTo = s
}
err := ipRange.Init()
if err != nil {
return nil, err
}
return ipRange, nil
}
// Init 初始化校验
func (this *IPRangeConfig) Init() error {
if this.Type == IPRangeTypeCIDR {
if len(this.CIDR) == 0 {
return errors.New("cidr should not be empty")
}
_, cidr, err := net.ParseCIDR(this.CIDR)
if err != nil {
return err
}
this.cidr = cidr
}
if this.Type == IPRangeTypeRange {
this.ipFrom = net.ParseIP(this.IPFrom)
this.ipTo = net.ParseIP(this.IPTo)
if this.ipFrom.To4() == nil && this.ipFrom.To16() == nil {
return errors.New("from ip should in IPv4 or IPV6 format")
}
if this.ipTo.To4() == nil && this.ipTo.To16() == nil {
return errors.New("to ip should in IPv4 or IPV6 format")
}
}
return nil
}
// Contains 是否包含某个IP
func (this *IPRangeConfig) Contains(ipString string) bool {
ip := net.ParseIP(ipString)
if ip == nil {
return false
}
if this.Type == IPRangeTypeCIDR {
if this.cidr == nil {
return false
}
return this.cidr.Contains(ip)
}
if this.Type == IPRangeTypeRange {
if this.ipFrom == nil || this.ipTo == nil {
return false
}
return bytes.Compare(ip, this.ipFrom) >= 0 && bytes.Compare(ip, this.ipTo) <= 0
}
if this.Type == IPRangeTypeWildcard {
if this.reg == nil {
return false
}
return this.reg.MatchString(ipString)
}
if this.Type == IPRangeTypeAll {
return true
}
return false
}