diff --git a/README.md b/README.md index 8964a55..46dc6ef 100644 --- a/README.md +++ b/README.md @@ -6,14 +6,12 @@ **FlowSentryX** is an open-source XDP-based fast packet processing DOS and DDOS Mitigation Framework solution designed to protect your network infrastructure from Denial of Service (DOS) and Distributed Denial of Service (DDOS) attacks at Layer 3 & 4. -> Current work is being done for Layer 3 based DOS and DDOS mitigation. +Current work is being done for Layer 3 based DOS and DDOS mitigation. The framework is a collection of XDP programs which track your network traffic and parse packets till the IP layer and make the descision to drop packets from malicious IP addresses using different algorithms and models for DOS and DDOS mitigation. We also plan to extend the ability BlackList IP addresses and write rules manually from the user space to block certain packets. The rules will be written in the config file which will be read by the xdp program and action will be taken accordingly, hence extending the framework to act as a _Basic Firewall_. -> Refine this text , use better words like packet inspection and filtering, Logging etc. - ## Table of Contents @@ -61,38 +59,25 @@ This framework is a set of [xdp](https://www.iovisor.org/technology/xdp) program The XDP programs parse all the packets in the ingress network traffic till the IP layer and make the descision to drop packets from malicious IP addresses using some Rate Limiting Algorithms like token bucket algorithm, fixed window algorithm and sliding window algorithm for DOS attack mitigation and using the features extracted from the packets and passing them to a trained ML model in the user space for inference of deciding whether that particular IP was involved in the DDOS attack. -> Explain why XDP is faster and why we plan to use it. - -> Describe the project in a little bit more detail and refine this. ### Why DOS/DDOS Mitigation? DOS and DDOS attacks can disrupt your network, causing downtime and financial losses. Our framework helps you safeguard your infrastructure by efficiently filtering malicious traffic, ensuring your network remains operational. - > Write about different Attach here the content from cloudfare blog - Ping of Death - Flood Attacks - Buffer overflow Attacks - > Also Write in detail about DDOS attack - ### Basic Firewall -> Fill this section with how we plan to extend our project to a stateless Firewall with Dynamic DOS and DDOS mitigation abilities. - We plan to extend the framework to an XDP based stateless Firewall, by allowing config files where the user can manually configure parameters such as the Threshold values and the time duration for black listing the IP address for the already existing features. We also plan to add Dynamic Rule Management to Manage dynamic rules and configurations, such as adding or removing IP addresses from the blocklist. This component can communicate with the kernel space to apply or remove rules as needed. Also we plan to add config files which can be used to blacklist user configured IP's and rules to drop certain packets. -> Need a better description for the above - ## Installation and Usage **Note**: This section is under development. -> Add Link to the Dependencies.md page and also like a checklist version of required features - - This section will provide clear instructions on how to install and run the framework. We'll include details on dependencies, installation commands, and sample usage commands. A setup script will be provided to simplify the installation process. ### Prerequisites @@ -116,11 +101,18 @@ Refer to [Dependencies](Dependencies.md). ### Installation -To install the framework, follow these steps: - -1. Step-by-step installation instructions. -2. Include any scripts or commands necessary for setup. -3. Submodules - Installation +To install the framework on Debian/Ubuntu, follow these steps: + +1. Clone the repo using the following command: +``` +git clone --recurse-submodules https://github.com/MeherRushi/FlowSentryX.git +``` +2. Then, type the following command to go into the repo and install all the dependencies required: +``` +cd FlowSentryX +chmod +x ./install_dependencies.sh +./install_dependencies.sh +``` ### Usage Provide guidance on how to use the framework: @@ -146,7 +138,6 @@ The XDP-based DOS and DDOS Mitigation Framework operates at the network level to - The plan is to create 2 Maps - Rate of Packet Arrival(per sec) per IP, and a normal Black listed IP table. - The packet arrival per IP per sec table is going to be updated with the count of the packet and then we need to refresh the table every one second for now - The algorithm that is going to be used is the simple Fixed window algorithm. - We pick the blacklisted to the BlackList IP table and drop the packets for that particular IP. - - _I think that is it_ - **User Space Program** : - _Clear the BlackList IP table_ - @@ -157,10 +148,6 @@ The XDP-based DOS and DDOS Mitigation Framework operates at the network level to - **eBPF Maps and Datastructures** - We are planning to use BPF_HASH_ARRAY_TYPE map for storing the IP address and the Packet Per second - - - - -> Need a way better description for the above ## Rate Limiting Algorithms @@ -176,7 +163,7 @@ We plan to implement a static window rate limiting algorithm. This algorithm tra ## References -- [Learning eBPF and XDP Repository](https://example.com/learning-ebpf-xdp): This repository provided valuable insights into the technologies used in this project. +- [Learning eBPF and XDP Repository](https://github.com/lizrice/learning-ebpf): This repository provided valuable insights into the technologies used in this project. References and Literature Survey @@ -225,7 +212,7 @@ Some other resources 30) Hooking : https://en.wikipedia.org/wiki/Hooking 31) eBPF.io : https://ebpf.io/what-is-ebpf/#development-toolchains -References from others (Didn't go through them) +References from others: 32) https://www.youtube.com/watch?v=iBkR4gvjxtE 33) https://blog.yadutaf.fr/2017/07/28/tracing-a-packet-journey-using-linux-tracepoints-perf-ebpf/ @@ -272,7 +259,6 @@ Rate Limiting Blogs: 54) [token bucket, fixed and sliding window ](https://dev.to/satrobit/rate-limiting-using-the-token-bucket-algorithm-3cjh) -> Need to reorder and neatly write it ## Project Status This project is currently in the development phase. We are actively working on building the framework and welcome contributions from the open-source community. diff --git a/TODO.md b/TODO.md index 3fc435a..e48a8fb 100644 --- a/TODO.md +++ b/TODO.md @@ -106,10 +106,28 @@ For now we are doing layer 3 based DOS mitigation _Dynamic Rules Management_: You can create a user space component that communicates with the kernel space to add or remove IP addresses from the blocklist dynamically. +ToDo List: + + - [ ] Integrating the in-kernel ml model + + - [ ] Refine Readme text, use better words like packet inspection and filtering, Logging etc. -Integrating the in-kernel ml model - - + - [ ] Explain why XDP is faster and why we plan to use it. + + - [ ] Describe the project in a little bit more detail and refine this. + + - [ ] Write about different Attach here the content from cloudfare blog + + - [ ] Also Write in detail about DDOS attack + + - [ ] Fill this section with how we plan to extend our project to a stateless Firewall with Dynamic DOS and DDOS mitigation abilities. + + - [ ] Add Link to the Dependencies.md page and also like a checklist version of required features + + - [ ] Need a way better description for the System Architechture section + + + diff --git a/install_dependencies.sh b/install_dependencies.sh new file mode 100755 index 0000000..50887f3 --- /dev/null +++ b/install_dependencies.sh @@ -0,0 +1,14 @@ +sudo apt install clang llvm libelf-dev libpcap-dev build-essential libc6-dev-i386 m4 +sudo apt install linux-headers-$(uname -r) +sudo apt install linux-tools-$(uname -r) +sudo apt install linux-tools-common linux-tools-generic +sudo apt install tcpdump + +cd modules/xdp-tools +./configure +make +make install +cd ../../ +cd src +make +cd .. \ No newline at end of file diff --git a/src/Makefile b/src/Makefile index bf75626..f9a7f8f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -2,6 +2,7 @@ TARGETS = fsx HEADERS = fsx_struct.h parsing_helper.h INCLUDE_DIRS = -I/usr/include/$(shell uname -m)-linux-gnu -I . +IFACE = lo all: $(TARGETS) .PHONY: all @@ -19,4 +20,15 @@ $(TARGETS): % : %_kern.o clean: - rm *.o - - rm -f /sys/fs/bpf/$(TARGETS) \ No newline at end of file + - rm -f /sys/fs/bpf/$(TARGETS) + + +load: fsx_kern.o + sudo ip link set dev $(IFACE) xdp obj fsx_kern.o section xdp + sudo mkdir -p /sys/fs/bpf + sudo mount -t bpf none /sys/fs/bpf +#pin any maps here + +detach: + sudo ip link set dev $(IFACE) xdp off +#remove the pinned maps here \ No newline at end of file diff --git a/src/fsx_kern.c b/src/fsx_kern.c index 2cd645c..b86559d 100644 --- a/src/fsx_kern.c +++ b/src/fsx_kern.c @@ -13,6 +13,18 @@ in the fsx_struct.h map */ #include "fsx_struct.h" #include "parsing_helper.h" + +#define SIZEOFPORTS_RST 65536 //number of ports +#define TIMEOUT_RST 1000000000 //1 sec +#define THRESHOLD_RST 100 //limit on number of packets to be configurable later +#define LIMIT_SYN 100 //limit on number of packets to be configurable later +#define EXTRA_TIME_SYN 1000000000 //1 sec +#define ICMP_MAX_PACKET_SIZE 1000 // not sure about a good limit, can modify it later +#define UDP_MAX_PACKET_RATE 100 +#define ICMP_INTERVAL_NS 1000000000 // 1 second +#define UDP_THRESHOLD_PACKETS 100 // Maximum packets per interval for a single port +#define UDP_TIME_WINDOW 1000000000 // 1 second + #ifndef memcpy #define memcpy(dest, src, n) __builtin_memcpy((dest), (src), (n)) #endif @@ -93,6 +105,41 @@ struct __type(value, __u64); } ipv6_blacklist_map SEC(".maps"); +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, 2); + __type(key, __u32); + __type(value, __u64); +} tcp_syn_size_oldtime SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_LRU_HASH); + __uint(max_entries, 1000); + __type(key, struct tcp_syn_packet_id_key); + __type(value, __u64); +} tcp_syn_lru_hash_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_ARRAY); + __uint(max_entries, SIZEOFPORTS_RST); + __type(key, __u32); + __type(value, struct tcp_rst_port_node); +} tcp_rst_port SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __type(key, __u16); + __type(value, struct udp_port_stat); + __uint(max_entries, 65536); +} udp_port_counters_map SEC(".maps"); + +struct { + __uint(type, BPF_MAP_TYPE_HASH); + __uint(max_entries, 1); + __type(key, __u32); + __type(value, struct icmp_rate_limit_data); +} icmp_rate_limit_map SEC(".maps"); + SEC("xdp") int fsx(struct xdp_md *ctx) { @@ -343,6 +390,221 @@ int fsx(struct xdp_md *ctx) bpf_printk("No of packets allowed %llu\n", stats->allowed); } + struct tcphdr *tcp=NULL; + struct udphdr *udp = NULL; + struct icmphdr *icmp = NULL; + + __u32 zero = 0,one = 1; + struct tcp_syn_packet_id_key packet_key; + __u32 application_layer_type = 0; //1 for tcp, 2 for udp, 3 for icmp + if(ip4hdr){ + packet_key.ip_type = 1; + packet_key.ipadd.ipv4 = ip4hdr->saddr; + if (ip4hdr->protocol == IPPROTO_TCP) { + tcp = (void *)((unsigned char *)ip4hdr + (ip4hdr->ihl * 4)); + application_layer_type = 1; + if ((void *)(tcp + 1) > data_end){ + return XDP_PASS; + } + } + else if(ip4hdr->protocol == IPPROTO_UDP){ + udp = (void*)(unsigned char *)ip4hdr + (ip4hdr->ihl * 4); + application_layer_type = 2; + if ((void *)(udp + 1) > data_end) { + return XDP_PASS; + } + } + else if(ip4hdr->protocol == IPPROTO_ICMP) { + icmp = (void *)((unsigned char *)ip4hdr + (ip4hdr->ihl * 4)); + application_layer_type = 3; + if ((void *)(icmp + 1) > data_end) { + return XDP_PASS; + } + } + } + else if(ip6hdr){ + packet_key.ip_type = 2; + __builtin_memcpy(&packet_key.ipadd.ipv6, &ip6hdr->saddr, sizeof(struct in6_addr)); + if (ip6hdr->nexthdr == IPPROTO_TCP){ + tcp = (void *)((unsigned char *)ip6hdr + 1); + application_layer_type = 1; + if ((void *)(tcp + 1) > data_end){ + return XDP_PASS; + } + } + else if(ip6hdr->nexthdr == IPPROTO_UDP){ + udp = (void *)((unsigned char *)ip6hdr + 1); + application_layer_type = 2; + if ((void *)(udp + 1) > data_end){ + return XDP_PASS; + } + } + // icmpv6 here + } + + if(application_layer_type==1 && tcp!=NULL){ + return XDP_PASS; + } + else if(application_layer_type==1 && tcp){ + packet_key.dest = tcp->dest; + packet_key.source = tcp->source; + __u64 *size_allowed,*old_time; + __u32 dest = tcp->dest; + size_allowed = bpf_map_lookup_elem(&tcp_syn_size_oldtime,&zero); + old_time = bpf_map_lookup_elem(&tcp_syn_size_oldtime,&one); + if(!size_allowed || !old_time){ + return XDP_PASS; + } + if(!(tcp->fin || + tcp->psh || + tcp->urg || + tcp->ece || + tcp->cwr || + tcp->rst )){ + if (tcp->syn && !tcp->ack) { + __u64 curr_time = bpf_ktime_get_ns(); + //check if time is greater than old time + extra + if(*old_time + EXTRA_TIME_SYN < curr_time){ + // if yes update old time and make size as 1 + *size_allowed = 1; + *old_time = curr_time; + bpf_map_update_elem(&tcp_syn_lru_hash_map,&packet_key,&curr_time,BPF_ANY); + bpf_printk("Passed"); + return XDP_PASS; + } + else{ + // else check size == limit + if(*size_allowed == LIMIT_SYN){ + // if yes DROP + bpf_printk("Dropped"); + return XDP_DROP; + } + else{ + //else update size and insert into hash and PASS + *size_allowed += 1; + bpf_map_update_elem(&tcp_syn_lru_hash_map,&packet_key,&curr_time,BPF_ANY); + bpf_printk("Passed"); + return XDP_PASS; + } + } + } + if (tcp->syn && tcp->ack) { + bpf_printk("TCP SYN-ACK packet detected!\n"); + return XDP_PASS; + } + if (!tcp->syn && tcp->ack) { + //check if element is present + __u64 *packet_time = bpf_map_lookup_elem(&tcp_syn_lru_hash_map,&packet_key); + if(!packet_time){ + // if yes check time is in range + if(*packet_time < *old_time + EXTRA_TIME_SYN){ + //size =-1 remove from map and PASS + *size_allowed -= 1; + bpf_map_delete_elem(&tcp_syn_lru_hash_map,&packet_key); + return XDP_PASS; + } + else{ + //PASS + return XDP_PASS; + } + } + else{ + // PASS + return XDP_PASS; + } + } + } + else if(tcp->rst){ + struct tcp_rst_port_node *node = bpf_map_lookup_elem(&tcp_rst_port,&dest); + if(!node){ + return XDP_PASS; + } + __u64 curr_time = bpf_ktime_get_ns(); + bpf_spin_lock(&node->semaphore); + if(node->port_time + TIMEOUT_RST < curr_time){ + node->port_time = curr_time; + node->rst_cnt = 1; + bpf_spin_unlock(&node->semaphore); + bpf_printk("Passed"); + return XDP_PASS; + } + else{ + if(node->rst_cntrst_cnt++; + bpf_spin_unlock(&node->semaphore); + bpf_printk("Passed"); + return XDP_PASS; + } + else{ + bpf_spin_unlock(&node->semaphore); + bpf_printk("Dropped"); + return XDP_DROP; + } + } + } + return XDP_PASS; + } + if(application_layer_type == 2 && udp){ + __u16 dest_port = 0; + dest_port = bpf_ntohs(udp->dest); + struct udp_port_stat *stat = bpf_map_lookup_elem(&udp_port_counters_map, &dest_port); + __u64 now = bpf_ktime_get_ns(); + + if (stat) { + if (now - (stat->last_check) < UDP_TIME_WINDOW) { + stat->packet_count += 1; + + // If packet count exceeds threshold, drop packet + if (stat->packet_count > UDP_THRESHOLD_PACKETS) { + bpf_printk("Dropping UDP packet to port %d due to flood\n", dest_port); + return XDP_DROP; + } + } else { + stat->packet_count = 1; + stat->last_check = now; + } + bpf_map_update_elem(&udp_port_counters_map, &dest_port, stat, BPF_ANY); + } else { + struct udp_port_stat new_stat = {}; + new_stat.packet_count = 1; + new_stat.last_check = now; + bpf_map_update_elem(&udp_port_counters_map, &dest_port, &new_stat, BPF_ANY); + } + } + if(application_layer_type == 3 && icmp){ + if (icmp->type == 8) { // 8 == icmp echo request packets + int packet_size = data_end - data; + + if (packet_size > ICMP_MAX_PACKET_SIZE) { + return XDP_DROP; + } + __u32 key = 0; + struct icmp_rate_limit_data *rate_data = bpf_map_lookup_elem(&icmp_rate_limit_map, &key); + __u64 now = bpf_ktime_get_ns(); + + if (rate_data) { + __u64 elapsed = now - rate_data->last_reset_time; + + if (elapsed >= ICMP_INTERVAL_NS) { // if too much time has passed since the first packet arrival time. + rate_data->packet_count = 1; + rate_data->last_reset_time = now; + } else { + if (rate_data->packet_count >= UDP_MAX_PACKET_RATE) { + return XDP_DROP; + } + rate_data->packet_count++; + } + bpf_map_update_elem(&icmp_rate_limit_map, &key, rate_data, BPF_ANY); + } else { + struct icmp_rate_limit_data new_data = { + .last_reset_time = now, + .packet_count = 1 + }; + bpf_map_update_elem(&icmp_rate_limit_map, &key, &new_data, BPF_ANY); + } + } + } + return XDP_PASS; } diff --git a/src/fsx_kern.o b/src/fsx_kern.o index d601259..49ba1da 100644 Binary files a/src/fsx_kern.o and b/src/fsx_kern.o differ diff --git a/src/fsx_struct.h b/src/fsx_struct.h index 8de915e..30b7255 100644 --- a/src/fsx_struct.h +++ b/src/fsx_struct.h @@ -21,5 +21,40 @@ struct ip_stats __u64 track_time; // time at which the packet arrived }; +struct tcp_rst_port_node{ + __u64 port_time; + __u32 rst_cnt; + struct bpf_spin_lock semaphore; +}; + +struct tcp_syn__u128 { + __u64 hi; // Higher 64 bits for IPv6 + __u64 lo; // Lower 64 bits for IPv6 +}; + +union tcp_syn_ip_address { + __u32 ipv4; // 32-bit IPv4 address + struct tcp_syn__u128 ipv6; // 128-bit IPv6 address +}; + +struct tcp_syn_packet_id_key{ + union tcp_syn_ip_address ipadd; // IPv4 or IPv6 + __u16 dest; + __u16 source; + __u8 ip_type; +}; +struct Semp{ + struct bpf_spin_lock semaphore; +}; + +struct icmp_rate_limit_data { + __u64 last_reset_time; + __u32 packet_count; +}; + +struct udp_port_stat { + __u32 packet_count; + __u64 last_check; +}; #endif \ No newline at end of file