-
Notifications
You must be signed in to change notification settings - Fork 6
/
net.go
173 lines (157 loc) · 3.21 KB
/
net.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
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
package fasttld
import "unicode/utf8"
// IP address lengths (bytes).
const (
iPv4len int = 4
iPv6len int = 16
lenDiff = iPv6len - iPv4len
)
// Bigger than we need, not too big to worry about overflow
const big int = 0xFFFFFF
// Decimal to integer.
// Returns number, characters consumed, success.
func dtoi(s string) (n int, i int, ok bool) {
n = 0
for i = 0; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
n = n*10 + int(s[i]-'0')
if n >= big {
return big, i, false
}
}
if i == 0 {
return 0, 0, false
}
return n, i, true
}
// Hexadecimal to integer.
// Returns number, characters consumed, success.
func xtoi(s string) (n int, i int, ok bool) {
n = 0
for i = 0; i < len(s); i++ {
if '0' <= s[i] && s[i] <= '9' {
n *= 16
n += int(s[i] - '0')
} else if 'a' <= s[i] && s[i] <= 'f' {
n *= 16
n += int(s[i]-'a') + 10
} else if 'A' <= s[i] && s[i] <= 'F' {
n *= 16
n += int(s[i]-'A') + 10
} else {
break
}
if n >= big {
return 0, i, false
}
}
if i == 0 {
return 0, i, false
}
return n, i, true
}
// isIPv4 returns true if s is a literal IPv4 address
//
// trailing label separators are accepted
func isIPv4(s string) bool {
s = fastTrim(s, labelSeparatorsRuneSet, trimRight)
for i := 0; i < iPv4len; i++ {
if len(s) == 0 {
// Missing octets.
return false
}
if i > 0 {
r, size := utf8.DecodeRuneInString(s)
if !labelSeparatorsRuneSet.Exists(r) {
return false
}
s = s[size:]
}
n, c, ok := dtoi(s)
if !ok || n > 0xFF {
return false
}
if c > 1 && s[0] == '0' {
// Reject non-zero components with leading zeroes.
return false
}
s = s[c:]
}
return len(s) == 0
}
// isIPv6 returns true if s is a literal IPv6 address as described in RFC 4291
// and RFC 5952.
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 < iPv6len {
// Hex number.
n, c, ok := xtoi(s)
if !ok || n > 0xFFFF {
return false
}
// If followed by any separator in labelSeparators, might be in trailing IPv4.
if c < len(s) && labelSeparatorsRuneSet.Exists([]rune(s[c:])[0]) {
if ellipsis < 0 && i != lenDiff {
// Not the right place.
return false
}
if i > lenDiff {
// Not enough room.
return false
}
if !isIPv4(s) {
return false
}
s = ""
i += iPv4len
break
}
// Save this 16-bit chunk.
i += 2
// Stop at end of string.
s = s[c:]
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 < iPv6len {
if ellipsis < 0 {
return false
}
} else if ellipsis >= 0 {
// Ellipsis must represent at least one 0 group.
return false
}
return true
}