1#!/usr/bin/python 2# 3# dddos.py DDOS dectection system. 4# 5# Written as a basic tracing example of using ePBF 6# to detect a potential DDOS attack against a system. 7# 8# Copyright (c) 2019 Jugurtha BELKALEM. 9# Licensed under the Apache License, Version 2.0 (the "License") 10# 11# 14-Jan-2019 Jugurtha BELKALEM Created this. 12 13from bcc import BPF 14import ctypes as ct 15import datetime 16prog = """ 17#include <linux/skbuff.h> 18#include <uapi/linux/ip.h> 19 20#define MAX_NB_PACKETS 1000 21#define LEGAL_DIFF_TIMESTAMP_PACKETS 1000000 22 23BPF_HASH(rcv_packets); 24 25struct detectionPackets { 26 u64 nb_ddos_packets; 27}; 28 29BPF_PERF_OUTPUT(events); 30 31int detect_ddos(struct pt_regs *ctx, void *skb){ 32 struct detectionPackets detectionPacket = {}; 33 34 // Used to count number of received packets 35 u64 rcv_packets_nb_index = 0, rcv_packets_nb_inter=1, *rcv_packets_nb_ptr; 36 37 // Used to measure elapsed time between 2 successive received packets 38 u64 rcv_packets_ts_index = 1, rcv_packets_ts_inter=0, *rcv_packets_ts_ptr; 39 40 /* The algorithm analyses packets received by ip_rcv function 41 * and measures the difference in reception time between each packet. 42 * DDOS flooders send millions of packets such that difference of 43 * timestamp between 2 successive packets is so small 44 * (which is not like regular applications behaviour). 45 * This script looks for this difference in time and if it sees 46 * more than MAX_NB_PACKETS successive packets with a difference 47 * of timestamp between each one of them less than 48 * LEGAL_DIFF_TIMESTAMP_PACKETS ns, 49 * ------------------ It Triggers an ALERT ----------------- 50 * Those settings must be adapted depending on regular network traffic 51 * ------------------------------------------------------------------- 52 * Important: this is a rudimentary intrusion detection system, one can 53 * test a real case attack using hping3. However; if regular network 54 * traffic increases above predefined detection settings, a false 55 * positive alert will be triggered (an example would be the 56 * case of large file downloads). 57 */ 58 rcv_packets_nb_ptr = rcv_packets.lookup(&rcv_packets_nb_index); 59 rcv_packets_ts_ptr = rcv_packets.lookup(&rcv_packets_ts_index); 60 if(rcv_packets_nb_ptr != 0 && rcv_packets_ts_ptr != 0){ 61 rcv_packets_nb_inter = *rcv_packets_nb_ptr; 62 rcv_packets_ts_inter = bpf_ktime_get_ns() - *rcv_packets_ts_ptr; 63 if(rcv_packets_ts_inter < LEGAL_DIFF_TIMESTAMP_PACKETS){ 64 rcv_packets_nb_inter++; 65 } else { 66 rcv_packets_nb_inter = 0; 67 } 68 if(rcv_packets_nb_inter > MAX_NB_PACKETS){ 69 detectionPacket.nb_ddos_packets = rcv_packets_nb_inter; 70 events.perf_submit(ctx, &detectionPacket, sizeof(detectionPacket)); 71 } 72 } 73 rcv_packets_ts_inter = bpf_ktime_get_ns(); 74 rcv_packets.update(&rcv_packets_nb_index, &rcv_packets_nb_inter); 75 rcv_packets.update(&rcv_packets_ts_index, &rcv_packets_ts_inter); 76 return 0; 77} 78""" 79 80# Loads eBPF program 81b = BPF(text=prog) 82 83# Attach kprobe to kernel function and sets detect_ddos as kprobe handler 84b.attach_kprobe(event="ip_rcv", fn_name="detect_ddos") 85 86class DetectionTimestamp(ct.Structure): 87 _fields_ = [("nb_ddos_packets", ct.c_ulonglong)] 88 89# Show message when ePBF starts 90print("DDOS detector started ... Hit Ctrl-C to end!") 91 92print("%-26s %-10s" % ("TIME(s)", "MESSAGE")) 93 94def trigger_alert_event(cpu, data, size): 95 event = ct.cast(data, ct.POINTER(DetectionTimestamp)).contents 96 print("%-26s %s %ld" % (datetime.datetime.now(), 97 "DDOS Attack => nb of packets up to now : ", event.nb_ddos_packets)) 98 99# loop with callback to trigger_alert_event 100b["events"].open_perf_buffer(trigger_alert_event) 101while 1: 102 try: 103 b.perf_buffer_poll() 104 except KeyboardInterrupt: 105 exit() 106