Created
January 15, 2023 16:09
-
-
Save jlkiri/e78a03655b406d80b410711361821101 to your computer and use it in GitHub Desktop.
IPv6 user ID filtering eBPF code
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <linux/bpf.h> | |
#include <linux/in.h> | |
#include <linux/in6.h> | |
#include <linux/if_ether.h> | |
#include <linux/ip.h> | |
#include <linux/ipv6.h> | |
#include <bpf/bpf_helpers.h> | |
#include <bpf/bpf_endian.h> | |
#include <stdbool.h> | |
// Header cursor to keep track of current parsing position | |
struct hdr_cursor | |
{ | |
void *pos; | |
}; | |
static __always_inline int parse_ethhdr(struct hdr_cursor *nh, void *data_end, | |
struct ethhdr **ethhdr) | |
{ | |
struct ethhdr *eth = nh->pos; | |
int hdrsize = sizeof(*eth); | |
// Check if size of header does not exceed remaining number of bytes to parse. | |
if (nh->pos + hdrsize > data_end) | |
{ | |
return -1; | |
} | |
nh->pos += hdrsize; | |
*ethhdr = eth; | |
return eth->h_proto; // Network byte order | |
} | |
static __always_inline int parse_ipv6hdr(struct hdr_cursor *nh, void *data_end, | |
struct ipv6hdr **ipv6hdr) | |
{ | |
struct ipv6hdr *ipv6h = nh->pos; | |
int hdrsize = sizeof(*ipv6h); | |
// Check if size of header does not exceed remaining number of bytes to parse. | |
if (nh->pos + hdrsize > data_end) | |
{ | |
return -1; | |
} | |
nh->pos += hdrsize; | |
*ipv6hdr = ipv6h; | |
return ipv6h->nexthdr; | |
} | |
SEC("xdp") | |
// If both source and destination IPv6 address of a packet | |
// is a ULA (that begins with fd20), drop the packet if | |
// the user IDs of two addresses (represented with the 7th quartet) | |
// are not equal. | |
int filter_ipv6(struct xdp_md *ctx) | |
{ | |
void *data = (void *)(long)ctx->data; | |
void *data_end = (void *)(long)ctx->data_end; | |
struct hdr_cursor nh; | |
struct ethhdr *eth; | |
struct ipv6hdr *ip6h; | |
nh.pos = data; | |
int protocol = parse_ethhdr(&nh, data_end, ð); | |
if (protocol == bpf_htons(ETH_P_IPV6)) | |
{ | |
if (parse_ipv6hdr(&nh, data_end, &ip6h) == -1) | |
{ | |
return XDP_DROP; | |
} | |
__be16 src_user = ip6h->saddr.s6_addr16[6]; // Network byte order | |
__be16 dest_user = ip6h->daddr.s6_addr16[6]; // Network byte order | |
bool is_src_ula = bpf_ntohs(ip6h->saddr.s6_addr16[0]) == 0xfd20; | |
bool is_dest_ula = bpf_ntohs(ip6h->daddr.s6_addr16[0]) == 0xfd20; | |
if (is_src_ula && is_dest_ula && src_user != dest_user) | |
{ | |
bpf_printk("[DROP] src: %pI6 dest: %pI6", ip6h->saddr.s6_addr, ip6h->daddr.s6_addr); | |
return XDP_DROP; | |
} | |
} | |
return XDP_PASS; | |
} | |
char LICENSE[] SEC("license") = "Dual BSD/GPL"; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment