brintos

brintos / linux-shallow public Read only

0
0
Text · 3.2 KiB · 4f2e232 Raw
143 lines · c
1// SPDX-License-Identifier: GPL-2.02/* Copyright (c) 2023 Isovalent */3#include <stdbool.h>4#include <linux/bpf.h>5#include <linux/if_ether.h>6#include <linux/in.h>7#include <linux/ip.h>8#include <linux/ipv6.h>9#include <linux/tcp.h>10#include <linux/udp.h>11#include <bpf/bpf_endian.h>12#include <bpf/bpf_helpers.h>13#include <linux/pkt_cls.h>14 15char LICENSE[] SEC("license") = "GPL";16 17__u64 sk_cookie_seen;18__u64 reuseport_executed;19union {20	struct tcphdr tcp;21	struct udphdr udp;22} headers;23 24const volatile __u16 dest_port;25 26struct {27	__uint(type, BPF_MAP_TYPE_SOCKMAP);28	__uint(max_entries, 1);29	__type(key, __u32);30	__type(value, __u64);31} sk_map SEC(".maps");32 33SEC("sk_reuseport")34int reuse_accept(struct sk_reuseport_md *ctx)35{36	reuseport_executed++;37 38	if (ctx->ip_protocol == IPPROTO_TCP) {39		if (ctx->data + sizeof(headers.tcp) > ctx->data_end)40			return SK_DROP;41 42		if (__builtin_memcmp(&headers.tcp, ctx->data, sizeof(headers.tcp)) != 0)43			return SK_DROP;44	} else if (ctx->ip_protocol == IPPROTO_UDP) {45		if (ctx->data + sizeof(headers.udp) > ctx->data_end)46			return SK_DROP;47 48		if (__builtin_memcmp(&headers.udp, ctx->data, sizeof(headers.udp)) != 0)49			return SK_DROP;50	} else {51		return SK_DROP;52	}53 54	sk_cookie_seen = bpf_get_socket_cookie(ctx->sk);55	return SK_PASS;56}57 58SEC("sk_reuseport")59int reuse_drop(struct sk_reuseport_md *ctx)60{61	reuseport_executed++;62	sk_cookie_seen = 0;63	return SK_DROP;64}65 66static int67assign_sk(struct __sk_buff *skb)68{69	int zero = 0, ret = 0;70	struct bpf_sock *sk;71 72	sk = bpf_map_lookup_elem(&sk_map, &zero);73	if (!sk)74		return TC_ACT_SHOT;75	ret = bpf_sk_assign(skb, sk, 0);76	bpf_sk_release(sk);77	return ret ? TC_ACT_SHOT : TC_ACT_OK;78}79 80static bool81maybe_assign_tcp(struct __sk_buff *skb, struct tcphdr *th)82{83	if (th + 1 > (void *)(long)(skb->data_end))84		return TC_ACT_SHOT;85 86	if (!th->syn || th->ack || th->dest != bpf_htons(dest_port))87		return TC_ACT_OK;88 89	__builtin_memcpy(&headers.tcp, th, sizeof(headers.tcp));90	return assign_sk(skb);91}92 93static bool94maybe_assign_udp(struct __sk_buff *skb, struct udphdr *uh)95{96	if (uh + 1 > (void *)(long)(skb->data_end))97		return TC_ACT_SHOT;98 99	if (uh->dest != bpf_htons(dest_port))100		return TC_ACT_OK;101 102	__builtin_memcpy(&headers.udp, uh, sizeof(headers.udp));103	return assign_sk(skb);104}105 106SEC("tc")107int tc_main(struct __sk_buff *skb)108{109	void *data_end = (void *)(long)skb->data_end;110	void *data = (void *)(long)skb->data;111	struct ethhdr *eth;112 113	eth = (struct ethhdr *)(data);114	if (eth + 1 > data_end)115		return TC_ACT_SHOT;116 117	if (eth->h_proto == bpf_htons(ETH_P_IP)) {118		struct iphdr *iph = (struct iphdr *)(data + sizeof(*eth));119 120		if (iph + 1 > data_end)121			return TC_ACT_SHOT;122 123		if (iph->protocol == IPPROTO_TCP)124			return maybe_assign_tcp(skb, (struct tcphdr *)(iph + 1));125		else if (iph->protocol == IPPROTO_UDP)126			return maybe_assign_udp(skb, (struct udphdr *)(iph + 1));127		else128			return TC_ACT_SHOT;129	} else {130		struct ipv6hdr *ip6h = (struct ipv6hdr *)(data + sizeof(*eth));131 132		if (ip6h + 1 > data_end)133			return TC_ACT_SHOT;134 135		if (ip6h->nexthdr == IPPROTO_TCP)136			return maybe_assign_tcp(skb, (struct tcphdr *)(ip6h + 1));137		else if (ip6h->nexthdr == IPPROTO_UDP)138			return maybe_assign_udp(skb, (struct udphdr *)(ip6h + 1));139		else140			return TC_ACT_SHOT;141	}142}143