github.com/rawahars/moby@v24.0.4+incompatible/libnetwork/netutils/utils.go (about)

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