Skip to content

Instantly share code, notes, and snippets.

@aidvu
Last active March 21, 2023 21:06
Show Gist options
  • Save aidvu/d83bd659fe962c49c7eb510ad5eebcf3 to your computer and use it in GitHub Desktop.
Save aidvu/d83bd659fe962c49c7eb510ad5eebcf3 to your computer and use it in GitHub Desktop.
Modify ping reply TTL with XDP
KDIR ?= /lib/modules/$(shell uname -r)
SDIR ?= $(KDIR)/source
CLANG ?= clang
LLC ?= llc
#ARCH := $(subst x86_64,x86,$(shell arch))
ARCH := x86
BIN := modify-ping-ttl.o
CLANG_FLAGS = -I. -I$(SDIR)/arch/$(ARCH)/include \
-I$(SDIR)/arch/$(ARCH)/include/generated \
-I$(SDIR)/include \
-I$(SDIR)/arch/$(ARCH)/include/uapi \
-I$(SDIR)/arch/$(ARCH)/include/generated/uapi \
-I$(SDIR)/include/uapi \
-I$(SDIR)/include/generated/uapi \
-I$(SDIR)/tools/testing/selftests/bpf/ \
-include $(SDIR)/include/linux/kconfig.h \
-I $(KDIR)/build/include/ \
-I $(KDIR)/build/arch/$(ARCH)/include/generated/ \
-D__KERNEL__ -D__BPF_TRACING__ -Wno-unused-value -Wno-pointer-sign \
-D__TARGET_ARCH_$(ARCH) -Wno-compare-distinct-pointer-types \
-Wno-gnu-variable-sized-type-not-at-end \
-Wno-address-of-packed-member -Wno-tautological-compare \
-Wno-unknown-warning-option \
-O2 -emit-llvm
all: $(BIN)
clean:
rm -f *.o
modify-ping-ttl.o: modify-ping-ttl.c
$(CLANG) $(CLANG_FLAGS) -c $< -o - | \
$(LLC) -march=bpf -mcpu=$(CPU) -filetype=obj -o $@
#define KBUILD_MODNAME "xdp_main"
#include <linux/bpf.h>
#include <linux/if_ether.h>
#include <linux/in.h>
#include <linux/ip.h>
#include <linux/udp.h>
#include <linux/icmp.h>
#include "bpf_helpers.h"
#define SEC(NAME) __attribute__((section(NAME), used))
#define bpf_printk(fmt, ...) ({char ____fmt[] = fmt; bpf_trace_printk(____fmt, sizeof(____fmt), ##__VA_ARGS__); })
#define proper_htons(x) ((__be16)___constant_swab16((x)))
SEC("prog")
int xdp_main(struct xdp_md *ctx)
{
void *data_end = (void *)(uintptr_t)ctx->data_end;
void *data = (void *)(uintptr_t)ctx->data;
struct ethhdr *eth = data;
uint64_t nh_off = sizeof(*eth);
/* sanity check needed by the eBPF verifier */
if (data + nh_off > data_end) {
return XDP_PASS;
}
uint16_t h_proto = eth->h_proto;
int i;
/* Handle double VLAN tagged packet. See https://en.wikipedia.org/wiki/IEEE_802.1ad */
for (i = 0; i < 2; i++) {
if (h_proto == proper_htons(ETH_P_8021Q) || h_proto == proper_htons(ETH_P_8021AD)) {
struct vlan_hdr *vhdr;
vhdr = data + nh_off;
nh_off += sizeof(struct vlan_hdr);
if (data + nh_off > data_end) {
return XDP_PASS;
}
h_proto = vhdr->h_vlan_encapsulated_proto;
}
}
if (h_proto == proper_htons(ETH_P_IP)) {
struct iphdr *iph = data + nh_off;
struct icmphdr *icmph = data + nh_off + sizeof(struct iphdr);
if (icmph + 1 > (struct icmphdr*)data_end) {
return XDP_PASS;
}
if (iph->protocol != IPPROTO_ICMP) {
return XDP_PASS;
}
if (icmph->type != ICMP_ECHOREPLY) {
return XDP_PASS;
}
if (iph->ttl) {
/* save the old TTL to recalculate the checksum */
uint16_t *ttlproto = (uint16_t *)&iph->ttl;
uint16_t old_ttlproto = *ttlproto;
/* set the TTL to a pseudorandom number 1 < x < TTL */
iph->ttl = bpf_get_prandom_u32() % iph->ttl + 1;
/* recalculate the checksum; otherwise, the IP stack will drop it */
csum_replace2(&iph->check, old_ttlproto, *ttlproto);
// Example of logging to /sys/kernel/debug/tracing/trace
bpf_printk("Should be new TTL");
}
}
return XDP_PASS;
}
char _license[] SEC("license") = "GPL";
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment