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  }