github.com/haraldrudell/parl@v0.4.176/pnet/pnet.go (about) 1 /* 2 © 2021–present Harald Rudell <harald.rudell@gmail.com> (https://haraldrudell.github.io/haraldrudell/) 3 ISC License 4 */ 5 6 // Package pnet provides IP-related functions with few dependencies beyond the net package 7 package pnet 8 9 import ( 10 "net" 11 "net/netip" 12 "strconv" 13 "strings" 14 ) 15 16 const ( 17 // zeroSuffix is used to shorten IPv4 addresses: “0.0.0.0/1” → “0/1” 18 zeroSuffix = ".0" 19 ) 20 21 // DefaultRouteIPv4 is the default route “0/0” for IPv4 22 var DefaultRouteIPv4 = netip.MustParsePrefix("0.0.0.0/0") 23 24 // VPNRoute0IPv4 is overriding VPN route “0/1” for IPv4 25 var VPNRoute0IPv4 = netip.MustParsePrefix("0.0.0.0/1") 26 27 // VPNRoute128IPv4 is overriding VPN route “128/1” for IPv4 28 var VPNRoute128IPv4 = netip.MustParsePrefix("128.0.0.0/1") 29 30 // DefaultRouteIPv6 is the default route “::/0” for IPv6 31 var DefaultRouteIPv6 = netip.MustParsePrefix("::/0") 32 33 // VPNRouteIPv6 is overriding VPN route “::/3” for IPv6 34 var VPNRouteIPv6 = netip.MustParsePrefix("::/3") 35 36 // IsNetwork determines if IP is the network address (all zeros) for this Mask 37 // for 1.2.3.4/24 the network address 1.2.3.0 returns true 38 func IsNetwork(IP net.IP, IPMask net.IPMask) (isNetwork bool) { 39 if len(IP) != net.IPv4len && len(IP) != net.IPv6len { 40 return 41 } 42 isNetwork = IsZeros(IP.Mask(InvertMask(IPMask))) 43 return 44 } 45 46 // IsZeros determines if every byte of the IP address is zero 47 func IsZeros(p net.IP) bool { 48 for i := 0; i < len(p); i++ { 49 if p[i] != 0 { 50 return false 51 } 52 } 53 return true 54 } 55 56 // IsDirect determines if the route is direct 57 // - a direct route has mask 32 or 128 bit length /32 /128 58 func IsDirect(route netip.Prefix) bool { 59 return route.Addr().Is4() && route.Bits() == 32 || 60 route.Addr().Is6() && route.Bits() == 128 61 } 62 63 // IsIPv4 determines if net.IP value is IPv4 64 func IsIPv4(ip net.IP) (isIPv4 bool) { 65 isIPv4 = len(ip.To4()) == net.IPv4len 66 return 67 } 68 69 // IsIPv6 determines if net.IP value is IPv6 70 func IsIPv6(ip net.IP) (isIPv6 bool) { 71 isIPv6 = len(ip.To4()) != net.IPv4len && len(ip) == net.IPv6len 72 return 73 } 74 75 // IsNzIP is ip set and not zero 76 func IsNzIP(ip net.IP) bool { 77 return ip != nil && !ip.IsUnspecified() 78 } 79 80 // IsBroadcast determines whether addr is the last address for Mask 81 // - the last address is typically broadcast 82 // - for 1.2.3.4/24 the network address 1.2.3.255 returns true 83 func IsBroadcast(addr netip.Addr, IPMask net.IPMask) (isBroadcast bool) { 84 if !addr.IsValid() { 85 return 86 } 87 88 // convert to net,.IP to use Mask 89 var netIP = net.IP(addr.AsSlice()) 90 91 invertedMask := InvertMask(IPMask) 92 isBroadcast = netIP.Mask(invertedMask).Equal(net.IP(invertedMask)) 93 return 94 } 95 96 // InvertMask inverts the bits of a mask 97 // the mask for 1.2.3.4/24 is normally ffffff00 or []byte{255, 255, 255, 0} 98 func InvertMask(IPMask net.IPMask) (out net.IPMask) { 99 out = make(net.IPMask, len(IPMask)) 100 for i, b := range IPMask { 101 out[i] = ^b 102 } 103 return 104 } 105 106 // IPNetString is abbreviated form 0/0 107 func IPNetString(ipNet net.IPNet) (s string) { 108 ones, _ := ipNet.Mask.Size() // the /24 or /32 of CIDR 109 s = shorten(ipNet.IP) + "/" + strconv.Itoa(ones) 110 return 111 } 112 113 func shorten(IP net.IP) (s string) { 114 s = IP.String() 115 if len(IP) != net.IPv4len { 116 return 117 } 118 for strings.HasSuffix(s, zeroSuffix) { 119 s = s[:len(s)-len(zeroSuffix)] 120 } 121 return 122 } 123 124 // IsErrClosed returns true if err is when waiting for accept and the socket is closed 125 // - can be used with net.Conn.Accept 126 func IsErrClosed(err error) (isErrNetClosing bool) { 127 // if err is nil, ok is false 128 if netOpError, ok := err.(*net.OpError); ok { // error occured during the operation 129 isErrNetClosing = netOpError.Err == net.ErrClosed // and it is that the listener was closed 130 } 131 return 132 } 133 134 func NetworkPrefixBitCount(byts []byte) (bits int) { 135 136 // count bits that are 1 from the high order bit until a zero bit is found 137 for _, byt := range byts { 138 if byt == 255 { 139 bits += 8 140 continue 141 } 142 for byt != 0 { 143 if byt&128 != 0 { 144 bits++ 145 } 146 byt <<= 1 147 } 148 break 149 } 150 return 151 }