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