github.com/haraldrudell/parl@v0.4.176/pnet/prefix.go (about) 1 /* 2 © 2023–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 package pnet 7 8 import ( 9 "net" 10 "net/netip" 11 12 "github.com/haraldrudell/parl/perrors" 13 ) 14 15 const Do46 = true 16 17 var IPv4DefaultNetwork = netip.MustParsePrefix("0.0.0.0/0") 18 var IPv6DefaultNetwork = netip.MustParsePrefix("::/0") 19 20 // MaskToBits returns number of leading 1-bits in byts 21 // - convert from net.IPMask to netip.Prefix 22 func MaskToBits(byts []byte) (bits int, err error) { 23 var hadZero bool 24 for _, byt := range byts { 25 if hadZero && byt != 0 { 26 err = perrors.ErrorfPF("mask has intermediate zeroes: %v", byts) 27 return 28 } else if byt == 255 { 29 30 // byte with all 1s 31 bits += 8 32 continue 33 } 34 35 // byte with mixed 0 and 1 bits 36 hadZero = true 37 for byt != 0 { 38 if byt&128 != 0 { 39 bits++ 40 byt <<= 1 41 continue 42 } 43 44 // there was a zero bit before all 1 bits were found 45 err = perrors.ErrorfPF("mask has intermediate zeroes: %v", byts) 46 return 47 } 48 } 49 return 50 } 51 52 // IPNetToPrefix returns the netip.Prefix that corresponds to older type net.IPNet 53 // - net.IPNet input is "1.2.3.4/24" or "fe80::1/64" 54 // - returned netip.Prefix values are valid 55 // - returned IPv6 addresses has blank Zone 56 func IPNetToPrefix(netIPNet *net.IPNet, noIs4In6Translation ...bool) (prefix netip.Prefix, err error) { 57 var i4Translation = true 58 if len(noIs4In6Translation) > 0 { 59 i4Translation = noIs4In6Translation[0] 60 } 61 var netipAddr netip.Addr 62 var ok bool 63 if netipAddr, ok = netip.AddrFromSlice(netIPNet.IP); !ok { 64 // netIPNet.IP is []byte 65 err = perrors.ErrorfPF("conversion to netip.Addr failed: IP: %#v", netIPNet.IP) 66 return 67 } 68 // translate an IPv6 address that is 4in6 to IPv4 69 // - IPv6 "::ffff:127.0.0.1" becomes IPv4 "127.0.0.1" 70 if i4Translation && netipAddr.Is4In6() { 71 netipAddr = netip.AddrFrom4(netipAddr.As4()) 72 } 73 var bits int 74 if bits, err = MaskToBits(netIPNet.Mask); err != nil { // net.IPMask is []byte 75 return 76 } 77 var p = netip.PrefixFrom(netipAddr, bits) 78 if !p.IsValid() { 79 err = perrors.ErrorfPF("conversion to netip.Addr failed net.IPNet: %#v", netIPNet.IP) 80 return 81 } 82 83 prefix = p 84 85 return 86 } 87 88 // AddrSlicetoPrefix returns a netip.Prefix slice from an Addr slice 89 // - net.Interface.Addrs returns []net.Addr which is really []*net.IPNet 90 // - IPNet is cidr not address: netip.Prefix 91 func AddrSlicetoPrefix(addrs []net.Addr, do46 bool) (prefixes []netip.Prefix, err error) { 92 prefixes = make([]netip.Prefix, len(addrs)) 93 for i, netAddr := range addrs { 94 var ipNet *net.IPNet 95 var ok bool 96 if ipNet, ok = netAddr.(*net.IPNet); !ok { 97 err = perrors.ErrorfPF("not net.IPNet at #%d: %q", i, netAddr) 98 return 99 } 100 var netipAddr netip.Addr 101 if netipAddr, ok = netip.AddrFromSlice(ipNet.IP); !ok { 102 err = perrors.ErrorfPF("AddrFromSlice at #%d: %q", i, netAddr) 103 return 104 } 105 var bits int 106 if bits, err = MaskToBits(ipNet.Mask); perrors.IsPF(&err, "AddrFromSlice at #%d: %q %q", i, netAddr, err) { 107 return 108 } 109 if do46 && netipAddr.Is4In6() { 110 netipAddr = Addr46(netipAddr) 111 // bits is for IPv4 already 112 } 113 prefixes[i] = netip.PrefixFrom(netipAddr, bits) 114 } 115 return 116 } 117 118 func Prefix46(prefix netip.Prefix) (prefix46 netip.Prefix) { 119 var addr = prefix.Addr() 120 if !addr.Is4In6() { 121 prefix46 = prefix 122 } else { 123 prefix46 = netip.PrefixFrom(Addr46(addr), prefix.Bits()) 124 } 125 return 126 }