github.com/datadog/cilium@v1.6.12/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