init
This commit is contained in:
		
							
								
								
									
										442
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/http.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										442
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/http.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,442 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package net | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
|  | ||||
| 	"golang.org/x/net/http2" | ||||
| 	"k8s.io/klog" | ||||
| ) | ||||
|  | ||||
| // 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 | ||||
| // connection closure errors (strongly correlated) and callers that need to | ||||
| // differentiate probable errors in connection behavior between normal "this is | ||||
| // disconnected" should use the method. | ||||
| func IsProbableEOF(err error) bool { | ||||
| 	if err == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	if uerr, ok := err.(*url.Error); ok { | ||||
| 		err = uerr.Err | ||||
| 	} | ||||
| 	switch { | ||||
| 	case err == io.EOF: | ||||
| 		return true | ||||
| 	case err.Error() == "http: can't write HTTP request on broken connection": | ||||
| 		return true | ||||
| 	case strings.Contains(err.Error(), "connection reset by peer"): | ||||
| 		return true | ||||
| 	case strings.Contains(strings.ToLower(err.Error()), "use of closed network connection"): | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| var defaultTransport = http.DefaultTransport.(*http.Transport) | ||||
|  | ||||
| // SetOldTransportDefaults applies the defaults from http.DefaultTransport | ||||
| // for the Proxy, Dial, and TLSHandshakeTimeout fields if unset | ||||
| func SetOldTransportDefaults(t *http.Transport) *http.Transport { | ||||
| 	if t.Proxy == nil || isDefault(t.Proxy) { | ||||
| 		// http.ProxyFromEnvironment doesn't respect CIDRs and that makes it impossible to exclude things like pod and service IPs from proxy settings | ||||
| 		// ProxierWithNoProxyCIDR allows CIDR rules in NO_PROXY | ||||
| 		t.Proxy = NewProxierWithNoProxyCIDR(http.ProxyFromEnvironment) | ||||
| 	} | ||||
| 	// If no custom dialer is set, use the default context dialer | ||||
| 	if t.DialContext == nil && t.Dial == nil { | ||||
| 		t.DialContext = defaultTransport.DialContext | ||||
| 	} | ||||
| 	if t.TLSHandshakeTimeout == 0 { | ||||
| 		t.TLSHandshakeTimeout = defaultTransport.TLSHandshakeTimeout | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| // SetTransportDefaults applies the defaults from http.DefaultTransport | ||||
| // for the Proxy, Dial, and TLSHandshakeTimeout fields if unset | ||||
| func SetTransportDefaults(t *http.Transport) *http.Transport { | ||||
| 	t = SetOldTransportDefaults(t) | ||||
| 	// Allow clients to disable http2 if needed. | ||||
| 	if s := os.Getenv("DISABLE_HTTP2"); len(s) > 0 { | ||||
| 		klog.Infof("HTTP2 has been explicitly disabled") | ||||
| 	} else { | ||||
| 		if err := http2.ConfigureTransport(t); err != nil { | ||||
| 			klog.Warningf("Transport failed http2 configuration: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| type RoundTripperWrapper interface { | ||||
| 	http.RoundTripper | ||||
| 	WrappedRoundTripper() http.RoundTripper | ||||
| } | ||||
|  | ||||
| type DialFunc func(ctx context.Context, net, addr string) (net.Conn, error) | ||||
|  | ||||
| func DialerFor(transport http.RoundTripper) (DialFunc, error) { | ||||
| 	if transport == nil { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	switch transport := transport.(type) { | ||||
| 	case *http.Transport: | ||||
| 		// transport.DialContext takes precedence over transport.Dial | ||||
| 		if transport.DialContext != nil { | ||||
| 			return transport.DialContext, nil | ||||
| 		} | ||||
| 		// adapt transport.Dial to the DialWithContext signature | ||||
| 		if transport.Dial != nil { | ||||
| 			return func(ctx context.Context, net, addr string) (net.Conn, error) { | ||||
| 				return transport.Dial(net, addr) | ||||
| 			}, nil | ||||
| 		} | ||||
| 		// otherwise return nil | ||||
| 		return nil, nil | ||||
| 	case RoundTripperWrapper: | ||||
| 		return DialerFor(transport.WrappedRoundTripper()) | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("unknown transport type: %T", transport) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type TLSClientConfigHolder interface { | ||||
| 	TLSClientConfig() *tls.Config | ||||
| } | ||||
|  | ||||
| func TLSClientConfig(transport http.RoundTripper) (*tls.Config, error) { | ||||
| 	if transport == nil { | ||||
| 		return nil, nil | ||||
| 	} | ||||
|  | ||||
| 	switch transport := transport.(type) { | ||||
| 	case *http.Transport: | ||||
| 		return transport.TLSClientConfig, nil | ||||
| 	case TLSClientConfigHolder: | ||||
| 		return transport.TLSClientConfig(), nil | ||||
| 	case RoundTripperWrapper: | ||||
| 		return TLSClientConfig(transport.WrappedRoundTripper()) | ||||
| 	default: | ||||
| 		return nil, fmt.Errorf("unknown transport type: %T", transport) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func FormatURL(scheme string, host string, port int, path string) *url.URL { | ||||
| 	return &url.URL{ | ||||
| 		Scheme: scheme, | ||||
| 		Host:   net.JoinHostPort(host, strconv.Itoa(port)), | ||||
| 		Path:   path, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func GetHTTPClient(req *http.Request) string { | ||||
| 	if ua := req.UserAgent(); len(ua) != 0 { | ||||
| 		return ua | ||||
| 	} | ||||
| 	return "unknown" | ||||
| } | ||||
|  | ||||
| // SourceIPs splits the comma separated X-Forwarded-For header or returns the X-Real-Ip header or req.RemoteAddr, | ||||
| // in that order, ignoring invalid IPs. It returns nil if all of these are empty or invalid. | ||||
| func SourceIPs(req *http.Request) []net.IP { | ||||
| 	hdr := req.Header | ||||
| 	// First check the X-Forwarded-For header for requests via proxy. | ||||
| 	hdrForwardedFor := hdr.Get("X-Forwarded-For") | ||||
| 	forwardedForIPs := []net.IP{} | ||||
| 	if hdrForwardedFor != "" { | ||||
| 		// X-Forwarded-For can be a csv of IPs in case of multiple proxies. | ||||
| 		// Use the first valid one. | ||||
| 		parts := strings.Split(hdrForwardedFor, ",") | ||||
| 		for _, part := range parts { | ||||
| 			ip := net.ParseIP(strings.TrimSpace(part)) | ||||
| 			if ip != nil { | ||||
| 				forwardedForIPs = append(forwardedForIPs, ip) | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if len(forwardedForIPs) > 0 { | ||||
| 		return forwardedForIPs | ||||
| 	} | ||||
|  | ||||
| 	// Try the X-Real-Ip header. | ||||
| 	hdrRealIp := hdr.Get("X-Real-Ip") | ||||
| 	if hdrRealIp != "" { | ||||
| 		ip := net.ParseIP(hdrRealIp) | ||||
| 		if ip != nil { | ||||
| 			return []net.IP{ip} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Fallback to Remote Address in request, which will give the correct client IP when there is no proxy. | ||||
| 	// Remote Address in Go's HTTP server is in the form host:port so we need to split that first. | ||||
| 	host, _, err := net.SplitHostPort(req.RemoteAddr) | ||||
| 	if err == nil { | ||||
| 		if remoteIP := net.ParseIP(host); remoteIP != nil { | ||||
| 			return []net.IP{remoteIP} | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Fallback if Remote Address was just IP. | ||||
| 	if remoteIP := net.ParseIP(req.RemoteAddr); remoteIP != nil { | ||||
| 		return []net.IP{remoteIP} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Extracts and returns the clients IP from the given request. | ||||
| // Looks at X-Forwarded-For header, X-Real-Ip header and request.RemoteAddr in that order. | ||||
| // Returns nil if none of them are set or is set to an invalid value. | ||||
| func GetClientIP(req *http.Request) net.IP { | ||||
| 	ips := SourceIPs(req) | ||||
| 	if len(ips) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	return ips[0] | ||||
| } | ||||
|  | ||||
| // Prepares the X-Forwarded-For header for another forwarding hop by appending the previous sender's | ||||
| // IP address to the X-Forwarded-For chain. | ||||
| func AppendForwardedForHeader(req *http.Request) { | ||||
| 	// Copied from net/http/httputil/reverseproxy.go: | ||||
| 	if clientIP, _, err := net.SplitHostPort(req.RemoteAddr); err == nil { | ||||
| 		// If we aren't the first proxy retain prior | ||||
| 		// X-Forwarded-For information as a comma+space | ||||
| 		// separated list and fold multiple headers into one. | ||||
| 		if prior, ok := req.Header["X-Forwarded-For"]; ok { | ||||
| 			clientIP = strings.Join(prior, ", ") + ", " + clientIP | ||||
| 		} | ||||
| 		req.Header.Set("X-Forwarded-For", clientIP) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var defaultProxyFuncPointer = fmt.Sprintf("%p", http.ProxyFromEnvironment) | ||||
|  | ||||
| // isDefault checks to see if the transportProxierFunc is pointing to the default one | ||||
| func isDefault(transportProxier func(*http.Request) (*url.URL, error)) bool { | ||||
| 	transportProxierPointer := fmt.Sprintf("%p", transportProxier) | ||||
| 	return transportProxierPointer == defaultProxyFuncPointer | ||||
| } | ||||
|  | ||||
| // 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 (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{} | ||||
| 	for _, noProxyRule := range noProxyRules { | ||||
| 		_, cidr, _ := net.ParseCIDR(noProxyRule) | ||||
| 		if cidr != nil { | ||||
| 			cidrs = append(cidrs, cidr) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if len(cidrs) == 0 { | ||||
| 		return delegate | ||||
| 	} | ||||
|  | ||||
| 	return func(req *http.Request) (*url.URL, error) { | ||||
| 		ip := net.ParseIP(req.URL.Hostname()) | ||||
| 		if ip == nil { | ||||
| 			return delegate(req) | ||||
| 		} | ||||
|  | ||||
| 		for _, cidr := range cidrs { | ||||
| 			if cidr.Contains(ip) { | ||||
| 				return nil, nil | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		return delegate(req) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| 	// returns the opened net.Conn. | ||||
| 	Dial(req *http.Request) (net.Conn, error) | ||||
| } | ||||
|  | ||||
| // ConnectWithRedirects uses dialer to send req, following up to 10 redirects (relative to | ||||
| // originalLocation). It returns the opened net.Conn and the raw response bytes. | ||||
| // If requireSameHostRedirects is true, only redirects to the same host are permitted. | ||||
| func ConnectWithRedirects(originalMethod string, originalLocation *url.URL, header http.Header, originalBody io.Reader, dialer Dialer, requireSameHostRedirects bool) (net.Conn, []byte, error) { | ||||
| 	const ( | ||||
| 		maxRedirects    = 9     // Fail on the 10th redirect | ||||
| 		maxResponseSize = 16384 // play it safe to allow the potential for lots of / large headers | ||||
| 	) | ||||
|  | ||||
| 	var ( | ||||
| 		location         = originalLocation | ||||
| 		method           = originalMethod | ||||
| 		intermediateConn net.Conn | ||||
| 		rawResponse      = bytes.NewBuffer(make([]byte, 0, 256)) | ||||
| 		body             = originalBody | ||||
| 	) | ||||
|  | ||||
| 	defer func() { | ||||
| 		if intermediateConn != nil { | ||||
| 			intermediateConn.Close() | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| redirectLoop: | ||||
| 	for redirects := 0; ; redirects++ { | ||||
| 		if redirects > maxRedirects { | ||||
| 			return nil, nil, fmt.Errorf("too many redirects (%d)", redirects) | ||||
| 		} | ||||
|  | ||||
| 		req, err := http.NewRequest(method, location.String(), body) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
|  | ||||
| 		req.Header = header | ||||
|  | ||||
| 		intermediateConn, err = dialer.Dial(req) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
|  | ||||
| 		// Peek at the backend response. | ||||
| 		rawResponse.Reset() | ||||
| 		respReader := bufio.NewReader(io.TeeReader( | ||||
| 			io.LimitReader(intermediateConn, maxResponseSize), // Don't read more than maxResponseSize bytes. | ||||
| 			rawResponse)) // Save the raw response. | ||||
| 		resp, err := http.ReadResponse(respReader, nil) | ||||
| 		if err != nil { | ||||
| 			// Unable to read the backend response; let the client handle it. | ||||
| 			klog.Warningf("Error reading backend response: %v", err) | ||||
| 			break redirectLoop | ||||
| 		} | ||||
|  | ||||
| 		switch resp.StatusCode { | ||||
| 		case http.StatusFound: | ||||
| 			// Redirect, continue. | ||||
| 		default: | ||||
| 			// Don't redirect. | ||||
| 			break redirectLoop | ||||
| 		} | ||||
|  | ||||
| 		// Redirected requests switch to "GET" according to the HTTP spec: | ||||
| 		// https://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3 | ||||
| 		method = "GET" | ||||
| 		// don't send a body when following redirects | ||||
| 		body = nil | ||||
|  | ||||
| 		resp.Body.Close() // not used | ||||
|  | ||||
| 		// Prepare to follow the redirect. | ||||
| 		redirectStr := resp.Header.Get("Location") | ||||
| 		if redirectStr == "" { | ||||
| 			return nil, nil, fmt.Errorf("%d response missing Location header", resp.StatusCode) | ||||
| 		} | ||||
| 		// We have to parse relative to the current location, NOT originalLocation. For example, | ||||
| 		// if we request http://foo.com/a and get back "http://bar.com/b", the result should be | ||||
| 		// http://bar.com/b. If we then make that request and get back a redirect to "/c", the result | ||||
| 		// should be http://bar.com/c, not http://foo.com/c. | ||||
| 		location, err = location.Parse(redirectStr) | ||||
| 		if err != nil { | ||||
| 			return nil, nil, fmt.Errorf("malformed Location header: %v", err) | ||||
| 		} | ||||
|  | ||||
| 		// Only follow redirects to the same host. Otherwise, propagate the redirect response back. | ||||
| 		if requireSameHostRedirects && location.Hostname() != originalLocation.Hostname() { | ||||
| 			break redirectLoop | ||||
| 		} | ||||
|  | ||||
| 		// Reset the connection. | ||||
| 		intermediateConn.Close() | ||||
| 		intermediateConn = nil | ||||
| 	} | ||||
|  | ||||
| 	connToReturn := intermediateConn | ||||
| 	intermediateConn = nil // Don't close the connection when we return it. | ||||
| 	return connToReturn, rawResponse.Bytes(), nil | ||||
| } | ||||
|  | ||||
| // CloneRequest creates a shallow copy of the request along with a deep copy of the Headers. | ||||
| func CloneRequest(req *http.Request) *http.Request { | ||||
| 	r := new(http.Request) | ||||
|  | ||||
| 	// shallow clone | ||||
| 	*r = *req | ||||
|  | ||||
| 	// deep copy headers | ||||
| 	r.Header = CloneHeader(req.Header) | ||||
|  | ||||
| 	return r | ||||
| } | ||||
|  | ||||
| // CloneHeader creates a deep copy of an http.Header. | ||||
| func CloneHeader(in http.Header) http.Header { | ||||
| 	out := make(http.Header, len(in)) | ||||
| 	for key, values := range in { | ||||
| 		newValues := make([]string, len(values)) | ||||
| 		copy(newValues, values) | ||||
| 		out[key] = newValues | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
							
								
								
									
										416
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/interface.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										416
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/interface.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,416 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package net | ||||
|  | ||||
| import ( | ||||
| 	"bufio" | ||||
| 	"encoding/hex" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"net" | ||||
| 	"os" | ||||
|  | ||||
| 	"strings" | ||||
|  | ||||
| 	"k8s.io/klog" | ||||
| ) | ||||
|  | ||||
| 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 | ||||
| 	Family      AddressFamily | ||||
| } | ||||
|  | ||||
| type RouteFile struct { | ||||
| 	name  string | ||||
| 	parse func(input io.Reader) ([]Route, error) | ||||
| } | ||||
|  | ||||
| // noRoutesError can be returned by ChooseBindAddress() in case of no routes | ||||
| type noRoutesError struct { | ||||
| 	message string | ||||
| } | ||||
|  | ||||
| func (e noRoutesError) Error() string { | ||||
| 	return e.message | ||||
| } | ||||
|  | ||||
| // IsNoRoutesError checks if an error is of type noRoutesError | ||||
| func IsNoRoutesError(err error) bool { | ||||
| 	if err == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	switch err.(type) { | ||||
| 	case noRoutesError: | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| 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') | ||||
| 		if err == io.EOF { | ||||
| 			break | ||||
| 		} | ||||
| 		//ignore the headers in the route info | ||||
| 		if strings.HasPrefix(line, "Iface") { | ||||
| 			continue | ||||
| 		} | ||||
| 		fields := strings.Fields(line) | ||||
| 		// 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 | ||||
| 		} | ||||
| 		gw, err := parseIP(fields[4], familyIPv6) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		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 | ||||
| } | ||||
|  | ||||
| // 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") | ||||
| 	} | ||||
| 	bytes, err := hex.DecodeString(str) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	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") | ||||
| 	} | ||||
| 	return net.IP(bytes), nil | ||||
| } | ||||
|  | ||||
| func isInterfaceUp(intf *net.Interface) bool { | ||||
| 	if intf == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	if intf.Flags&net.FlagUp != 0 { | ||||
| 		klog.V(4).Infof("Interface %v is up", intf.Name) | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| 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 { | ||||
| 			klog.V(4).Infof("Checking addr  %s.", addrs[i].String()) | ||||
| 			ip, _, err := net.ParseCIDR(addrs[i].String()) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			if memberOf(ip, family) { | ||||
| 				if ip.IsGlobalUnicast() { | ||||
| 					klog.V(4).Infof("IP found %v", ip) | ||||
| 					return ip, nil | ||||
| 				} else { | ||||
| 					klog.V(4).Infof("Non-global unicast address found %v", ip) | ||||
| 				} | ||||
| 			} else { | ||||
| 				klog.V(4).Infof("%v is not an IPv%d address", ip, int(family)) | ||||
| 			} | ||||
|  | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| 	} | ||||
| 	if isInterfaceUp(intf) { | ||||
| 		addrs, err := nw.Addrs(intf) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		klog.V(4).Infof("Interface %q has %d addresses :%v.", intfName, len(addrs), addrs) | ||||
| 		matchingIP, err := getMatchingGlobalIP(addrs, forFamily) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if matchingIP != nil { | ||||
| 			klog.V(4).Infof("Found valid IPv%d address %v for interface %q.", int(forFamily), matchingIP, intfName) | ||||
| 			return matchingIP, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| 	} | ||||
| 	if len(intfs) == 0 { | ||||
| 		return nil, fmt.Errorf("no interfaces found on host.") | ||||
| 	} | ||||
| 	for _, family := range []AddressFamily{familyIPv4, familyIPv6} { | ||||
| 		klog.V(4).Infof("Looking for system interface with a global IPv%d address", uint(family)) | ||||
| 		for _, intf := range intfs { | ||||
| 			if !isInterfaceUp(&intf) { | ||||
| 				klog.V(4).Infof("Skipping: down interface %q", intf.Name) | ||||
| 				continue | ||||
| 			} | ||||
| 			if isLoopbackOrPointToPoint(&intf) { | ||||
| 				klog.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 { | ||||
| 				klog.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) { | ||||
| 					klog.V(4).Infof("Skipping: no address family match for %q on interface %q.", ip, intf.Name) | ||||
| 					continue | ||||
| 				} | ||||
| 				// TODO: Decide if should open up to allow IPv6 LLAs in future. | ||||
| 				if !ip.IsGlobalUnicast() { | ||||
| 					klog.V(4).Infof("Skipping: non-global address %q on interface %q.", ip, intf.Name) | ||||
| 					continue | ||||
| 				} | ||||
| 				klog.V(4).Infof("Found global unicast address %q on interface %q.", ip, intf.Name) | ||||
| 				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. | ||||
| // 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) { | ||||
| 	var nw networkInterfacer = networkInterface{} | ||||
| 	if _, err := os.Stat(ipv4RouteFile); os.IsNotExist(err) { | ||||
| 		return chooseIPFromHostInterfaces(nw) | ||||
| 	} | ||||
| 	routes, err := getAllDefaultRoutes() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	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) { | ||||
| 	return net.InterfaceByName(intfName) | ||||
| } | ||||
|  | ||||
| func (_ networkInterface) Addrs(intf *net.Interface) ([]net.Addr, error) { | ||||
| 	return intf.Addrs() | ||||
| } | ||||
|  | ||||
| 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 | ||||
| 	} | ||||
| 	v6Routes, _ := v6File.extract() | ||||
| 	routes = append(routes, v6Routes...) | ||||
| 	if len(routes) == 0 { | ||||
| 		return nil, noRoutesError{ | ||||
| 			message: fmt.Sprintf("no default routes found in %q or %q", v4File.name, v6File.name), | ||||
| 		} | ||||
| 	} | ||||
| 	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} { | ||||
| 		klog.V(4).Infof("Looking for default routes with IPv%d addresses", uint(family)) | ||||
| 		for _, route := range routes { | ||||
| 			if route.Family != family { | ||||
| 				continue | ||||
| 			} | ||||
| 			klog.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 { | ||||
| 				klog.V(4).Infof("Found active IP %v ", finalIP) | ||||
| 				return finalIP, nil | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	klog.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 | ||||
| // If bind-address is not usable (unset, 0.0.0.0, or loopback), we will use the host's default | ||||
| // interface. | ||||
| func ChooseBindAddress(bindAddress net.IP) (net.IP, error) { | ||||
| 	if bindAddress == nil || bindAddress.IsUnspecified() || bindAddress.IsLoopback() { | ||||
| 		hostIP, err := ChooseHostInterface() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		bindAddress = hostIP | ||||
| 	} | ||||
| 	return bindAddress, nil | ||||
| } | ||||
							
								
								
									
										149
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/port_range.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										149
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/port_range.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,149 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package net | ||||
|  | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| ) | ||||
|  | ||||
| // PortRange represents a range of TCP/UDP ports.  To represent a single port, | ||||
| // set Size to 1. | ||||
| type PortRange struct { | ||||
| 	Base int | ||||
| 	Size int | ||||
| } | ||||
|  | ||||
| // Contains tests whether a given port falls within the PortRange. | ||||
| func (pr *PortRange) Contains(p int) bool { | ||||
| 	return (p >= pr.Base) && ((p - pr.Base) < pr.Size) | ||||
| } | ||||
|  | ||||
| // String converts the PortRange to a string representation, which can be | ||||
| // parsed by PortRange.Set or ParsePortRange. | ||||
| func (pr PortRange) String() string { | ||||
| 	if pr.Size == 0 { | ||||
| 		return "" | ||||
| 	} | ||||
| 	return fmt.Sprintf("%d-%d", pr.Base, pr.Base+pr.Size-1) | ||||
| } | ||||
|  | ||||
| // Set parses a string of the form "value", "min-max", or "min+offset", inclusive at both ends, and | ||||
| // sets the PortRange from it.  This is part of the flag.Value and pflag.Value | ||||
| // interfaces. | ||||
| func (pr *PortRange) Set(value string) error { | ||||
| 	const ( | ||||
| 		SinglePortNotation = 1 << iota | ||||
| 		HyphenNotation | ||||
| 		PlusNotation | ||||
| 	) | ||||
|  | ||||
| 	value = strings.TrimSpace(value) | ||||
| 	hyphenIndex := strings.Index(value, "-") | ||||
| 	plusIndex := strings.Index(value, "+") | ||||
|  | ||||
| 	if value == "" { | ||||
| 		pr.Base = 0 | ||||
| 		pr.Size = 0 | ||||
| 		return nil | ||||
| 	} | ||||
|  | ||||
| 	var err error | ||||
| 	var low, high int | ||||
| 	var notation int | ||||
|  | ||||
| 	if plusIndex == -1 && hyphenIndex == -1 { | ||||
| 		notation |= SinglePortNotation | ||||
| 	} | ||||
| 	if hyphenIndex != -1 { | ||||
| 		notation |= HyphenNotation | ||||
| 	} | ||||
| 	if plusIndex != -1 { | ||||
| 		notation |= PlusNotation | ||||
| 	} | ||||
|  | ||||
| 	switch notation { | ||||
| 	case SinglePortNotation: | ||||
| 		var port int | ||||
| 		port, err = strconv.Atoi(value) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		low = port | ||||
| 		high = port | ||||
| 	case HyphenNotation: | ||||
| 		low, err = strconv.Atoi(value[:hyphenIndex]) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		high, err = strconv.Atoi(value[hyphenIndex+1:]) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	case PlusNotation: | ||||
| 		var offset int | ||||
| 		low, err = strconv.Atoi(value[:plusIndex]) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		offset, err = strconv.Atoi(value[plusIndex+1:]) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		high = low + offset | ||||
| 	default: | ||||
| 		return fmt.Errorf("unable to parse port range: %s", value) | ||||
| 	} | ||||
|  | ||||
| 	if low > 65535 || high > 65535 { | ||||
| 		return fmt.Errorf("the port range cannot be greater than 65535: %s", value) | ||||
| 	} | ||||
|  | ||||
| 	if high < low { | ||||
| 		return fmt.Errorf("end port cannot be less than start port: %s", value) | ||||
| 	} | ||||
|  | ||||
| 	pr.Base = low | ||||
| 	pr.Size = 1 + high - low | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Type returns a descriptive string about this type.  This is part of the | ||||
| // pflag.Value interface. | ||||
| func (*PortRange) Type() string { | ||||
| 	return "portRange" | ||||
| } | ||||
|  | ||||
| // ParsePortRange parses a string of the form "min-max", inclusive at both | ||||
| // ends, and initializs a new PortRange from it. | ||||
| func ParsePortRange(value string) (*PortRange, error) { | ||||
| 	pr := &PortRange{} | ||||
| 	err := pr.Set(value) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return pr, nil | ||||
| } | ||||
|  | ||||
| func ParsePortRangeOrDie(value string) *PortRange { | ||||
| 	pr, err := ParsePortRange(value) | ||||
| 	if err != nil { | ||||
| 		panic(fmt.Sprintf("couldn't parse port range %q: %v", value, err)) | ||||
| 	} | ||||
| 	return pr | ||||
| } | ||||
							
								
								
									
										77
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/port_split.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/port_split.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| /* | ||||
| Copyright 2015 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package net | ||||
|  | ||||
| import ( | ||||
| 	"strings" | ||||
|  | ||||
| 	"k8s.io/apimachinery/pkg/util/sets" | ||||
| ) | ||||
|  | ||||
| var validSchemes = sets.NewString("http", "https", "") | ||||
|  | ||||
| // SplitSchemeNamePort takes a string of the following forms: | ||||
| //  * "<name>",                 returns "",        "<name>","",      true | ||||
| //  * "<name>:<port>",          returns "",        "<name>","<port>",true | ||||
| //  * "<scheme>:<name>:<port>", returns "<scheme>","<name>","<port>",true | ||||
| // | ||||
| // Name must be non-empty or valid will be returned false. | ||||
| // Scheme must be "http" or "https" if specified | ||||
| // Port is returned as a string, and it is not required to be numeric (could be | ||||
| // used for a named port, for example). | ||||
| func SplitSchemeNamePort(id string) (scheme, name, port string, valid bool) { | ||||
| 	parts := strings.Split(id, ":") | ||||
| 	switch len(parts) { | ||||
| 	case 1: | ||||
| 		name = parts[0] | ||||
| 	case 2: | ||||
| 		name = parts[0] | ||||
| 		port = parts[1] | ||||
| 	case 3: | ||||
| 		scheme = parts[0] | ||||
| 		name = parts[1] | ||||
| 		port = parts[2] | ||||
| 	default: | ||||
| 		return "", "", "", false | ||||
| 	} | ||||
|  | ||||
| 	if len(name) > 0 && validSchemes.Has(scheme) { | ||||
| 		return scheme, name, port, true | ||||
| 	} else { | ||||
| 		return "", "", "", false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // JoinSchemeNamePort returns a string that specifies the scheme, name, and port: | ||||
| //  * "<name>" | ||||
| //  * "<name>:<port>" | ||||
| //  * "<scheme>:<name>:<port>" | ||||
| // None of the parameters may contain a ':' character | ||||
| // Name is required | ||||
| // Scheme must be "", "http", or "https" | ||||
| func JoinSchemeNamePort(scheme, name, port string) string { | ||||
| 	if len(scheme) > 0 { | ||||
| 		// Must include three segments to specify scheme | ||||
| 		return scheme + ":" + name + ":" + port | ||||
| 	} | ||||
| 	if len(port) > 0 { | ||||
| 		// Must include two segments to specify port | ||||
| 		return name + ":" + port | ||||
| 	} | ||||
| 	// Return name alone | ||||
| 	return name | ||||
| } | ||||
							
								
								
									
										56
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										56
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,56 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package net | ||||
|  | ||||
| import ( | ||||
| 	"net" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"syscall" | ||||
| ) | ||||
|  | ||||
| // IPNetEqual checks if the two input IPNets are representing the same subnet. | ||||
| // For example, | ||||
| //	10.0.0.1/24 and 10.0.0.0/24 are the same subnet. | ||||
| //	10.0.0.1/24 and 10.0.0.0/25 are not the same subnet. | ||||
| func IPNetEqual(ipnet1, ipnet2 *net.IPNet) bool { | ||||
| 	if ipnet1 == nil || ipnet2 == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	if reflect.DeepEqual(ipnet1.Mask, ipnet2.Mask) && ipnet1.Contains(ipnet2.IP) && ipnet2.Contains(ipnet1.IP) { | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Returns if the given err is "connection reset by peer" error. | ||||
| func IsConnectionReset(err error) bool { | ||||
| 	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 | ||||
| } | ||||
		Reference in New Issue
	
	Block a user