Skip to content

Commit

Permalink
refactor: ParseIPx() supports big.Int conversion to ipv6
Browse files Browse the repository at this point in the history
  • Loading branch information
fufuok committed Mar 15, 2024
1 parent 22e0563 commit eafadf5
Show file tree
Hide file tree
Showing 3 changed files with 96 additions and 30 deletions.
62 changes: 49 additions & 13 deletions ip.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ import (
"strings"
)

const (
IPv4Min = 0
IPv4Max = 1<<32 - 1
)

var (
ErrInvalidHostPort = errors.New("invalid Host or Port")
)
Expand Down Expand Up @@ -138,7 +143,7 @@ func Int2IPv6(ipInt *big.Int) net.IP {

// Long2IPv4 数值转 IPv4
func Long2IPv4(n int) net.IP {
if n > 4294967295 || n < 0 {
if n > IPv4Max || n < 0 {
return nil
}

Expand All @@ -152,7 +157,7 @@ func Long2IPv4(n int) net.IP {

// LongLittle2IPv4 小端数值转 IPv4
func LongLittle2IPv4(n int) net.IP {
if n > 4294967295 || n < 0 {
if n > IPv4Max || n < 0 {
return nil
}

Expand Down Expand Up @@ -280,30 +285,61 @@ func ParseIP(s string) (net.IP, bool) {
return ip, strings.Contains(s, ":")
}

// ParseIPx 解析 IP, 包括数字形态
func ParseIPx(s string) net.IP {
// ParseIPx 解析 IP, 并返回是否为 IPv6
func ParseIPx(s string) (net.IP, bool) {
if s == "" {
return nil
return nil, false
}

for i := 0; i < len(s); i++ {
char := s[i]
if char == '.' {
return net.ParseIP(s), false
}
if char == ':' {
return net.ParseIP(s), true
}
}
return nil, false
}

// ParseIPxWithNumeric 解析 IP, 支持数字形态, 并返回是否为 IPv6
func ParseIPxWithNumeric(s string) (net.IP, bool) {
if s == "" {
return nil, false
}

allNumeric := true
for i := 0; i < len(s); i++ {
char := s[i]
if char == '.' || char == ':' {
return net.ParseIP(s)
if char == '.' {
return net.ParseIP(s), false
}
if char == ':' {
return net.ParseIP(s), true
}
if char < '0' || char > '9' {
allNumeric = false
}
}

// 数字转 IPv4
if allNumeric {
if n, err := strconv.Atoi(s); err == nil {
return Long2IPv4(n)
}
if !allNumeric {
return nil, false
}
return nil

// 数字转 IP, 优先转换为 IPv4
n, err := strconv.Atoi(s)
if err == nil && n <= IPv4Max {
return Long2IPv4(n), false
}

if n < 0 {
return nil, false
}

i := big.NewInt(0)
i.SetString(s, 10)
return Int2IPv6(i), true
}

// ParseHostPort 解析 IP 和端口
Expand Down
62 changes: 45 additions & 17 deletions ip_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ func TestIPv4AndLong(t *testing.T) {
{"0.0.0.1", 1},
{"1.2.3.4", 16909060},
{"10.0.0.0", 167772160},
{"255.255.255.255", 4294967295},
{"255.255.255.255", IPv4Max},
{"", -1},
} {
assert.Equal(t, v.long, IPv4String2Long(v.ipv4))
Expand All @@ -76,7 +76,7 @@ func TestIPv4AndLong(t *testing.T) {
// Equal(t, 151060737, IPv4String2Long("009.001.01.1"))
assert.Equal(t, -1, IPv4String2Long("ff"))
assert.Equal(t, -1, IPv4String2Long("255.255.255.256"))
assert.Equal(t, "", Long2IPv4String(4294967296))
assert.Equal(t, "", Long2IPv4String(IPv4Max+1))
}

func TestIPv6AndInt(t *testing.T) {
Expand Down Expand Up @@ -269,24 +269,52 @@ func TestParseHostPort(t *testing.T) {

func TestParseIPx(t *testing.T) {
tests := []struct {
s string
isNil bool
s string
isNil bool
isIPv6 bool
}{
{"", true},
{" 0.0.0.0", true},
{"[2001::]", true},
{"4294967296", true},
{"-1", true},
{"", true, false},
{" 0.0.0.0", true, false},
{"[2001::]", true, true},
{"-1", true, false},
{"abc", true, false},

{"0.0.0.0", false},
{"255.255.255.255", false},
{"::1", false},
{"::ffff:0.0.0.0", false},
{"2001:4860:4860::8888", false},
{"0", false},
{"4294967295", false},
{"0.0.0.0", false, false},
{"255.255.255.255", false, false},
{"::1", false, true},
{"::ffff:0.0.0.0", false, true},
{"2001:4860:4860::8888", false, true},
{"ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", false, true},
}
for _, v := range tests {
ip, isIPv6 := ParseIPx(v.s)
assert.Equal(t, v.isNil, ip == nil)
assert.Equal(t, v.isIPv6, isIPv6)

ip, isIPv6 = ParseIPxWithNumeric(v.s)
assert.Equal(t, v.isNil, ip == nil)
assert.Equal(t, v.isIPv6, isIPv6)
}

ip, isIPv6 := ParseIPx("0")
assert.Nil(t, ip)
assert.False(t, isIPv6)

tests = []struct {
s string
isNil bool
isIPv6 bool
}{
{"-1", true, false},
{"0", false, false},
{"4294967295", false, false},
{"4294967296", false, true},
{"340282366920938463463374607431768211455", false, true},
{"340282366920938463463374607431768211456", true, true},
}
for _, v := range tests {
assert.Equal(t, v.isNil, ParseIPx(v.s) == nil)
ip, isIPv6 = ParseIPxWithNumeric(v.s)
assert.Equal(t, v.isNil, ip == nil)
assert.Equal(t, v.isIPv6, isIPv6)
}
}
2 changes: 2 additions & 0 deletions strings.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ func AddString(s ...string) string {
}

// SearchString 搜索字符串位置(左, 第一个)
// 用 slices.Index 替代
func SearchString(ss []string, s string) int {
for i := range ss {
if s == ss[i] {
Expand All @@ -137,6 +138,7 @@ func SearchString(ss []string, s string) int {
}

// InStrings 检查字符串是否存在于 slice
// 用 slices.Contains 替代
func InStrings(ss []string, s string) bool {
return SearchString(ss, s) != -1
}
Expand Down

0 comments on commit eafadf5

Please sign in to comment.