]>
Commit | Line | Data |
---|---|---|
7a938933 ILT |
1 | // Copyright 2009 The Go Authors. All rights reserved. |
2 | // Use of this source code is governed by a BSD-style | |
3 | // license that can be found in the LICENSE file. | |
4 | ||
5 | // IP address manipulations | |
6 | // | |
7 | // IPv4 addresses are 4 bytes; IPv6 addresses are 16 bytes. | |
8 | // An IPv4 address can be converted to an IPv6 address by | |
9 | // adding a canonical prefix (10 zeros, 2 0xFFs). | |
d6f2922e | 10 | // This library accepts either size of byte slice but always |
7a938933 ILT |
11 | // returns 16-byte addresses. |
12 | ||
13 | package net | |
14 | ||
4f4a855d | 15 | import "internal/bytealg" |
bc998d03 | 16 | |
7a938933 ILT |
17 | // IP address lengths (bytes). |
18 | const ( | |
19 | IPv4len = 4 | |
20 | IPv6len = 16 | |
21 | ) | |
22 | ||
d6f2922e | 23 | // An IP is a single IP address, a slice of bytes. |
d8f41257 | 24 | // Functions in this package accept either 4-byte (IPv4) |
d6f2922e | 25 | // or 16-byte (IPv6) slices as input. |
7a938933 ILT |
26 | // |
27 | // Note that in this documentation, referring to an | |
28 | // IP address as an IPv4 address or an IPv6 address | |
29 | // is a semantic property of the address, not just the | |
d6f2922e | 30 | // length of the byte slice: a 16-byte slice can still |
7a938933 ILT |
31 | // be an IPv4 address. |
32 | type IP []byte | |
33 | ||
5a8ea165 ILT |
34 | // An IPMask is a bitmask that can be used to manipulate |
35 | // IP addresses for IP addressing and routing. | |
36 | // | |
37 | // See type IPNet and func ParseCIDR for details. | |
7a938933 ILT |
38 | type IPMask []byte |
39 | ||
d8f41257 ILT |
40 | // An IPNet represents an IP network. |
41 | type IPNet struct { | |
42 | IP IP // network number | |
43 | Mask IPMask // network mask | |
44 | } | |
45 | ||
7a938933 ILT |
46 | // IPv4 returns the IP address (in 16-byte form) of the |
47 | // IPv4 address a.b.c.d. | |
48 | func IPv4(a, b, c, d byte) IP { | |
49 | p := make(IP, IPv6len) | |
8039ca76 | 50 | copy(p, v4InV6Prefix) |
7a938933 ILT |
51 | p[12] = a |
52 | p[13] = b | |
53 | p[14] = c | |
54 | p[15] = d | |
55 | return p | |
56 | } | |
57 | ||
8039ca76 ILT |
58 | var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff} |
59 | ||
d8f41257 | 60 | // IPv4Mask returns the IP mask (in 4-byte form) of the |
7a938933 ILT |
61 | // IPv4 mask a.b.c.d. |
62 | func IPv4Mask(a, b, c, d byte) IPMask { | |
d8f41257 ILT |
63 | p := make(IPMask, IPv4len) |
64 | p[0] = a | |
65 | p[1] = b | |
66 | p[2] = c | |
67 | p[3] = d | |
7a938933 ILT |
68 | return p |
69 | } | |
70 | ||
5a8ea165 ILT |
71 | // CIDRMask returns an IPMask consisting of 'ones' 1 bits |
72 | // followed by 0s up to a total length of 'bits' bits. | |
d8f41257 ILT |
73 | // For a mask of this form, CIDRMask is the inverse of IPMask.Size. |
74 | func CIDRMask(ones, bits int) IPMask { | |
75 | if bits != 8*IPv4len && bits != 8*IPv6len { | |
76 | return nil | |
77 | } | |
78 | if ones < 0 || ones > bits { | |
79 | return nil | |
80 | } | |
81 | l := bits / 8 | |
82 | m := make(IPMask, l) | |
83 | n := uint(ones) | |
84 | for i := 0; i < l; i++ { | |
85 | if n >= 8 { | |
86 | m[i] = 0xff | |
87 | n -= 8 | |
88 | continue | |
89 | } | |
90 | m[i] = ^byte(0xff >> n) | |
91 | n = 0 | |
92 | } | |
93 | return m | |
94 | } | |
95 | ||
7a938933 ILT |
96 | // Well-known IPv4 addresses |
97 | var ( | |
c2047754 | 98 | IPv4bcast = IPv4(255, 255, 255, 255) // limited broadcast |
7a938933 ILT |
99 | IPv4allsys = IPv4(224, 0, 0, 1) // all systems |
100 | IPv4allrouter = IPv4(224, 0, 0, 2) // all routers | |
101 | IPv4zero = IPv4(0, 0, 0, 0) // all zeros | |
102 | ) | |
103 | ||
104 | // Well-known IPv6 addresses | |
105 | var ( | |
adb0401d ILT |
106 | IPv6zero = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} |
107 | IPv6unspecified = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} | |
108 | IPv6loopback = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1} | |
109 | IPv6interfacelocalallnodes = IP{0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01} | |
110 | IPv6linklocalallnodes = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01} | |
111 | IPv6linklocalallrouters = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02} | |
7a938933 ILT |
112 | ) |
113 | ||
bc998d03 ILT |
114 | // IsUnspecified reports whether ip is an unspecified address, either |
115 | // the IPv4 address "0.0.0.0" or the IPv6 address "::". | |
adb0401d | 116 | func (ip IP) IsUnspecified() bool { |
af146490 | 117 | return ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified) |
adb0401d ILT |
118 | } |
119 | ||
af146490 | 120 | // IsLoopback reports whether ip is a loopback address. |
adb0401d | 121 | func (ip IP) IsLoopback() bool { |
af146490 ILT |
122 | if ip4 := ip.To4(); ip4 != nil { |
123 | return ip4[0] == 127 | |
adb0401d ILT |
124 | } |
125 | return ip.Equal(IPv6loopback) | |
126 | } | |
127 | ||
af146490 | 128 | // IsMulticast reports whether ip is a multicast address. |
adb0401d | 129 | func (ip IP) IsMulticast() bool { |
af146490 ILT |
130 | if ip4 := ip.To4(); ip4 != nil { |
131 | return ip4[0]&0xf0 == 0xe0 | |
adb0401d | 132 | } |
af146490 | 133 | return len(ip) == IPv6len && ip[0] == 0xff |
adb0401d ILT |
134 | } |
135 | ||
af146490 | 136 | // IsInterfaceLocalMulticast reports whether ip is |
adb0401d ILT |
137 | // an interface-local multicast address. |
138 | func (ip IP) IsInterfaceLocalMulticast() bool { | |
139 | return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01 | |
140 | } | |
141 | ||
af146490 | 142 | // IsLinkLocalMulticast reports whether ip is a link-local |
adb0401d ILT |
143 | // multicast address. |
144 | func (ip IP) IsLinkLocalMulticast() bool { | |
af146490 ILT |
145 | if ip4 := ip.To4(); ip4 != nil { |
146 | return ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0 | |
adb0401d | 147 | } |
af146490 | 148 | return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x02 |
adb0401d ILT |
149 | } |
150 | ||
af146490 | 151 | // IsLinkLocalUnicast reports whether ip is a link-local |
adb0401d ILT |
152 | // unicast address. |
153 | func (ip IP) IsLinkLocalUnicast() bool { | |
af146490 ILT |
154 | if ip4 := ip.To4(); ip4 != nil { |
155 | return ip4[0] == 169 && ip4[1] == 254 | |
adb0401d | 156 | } |
af146490 | 157 | return len(ip) == IPv6len && ip[0] == 0xfe && ip[1]&0xc0 == 0x80 |
adb0401d ILT |
158 | } |
159 | ||
af146490 | 160 | // IsGlobalUnicast reports whether ip is a global unicast |
adb0401d | 161 | // address. |
c2047754 ILT |
162 | // |
163 | // The identification of global unicast addresses uses address type | |
164 | // identification as defined in RFC 1122, RFC 4632 and RFC 4291 with | |
165 | // the exception of IPv4 directed broadcast addresses. | |
166 | // It returns true even if ip is in IPv4 private address space or | |
167 | // local IPv6 unicast address space. | |
adb0401d | 168 | func (ip IP) IsGlobalUnicast() bool { |
af146490 ILT |
169 | return (len(ip) == IPv4len || len(ip) == IPv6len) && |
170 | !ip.Equal(IPv4bcast) && | |
171 | !ip.IsUnspecified() && | |
adb0401d ILT |
172 | !ip.IsLoopback() && |
173 | !ip.IsMulticast() && | |
174 | !ip.IsLinkLocalUnicast() | |
175 | } | |
176 | ||
7a938933 ILT |
177 | // Is p all zeros? |
178 | func isZeros(p IP) bool { | |
179 | for i := 0; i < len(p); i++ { | |
180 | if p[i] != 0 { | |
181 | return false | |
182 | } | |
183 | } | |
184 | return true | |
185 | } | |
186 | ||
187 | // To4 converts the IPv4 address ip to a 4-byte representation. | |
188 | // If ip is not an IPv4 address, To4 returns nil. | |
189 | func (ip IP) To4() IP { | |
190 | if len(ip) == IPv4len { | |
191 | return ip | |
192 | } | |
193 | if len(ip) == IPv6len && | |
194 | isZeros(ip[0:10]) && | |
195 | ip[10] == 0xff && | |
196 | ip[11] == 0xff { | |
197 | return ip[12:16] | |
198 | } | |
199 | return nil | |
200 | } | |
201 | ||
202 | // To16 converts the IP address ip to a 16-byte representation. | |
203 | // If ip is not an IP address (it is the wrong length), To16 returns nil. | |
204 | func (ip IP) To16() IP { | |
205 | if len(ip) == IPv4len { | |
206 | return IPv4(ip[0], ip[1], ip[2], ip[3]) | |
207 | } | |
208 | if len(ip) == IPv6len { | |
209 | return ip | |
210 | } | |
211 | return nil | |
212 | } | |
213 | ||
214 | // Default route masks for IPv4. | |
215 | var ( | |
216 | classAMask = IPv4Mask(0xff, 0, 0, 0) | |
217 | classBMask = IPv4Mask(0xff, 0xff, 0, 0) | |
218 | classCMask = IPv4Mask(0xff, 0xff, 0xff, 0) | |
219 | ) | |
220 | ||
221 | // DefaultMask returns the default IP mask for the IP address ip. | |
222 | // Only IPv4 addresses have default masks; DefaultMask returns | |
223 | // nil if ip is not a valid IPv4 address. | |
224 | func (ip IP) DefaultMask() IPMask { | |
225 | if ip = ip.To4(); ip == nil { | |
226 | return nil | |
227 | } | |
4f4a855d | 228 | switch { |
7a938933 ILT |
229 | case ip[0] < 0x80: |
230 | return classAMask | |
231 | case ip[0] < 0xC0: | |
232 | return classBMask | |
233 | default: | |
234 | return classCMask | |
235 | } | |
7a938933 ILT |
236 | } |
237 | ||
8039ca76 ILT |
238 | func allFF(b []byte) bool { |
239 | for _, c := range b { | |
240 | if c != 0xff { | |
241 | return false | |
242 | } | |
243 | } | |
244 | return true | |
245 | } | |
246 | ||
7a938933 ILT |
247 | // Mask returns the result of masking the IP address ip with mask. |
248 | func (ip IP) Mask(mask IPMask) IP { | |
d8f41257 | 249 | if len(mask) == IPv6len && len(ip) == IPv4len && allFF(mask[:12]) { |
8039ca76 ILT |
250 | mask = mask[12:] |
251 | } | |
4f4a855d | 252 | if len(mask) == IPv4len && len(ip) == IPv6len && bytealg.Equal(ip[:12], v4InV6Prefix) { |
8039ca76 ILT |
253 | ip = ip[12:] |
254 | } | |
d8f41257 | 255 | n := len(ip) |
7a938933 ILT |
256 | if n != len(mask) { |
257 | return nil | |
258 | } | |
259 | out := make(IP, n) | |
260 | for i := 0; i < n; i++ { | |
261 | out[i] = ip[i] & mask[i] | |
262 | } | |
263 | return out | |
264 | } | |
265 | ||
dd931d9b ILT |
266 | // ubtoa encodes the string form of the integer v to dst[start:] and |
267 | // returns the number of bytes written to dst. The caller must ensure | |
268 | // that dst has sufficient length. | |
269 | func ubtoa(dst []byte, start int, v byte) int { | |
270 | if v < 10 { | |
271 | dst[start] = v + '0' | |
272 | return 1 | |
273 | } else if v < 100 { | |
274 | dst[start+1] = v%10 + '0' | |
275 | dst[start] = v/10 + '0' | |
276 | return 2 | |
277 | } | |
278 | ||
279 | dst[start+2] = v%10 + '0' | |
280 | dst[start+1] = (v/10)%10 + '0' | |
281 | dst[start] = v/100 + '0' | |
282 | return 3 | |
283 | } | |
284 | ||
7a938933 | 285 | // String returns the string form of the IP address ip. |
22b955cc ILT |
286 | // It returns one of 4 forms: |
287 | // - "<nil>", if ip has length 0 | |
288 | // - dotted decimal ("192.0.2.1"), if ip is an IPv4 or IP4-mapped IPv6 address | |
289 | // - IPv6 ("2001:db8::1"), if ip is a valid IPv6 address | |
290 | // - the hexadecimal form of ip, without punctuation, if no other cases apply | |
7a938933 ILT |
291 | func (ip IP) String() string { |
292 | p := ip | |
293 | ||
294 | if len(ip) == 0 { | |
d8f41257 | 295 | return "<nil>" |
7a938933 ILT |
296 | } |
297 | ||
298 | // If IPv4, use dotted notation. | |
d8f41257 | 299 | if p4 := p.To4(); len(p4) == IPv4len { |
dd931d9b ILT |
300 | const maxIPv4StringLen = len("255.255.255.255") |
301 | b := make([]byte, maxIPv4StringLen) | |
302 | ||
303 | n := ubtoa(b, 0, p4[0]) | |
304 | b[n] = '.' | |
305 | n++ | |
306 | ||
307 | n += ubtoa(b, n, p4[1]) | |
308 | b[n] = '.' | |
309 | n++ | |
310 | ||
311 | n += ubtoa(b, n, p4[2]) | |
312 | b[n] = '.' | |
313 | n++ | |
314 | ||
315 | n += ubtoa(b, n, p4[3]) | |
316 | return string(b[:n]) | |
7a938933 ILT |
317 | } |
318 | if len(p) != IPv6len { | |
22b955cc | 319 | return "?" + hexString(ip) |
7a938933 ILT |
320 | } |
321 | ||
322 | // Find longest run of zeros. | |
323 | e0 := -1 | |
324 | e1 := -1 | |
d8f41257 | 325 | for i := 0; i < IPv6len; i += 2 { |
7a938933 | 326 | j := i |
d8f41257 | 327 | for j < IPv6len && p[j] == 0 && p[j+1] == 0 { |
7a938933 ILT |
328 | j += 2 |
329 | } | |
330 | if j > i && j-i > e1-e0 { | |
331 | e0 = i | |
332 | e1 = j | |
f8d9fa9e | 333 | i = j |
7a938933 ILT |
334 | } |
335 | } | |
336 | // The symbol "::" MUST NOT be used to shorten just one 16 bit 0 field. | |
337 | if e1-e0 <= 2 { | |
338 | e0 = -1 | |
339 | e1 = -1 | |
340 | } | |
341 | ||
f8d9fa9e ILT |
342 | const maxLen = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff") |
343 | b := make([]byte, 0, maxLen) | |
344 | ||
7a938933 | 345 | // Print with possible :: in place of run of zeros |
d8f41257 | 346 | for i := 0; i < IPv6len; i += 2 { |
7a938933 | 347 | if i == e0 { |
f8d9fa9e | 348 | b = append(b, ':', ':') |
7a938933 | 349 | i = e1 |
d8f41257 | 350 | if i >= IPv6len { |
7a938933 ILT |
351 | break |
352 | } | |
353 | } else if i > 0 { | |
f8d9fa9e | 354 | b = append(b, ':') |
7a938933 | 355 | } |
f8d9fa9e | 356 | b = appendHex(b, (uint32(p[i])<<8)|uint32(p[i+1])) |
7a938933 | 357 | } |
f8d9fa9e | 358 | return string(b) |
7a938933 ILT |
359 | } |
360 | ||
22b955cc ILT |
361 | func hexString(b []byte) string { |
362 | s := make([]byte, len(b)*2) | |
363 | for i, tn := range b { | |
364 | s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf] | |
365 | } | |
366 | return string(s) | |
367 | } | |
368 | ||
f038dae6 ILT |
369 | // ipEmptyString is like ip.String except that it returns |
370 | // an empty string when ip is unset. | |
371 | func ipEmptyString(ip IP) string { | |
372 | if len(ip) == 0 { | |
373 | return "" | |
374 | } | |
375 | return ip.String() | |
376 | } | |
377 | ||
378 | // MarshalText implements the encoding.TextMarshaler interface. | |
bc998d03 ILT |
379 | // The encoding is the same as returned by String, with one exception: |
380 | // When len(ip) is zero, it returns an empty slice. | |
f038dae6 ILT |
381 | func (ip IP) MarshalText() ([]byte, error) { |
382 | if len(ip) == 0 { | |
383 | return []byte(""), nil | |
384 | } | |
385 | if len(ip) != IPv4len && len(ip) != IPv6len { | |
22b955cc | 386 | return nil, &AddrError{Err: "invalid IP address", Addr: hexString(ip)} |
f038dae6 ILT |
387 | } |
388 | return []byte(ip.String()), nil | |
389 | } | |
390 | ||
391 | // UnmarshalText implements the encoding.TextUnmarshaler interface. | |
392 | // The IP address is expected in a form accepted by ParseIP. | |
393 | func (ip *IP) UnmarshalText(text []byte) error { | |
394 | if len(text) == 0 { | |
395 | *ip = nil | |
396 | return nil | |
397 | } | |
398 | s := string(text) | |
399 | x := ParseIP(s) | |
400 | if x == nil { | |
af146490 | 401 | return &ParseError{Type: "IP address", Text: s} |
f038dae6 ILT |
402 | } |
403 | *ip = x | |
404 | return nil | |
405 | } | |
406 | ||
af146490 | 407 | // Equal reports whether ip and x are the same IP address. |
8039ca76 ILT |
408 | // An IPv4 address and that same address in IPv6 form are |
409 | // considered to be equal. | |
410 | func (ip IP) Equal(x IP) bool { | |
411 | if len(ip) == len(x) { | |
4f4a855d | 412 | return bytealg.Equal(ip, x) |
8039ca76 | 413 | } |
d8f41257 | 414 | if len(ip) == IPv4len && len(x) == IPv6len { |
4f4a855d | 415 | return bytealg.Equal(x[0:12], v4InV6Prefix) && bytealg.Equal(ip, x[12:]) |
8039ca76 | 416 | } |
d8f41257 | 417 | if len(ip) == IPv6len && len(x) == IPv4len { |
4f4a855d | 418 | return bytealg.Equal(ip[0:12], v4InV6Prefix) && bytealg.Equal(ip[12:], x) |
8039ca76 ILT |
419 | } |
420 | return false | |
421 | } | |
422 | ||
22b955cc ILT |
423 | func (ip IP) matchAddrFamily(x IP) bool { |
424 | return ip.To4() != nil && x.To4() != nil || ip.To16() != nil && ip.To4() == nil && x.To16() != nil && x.To4() == nil | |
425 | } | |
426 | ||
7a938933 ILT |
427 | // If mask is a sequence of 1 bits followed by 0 bits, |
428 | // return the number of 1 bits. | |
429 | func simpleMaskLength(mask IPMask) int { | |
430 | var n int | |
431 | for i, v := range mask { | |
432 | if v == 0xff { | |
433 | n += 8 | |
434 | continue | |
435 | } | |
436 | // found non-ff byte | |
437 | // count 1 bits | |
438 | for v&0x80 != 0 { | |
439 | n++ | |
440 | v <<= 1 | |
441 | } | |
442 | // rest must be 0 bits | |
443 | if v != 0 { | |
444 | return -1 | |
445 | } | |
446 | for i++; i < len(mask); i++ { | |
447 | if mask[i] != 0 { | |
448 | return -1 | |
449 | } | |
450 | } | |
451 | break | |
452 | } | |
453 | return n | |
454 | } | |
455 | ||
d8f41257 ILT |
456 | // Size returns the number of leading ones and total bits in the mask. |
457 | // If the mask is not in the canonical form--ones followed by zeros--then | |
458 | // Size returns 0, 0. | |
459 | func (m IPMask) Size() (ones, bits int) { | |
460 | ones, bits = simpleMaskLength(m), len(m)*8 | |
461 | if ones == -1 { | |
462 | return 0, 0 | |
463 | } | |
464 | return | |
465 | } | |
466 | ||
467 | // String returns the hexadecimal form of m, with no punctuation. | |
468 | func (m IPMask) String() string { | |
f8d9fa9e | 469 | if len(m) == 0 { |
d8f41257 ILT |
470 | return "<nil>" |
471 | } | |
22b955cc | 472 | return hexString(m) |
d8f41257 ILT |
473 | } |
474 | ||
475 | func networkNumberAndMask(n *IPNet) (ip IP, m IPMask) { | |
476 | if ip = n.IP.To4(); ip == nil { | |
477 | ip = n.IP | |
478 | if len(ip) != IPv6len { | |
479 | return nil, nil | |
7a938933 | 480 | } |
d8f41257 ILT |
481 | } |
482 | m = n.Mask | |
483 | switch len(m) { | |
484 | case IPv4len: | |
485 | if len(ip) != IPv4len { | |
486 | return nil, nil | |
487 | } | |
488 | case IPv6len: | |
489 | if len(ip) == IPv4len { | |
490 | m = m[12:] | |
491 | } | |
492 | default: | |
493 | return nil, nil | |
494 | } | |
495 | return | |
496 | } | |
497 | ||
498 | // Contains reports whether the network includes ip. | |
499 | func (n *IPNet) Contains(ip IP) bool { | |
500 | nn, m := networkNumberAndMask(n) | |
501 | if x := ip.To4(); x != nil { | |
502 | ip = x | |
503 | } | |
504 | l := len(ip) | |
505 | if l != len(nn) { | |
506 | return false | |
507 | } | |
508 | for i := 0; i < l; i++ { | |
509 | if nn[i]&m[i] != ip[i]&m[i] { | |
510 | return false | |
7a938933 ILT |
511 | } |
512 | } | |
d8f41257 ILT |
513 | return true |
514 | } | |
515 | ||
be47d6ec ILT |
516 | // Network returns the address's network name, "ip+net". |
517 | func (n *IPNet) Network() string { return "ip+net" } | |
518 | ||
656297e1 | 519 | // String returns the CIDR notation of n like "192.0.2.0/24" |
22b955cc | 520 | // or "2001:db8::/48" as defined in RFC 4632 and RFC 4291. |
d8f41257 ILT |
521 | // If the mask is not in the canonical form, it returns the |
522 | // string which consists of an IP address, followed by a slash | |
523 | // character and a mask expressed as hexadecimal form with no | |
656297e1 | 524 | // punctuation like "198.51.100.0/c000ff00". |
d8f41257 ILT |
525 | func (n *IPNet) String() string { |
526 | nn, m := networkNumberAndMask(n) | |
527 | if nn == nil || m == nil { | |
528 | return "<nil>" | |
529 | } | |
530 | l := simpleMaskLength(m) | |
531 | if l == -1 { | |
532 | return nn.String() + "/" + m.String() | |
533 | } | |
af146490 | 534 | return nn.String() + "/" + uitoa(uint(l)) |
7a938933 ILT |
535 | } |
536 | ||
537 | // Parse IPv4 address (d.d.d.d). | |
538 | func parseIPv4(s string) IP { | |
539 | var p [IPv4len]byte | |
c2047754 ILT |
540 | for i := 0; i < IPv4len; i++ { |
541 | if len(s) == 0 { | |
7a938933 ILT |
542 | // Missing octets. |
543 | return nil | |
544 | } | |
c2047754 ILT |
545 | if i > 0 { |
546 | if s[0] != '.' { | |
7a938933 ILT |
547 | return nil |
548 | } | |
c2047754 | 549 | s = s[1:] |
7a938933 | 550 | } |
c2047754 | 551 | n, c, ok := dtoi(s) |
7a938933 ILT |
552 | if !ok || n > 0xFF { |
553 | return nil | |
554 | } | |
c2047754 ILT |
555 | s = s[c:] |
556 | p[i] = byte(n) | |
7a938933 | 557 | } |
c2047754 | 558 | if len(s) != 0 { |
7a938933 ILT |
559 | return nil |
560 | } | |
561 | return IPv4(p[0], p[1], p[2], p[3]) | |
562 | } | |
563 | ||
dd931d9b ILT |
564 | // parseIPv6Zone parses s as a literal IPv6 address and its associated zone |
565 | // identifier which is described in RFC 4007. | |
566 | func parseIPv6Zone(s string) (IP, string) { | |
567 | s, zone := splitHostZone(s) | |
568 | return parseIPv6(s), zone | |
569 | } | |
570 | ||
aa8901e9 | 571 | // parseIPv6 parses s as a literal IPv6 address described in RFC 4291 |
dd931d9b ILT |
572 | // and RFC 5952. |
573 | func parseIPv6(s string) (ip IP) { | |
be47d6ec | 574 | ip = make(IP, IPv6len) |
c2047754 | 575 | ellipsis := -1 // position of ellipsis in ip |
7a938933 ILT |
576 | |
577 | // Might have leading ellipsis | |
578 | if len(s) >= 2 && s[0] == ':' && s[1] == ':' { | |
579 | ellipsis = 0 | |
c2047754 | 580 | s = s[2:] |
7a938933 | 581 | // Might be only ellipsis |
c2047754 | 582 | if len(s) == 0 { |
dd931d9b | 583 | return ip |
7a938933 ILT |
584 | } |
585 | } | |
586 | ||
587 | // Loop, parsing hex numbers followed by colon. | |
c2047754 ILT |
588 | i := 0 |
589 | for i < IPv6len { | |
7a938933 | 590 | // Hex number. |
c2047754 | 591 | n, c, ok := xtoi(s) |
7a938933 | 592 | if !ok || n > 0xFFFF { |
dd931d9b | 593 | return nil |
7a938933 ILT |
594 | } |
595 | ||
596 | // If followed by dot, might be in trailing IPv4. | |
c2047754 ILT |
597 | if c < len(s) && s[c] == '.' { |
598 | if ellipsis < 0 && i != IPv6len-IPv4len { | |
7a938933 | 599 | // Not the right place. |
dd931d9b | 600 | return nil |
7a938933 | 601 | } |
c2047754 | 602 | if i+IPv4len > IPv6len { |
7a938933 | 603 | // Not enough room. |
dd931d9b | 604 | return nil |
7a938933 | 605 | } |
c2047754 | 606 | ip4 := parseIPv4(s) |
be47d6ec | 607 | if ip4 == nil { |
dd931d9b | 608 | return nil |
7a938933 | 609 | } |
c2047754 ILT |
610 | ip[i] = ip4[12] |
611 | ip[i+1] = ip4[13] | |
612 | ip[i+2] = ip4[14] | |
613 | ip[i+3] = ip4[15] | |
614 | s = "" | |
615 | i += IPv4len | |
7a938933 ILT |
616 | break |
617 | } | |
618 | ||
619 | // Save this 16-bit chunk. | |
c2047754 ILT |
620 | ip[i] = byte(n >> 8) |
621 | ip[i+1] = byte(n) | |
622 | i += 2 | |
7a938933 ILT |
623 | |
624 | // Stop at end of string. | |
c2047754 ILT |
625 | s = s[c:] |
626 | if len(s) == 0 { | |
7a938933 ILT |
627 | break |
628 | } | |
629 | ||
630 | // Otherwise must be followed by colon and more. | |
c2047754 | 631 | if s[0] != ':' || len(s) == 1 { |
dd931d9b | 632 | return nil |
7a938933 | 633 | } |
c2047754 | 634 | s = s[1:] |
7a938933 ILT |
635 | |
636 | // Look for ellipsis. | |
c2047754 | 637 | if s[0] == ':' { |
7a938933 | 638 | if ellipsis >= 0 { // already have one |
dd931d9b | 639 | return nil |
7a938933 | 640 | } |
c2047754 ILT |
641 | ellipsis = i |
642 | s = s[1:] | |
643 | if len(s) == 0 { // can be at end | |
7a938933 ILT |
644 | break |
645 | } | |
646 | } | |
647 | } | |
648 | ||
649 | // Must have used entire string. | |
c2047754 | 650 | if len(s) != 0 { |
dd931d9b | 651 | return nil |
7a938933 ILT |
652 | } |
653 | ||
654 | // If didn't parse enough, expand ellipsis. | |
c2047754 | 655 | if i < IPv6len { |
7a938933 | 656 | if ellipsis < 0 { |
dd931d9b | 657 | return nil |
7a938933 | 658 | } |
c2047754 ILT |
659 | n := IPv6len - i |
660 | for j := i - 1; j >= ellipsis; j-- { | |
661 | ip[j+n] = ip[j] | |
7a938933 | 662 | } |
c2047754 ILT |
663 | for j := ellipsis + n - 1; j >= ellipsis; j-- { |
664 | ip[j] = 0 | |
7a938933 | 665 | } |
bae90c98 ILT |
666 | } else if ellipsis >= 0 { |
667 | // Ellipsis must represent at least one 0 group. | |
dd931d9b | 668 | return nil |
7a938933 | 669 | } |
dd931d9b | 670 | return ip |
7a938933 ILT |
671 | } |
672 | ||
673 | // ParseIP parses s as an IP address, returning the result. | |
22b955cc ILT |
674 | // The string s can be in dotted decimal ("192.0.2.1") |
675 | // or IPv6 ("2001:db8::68") form. | |
7a938933 ILT |
676 | // If s is not a valid textual representation of an IP address, |
677 | // ParseIP returns nil. | |
678 | func ParseIP(s string) IP { | |
f8d9fa9e ILT |
679 | for i := 0; i < len(s); i++ { |
680 | switch s[i] { | |
681 | case '.': | |
682 | return parseIPv4(s) | |
683 | case ':': | |
dd931d9b | 684 | return parseIPv6(s) |
f8d9fa9e | 685 | } |
7a938933 | 686 | } |
f8d9fa9e | 687 | return nil |
7a938933 | 688 | } |
8039ca76 | 689 | |
dd931d9b ILT |
690 | // parseIPZone parses s as an IP address, return it and its associated zone |
691 | // identifier (IPv6 only). | |
692 | func parseIPZone(s string) (IP, string) { | |
693 | for i := 0; i < len(s); i++ { | |
694 | switch s[i] { | |
695 | case '.': | |
696 | return parseIPv4(s), "" | |
697 | case ':': | |
698 | return parseIPv6Zone(s) | |
699 | } | |
700 | } | |
701 | return nil, "" | |
702 | } | |
703 | ||
c2047754 | 704 | // ParseCIDR parses s as a CIDR notation IP address and prefix length, |
22b955cc | 705 | // like "192.0.2.0/24" or "2001:db8::/32", as defined in |
f72f4169 | 706 | // RFC 4632 and RFC 4291. |
d8f41257 | 707 | // |
c2047754 ILT |
708 | // It returns the IP address and the network implied by the IP and |
709 | // prefix length. | |
710 | // For example, ParseCIDR("192.0.2.1/24") returns the IP address | |
bc998d03 | 711 | // 192.0.2.1 and the network 192.0.2.0/24. |
2fd401c8 | 712 | func ParseCIDR(s string) (IP, *IPNet, error) { |
4f4a855d | 713 | i := bytealg.IndexByteString(s, '/') |
8039ca76 | 714 | if i < 0 { |
af146490 | 715 | return nil, nil, &ParseError{Type: "CIDR address", Text: s} |
8039ca76 | 716 | } |
be47d6ec | 717 | addr, mask := s[:i], s[i+1:] |
d8f41257 | 718 | iplen := IPv4len |
be47d6ec | 719 | ip := parseIPv4(addr) |
f72f4169 | 720 | if ip == nil { |
d8f41257 | 721 | iplen = IPv6len |
dd931d9b | 722 | ip = parseIPv6(addr) |
f72f4169 | 723 | } |
c2047754 | 724 | n, i, ok := dtoi(mask) |
be47d6ec | 725 | if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen { |
af146490 | 726 | return nil, nil, &ParseError{Type: "CIDR address", Text: s} |
8039ca76 | 727 | } |
d8f41257 | 728 | m := CIDRMask(n, 8*iplen) |
a42a906c | 729 | return ip, &IPNet{IP: ip.Mask(m), Mask: m}, nil |
8039ca76 | 730 | } |