From 22a7b477b34f868d9fb26f29e93f0c19d80405b7 Mon Sep 17 00:00:00 2001 From: Brian Downs Date: Wed, 9 Mar 2022 14:25:59 -0700 Subject: [PATCH] add net util funcs (#5245) --- pkg/util/net.go | 115 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) diff --git a/pkg/util/net.go b/pkg/util/net.go index 62e14cd9b8..804a33b917 100644 --- a/pkg/util/net.go +++ b/pkg/util/net.go @@ -80,6 +80,46 @@ func JoinIP4Nets(elems []*net.IPNet) string { return strings.Join(strs, ",") } +// GetFirst6 returns the first IPv6 address from the list of IP addresses. +// If no IPv6 addresses are found, an error is raised. +func GetFirst6(elems []net.IP) (net.IP, error) { + for _, elem := range elems { + if elem == nil || elem.To16() == nil { + continue + } + return elem, nil + } + return nil, errors.New("no IPv6 address found") +} + +// GetFirst6Net returns the first IPv4 network from the list of IP networks. +// If no IPv6 addresses are found, an error is raised. +func GetFirst6Net(elems []*net.IPNet) (*net.IPNet, error) { + for _, elem := range elems { + if elem == nil || elem.IP.To16() == nil { + continue + } + return elem, nil + } + return nil, errors.New("no IPv6 CIDRs found") +} + +// GetFirst6String returns the first IPv6 address from a list of IP address strings. +// If no IPv6 addresses are found, an error is raised. +func GetFirst6String(elems []string) (string, error) { + ips := []net.IP{} + for _, elem := range elems { + for _, v := range strings.Split(elem, ",") { + ips = append(ips, net.ParseIP(v)) + } + } + ip, err := GetFirst6(ips) + if err != nil { + return "", err + } + return ip.String(), nil +} + // JoinIP6Nets stringifies and joins a list of IPv6 networks with commas. func JoinIP6Nets(elems []*net.IPNet) string { var strs []string @@ -141,3 +181,78 @@ func ParseStringSliceToIPs(s cli.StringSlice) ([]net.IP, error) { return ips, nil } + +// GetFirstIP returns the first IPv4 address from the list of IP addresses. +// If no IPv4 addresses are found, returns the first IPv6 address +// if neither of IPv4 or IPv6 are found an error is raised. +// Additionally matching listen address and IP version is returned. +func GetFirstIP(nodeIPs []net.IP) (net.IP, string, bool, error) { + nodeIP, err := GetFirst4(nodeIPs) + ListenAddress := "0.0.0.0" + IPv6only := false + if err != nil { + nodeIP, err = GetFirst6(nodeIPs) + if err != nil { + return nil, "", false, err + } + ListenAddress = "::" + IPv6only = true + } + return nodeIP, ListenAddress, IPv6only, nil +} + +// GetFirstNet returns the first IPv4 network from the list of IP networks. +// If no IPv4 addresses are found, returns the first IPv6 address +// if neither of IPv4 or IPv6 are found an error is raised. +func GetFirstNet(elems []*net.IPNet) (*net.IPNet, error) { + serviceIPRange, err := GetFirst4Net(elems) + if err != nil { + serviceIPRange, err = GetFirst6Net(elems) + if err != nil { + return nil, err + } + } + return serviceIPRange, nil +} + +// GetFirstString returns the first IP4 address from a list of IP address strings. +// If no IPv4 addresses are found, returns the first IPv6 address +// if neither of IPv4 or IPv6 are found an error is raised. +func GetFirstString(elems []string) (string, bool, error) { + ip, err := GetFirst4String(elems) + IPv6only := false + if err != nil { + ip, err = GetFirst6String(elems) + if err != nil { + return "", false, err + } + IPv6only = true + } + return ip, IPv6only, nil +} + +// IsIPv6OnlyCIDRs returns if +// - all are valid cidrs +// - at least one cidr from v6 family is found +// - v4 family cidr is not found +func IsIPv6OnlyCIDRs(cidrs []*net.IPNet) (bool, error) { + v4Found := false + v6Found := false + for _, cidr := range cidrs { + if cidr == nil { + return false, fmt.Errorf("cidr %v is invalid", cidr) + } + + if v4Found && v6Found { + continue + } + + if cidr.IP != nil && cidr.IP.To4() == nil { + v6Found = true + continue + } + v4Found = true + } + + return !v4Found && v6Found, nil +}