Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <stddef.h>
0003 #include <stdint.h>
0004 #include <stdbool.h>
0005 
0006 #include <linux/bpf.h>
0007 #include <linux/stddef.h>
0008 #include <linux/pkt_cls.h>
0009 #include <linux/if_ether.h>
0010 #include <linux/in.h>
0011 #include <linux/ip.h>
0012 #include <linux/ipv6.h>
0013 
0014 #include <bpf/bpf_helpers.h>
0015 #include <bpf/bpf_endian.h>
0016 
0017 #ifndef ctx_ptr
0018 # define ctx_ptr(field)     (void *)(long)(field)
0019 #endif
0020 
0021 #define ip4_src         0xac100164 /* 172.16.1.100 */
0022 #define ip4_dst         0xac100264 /* 172.16.2.100 */
0023 
0024 #define ip6_src         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0025                   0x00, 0x01, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe }
0026 #define ip6_dst         { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0027                   0x00, 0x02, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe }
0028 
0029 #ifndef v6_equal
0030 # define v6_equal(a, b)     (a.s6_addr32[0] == b.s6_addr32[0] && \
0031                  a.s6_addr32[1] == b.s6_addr32[1] && \
0032                  a.s6_addr32[2] == b.s6_addr32[2] && \
0033                  a.s6_addr32[3] == b.s6_addr32[3])
0034 #endif
0035 
0036 volatile const __u32 IFINDEX_SRC;
0037 volatile const __u32 IFINDEX_DST;
0038 
0039 static __always_inline bool is_remote_ep_v4(struct __sk_buff *skb,
0040                         __be32 addr)
0041 {
0042     void *data_end = ctx_ptr(skb->data_end);
0043     void *data = ctx_ptr(skb->data);
0044     struct iphdr *ip4h;
0045 
0046     if (data + sizeof(struct ethhdr) > data_end)
0047         return false;
0048 
0049     ip4h = (struct iphdr *)(data + sizeof(struct ethhdr));
0050     if ((void *)(ip4h + 1) > data_end)
0051         return false;
0052 
0053     return ip4h->daddr == addr;
0054 }
0055 
0056 static __always_inline bool is_remote_ep_v6(struct __sk_buff *skb,
0057                         struct in6_addr addr)
0058 {
0059     void *data_end = ctx_ptr(skb->data_end);
0060     void *data = ctx_ptr(skb->data);
0061     struct ipv6hdr *ip6h;
0062 
0063     if (data + sizeof(struct ethhdr) > data_end)
0064         return false;
0065 
0066     ip6h = (struct ipv6hdr *)(data + sizeof(struct ethhdr));
0067     if ((void *)(ip6h + 1) > data_end)
0068         return false;
0069 
0070     return v6_equal(ip6h->daddr, addr);
0071 }
0072 
0073 SEC("tc")
0074 int tc_chk(struct __sk_buff *skb)
0075 {
0076     void *data_end = ctx_ptr(skb->data_end);
0077     void *data = ctx_ptr(skb->data);
0078     __u32 *raw = data;
0079 
0080     if (data + sizeof(struct ethhdr) > data_end)
0081         return TC_ACT_SHOT;
0082 
0083     return !raw[0] && !raw[1] && !raw[2] ? TC_ACT_SHOT : TC_ACT_OK;
0084 }
0085 
0086 SEC("tc")
0087 int tc_dst(struct __sk_buff *skb)
0088 {
0089     __u8 zero[ETH_ALEN * 2];
0090     bool redirect = false;
0091 
0092     switch (skb->protocol) {
0093     case __bpf_constant_htons(ETH_P_IP):
0094         redirect = is_remote_ep_v4(skb, __bpf_constant_htonl(ip4_src));
0095         break;
0096     case __bpf_constant_htons(ETH_P_IPV6):
0097         redirect = is_remote_ep_v6(skb, (struct in6_addr)ip6_src);
0098         break;
0099     }
0100 
0101     if (!redirect)
0102         return TC_ACT_OK;
0103 
0104     __builtin_memset(&zero, 0, sizeof(zero));
0105     if (bpf_skb_store_bytes(skb, 0, &zero, sizeof(zero), 0) < 0)
0106         return TC_ACT_SHOT;
0107 
0108     return bpf_redirect_neigh(IFINDEX_SRC, NULL, 0, 0);
0109 }
0110 
0111 SEC("tc")
0112 int tc_src(struct __sk_buff *skb)
0113 {
0114     __u8 zero[ETH_ALEN * 2];
0115     bool redirect = false;
0116 
0117     switch (skb->protocol) {
0118     case __bpf_constant_htons(ETH_P_IP):
0119         redirect = is_remote_ep_v4(skb, __bpf_constant_htonl(ip4_dst));
0120         break;
0121     case __bpf_constant_htons(ETH_P_IPV6):
0122         redirect = is_remote_ep_v6(skb, (struct in6_addr)ip6_dst);
0123         break;
0124     }
0125 
0126     if (!redirect)
0127         return TC_ACT_OK;
0128 
0129     __builtin_memset(&zero, 0, sizeof(zero));
0130     if (bpf_skb_store_bytes(skb, 0, &zero, sizeof(zero), 0) < 0)
0131         return TC_ACT_SHOT;
0132 
0133     return bpf_redirect_neigh(IFINDEX_DST, NULL, 0, 0);
0134 }
0135 
0136 char __license[] SEC("license") = "GPL";