github.com/pwn-term/docker@v0.0.0-20210616085119-6e977cce2565/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/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  	// ErrNoDefaultRoute preformatted error
    23  	ErrNoDefaultRoute = errors.New("no default route")
    24  )
    25  
    26  // CheckNameserverOverlaps checks whether the passed network overlaps with any of the nameservers
    27  func CheckNameserverOverlaps(nameservers []string, toCheck *net.IPNet) error {
    28  	if len(nameservers) > 0 {
    29  		for _, ns := range nameservers {
    30  			_, nsNetwork, err := net.ParseCIDR(ns)
    31  			if err != nil {
    32  				return err
    33  			}
    34  			if NetworkOverlaps(toCheck, nsNetwork) {
    35  				return ErrNetworkOverlapsWithNameservers
    36  			}
    37  		}
    38  	}
    39  	return nil
    40  }
    41  
    42  // NetworkOverlaps detects overlap between one IPNet and another
    43  func NetworkOverlaps(netX *net.IPNet, netY *net.IPNet) bool {
    44  	return netX.Contains(netY.IP) || netY.Contains(netX.IP)
    45  }
    46  
    47  // NetworkRange calculates the first and last IP addresses in an IPNet
    48  func NetworkRange(network *net.IPNet) (net.IP, net.IP) {
    49  	if network == nil {
    50  		return nil, nil
    51  	}
    52  
    53  	firstIP := network.IP.Mask(network.Mask)
    54  	lastIP := types.GetIPCopy(firstIP)
    55  	for i := 0; i < len(firstIP); i++ {
    56  		lastIP[i] = firstIP[i] | ^network.Mask[i]
    57  	}
    58  
    59  	if network.IP.To4() != nil {
    60  		firstIP = firstIP.To4()
    61  		lastIP = lastIP.To4()
    62  	}
    63  
    64  	return firstIP, lastIP
    65  }
    66  
    67  // GetIfaceAddr returns the first IPv4 address and slice of IPv6 addresses for the specified network interface
    68  func GetIfaceAddr(name string) (net.Addr, []net.Addr, error) {
    69  	iface, err := net.InterfaceByName(name)
    70  	if err != nil {
    71  		return nil, nil, err
    72  	}
    73  	addrs, err := iface.Addrs()
    74  	if err != nil {
    75  		return nil, nil, err
    76  	}
    77  	var addrs4 []net.Addr
    78  	var addrs6 []net.Addr
    79  	for _, addr := range addrs {
    80  		ip := (addr.(*net.IPNet)).IP
    81  		if ip4 := ip.To4(); ip4 != nil {
    82  			addrs4 = append(addrs4, addr)
    83  		} else if ip6 := ip.To16(); len(ip6) == net.IPv6len {
    84  			addrs6 = append(addrs6, addr)
    85  		}
    86  	}
    87  	switch {
    88  	case len(addrs4) == 0:
    89  		return nil, nil, fmt.Errorf("Interface %v has no IPv4 addresses", name)
    90  	case len(addrs4) > 1:
    91  		fmt.Printf("Interface %v has more than 1 IPv4 address. Defaulting to using %v\n",
    92  			name, (addrs4[0].(*net.IPNet)).IP)
    93  	}
    94  	return addrs4[0], addrs6, nil
    95  }
    96  
    97  func genMAC(ip net.IP) net.HardwareAddr {
    98  	hw := make(net.HardwareAddr, 6)
    99  	// The first byte of the MAC address has to comply with these rules:
   100  	// 1. Unicast: Set the least-significant bit to 0.
   101  	// 2. Address is locally administered: Set the second-least-significant bit (U/L) to 1.
   102  	hw[0] = 0x02
   103  	// The first 24 bits of the MAC represent the Organizationally Unique Identifier (OUI).
   104  	// Since this address is locally administered, we can do whatever we want as long as
   105  	// it doesn't conflict with other addresses.
   106  	hw[1] = 0x42
   107  	// Fill the remaining 4 bytes based on the input
   108  	if ip == nil {
   109  		rand.Read(hw[2:])
   110  	} else {
   111  		copy(hw[2:], ip.To4())
   112  	}
   113  	return hw
   114  }
   115  
   116  // GenerateRandomMAC returns a new 6-byte(48-bit) hardware address (MAC)
   117  func GenerateRandomMAC() net.HardwareAddr {
   118  	return genMAC(nil)
   119  }
   120  
   121  // GenerateMACFromIP returns a locally administered MAC address where the 4 least
   122  // significant bytes are derived from the IPv4 address.
   123  func GenerateMACFromIP(ip net.IP) net.HardwareAddr {
   124  	return genMAC(ip)
   125  }
   126  
   127  // GenerateRandomName returns a new name joined with a prefix.  This size
   128  // specified is used to truncate the randomly generated value
   129  func GenerateRandomName(prefix string, size int) (string, error) {
   130  	id := make([]byte, 32)
   131  	if _, err := io.ReadFull(rand.Reader, id); err != nil {
   132  		return "", err
   133  	}
   134  	return prefix + hex.EncodeToString(id)[:size], nil
   135  }
   136  
   137  // ReverseIP accepts a V4 or V6 IP string in the canonical form and returns a reversed IP in
   138  // the dotted decimal form . This is used to setup the IP to service name mapping in the optimal
   139  // way for the DNS PTR queries.
   140  func ReverseIP(IP string) string {
   141  	var reverseIP []string
   142  
   143  	if net.ParseIP(IP).To4() != nil {
   144  		reverseIP = strings.Split(IP, ".")
   145  		l := len(reverseIP)
   146  		for i, j := 0, l-1; i < l/2; i, j = i+1, j-1 {
   147  			reverseIP[i], reverseIP[j] = reverseIP[j], reverseIP[i]
   148  		}
   149  	} else {
   150  		reverseIP = strings.Split(IP, ":")
   151  
   152  		// Reversed IPv6 is represented in dotted decimal instead of the typical
   153  		// colon hex notation
   154  		for key := range reverseIP {
   155  			if len(reverseIP[key]) == 0 { // expand the compressed 0s
   156  				reverseIP[key] = strings.Repeat("0000", 8-strings.Count(IP, ":"))
   157  			} else if len(reverseIP[key]) < 4 { // 0-padding needed
   158  				reverseIP[key] = strings.Repeat("0", 4-len(reverseIP[key])) + reverseIP[key]
   159  			}
   160  		}
   161  
   162  		reverseIP = strings.Split(strings.Join(reverseIP, ""), "")
   163  
   164  		l := len(reverseIP)
   165  		for i, j := 0, l-1; i < l/2; i, j = i+1, j-1 {
   166  			reverseIP[i], reverseIP[j] = reverseIP[j], reverseIP[i]
   167  		}
   168  	}
   169  
   170  	return strings.Join(reverseIP, ".")
   171  }
   172  
   173  // ParseAlias parses and validates the specified string as an alias format (name:alias)
   174  func ParseAlias(val string) (string, string, error) {
   175  	if val == "" {
   176  		return "", "", errors.New("empty string specified for alias")
   177  	}
   178  	arr := strings.Split(val, ":")
   179  	if len(arr) > 2 {
   180  		return "", "", fmt.Errorf("bad format for alias: %s", val)
   181  	}
   182  	if len(arr) == 1 {
   183  		return val, val, nil
   184  	}
   185  	return arr[0], arr[1], nil
   186  }
   187  
   188  // ValidateAlias validates that the specified string has a valid alias format (containerName:alias).
   189  func ValidateAlias(val string) (string, error) {
   190  	if _, _, err := ParseAlias(val); err != nil {
   191  		return val, err
   192  	}
   193  	return val, nil
   194  }