brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · de15155 Raw
137 lines · c
1// SPDX-License-Identifier: GPL-2.02#include <stddef.h>3#include <stdint.h>4#include <stdbool.h>5 6#include <linux/bpf.h>7#include <linux/stddef.h>8#include <linux/pkt_cls.h>9#include <linux/if_ether.h>10#include <linux/in.h>11#include <linux/ip.h>12#include <linux/ipv6.h>13 14#include <bpf/bpf_helpers.h>15#include <bpf/bpf_endian.h>16 17#ifndef ctx_ptr18# define ctx_ptr(field)		(void *)(long)(field)19#endif20 21#define ip4_src			0xac100164 /* 172.16.1.100 */22#define ip4_dst			0xac100264 /* 172.16.2.100 */23 24#define ip6_src			{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \25				  0x00, 0x01, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe }26#define ip6_dst			{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \27				  0x00, 0x02, 0xde, 0xad, 0xbe, 0xef, 0xca, 0xfe }28 29#ifndef v6_equal30# define v6_equal(a, b)		(a.s6_addr32[0] == b.s6_addr32[0] && \31				 a.s6_addr32[1] == b.s6_addr32[1] && \32				 a.s6_addr32[2] == b.s6_addr32[2] && \33				 a.s6_addr32[3] == b.s6_addr32[3])34#endif35 36volatile const __u32 IFINDEX_SRC;37volatile const __u32 IFINDEX_DST;38 39static __always_inline bool is_remote_ep_v4(struct __sk_buff *skb,40					    __be32 addr)41{42	void *data_end = ctx_ptr(skb->data_end);43	void *data = ctx_ptr(skb->data);44	struct iphdr *ip4h;45 46	if (data + sizeof(struct ethhdr) > data_end)47		return false;48 49	ip4h = (struct iphdr *)(data + sizeof(struct ethhdr));50	if ((void *)(ip4h + 1) > data_end)51		return false;52 53	return ip4h->daddr == addr;54}55 56static __always_inline bool is_remote_ep_v6(struct __sk_buff *skb,57					    struct in6_addr addr)58{59	void *data_end = ctx_ptr(skb->data_end);60	void *data = ctx_ptr(skb->data);61	struct ipv6hdr *ip6h;62 63	if (data + sizeof(struct ethhdr) > data_end)64		return false;65 66	ip6h = (struct ipv6hdr *)(data + sizeof(struct ethhdr));67	if ((void *)(ip6h + 1) > data_end)68		return false;69 70	return v6_equal(ip6h->daddr, addr);71}72 73SEC("tc")74int tc_chk(struct __sk_buff *skb)75{76	void *data_end = ctx_ptr(skb->data_end);77	void *data = ctx_ptr(skb->data);78	__u32 *raw = data;79 80	if (data + sizeof(struct ethhdr) > data_end)81		return TC_ACT_SHOT;82 83	return !raw[0] && !raw[1] && !raw[2] ? TC_ACT_SHOT : TC_ACT_OK;84}85 86SEC("tc")87int tc_dst(struct __sk_buff *skb)88{89	__u8 zero[ETH_ALEN * 2];90	bool redirect = false;91 92	switch (skb->protocol) {93	case __bpf_constant_htons(ETH_P_IP):94		redirect = is_remote_ep_v4(skb, __bpf_constant_htonl(ip4_src));95		break;96	case __bpf_constant_htons(ETH_P_IPV6):97		redirect = is_remote_ep_v6(skb, (struct in6_addr){{ip6_src}});98		break;99	}100 101	if (!redirect)102		return TC_ACT_OK;103 104	__builtin_memset(&zero, 0, sizeof(zero));105	if (bpf_skb_store_bytes(skb, 0, &zero, sizeof(zero), 0) < 0)106		return TC_ACT_SHOT;107 108	return bpf_redirect_neigh(IFINDEX_SRC, NULL, 0, 0);109}110 111SEC("tc")112int tc_src(struct __sk_buff *skb)113{114	__u8 zero[ETH_ALEN * 2];115	bool redirect = false;116 117	switch (skb->protocol) {118	case __bpf_constant_htons(ETH_P_IP):119		redirect = is_remote_ep_v4(skb, __bpf_constant_htonl(ip4_dst));120		break;121	case __bpf_constant_htons(ETH_P_IPV6):122		redirect = is_remote_ep_v6(skb, (struct in6_addr){{ip6_dst}});123		break;124	}125 126	if (!redirect)127		return TC_ACT_OK;128 129	__builtin_memset(&zero, 0, sizeof(zero));130	if (bpf_skb_store_bytes(skb, 0, &zero, sizeof(zero), 0) < 0)131		return TC_ACT_SHOT;132 133	return bpf_redirect_neigh(IFINDEX_DST, NULL, 0, 0);134}135 136char __license[] SEC("license") = "GPL";137