Source file
src/net/netip/netip.go
1
2
3
4
5
6
7
8
9
10
11
12 package netip
13
14 import (
15 "cmp"
16 "errors"
17 "internal/bytealg"
18 "internal/byteorder"
19 "math"
20 "strconv"
21 "unique"
22 )
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37 type Addr struct {
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53 addr uint128
54
55
56 z unique.Handle[addrDetail]
57 }
58
59
60 type addrDetail struct {
61 isV6 bool
62 zoneV6 string
63 }
64
65
66
67 var (
68 z0 unique.Handle[addrDetail]
69 z4 = unique.Make(addrDetail{})
70 z6noz = unique.Make(addrDetail{isV6: true})
71 )
72
73
74
75 func IPv6LinkLocalAllNodes() Addr { return AddrFrom16([16]byte{0: 0xff, 1: 0x02, 15: 0x01}) }
76
77
78
79 func IPv6LinkLocalAllRouters() Addr { return AddrFrom16([16]byte{0: 0xff, 1: 0x02, 15: 0x02}) }
80
81
82 func IPv6Loopback() Addr { return AddrFrom16([16]byte{15: 0x01}) }
83
84
85 func IPv6Unspecified() Addr { return Addr{z: z6noz} }
86
87
88 func IPv4Unspecified() Addr { return AddrFrom4([4]byte{}) }
89
90
91 func AddrFrom4(addr [4]byte) Addr {
92 return Addr{
93 addr: uint128{0, 0xffff00000000 | uint64(addr[0])<<24 | uint64(addr[1])<<16 | uint64(addr[2])<<8 | uint64(addr[3])},
94 z: z4,
95 }
96 }
97
98
99
100
101 func AddrFrom16(addr [16]byte) Addr {
102 return Addr{
103 addr: uint128{
104 byteorder.BEUint64(addr[:8]),
105 byteorder.BEUint64(addr[8:]),
106 },
107 z: z6noz,
108 }
109 }
110
111
112
113
114 func ParseAddr(s string) (Addr, error) {
115 for i := 0; i < len(s); i++ {
116 switch s[i] {
117 case '.':
118 return parseIPv4(s)
119 case ':':
120 return parseIPv6(s)
121 case '%':
122
123
124 return Addr{}, parseAddrError{in: s, msg: "missing IPv6 address"}
125 }
126 }
127 return Addr{}, parseAddrError{in: s, msg: "unable to parse IP"}
128 }
129
130
131
132 func MustParseAddr(s string) Addr {
133 ip, err := ParseAddr(s)
134 if err != nil {
135 panic(err)
136 }
137 return ip
138 }
139
140 type parseAddrError struct {
141 in string
142 msg string
143 at string
144 }
145
146 func (err parseAddrError) Error() string {
147 q := strconv.Quote
148 if err.at != "" {
149 return "ParseAddr(" + q(err.in) + "): " + err.msg + " (at " + q(err.at) + ")"
150 }
151 return "ParseAddr(" + q(err.in) + "): " + err.msg
152 }
153
154 func parseIPv4Fields(in string, off, end int, fields []uint8) error {
155 var val, pos int
156 var digLen int
157 s := in[off:end]
158 for i := 0; i < len(s); i++ {
159 if s[i] >= '0' && s[i] <= '9' {
160 if digLen == 1 && val == 0 {
161 return parseAddrError{in: in, msg: "IPv4 field has octet with leading zero"}
162 }
163 val = val*10 + int(s[i]) - '0'
164 digLen++
165 if val > 255 {
166 return parseAddrError{in: in, msg: "IPv4 field has value >255"}
167 }
168 } else if s[i] == '.' {
169
170
171
172 if i == 0 || i == len(s)-1 || s[i-1] == '.' {
173 return parseAddrError{in: in, msg: "IPv4 field must have at least one digit", at: s[i:]}
174 }
175
176 if pos == 3 {
177 return parseAddrError{in: in, msg: "IPv4 address too long"}
178 }
179 fields[pos] = uint8(val)
180 pos++
181 val = 0
182 digLen = 0
183 } else {
184 return parseAddrError{in: in, msg: "unexpected character", at: s[i:]}
185 }
186 }
187 if pos < 3 {
188 return parseAddrError{in: in, msg: "IPv4 address too short"}
189 }
190 fields[3] = uint8(val)
191 return nil
192 }
193
194
195 func parseIPv4(s string) (ip Addr, err error) {
196 var fields [4]uint8
197 err = parseIPv4Fields(s, 0, len(s), fields[:])
198 if err != nil {
199 return Addr{}, err
200 }
201 return AddrFrom4(fields), nil
202 }
203
204
205 func parseIPv6(in string) (Addr, error) {
206 s := in
207
208
209
210
211
212 zone := ""
213 i := bytealg.IndexByteString(s, '%')
214 if i != -1 {
215 s, zone = s[:i], s[i+1:]
216 if zone == "" {
217
218 return Addr{}, parseAddrError{in: in, msg: "zone must be a non-empty string"}
219 }
220 }
221
222 var ip [16]byte
223 ellipsis := -1
224
225
226 if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
227 ellipsis = 0
228 s = s[2:]
229
230 if len(s) == 0 {
231 return IPv6Unspecified().WithZone(zone), nil
232 }
233 }
234
235
236 i = 0
237 for i < 16 {
238
239
240 off := 0
241 acc := uint32(0)
242 for ; off < len(s); off++ {
243 c := s[off]
244 if c >= '0' && c <= '9' {
245 acc = (acc << 4) + uint32(c-'0')
246 } else if c >= 'a' && c <= 'f' {
247 acc = (acc << 4) + uint32(c-'a'+10)
248 } else if c >= 'A' && c <= 'F' {
249 acc = (acc << 4) + uint32(c-'A'+10)
250 } else {
251 break
252 }
253 if off > 3 {
254
255 return Addr{}, parseAddrError{in: in, msg: "each group must have 4 or less digits", at: s}
256 }
257 if acc > math.MaxUint16 {
258
259 return Addr{}, parseAddrError{in: in, msg: "IPv6 field has value >=2^16", at: s}
260 }
261 }
262 if off == 0 {
263
264 return Addr{}, parseAddrError{in: in, msg: "each colon-separated field must have at least one digit", at: s}
265 }
266
267
268 if off < len(s) && s[off] == '.' {
269 if ellipsis < 0 && i != 12 {
270
271 return Addr{}, parseAddrError{in: in, msg: "embedded IPv4 address must replace the final 2 fields of the address", at: s}
272 }
273 if i+4 > 16 {
274
275 return Addr{}, parseAddrError{in: in, msg: "too many hex fields to fit an embedded IPv4 at the end of the address", at: s}
276 }
277
278 end := len(in)
279 if len(zone) > 0 {
280 end -= len(zone) + 1
281 }
282 err := parseIPv4Fields(in, end-len(s), end, ip[i:i+4])
283 if err != nil {
284 return Addr{}, err
285 }
286 s = ""
287 i += 4
288 break
289 }
290
291
292 ip[i] = byte(acc >> 8)
293 ip[i+1] = byte(acc)
294 i += 2
295
296
297 s = s[off:]
298 if len(s) == 0 {
299 break
300 }
301
302
303 if s[0] != ':' {
304 return Addr{}, parseAddrError{in: in, msg: "unexpected character, want colon", at: s}
305 } else if len(s) == 1 {
306 return Addr{}, parseAddrError{in: in, msg: "colon must be followed by more characters", at: s}
307 }
308 s = s[1:]
309
310
311 if s[0] == ':' {
312 if ellipsis >= 0 {
313 return Addr{}, parseAddrError{in: in, msg: "multiple :: in address", at: s}
314 }
315 ellipsis = i
316 s = s[1:]
317 if len(s) == 0 {
318 break
319 }
320 }
321 }
322
323
324 if len(s) != 0 {
325 return Addr{}, parseAddrError{in: in, msg: "trailing garbage after address", at: s}
326 }
327
328
329 if i < 16 {
330 if ellipsis < 0 {
331 return Addr{}, parseAddrError{in: in, msg: "address string too short"}
332 }
333 n := 16 - i
334 for j := i - 1; j >= ellipsis; j-- {
335 ip[j+n] = ip[j]
336 }
337 clear(ip[ellipsis : ellipsis+n])
338 } else if ellipsis >= 0 {
339
340 return Addr{}, parseAddrError{in: in, msg: "the :: must expand to at least one field of zeros"}
341 }
342 return AddrFrom16(ip).WithZone(zone), nil
343 }
344
345
346
347
348 func AddrFromSlice(slice []byte) (ip Addr, ok bool) {
349 switch len(slice) {
350 case 4:
351 return AddrFrom4([4]byte(slice)), true
352 case 16:
353 return AddrFrom16([16]byte(slice)), true
354 }
355 return Addr{}, false
356 }
357
358
359
360 func (ip Addr) v4(i uint8) uint8 {
361 return uint8(ip.addr.lo >> ((3 - i) * 8))
362 }
363
364
365
366 func (ip Addr) v6(i uint8) uint8 {
367 return uint8(*(ip.addr.halves()[(i/8)%2]) >> ((7 - i%8) * 8))
368 }
369
370
371
372 func (ip Addr) v6u16(i uint8) uint16 {
373 return uint16(*(ip.addr.halves()[(i/4)%2]) >> ((3 - i%4) * 16))
374 }
375
376
377
378
379
380
381 func (ip Addr) isZero() bool {
382
383
384 return ip.z == z0
385 }
386
387
388
389
390 func (ip Addr) IsValid() bool { return ip.z != z0 }
391
392
393
394
395
396
397 func (ip Addr) BitLen() int {
398 switch ip.z {
399 case z0:
400 return 0
401 case z4:
402 return 32
403 }
404 return 128
405 }
406
407
408 func (ip Addr) Zone() string {
409 if ip.z == z0 {
410 return ""
411 }
412 return ip.z.Value().zoneV6
413 }
414
415
416
417
418 func (ip Addr) Compare(ip2 Addr) int {
419 f1, f2 := ip.BitLen(), ip2.BitLen()
420 if f1 < f2 {
421 return -1
422 }
423 if f1 > f2 {
424 return 1
425 }
426 hi1, hi2 := ip.addr.hi, ip2.addr.hi
427 if hi1 < hi2 {
428 return -1
429 }
430 if hi1 > hi2 {
431 return 1
432 }
433 lo1, lo2 := ip.addr.lo, ip2.addr.lo
434 if lo1 < lo2 {
435 return -1
436 }
437 if lo1 > lo2 {
438 return 1
439 }
440 if ip.Is6() {
441 za, zb := ip.Zone(), ip2.Zone()
442 if za < zb {
443 return -1
444 }
445 if za > zb {
446 return 1
447 }
448 }
449 return 0
450 }
451
452
453
454
455 func (ip Addr) Less(ip2 Addr) bool { return ip.Compare(ip2) == -1 }
456
457
458
459
460 func (ip Addr) Is4() bool {
461 return ip.z == z4
462 }
463
464
465
466
467 func (ip Addr) Is4In6() bool {
468 return ip.Is6() && ip.addr.hi == 0 && ip.addr.lo>>32 == 0xffff
469 }
470
471
472
473 func (ip Addr) Is6() bool {
474 return ip.z != z0 && ip.z != z4
475 }
476
477
478
479
480
481 func (ip Addr) Unmap() Addr {
482 if ip.Is4In6() {
483 ip.z = z4
484 }
485 return ip
486 }
487
488
489
490
491 func (ip Addr) WithZone(zone string) Addr {
492 if !ip.Is6() {
493 return ip
494 }
495 if zone == "" {
496 ip.z = z6noz
497 return ip
498 }
499 ip.z = unique.Make(addrDetail{isV6: true, zoneV6: zone})
500 return ip
501 }
502
503
504
505 func (ip Addr) withoutZone() Addr {
506 if !ip.Is6() {
507 return ip
508 }
509 ip.z = z6noz
510 return ip
511 }
512
513
514 func (ip Addr) hasZone() bool {
515 return ip.z != z0 && ip.z != z4 && ip.z != z6noz
516 }
517
518
519 func (ip Addr) IsLinkLocalUnicast() bool {
520 if ip.Is4In6() {
521 ip = ip.Unmap()
522 }
523
524
525
526 if ip.Is4() {
527 return ip.v4(0) == 169 && ip.v4(1) == 254
528 }
529
530
531 if ip.Is6() {
532 return ip.v6u16(0)&0xffc0 == 0xfe80
533 }
534 return false
535 }
536
537
538 func (ip Addr) IsLoopback() bool {
539 if ip.Is4In6() {
540 ip = ip.Unmap()
541 }
542
543
544
545 if ip.Is4() {
546 return ip.v4(0) == 127
547 }
548
549
550 if ip.Is6() {
551 return ip.addr.hi == 0 && ip.addr.lo == 1
552 }
553 return false
554 }
555
556
557 func (ip Addr) IsMulticast() bool {
558 if ip.Is4In6() {
559 ip = ip.Unmap()
560 }
561
562
563
564 if ip.Is4() {
565 return ip.v4(0)&0xf0 == 0xe0
566 }
567
568
569 if ip.Is6() {
570 return ip.addr.hi>>(64-8) == 0xff
571 }
572 return false
573 }
574
575
576
577 func (ip Addr) IsInterfaceLocalMulticast() bool {
578
579
580 if ip.Is6() && !ip.Is4In6() {
581 return ip.v6u16(0)&0xff0f == 0xff01
582 }
583 return false
584 }
585
586
587 func (ip Addr) IsLinkLocalMulticast() bool {
588 if ip.Is4In6() {
589 ip = ip.Unmap()
590 }
591
592
593
594 if ip.Is4() {
595 return ip.v4(0) == 224 && ip.v4(1) == 0 && ip.v4(2) == 0
596 }
597
598
599 if ip.Is6() {
600 return ip.v6u16(0)&0xff0f == 0xff02
601 }
602 return false
603 }
604
605
606
607
608
609
610
611
612
613
614 func (ip Addr) IsGlobalUnicast() bool {
615 if ip.z == z0 {
616
617 return false
618 }
619
620 if ip.Is4In6() {
621 ip = ip.Unmap()
622 }
623
624
625
626 if ip.Is4() && (ip == IPv4Unspecified() || ip == AddrFrom4([4]byte{255, 255, 255, 255})) {
627 return false
628 }
629
630 return ip != IPv6Unspecified() &&
631 !ip.IsLoopback() &&
632 !ip.IsMulticast() &&
633 !ip.IsLinkLocalUnicast()
634 }
635
636
637
638
639
640
641
642
643 func (ip Addr) IsPrivate() bool {
644 if ip.Is4In6() {
645 ip = ip.Unmap()
646 }
647
648
649 if ip.Is4() {
650
651
652 return ip.v4(0) == 10 ||
653 (ip.v4(0) == 172 && ip.v4(1)&0xf0 == 16) ||
654 (ip.v4(0) == 192 && ip.v4(1) == 168)
655 }
656
657 if ip.Is6() {
658
659
660 return ip.v6(0)&0xfe == 0xfc
661 }
662
663 return false
664 }
665
666
667
668
669
670 func (ip Addr) IsUnspecified() bool {
671 return ip == IPv4Unspecified() || ip == IPv6Unspecified()
672 }
673
674
675
676
677
678
679 func (ip Addr) Prefix(b int) (Prefix, error) {
680 if b < 0 {
681 return Prefix{}, errors.New("negative Prefix bits")
682 }
683 effectiveBits := b
684 switch ip.z {
685 case z0:
686 return Prefix{}, nil
687 case z4:
688 if b > 32 {
689 return Prefix{}, errors.New("prefix length " + strconv.Itoa(b) + " too large for IPv4")
690 }
691 effectiveBits += 96
692 default:
693 if b > 128 {
694 return Prefix{}, errors.New("prefix length " + strconv.Itoa(b) + " too large for IPv6")
695 }
696 }
697 ip.addr = ip.addr.and(mask6(effectiveBits))
698 return PrefixFrom(ip, b), nil
699 }
700
701
702
703
704
705
706 func (ip Addr) As16() (a16 [16]byte) {
707 byteorder.BEPutUint64(a16[:8], ip.addr.hi)
708 byteorder.BEPutUint64(a16[8:], ip.addr.lo)
709 return a16
710 }
711
712
713
714
715 func (ip Addr) As4() (a4 [4]byte) {
716 if ip.z == z4 || ip.Is4In6() {
717 byteorder.BEPutUint32(a4[:], uint32(ip.addr.lo))
718 return a4
719 }
720 if ip.z == z0 {
721 panic("As4 called on IP zero value")
722 }
723 panic("As4 called on IPv6 address")
724 }
725
726
727 func (ip Addr) AsSlice() []byte {
728 switch ip.z {
729 case z0:
730 return nil
731 case z4:
732 var ret [4]byte
733 byteorder.BEPutUint32(ret[:], uint32(ip.addr.lo))
734 return ret[:]
735 default:
736 var ret [16]byte
737 byteorder.BEPutUint64(ret[:8], ip.addr.hi)
738 byteorder.BEPutUint64(ret[8:], ip.addr.lo)
739 return ret[:]
740 }
741 }
742
743
744
745 func (ip Addr) Next() Addr {
746 ip.addr = ip.addr.addOne()
747 if ip.Is4() {
748 if uint32(ip.addr.lo) == 0 {
749
750 return Addr{}
751 }
752 } else {
753 if ip.addr.isZero() {
754
755 return Addr{}
756 }
757 }
758 return ip
759 }
760
761
762
763 func (ip Addr) Prev() Addr {
764 if ip.Is4() {
765 if uint32(ip.addr.lo) == 0 {
766 return Addr{}
767 }
768 } else if ip.addr.isZero() {
769 return Addr{}
770 }
771 ip.addr = ip.addr.subOne()
772 return ip
773 }
774
775
776
777
778
779
780
781
782
783
784
785
786
787 func (ip Addr) String() string {
788 if !ip.IsValid() {
789 return "invalid IP"
790 }
791 var b []byte
792 switch {
793 case ip.z == z4:
794 const max = len("255.255.255.255")
795 b = make([]byte, 0, max)
796 b = ip.appendTo4(b)
797 case ip.Is4In6():
798 const max = len("::ffff:255.255.255.255%enp5s0")
799 b = make([]byte, 0, max)
800 b = ip.appendTo4In6(b)
801 default:
802
803
804
805
806
807
808
809 const max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0")
810 b = make([]byte, 0, max)
811 b = ip.appendTo6(b)
812 }
813 return string(b)
814 }
815
816
817
818
819 func (ip Addr) AppendTo(b []byte) []byte {
820 switch ip.z {
821 case z0:
822 return b
823 case z4:
824 return ip.appendTo4(b)
825 default:
826 if ip.Is4In6() {
827 return ip.appendTo4In6(b)
828 }
829 return ip.appendTo6(b)
830 }
831 }
832
833
834
835 const digits = "0123456789abcdef"
836
837
838 func appendDecimal(b []byte, x uint8) []byte {
839
840
841
842 if x >= 100 {
843 b = append(b, digits[x/100])
844 }
845 if x >= 10 {
846 b = append(b, digits[x/10%10])
847 }
848 return append(b, digits[x%10])
849 }
850
851
852 func appendHex(b []byte, x uint16) []byte {
853
854
855
856 if x >= 0x1000 {
857 b = append(b, digits[x>>12])
858 }
859 if x >= 0x100 {
860 b = append(b, digits[x>>8&0xf])
861 }
862 if x >= 0x10 {
863 b = append(b, digits[x>>4&0xf])
864 }
865 return append(b, digits[x&0xf])
866 }
867
868
869 func appendHexPad(b []byte, x uint16) []byte {
870 return append(b, digits[x>>12], digits[x>>8&0xf], digits[x>>4&0xf], digits[x&0xf])
871 }
872
873 func (ip Addr) appendTo4(ret []byte) []byte {
874 ret = appendDecimal(ret, ip.v4(0))
875 ret = append(ret, '.')
876 ret = appendDecimal(ret, ip.v4(1))
877 ret = append(ret, '.')
878 ret = appendDecimal(ret, ip.v4(2))
879 ret = append(ret, '.')
880 ret = appendDecimal(ret, ip.v4(3))
881 return ret
882 }
883
884 func (ip Addr) appendTo4In6(ret []byte) []byte {
885 ret = append(ret, "::ffff:"...)
886 ret = ip.Unmap().appendTo4(ret)
887 if ip.z != z6noz {
888 ret = append(ret, '%')
889 ret = append(ret, ip.Zone()...)
890 }
891 return ret
892 }
893
894
895
896
897
898
899 func (ip Addr) appendTo6(ret []byte) []byte {
900 zeroStart, zeroEnd := uint8(255), uint8(255)
901 for i := uint8(0); i < 8; i++ {
902 j := i
903 for j < 8 && ip.v6u16(j) == 0 {
904 j++
905 }
906 if l := j - i; l >= 2 && l > zeroEnd-zeroStart {
907 zeroStart, zeroEnd = i, j
908 }
909 }
910
911 for i := uint8(0); i < 8; i++ {
912 if i == zeroStart {
913 ret = append(ret, ':', ':')
914 i = zeroEnd
915 if i >= 8 {
916 break
917 }
918 } else if i > 0 {
919 ret = append(ret, ':')
920 }
921
922 ret = appendHex(ret, ip.v6u16(i))
923 }
924
925 if ip.z != z6noz {
926 ret = append(ret, '%')
927 ret = append(ret, ip.Zone()...)
928 }
929 return ret
930 }
931
932
933
934
935 func (ip Addr) StringExpanded() string {
936 switch ip.z {
937 case z0, z4:
938 return ip.String()
939 }
940
941 const size = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
942 ret := make([]byte, 0, size)
943 for i := uint8(0); i < 8; i++ {
944 if i > 0 {
945 ret = append(ret, ':')
946 }
947
948 ret = appendHexPad(ret, ip.v6u16(i))
949 }
950
951 if ip.z != z6noz {
952
953
954 ret = append(ret, '%')
955 ret = append(ret, ip.Zone()...)
956 }
957 return string(ret)
958 }
959
960
961
962 func (ip Addr) AppendText(b []byte) ([]byte, error) {
963 return ip.AppendTo(b), nil
964 }
965
966
967
968
969 func (ip Addr) MarshalText() ([]byte, error) {
970 buf := []byte{}
971 switch ip.z {
972 case z0:
973 case z4:
974 const maxCap = len("255.255.255.255")
975 buf = make([]byte, 0, maxCap)
976 default:
977 if ip.Is4In6() {
978 const maxCap = len("::ffff:255.255.255.255%enp5s0")
979 buf = make([]byte, 0, maxCap)
980 break
981 }
982 const maxCap = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0")
983 buf = make([]byte, 0, maxCap)
984 }
985 return ip.AppendText(buf)
986 }
987
988
989
990
991
992
993 func (ip *Addr) UnmarshalText(text []byte) error {
994 if len(text) == 0 {
995 *ip = Addr{}
996 return nil
997 }
998 var err error
999 *ip, err = ParseAddr(string(text))
1000 return err
1001 }
1002
1003
1004 func (ip Addr) AppendBinary(b []byte) ([]byte, error) {
1005 switch ip.z {
1006 case z0:
1007 case z4:
1008 b = byteorder.BEAppendUint32(b, uint32(ip.addr.lo))
1009 default:
1010 b = byteorder.BEAppendUint64(b, ip.addr.hi)
1011 b = byteorder.BEAppendUint64(b, ip.addr.lo)
1012 b = append(b, ip.Zone()...)
1013 }
1014 return b, nil
1015 }
1016
1017 func (ip Addr) marshalBinarySize() int {
1018 switch ip.z {
1019 case z0:
1020 return 0
1021 case z4:
1022 return 4
1023 default:
1024 return 16 + len(ip.Zone())
1025 }
1026 }
1027
1028
1029
1030
1031
1032 func (ip Addr) MarshalBinary() ([]byte, error) {
1033 return ip.AppendBinary(make([]byte, 0, ip.marshalBinarySize()))
1034 }
1035
1036
1037
1038 func (ip *Addr) UnmarshalBinary(b []byte) error {
1039 n := len(b)
1040 switch {
1041 case n == 0:
1042 *ip = Addr{}
1043 return nil
1044 case n == 4:
1045 *ip = AddrFrom4([4]byte(b))
1046 return nil
1047 case n == 16:
1048 *ip = AddrFrom16([16]byte(b))
1049 return nil
1050 case n > 16:
1051 *ip = AddrFrom16([16]byte(b[:16])).WithZone(string(b[16:]))
1052 return nil
1053 }
1054 return errors.New("unexpected slice size")
1055 }
1056
1057
1058 type AddrPort struct {
1059 ip Addr
1060 port uint16
1061 }
1062
1063
1064
1065 func AddrPortFrom(ip Addr, port uint16) AddrPort { return AddrPort{ip: ip, port: port} }
1066
1067
1068 func (p AddrPort) Addr() Addr { return p.ip }
1069
1070
1071 func (p AddrPort) Port() uint16 { return p.port }
1072
1073
1074
1075
1076
1077
1078 func splitAddrPort(s string) (ip, port string, v6 bool, err error) {
1079 i := bytealg.LastIndexByteString(s, ':')
1080 if i == -1 {
1081 return "", "", false, errors.New("not an ip:port")
1082 }
1083
1084 ip, port = s[:i], s[i+1:]
1085 if len(ip) == 0 {
1086 return "", "", false, errors.New("no IP")
1087 }
1088 if len(port) == 0 {
1089 return "", "", false, errors.New("no port")
1090 }
1091 if ip[0] == '[' {
1092 if len(ip) < 2 || ip[len(ip)-1] != ']' {
1093 return "", "", false, errors.New("missing ]")
1094 }
1095 ip = ip[1 : len(ip)-1]
1096 v6 = true
1097 }
1098
1099 return ip, port, v6, nil
1100 }
1101
1102
1103
1104
1105
1106 func ParseAddrPort(s string) (AddrPort, error) {
1107 var ipp AddrPort
1108 ip, port, v6, err := splitAddrPort(s)
1109 if err != nil {
1110 return ipp, err
1111 }
1112 port16, err := strconv.ParseUint(port, 10, 16)
1113 if err != nil {
1114 return ipp, errors.New("invalid port " + strconv.Quote(port) + " parsing " + strconv.Quote(s))
1115 }
1116 ipp.port = uint16(port16)
1117 ipp.ip, err = ParseAddr(ip)
1118 if err != nil {
1119 return AddrPort{}, err
1120 }
1121 if v6 && ipp.ip.Is4() {
1122 return AddrPort{}, errors.New("invalid ip:port " + strconv.Quote(s) + ", square brackets can only be used with IPv6 addresses")
1123 } else if !v6 && ipp.ip.Is6() {
1124 return AddrPort{}, errors.New("invalid ip:port " + strconv.Quote(s) + ", IPv6 addresses must be surrounded by square brackets")
1125 }
1126 return ipp, nil
1127 }
1128
1129
1130
1131 func MustParseAddrPort(s string) AddrPort {
1132 ip, err := ParseAddrPort(s)
1133 if err != nil {
1134 panic(err)
1135 }
1136 return ip
1137 }
1138
1139
1140
1141 func (p AddrPort) IsValid() bool { return p.ip.IsValid() }
1142
1143
1144
1145
1146 func (p AddrPort) Compare(p2 AddrPort) int {
1147 if c := p.Addr().Compare(p2.Addr()); c != 0 {
1148 return c
1149 }
1150 return cmp.Compare(p.Port(), p2.Port())
1151 }
1152
1153 func (p AddrPort) String() string {
1154 var b []byte
1155 switch p.ip.z {
1156 case z0:
1157 return "invalid AddrPort"
1158 case z4:
1159 const max = len("255.255.255.255:65535")
1160 b = make([]byte, 0, max)
1161 b = p.ip.appendTo4(b)
1162 default:
1163 if p.ip.Is4In6() {
1164 const max = len("[::ffff:255.255.255.255%enp5s0]:65535")
1165 b = make([]byte, 0, max)
1166 b = append(b, '[')
1167 b = p.ip.appendTo4In6(b)
1168 } else {
1169 const max = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535")
1170 b = make([]byte, 0, max)
1171 b = append(b, '[')
1172 b = p.ip.appendTo6(b)
1173 }
1174 b = append(b, ']')
1175 }
1176 b = append(b, ':')
1177 b = strconv.AppendUint(b, uint64(p.port), 10)
1178 return string(b)
1179 }
1180
1181
1182
1183
1184 func (p AddrPort) AppendTo(b []byte) []byte {
1185 switch p.ip.z {
1186 case z0:
1187 return b
1188 case z4:
1189 b = p.ip.appendTo4(b)
1190 default:
1191 b = append(b, '[')
1192 if p.ip.Is4In6() {
1193 b = p.ip.appendTo4In6(b)
1194 } else {
1195 b = p.ip.appendTo6(b)
1196 }
1197 b = append(b, ']')
1198 }
1199 b = append(b, ':')
1200 b = strconv.AppendUint(b, uint64(p.port), 10)
1201 return b
1202 }
1203
1204
1205
1206 func (p AddrPort) AppendText(b []byte) ([]byte, error) {
1207 return p.AppendTo(b), nil
1208 }
1209
1210
1211
1212
1213 func (p AddrPort) MarshalText() ([]byte, error) {
1214 buf := []byte{}
1215 switch p.ip.z {
1216 case z0:
1217 case z4:
1218 const maxCap = len("255.255.255.255:65535")
1219 buf = make([]byte, 0, maxCap)
1220 default:
1221 const maxCap = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535")
1222 buf = make([]byte, 0, maxCap)
1223 }
1224 return p.AppendText(buf)
1225 }
1226
1227
1228
1229
1230 func (p *AddrPort) UnmarshalText(text []byte) error {
1231 if len(text) == 0 {
1232 *p = AddrPort{}
1233 return nil
1234 }
1235 var err error
1236 *p, err = ParseAddrPort(string(text))
1237 return err
1238 }
1239
1240
1241
1242
1243 func (p AddrPort) AppendBinary(b []byte) ([]byte, error) {
1244 b, err := p.Addr().AppendBinary(b)
1245 if err != nil {
1246 return nil, err
1247 }
1248 return byteorder.LEAppendUint16(b, p.Port()), nil
1249 }
1250
1251
1252
1253
1254 func (p AddrPort) MarshalBinary() ([]byte, error) {
1255 return p.AppendBinary(make([]byte, 0, p.Addr().marshalBinarySize()+2))
1256 }
1257
1258
1259
1260 func (p *AddrPort) UnmarshalBinary(b []byte) error {
1261 if len(b) < 2 {
1262 return errors.New("unexpected slice size")
1263 }
1264 var addr Addr
1265 err := addr.UnmarshalBinary(b[:len(b)-2])
1266 if err != nil {
1267 return err
1268 }
1269 *p = AddrPortFrom(addr, byteorder.LEUint16(b[len(b)-2:]))
1270 return nil
1271 }
1272
1273
1274
1275
1276
1277 type Prefix struct {
1278 ip Addr
1279
1280
1281
1282 bitsPlusOne uint8
1283 }
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293 func PrefixFrom(ip Addr, bits int) Prefix {
1294 var bitsPlusOne uint8
1295 if !ip.isZero() && bits >= 0 && bits <= ip.BitLen() {
1296 bitsPlusOne = uint8(bits) + 1
1297 }
1298 return Prefix{
1299 ip: ip.withoutZone(),
1300 bitsPlusOne: bitsPlusOne,
1301 }
1302 }
1303
1304
1305 func (p Prefix) Addr() Addr { return p.ip }
1306
1307
1308
1309
1310 func (p Prefix) Bits() int { return int(p.bitsPlusOne) - 1 }
1311
1312
1313
1314
1315 func (p Prefix) IsValid() bool { return p.bitsPlusOne > 0 }
1316
1317 func (p Prefix) isZero() bool { return p == Prefix{} }
1318
1319
1320 func (p Prefix) IsSingleIP() bool { return p.IsValid() && p.Bits() == p.ip.BitLen() }
1321
1322
1323
1324
1325
1326
1327 func (p Prefix) Compare(p2 Prefix) int {
1328
1329
1330
1331 if c := p.Masked().Addr().Compare(p2.Masked().Addr()); c != 0 {
1332 return c
1333 }
1334
1335 if c := cmp.Compare(p.Bits(), p2.Bits()); c != 0 {
1336 return c
1337 }
1338
1339 return p.Addr().Compare(p2.Addr())
1340 }
1341
1342 type parsePrefixError struct {
1343 in string
1344 msg string
1345 }
1346
1347 func (err parsePrefixError) Error() string {
1348 return "netip.ParsePrefix(" + strconv.Quote(err.in) + "): " + err.msg
1349 }
1350
1351
1352
1353
1354
1355
1356
1357
1358 func ParsePrefix(s string) (Prefix, error) {
1359 i := bytealg.LastIndexByteString(s, '/')
1360 if i < 0 {
1361 return Prefix{}, parsePrefixError{in: s, msg: "no '/'"}
1362 }
1363 ip, err := ParseAddr(s[:i])
1364 if err != nil {
1365 return Prefix{}, parsePrefixError{in: s, msg: err.Error()}
1366 }
1367
1368 if ip.Is6() && ip.z != z6noz {
1369 return Prefix{}, parsePrefixError{in: s, msg: "IPv6 zones cannot be present in a prefix"}
1370 }
1371
1372 bitsStr := s[i+1:]
1373
1374
1375 if len(bitsStr) > 1 && (bitsStr[0] < '1' || bitsStr[0] > '9') {
1376 return Prefix{}, parsePrefixError{in: s, msg: "bad bits after slash: " + strconv.Quote(bitsStr)}
1377 }
1378
1379 bits, err := strconv.Atoi(bitsStr)
1380 if err != nil {
1381 return Prefix{}, parsePrefixError{in: s, msg: "bad bits after slash: " + strconv.Quote(bitsStr)}
1382 }
1383 maxBits := 32
1384 if ip.Is6() {
1385 maxBits = 128
1386 }
1387 if bits < 0 || bits > maxBits {
1388 return Prefix{}, parsePrefixError{in: s, msg: "prefix length out of range"}
1389 }
1390 return PrefixFrom(ip, bits), nil
1391 }
1392
1393
1394
1395 func MustParsePrefix(s string) Prefix {
1396 ip, err := ParsePrefix(s)
1397 if err != nil {
1398 panic(err)
1399 }
1400 return ip
1401 }
1402
1403
1404
1405
1406
1407 func (p Prefix) Masked() Prefix {
1408 m, _ := p.ip.Prefix(p.Bits())
1409 return m
1410 }
1411
1412
1413
1414
1415
1416
1417
1418
1419 func (p Prefix) Contains(ip Addr) bool {
1420 if !p.IsValid() || ip.hasZone() {
1421 return false
1422 }
1423 if f1, f2 := p.ip.BitLen(), ip.BitLen(); f1 == 0 || f2 == 0 || f1 != f2 {
1424 return false
1425 }
1426 if ip.Is4() {
1427
1428
1429
1430
1431
1432
1433
1434
1435 return uint32((ip.addr.lo^p.ip.addr.lo)>>((32-p.Bits())&63)) == 0
1436 } else {
1437
1438
1439
1440 return ip.addr.xor(p.ip.addr).and(mask6(p.Bits())).isZero()
1441 }
1442 }
1443
1444
1445
1446
1447
1448
1449 func (p Prefix) Overlaps(o Prefix) bool {
1450 if !p.IsValid() || !o.IsValid() {
1451 return false
1452 }
1453 if p == o {
1454 return true
1455 }
1456 if p.ip.Is4() != o.ip.Is4() {
1457 return false
1458 }
1459 var minBits int
1460 if pb, ob := p.Bits(), o.Bits(); pb < ob {
1461 minBits = pb
1462 } else {
1463 minBits = ob
1464 }
1465 if minBits == 0 {
1466 return true
1467 }
1468
1469
1470
1471
1472 var err error
1473 if p, err = p.ip.Prefix(minBits); err != nil {
1474 return false
1475 }
1476 if o, err = o.ip.Prefix(minBits); err != nil {
1477 return false
1478 }
1479 return p.ip == o.ip
1480 }
1481
1482
1483
1484
1485 func (p Prefix) AppendTo(b []byte) []byte {
1486 if p.isZero() {
1487 return b
1488 }
1489 if !p.IsValid() {
1490 return append(b, "invalid Prefix"...)
1491 }
1492
1493 if p.ip.z == z4 {
1494 b = p.ip.appendTo4(b)
1495 } else {
1496 if p.ip.Is4In6() {
1497 b = append(b, "::ffff:"...)
1498 b = p.ip.Unmap().appendTo4(b)
1499 } else {
1500 b = p.ip.appendTo6(b)
1501 }
1502 }
1503
1504 b = append(b, '/')
1505 b = appendDecimal(b, uint8(p.Bits()))
1506 return b
1507 }
1508
1509
1510
1511 func (p Prefix) AppendText(b []byte) ([]byte, error) {
1512 return p.AppendTo(b), nil
1513 }
1514
1515
1516
1517
1518 func (p Prefix) MarshalText() ([]byte, error) {
1519 buf := []byte{}
1520 switch p.ip.z {
1521 case z0:
1522 case z4:
1523 const maxCap = len("255.255.255.255/32")
1524 buf = make([]byte, 0, maxCap)
1525 default:
1526 const maxCap = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0/128")
1527 buf = make([]byte, 0, maxCap)
1528 }
1529 return p.AppendText(buf)
1530 }
1531
1532
1533
1534
1535 func (p *Prefix) UnmarshalText(text []byte) error {
1536 if len(text) == 0 {
1537 *p = Prefix{}
1538 return nil
1539 }
1540 var err error
1541 *p, err = ParsePrefix(string(text))
1542 return err
1543 }
1544
1545
1546
1547
1548 func (p Prefix) AppendBinary(b []byte) ([]byte, error) {
1549 b, err := p.Addr().withoutZone().AppendBinary(b)
1550 if err != nil {
1551 return nil, err
1552 }
1553 return append(b, uint8(p.Bits())), nil
1554 }
1555
1556
1557
1558
1559 func (p Prefix) MarshalBinary() ([]byte, error) {
1560
1561 return p.AppendBinary(make([]byte, 0, p.Addr().withoutZone().marshalBinarySize()+1))
1562 }
1563
1564
1565
1566 func (p *Prefix) UnmarshalBinary(b []byte) error {
1567 if len(b) < 1 {
1568 return errors.New("unexpected slice size")
1569 }
1570 var addr Addr
1571 err := addr.UnmarshalBinary(b[:len(b)-1])
1572 if err != nil {
1573 return err
1574 }
1575 *p = PrefixFrom(addr, int(b[len(b)-1]))
1576 return nil
1577 }
1578
1579
1580 func (p Prefix) String() string {
1581 if !p.IsValid() {
1582 return "invalid Prefix"
1583 }
1584 var b []byte
1585 switch {
1586 case p.ip.z == z4:
1587 const maxCap = len("255.255.255.255/32")
1588 b = make([]byte, 0, maxCap)
1589 b = p.ip.appendTo4(b)
1590 case p.ip.Is4In6():
1591 const maxCap = len("::ffff:255.255.255.255/32")
1592 b = make([]byte, 0, maxCap)
1593 b = append(b, "::ffff:"...)
1594 b = p.ip.Unmap().appendTo4(b)
1595 default:
1596 const maxCap = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")
1597 b = make([]byte, 0, maxCap)
1598 b = p.ip.appendTo6(b)
1599 }
1600 b = append(b, '/')
1601 b = appendDecimal(b, uint8(p.Bits()))
1602 return string(b)
1603 }
1604
View as plain text