Commit d1d4b373 authored by watermelo's avatar watermelo

Add: add net ip match function

parent 8b727f60
...@@ -18,7 +18,9 @@ ...@@ -18,7 +18,9 @@
package gxnet package gxnet
import ( import (
"log"
"net" "net"
"strconv"
"strings" "strings"
) )
...@@ -30,6 +32,12 @@ var ( ...@@ -30,6 +32,12 @@ var (
privateBlocks []*net.IPNet privateBlocks []*net.IPNet
) )
const (
AnyhostValue = "0.0.0.0"
Ipv4SplitCharacter = "."
Ipv6SplitCharacter = ":"
)
func init() { func init() {
for _, b := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"} { for _, b := range []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16"} {
if _, block, err := net.ParseCIDR(b); err == nil { if _, block, err := net.ParseCIDR(b); err == nil {
...@@ -175,3 +183,131 @@ func ListenOnUDPRandomPort(ip string) (*net.UDPConn, error) { ...@@ -175,3 +183,131 @@ func ListenOnUDPRandomPort(ip string) (*net.UDPConn, error) {
return net.ListenUDP("udp4", &localAddr) return net.ListenUDP("udp4", &localAddr)
} }
// MatchIp is used to determine whether @pattern and @host:@port match, It's supports subnet/range
func MatchIp(pattern, host, port string) bool {
// if the pattern is subnet format, it will not be allowed to config port param in pattern.
if strings.Contains(pattern, "/") {
_, subnet, _ := net.ParseCIDR(pattern)
return subnet != nil && subnet.Contains(net.ParseIP(host))
}
return matchIpRange(pattern, host, port)
}
func matchIpRange(pattern, host, port string) bool {
if pattern == "" || host == "" {
log.Print("Illegal Argument pattern or hostName. Pattern:" + pattern + ", Host:" + host)
return false
}
pattern = strings.TrimSpace(pattern)
if "*.*.*.*" == pattern || "*" == pattern {
return true
}
isIpv4 := true
ip4 := net.ParseIP(host).To4()
if ip4 == nil {
isIpv4 = false
}
hostAndPort := getPatternHostAndPort(pattern, isIpv4)
if hostAndPort[1] != "" && hostAndPort[1] != port {
return false
}
pattern = hostAndPort[0]
splitCharacter := Ipv4SplitCharacter
if !isIpv4 {
splitCharacter = Ipv6SplitCharacter
}
mask := strings.Split(pattern, splitCharacter)
// check format of pattern
if err := checkHostPattern(pattern, mask, isIpv4); err != nil {
log.Printf("gost/net check host pattern error: %s", err.Error())
return false
}
if pattern == host {
return true
}
// short name condition
if !ipPatternContains(pattern) {
return pattern == host
}
ipAddress := strings.Split(host, splitCharacter)
for i := 0; i < len(mask); i++ {
if "*" == mask[i] || mask[i] == ipAddress[i] {
continue
} else if strings.Contains(mask[i], "-") {
rangeNumStrs := strings.Split(mask[i], "-")
if len(rangeNumStrs) != 2 {
log.Print("There is wrong format of ip Address: " + mask[i])
return false
}
min := getNumOfIpSegment(rangeNumStrs[0], isIpv4)
max := getNumOfIpSegment(rangeNumStrs[1], isIpv4)
ip := getNumOfIpSegment(ipAddress[i], isIpv4)
if ip < min || ip > max {
return false
}
} else if "0" == ipAddress[i] && "0" == mask[i] || "00" == mask[i] || "000" == mask[i] || "0000" == mask[i] {
continue
} else if mask[i] != ipAddress[i] {
return false
}
}
return true
}
func ipPatternContains(pattern string) bool {
return strings.Contains(pattern, "*") || strings.Contains(pattern, "-")
}
func checkHostPattern(pattern string, mask []string, isIpv4 bool) error {
if !isIpv4 {
if len(mask) != 8 && ipPatternContains(pattern) {
return perrors.New("If you config ip expression that contains '*' or '-', please fill qualified ip pattern like 234e:0:4567:0:0:0:3d:*. ")
}
if len(mask) != 8 && !strings.Contains(pattern, "::") {
return perrors.New("The host is ipv6, but the pattern is not ipv6 pattern : " + pattern)
}
} else {
if len(mask) != 4 {
return perrors.New("The host is ipv4, but the pattern is not ipv4 pattern : " + pattern)
}
}
return nil
}
func getPatternHostAndPort(pattern string, isIpv4 bool) []string {
result := make([]string, 2)
if strings.HasPrefix(pattern, "[") && strings.Contains(pattern, "]:") {
end := strings.Index(pattern, "]:")
result[0] = pattern[1:end]
result[1] = pattern[end+2:]
} else if strings.HasPrefix(pattern, "[") && strings.HasSuffix(pattern, "]") {
result[0] = pattern[1 : len(pattern)-1]
result[1] = ""
} else if isIpv4 && strings.Contains(pattern, ":") {
end := strings.Index(pattern, ":")
result[0] = pattern[:end]
result[1] = pattern[end+1:]
} else {
result[0] = pattern
}
return result
}
func getNumOfIpSegment(ipSegment string, isIpv4 bool) int {
if isIpv4 {
ipSeg, _ := strconv.Atoi(ipSegment)
return ipSeg
}
ipSeg, _ := strconv.ParseInt(ipSegment, 0, 16)
return int(ipSeg)
}
...@@ -87,3 +87,81 @@ func TestListenOnUDPRandomPort(t *testing.T) { ...@@ -87,3 +87,81 @@ func TestListenOnUDPRandomPort(t *testing.T) {
l.Close() l.Close()
} }
} }
func TestMatchIpIpv4Equal(t *testing.T) {
flag := MatchIp("192.168.0.1:8080", "192.168.0.1", "8080")
assert.True(t, flag)
flag = MatchIp("*", "192.168.0.1", "8080")
assert.True(t, flag)
flag = MatchIp("*", "192.168.0.1", "")
assert.True(t, flag)
flag = MatchIp("*.*.*.*", "192.168.0.1", "8080")
assert.True(t, flag)
flag = MatchIp("*", "", "")
assert.False(t, flag)
}
func TestMatchIpIpv4Subnet(t *testing.T) {
flag := MatchIp("206.0.68.0/23", "206.0.68.123", "8080")
assert.True(t, flag)
flag = MatchIp("206.0.68.0/23", "207.0.69.123", "8080")
assert.False(t, flag)
}
func TestMatchIpIpv4Range(t *testing.T) {
flag := MatchIp("206.*.68.0", "206.0.68.0", "8080")
assert.True(t, flag)
flag = MatchIp("206.*.68.0", "206.0.69.0", "8080")
assert.False(t, flag)
flag = MatchIp("206.0.68-69.0", "206.0.68.0", "8080")
assert.True(t, flag)
flag = MatchIp("206.0.68-69.0", "206.0.70.0", "8080")
assert.False(t, flag)
}
func TestMatchIpIpv6Equal(t *testing.T) {
flag := MatchIp("[1fff:0:a88:85a3::ac1f]:8080", "1fff:0:a88:85a3::ac1f", "8080")
assert.True(t, flag)
flag = MatchIp("*", "1fff:0:a88:85a3::ac1f", "8080")
assert.True(t, flag)
flag = MatchIp("*", "1fff:0:a88:85a3::ac1f", "")
assert.True(t, flag)
flag = MatchIp("*.*.*.*", "1fff:0:a88:85a3::ac1f", "8080")
assert.True(t, flag)
flag = MatchIp("*", "", "")
assert.False(t, flag)
}
func TestMatchIpIpv6Subnet(t *testing.T) {
flag := MatchIp("1fff:0:a88:85a3::ac1f/64", "1fff:0000:0a88:85a3:0000:0000:0000:0000", "8080")
assert.True(t, flag)
flag = MatchIp("1fff:0:a88:85a3::ac1f/64", "2fff:0000:0a88:85a3:0000:0000:0000:0000", "8080")
assert.False(t, flag)
}
func TestMatchIpIpv6Range(t *testing.T) {
flag := MatchIp("234e:0:4567:0:0:0:3d:*", "234e:0:4567:0:0:0:3d:4", "8080")
assert.True(t, flag)
flag = MatchIp("234e:0:4567:0:0:0:3d:*", "234e:0:4567:0:0:0:2d:4", "8080")
assert.False(t, flag)
flag = MatchIp("234e:0:4567:0:0:0:3d:1-2", "234e:0:4567:0:0:0:3d:1", "8080")
assert.True(t, flag)
flag = MatchIp("234e:0:4567:0:0:0:3d:1-2", "234e:0:4567:0:0:0:3d:3", "8080")
assert.False(t, flag)
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment