xref: /aosp_15_r20/external/bcc/examples/tracing/dddos.py (revision 387f9dfdfa2baef462e92476d413c7bc2470293e)
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