-
Notifications
You must be signed in to change notification settings - Fork 10
/
ips.go
143 lines (122 loc) · 2.46 KB
/
ips.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
package utils
import (
"net"
)
// IsIPv4 works the same way as net.ParseIP,
// but without check for IPv6 case and without returning net.IP slice, whereby IsIPv4 makes no allocations.
func IsIPv4(s string) bool {
for i := 0; i < net.IPv4len; i++ {
if len(s) == 0 {
return false
}
if i > 0 {
if s[0] != '.' {
return false
}
s = s[1:]
}
n, ci := 0, 0
for ci = 0; ci < len(s) && '0' <= s[ci] && s[ci] <= '9'; ci++ {
n = n*10 + int(s[ci]-'0')
if n > 0xFF {
return false
}
}
if ci == 0 || (ci > 1 && s[0] == '0') {
return false
}
s = s[ci:]
}
return len(s) == 0
}
// IsIPv6 works the same way as net.ParseIP,
// but without check for IPv4 case and without returning net.IP slice, whereby IsIPv6 makes no allocations.
func IsIPv6(s string) bool {
ellipsis := -1 // position of ellipsis in ip
// Might have leading ellipsis
if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
ellipsis = 0
s = s[2:]
// Might be only ellipsis
if len(s) == 0 {
return true
}
}
// Loop, parsing hex numbers followed by colon.
i := 0
for i < net.IPv6len {
// Hex number.
n, ci := 0, 0
for ci = 0; ci < len(s); ci++ {
if '0' <= s[ci] && s[ci] <= '9' {
n *= 16
n += int(s[ci] - '0')
} else if 'a' <= s[ci] && s[ci] <= 'f' {
n *= 16
n += int(s[ci]-'a') + 10
} else if 'A' <= s[ci] && s[ci] <= 'F' {
n *= 16
n += int(s[ci]-'A') + 10
} else {
break
}
if n > 0xFFFF {
return false
}
}
if ci == 0 || n > 0xFFFF {
return false
}
if ci < len(s) && s[ci] == '.' {
if ellipsis < 0 && i != net.IPv6len-net.IPv4len {
return false
}
if i+net.IPv4len > net.IPv6len {
return false
}
if !IsIPv4(s) {
return false
}
s = ""
i += net.IPv4len
break
}
// Save this 16-bit chunk.
i += 2
// Stop at end of string.
s = s[ci:]
if len(s) == 0 {
break
}
// Otherwise must be followed by colon and more.
if s[0] != ':' || len(s) == 1 {
return false
}
s = s[1:]
// Look for ellipsis.
if s[0] == ':' {
if ellipsis >= 0 { // already have one
return false
}
ellipsis = i
s = s[1:]
if len(s) == 0 { // can be at end
break
}
}
}
// Must have used entire string.
if len(s) != 0 {
return false
}
// If didn't parse enough, expand ellipsis.
if i < net.IPv6len {
if ellipsis < 0 {
return false
}
} else if ellipsis >= 0 {
// Ellipsis must represent at least one 0 group.
return false
}
return true
}