0001
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
0022 #define ip4_dst 0xac100264
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";