Source file
src/net/ip.go
1
2
3
4
5
6
7
8
9
10
11
12
13 package net
14
15 import (
16 "internal/bytealg"
17 "internal/itoa"
18 "internal/stringslite"
19 "net/netip"
20 )
21
22
23 const (
24 IPv4len = 4
25 IPv6len = 16
26 )
27
28
29
30
31
32
33
34
35
36
37 type IP []byte
38
39
40
41
42
43 type IPMask []byte
44
45
46 type IPNet struct {
47 IP IP
48 Mask IPMask
49 }
50
51
52
53 func IPv4(a, b, c, d byte) IP {
54 p := make(IP, IPv6len)
55 copy(p, v4InV6Prefix)
56 p[12] = a
57 p[13] = b
58 p[14] = c
59 p[15] = d
60 return p
61 }
62
63 var v4InV6Prefix = []byte{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff}
64
65
66
67 func IPv4Mask(a, b, c, d byte) IPMask {
68 p := make(IPMask, IPv4len)
69 p[0] = a
70 p[1] = b
71 p[2] = c
72 p[3] = d
73 return p
74 }
75
76
77
78
79 func CIDRMask(ones, bits int) IPMask {
80 if bits != 8*IPv4len && bits != 8*IPv6len {
81 return nil
82 }
83 if ones < 0 || ones > bits {
84 return nil
85 }
86 l := bits / 8
87 m := make(IPMask, l)
88 n := uint(ones)
89 for i := 0; i < l; i++ {
90 if n >= 8 {
91 m[i] = 0xff
92 n -= 8
93 continue
94 }
95 m[i] = ^byte(0xff >> n)
96 n = 0
97 }
98 return m
99 }
100
101
102 var (
103 IPv4bcast = IPv4(255, 255, 255, 255)
104 IPv4allsys = IPv4(224, 0, 0, 1)
105 IPv4allrouter = IPv4(224, 0, 0, 2)
106 IPv4zero = IPv4(0, 0, 0, 0)
107 )
108
109
110 var (
111 IPv6zero = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
112 IPv6unspecified = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
113 IPv6loopback = IP{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}
114 IPv6interfacelocalallnodes = IP{0xff, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
115 IPv6linklocalallnodes = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x01}
116 IPv6linklocalallrouters = IP{0xff, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x02}
117 )
118
119
120
121 func (ip IP) IsUnspecified() bool {
122 return ip.Equal(IPv4zero) || ip.Equal(IPv6unspecified)
123 }
124
125
126 func (ip IP) IsLoopback() bool {
127 if ip4 := ip.To4(); ip4 != nil {
128 return ip4[0] == 127
129 }
130 return ip.Equal(IPv6loopback)
131 }
132
133
134
135 func (ip IP) IsPrivate() bool {
136 if ip4 := ip.To4(); ip4 != nil {
137
138
139
140
141
142
143 return ip4[0] == 10 ||
144 (ip4[0] == 172 && ip4[1]&0xf0 == 16) ||
145 (ip4[0] == 192 && ip4[1] == 168)
146 }
147
148
149 return len(ip) == IPv6len && ip[0]&0xfe == 0xfc
150 }
151
152
153 func (ip IP) IsMulticast() bool {
154 if ip4 := ip.To4(); ip4 != nil {
155 return ip4[0]&0xf0 == 0xe0
156 }
157 return len(ip) == IPv6len && ip[0] == 0xff
158 }
159
160
161
162 func (ip IP) IsInterfaceLocalMulticast() bool {
163 return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x01
164 }
165
166
167
168 func (ip IP) IsLinkLocalMulticast() bool {
169 if ip4 := ip.To4(); ip4 != nil {
170 return ip4[0] == 224 && ip4[1] == 0 && ip4[2] == 0
171 }
172 return len(ip) == IPv6len && ip[0] == 0xff && ip[1]&0x0f == 0x02
173 }
174
175
176
177 func (ip IP) IsLinkLocalUnicast() bool {
178 if ip4 := ip.To4(); ip4 != nil {
179 return ip4[0] == 169 && ip4[1] == 254
180 }
181 return len(ip) == IPv6len && ip[0] == 0xfe && ip[1]&0xc0 == 0x80
182 }
183
184
185
186
187
188
189
190
191
192 func (ip IP) IsGlobalUnicast() bool {
193 return (len(ip) == IPv4len || len(ip) == IPv6len) &&
194 !ip.Equal(IPv4bcast) &&
195 !ip.IsUnspecified() &&
196 !ip.IsLoopback() &&
197 !ip.IsMulticast() &&
198 !ip.IsLinkLocalUnicast()
199 }
200
201
202 func isZeros(p IP) bool {
203 for i := 0; i < len(p); i++ {
204 if p[i] != 0 {
205 return false
206 }
207 }
208 return true
209 }
210
211
212
213 func (ip IP) To4() IP {
214 if len(ip) == IPv4len {
215 return ip
216 }
217 if len(ip) == IPv6len &&
218 isZeros(ip[0:10]) &&
219 ip[10] == 0xff &&
220 ip[11] == 0xff {
221 return ip[12:16]
222 }
223 return nil
224 }
225
226
227
228 func (ip IP) To16() IP {
229 if len(ip) == IPv4len {
230 return IPv4(ip[0], ip[1], ip[2], ip[3])
231 }
232 if len(ip) == IPv6len {
233 return ip
234 }
235 return nil
236 }
237
238
239 var (
240 classAMask = IPv4Mask(0xff, 0, 0, 0)
241 classBMask = IPv4Mask(0xff, 0xff, 0, 0)
242 classCMask = IPv4Mask(0xff, 0xff, 0xff, 0)
243 )
244
245
246
247
248 func (ip IP) DefaultMask() IPMask {
249 if ip = ip.To4(); ip == nil {
250 return nil
251 }
252 switch {
253 case ip[0] < 0x80:
254 return classAMask
255 case ip[0] < 0xC0:
256 return classBMask
257 default:
258 return classCMask
259 }
260 }
261
262 func allFF(b []byte) bool {
263 for _, c := range b {
264 if c != 0xff {
265 return false
266 }
267 }
268 return true
269 }
270
271
272 func (ip IP) Mask(mask IPMask) IP {
273 if len(mask) == IPv6len && len(ip) == IPv4len && allFF(mask[:12]) {
274 mask = mask[12:]
275 }
276 if len(mask) == IPv4len && len(ip) == IPv6len && bytealg.Equal(ip[:12], v4InV6Prefix) {
277 ip = ip[12:]
278 }
279 n := len(ip)
280 if n != len(mask) {
281 return nil
282 }
283 out := make(IP, n)
284 for i := 0; i < n; i++ {
285 out[i] = ip[i] & mask[i]
286 }
287 return out
288 }
289
290
291
292
293
294
295
296 func (ip IP) String() string {
297 if len(ip) == 0 {
298 return "<nil>"
299 }
300
301 if len(ip) != IPv4len && len(ip) != IPv6len {
302 return "?" + hexString(ip)
303 }
304
305 var buf []byte
306 switch len(ip) {
307 case IPv4len:
308 const maxCap = len("255.255.255.255")
309 buf = make([]byte, 0, maxCap)
310 case IPv6len:
311 const maxCap = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
312 buf = make([]byte, 0, maxCap)
313 }
314 buf = ip.appendTo(buf)
315 return string(buf)
316 }
317
318 func hexString(b []byte) string {
319 s := make([]byte, len(b)*2)
320 for i, tn := range b {
321 s[i*2], s[i*2+1] = hexDigit[tn>>4], hexDigit[tn&0xf]
322 }
323 return string(s)
324 }
325
326
327
328 func ipEmptyString(ip IP) string {
329 if len(ip) == 0 {
330 return ""
331 }
332 return ip.String()
333 }
334
335
336
337 func (ip IP) appendTo(b []byte) []byte {
338
339 if p4 := ip.To4(); len(p4) == IPv4len {
340 ip = p4
341 }
342 addr, _ := netip.AddrFromSlice(ip)
343 return addr.AppendTo(b)
344 }
345
346
347
348
349 func (ip IP) AppendText(b []byte) ([]byte, error) {
350 if len(ip) == 0 {
351 return b, nil
352 }
353 if len(ip) != IPv4len && len(ip) != IPv6len {
354 return b, &AddrError{Err: "invalid IP address", Addr: hexString(ip)}
355 }
356
357 return ip.appendTo(b), nil
358 }
359
360
361
362
363 func (ip IP) MarshalText() ([]byte, error) {
364
365 b, err := ip.AppendText(make([]byte, 0, 24))
366 if err != nil {
367 return nil, err
368 }
369 return b, nil
370 }
371
372
373
374 func (ip *IP) UnmarshalText(text []byte) error {
375 if len(text) == 0 {
376 *ip = nil
377 return nil
378 }
379 s := string(text)
380 x := ParseIP(s)
381 if x == nil {
382 return &ParseError{Type: "IP address", Text: s}
383 }
384 *ip = x
385 return nil
386 }
387
388
389
390
391 func (ip IP) Equal(x IP) bool {
392 if len(ip) == len(x) {
393 return bytealg.Equal(ip, x)
394 }
395 if len(ip) == IPv4len && len(x) == IPv6len {
396 return bytealg.Equal(x[0:12], v4InV6Prefix) && bytealg.Equal(ip, x[12:])
397 }
398 if len(ip) == IPv6len && len(x) == IPv4len {
399 return bytealg.Equal(ip[0:12], v4InV6Prefix) && bytealg.Equal(ip[12:], x)
400 }
401 return false
402 }
403
404 func (ip IP) matchAddrFamily(x IP) bool {
405 return ip.To4() != nil && x.To4() != nil || ip.To16() != nil && ip.To4() == nil && x.To16() != nil && x.To4() == nil
406 }
407
408
409
410 func simpleMaskLength(mask IPMask) int {
411 var n int
412 for i, v := range mask {
413 if v == 0xff {
414 n += 8
415 continue
416 }
417
418
419 for v&0x80 != 0 {
420 n++
421 v <<= 1
422 }
423
424 if v != 0 {
425 return -1
426 }
427 for i++; i < len(mask); i++ {
428 if mask[i] != 0 {
429 return -1
430 }
431 }
432 break
433 }
434 return n
435 }
436
437
438
439
440 func (m IPMask) Size() (ones, bits int) {
441 ones, bits = simpleMaskLength(m), len(m)*8
442 if ones == -1 {
443 return 0, 0
444 }
445 return
446 }
447
448
449 func (m IPMask) String() string {
450 if len(m) == 0 {
451 return "<nil>"
452 }
453 return hexString(m)
454 }
455
456 func networkNumberAndMask(n *IPNet) (ip IP, m IPMask) {
457 if ip = n.IP.To4(); ip == nil {
458 ip = n.IP
459 if len(ip) != IPv6len {
460 return nil, nil
461 }
462 }
463 m = n.Mask
464 switch len(m) {
465 case IPv4len:
466 if len(ip) != IPv4len {
467 return nil, nil
468 }
469 case IPv6len:
470 if len(ip) == IPv4len {
471 m = m[12:]
472 }
473 default:
474 return nil, nil
475 }
476 return
477 }
478
479
480 func (n *IPNet) Contains(ip IP) bool {
481 nn, m := networkNumberAndMask(n)
482 if x := ip.To4(); x != nil {
483 ip = x
484 }
485 l := len(ip)
486 if l != len(nn) {
487 return false
488 }
489 for i := 0; i < l; i++ {
490 if nn[i]&m[i] != ip[i]&m[i] {
491 return false
492 }
493 }
494 return true
495 }
496
497
498 func (n *IPNet) Network() string { return "ip+net" }
499
500
501
502
503
504
505
506 func (n *IPNet) String() string {
507 if n == nil {
508 return "<nil>"
509 }
510 nn, m := networkNumberAndMask(n)
511 if nn == nil || m == nil {
512 return "<nil>"
513 }
514 l := simpleMaskLength(m)
515 if l == -1 {
516 return nn.String() + "/" + m.String()
517 }
518 return nn.String() + "/" + itoa.Uitoa(uint(l))
519 }
520
521
522
523
524
525
526
527 func ParseIP(s string) IP {
528 if addr, valid := parseIP(s); valid {
529 return IP(addr[:])
530 }
531 return nil
532 }
533
534 func parseIP(s string) ([16]byte, bool) {
535 ip, err := netip.ParseAddr(s)
536 if err != nil || ip.Zone() != "" {
537 return [16]byte{}, false
538 }
539 return ip.As16(), true
540 }
541
542
543
544
545
546
547
548
549
550 func ParseCIDR(s string) (IP, *IPNet, error) {
551 addr, mask, found := stringslite.Cut(s, "/")
552 if !found {
553 return nil, nil, &ParseError{Type: "CIDR address", Text: s}
554 }
555
556 ipAddr, err := netip.ParseAddr(addr)
557 if err != nil || ipAddr.Zone() != "" {
558 return nil, nil, &ParseError{Type: "CIDR address", Text: s}
559 }
560
561 n, i, ok := dtoi(mask)
562 if !ok || i != len(mask) || n < 0 || n > ipAddr.BitLen() {
563 return nil, nil, &ParseError{Type: "CIDR address", Text: s}
564 }
565 m := CIDRMask(n, ipAddr.BitLen())
566 addr16 := ipAddr.As16()
567 return IP(addr16[:]), &IPNet{IP: IP(addr16[:]).Mask(m), Mask: m}, nil
568 }
569
570 func copyIP(x IP) IP {
571 y := make(IP, len(x))
572 copy(y, x)
573 return y
574 }
575
View as plain text