go.mod: bump client-go and api machinerie
I had to run `make generate`. Some API functions got additional parameters `Options` and `Context`. I used empty options and `context.TODO()` for now. Signed-off-by: leonnicolas <leonloechner@gmx.de>
This commit is contained in:
		
							
								
								
									
										378
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/http.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										378
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/http.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -21,18 +21,24 @@ import ( | ||||
| 	"bytes" | ||||
| 	"context" | ||||
| 	"crypto/tls" | ||||
| 	"errors" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"mime" | ||||
| 	"net" | ||||
| 	"net/http" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"regexp" | ||||
| 	"strconv" | ||||
| 	"strings" | ||||
| 	"time" | ||||
| 	"unicode" | ||||
| 	"unicode/utf8" | ||||
|  | ||||
| 	"golang.org/x/net/http2" | ||||
| 	"k8s.io/klog" | ||||
| 	"k8s.io/klog/v2" | ||||
| ) | ||||
|  | ||||
| // JoinPreservingTrailingSlash does a path.Join of the specified elements, | ||||
| @@ -55,6 +61,15 @@ func JoinPreservingTrailingSlash(elem ...string) string { | ||||
| 	return result | ||||
| } | ||||
|  | ||||
| // IsTimeout returns true if the given error is a network timeout error | ||||
| func IsTimeout(err error) bool { | ||||
| 	var neterr net.Error | ||||
| 	if errors.As(err, &neterr) { | ||||
| 		return neterr != nil && neterr.Timeout() | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // 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 | ||||
| @@ -65,13 +80,16 @@ func IsProbableEOF(err error) bool { | ||||
| 	if err == nil { | ||||
| 		return false | ||||
| 	} | ||||
| 	if uerr, ok := err.(*url.Error); ok { | ||||
| 	var uerr *url.Error | ||||
| 	if errors.As(err, &uerr) { | ||||
| 		err = uerr.Err | ||||
| 	} | ||||
| 	msg := err.Error() | ||||
| 	switch { | ||||
| 	case err == io.EOF: | ||||
| 		return true | ||||
| 	case err == io.ErrUnexpectedEOF: | ||||
| 		return true | ||||
| 	case msg == "http: can't write HTTP request on broken connection": | ||||
| 		return true | ||||
| 	case strings.Contains(msg, "http2: server sent GOAWAY and closed the connection"): | ||||
| @@ -101,6 +119,9 @@ func SetOldTransportDefaults(t *http.Transport) *http.Transport { | ||||
| 	if t.TLSHandshakeTimeout == 0 { | ||||
| 		t.TLSHandshakeTimeout = defaultTransport.TLSHandshakeTimeout | ||||
| 	} | ||||
| 	if t.IdleConnTimeout == 0 { | ||||
| 		t.IdleConnTimeout = defaultTransport.IdleConnTimeout | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| @@ -110,15 +131,78 @@ 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.Info("HTTP2 has been explicitly disabled") | ||||
| 	} else if allowsHTTP2(t) { | ||||
| 		if err := configureHTTP2Transport(t); err != nil { | ||||
| 			klog.Warningf("Transport failed http2 configuration: %v", err) | ||||
| 		} | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| func readIdleTimeoutSeconds() int { | ||||
| 	ret := 30 | ||||
| 	// User can set the readIdleTimeout to 0 to disable the HTTP/2 | ||||
| 	// connection health check. | ||||
| 	if s := os.Getenv("HTTP2_READ_IDLE_TIMEOUT_SECONDS"); len(s) > 0 { | ||||
| 		i, err := strconv.Atoi(s) | ||||
| 		if err != nil { | ||||
| 			klog.Warningf("Illegal HTTP2_READ_IDLE_TIMEOUT_SECONDS(%q): %v."+ | ||||
| 				" Default value %d is used", s, err, ret) | ||||
| 			return ret | ||||
| 		} | ||||
| 		ret = i | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|  | ||||
| func pingTimeoutSeconds() int { | ||||
| 	ret := 15 | ||||
| 	if s := os.Getenv("HTTP2_PING_TIMEOUT_SECONDS"); len(s) > 0 { | ||||
| 		i, err := strconv.Atoi(s) | ||||
| 		if err != nil { | ||||
| 			klog.Warningf("Illegal HTTP2_PING_TIMEOUT_SECONDS(%q): %v."+ | ||||
| 				" Default value %d is used", s, err, ret) | ||||
| 			return ret | ||||
| 		} | ||||
| 		ret = i | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|  | ||||
| func configureHTTP2Transport(t *http.Transport) error { | ||||
| 	t2, err := http2.ConfigureTransports(t) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	// The following enables the HTTP/2 connection health check added in | ||||
| 	// https://github.com/golang/net/pull/55. The health check detects and | ||||
| 	// closes broken transport layer connections. Without the health check, | ||||
| 	// a broken connection can linger too long, e.g., a broken TCP | ||||
| 	// connection will be closed by the Linux kernel after 13 to 30 minutes | ||||
| 	// by default, which caused | ||||
| 	// https://github.com/kubernetes/client-go/issues/374 and | ||||
| 	// https://github.com/kubernetes/kubernetes/issues/87615. | ||||
| 	t2.ReadIdleTimeout = time.Duration(readIdleTimeoutSeconds()) * time.Second | ||||
| 	t2.PingTimeout = time.Duration(pingTimeoutSeconds()) * time.Second | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func allowsHTTP2(t *http.Transport) bool { | ||||
| 	if t.TLSClientConfig == nil || len(t.TLSClientConfig.NextProtos) == 0 { | ||||
| 		// the transport expressed no NextProto preference, allow | ||||
| 		return true | ||||
| 	} | ||||
| 	for _, p := range t.TLSClientConfig.NextProtos { | ||||
| 		if p == http2.NextProtoTLS { | ||||
| 			// the transport explicitly allowed http/2 | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	// the transport explicitly set NextProtos and excluded http/2 | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| type RoundTripperWrapper interface { | ||||
| 	http.RoundTripper | ||||
| 	WrappedRoundTripper() http.RoundTripper | ||||
| @@ -188,13 +272,17 @@ func GetHTTPClient(req *http.Request) string { | ||||
| 	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. | ||||
| // SourceIPs splits the comma separated X-Forwarded-For header and joins it with | ||||
| // the X-Real-Ip header and/or req.RemoteAddr, ignoring invalid IPs. | ||||
| // The X-Real-Ip is omitted if it's already present in the X-Forwarded-For chain. | ||||
| // The req.RemoteAddr is always the last IP in the returned list. | ||||
| // It returns nil if all of these are empty or invalid. | ||||
| func SourceIPs(req *http.Request) []net.IP { | ||||
| 	var srcIPs []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. | ||||
| @@ -202,38 +290,49 @@ func SourceIPs(req *http.Request) []net.IP { | ||||
| 		for _, part := range parts { | ||||
| 			ip := net.ParseIP(strings.TrimSpace(part)) | ||||
| 			if ip != nil { | ||||
| 				forwardedForIPs = append(forwardedForIPs, ip) | ||||
| 				srcIPs = append(srcIPs, 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} | ||||
| 		// Only append the X-Real-Ip if it's not already contained in the X-Forwarded-For chain. | ||||
| 		if ip != nil && !containsIP(srcIPs, ip) { | ||||
| 			srcIPs = append(srcIPs, ip) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Fallback to Remote Address in request, which will give the correct client IP when there is no proxy. | ||||
| 	// Always include the request Remote Address as it cannot be easily spoofed. | ||||
| 	var remoteIP net.IP | ||||
| 	// 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} | ||||
| 		remoteIP = net.ParseIP(host) | ||||
| 	} | ||||
| 	// Fallback if Remote Address was just IP. | ||||
| 	if remoteIP == nil { | ||||
| 		remoteIP = net.ParseIP(req.RemoteAddr) | ||||
| 	} | ||||
|  | ||||
| 	// Don't duplicate remote IP if it's already the last address in the chain. | ||||
| 	if remoteIP != nil && (len(srcIPs) == 0 || !remoteIP.Equal(srcIPs[len(srcIPs)-1])) { | ||||
| 		srcIPs = append(srcIPs, remoteIP) | ||||
| 	} | ||||
|  | ||||
| 	return srcIPs | ||||
| } | ||||
|  | ||||
| // Checks whether the given IP address is contained in the list of IPs. | ||||
| func containsIP(ips []net.IP, ip net.IP) bool { | ||||
| 	for _, v := range ips { | ||||
| 		if v.Equal(ip) { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	// Fallback if Remote Address was just IP. | ||||
| 	if remoteIP := net.ParseIP(req.RemoteAddr); remoteIP != nil { | ||||
| 		return []net.IP{remoteIP} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Extracts and returns the clients IP from the given request. | ||||
| @@ -407,7 +506,7 @@ redirectLoop: | ||||
|  | ||||
| 		// Only follow redirects to the same host. Otherwise, propagate the redirect response back. | ||||
| 		if requireSameHostRedirects && location.Hostname() != originalLocation.Hostname() { | ||||
| 			break redirectLoop | ||||
| 			return nil, nil, fmt.Errorf("hostname mismatch: expected %s, found %s", originalLocation.Hostname(), location.Hostname()) | ||||
| 		} | ||||
|  | ||||
| 		// Reset the connection. | ||||
| @@ -443,3 +542,232 @@ func CloneHeader(in http.Header) http.Header { | ||||
| 	} | ||||
| 	return out | ||||
| } | ||||
|  | ||||
| // WarningHeader contains a single RFC2616 14.46 warnings header | ||||
| type WarningHeader struct { | ||||
| 	// Codeindicates the type of warning. 299 is a miscellaneous persistent warning | ||||
| 	Code int | ||||
| 	// Agent contains the name or pseudonym of the server adding the Warning header. | ||||
| 	// A single "-" is recommended when agent is unknown. | ||||
| 	Agent string | ||||
| 	// Warning text | ||||
| 	Text string | ||||
| } | ||||
|  | ||||
| // ParseWarningHeaders extract RFC2616 14.46 warnings headers from the specified set of header values. | ||||
| // Multiple comma-separated warnings per header are supported. | ||||
| // If errors are encountered on a header, the remainder of that header are skipped and subsequent headers are parsed. | ||||
| // Returns successfully parsed warnings and any errors encountered. | ||||
| func ParseWarningHeaders(headers []string) ([]WarningHeader, []error) { | ||||
| 	var ( | ||||
| 		results []WarningHeader | ||||
| 		errs    []error | ||||
| 	) | ||||
| 	for _, header := range headers { | ||||
| 		for len(header) > 0 { | ||||
| 			result, remainder, err := ParseWarningHeader(header) | ||||
| 			if err != nil { | ||||
| 				errs = append(errs, err) | ||||
| 				break | ||||
| 			} | ||||
| 			results = append(results, result) | ||||
| 			header = remainder | ||||
| 		} | ||||
| 	} | ||||
| 	return results, errs | ||||
| } | ||||
|  | ||||
| var ( | ||||
| 	codeMatcher = regexp.MustCompile(`^[0-9]{3}$`) | ||||
| 	wordDecoder = &mime.WordDecoder{} | ||||
| ) | ||||
|  | ||||
| // ParseWarningHeader extracts one RFC2616 14.46 warning from the specified header, | ||||
| // returning an error if the header does not contain a correctly formatted warning. | ||||
| // Any remaining content in the header is returned. | ||||
| func ParseWarningHeader(header string) (result WarningHeader, remainder string, err error) { | ||||
| 	// https://tools.ietf.org/html/rfc2616#section-14.46 | ||||
| 	//   updated by | ||||
| 	// https://tools.ietf.org/html/rfc7234#section-5.5 | ||||
| 	//   https://tools.ietf.org/html/rfc7234#appendix-A | ||||
| 	//     Some requirements regarding production and processing of the Warning | ||||
| 	//     header fields have been relaxed, as it is not widely implemented. | ||||
| 	//     Furthermore, the Warning header field no longer uses RFC 2047 | ||||
| 	//     encoding, nor does it allow multiple languages, as these aspects were | ||||
| 	//     not implemented. | ||||
| 	// | ||||
| 	// Format is one of: | ||||
| 	// warn-code warn-agent "warn-text" | ||||
| 	// warn-code warn-agent "warn-text" "warn-date" | ||||
| 	// | ||||
| 	// warn-code is a three digit number | ||||
| 	// warn-agent is unquoted and contains no spaces | ||||
| 	// warn-text is quoted with backslash escaping (RFC2047-encoded according to RFC2616, not encoded according to RFC7234) | ||||
| 	// warn-date is optional, quoted, and in HTTP-date format (no embedded or escaped quotes) | ||||
| 	// | ||||
| 	// additional warnings can optionally be included in the same header by comma-separating them: | ||||
| 	// warn-code warn-agent "warn-text" "warn-date"[, warn-code warn-agent "warn-text" "warn-date", ...] | ||||
|  | ||||
| 	// tolerate leading whitespace | ||||
| 	header = strings.TrimSpace(header) | ||||
|  | ||||
| 	parts := strings.SplitN(header, " ", 3) | ||||
| 	if len(parts) != 3 { | ||||
| 		return WarningHeader{}, "", errors.New("invalid warning header: fewer than 3 segments") | ||||
| 	} | ||||
| 	code, agent, textDateRemainder := parts[0], parts[1], parts[2] | ||||
|  | ||||
| 	// verify code format | ||||
| 	if !codeMatcher.Match([]byte(code)) { | ||||
| 		return WarningHeader{}, "", errors.New("invalid warning header: code segment is not 3 digits between 100-299") | ||||
| 	} | ||||
| 	codeInt, _ := strconv.ParseInt(code, 10, 64) | ||||
|  | ||||
| 	// verify agent presence | ||||
| 	if len(agent) == 0 { | ||||
| 		return WarningHeader{}, "", errors.New("invalid warning header: empty agent segment") | ||||
| 	} | ||||
| 	if !utf8.ValidString(agent) || hasAnyRunes(agent, unicode.IsControl) { | ||||
| 		return WarningHeader{}, "", errors.New("invalid warning header: invalid agent") | ||||
| 	} | ||||
|  | ||||
| 	// verify textDateRemainder presence | ||||
| 	if len(textDateRemainder) == 0 { | ||||
| 		return WarningHeader{}, "", errors.New("invalid warning header: empty text segment") | ||||
| 	} | ||||
|  | ||||
| 	// extract text | ||||
| 	text, dateAndRemainder, err := parseQuotedString(textDateRemainder) | ||||
| 	if err != nil { | ||||
| 		return WarningHeader{}, "", fmt.Errorf("invalid warning header: %v", err) | ||||
| 	} | ||||
| 	// tolerate RFC2047-encoded text from warnings produced according to RFC2616 | ||||
| 	if decodedText, err := wordDecoder.DecodeHeader(text); err == nil { | ||||
| 		text = decodedText | ||||
| 	} | ||||
| 	if !utf8.ValidString(text) || hasAnyRunes(text, unicode.IsControl) { | ||||
| 		return WarningHeader{}, "", errors.New("invalid warning header: invalid text") | ||||
| 	} | ||||
| 	result = WarningHeader{Code: int(codeInt), Agent: agent, Text: text} | ||||
|  | ||||
| 	if len(dateAndRemainder) > 0 { | ||||
| 		if dateAndRemainder[0] == '"' { | ||||
| 			// consume date | ||||
| 			foundEndQuote := false | ||||
| 			for i := 1; i < len(dateAndRemainder); i++ { | ||||
| 				if dateAndRemainder[i] == '"' { | ||||
| 					foundEndQuote = true | ||||
| 					remainder = strings.TrimSpace(dateAndRemainder[i+1:]) | ||||
| 					break | ||||
| 				} | ||||
| 			} | ||||
| 			if !foundEndQuote { | ||||
| 				return WarningHeader{}, "", errors.New("invalid warning header: unterminated date segment") | ||||
| 			} | ||||
| 		} else { | ||||
| 			remainder = dateAndRemainder | ||||
| 		} | ||||
| 	} | ||||
| 	if len(remainder) > 0 { | ||||
| 		if remainder[0] == ',' { | ||||
| 			// consume comma if present | ||||
| 			remainder = strings.TrimSpace(remainder[1:]) | ||||
| 		} else { | ||||
| 			return WarningHeader{}, "", errors.New("invalid warning header: unexpected token after warn-date") | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return result, remainder, nil | ||||
| } | ||||
|  | ||||
| func parseQuotedString(quotedString string) (string, string, error) { | ||||
| 	if len(quotedString) == 0 { | ||||
| 		return "", "", errors.New("invalid quoted string: 0-length") | ||||
| 	} | ||||
|  | ||||
| 	if quotedString[0] != '"' { | ||||
| 		return "", "", errors.New("invalid quoted string: missing initial quote") | ||||
| 	} | ||||
|  | ||||
| 	quotedString = quotedString[1:] | ||||
| 	var remainder string | ||||
| 	escaping := false | ||||
| 	closedQuote := false | ||||
| 	result := &strings.Builder{} | ||||
| loop: | ||||
| 	for i := 0; i < len(quotedString); i++ { | ||||
| 		b := quotedString[i] | ||||
| 		switch b { | ||||
| 		case '"': | ||||
| 			if escaping { | ||||
| 				result.WriteByte(b) | ||||
| 				escaping = false | ||||
| 			} else { | ||||
| 				closedQuote = true | ||||
| 				remainder = strings.TrimSpace(quotedString[i+1:]) | ||||
| 				break loop | ||||
| 			} | ||||
| 		case '\\': | ||||
| 			if escaping { | ||||
| 				result.WriteByte(b) | ||||
| 				escaping = false | ||||
| 			} else { | ||||
| 				escaping = true | ||||
| 			} | ||||
| 		default: | ||||
| 			result.WriteByte(b) | ||||
| 			escaping = false | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	if !closedQuote { | ||||
| 		return "", "", errors.New("invalid quoted string: missing closing quote") | ||||
| 	} | ||||
| 	return result.String(), remainder, nil | ||||
| } | ||||
|  | ||||
| func NewWarningHeader(code int, agent, text string) (string, error) { | ||||
| 	if code < 0 || code > 999 { | ||||
| 		return "", errors.New("code must be between 0 and 999") | ||||
| 	} | ||||
| 	if len(agent) == 0 { | ||||
| 		agent = "-" | ||||
| 	} else if !utf8.ValidString(agent) || strings.ContainsAny(agent, `\"`) || hasAnyRunes(agent, unicode.IsSpace, unicode.IsControl) { | ||||
| 		return "", errors.New("agent must be valid UTF-8 and must not contain spaces, quotes, backslashes, or control characters") | ||||
| 	} | ||||
| 	if !utf8.ValidString(text) || hasAnyRunes(text, unicode.IsControl) { | ||||
| 		return "", errors.New("text must be valid UTF-8 and must not contain control characters") | ||||
| 	} | ||||
| 	return fmt.Sprintf("%03d %s %s", code, agent, makeQuotedString(text)), nil | ||||
| } | ||||
|  | ||||
| func hasAnyRunes(s string, runeCheckers ...func(rune) bool) bool { | ||||
| 	for _, r := range s { | ||||
| 		for _, checker := range runeCheckers { | ||||
| 			if checker(r) { | ||||
| 				return true | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| func makeQuotedString(s string) string { | ||||
| 	result := &bytes.Buffer{} | ||||
| 	// opening quote | ||||
| 	result.WriteRune('"') | ||||
| 	for _, c := range s { | ||||
| 		switch c { | ||||
| 		case '"', '\\': | ||||
| 			// escape " and \ | ||||
| 			result.WriteRune('\\') | ||||
| 			result.WriteRune(c) | ||||
| 		default: | ||||
| 			// write everything else as-is | ||||
| 			result.WriteRune(c) | ||||
| 		} | ||||
| 	} | ||||
| 	// closing quote | ||||
| 	result.WriteRune('"') | ||||
| 	return result.String() | ||||
| } | ||||
|   | ||||
							
								
								
									
										117
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/interface.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										117
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/interface.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -26,7 +26,7 @@ import ( | ||||
|  | ||||
| 	"strings" | ||||
|  | ||||
| 	"k8s.io/klog" | ||||
| 	"k8s.io/klog/v2" | ||||
| ) | ||||
|  | ||||
| type AddressFamily uint | ||||
| @@ -36,6 +36,18 @@ const ( | ||||
| 	familyIPv6 AddressFamily = 6 | ||||
| ) | ||||
|  | ||||
| type AddressFamilyPreference []AddressFamily | ||||
|  | ||||
| var ( | ||||
| 	preferIPv4 = AddressFamilyPreference{familyIPv4, familyIPv6} | ||||
| 	preferIPv6 = AddressFamilyPreference{familyIPv6, familyIPv4} | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	// LoopbackInterfaceName is the default name of the loopback interface | ||||
| 	LoopbackInterfaceName = "lo" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	ipv4RouteFile = "/proc/net/route" | ||||
| 	ipv6RouteFile = "/proc/net/ipv6_route" | ||||
| @@ -53,7 +65,7 @@ type RouteFile struct { | ||||
| 	parse func(input io.Reader) ([]Route, error) | ||||
| } | ||||
|  | ||||
| // noRoutesError can be returned by ChooseBindAddress() in case of no routes | ||||
| // noRoutesError can be returned in case of no routes | ||||
| type noRoutesError struct { | ||||
| 	message string | ||||
| } | ||||
| @@ -254,7 +266,37 @@ func getIPFromInterface(intfName string, forFamily AddressFamily, nw networkInte | ||||
| 	return nil, nil | ||||
| } | ||||
|  | ||||
| // memberOF tells if the IP is of the desired family. Used for checking interface addresses. | ||||
| // getIPFromLoopbackInterface gets the IPs on a loopback interface and returns a global unicast address, if any. | ||||
| // The loopback interface must be up, the IP must in the family requested, and the IP must be a global unicast address. | ||||
| func getIPFromLoopbackInterface(forFamily AddressFamily, nw networkInterfacer) (net.IP, error) { | ||||
| 	intfs, err := nw.Interfaces() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	for _, intf := range intfs { | ||||
| 		if !isInterfaceUp(&intf) { | ||||
| 			continue | ||||
| 		} | ||||
| 		if intf.Flags&(net.FlagLoopback) != 0 { | ||||
| 			addrs, err := nw.Addrs(&intf) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			klog.V(4).Infof("Interface %q has %d addresses :%v.", intf.Name, 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, intf.Name) | ||||
| 				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 | ||||
| @@ -265,8 +307,8 @@ func memberOf(ip net.IP, family AddressFamily) bool { | ||||
|  | ||||
| // 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) { | ||||
| // addressFamilies determines whether it prefers IPv4 or IPv6 | ||||
| func chooseIPFromHostInterfaces(nw networkInterfacer, addressFamilies AddressFamilyPreference) (net.IP, error) { | ||||
| 	intfs, err := nw.Interfaces() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @@ -274,7 +316,7 @@ func chooseIPFromHostInterfaces(nw networkInterfacer) (net.IP, error) { | ||||
| 	if len(intfs) == 0 { | ||||
| 		return nil, fmt.Errorf("no interfaces found on host.") | ||||
| 	} | ||||
| 	for _, family := range []AddressFamily{familyIPv4, familyIPv6} { | ||||
| 	for _, family := range addressFamilies { | ||||
| 		klog.V(4).Infof("Looking for system interface with a global IPv%d address", uint(family)) | ||||
| 		for _, intf := range intfs { | ||||
| 			if !isInterfaceUp(&intf) { | ||||
| @@ -321,15 +363,19 @@ func chooseIPFromHostInterfaces(nw networkInterfacer) (net.IP, error) { | ||||
| // 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) { | ||||
| 	return chooseHostInterface(preferIPv4) | ||||
| } | ||||
|  | ||||
| func chooseHostInterface(addressFamilies AddressFamilyPreference) (net.IP, error) { | ||||
| 	var nw networkInterfacer = networkInterface{} | ||||
| 	if _, err := os.Stat(ipv4RouteFile); os.IsNotExist(err) { | ||||
| 		return chooseIPFromHostInterfaces(nw) | ||||
| 		return chooseIPFromHostInterfaces(nw, addressFamilies) | ||||
| 	} | ||||
| 	routes, err := getAllDefaultRoutes() | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return chooseHostInterfaceFromRoute(routes, nw) | ||||
| 	return chooseHostInterfaceFromRoute(routes, nw, addressFamilies) | ||||
| } | ||||
|  | ||||
| // networkInterfacer defines an interface for several net library functions. Production | ||||
| @@ -377,10 +423,11 @@ func getAllDefaultRoutes() ([]Route, error) { | ||||
| } | ||||
|  | ||||
| // 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} { | ||||
| // global IP address from the interface for the route. If there are routes but no global | ||||
| // address is obtained from the interfaces, it checks if the loopback interface has a global address. | ||||
| // addressFamilies determines whether it prefers IPv4 or IPv6 | ||||
| func chooseHostInterfaceFromRoute(routes []Route, nw networkInterfacer, addressFamilies AddressFamilyPreference) (net.IP, error) { | ||||
| 	for _, family := range addressFamilies { | ||||
| 		klog.V(4).Infof("Looking for default routes with IPv%d addresses", uint(family)) | ||||
| 		for _, route := range routes { | ||||
| 			if route.Family != family { | ||||
| @@ -395,18 +442,36 @@ func chooseHostInterfaceFromRoute(routes []Route, nw networkInterfacer) (net.IP, | ||||
| 				klog.V(4).Infof("Found active IP %v ", finalIP) | ||||
| 				return finalIP, nil | ||||
| 			} | ||||
| 			// In case of network setups where default routes are present, but network | ||||
| 			// interfaces use only link-local addresses (e.g. as described in RFC5549). | ||||
| 			// the global IP is assigned to the loopback interface, and we should use it | ||||
| 			loopbackIP, err := getIPFromLoopbackInterface(family, nw) | ||||
| 			if err != nil { | ||||
| 				return nil, err | ||||
| 			} | ||||
| 			if loopbackIP != nil { | ||||
| 				klog.V(4).Infof("Found active IP %v on Loopback interface", loopbackIP) | ||||
| 				return loopbackIP, 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) { | ||||
| // ResolveBindAddress returns the IP address of a daemon, based on the given bindAddress: | ||||
| // If bindAddress is unset, it returns the host's default IP, as with ChooseHostInterface(). | ||||
| // If bindAddress is unspecified or loopback, it returns the default IP of the same | ||||
| // address family as bindAddress. | ||||
| // Otherwise, it just returns bindAddress. | ||||
| func ResolveBindAddress(bindAddress net.IP) (net.IP, error) { | ||||
| 	addressFamilies := preferIPv4 | ||||
| 	if bindAddress != nil && memberOf(bindAddress, familyIPv6) { | ||||
| 		addressFamilies = preferIPv6 | ||||
| 	} | ||||
|  | ||||
| 	if bindAddress == nil || bindAddress.IsUnspecified() || bindAddress.IsLoopback() { | ||||
| 		hostIP, err := ChooseHostInterface() | ||||
| 		hostIP, err := chooseHostInterface(addressFamilies) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| @@ -414,3 +479,21 @@ func ChooseBindAddress(bindAddress net.IP) (net.IP, error) { | ||||
| 	} | ||||
| 	return bindAddress, nil | ||||
| } | ||||
|  | ||||
| // ChooseBindAddressForInterface choose a global IP for a specific interface, with priority given to IPv4. | ||||
| // This is required in case of network setups where default routes are present, but network | ||||
| // interfaces use only link-local addresses (e.g. as described in RFC5549). | ||||
| // e.g when using BGP to announce a host IP over link-local ip addresses and this ip address is attached to the lo interface. | ||||
| func ChooseBindAddressForInterface(intfName string) (net.IP, error) { | ||||
| 	var nw networkInterfacer = networkInterface{} | ||||
| 	for _, family := range preferIPv4 { | ||||
| 		ip, err := getIPFromInterface(intfName, family, nw) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		if ip != nil { | ||||
| 			return ip, nil | ||||
| 		} | ||||
| 	} | ||||
| 	return nil, fmt.Errorf("unable to select an IP from %s network interface", intfName) | ||||
| } | ||||
|   | ||||
							
								
								
									
										2
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/port_range.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/port_range.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -130,7 +130,7 @@ func (*PortRange) Type() string { | ||||
| } | ||||
|  | ||||
| // ParsePortRange parses a string of the form "min-max", inclusive at both | ||||
| // ends, and initializs a new PortRange from it. | ||||
| // ends, and initializes a new PortRange from it. | ||||
| func ParsePortRange(value string) (*PortRange, error) { | ||||
| 	pr := &PortRange{} | ||||
| 	err := pr.Set(value) | ||||
|   | ||||
							
								
								
									
										26
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/util.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										26
									
								
								vendor/k8s.io/apimachinery/pkg/util/net/util.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -17,9 +17,8 @@ limitations under the License. | ||||
| package net | ||||
|  | ||||
| import ( | ||||
| 	"errors" | ||||
| 	"net" | ||||
| 	"net/url" | ||||
| 	"os" | ||||
| 	"reflect" | ||||
| 	"syscall" | ||||
| ) | ||||
| @@ -40,17 +39,18 @@ func IPNetEqual(ipnet1, ipnet2 *net.IPNet) bool { | ||||
|  | ||||
| // 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 | ||||
| 	var errno syscall.Errno | ||||
| 	if errors.As(err, &errno) { | ||||
| 		return errno == syscall.ECONNRESET | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // Returns if the given err is "connection refused" error | ||||
| func IsConnectionRefused(err error) bool { | ||||
| 	var errno syscall.Errno | ||||
| 	if errors.As(err, &errno) { | ||||
| 		return errno == syscall.ECONNREFUSED | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user