summaryrefslogtreecommitdiff
path: root/vendor/k8s.io/apimachinery/pkg/util/net
diff options
context:
space:
mode:
authorDaniel J Walsh <dwalsh@redhat.com>2018-03-26 18:26:55 -0400
committerAtomic Bot <atomic-devel@projectatomic.io>2018-03-27 18:09:12 +0000
commitaf64e10400f8533a0c48ecdf5ab9b7fbf329e14e (patch)
tree59160e3841b440dd35189c724bbb4375a7be173b /vendor/k8s.io/apimachinery/pkg/util/net
parent26d7e3c7b85e28c4e42998c90fdcc14079f13eef (diff)
downloadpodman-af64e10400f8533a0c48ecdf5ab9b7fbf329e14e.tar.gz
podman-af64e10400f8533a0c48ecdf5ab9b7fbf329e14e.tar.bz2
podman-af64e10400f8533a0c48ecdf5ab9b7fbf329e14e.zip
Vendor in lots of kubernetes stuff to shrink image size
Signed-off-by: Daniel J Walsh <dwalsh@redhat.com> Closes: #554 Approved by: mheon
Diffstat (limited to 'vendor/k8s.io/apimachinery/pkg/util/net')
-rw-r--r--vendor/k8s.io/apimachinery/pkg/util/net/http.go49
-rw-r--r--vendor/k8s.io/apimachinery/pkg/util/net/interface.go314
-rw-r--r--vendor/k8s.io/apimachinery/pkg/util/net/util.go14
3 files changed, 261 insertions, 116 deletions
diff --git a/vendor/k8s.io/apimachinery/pkg/util/net/http.go b/vendor/k8s.io/apimachinery/pkg/util/net/http.go
index adb80813b..bc2a531b9 100644
--- a/vendor/k8s.io/apimachinery/pkg/util/net/http.go
+++ b/vendor/k8s.io/apimachinery/pkg/util/net/http.go
@@ -26,6 +26,7 @@ import (
"net/http"
"net/url"
"os"
+ "path"
"strconv"
"strings"
@@ -33,6 +34,26 @@ import (
"golang.org/x/net/http2"
)
+// JoinPreservingTrailingSlash does a path.Join of the specified elements,
+// preserving any trailing slash on the last non-empty segment
+func JoinPreservingTrailingSlash(elem ...string) string {
+ // do the basic path join
+ result := path.Join(elem...)
+
+ // find the last non-empty segment
+ for i := len(elem) - 1; i >= 0; i-- {
+ if len(elem[i]) > 0 {
+ // if the last segment ended in a slash, ensure our result does as well
+ if strings.HasSuffix(elem[i], "/") && !strings.HasSuffix(result, "/") {
+ result += "/"
+ }
+ break
+ }
+ }
+
+ return result
+}
+
// IsProbableEOF returns true if the given error resembles a connection termination
// scenario that would justify assuming that the watch is empty.
// These errors are what the Go http stack returns back to us which are general
@@ -108,7 +129,7 @@ func DialerFor(transport http.RoundTripper) (DialFunc, error) {
case RoundTripperWrapper:
return DialerFor(transport.WrappedRoundTripper())
default:
- return nil, fmt.Errorf("unknown transport type: %v", transport)
+ return nil, fmt.Errorf("unknown transport type: %T", transport)
}
}
@@ -129,7 +150,7 @@ func TLSClientConfig(transport http.RoundTripper) (*tls.Config, error) {
case RoundTripperWrapper:
return TLSClientConfig(transport.WrappedRoundTripper())
default:
- return nil, fmt.Errorf("unknown transport type: %v", transport)
+ return nil, fmt.Errorf("unknown transport type: %T", transport)
}
}
@@ -235,8 +256,11 @@ func isDefault(transportProxier func(*http.Request) (*url.URL, error)) bool {
// NewProxierWithNoProxyCIDR constructs a Proxier function that respects CIDRs in NO_PROXY and delegates if
// no matching CIDRs are found
func NewProxierWithNoProxyCIDR(delegate func(req *http.Request) (*url.URL, error)) func(req *http.Request) (*url.URL, error) {
- // we wrap the default method, so we only need to perform our check if the NO_PROXY envvar has a CIDR in it
+ // we wrap the default method, so we only need to perform our check if the NO_PROXY (or no_proxy) envvar has a CIDR in it
noProxyEnv := os.Getenv("NO_PROXY")
+ if noProxyEnv == "" {
+ noProxyEnv = os.Getenv("no_proxy")
+ }
noProxyRules := strings.Split(noProxyEnv, ",")
cidrs := []*net.IPNet{}
@@ -252,17 +276,7 @@ func NewProxierWithNoProxyCIDR(delegate func(req *http.Request) (*url.URL, error
}
return func(req *http.Request) (*url.URL, error) {
- host := req.URL.Host
- // for some urls, the Host is already the host, not the host:port
- if net.ParseIP(host) == nil {
- var err error
- host, _, err = net.SplitHostPort(req.URL.Host)
- if err != nil {
- return delegate(req)
- }
- }
-
- ip := net.ParseIP(host)
+ ip := net.ParseIP(req.URL.Hostname())
if ip == nil {
return delegate(req)
}
@@ -277,6 +291,13 @@ func NewProxierWithNoProxyCIDR(delegate func(req *http.Request) (*url.URL, error
}
}
+// DialerFunc implements Dialer for the provided function.
+type DialerFunc func(req *http.Request) (net.Conn, error)
+
+func (fn DialerFunc) Dial(req *http.Request) (net.Conn, error) {
+ return fn(req)
+}
+
// Dialer dials a host and writes a request to it.
type Dialer interface {
// Dial connects to the host specified by req's URL, writes the request to the connection, and
diff --git a/vendor/k8s.io/apimachinery/pkg/util/net/interface.go b/vendor/k8s.io/apimachinery/pkg/util/net/interface.go
index a1e53d2e4..42816bd70 100644
--- a/vendor/k8s.io/apimachinery/pkg/util/net/interface.go
+++ b/vendor/k8s.io/apimachinery/pkg/util/net/interface.go
@@ -29,18 +29,47 @@ import (
"github.com/golang/glog"
)
+type AddressFamily uint
+
+const (
+ familyIPv4 AddressFamily = 4
+ familyIPv6 AddressFamily = 6
+)
+
+const (
+ ipv4RouteFile = "/proc/net/route"
+ ipv6RouteFile = "/proc/net/ipv6_route"
+)
+
type Route struct {
Interface string
Destination net.IP
Gateway net.IP
- // TODO: add more fields here if needed
+ Family AddressFamily
}
-func getRoutes(input io.Reader) ([]Route, error) {
- routes := []Route{}
- if input == nil {
- return nil, fmt.Errorf("input is nil")
+type RouteFile struct {
+ name string
+ parse func(input io.Reader) ([]Route, error)
+}
+
+var (
+ v4File = RouteFile{name: ipv4RouteFile, parse: getIPv4DefaultRoutes}
+ v6File = RouteFile{name: ipv6RouteFile, parse: getIPv6DefaultRoutes}
+)
+
+func (rf RouteFile) extract() ([]Route, error) {
+ file, err := os.Open(rf.name)
+ if err != nil {
+ return nil, err
}
+ defer file.Close()
+ return rf.parse(file)
+}
+
+// getIPv4DefaultRoutes obtains the IPv4 routes, and filters out non-default routes.
+func getIPv4DefaultRoutes(input io.Reader) ([]Route, error) {
+ routes := []Route{}
scanner := bufio.NewReader(input)
for {
line, err := scanner.ReadString('\n')
@@ -52,24 +81,71 @@ func getRoutes(input io.Reader) ([]Route, error) {
continue
}
fields := strings.Fields(line)
- routes = append(routes, Route{})
- route := &routes[len(routes)-1]
- route.Interface = fields[0]
- ip, err := parseIP(fields[1])
+ // Interested in fields:
+ // 0 - interface name
+ // 1 - destination address
+ // 2 - gateway
+ dest, err := parseIP(fields[1], familyIPv4)
+ if err != nil {
+ return nil, err
+ }
+ gw, err := parseIP(fields[2], familyIPv4)
+ if err != nil {
+ return nil, err
+ }
+ if !dest.Equal(net.IPv4zero) {
+ continue
+ }
+ routes = append(routes, Route{
+ Interface: fields[0],
+ Destination: dest,
+ Gateway: gw,
+ Family: familyIPv4,
+ })
+ }
+ return routes, nil
+}
+
+func getIPv6DefaultRoutes(input io.Reader) ([]Route, error) {
+ routes := []Route{}
+ scanner := bufio.NewReader(input)
+ for {
+ line, err := scanner.ReadString('\n')
+ if err == io.EOF {
+ break
+ }
+ fields := strings.Fields(line)
+ // Interested in fields:
+ // 0 - destination address
+ // 4 - gateway
+ // 9 - interface name
+ dest, err := parseIP(fields[0], familyIPv6)
if err != nil {
return nil, err
}
- route.Destination = ip
- ip, err = parseIP(fields[2])
+ gw, err := parseIP(fields[4], familyIPv6)
if err != nil {
return nil, err
}
- route.Gateway = ip
+ if !dest.Equal(net.IPv6zero) {
+ continue
+ }
+ if gw.Equal(net.IPv6zero) {
+ continue // loopback
+ }
+ routes = append(routes, Route{
+ Interface: fields[9],
+ Destination: dest,
+ Gateway: gw,
+ Family: familyIPv6,
+ })
}
return routes, nil
}
-func parseIP(str string) (net.IP, error) {
+// parseIP takes the hex IP address string from route file and converts it
+// to a net.IP address. For IPv4, the value must be converted to big endian.
+func parseIP(str string, family AddressFamily) (net.IP, error) {
if str == "" {
return nil, fmt.Errorf("input is nil")
}
@@ -77,11 +153,16 @@ func parseIP(str string) (net.IP, error) {
if err != nil {
return nil, err
}
- //TODO add ipv6 support
- if len(bytes) != net.IPv4len {
- return nil, fmt.Errorf("only IPv4 is supported")
+ if family == familyIPv4 {
+ if len(bytes) != net.IPv4len {
+ return nil, fmt.Errorf("invalid IPv4 address in route")
+ }
+ return net.IP([]byte{bytes[3], bytes[2], bytes[1], bytes[0]}), nil
+ }
+ // Must be IPv6
+ if len(bytes) != net.IPv6len {
+ return nil, fmt.Errorf("invalid IPv6 address in route")
}
- bytes[0], bytes[1], bytes[2], bytes[3] = bytes[3], bytes[2], bytes[1], bytes[0]
return net.IP(bytes), nil
}
@@ -96,10 +177,13 @@ func isInterfaceUp(intf *net.Interface) bool {
return false
}
-//getFinalIP method receives all the IP addrs of a Interface
-//and returns a nil if the address is Loopback, Ipv6, link-local or nil.
-//It returns a valid IPv4 if an Ipv4 address is found in the array.
-func getFinalIP(addrs []net.Addr) (net.IP, error) {
+func isLoopbackOrPointToPoint(intf *net.Interface) bool {
+ return intf.Flags&(net.FlagLoopback|net.FlagPointToPoint) != 0
+}
+
+// getMatchingGlobalIP returns the first valid global unicast address of the given
+// 'family' from the list of 'addrs'.
+func getMatchingGlobalIP(addrs []net.Addr, family AddressFamily) (net.IP, error) {
if len(addrs) > 0 {
for i := range addrs {
glog.V(4).Infof("Checking addr %s.", addrs[i].String())
@@ -107,17 +191,15 @@ func getFinalIP(addrs []net.Addr) (net.IP, error) {
if err != nil {
return nil, err
}
- //Only IPv4
- //TODO : add IPv6 support
- if ip.To4() != nil {
- if !ip.IsLoopback() && !ip.IsLinkLocalMulticast() && !ip.IsLinkLocalUnicast() {
+ if memberOf(ip, family) {
+ if ip.IsGlobalUnicast() {
glog.V(4).Infof("IP found %v", ip)
return ip, nil
} else {
- glog.V(4).Infof("Loopback/link-local found %v", ip)
+ glog.V(4).Infof("Non-global unicast address found %v", ip)
}
} else {
- glog.V(4).Infof("%v is not a valid IPv4 address", ip)
+ glog.V(4).Infof("%v is not an IPv%d address", ip, int(family))
}
}
@@ -125,7 +207,9 @@ func getFinalIP(addrs []net.Addr) (net.IP, error) {
return nil, nil
}
-func getIPFromInterface(intfName string, nw networkInterfacer) (net.IP, error) {
+// getIPFromInterface gets the IPs on an interface and returns a global unicast address, if any. The
+// interface must be up, the IP must in the family requested, and the IP must be a global unicast address.
+func getIPFromInterface(intfName string, forFamily AddressFamily, nw networkInterfacer) (net.IP, error) {
intf, err := nw.InterfaceByName(intfName)
if err != nil {
return nil, err
@@ -136,131 +220,161 @@ func getIPFromInterface(intfName string, nw networkInterfacer) (net.IP, error) {
return nil, err
}
glog.V(4).Infof("Interface %q has %d addresses :%v.", intfName, len(addrs), addrs)
- finalIP, err := getFinalIP(addrs)
+ matchingIP, err := getMatchingGlobalIP(addrs, forFamily)
if err != nil {
return nil, err
}
- if finalIP != nil {
- glog.V(4).Infof("valid IPv4 address for interface %q found as %v.", intfName, finalIP)
- return finalIP, nil
+ if matchingIP != nil {
+ glog.V(4).Infof("Found valid IPv%d address %v for interface %q.", int(forFamily), matchingIP, intfName)
+ return matchingIP, nil
}
}
-
return nil, nil
}
-func flagsSet(flags net.Flags, test net.Flags) bool {
- return flags&test != 0
-}
-
-func flagsClear(flags net.Flags, test net.Flags) bool {
- return flags&test == 0
+// memberOF tells if the IP is of the desired family. Used for checking interface addresses.
+func memberOf(ip net.IP, family AddressFamily) bool {
+ if ip.To4() != nil {
+ return family == familyIPv4
+ } else {
+ return family == familyIPv6
+ }
}
-func chooseHostInterfaceNativeGo() (net.IP, error) {
- intfs, err := net.Interfaces()
+// chooseIPFromHostInterfaces looks at all system interfaces, trying to find one that is up that
+// has a global unicast address (non-loopback, non-link local, non-point2point), and returns the IP.
+// Searches for IPv4 addresses, and then IPv6 addresses.
+func chooseIPFromHostInterfaces(nw networkInterfacer) (net.IP, error) {
+ intfs, err := nw.Interfaces()
if err != nil {
return nil, err
}
- i := 0
- var ip net.IP
- for i = range intfs {
- if flagsSet(intfs[i].Flags, net.FlagUp) && flagsClear(intfs[i].Flags, net.FlagLoopback|net.FlagPointToPoint) {
- addrs, err := intfs[i].Addrs()
+ if len(intfs) == 0 {
+ return nil, fmt.Errorf("no interfaces found on host.")
+ }
+ for _, family := range []AddressFamily{familyIPv4, familyIPv6} {
+ glog.V(4).Infof("Looking for system interface with a global IPv%d address", uint(family))
+ for _, intf := range intfs {
+ if !isInterfaceUp(&intf) {
+ glog.V(4).Infof("Skipping: down interface %q", intf.Name)
+ continue
+ }
+ if isLoopbackOrPointToPoint(&intf) {
+ glog.V(4).Infof("Skipping: LB or P2P interface %q", intf.Name)
+ continue
+ }
+ addrs, err := nw.Addrs(&intf)
if err != nil {
return nil, err
}
- if len(addrs) > 0 {
- for _, addr := range addrs {
- if addrIP, _, err := net.ParseCIDR(addr.String()); err == nil {
- if addrIP.To4() != nil {
- ip = addrIP.To4()
- if !ip.IsLinkLocalMulticast() && !ip.IsLinkLocalUnicast() {
- break
- }
- }
- }
+ if len(addrs) == 0 {
+ glog.V(4).Infof("Skipping: no addresses on interface %q", intf.Name)
+ continue
+ }
+ for _, addr := range addrs {
+ ip, _, err := net.ParseCIDR(addr.String())
+ if err != nil {
+ return nil, fmt.Errorf("Unable to parse CIDR for interface %q: %s", intf.Name, err)
+ }
+ if !memberOf(ip, family) {
+ glog.V(4).Infof("Skipping: no address family match for %q on interface %q.", ip, intf.Name)
+ continue
}
- if ip != nil {
- // This interface should suffice.
- break
+ // TODO: Decide if should open up to allow IPv6 LLAs in future.
+ if !ip.IsGlobalUnicast() {
+ glog.V(4).Infof("Skipping: non-global address %q on interface %q.", ip, intf.Name)
+ continue
}
+ glog.V(4).Infof("Found global unicast address %q on interface %q.", ip, intf.Name)
+ return ip, nil
}
}
}
- if ip == nil {
- return nil, fmt.Errorf("no acceptable interface from host")
- }
- glog.V(4).Infof("Choosing interface %s (IP %v) as default", intfs[i].Name, ip)
- return ip, nil
+ return nil, fmt.Errorf("no acceptable interface with global unicast address found on host")
}
-//ChooseHostInterface is a method used fetch an IP for a daemon.
-//It uses data from /proc/net/route file.
-//For a node with no internet connection ,it returns error
-//For a multi n/w interface node it returns the IP of the interface with gateway on it.
+// ChooseHostInterface is a method used fetch an IP for a daemon.
+// If there is no routing info file, it will choose a global IP from the system
+// interfaces. Otherwise, it will use IPv4 and IPv6 route information to return the
+// IP of the interface with a gateway on it (with priority given to IPv4). For a node
+// with no internet connection, it returns error.
func ChooseHostInterface() (net.IP, error) {
- inFile, err := os.Open("/proc/net/route")
+ var nw networkInterfacer = networkInterface{}
+ if _, err := os.Stat(ipv4RouteFile); os.IsNotExist(err) {
+ return chooseIPFromHostInterfaces(nw)
+ }
+ routes, err := getAllDefaultRoutes()
if err != nil {
- if os.IsNotExist(err) {
- return chooseHostInterfaceNativeGo()
- }
return nil, err
}
- defer inFile.Close()
- var nw networkInterfacer = networkInterface{}
- return chooseHostInterfaceFromRoute(inFile, nw)
+ return chooseHostInterfaceFromRoute(routes, nw)
}
+// networkInterfacer defines an interface for several net library functions. Production
+// code will forward to net library functions, and unit tests will override the methods
+// for testing purposes.
type networkInterfacer interface {
InterfaceByName(intfName string) (*net.Interface, error)
Addrs(intf *net.Interface) ([]net.Addr, error)
+ Interfaces() ([]net.Interface, error)
}
+// networkInterface implements the networkInterfacer interface for production code, just
+// wrapping the underlying net library function calls.
type networkInterface struct{}
func (_ networkInterface) InterfaceByName(intfName string) (*net.Interface, error) {
- intf, err := net.InterfaceByName(intfName)
- if err != nil {
- return nil, err
- }
- return intf, nil
+ return net.InterfaceByName(intfName)
}
func (_ networkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) {
- addrs, err := intf.Addrs()
- if err != nil {
- return nil, err
- }
- return addrs, nil
+ return intf.Addrs()
}
-func chooseHostInterfaceFromRoute(inFile io.Reader, nw networkInterfacer) (net.IP, error) {
- routes, err := getRoutes(inFile)
+func (_ networkInterface) Interfaces() ([]net.Interface, error) {
+ return net.Interfaces()
+}
+
+// getAllDefaultRoutes obtains IPv4 and IPv6 default routes on the node. If unable
+// to read the IPv4 routing info file, we return an error. If unable to read the IPv6
+// routing info file (which is optional), we'll just use the IPv4 route information.
+// Using all the routing info, if no default routes are found, an error is returned.
+func getAllDefaultRoutes() ([]Route, error) {
+ routes, err := v4File.extract()
if err != nil {
return nil, err
}
- zero := net.IP{0, 0, 0, 0}
- var finalIP net.IP
- for i := range routes {
- //find interface with gateway
- if routes[i].Destination.Equal(zero) {
- glog.V(4).Infof("Default route transits interface %q", routes[i].Interface)
- finalIP, err := getIPFromInterface(routes[i].Interface, nw)
+ v6Routes, _ := v6File.extract()
+ routes = append(routes, v6Routes...)
+ if len(routes) == 0 {
+ return nil, fmt.Errorf("No default routes.")
+ }
+ return routes, nil
+}
+
+// chooseHostInterfaceFromRoute cycles through each default route provided, looking for a
+// global IP address from the interface for the route. Will first look all each IPv4 route for
+// an IPv4 IP, and then will look at each IPv6 route for an IPv6 IP.
+func chooseHostInterfaceFromRoute(routes []Route, nw networkInterfacer) (net.IP, error) {
+ for _, family := range []AddressFamily{familyIPv4, familyIPv6} {
+ glog.V(4).Infof("Looking for default routes with IPv%d addresses", uint(family))
+ for _, route := range routes {
+ if route.Family != family {
+ continue
+ }
+ glog.V(4).Infof("Default route transits interface %q", route.Interface)
+ finalIP, err := getIPFromInterface(route.Interface, family, nw)
if err != nil {
return nil, err
}
if finalIP != nil {
- glog.V(4).Infof("Choosing IP %v ", finalIP)
+ glog.V(4).Infof("Found active IP %v ", finalIP)
return finalIP, nil
}
}
}
- glog.V(4).Infof("No valid IP found")
- if finalIP == nil {
- return nil, fmt.Errorf("Unable to select an IP.")
- }
- return nil, nil
+ glog.V(4).Infof("No active IP found by looking at default routes")
+ return nil, fmt.Errorf("unable to select an IP from default routes.")
}
// If bind-address is usable, return it directly
diff --git a/vendor/k8s.io/apimachinery/pkg/util/net/util.go b/vendor/k8s.io/apimachinery/pkg/util/net/util.go
index 461144f0b..8344d10c8 100644
--- a/vendor/k8s.io/apimachinery/pkg/util/net/util.go
+++ b/vendor/k8s.io/apimachinery/pkg/util/net/util.go
@@ -18,6 +18,8 @@ package net
import (
"net"
+ "net/url"
+ "os"
"reflect"
"syscall"
)
@@ -38,8 +40,16 @@ func IPNetEqual(ipnet1, ipnet2 *net.IPNet) bool {
// Returns if the given err is "connection reset by peer" error.
func IsConnectionReset(err error) bool {
- opErr, ok := err.(*net.OpError)
- if ok && opErr.Err.Error() == syscall.ECONNRESET.Error() {
+ if urlErr, ok := err.(*url.Error); ok {
+ err = urlErr.Err
+ }
+ if opErr, ok := err.(*net.OpError); ok {
+ err = opErr.Err
+ }
+ if osErr, ok := err.(*os.SyscallError); ok {
+ err = osErr.Err
+ }
+ if errno, ok := err.(syscall.Errno); ok && errno == syscall.ECONNRESET {
return true
}
return false