github.com/fafucoder/cilium@v1.6.11/bpf/lib/policy.h (about) 1 /* 2 * Copyright (C) 2016-2019 Authors of Cilium 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 #ifndef __LIB_POLICY_H_ 19 #define __LIB_POLICY_H_ 20 21 #include "drop.h" 22 #include "dbg.h" 23 #include "eps.h" 24 #include "maps.h" 25 26 static inline bool __inline__ inherit_identity_from_host(struct __sk_buff *skb, __u32 *identity) 27 { 28 __u32 magic = skb->mark & MARK_MAGIC_HOST_MASK; 29 bool from_proxy = false; 30 31 /* Packets from the ingress proxy must skip the proxy when the 32 * destination endpoint evaluates the policy. As the packet 33 * would loop and/or the connection be reset otherwise. */ 34 if (magic == MARK_MAGIC_PROXY_INGRESS) { 35 *identity = get_identity(skb); 36 skb->tc_index |= TC_INDEX_F_SKIP_INGRESS_PROXY; 37 from_proxy = true; 38 /* (Return) packets from the egress proxy must skip the 39 * redirection to the proxy, as the packet would loop and/or 40 * the connection be reset otherwise. */ 41 } else if (magic == MARK_MAGIC_PROXY_EGRESS) { 42 *identity = get_identity(skb); 43 skb->tc_index |= TC_INDEX_F_SKIP_EGRESS_PROXY; 44 from_proxy = true; 45 } else if (magic == MARK_MAGIC_IDENTITY) { 46 *identity = get_identity(skb); 47 } else if (magic == MARK_MAGIC_HOST) { 48 *identity = HOST_ID; 49 } else { 50 *identity = WORLD_ID; 51 } 52 53 /* Reset packet mark to avoid hitting routing rules again */ 54 skb->mark = 0; 55 cilium_dbg(skb, DBG_INHERIT_IDENTITY, *identity, 0); 56 57 return from_proxy; 58 } 59 60 61 /** 62 * identity_is_reserved is used to determine whether an identity is one of the 63 * reserved identities that are not handed out to endpoints. 64 * 65 * Specifically, it should return true if the identity is one of these: 66 * - IdentityUnknown (0) 67 * - ReservedIdentityHost (1) 68 * - ReservedIdentityWorld (2) 69 * 70 * The following identities are given to endpoints so return false for these: 71 * - ReservedIdentityUnmanaged (3) 72 * - ReservedIdentityHealth (4) 73 * - ReservedIdentityInit (5) 74 * 75 * Identities 128 and higher are guaranteed to be generated based on user input. 76 */ 77 static inline bool identity_is_reserved(__u32 identity) 78 { 79 return identity < UNMANAGED_ID; 80 } 81 82 #ifdef SOCKMAP 83 static inline int __inline__ 84 policy_sk_egress(__u32 identity, __u32 ip, __u16 dport) 85 { 86 void *map = lookup_ip4_endpoint_policy_map(ip); 87 int dir = CT_EGRESS; 88 __u8 proto = IPPROTO_TCP; 89 struct policy_entry *policy; 90 struct policy_key key = { 91 .sec_label = identity, 92 .dport = dport, 93 .protocol = proto, 94 .egress = !dir, 95 .pad = 0, 96 }; 97 98 if (!map) 99 return 0; 100 101 policy = map_lookup_elem(map, &key); 102 if (likely(policy)) { 103 /* FIXME: Need byte counter */ 104 __sync_fetch_and_add(&policy->packets, 1); 105 goto get_proxy_port; 106 } 107 108 /* If L4 policy check misses, fall back to L3. */ 109 key.dport = 0; 110 key.protocol = 0; 111 policy = map_lookup_elem(map, &key); 112 if (likely(policy)) { 113 /* FIXME: Need byte counter */ 114 __sync_fetch_and_add(&policy->packets, 1); 115 return TC_ACT_OK; 116 } 117 118 key.sec_label = 0; 119 key.dport = dport; 120 key.protocol = proto; 121 policy = map_lookup_elem(map, &key); 122 if (likely(policy)) { 123 /* FIXME: Use per cpu counters */ 124 __sync_fetch_and_add(&policy->packets, 1); 125 goto get_proxy_port; 126 } 127 return DROP_POLICY; 128 get_proxy_port: 129 if (likely(policy)) { 130 return policy->proxy_port; 131 } 132 return TC_ACT_OK; 133 } 134 #else 135 136 static inline void __inline__ 137 account(struct __sk_buff *skb, struct policy_entry *policy) 138 { 139 /* FIXME: Use per cpu counters */ 140 __sync_fetch_and_add(&policy->packets, 1); 141 __sync_fetch_and_add(&policy->bytes, skb->len); 142 } 143 144 static inline int __inline__ 145 __policy_can_access(void *map, struct __sk_buff *skb, __u32 identity, 146 __u16 dport, __u8 proto, int dir, bool is_fragment) 147 { 148 struct policy_entry *policy; 149 150 struct policy_key key = { 151 .sec_label = identity, 152 .dport = dport, 153 .protocol = proto, 154 .egress = !dir, 155 .pad = 0, 156 }; 157 158 if (!is_fragment) { 159 policy = map_lookup_elem(map, &key); 160 if (likely(policy)) { 161 cilium_dbg3(skb, DBG_L4_CREATE, identity, SECLABEL, 162 dport << 16 | proto); 163 164 account(skb, policy); 165 goto get_proxy_port; 166 } 167 } 168 169 /* If L4 policy check misses, fall back to L3. */ 170 key.dport = 0; 171 key.protocol = 0; 172 policy = map_lookup_elem(map, &key); 173 if (likely(policy)) { 174 account(skb, policy); 175 return TC_ACT_OK; 176 } 177 178 if (!is_fragment) { 179 key.sec_label = 0; 180 key.dport = dport; 181 key.protocol = proto; 182 policy = map_lookup_elem(map, &key); 183 if (likely(policy)) { 184 account(skb, policy); 185 goto get_proxy_port; 186 } 187 key.dport = 0; 188 key.protocol = 0; 189 } 190 191 /* Final fallback if allow-all policy is in place. */ 192 key.sec_label = 0; 193 policy = map_lookup_elem(map, &key); 194 if (policy) { 195 account(skb, policy); 196 return TC_ACT_OK; 197 } 198 199 if (skb->cb[CB_POLICY]) 200 goto allow; 201 202 if (is_fragment) 203 return DROP_FRAG_NOSUPPORT; 204 return DROP_POLICY; 205 get_proxy_port: 206 if (likely(policy)) { 207 return policy->proxy_port; 208 } 209 allow: 210 return TC_ACT_OK; 211 } 212 213 /** 214 * Determine whether the policy allows this traffic on ingress. 215 * @arg skb Packet to allow or deny 216 * @arg src_identity Source security identity for this packet 217 * @arg dport Destination port of this packet 218 * @arg proto L3 Protocol of this packet 219 * 220 * Returns: 221 * - Positive integer indicating the proxy_port to handle this traffic 222 * - TC_ACT_OK if the policy allows this traffic based only on labels/L3/L4 223 * - Negative error code if the packet should be dropped 224 */ 225 static inline int __inline__ 226 policy_can_access_ingress(struct __sk_buff *skb, __u32 src_identity, 227 __u16 dport, __u8 proto, bool is_fragment) 228 { 229 int ret; 230 231 ret = __policy_can_access(&POLICY_MAP, skb, src_identity, dport, 232 proto, CT_INGRESS, is_fragment); 233 if (ret >= TC_ACT_OK) 234 return ret; 235 236 cilium_dbg(skb, DBG_POLICY_DENIED, src_identity, SECLABEL); 237 238 #ifdef IGNORE_DROP 239 ret = TC_ACT_OK; 240 #endif 241 242 return ret; 243 } 244 245 #ifdef ENCAP_IFINDEX 246 static inline bool __inline__ 247 is_encap(struct __sk_buff *skb, __u16 dport, __u8 proto) 248 { 249 return proto == IPPROTO_UDP && 250 (dport == bpf_htons(PORT_UDP_VXLAN) || 251 dport == bpf_htons(PORT_UDP_GENEVE) || 252 dport == bpf_htons(PORT_UDP_VXLAN_LINUX)); 253 } 254 #endif 255 256 static inline int __inline__ 257 policy_can_egress(struct __sk_buff *skb, __u32 identity, __u16 dport, __u8 proto) 258 { 259 #ifdef ENCAP_IFINDEX 260 if (is_encap(skb, dport, proto)) 261 return DROP_ENCAP_PROHIBITED; 262 #endif 263 264 int ret = __policy_can_access(&POLICY_MAP, skb, identity, dport, proto, 265 CT_EGRESS, false); 266 if (ret >= 0) 267 return ret; 268 269 cilium_dbg(skb, DBG_POLICY_DENIED, SECLABEL, identity); 270 271 #ifdef IGNORE_DROP 272 ret = TC_ACT_OK; 273 #endif 274 275 return ret; 276 } 277 278 static inline int policy_can_egress6(struct __sk_buff *skb, 279 struct ipv6_ct_tuple *tuple, 280 __u32 identity) 281 { 282 return policy_can_egress(skb, identity, tuple->dport, tuple->nexthdr); 283 } 284 285 static inline int policy_can_egress4(struct __sk_buff *skb, 286 struct ipv4_ct_tuple *tuple, 287 __u32 identity) 288 { 289 return policy_can_egress(skb, identity, tuple->dport, tuple->nexthdr); 290 } 291 292 /** 293 * Mark skb to skip policy enforcement 294 * @arg skb packet 295 * 296 * Will cause the packet to ignore the policy enforcement layer and 297 * be considered accepted despite of the policy outcome. 298 */ 299 static inline void policy_mark_skip(struct __sk_buff *skb) 300 { 301 skb->cb[CB_POLICY] = 1; 302 } 303 304 static inline void policy_clear_mark(struct __sk_buff *skb) 305 { 306 skb->cb[CB_POLICY] = 0; 307 } 308 309 #endif // SOCKMAP 310 #else 311 312 313 static inline void policy_mark_skip(struct __sk_buff *skb) 314 { 315 } 316 317 static inline void policy_clear_mark(struct __sk_buff *skb) 318 { 319 } 320 321 #endif