mirror of
				https://github.com/optim-enterprises-bv/kubernetes.git
				synced 2025-11-03 19:58:17 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			217 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			217 lines
		
	
	
		
			6.5 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
/*
 | 
						|
Copyright 2017 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 util
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"errors"
 | 
						|
	"fmt"
 | 
						|
	"net"
 | 
						|
 | 
						|
	"k8s.io/api/core/v1"
 | 
						|
	"k8s.io/apimachinery/pkg/types"
 | 
						|
	"k8s.io/apimachinery/pkg/util/sets"
 | 
						|
	"k8s.io/client-go/tools/record"
 | 
						|
	helper "k8s.io/kubernetes/pkg/apis/core/v1/helper"
 | 
						|
	utilnet "k8s.io/utils/net"
 | 
						|
 | 
						|
	"k8s.io/klog"
 | 
						|
)
 | 
						|
 | 
						|
const (
 | 
						|
	IPv4ZeroCIDR = "0.0.0.0/0"
 | 
						|
	IPv6ZeroCIDR = "::/0"
 | 
						|
)
 | 
						|
 | 
						|
var (
 | 
						|
	ErrAddressNotAllowed = errors.New("address not allowed")
 | 
						|
	ErrNoAddresses       = errors.New("No addresses for hostname")
 | 
						|
)
 | 
						|
 | 
						|
func IsZeroCIDR(cidr string) bool {
 | 
						|
	if cidr == IPv4ZeroCIDR || cidr == IPv6ZeroCIDR {
 | 
						|
		return true
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// IsProxyableIP checks if a given IP address is permitted to be proxied
 | 
						|
func IsProxyableIP(ip string) error {
 | 
						|
	netIP := net.ParseIP(ip)
 | 
						|
	if netIP == nil {
 | 
						|
		return ErrAddressNotAllowed
 | 
						|
	}
 | 
						|
	return isProxyableIP(netIP)
 | 
						|
}
 | 
						|
 | 
						|
func isProxyableIP(ip net.IP) error {
 | 
						|
	if ip.IsLoopback() || ip.IsLinkLocalUnicast() || ip.IsLinkLocalMulticast() || ip.IsInterfaceLocalMulticast() {
 | 
						|
		return ErrAddressNotAllowed
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
// Resolver is an interface for net.Resolver
 | 
						|
type Resolver interface {
 | 
						|
	LookupIPAddr(ctx context.Context, host string) ([]net.IPAddr, error)
 | 
						|
}
 | 
						|
 | 
						|
// IsProxyableHostname checks if the IP addresses for a given hostname are permitted to be proxied
 | 
						|
func IsProxyableHostname(ctx context.Context, resolv Resolver, hostname string) error {
 | 
						|
	resp, err := resolv.LookupIPAddr(ctx, hostname)
 | 
						|
	if err != nil {
 | 
						|
		return err
 | 
						|
	}
 | 
						|
 | 
						|
	if len(resp) == 0 {
 | 
						|
		return ErrNoAddresses
 | 
						|
	}
 | 
						|
 | 
						|
	for _, host := range resp {
 | 
						|
		if err := isProxyableIP(host.IP); err != nil {
 | 
						|
			return err
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return nil
 | 
						|
}
 | 
						|
 | 
						|
func IsLocalIP(ip string) (bool, error) {
 | 
						|
	addrs, err := net.InterfaceAddrs()
 | 
						|
	if err != nil {
 | 
						|
		return false, err
 | 
						|
	}
 | 
						|
	for i := range addrs {
 | 
						|
		intf, _, err := net.ParseCIDR(addrs[i].String())
 | 
						|
		if err != nil {
 | 
						|
			return false, err
 | 
						|
		}
 | 
						|
		if net.ParseIP(ip).Equal(intf) {
 | 
						|
			return true, nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return false, nil
 | 
						|
}
 | 
						|
 | 
						|
func ShouldSkipService(svcName types.NamespacedName, service *v1.Service) bool {
 | 
						|
	// if ClusterIP is "None" or empty, skip proxying
 | 
						|
	if !helper.IsServiceIPSet(service) {
 | 
						|
		klog.V(3).Infof("Skipping service %s due to clusterIP = %q", svcName, service.Spec.ClusterIP)
 | 
						|
		return true
 | 
						|
	}
 | 
						|
	// Even if ClusterIP is set, ServiceTypeExternalName services don't get proxied
 | 
						|
	if service.Spec.Type == v1.ServiceTypeExternalName {
 | 
						|
		klog.V(3).Infof("Skipping service %s due to Type=ExternalName", svcName)
 | 
						|
		return true
 | 
						|
	}
 | 
						|
	return false
 | 
						|
}
 | 
						|
 | 
						|
// GetNodeAddresses return all matched node IP addresses based on given cidr slice.
 | 
						|
// Some callers, e.g. IPVS proxier, need concrete IPs, not ranges, which is why this exists.
 | 
						|
// NetworkInterfacer is injected for test purpose.
 | 
						|
// We expect the cidrs passed in is already validated.
 | 
						|
// Given an empty input `[]`, it will return `0.0.0.0/0` and `::/0` directly.
 | 
						|
// If multiple cidrs is given, it will return the minimal IP sets, e.g. given input `[1.2.0.0/16, 0.0.0.0/0]`, it will
 | 
						|
// only return `0.0.0.0/0`.
 | 
						|
// NOTE: GetNodeAddresses only accepts CIDRs, if you want concrete IPs, e.g. 1.2.3.4, then the input should be 1.2.3.4/32.
 | 
						|
func GetNodeAddresses(cidrs []string, nw NetworkInterfacer) (sets.String, error) {
 | 
						|
	uniqueAddressList := sets.NewString()
 | 
						|
	if len(cidrs) == 0 {
 | 
						|
		uniqueAddressList.Insert(IPv4ZeroCIDR)
 | 
						|
		uniqueAddressList.Insert(IPv6ZeroCIDR)
 | 
						|
		return uniqueAddressList, nil
 | 
						|
	}
 | 
						|
	// First round of iteration to pick out `0.0.0.0/0` or `::/0` for the sake of excluding non-zero IPs.
 | 
						|
	for _, cidr := range cidrs {
 | 
						|
		if IsZeroCIDR(cidr) {
 | 
						|
			uniqueAddressList.Insert(cidr)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	// Second round of iteration to parse IPs based on cidr.
 | 
						|
	for _, cidr := range cidrs {
 | 
						|
		if IsZeroCIDR(cidr) {
 | 
						|
			continue
 | 
						|
		}
 | 
						|
		_, ipNet, _ := net.ParseCIDR(cidr)
 | 
						|
		itfs, err := nw.Interfaces()
 | 
						|
		if err != nil {
 | 
						|
			return nil, fmt.Errorf("error listing all interfaces from host, error: %v", err)
 | 
						|
		}
 | 
						|
		for _, itf := range itfs {
 | 
						|
			addrs, err := nw.Addrs(&itf)
 | 
						|
			if err != nil {
 | 
						|
				return nil, fmt.Errorf("error getting address from interface %s, error: %v", itf.Name, err)
 | 
						|
			}
 | 
						|
			for _, addr := range addrs {
 | 
						|
				if addr == nil {
 | 
						|
					continue
 | 
						|
				}
 | 
						|
				ip, _, err := net.ParseCIDR(addr.String())
 | 
						|
				if err != nil {
 | 
						|
					return nil, fmt.Errorf("error parsing CIDR for interface %s, error: %v", itf.Name, err)
 | 
						|
				}
 | 
						|
				if ipNet.Contains(ip) {
 | 
						|
					if utilnet.IsIPv6(ip) && !uniqueAddressList.Has(IPv6ZeroCIDR) {
 | 
						|
						uniqueAddressList.Insert(ip.String())
 | 
						|
					}
 | 
						|
					if !utilnet.IsIPv6(ip) && !uniqueAddressList.Has(IPv4ZeroCIDR) {
 | 
						|
						uniqueAddressList.Insert(ip.String())
 | 
						|
					}
 | 
						|
				}
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return uniqueAddressList, nil
 | 
						|
}
 | 
						|
 | 
						|
// LogAndEmitIncorrectIPVersionEvent logs and emits incorrect IP version event.
 | 
						|
func LogAndEmitIncorrectIPVersionEvent(recorder record.EventRecorder, fieldName, fieldValue, svcNamespace, svcName string, svcUID types.UID) {
 | 
						|
	errMsg := fmt.Sprintf("%s in %s has incorrect IP version", fieldValue, fieldName)
 | 
						|
	klog.Errorf("%s (service %s/%s).", errMsg, svcNamespace, svcName)
 | 
						|
	if recorder != nil {
 | 
						|
		recorder.Eventf(
 | 
						|
			&v1.ObjectReference{
 | 
						|
				Kind:      "Service",
 | 
						|
				Name:      svcName,
 | 
						|
				Namespace: svcNamespace,
 | 
						|
				UID:       svcUID,
 | 
						|
			}, v1.EventTypeWarning, "KubeProxyIncorrectIPVersion", errMsg)
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// FilterIncorrectIPVersion filters out the incorrect IP version case from a slice of IP strings.
 | 
						|
func FilterIncorrectIPVersion(ipStrings []string, isIPv6Mode bool) ([]string, []string) {
 | 
						|
	return filterWithCondition(ipStrings, isIPv6Mode, utilnet.IsIPv6String)
 | 
						|
}
 | 
						|
 | 
						|
// FilterIncorrectCIDRVersion filters out the incorrect IP version case from a slice of CIDR strings.
 | 
						|
func FilterIncorrectCIDRVersion(ipStrings []string, isIPv6Mode bool) ([]string, []string) {
 | 
						|
	return filterWithCondition(ipStrings, isIPv6Mode, utilnet.IsIPv6CIDRString)
 | 
						|
}
 | 
						|
 | 
						|
func filterWithCondition(strs []string, expectedCondition bool, conditionFunc func(string) bool) ([]string, []string) {
 | 
						|
	var corrects, incorrects []string
 | 
						|
	for _, str := range strs {
 | 
						|
		if conditionFunc(str) != expectedCondition {
 | 
						|
			incorrects = append(incorrects, str)
 | 
						|
		} else {
 | 
						|
			corrects = append(corrects, str)
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return corrects, incorrects
 | 
						|
}
 |