github.com/cilium/cilium@v1.16.2/pkg/policy/api/cidr.go (about)

     1  // SPDX-License-Identifier: Apache-2.0
     2  // Copyright Authors of Cilium
     3  
     4  package api
     5  
     6  import (
     7  	"net"
     8  	"net/netip"
     9  	"strings"
    10  
    11  	"github.com/cilium/cilium/pkg/ip"
    12  	"github.com/cilium/cilium/pkg/labels"
    13  	"github.com/cilium/cilium/pkg/option"
    14  )
    15  
    16  // CIDR specifies a block of IP addresses.
    17  // Example: 192.0.2.1/32
    18  //
    19  // +kubebuilder:validation:Format=cidr
    20  type CIDR string
    21  
    22  var (
    23  	ipv4All = CIDR("0.0.0.0/0")
    24  	ipv6All = CIDR("::/0")
    25  )
    26  
    27  // CIDRRule is a rule that specifies a CIDR prefix to/from which outside
    28  // communication  is allowed, along with an optional list of subnets within that
    29  // CIDR prefix to/from which outside communication is not allowed.
    30  type CIDRRule struct {
    31  	// CIDR is a CIDR prefix / IP Block.
    32  	//
    33  	// +kubebuilder:validation:OneOf
    34  	Cidr CIDR `json:"cidr,omitempty"`
    35  
    36  	// CIDRGroupRef is a reference to a CiliumCIDRGroup object.
    37  	// A CiliumCIDRGroup contains a list of CIDRs that the endpoint, subject to
    38  	// the rule, can (Ingress/Egress) or cannot (IngressDeny/EgressDeny) receive
    39  	// connections from.
    40  	//
    41  	// +kubebuilder:validation:OneOf
    42  	CIDRGroupRef CIDRGroupRef `json:"cidrGroupRef,omitempty"`
    43  
    44  	// ExceptCIDRs is a list of IP blocks which the endpoint subject to the rule
    45  	// is not allowed to initiate connections to. These CIDR prefixes should be
    46  	// contained within Cidr, using ExceptCIDRs together with CIDRGroupRef is not
    47  	// supported yet.
    48  	// These exceptions are only applied to the Cidr in this CIDRRule, and do not
    49  	// apply to any other CIDR prefixes in any other CIDRRules.
    50  	//
    51  	// +kubebuilder:validation:Optional
    52  	ExceptCIDRs []CIDR `json:"except,omitempty"`
    53  
    54  	// Generated indicates whether the rule was generated based on other rules
    55  	// or provided by user
    56  	Generated bool `json:"-"`
    57  }
    58  
    59  // String converts the CIDRRule into a human-readable string.
    60  func (r CIDRRule) String() string {
    61  	exceptCIDRs := ""
    62  	if len(r.ExceptCIDRs) > 0 {
    63  		exceptCIDRs = "-" + CIDRSlice(r.ExceptCIDRs).String()
    64  	}
    65  	return string(r.Cidr) + exceptCIDRs
    66  }
    67  
    68  // CIDRSlice is a slice of CIDRs. It allows receiver methods to be defined for
    69  // transforming the slice into other convenient forms such as
    70  // EndpointSelectorSlice.
    71  type CIDRSlice []CIDR
    72  
    73  // GetAsEndpointSelectors returns the provided CIDR slice as a slice of
    74  // endpoint selectors
    75  func (s CIDRSlice) GetAsEndpointSelectors() EndpointSelectorSlice {
    76  	// If multiple CIDRs representing reserved:world are in this CIDRSlice,
    77  	// we only have to add the EndpointSelector representing reserved:world
    78  	// once.
    79  	var hasIPv4AllBeenAdded, hasIPv6AllBeenAdded bool
    80  	slice := EndpointSelectorSlice{}
    81  	for _, cidr := range s {
    82  		if cidr == ipv4All {
    83  			hasIPv4AllBeenAdded = true
    84  		}
    85  		if cidr == ipv6All {
    86  			hasIPv6AllBeenAdded = true
    87  		}
    88  		lbl, err := labels.IPStringToLabel(string(cidr))
    89  		if err == nil {
    90  			slice = append(slice, NewESFromLabels(lbl))
    91  		}
    92  		// TODO: Log the error?
    93  	}
    94  
    95  	if option.Config.IsDualStack() {
    96  		// If Cilium is in dual-stack mode then world-ipv4 and
    97  		// world-ipv6 need to be distinguished from one another.
    98  		if hasIPv4AllBeenAdded && hasIPv6AllBeenAdded {
    99  			slice = append(slice, ReservedEndpointSelectors[labels.IDNameWorld])
   100  		}
   101  		if hasIPv4AllBeenAdded {
   102  			slice = append(slice, ReservedEndpointSelectors[labels.IDNameWorldIPv4])
   103  		}
   104  		if hasIPv6AllBeenAdded {
   105  			slice = append(slice, ReservedEndpointSelectors[labels.IDNameWorldIPv6])
   106  		}
   107  	} else if option.Config.EnableIPv4 && hasIPv4AllBeenAdded {
   108  		slice = append(slice, ReservedEndpointSelectors[labels.IDNameWorld])
   109  	} else if option.Config.EnableIPv6 && hasIPv6AllBeenAdded {
   110  		slice = append(slice, ReservedEndpointSelectors[labels.IDNameWorld])
   111  	}
   112  	return slice
   113  }
   114  
   115  // StringSlice returns the CIDR slice as a slice of strings.
   116  func (s CIDRSlice) StringSlice() []string {
   117  	result := make([]string, 0, len(s))
   118  	for _, c := range s {
   119  		result = append(result, string(c))
   120  	}
   121  	return result
   122  }
   123  
   124  // String converts the CIDRSlice into a human-readable string.
   125  func (s CIDRSlice) String() string {
   126  	if len(s) == 0 {
   127  		return ""
   128  	}
   129  	return "[" + strings.Join(s.StringSlice(), ",") + "]"
   130  }
   131  
   132  // CIDRRuleSlice is a slice of CIDRRules. It allows receiver methods to be
   133  // defined for transforming the slice into other convenient forms such as
   134  // EndpointSelectorSlice.
   135  type CIDRRuleSlice []CIDRRule
   136  
   137  // GetAsEndpointSelectors returns the provided CIDRRule slice as a slice of
   138  // endpoint selectors
   139  func (s CIDRRuleSlice) GetAsEndpointSelectors() EndpointSelectorSlice {
   140  	cidrs := ComputeResultantCIDRSet(s)
   141  	return cidrs.GetAsEndpointSelectors()
   142  }
   143  
   144  // StringSlice returns the CIDRRuleSlice as a slice of strings.
   145  func (s CIDRRuleSlice) StringSlice() []string {
   146  	result := make([]string, 0, len(s))
   147  	for _, c := range s {
   148  		result = append(result, c.String())
   149  	}
   150  	return result
   151  }
   152  
   153  // ComputeResultantCIDRSet converts a slice of CIDRRules into a slice of
   154  // individual CIDRs. This expands the cidr defined by each CIDRRule, applies
   155  // the CIDR exceptions defined in "ExceptCIDRs", and forms a minimal set of
   156  // CIDRs that cover all of the CIDRRules.
   157  //
   158  // Assumes no error checking is necessary as CIDRRule.Sanitize already does this.
   159  func ComputeResultantCIDRSet(cidrs CIDRRuleSlice) CIDRSlice {
   160  	var allResultantAllowedCIDRs CIDRSlice
   161  	for _, s := range cidrs {
   162  		_, allowNet, _ := net.ParseCIDR(string(s.Cidr))
   163  
   164  		var removeSubnets []*net.IPNet
   165  		for _, t := range s.ExceptCIDRs {
   166  			_, removeSubnet, _ := net.ParseCIDR(string(t))
   167  			removeSubnets = append(removeSubnets, removeSubnet)
   168  		}
   169  		resultantAllowedCIDRs := ip.RemoveCIDRs([]*net.IPNet{allowNet}, removeSubnets)
   170  
   171  		for _, u := range resultantAllowedCIDRs {
   172  			allResultantAllowedCIDRs = append(allResultantAllowedCIDRs, CIDR(u.String()))
   173  		}
   174  	}
   175  	return allResultantAllowedCIDRs
   176  }
   177  
   178  // addrsToCIDRRules generates CIDRRules for the IPs passed in.
   179  // This function will mark the rule to Generated true by default.
   180  func addrsToCIDRRules(addrs []netip.Addr) []CIDRRule {
   181  	cidrRules := make([]CIDRRule, 0, len(addrs))
   182  	for _, addr := range addrs {
   183  		rule := CIDRRule{ExceptCIDRs: make([]CIDR, 0)}
   184  		rule.Generated = true
   185  		if addr.Is4() {
   186  			rule.Cidr = CIDR(addr.String() + "/32")
   187  		} else {
   188  			rule.Cidr = CIDR(addr.String() + "/128")
   189  		}
   190  		cidrRules = append(cidrRules, rule)
   191  	}
   192  	return cidrRules
   193  }
   194  
   195  // +kubebuilder:validation:MaxLength=253
   196  // +kubebuilder:validation:Pattern=`^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$`
   197  //
   198  // CIDRGroupRef is a reference to a CIDR Group.
   199  // A CIDR Group is a list of CIDRs whose IP addresses should be considered as a
   200  // same entity when applying fromCIDRGroupRefs policies on incoming network traffic.
   201  type CIDRGroupRef string