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 switch ip.z {
789 case z0:
790 return "invalid IP"
791 case z4:
792 return ip.string4()
793 default:
794 if ip.Is4In6() {
795 return ip.string4In6()
796 }
797 return ip.string6()
798 }
799 }
800
801
802
803
804 func (ip Addr) AppendTo(b []byte) []byte {
805 switch ip.z {
806 case z0:
807 return b
808 case z4:
809 return ip.appendTo4(b)
810 default:
811 if ip.Is4In6() {
812 return ip.appendTo4In6(b)
813 }
814 return ip.appendTo6(b)
815 }
816 }
817
818
819
820 const digits = "0123456789abcdef"
821
822
823 func appendDecimal(b []byte, x uint8) []byte {
824
825
826
827 if x >= 100 {
828 b = append(b, digits[x/100])
829 }
830 if x >= 10 {
831 b = append(b, digits[x/10%10])
832 }
833 return append(b, digits[x%10])
834 }
835
836
837 func appendHex(b []byte, x uint16) []byte {
838
839
840
841 if x >= 0x1000 {
842 b = append(b, digits[x>>12])
843 }
844 if x >= 0x100 {
845 b = append(b, digits[x>>8&0xf])
846 }
847 if x >= 0x10 {
848 b = append(b, digits[x>>4&0xf])
849 }
850 return append(b, digits[x&0xf])
851 }
852
853
854 func appendHexPad(b []byte, x uint16) []byte {
855 return append(b, digits[x>>12], digits[x>>8&0xf], digits[x>>4&0xf], digits[x&0xf])
856 }
857
858 func (ip Addr) string4() string {
859 const max = len("255.255.255.255")
860 ret := make([]byte, 0, max)
861 ret = ip.appendTo4(ret)
862 return string(ret)
863 }
864
865 func (ip Addr) appendTo4(ret []byte) []byte {
866 ret = appendDecimal(ret, ip.v4(0))
867 ret = append(ret, '.')
868 ret = appendDecimal(ret, ip.v4(1))
869 ret = append(ret, '.')
870 ret = appendDecimal(ret, ip.v4(2))
871 ret = append(ret, '.')
872 ret = appendDecimal(ret, ip.v4(3))
873 return ret
874 }
875
876 func (ip Addr) string4In6() string {
877 const max = len("::ffff:255.255.255.255%enp5s0")
878 ret := make([]byte, 0, max)
879 ret = ip.appendTo4In6(ret)
880 return string(ret)
881 }
882
883 func (ip Addr) appendTo4In6(ret []byte) []byte {
884 ret = append(ret, "::ffff:"...)
885 ret = ip.Unmap().appendTo4(ret)
886 if ip.z != z6noz {
887 ret = append(ret, '%')
888 ret = append(ret, ip.Zone()...)
889 }
890 return ret
891 }
892
893
894
895
896
897
898 func (ip Addr) string6() string {
899
900
901
902
903
904
905
906 const max = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0")
907 ret := make([]byte, 0, max)
908 ret = ip.appendTo6(ret)
909 return string(ret)
910 }
911
912 func (ip Addr) appendTo6(ret []byte) []byte {
913 zeroStart, zeroEnd := uint8(255), uint8(255)
914 for i := uint8(0); i < 8; i++ {
915 j := i
916 for j < 8 && ip.v6u16(j) == 0 {
917 j++
918 }
919 if l := j - i; l >= 2 && l > zeroEnd-zeroStart {
920 zeroStart, zeroEnd = i, j
921 }
922 }
923
924 for i := uint8(0); i < 8; i++ {
925 if i == zeroStart {
926 ret = append(ret, ':', ':')
927 i = zeroEnd
928 if i >= 8 {
929 break
930 }
931 } else if i > 0 {
932 ret = append(ret, ':')
933 }
934
935 ret = appendHex(ret, ip.v6u16(i))
936 }
937
938 if ip.z != z6noz {
939 ret = append(ret, '%')
940 ret = append(ret, ip.Zone()...)
941 }
942 return ret
943 }
944
945
946
947
948 func (ip Addr) StringExpanded() string {
949 switch ip.z {
950 case z0, z4:
951 return ip.String()
952 }
953
954 const size = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff")
955 ret := make([]byte, 0, size)
956 for i := uint8(0); i < 8; i++ {
957 if i > 0 {
958 ret = append(ret, ':')
959 }
960
961 ret = appendHexPad(ret, ip.v6u16(i))
962 }
963
964 if ip.z != z6noz {
965
966
967 ret = append(ret, '%')
968 ret = append(ret, ip.Zone()...)
969 }
970 return string(ret)
971 }
972
973
974
975 func (ip Addr) AppendText(b []byte) ([]byte, error) {
976 return ip.AppendTo(b), nil
977 }
978
979
980
981
982 func (ip Addr) MarshalText() ([]byte, error) {
983 buf := []byte{}
984 switch ip.z {
985 case z0:
986 case z4:
987 const maxCap = len("255.255.255.255")
988 buf = make([]byte, 0, maxCap)
989 default:
990 if ip.Is4In6() {
991 const maxCap = len("::ffff:255.255.255.255%enp5s0")
992 buf = make([]byte, 0, maxCap)
993 break
994 }
995 const maxCap = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0")
996 buf = make([]byte, 0, maxCap)
997 }
998 return ip.AppendText(buf)
999 }
1000
1001
1002
1003
1004
1005
1006 func (ip *Addr) UnmarshalText(text []byte) error {
1007 if len(text) == 0 {
1008 *ip = Addr{}
1009 return nil
1010 }
1011 var err error
1012 *ip, err = ParseAddr(string(text))
1013 return err
1014 }
1015
1016
1017 func (ip Addr) AppendBinary(b []byte) ([]byte, error) {
1018 switch ip.z {
1019 case z0:
1020 case z4:
1021 b = byteorder.BEAppendUint32(b, uint32(ip.addr.lo))
1022 default:
1023 b = byteorder.BEAppendUint64(b, ip.addr.hi)
1024 b = byteorder.BEAppendUint64(b, ip.addr.lo)
1025 b = append(b, ip.Zone()...)
1026 }
1027 return b, nil
1028 }
1029
1030 func (ip Addr) marshalBinarySize() int {
1031 switch ip.z {
1032 case z0:
1033 return 0
1034 case z4:
1035 return 4
1036 default:
1037 return 16 + len(ip.Zone())
1038 }
1039 }
1040
1041
1042
1043
1044
1045 func (ip Addr) MarshalBinary() ([]byte, error) {
1046 return ip.AppendBinary(make([]byte, 0, ip.marshalBinarySize()))
1047 }
1048
1049
1050
1051 func (ip *Addr) UnmarshalBinary(b []byte) error {
1052 n := len(b)
1053 switch {
1054 case n == 0:
1055 *ip = Addr{}
1056 return nil
1057 case n == 4:
1058 *ip = AddrFrom4([4]byte(b))
1059 return nil
1060 case n == 16:
1061 *ip = AddrFrom16([16]byte(b))
1062 return nil
1063 case n > 16:
1064 *ip = AddrFrom16([16]byte(b[:16])).WithZone(string(b[16:]))
1065 return nil
1066 }
1067 return errors.New("unexpected slice size")
1068 }
1069
1070
1071 type AddrPort struct {
1072 ip Addr
1073 port uint16
1074 }
1075
1076
1077
1078 func AddrPortFrom(ip Addr, port uint16) AddrPort { return AddrPort{ip: ip, port: port} }
1079
1080
1081 func (p AddrPort) Addr() Addr { return p.ip }
1082
1083
1084 func (p AddrPort) Port() uint16 { return p.port }
1085
1086
1087
1088
1089
1090
1091 func splitAddrPort(s string) (ip, port string, v6 bool, err error) {
1092 i := bytealg.LastIndexByteString(s, ':')
1093 if i == -1 {
1094 return "", "", false, errors.New("not an ip:port")
1095 }
1096
1097 ip, port = s[:i], s[i+1:]
1098 if len(ip) == 0 {
1099 return "", "", false, errors.New("no IP")
1100 }
1101 if len(port) == 0 {
1102 return "", "", false, errors.New("no port")
1103 }
1104 if ip[0] == '[' {
1105 if len(ip) < 2 || ip[len(ip)-1] != ']' {
1106 return "", "", false, errors.New("missing ]")
1107 }
1108 ip = ip[1 : len(ip)-1]
1109 v6 = true
1110 }
1111
1112 return ip, port, v6, nil
1113 }
1114
1115
1116
1117
1118
1119 func ParseAddrPort(s string) (AddrPort, error) {
1120 var ipp AddrPort
1121 ip, port, v6, err := splitAddrPort(s)
1122 if err != nil {
1123 return ipp, err
1124 }
1125 port16, err := strconv.ParseUint(port, 10, 16)
1126 if err != nil {
1127 return ipp, errors.New("invalid port " + strconv.Quote(port) + " parsing " + strconv.Quote(s))
1128 }
1129 ipp.port = uint16(port16)
1130 ipp.ip, err = ParseAddr(ip)
1131 if err != nil {
1132 return AddrPort{}, err
1133 }
1134 if v6 && ipp.ip.Is4() {
1135 return AddrPort{}, errors.New("invalid ip:port " + strconv.Quote(s) + ", square brackets can only be used with IPv6 addresses")
1136 } else if !v6 && ipp.ip.Is6() {
1137 return AddrPort{}, errors.New("invalid ip:port " + strconv.Quote(s) + ", IPv6 addresses must be surrounded by square brackets")
1138 }
1139 return ipp, nil
1140 }
1141
1142
1143
1144 func MustParseAddrPort(s string) AddrPort {
1145 ip, err := ParseAddrPort(s)
1146 if err != nil {
1147 panic(err)
1148 }
1149 return ip
1150 }
1151
1152
1153
1154 func (p AddrPort) IsValid() bool { return p.ip.IsValid() }
1155
1156
1157
1158
1159 func (p AddrPort) Compare(p2 AddrPort) int {
1160 if c := p.Addr().Compare(p2.Addr()); c != 0 {
1161 return c
1162 }
1163 return cmp.Compare(p.Port(), p2.Port())
1164 }
1165
1166 func (p AddrPort) String() string {
1167 var b []byte
1168 switch p.ip.z {
1169 case z0:
1170 return "invalid AddrPort"
1171 case z4:
1172 const max = len("255.255.255.255:65535")
1173 b = make([]byte, 0, max)
1174 b = p.ip.appendTo4(b)
1175 default:
1176 if p.ip.Is4In6() {
1177 const max = len("[::ffff:255.255.255.255%enp5s0]:65535")
1178 b = make([]byte, 0, max)
1179 b = append(b, '[')
1180 b = p.ip.appendTo4In6(b)
1181 } else {
1182 const max = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535")
1183 b = make([]byte, 0, max)
1184 b = append(b, '[')
1185 b = p.ip.appendTo6(b)
1186 }
1187 b = append(b, ']')
1188 }
1189 b = append(b, ':')
1190 b = strconv.AppendUint(b, uint64(p.port), 10)
1191 return string(b)
1192 }
1193
1194
1195
1196
1197 func (p AddrPort) AppendTo(b []byte) []byte {
1198 switch p.ip.z {
1199 case z0:
1200 return b
1201 case z4:
1202 b = p.ip.appendTo4(b)
1203 default:
1204 b = append(b, '[')
1205 if p.ip.Is4In6() {
1206 b = p.ip.appendTo4In6(b)
1207 } else {
1208 b = p.ip.appendTo6(b)
1209 }
1210 b = append(b, ']')
1211 }
1212 b = append(b, ':')
1213 b = strconv.AppendUint(b, uint64(p.port), 10)
1214 return b
1215 }
1216
1217
1218
1219 func (p AddrPort) AppendText(b []byte) ([]byte, error) {
1220 return p.AppendTo(b), nil
1221 }
1222
1223
1224
1225
1226 func (p AddrPort) MarshalText() ([]byte, error) {
1227 buf := []byte{}
1228 switch p.ip.z {
1229 case z0:
1230 case z4:
1231 const maxCap = len("255.255.255.255:65535")
1232 buf = make([]byte, 0, maxCap)
1233 default:
1234 const maxCap = len("[ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0]:65535")
1235 buf = make([]byte, 0, maxCap)
1236 }
1237 return p.AppendText(buf)
1238 }
1239
1240
1241
1242
1243 func (p *AddrPort) UnmarshalText(text []byte) error {
1244 if len(text) == 0 {
1245 *p = AddrPort{}
1246 return nil
1247 }
1248 var err error
1249 *p, err = ParseAddrPort(string(text))
1250 return err
1251 }
1252
1253
1254
1255
1256 func (p AddrPort) AppendBinary(b []byte) ([]byte, error) {
1257 b, err := p.Addr().AppendBinary(b)
1258 if err != nil {
1259 return nil, err
1260 }
1261 return byteorder.LEAppendUint16(b, p.Port()), nil
1262 }
1263
1264
1265
1266
1267 func (p AddrPort) MarshalBinary() ([]byte, error) {
1268 return p.AppendBinary(make([]byte, 0, p.Addr().marshalBinarySize()+2))
1269 }
1270
1271
1272
1273 func (p *AddrPort) UnmarshalBinary(b []byte) error {
1274 if len(b) < 2 {
1275 return errors.New("unexpected slice size")
1276 }
1277 var addr Addr
1278 err := addr.UnmarshalBinary(b[:len(b)-2])
1279 if err != nil {
1280 return err
1281 }
1282 *p = AddrPortFrom(addr, byteorder.LEUint16(b[len(b)-2:]))
1283 return nil
1284 }
1285
1286
1287
1288
1289
1290 type Prefix struct {
1291 ip Addr
1292
1293
1294
1295 bitsPlusOne uint8
1296 }
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306 func PrefixFrom(ip Addr, bits int) Prefix {
1307 var bitsPlusOne uint8
1308 if !ip.isZero() && bits >= 0 && bits <= ip.BitLen() {
1309 bitsPlusOne = uint8(bits) + 1
1310 }
1311 return Prefix{
1312 ip: ip.withoutZone(),
1313 bitsPlusOne: bitsPlusOne,
1314 }
1315 }
1316
1317
1318 func (p Prefix) Addr() Addr { return p.ip }
1319
1320
1321
1322
1323 func (p Prefix) Bits() int { return int(p.bitsPlusOne) - 1 }
1324
1325
1326
1327
1328 func (p Prefix) IsValid() bool { return p.bitsPlusOne > 0 }
1329
1330 func (p Prefix) isZero() bool { return p == Prefix{} }
1331
1332
1333 func (p Prefix) IsSingleIP() bool { return p.IsValid() && p.Bits() == p.ip.BitLen() }
1334
1335
1336
1337
1338
1339
1340 func (p Prefix) Compare(p2 Prefix) int {
1341
1342
1343
1344 if c := p.Masked().Addr().Compare(p2.Masked().Addr()); c != 0 {
1345 return c
1346 }
1347
1348 if c := cmp.Compare(p.Bits(), p2.Bits()); c != 0 {
1349 return c
1350 }
1351
1352 return p.Addr().Compare(p2.Addr())
1353 }
1354
1355 type parsePrefixError struct {
1356 in string
1357 msg string
1358 }
1359
1360 func (err parsePrefixError) Error() string {
1361 return "netip.ParsePrefix(" + strconv.Quote(err.in) + "): " + err.msg
1362 }
1363
1364
1365
1366
1367
1368
1369
1370
1371 func ParsePrefix(s string) (Prefix, error) {
1372 i := bytealg.LastIndexByteString(s, '/')
1373 if i < 0 {
1374 return Prefix{}, parsePrefixError{in: s, msg: "no '/'"}
1375 }
1376 ip, err := ParseAddr(s[:i])
1377 if err != nil {
1378 return Prefix{}, parsePrefixError{in: s, msg: err.Error()}
1379 }
1380
1381 if ip.Is6() && ip.z != z6noz {
1382 return Prefix{}, parsePrefixError{in: s, msg: "IPv6 zones cannot be present in a prefix"}
1383 }
1384
1385 bitsStr := s[i+1:]
1386
1387
1388 if len(bitsStr) > 1 && (bitsStr[0] < '1' || bitsStr[0] > '9') {
1389 return Prefix{}, parsePrefixError{in: s, msg: "bad bits after slash: " + strconv.Quote(bitsStr)}
1390 }
1391
1392 bits, err := strconv.Atoi(bitsStr)
1393 if err != nil {
1394 return Prefix{}, parsePrefixError{in: s, msg: "bad bits after slash: " + strconv.Quote(bitsStr)}
1395 }
1396 maxBits := 32
1397 if ip.Is6() {
1398 maxBits = 128
1399 }
1400 if bits < 0 || bits > maxBits {
1401 return Prefix{}, parsePrefixError{in: s, msg: "prefix length out of range"}
1402 }
1403 return PrefixFrom(ip, bits), nil
1404 }
1405
1406
1407
1408 func MustParsePrefix(s string) Prefix {
1409 ip, err := ParsePrefix(s)
1410 if err != nil {
1411 panic(err)
1412 }
1413 return ip
1414 }
1415
1416
1417
1418
1419
1420 func (p Prefix) Masked() Prefix {
1421 m, _ := p.ip.Prefix(p.Bits())
1422 return m
1423 }
1424
1425
1426
1427
1428
1429
1430
1431
1432 func (p Prefix) Contains(ip Addr) bool {
1433 if !p.IsValid() || ip.hasZone() {
1434 return false
1435 }
1436 if f1, f2 := p.ip.BitLen(), ip.BitLen(); f1 == 0 || f2 == 0 || f1 != f2 {
1437 return false
1438 }
1439 if ip.Is4() {
1440
1441
1442
1443
1444
1445
1446
1447
1448 return uint32((ip.addr.lo^p.ip.addr.lo)>>((32-p.Bits())&63)) == 0
1449 } else {
1450
1451
1452
1453 return ip.addr.xor(p.ip.addr).and(mask6(p.Bits())).isZero()
1454 }
1455 }
1456
1457
1458
1459
1460
1461
1462 func (p Prefix) Overlaps(o Prefix) bool {
1463 if !p.IsValid() || !o.IsValid() {
1464 return false
1465 }
1466 if p == o {
1467 return true
1468 }
1469 if p.ip.Is4() != o.ip.Is4() {
1470 return false
1471 }
1472 var minBits int
1473 if pb, ob := p.Bits(), o.Bits(); pb < ob {
1474 minBits = pb
1475 } else {
1476 minBits = ob
1477 }
1478 if minBits == 0 {
1479 return true
1480 }
1481
1482
1483
1484
1485 var err error
1486 if p, err = p.ip.Prefix(minBits); err != nil {
1487 return false
1488 }
1489 if o, err = o.ip.Prefix(minBits); err != nil {
1490 return false
1491 }
1492 return p.ip == o.ip
1493 }
1494
1495
1496
1497
1498 func (p Prefix) AppendTo(b []byte) []byte {
1499 if p.isZero() {
1500 return b
1501 }
1502 if !p.IsValid() {
1503 return append(b, "invalid Prefix"...)
1504 }
1505
1506
1507 if p.ip.z == z4 {
1508 b = p.ip.appendTo4(b)
1509 } else {
1510 if p.ip.Is4In6() {
1511 b = append(b, "::ffff:"...)
1512 b = p.ip.Unmap().appendTo4(b)
1513 } else {
1514 b = p.ip.appendTo6(b)
1515 }
1516 }
1517
1518 b = append(b, '/')
1519 b = appendDecimal(b, uint8(p.Bits()))
1520 return b
1521 }
1522
1523
1524
1525 func (p Prefix) AppendText(b []byte) ([]byte, error) {
1526 return p.AppendTo(b), nil
1527 }
1528
1529
1530
1531
1532 func (p Prefix) MarshalText() ([]byte, error) {
1533 buf := []byte{}
1534 switch p.ip.z {
1535 case z0:
1536 case z4:
1537 const maxCap = len("255.255.255.255/32")
1538 buf = make([]byte, 0, maxCap)
1539 default:
1540 const maxCap = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff%enp5s0/128")
1541 buf = make([]byte, 0, maxCap)
1542 }
1543 return p.AppendText(buf)
1544 }
1545
1546
1547
1548
1549 func (p *Prefix) UnmarshalText(text []byte) error {
1550 if len(text) == 0 {
1551 *p = Prefix{}
1552 return nil
1553 }
1554 var err error
1555 *p, err = ParsePrefix(string(text))
1556 return err
1557 }
1558
1559
1560
1561
1562 func (p Prefix) AppendBinary(b []byte) ([]byte, error) {
1563 b, err := p.Addr().withoutZone().AppendBinary(b)
1564 if err != nil {
1565 return nil, err
1566 }
1567 return append(b, uint8(p.Bits())), nil
1568 }
1569
1570
1571
1572
1573 func (p Prefix) MarshalBinary() ([]byte, error) {
1574
1575 return p.AppendBinary(make([]byte, 0, p.Addr().withoutZone().marshalBinarySize()+1))
1576 }
1577
1578
1579
1580 func (p *Prefix) UnmarshalBinary(b []byte) error {
1581 if len(b) < 1 {
1582 return errors.New("unexpected slice size")
1583 }
1584 var addr Addr
1585 err := addr.UnmarshalBinary(b[:len(b)-1])
1586 if err != nil {
1587 return err
1588 }
1589 *p = PrefixFrom(addr, int(b[len(b)-1]))
1590 return nil
1591 }
1592
1593
1594 func (p Prefix) String() string {
1595 if !p.IsValid() {
1596 return "invalid Prefix"
1597 }
1598 var b []byte
1599 switch {
1600 case p.ip.z == z4:
1601 const maxCap = len("255.255.255.255/32")
1602 b = make([]byte, 0, maxCap)
1603 b = p.ip.appendTo4(b)
1604 case p.ip.Is4In6():
1605 const maxCap = len("::ffff:255.255.255.255/32")
1606 b = make([]byte, 0, maxCap)
1607 b = append(b, "::ffff:"...)
1608 b = p.ip.Unmap().appendTo4(b)
1609 default:
1610 const maxCap = len("ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff/128")
1611 b = make([]byte, 0, maxCap)
1612 b = p.ip.appendTo6(b)
1613 }
1614 b = append(b, '/')
1615 b = appendDecimal(b, uint8(p.Bits()))
1616 return string(b)
1617 }
1618
View as plain text