├── .gitmodules ├── Makefile ├── README.md └── src ├── common.h ├── helpers.h ├── loader.c ├── xdp_methodfour.c ├── xdp_methodone.c ├── xdp_methodthree.c ├── xdp_methodtwo.c └── xdp_prog.c /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libbpf"] 2 | path = libbpf 3 | url = https://github.com/libbpf/libbpf 4 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | CC = clang 2 | 3 | objects += src/loader.o 4 | 5 | libbpf_static_objects += libbpf/src/staticobjs/bpf.o libbpf/src/staticobjs/btf.o libbpf/src/staticobjs/libbpf_errno.o libbpf/src/staticobjs/libbpf_probes.o 6 | libbpf_static_objects += libbpf/src/staticobjs/libbpf.o libbpf/src/staticobjs/netlink.o libbpf/src/staticobjs/nlattr.o libbpf/src/staticobjs/str_error.o 7 | libbpf_static_objects += libbpf/src/staticobjs/hashmap.o libbpf/src/staticobjs/bpf_prog_linfo.o 8 | 9 | LDFLAGS += -lelf -lz 10 | 11 | all: loader methodone methodtwo methodthree methodfour 12 | loader: libbpf $(objects) 13 | clang $(LDFLAGS) -o loader $(libbpf_static_objects) $(objects) 14 | methodone: src/xdp_methodone.o 15 | clang -D__BPF__ -Wall -Wextra -O2 -emit-llvm -c src/xdp_methodone.c -o src/xdp_methodone.bc 16 | llc -march=bpf -filetype=obj src/xdp_methodone.bc -o src/xdp_methodone.o 17 | methodtwo: src/xdp_methodtwo.o 18 | clang -D__BPF__ -Wall -Wextra -O2 -emit-llvm -c src/xdp_methodtwo.c -o src/xdp_methodtwo.bc 19 | llc -march=bpf -filetype=obj src/xdp_methodtwo.bc -o src/xdp_methodtwo.o 20 | methodthree: src/xdp_methodthree.o 21 | clang -D__BPF__ -Wall -Wextra -O2 -emit-llvm -c src/xdp_methodthree.c -o src/xdp_methodthree.bc 22 | llc -march=bpf -filetype=obj src/xdp_methodthree.bc -o src/xdp_methodthree.o 23 | methodfour: src/xdp_methodfour.o 24 | clang -D__BPF__ -Wall -Wextra -O2 -emit-llvm -c src/xdp_methodfour.c -o src/xdp_methodfour.bc 25 | llc -march=bpf -filetype=obj src/xdp_methodfour.bc -o src/xdp_methodfour.o 26 | libbpf: 27 | $(MAKE) -C libbpf/src 28 | clean: 29 | $(MAKE) -C libbpf/src clean 30 | rm -f src/*.o src/*.bc 31 | rm -f loader 32 | .PHONY: libbpf all 33 | .DEFAULT: all -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # XDP Dynamic Payload Matching Findings 2 | This repository is used to store my findings on matching dynamic payloads in XDP. In my opinion, being able to match payload data from a BPF map is important for the future of XDP. 3 | 4 | I made a thread on the XDP Newbies mailing list [here](https://marc.info/?l=xdp-newbies&m=158894658804356&w=2) addressing this. Unfortunately, it appears nobody has found a way to match XDP payload data dynamically yet. However, Toke did give a suggestion that I plan on trying and noting in this repository. 5 | 6 | In these XDP program sections, we try to compare payload data from the `payload_map` BPF map. You may specify the payload in `src/loader.c`. 7 | 8 | ## Section "methodone" (FAIL) 9 | In this method, we attempt to match the payload data using a for loop. We check if the offset is outside of the packet via: 10 | 11 | ```C 12 | if (byte + 1 > (uint8_t *)data_end) 13 | { 14 | break; 15 | } 16 | ``` 17 | 18 | Unfortunately, this still fails the BPF verifier: 19 | 20 | ``` 21 | invalid access to packet, off=22 size=1, R7(id=3,off=22,r=0) 22 | R7 offset is outside of the packet 23 | processed 55 insns (limit 1000000) max_states_per_insn 0 total_states 4 peak_states 4 mark_read 3 24 | ``` 25 | 26 | ## Section "methodtwo" (FAIL) 27 | In this method, we attempt to match the payload data using a for loop just like method one. However, we use goto. 28 | 29 | We check if the offset is outside of the packet via: 30 | 31 | ```C 32 | if (byte + 1 > (uint8_t *)data_end) 33 | { 34 | break; 35 | } 36 | ``` 37 | 38 | Unfortunately, this still fails the BPF verifier just like method one: 39 | 40 | ``` 41 | invalid access to packet, off=22 size=1, R7(id=3,off=22,r=0) 42 | R7 offset is outside of the packet 43 | processed 55 insns (limit 1000000) max_states_per_insn 0 total_states 4 peak_states 4 mark_read 3 44 | ``` 45 | 46 | ## Section "methodthree" (FAIL) 47 | *Not finished* 48 | 49 | ## Section "methodfour" (SUCCESS!) 50 | This method works! However, with its current implementation, it can only match payload data from the beginning of the string and once. With that said, the payload needs to be exact. 51 | 52 | This is because we store the payload data we want to match inside of a BPF map as the key. The main code looks like this: 53 | 54 | 55 | ```C 56 | uint8_t *pcktdata = data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4len; 57 | 58 | uint8_t hashkey[MAX_PAYLOAD_LENGTH] = {0}; 59 | 60 | for (int i = 0; i < MAX_PAYLOAD_LENGTH; i++) 61 | { 62 | if (pcktdata + (i + 1) > (uint8_t *)data_end) 63 | { 64 | break; 65 | } 66 | 67 | hashkey[i] = *(pcktdata + i); 68 | } 69 | 70 | uint8_t *match = bpf_map_lookup_elem(&payload_map, &hashkey); 71 | 72 | if (match) 73 | { 74 | printk("Dropping matched packet.\n"); 75 | } 76 | ``` 77 | 78 | ## Credits 79 | * [Christian Deacon](https://github.com/gamemann) -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define MAX_PAYLOAD_LENGTH 12 4 | 5 | struct payload 6 | { 7 | uint16_t length; 8 | uint8_t payload[MAX_PAYLOAD_LENGTH]; 9 | }; -------------------------------------------------------------------------------- /src/helpers.h: -------------------------------------------------------------------------------- 1 | #define likely(x) __builtin_expect(!!(x), 1) 2 | #define unlikely(x) __builtin_expect(!!(x), 0) 3 | #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 4 | #define htons(x) ((__be16)___constant_swab16((x))) 5 | #define ntohs(x) ((__be16)___constant_swab16((x))) 6 | #define htonl(x) ((__be32)___constant_swab32((x))) 7 | #define ntohl(x) ((__be32)___constant_swab32((x))) 8 | #elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ 9 | #define htons(x) (x) 10 | #define ntohs(X) (x) 11 | #define htonl(x) (x) 12 | #define ntohl(x) (x) 13 | #endif -------------------------------------------------------------------------------- /src/loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | 13 | #include "../libbpf/src/bpf.h" 14 | #include "../libbpf/src/libbpf.h" 15 | #include "common.h" 16 | 17 | #define PAYLOAD "FF FF 50 60 AE" 18 | #define SECTION "xdp_methodfour" 19 | #define PROGRAM "src/xdp_methodfour.o" 20 | 21 | static int cont = 1; 22 | const char *dev = "ens18"; 23 | static int progfd; 24 | uint32_t xdp_flags = XDP_FLAGS_SKB_MODE; // Load with SKB/Generic mode just so we know it'll work (e.g. if we don't support XDP-native). This is all for testing afterall and everything within the XDP program should work with XDP-native as well. 25 | 26 | void ShutDown(int tmp) 27 | { 28 | cont = 0; 29 | } 30 | 31 | int find_map_fd(struct bpf_object *bpf_obj, const char *mapname) 32 | { 33 | struct bpf_map *map; 34 | int fd = -1; 35 | 36 | map = bpf_object__find_map_by_name(bpf_obj, mapname); 37 | 38 | if (!map) 39 | { 40 | fprintf(stderr, "Error finding eBPF map: %s\n", mapname); 41 | 42 | goto out; 43 | } 44 | 45 | fd = bpf_map__fd(map); 46 | 47 | out: 48 | return fd; 49 | } 50 | 51 | struct bpf_object *load_bpf_object_file__simple(const char *filename) 52 | { 53 | int first_prog_fd = -1; 54 | struct bpf_object *obj; 55 | struct bpf_program *bpf_prog; 56 | int err; 57 | 58 | err = bpf_prog_load(filename, BPF_PROG_TYPE_XDP, &obj, &first_prog_fd); 59 | 60 | if (err) 61 | { 62 | fprintf(stderr, "Error loading XDP program. File => %s. Error => %s. Error Num => %d\n", filename, strerror(-err), err); 63 | 64 | return obj; 65 | } 66 | 67 | bpf_prog = bpf_object__find_program_by_title(obj, SECTION); 68 | 69 | if (!bpf_prog) 70 | { 71 | fprintf(stderr, "Error loading XDP section. File => %s. Error => %s. Error Num => %d. Section => %s.\n", filename, strerror(-err), err, SECTION); 72 | 73 | return obj; 74 | } 75 | 76 | progfd = bpf_program__fd(bpf_prog); 77 | 78 | return obj; 79 | } 80 | 81 | static int xdp_detach(int ifindex, uint32_t xdp_flags) 82 | { 83 | int err; 84 | 85 | err = bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); 86 | 87 | if (err < 0) 88 | { 89 | fprintf(stderr, "Error detaching XDP program. Error => %s. Error Num => %.d\n", strerror(-err), err); 90 | 91 | return -1; 92 | } 93 | 94 | return EXIT_SUCCESS; 95 | } 96 | 97 | static int xdp_attach(int ifindex, uint32_t xdp_flags, int prog_fd) 98 | { 99 | int err; 100 | 101 | err = bpf_set_link_xdp_fd(ifindex, prog_fd, xdp_flags); 102 | 103 | if (err == -EEXIST && !(xdp_flags & XDP_FLAGS_UPDATE_IF_NOEXIST)) 104 | { 105 | 106 | uint32_t oldflags = xdp_flags; 107 | 108 | xdp_flags &= ~XDP_FLAGS_MODES; 109 | xdp_flags |= (oldflags & XDP_FLAGS_SKB_MODE) ? XDP_FLAGS_DRV_MODE : XDP_FLAGS_SKB_MODE; 110 | 111 | err = bpf_set_link_xdp_fd(ifindex, -1, xdp_flags); 112 | 113 | if (!err) 114 | { 115 | err = bpf_set_link_xdp_fd(ifindex, prog_fd, oldflags); 116 | } 117 | } 118 | 119 | if (err < 0) 120 | { 121 | fprintf(stderr, "Error attaching XDP program. Error => %s. Error Num => %d. IfIndex => %d.\n", strerror(-err), -err, ifindex); 122 | 123 | switch(-err) 124 | { 125 | case EBUSY: 126 | 127 | case EEXIST: 128 | { 129 | xdp_detach(ifindex, xdp_flags); 130 | fprintf(stderr, "Additional: XDP already loaded on device.\n"); 131 | break; 132 | } 133 | 134 | case EOPNOTSUPP: 135 | fprintf(stderr, "Additional: XDP-native nor SKB not supported? Not sure how that's possible.\n"); 136 | 137 | break; 138 | 139 | default: 140 | break; 141 | } 142 | 143 | return -1; 144 | } 145 | 146 | return EXIT_SUCCESS; 147 | } 148 | 149 | int main(int argc, char **argv) 150 | { 151 | int ifidx; 152 | struct rlimit rlim = {RLIM_INFINITY, RLIM_INFINITY}; 153 | struct bpf_object *bpf_obj = NULL; 154 | int payload_map_fd; 155 | 156 | ifidx = if_nametoindex(dev); 157 | 158 | if (ifidx < 1) 159 | { 160 | fprintf(stderr, "Error finding device: %s\n", dev); 161 | 162 | exit(EXIT_FAILURE); 163 | } 164 | 165 | signal(SIGINT, ShutDown); 166 | 167 | xdp_detach(ifidx, xdp_flags); 168 | 169 | struct bpf_map *map; 170 | struct bpf_map *length_map; 171 | 172 | bpf_obj = load_bpf_object_file__simple(PROGRAM); 173 | 174 | if (!bpf_obj) 175 | { 176 | fprintf(stderr, "Error opening BPF object file."); 177 | 178 | exit(EXIT_FAILURE); 179 | } 180 | 181 | if (xdp_attach(ifidx, xdp_flags, progfd) != 0) 182 | { 183 | fprintf(stderr, "Error attaching XDP program: %s\n", strerror(errno)); 184 | 185 | exit(EXIT_FAILURE); 186 | } 187 | 188 | map = bpf_object__find_map_by_name(bpf_obj, "payload_map"); 189 | 190 | payload_map_fd = bpf_map__fd(map); 191 | 192 | if (payload_map_fd < 0) 193 | { 194 | fprintf(stderr, "ERROR: payload map not found: %s\n", strerror(payload_map_fd)); 195 | 196 | exit(EXIT_FAILURE); 197 | } 198 | 199 | if (setrlimit(RLIMIT_MEMLOCK, &rlim)) 200 | { 201 | fprintf(stderr, "ERROR: setrlimit(RLIMIT_MEMLOCK) \"%s\"\n", strerror(errno)); 202 | 203 | exit(EXIT_FAILURE); 204 | } 205 | 206 | if (strcmp(SECTION, "xdp_methodthree") == 0) 207 | { 208 | char str[MAX_PAYLOAD_LENGTH]; 209 | 210 | strcpy(str, PAYLOAD); 211 | 212 | char *ptr = strtok(str, " "); 213 | 214 | int i = 0; 215 | 216 | while (ptr != NULL) 217 | { 218 | uint8_t key; 219 | sscanf(ptr, "%2hhx", &key); 220 | 221 | uint8_t val = 1; 222 | ptr = strtok(NULL, " "); 223 | 224 | i++; 225 | 226 | bpf_map_update_elem(payload_map_fd, &key, &val, BPF_ANY); 227 | } 228 | } 229 | else if (strcmp(SECTION, "xdp_methodfour") == 0) 230 | { 231 | char str[256]; 232 | 233 | strcpy(str, PAYLOAD); 234 | 235 | char *ptr = strtok(str, " "); 236 | 237 | int i = 0; 238 | 239 | uint8_t key[MAX_PAYLOAD_LENGTH] = {0}; 240 | uint8_t val = 1; 241 | 242 | while (ptr != NULL) 243 | { 244 | sscanf(ptr, "%2hhx", &key[i]); 245 | ptr = strtok(NULL, " "); 246 | i++; 247 | } 248 | 249 | if (bpf_map_update_elem(payload_map_fd, &key, &val, BPF_ANY) != 0) 250 | { 251 | printf("Error updating BPF map."); 252 | } 253 | else 254 | { 255 | printf("Updated BPF map and set %d %d %d %d %d\n", key[0], key[1], key[2], key[3], key[4]); 256 | } 257 | } 258 | else 259 | { 260 | uint32_t key = 0; 261 | struct payload entry; 262 | char str[MAX_PAYLOAD_LENGTH]; 263 | 264 | strcpy(str, PAYLOAD); 265 | 266 | char *ptr = strtok(str, " "); 267 | 268 | int i = 0; 269 | 270 | while (ptr != NULL) 271 | { 272 | sscanf(ptr, "%2hhx", &entry.payload[i]); 273 | ptr = strtok(NULL, " "); 274 | 275 | entry.length++; 276 | i++; 277 | } 278 | 279 | bpf_map_update_elem(payload_map_fd, &key, &entry, BPF_ANY); 280 | } 281 | 282 | fprintf(stdout, "Starting XDP program and updated maps...\n"); 283 | 284 | while (cont) 285 | { 286 | sleep(1); 287 | } 288 | 289 | xdp_detach(ifidx, xdp_flags); 290 | 291 | return EXIT_SUCCESS; 292 | } -------------------------------------------------------------------------------- /src/xdp_methodfour.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "../libbpf/src/bpf_helpers.h" 12 | #include "helpers.h" 13 | #include "common.h" 14 | 15 | struct bpf_map_def SEC("maps") payload_map = 16 | { 17 | .type = BPF_MAP_TYPE_HASH, 18 | .key_size = MAX_PAYLOAD_LENGTH, 19 | .value_size = sizeof(uint8_t), 20 | .max_entries = 1 21 | }; 22 | 23 | struct bpf_map_def SEC("maps") payload_length = 24 | { 25 | .type = BPF_MAP_TYPE_ARRAY, 26 | .key_size = sizeof(uint32_t), 27 | .value_size = sizeof(uint8_t), 28 | .max_entries = 1 29 | }; 30 | 31 | #define printk(fmt, ...) \ 32 | ({ \ 33 | char ____fmt[] = fmt; \ 34 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 35 | ##__VA_ARGS__); \ 36 | }) 37 | 38 | #ifndef memcpy 39 | # define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) 40 | #endif 41 | 42 | SEC("xdp_methodfour") 43 | int xdp_prog(struct xdp_md *ctx) 44 | { 45 | void *data = (void *)(long)ctx->data; 46 | void *data_end = (void *)(long)ctx->data_end; 47 | 48 | struct ethhdr *eth = data; 49 | 50 | if (eth + 1 > (struct ethhdr *)data_end) 51 | { 52 | return XDP_DROP; 53 | } 54 | 55 | struct iphdr *iph = data + sizeof(struct ethhdr); 56 | 57 | if (iph + 1 > (struct iphdr *)data_end) 58 | { 59 | return XDP_DROP; 60 | } 61 | 62 | if (iph->protocol == IPPROTO_TCP) 63 | { 64 | struct tcphdr *tcph = data + sizeof(struct ethhdr) + (iph->ihl * 4); 65 | 66 | if (tcph + 1 > (struct tcphdr *)data_end) 67 | { 68 | return XDP_DROP; 69 | } 70 | 71 | if (tcph->dest != htons(8800)) 72 | { 73 | return XDP_PASS; 74 | } 75 | 76 | uint16_t l4len = tcph->doff * 4; 77 | 78 | uint8_t *pcktdata = data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4len; 79 | 80 | uint8_t hashkey[MAX_PAYLOAD_LENGTH] = {0}; 81 | 82 | for (int i = 0; i < MAX_PAYLOAD_LENGTH; i++) 83 | { 84 | if (pcktdata + (i + 1) > (uint8_t *)data_end) 85 | { 86 | break; 87 | } 88 | 89 | hashkey[i] = *(pcktdata + i); 90 | } 91 | 92 | uint8_t *match = bpf_map_lookup_elem(&payload_map, &hashkey); 93 | 94 | if (match) 95 | { 96 | printk("Dropping matched packet.\n"); 97 | } 98 | } 99 | 100 | return XDP_PASS; 101 | } 102 | 103 | char _license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /src/xdp_methodone.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "../libbpf/src/bpf_helpers.h" 12 | #include "helpers.h" 13 | #include "common.h" 14 | 15 | struct bpf_map_def SEC("maps") payload_map = 16 | { 17 | .type = BPF_MAP_TYPE_ARRAY, 18 | .key_size = sizeof(uint32_t), 19 | .value_size = sizeof(struct payload), 20 | .max_entries = 1 21 | }; 22 | 23 | #define printk(fmt, ...) \ 24 | ({ \ 25 | char ____fmt[] = fmt; \ 26 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 27 | ##__VA_ARGS__); \ 28 | }) 29 | 30 | SEC("xdp_methodone") 31 | int xdp_prog(struct xdp_md *ctx) 32 | { 33 | void *data = (void *)(long)ctx->data; 34 | void *data_end = (void *)(long)ctx->data_end; 35 | 36 | struct ethhdr *eth = data; 37 | 38 | if (eth + 1 > (struct ethhdr *)data_end) 39 | { 40 | return XDP_DROP; 41 | } 42 | 43 | struct iphdr *iph = data + sizeof(struct ethhdr); 44 | 45 | if (iph + 1 > (struct iphdr *)data_end) 46 | { 47 | return XDP_DROP; 48 | } 49 | 50 | if (unlikely(iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)) 51 | { 52 | return XDP_DROP; 53 | } 54 | 55 | uint16_t l4len = 0; 56 | 57 | if (iph->protocol == IPPROTO_TCP) 58 | { 59 | struct tcphdr *tcph = data + sizeof(struct ethhdr) + (iph->ihl * 4); 60 | 61 | if (tcph + 1 > (struct tcphdr *)data_end) 62 | { 63 | return XDP_DROP; 64 | } 65 | 66 | l4len = tcph->doff * 4; 67 | } 68 | else 69 | { 70 | l4len = 8; 71 | } 72 | 73 | uint8_t matched = 1; 74 | uint32_t key = 0; 75 | struct payload *pl = bpf_map_lookup_elem(&payload_map, &key); 76 | 77 | if (pl) 78 | { 79 | for (int i = 0; i < MAX_PAYLOAD_LENGTH; i++) 80 | { 81 | if (i + 1 > pl->length) 82 | { 83 | break; 84 | } 85 | 86 | uint8_t *byte = data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4len + i; 87 | 88 | if (byte + 1 > (uint8_t *)data_end) 89 | { 90 | break; 91 | } 92 | 93 | if (*(byte + i) == pl->payload[i]) 94 | { 95 | continue; 96 | } 97 | 98 | matched = 0; 99 | break; 100 | } 101 | } 102 | 103 | if (matched) 104 | { 105 | printk("Dropping matched packet.\n"); 106 | 107 | return XDP_DROP; 108 | } 109 | 110 | return XDP_PASS; 111 | } 112 | 113 | char _license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /src/xdp_methodthree.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "../libbpf/src/bpf_helpers.h" 12 | #include "helpers.h" 13 | #include "common.h" 14 | 15 | struct bpf_map_def SEC("maps") payload_map = 16 | { 17 | .type = BPF_MAP_TYPE_ARRAY, 18 | .key_size = sizeof(uint8_t), 19 | .value_size = sizeof(uint8_t), 20 | .max_entries = MAX_PAYLOAD_LENGTH 21 | }; 22 | 23 | #define printk(fmt, ...) \ 24 | ({ \ 25 | char ____fmt[] = fmt; \ 26 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 27 | ##__VA_ARGS__); \ 28 | }) 29 | 30 | SEC("xdp_methodtwo") 31 | int xdp_prog(struct xdp_md *ctx) 32 | { 33 | void *data = (void *)(long)ctx->data; 34 | void *data_end = (void *)(long)ctx->data_end; 35 | 36 | struct ethhdr *eth = data; 37 | 38 | if (eth + 1 > (struct ethhdr *)data_end) 39 | { 40 | return XDP_DROP; 41 | } 42 | 43 | struct iphdr *iph = data + sizeof(struct ethhdr); 44 | 45 | if (iph + 1 > (struct iphdr *)data_end) 46 | { 47 | return XDP_DROP; 48 | } 49 | 50 | if (unlikely(iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)) 51 | { 52 | return XDP_DROP; 53 | } 54 | 55 | uint16_t l4len = 0; 56 | 57 | if (iph->protocol == IPPROTO_TCP) 58 | { 59 | struct tcphdr *tcph = data + sizeof(struct ethhdr) + (iph->ihl * 4); 60 | 61 | if (tcph + 1 > (struct tcphdr *)data_end) 62 | { 63 | return XDP_DROP; 64 | } 65 | 66 | l4len = tcph->doff * 4; 67 | } 68 | else 69 | { 70 | l4len = 8; 71 | } 72 | 73 | for (int i = 0; i < MAX_PAYLOAD_LENGTH; i++) 74 | { 75 | uint8_t *byte = data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4len; 76 | 77 | if (!(*(byte + i + 1) > (uint8_t *)data_end)) 78 | { 79 | uint8_t *map = bpf_map_lookup_elem(&payload_map, byte); 80 | 81 | if (map) 82 | { 83 | 84 | } 85 | } 86 | 87 | goto pass; 88 | } 89 | 90 | return XDP_DROP; 91 | 92 | pass: 93 | 94 | return XDP_PASS; 95 | 96 | } 97 | 98 | char _license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /src/xdp_methodtwo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "../libbpf/src/bpf_helpers.h" 12 | #include "helpers.h" 13 | #include "common.h" 14 | 15 | struct bpf_map_def SEC("maps") payload_map = 16 | { 17 | .type = BPF_MAP_TYPE_ARRAY, 18 | .key_size = sizeof(uint32_t), 19 | .value_size = sizeof(struct payload), 20 | .max_entries = 1 21 | }; 22 | 23 | #define printk(fmt, ...) \ 24 | ({ \ 25 | char ____fmt[] = fmt; \ 26 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 27 | ##__VA_ARGS__); \ 28 | }) 29 | 30 | SEC("xdp_methodtwo") 31 | int xdp_prog(struct xdp_md *ctx) 32 | { 33 | void *data = (void *)(long)ctx->data; 34 | void *data_end = (void *)(long)ctx->data_end; 35 | 36 | struct ethhdr *eth = data; 37 | 38 | if (eth + 1 > (struct ethhdr *)data_end) 39 | { 40 | return XDP_DROP; 41 | } 42 | 43 | struct iphdr *iph = data + sizeof(struct ethhdr); 44 | 45 | if (iph + 1 > (struct iphdr *)data_end) 46 | { 47 | return XDP_DROP; 48 | } 49 | 50 | if (unlikely(iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)) 51 | { 52 | return XDP_DROP; 53 | } 54 | 55 | uint16_t l4len = 0; 56 | 57 | if (iph->protocol == IPPROTO_TCP) 58 | { 59 | struct tcphdr *tcph = data + sizeof(struct ethhdr) + (iph->ihl * 4); 60 | 61 | if (tcph + 1 > (struct tcphdr *)data_end) 62 | { 63 | return XDP_DROP; 64 | } 65 | 66 | l4len = tcph->doff * 4; 67 | } 68 | else 69 | { 70 | l4len = 8; 71 | } 72 | 73 | uint32_t key = 0; 74 | struct payload *pl = bpf_map_lookup_elem(&payload_map, &key); 75 | 76 | if (pl) 77 | { 78 | for (int i = 0; i < MAX_PAYLOAD_LENGTH; i++) 79 | { 80 | if (i + 1 > pl->length) 81 | { 82 | break; 83 | } 84 | 85 | uint8_t *byte = data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4len + i; 86 | 87 | if (byte + 1 > (uint8_t *)data_end) 88 | { 89 | break; 90 | } 91 | 92 | if (*(byte + i) == pl->payload[i]) 93 | { 94 | continue; 95 | } 96 | 97 | goto pass; 98 | } 99 | } 100 | 101 | return XDP_DROP; 102 | 103 | pass: 104 | 105 | return XDP_PASS; 106 | } 107 | 108 | char _license[] SEC("license") = "GPL"; -------------------------------------------------------------------------------- /src/xdp_prog.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | 11 | #include "../libbpf/src/bpf_helpers.h" 12 | #include "helpers.h" 13 | #include "common.h" 14 | 15 | struct bpf_map_def SEC("maps") payload_map = 16 | { 17 | .type = BPF_MAP_TYPE_ARRAY, 18 | .key_size = sizeof(uint32_t), 19 | .value_size = sizeof(struct payload), 20 | .max_entries = 1 21 | }; 22 | 23 | #define printk(fmt, ...) \ 24 | ({ \ 25 | char ____fmt[] = fmt; \ 26 | bpf_trace_printk(____fmt, sizeof(____fmt), \ 27 | ##__VA_ARGS__); \ 28 | }) 29 | 30 | SEC("plain") 31 | int xdp_plain(struct xdp_md *ctx) 32 | { 33 | return XDP_PASS; 34 | } 35 | 36 | 37 | SEC("methodone") 38 | int xdp_methodone(struct xdp_md *ctx) 39 | { 40 | void *data = (void *)(long)ctx->data; 41 | void *data_end = (void *)(long)ctx->data_end; 42 | 43 | struct ethhdr *eth = data; 44 | 45 | if (eth + 1 > (struct ethhdr *)data_end) 46 | { 47 | return XDP_DROP; 48 | } 49 | 50 | struct iphdr *iph = data + sizeof(struct ethhdr); 51 | 52 | if (iph + 1 > (struct iphdr *)data_end) 53 | { 54 | return XDP_DROP; 55 | } 56 | 57 | if (unlikely(iph->protocol != IPPROTO_TCP && iph->protocol != IPPROTO_UDP)) 58 | { 59 | return XDP_DROP; 60 | } 61 | 62 | uint16_t l4len = 0; 63 | 64 | if (iph->protocol == IPPROTO_TCP) 65 | { 66 | struct tcphdr *tcph = data + sizeof(struct ethhdr) + (iph->ihl * 4); 67 | 68 | if (tcph + 1 > (struct tcphdr *)data_end) 69 | { 70 | return XDP_DROP; 71 | } 72 | 73 | l4len = tcph->doff * 4; 74 | } 75 | else 76 | { 77 | l4len = 8; 78 | } 79 | 80 | uint8_t matched = 1; 81 | uint32_t key = 0; 82 | struct payload *pl = bpf_map_lookup_elem(&payload_map, &key); 83 | 84 | if (pl) 85 | { 86 | for (int i = 0; i < MAX_PAYLOAD_LENGTH; i++) 87 | { 88 | if (i + 1 > pl->length) 89 | { 90 | break; 91 | } 92 | 93 | uint8_t *byte = data + sizeof(struct ethhdr) + (iph->ihl * 4) + l4len + i; 94 | 95 | if (byte + 1 > (uint8_t *)data_end) 96 | { 97 | break; 98 | } 99 | 100 | if (*(byte + i) == pl->payload[i]) 101 | { 102 | continue; 103 | } 104 | 105 | matched = 0; 106 | break; 107 | } 108 | } 109 | 110 | if (matched) 111 | { 112 | printk("Dropping matched packet.\n"); 113 | 114 | return XDP_DROP; 115 | } 116 | 117 | return XDP_PASS; 118 | } 119 | 120 | char _license[] SEC("license") = "GPL"; --------------------------------------------------------------------------------