From 1ee8439ed8b717e7e2863d9321c5d18f44c5c365 Mon Sep 17 00:00:00 2001 From: Quentin Dufour Date: Sun, 25 Apr 2021 16:27:43 +0200 Subject: [PATCH] WIP checksum --- xdp/test.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++++ xdp/xdp_udp.c | 40 +++++++++++++++++--- 2 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 xdp/test.c diff --git a/xdp/test.c b/xdp/test.c new file mode 100644 index 0000000..80a909a --- /dev/null +++ b/xdp/test.c @@ -0,0 +1,102 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +char pkt[]={0x04, 0xf0, 0x21, 0x65, 0x18, 0x12, 0x50, 0x9a, 0x4c, + 0x24, 0x1a, 0x72, 0x08, 0x00, 0x45, 0x00, 0x00, 0x20, + 0x37, 0xb5, 0x40, 0x00, 0x40, 0x11, 0x70, 0x86, 0xc0, + 0xa8, 0x00, 0xad, 0xd4, 0x2f, 0xfd, 0x0c, 0x9e, 0x1e, + 0x09, 0x44, 0x00, 0x0c, 0xfd, 0x72, 0x64, 0x64, 0x64, + 0x0a}; + +char pkt2[] = { 0x04,0xf0,0x21,0x65,0x18,0x12,0x50,0x9a,0x4c,0x24,0x1a,0x72,0x08,0x00,0x45,0x00,0x00,0x4e,0xf7,0xb9,0x00,0x00,0x40,0x11,0xb1,0x80,0xc0,0xa8,0x00,0xad,0x08,0x08,0x08,0x08,0x95,0xa2,0x00,0x35,0x00,0x3a,0xd1,0xb0,0x4a,0x8d,0x01,0x20,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x02,0x66,0x72,0x00,0x00,0x01,0x00,0x01,0x00,0x00,0x29,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x0c,0x00,0x0a,0x00,0x08,0x32,0x1b,0xf3,0x55,0xed,0xd5,0xd5,0x6b }; + +char pkt3[] = { 0x50,0x9a,0x4c,0x24,0x1a,0x72,0x04,0xf0,0x21,0x65,0x18,0x12,0x08,0x00,0x45,0x00,0x00,0x64,0x7e,0x9c,0x40,0x00,0x40,0x11,0xfb,0xfe,0xc0,0xa8,0x00,0xfe,0xc0,0xa8,0x00,0xad,0x00,0x35,0xe6,0x4c,0x00,0x50,0x88,0x50,0xd1,0x70,0x81,0x80,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x01,0x0c,0x73,0x61,0x66,0x65,0x62,0x72,0x6f,0x77,0x73,0x69,0x6e,0x67,0x0a,0x67,0x6f,0x6f,0x67,0x6c,0x65,0x61,0x70,0x69,0x73,0x03,0x63,0x6f,0x6d,0x00,0x00,0x01,0x00,0x01,0xc0,0x0c,0x00,0x01,0x00,0x01,0x00,0x00,0x01,0x0d,0x00,0x04,0x8e,0xfa,0xba,0x8a,0x00,0x00,0x29,0x04,0xd0,0x00,0x00,0x00,0x00,0x00,0x00 }; + +char csDesired[] = { 0x38, 0xf1 }; + +// Checksum utilities +__attribute__((__always_inline__)) +static inline __u16 csum_fold_helper(__u64 csum) { + int i; + #pragma unroll + for (i = 0; i < 4; i ++) { + if (csum >> 16) + csum = (csum & 0xffff) + (csum >> 16); + } + return ~csum; +} + +// Update checksum following RFC 1624 (Eqn. 3): https://tools.ietf.org/html/rfc1624 +// HC' = ~(~HC + ~m + m') +// Where : +// HC - old checksum in header +// HC' - new checksum in header +// m - old value +// m' - new value +__attribute__((__always_inline__)) +static inline void update_csum(__u64 *csum, __be32 old_flag,__be32 new_flag ) { + // ~HC + *csum = ~*csum; + *csum = *csum & 0xffff; + // + ~m + __u32 tmp; + tmp = ~old_addr; + *csum += tmp; + // + m + *csum += new_addr; + // then fold and complement result ! + *csum = csum_fold_helper(*csum); +} + + +int main(void) { + void *data = pkt3; + void *data_end = pkt3+114; + + struct ethhdr *eth = data; //structure ethernet from if_ether.h + struct iphdr *ip = (struct iphdr*)(eth + 1); + printf("%#06x\n", bpf_ntohs(ip->check)); + __u64 cs = iph->check; + update_csum(&cs, old_addr, new_addr); + iph->check = cs; + printf("new cs: %x\n", ip->check); +} + +int main2(void) { + void *data = pkt2; //pkt; + void *data_end = pkt2+92;//pkt+46; + + struct ethhdr *eth = data; //structure ethernet from if_ether.h + struct iphdr *ip = (struct iphdr*)(eth + 1); + + // Check that our packet ethernet headers is big enough, ie. at least the size of Ethernet's fixed headers + if((void*)ip > data_end) { + printf("eth headers too short\n"); + return EXIT_SUCCESS; + } + + // Check that the ethernet header declares an IPv4 packet + if(eth->h_proto == bpf_htons(ETH_P_IP)) { + printf("this is an IPv4 packet according to ethernet headers\n"); + // Check that the IP packet is big enough, ie. at least the size of IP's fixed headers + if((void*)(ip + 1) > data_end) { + printf("IPv4 headers are too short \n"); + return EXIT_SUCCESS; + } + + if(ip->protocol == IPPROTO_UDP) { + printf("Protocol is UDP, flags are %#06x\n", ip->frag_off); + printf("Total offset: %x\n", (void*)&(ip->frag_off) - data); + ip->frag_off |= bpf_htons(0x4000); //Set the DF flag to 1 -> 0b 0100 0000 0000 0000 + printf("Protocol is UDP, flags are now %#06x\n", ip->frag_off); + } + } + + +} diff --git a/xdp/xdp_udp.c b/xdp/xdp_udp.c index 9d28cdd..2cdca60 100644 --- a/xdp/xdp_udp.c +++ b/xdp/xdp_udp.c @@ -25,6 +25,32 @@ +#define bpf_printk(fmt, ...) \ +({ \ + char ____fmt[] = fmt; \ + bpf_trace_printk(____fmt, sizeof(____fmt), \ + ##__VA_ARGS__); \ +}) + +static inline unsigned short checksum(unsigned short *buf, int bufsz) { + unsigned long sum = 0; + + while (bufsz > 1) { + sum += *buf; + buf++; + bufsz -= 2; + } + + if (bufsz == 1) { + sum += *(unsigned char *)buf; + } + + sum = (sum & 0xffff) + (sum >> 16); + sum = (sum & 0xffff) + (sum >> 16); + + return ~sum; +} + SEC("xdp_udp") int xdp_udp_func(struct xdp_md *ctx) { @@ -32,25 +58,27 @@ int xdp_udp_func(struct xdp_md *ctx) void *data = (void *)(long)ctx->data; struct ethhdr *eth = data; //structure ethernet from if_ether.h + struct iphdr *ip = (struct iphdr*)(eth + 1); // Check that our packet ethernet headers is big enough, ie. at least the size of Ethernet's fixed headers - if((void*)(eth + 1) > data_end) { + if((void*)ip > data_end) { return XDP_PASS; } // Check that the ethernet header declares an IPv4 packet if(eth->h_proto == bpf_htons(ETH_P_IP)) { - struct iphdr *ip = (struct iphdr*)(eth + 1); // Check that the IP packet is big enough, ie. at least the size of IP's fixed headers - if((void*)(ip + 1) > data_end) { + if ((void*)(ip + 1) > data_end) { return XDP_PASS; } if(ip->protocol == IPPROTO_UDP) { - ip->frag_off |= 0x4000; //Set the DF flag to 1 -> 0b 0100 0000 0000 0000 + ip->frag_off |= bpf_htons(0x4000); //Set the DF flag to 1 -> 0b 0100 0000 0000 0000 + ip->check = 0x0000; + ip->check = checksum((unsigned short*)ip, sizeof(ip)); } } - - return XDP_PASS; } + +char _license[] SEC("license") = "GPL";