| /* |
| 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 ( |
| "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/kubernetes/pkg/util/net" |
| |
| "k8s.io/klog" |
| ) |
| |
| const ( |
| IPv4ZeroCIDR = "0.0.0.0/0" |
| IPv6ZeroCIDR = "::/0" |
| ) |
| |
| func IsZeroCIDR(cidr string) bool { |
| if cidr == IPv4ZeroCIDR || cidr == IPv6ZeroCIDR { |
| return true |
| } |
| return false |
| } |
| |
| 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) |
| } |
| } |