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