github.com/moby/docker@v26.1.3+incompatible/libnetwork/netutils/utils.go (about) 1 // Network utility functions. 2 3 package netutils 4 5 import ( 6 "context" 7 "crypto/rand" 8 "encoding/hex" 9 "errors" 10 "fmt" 11 "io" 12 "net" 13 "strings" 14 "sync" 15 16 "github.com/containerd/log" 17 "github.com/docker/docker/libnetwork/types" 18 ) 19 20 var ( 21 // ErrNetworkOverlapsWithNameservers preformatted error 22 ErrNetworkOverlapsWithNameservers = errors.New("requested network overlaps with nameserver") 23 // ErrNetworkOverlaps preformatted error 24 ErrNetworkOverlaps = errors.New("requested network overlaps with existing network") 25 ) 26 27 // CheckNameserverOverlaps checks whether the passed network overlaps with any of the nameservers 28 func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error { 29 if len(nameservers) > 0 { 30 for _, ns := range nameservers { 31 _, nsNetwork, err := net.ParseCIDR(ns) 32 if err != nil { 33 return err 34 } 35 if NetworkOverlaps(toCheck, nsNetwork) { 36 return ErrNetworkOverlapsWithNameservers 37 } 38 } 39 } 40 return nil 41 } 42 43 // NetworkOverlaps detects overlap between one IPNet and another 44 func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool { 45 return netX.Contains(netY.IP) || netY.Contains(netX.IP) 46 } 47 48 // NetworkRange calculates the first and last IP addresses in an IPNet 49 func NetworkRange(network *net.IPNet) (net.IP, net.IP) { 50 if network == nil { 51 return nil, nil 52 } 53 54 firstIP := network.IP.Mask(network.Mask) 55 lastIP := types.GetIPCopy(firstIP) 56 for i := 0; i < len(firstIP); i++ { 57 lastIP[i] = firstIP[i] | ^network.Mask[i] 58 } 59 60 if network.IP.To4() != nil { 61 firstIP = firstIP.To4() 62 lastIP = lastIP.To4() 63 } 64 65 return firstIP, lastIP 66 } 67 68 func genMAC(ip net.IP) net.HardwareAddr { 69 hw := make(net.HardwareAddr, 6) 70 // The first byte of the MAC address has to comply with these rules: 71 // 1. Unicast: Set the least-significant bit to 0. 72 // 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1. 73 hw[0] = 0x02 74 // The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI). 75 // Since this address is locally administered, we can do whatever we want as long as 76 // it doesn't conflict with other addresses. 77 hw[1] = 0x42 78 // Fill the remaining 4 bytes based on the input 79 if ip == nil { 80 rand.Read(hw[2:]) 81 } else { 82 copy(hw[2:], ip.To4()) 83 } 84 return hw 85 } 86 87 // GenerateRandomMAC returns a new 6-byte(48-bit) hardware address (MAC) 88 func GenerateRandomMAC() net.HardwareAddr { 89 return genMAC(nil) 90 } 91 92 // GenerateMACFromIP returns a locally administered MAC address where the 4 least 93 // significant bytes are derived from the IPv4 address. 94 func GenerateMACFromIP(ip net.IP) net.HardwareAddr { 95 return genMAC(ip) 96 } 97 98 // GenerateRandomName returns a string of the specified length, created by joining the prefix to random hex characters. 99 // The length must be strictly larger than len(prefix), or an error will be returned. 100 func GenerateRandomName(prefix string, length int) (string, error) { 101 if length <= len(prefix) { 102 return "", fmt.Errorf("invalid length %d for prefix %s", length, prefix) 103 } 104 105 // We add 1 here as integer division will round down, and we want to round up. 106 b := make([]byte, (length-len(prefix)+1)/2) 107 if _, err := io.ReadFull(rand.Reader, b); err != nil { 108 return "", err 109 } 110 111 // By taking a slice here, we ensure that the string is always the correct length. 112 return (prefix + hex.EncodeToString(b))[:length], nil 113 } 114 115 // ReverseIP accepts a V4 or V6 IP string in the canonical form and returns a reversed IP in 116 // the dotted decimal form . This is used to setup the IP to service name mapping in the optimal 117 // way for the DNS PTR queries. 118 func ReverseIP(IP string) string { 119 var reverseIP []string 120 121 if net.ParseIP(IP).To4() != nil { 122 reverseIP = strings.Split(IP, ".") 123 l := len(reverseIP) 124 for i, j := 0, l-1; i < l/2; i, j = i+1, j-1 { 125 reverseIP[i], reverseIP[j] = reverseIP[j], reverseIP[i] 126 } 127 } else { 128 reverseIP = strings.Split(IP, ":") 129 130 // Reversed IPv6 is represented in dotted decimal instead of the typical 131 // colon hex notation 132 for key := range reverseIP { 133 if len(reverseIP[key]) == 0 { // expand the compressed 0s 134 reverseIP[key] = strings.Repeat("0000", 8-strings.Count(IP, ":")) 135 } else if len(reverseIP[key]) < 4 { // 0-padding needed 136 reverseIP[key] = strings.Repeat("0", 4-len(reverseIP[key])) + reverseIP[key] 137 } 138 } 139 140 reverseIP = strings.Split(strings.Join(reverseIP, ""), "") 141 142 l := len(reverseIP) 143 for i, j := 0, l-1; i < l/2; i, j = i+1, j-1 { 144 reverseIP[i], reverseIP[j] = reverseIP[j], reverseIP[i] 145 } 146 } 147 148 return strings.Join(reverseIP, ".") 149 } 150 151 var ( 152 v6ListenableCached bool 153 v6ListenableOnce sync.Once 154 ) 155 156 // IsV6Listenable returns true when `[::1]:0` is listenable. 157 // IsV6Listenable returns false mostly when the kernel was booted with `ipv6.disable=1` option. 158 func IsV6Listenable() bool { 159 v6ListenableOnce.Do(func() { 160 ln, err := net.Listen("tcp6", "[::1]:0") 161 if err != nil { 162 // When the kernel was booted with `ipv6.disable=1`, 163 // we get err "listen tcp6 [::1]:0: socket: address family not supported by protocol" 164 // https://github.com/moby/moby/issues/42288 165 log.G(context.TODO()).Debugf("v6Listenable=false (%v)", err) 166 } else { 167 v6ListenableCached = true 168 ln.Close() 169 } 170 }) 171 return v6ListenableCached 172 }