Last active
May 7, 2017 07:19
-
-
Save yjuba/b4d0cf3396941bbb4338f9bd04e098ef to your computer and use it in GitHub Desktop.
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
#define KBUILD_MODNAME "drop_80" | |
#include <uapi/linux/bpf.h> | |
#include <linux/in.h> | |
#include <linux/if_ether.h> | |
#include <linux/if_packet.h> | |
#include <linux/if_vlan.h> | |
#include <linux/ip.h> | |
#include <linux/ipv6.h> | |
BPF_HASH(counter, uint32_t, long); | |
static inline int tcp_dest_port(void *data, u64 nh_off, void *data_end) { | |
struct tcphdr *tcph = data + nh_off; | |
if (data + nh_off + sizeof(struct tcphdr) > data_end) { | |
return 0; | |
} | |
return tcph->dest; | |
} | |
static inline int parse_ipv4(void *data, u64 nh_off, void *data_end) { | |
struct iphdr *iph = data + nh_off; | |
if ((void*)&iph[1] > data_end) { | |
return 0; | |
} | |
return iph->protocol; | |
} | |
static inline int parse_ipv6(void *data, u64 nh_off, void *data_end) { | |
struct ipv6hdr *ip6h = data + nh_off; | |
if ((void*)&ip6h[1] > data_end) { | |
return 0; | |
} | |
return ip6h->nexthdr; | |
} | |
int drop_80(struct xdp_md *ctx) { | |
void* data_end = (void*)(long)ctx->data_end; | |
void* data = (void*)(long)ctx->data; | |
struct ethhdr *eth = data; | |
long *value; | |
long zero = 0; | |
uint16_t h_proto; | |
uint64_t nh_off = 0; | |
uint16_t dest_port; | |
uint32_t index; | |
nh_off = sizeof(*eth); | |
if (data + nh_off > data_end) { | |
return XDP_PASS; | |
} | |
h_proto = eth->h_proto; | |
if (h_proto == htons(ETH_P_8021Q) || h_proto == 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 == htons(ETH_P_8021Q) || h_proto == 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 == htons(ETH_P_IP)) { | |
h_proto = parse_ipv4(data, nh_off, data_end); | |
nh_off += sizeof(struct iphdr); | |
} else if (h_proto == htons(ETH_P_IPV6)) { | |
h_proto = parse_ipv6(data, nh_off, data_end); | |
nh_off += sizeof(struct ipv6hdr); | |
} else { | |
return XDP_PASS; | |
} | |
if (h_proto == IPPROTO_TCP) { | |
dest_port = ntohs(tcp_dest_port(data, nh_off, data_end)); | |
if (dest_port == 80) { | |
index = (uint32_t)dest_port; | |
value = counter.lookup_or_init(&index, &zero); | |
(*value) += 1; | |
return XDP_DROP; | |
} | |
} | |
return XDP_PASS; | |
} |
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
#!/usr/bin/env python | |
from bcc import BPF, libbcc | |
import ctypes | |
import time | |
def load_xdp(source_path, func_name, device): | |
bpf = BPF(src_file=source_path) | |
func = bpf.load_func(func_name, BPF.XDP) | |
bpf.attach_xdp(device, func) | |
return bpf | |
def drop_packet(device, pin_path): | |
bpf = load_xdp("./drop_80.c", "drop_80", device) | |
print("XDP loaded.") | |
counter = bpf.get_table("counter") | |
ret = libbcc.lib.bpf_obj_pin(counter.map_fd, ctypes.c_char_p(pin_path)) | |
old_val = {} | |
while True: | |
try: | |
for k, v in counter.items(): | |
if k.value not in old_val or old_val[k.value] != v.value: | |
print("Port:{}\tCount:{}".format(k.value, v.value)) | |
old_val[k.value] = v.value | |
time.sleep(1) | |
except KeyboardInterrupt: | |
break; | |
bpf.remove_xdp(device) | |
if __name__ == '__main__': | |
import sys | |
if len(sys.argv) < 3: | |
print("Usage: {} <DEVICE> <PIN_PATH>".format(sys.argv[0])) | |
exit(1) | |
drop_packet(sys.argv[1], sys.argv[2]) |
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
#!/usr/bin/python | |
from bcc import libbcc, table | |
import ctypes | |
import sys | |
class DropHash(table.HashTable): | |
def __init__(self, path, keytype, leaftype): | |
fd = libbcc.lib.bpf_obj_get(ctypes.c_char_p(path)) | |
if fd < 0: | |
raise ValueError("Failed to open eBPF map") | |
self.map_fd = fd | |
self.Key = keytype | |
self.Leaf = leaftype | |
def fetch_counter(path): | |
return DropHash(path, ctypes.c_uint32, ctypes.c_long) | |
if __name__ == '__main__': | |
import sys | |
if len(sys.argv) < 2: | |
print("Usage: {} <PIN_PATH>".format(sys.argv[0])) | |
exit(1) | |
for k, v in fetch_counter(sys.argv[1]).items(): | |
print("Port:{}\tCount:{}".format(k.value, v.value)) |
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
.PHONY: help | |
.DEFAULT_GOAL := help | |
bpf_path = /sys/fs/bpf | |
counter_path = /sys/fs/bpf/counter | |
interface = ens3 | |
mount-bpf: ## Mount /sys/fs/bpf | |
@sudo mount -t bpf bpf $(bpf_path) | |
exec-drop80: ## Execute drop_80 module | |
@sudo python ./drop_80.py $(interface) $(counter_path) | |
fetch-counter: ## Fetch drop_80 counter | |
@sudo python ./fetch_counter.py $(counter_path) | |
cleanup: ## Unlink /sys/fs/bpf/counter and remove xdp module | |
@sudo unlink $(counter_path) | |
@sudo /sbin/ip link set dev $(interface) xdp off | |
help: | |
@grep -E '^[a-zA-Z0-9_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "\033[36m%-30s\033[0m %s\n", $$1, $$2}' |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment