...

Source file src/k8s.io/kubernetes/pkg/proxy/util/nodeport_addresses.go

Documentation: k8s.io/kubernetes/pkg/proxy/util

     1  /*
     2  Copyright 2022 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package util
    18  
    19  import (
    20  	"fmt"
    21  	"net"
    22  
    23  	v1 "k8s.io/api/core/v1"
    24  	netutils "k8s.io/utils/net"
    25  )
    26  
    27  // NodePortAddresses is used to handle the --nodeport-addresses flag
    28  type NodePortAddresses struct {
    29  	cidrStrings []string
    30  
    31  	cidrs                []*net.IPNet
    32  	containsIPv4Loopback bool
    33  	matchAll             bool
    34  }
    35  
    36  // RFC 5735 127.0.0.0/8 - This block is assigned for use as the Internet host loopback address
    37  var ipv4LoopbackStart = net.IPv4(127, 0, 0, 0)
    38  
    39  // NewNodePortAddresses takes an IP family and the `--nodeport-addresses` value (which is
    40  // assumed to contain only valid CIDRs, potentially of both IP families) and the primary IP
    41  // (which will be used as node port address when `--nodeport-addresses` is empty).
    42  // It will return a NodePortAddresses object for the given family. If there are no CIDRs of
    43  // the given family then the CIDR "0.0.0.0/0" or "::/0" will be added (even if there are
    44  // CIDRs of the other family).
    45  func NewNodePortAddresses(family v1.IPFamily, cidrStrings []string, primaryIP net.IP) *NodePortAddresses {
    46  	npa := &NodePortAddresses{}
    47  
    48  	// Filter CIDRs to correct family
    49  	for _, str := range cidrStrings {
    50  		if (family == v1.IPv4Protocol) == netutils.IsIPv4CIDRString(str) {
    51  			npa.cidrStrings = append(npa.cidrStrings, str)
    52  		}
    53  	}
    54  	if len(npa.cidrStrings) == 0 {
    55  		if primaryIP == nil {
    56  			if family == v1.IPv4Protocol {
    57  				npa.cidrStrings = []string{IPv4ZeroCIDR}
    58  			} else {
    59  				npa.cidrStrings = []string{IPv6ZeroCIDR}
    60  			}
    61  		} else {
    62  			if family == v1.IPv4Protocol {
    63  				npa.cidrStrings = []string{fmt.Sprintf("%s/32", primaryIP.String())}
    64  			} else {
    65  				npa.cidrStrings = []string{fmt.Sprintf("%s/128", primaryIP.String())}
    66  			}
    67  		}
    68  	}
    69  
    70  	// Now parse
    71  	for _, str := range npa.cidrStrings {
    72  		_, cidr, _ := netutils.ParseCIDRSloppy(str)
    73  		if netutils.IsIPv4CIDR(cidr) {
    74  			if cidr.IP.IsLoopback() || cidr.Contains(ipv4LoopbackStart) {
    75  				npa.containsIPv4Loopback = true
    76  			}
    77  		}
    78  
    79  		if IsZeroCIDR(str) {
    80  			// Ignore everything else
    81  			npa.cidrs = []*net.IPNet{cidr}
    82  			npa.matchAll = true
    83  			break
    84  		}
    85  
    86  		npa.cidrs = append(npa.cidrs, cidr)
    87  	}
    88  
    89  	return npa
    90  }
    91  
    92  func (npa *NodePortAddresses) String() string {
    93  	return fmt.Sprintf("%v", npa.cidrStrings)
    94  }
    95  
    96  // MatchAll returns true if npa matches all node IPs (of npa's given family)
    97  func (npa *NodePortAddresses) MatchAll() bool {
    98  	return npa.matchAll
    99  }
   100  
   101  // GetNodeIPs return all matched node IP addresses for npa's CIDRs. If no matching
   102  // IPs are found, it returns an empty list.
   103  // NetworkInterfacer is injected for test purpose.
   104  func (npa *NodePortAddresses) GetNodeIPs(nw NetworkInterfacer) ([]net.IP, error) {
   105  	addrs, err := nw.InterfaceAddrs()
   106  	if err != nil {
   107  		return nil, fmt.Errorf("error listing all interfaceAddrs from host, error: %v", err)
   108  	}
   109  
   110  	// Use a map to dedup matches
   111  	addresses := make(map[string]net.IP)
   112  	for _, cidr := range npa.cidrs {
   113  		for _, addr := range addrs {
   114  			var ip net.IP
   115  			// nw.InterfaceAddrs may return net.IPAddr or net.IPNet on windows, and it will return net.IPNet on linux.
   116  			switch v := addr.(type) {
   117  			case *net.IPAddr:
   118  				ip = v.IP
   119  			case *net.IPNet:
   120  				ip = v.IP
   121  			default:
   122  				continue
   123  			}
   124  
   125  			if cidr.Contains(ip) {
   126  				addresses[ip.String()] = ip
   127  			}
   128  		}
   129  	}
   130  
   131  	ips := make([]net.IP, 0, len(addresses))
   132  	for _, ip := range addresses {
   133  		ips = append(ips, ip)
   134  	}
   135  
   136  	return ips, nil
   137  }
   138  
   139  // ContainsIPv4Loopback returns true if npa's CIDRs contain an IPv4 loopback address.
   140  func (npa *NodePortAddresses) ContainsIPv4Loopback() bool {
   141  	return npa.containsIPv4Loopback
   142  }
   143  

View as plain text