dpdk添加ddos攻击检测

ddos是一种攻击,不断给服务器发送不必要的命令,增加服务器的负担。

常规做法是把连接使用hash记录下来,key是ip和port,value就是连接的请求数量,统计连接请求的频率,如果超过阈值就视为ddos攻击。

比如大量发送三次握手中的第一次握手,不进行后续第二三次握手。

那么有没有一种办法可以在不解析ip地址的情况下,处理这种ddos攻击。

先统计一个包的二进制表达式里面有多少个1,再统计整个包的bit数量。

再计算两者的复杂度。

统计每个包的复杂度,把所有包的复杂度加在一起。

与 全部包的复杂度进行比较,如果超过阈值就视为ddos攻击。

在检测的时候需要使用边沿检测,不是水平检测。

如果是水平触发,一旦有攻击就会一直触发警告,我们需要的是从正常到攻击这个状态转变才会触发警告。

如果使用for循环每个if判断,然后移位,时间复杂度是O(n)。

这里采用另外一种计算bit中1数量的算法,count_bit 的 SWAR 是 O(log n)。

复制代码
/*
原始数据
V1 = 0x00000000000000F0
每2位1组中1的个数
V2 = 0x00000000000000A0
每4位1组中1的个数
V3 = 0x0000000000000040
每8位1组中1的个数
V4 = 0x0000000000000004


F0 = 11110000
两位一组,分为四组
11  11  00  00
每一组,1的个数
10  10  00  00
就是A0

四位一组,分为两组
1111  0000
每一组,1的个数
0100  0000
就是40

*/
static uint64_t count_bit(uint8_t *msg, const uint32_t length){

	uint64_t v, set_bits = 0;
   	const uint64_t *ptr = (uint64_t *) msg;
   	const uint64_t *end = (uint64_t *) (msg + length);
   	
	do {
    // v1 原始数据
    v = *(ptr++);
    // v2 每2位1组中1的个数
    v = v - ((v >> 1) & 0x5555555555555555);  // reuse input as temporary
    // v3 每4位1组中1的个数
    v = (v & 0x3333333333333333) + ((v >> 2) & 0x3333333333333333); // temp
    // v4 每8位1组中1的个数
    v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0F;
    // 每64位1组中1的个数    
    // *有优先级高于>> ,  (sizeof(v) - 1) * 8 = 56
    set_bits += (v * 0x0101010101010101) >> (sizeof(v) - 1) * 8; // count

    } while(end > ptr);

	return set_bits;
}

tcp

hping3 -c 1200 -d 130 -S -W 64 -p 8899 --flood --rand-source 192.168.222.134

-c 数据包数量

-d 单个数据包大小

-S TCP SYN标记

-W tcp窗口大小

-p 目标port

--flood 泛洪模式,以最快速度发包,不等回复

--rand-source 随机伪造源ip

sudo hping3 -c 1200 -d 130 -S -p 8899 --flood 192.168.222.134


还可以通过TCP标记位的计数来判断,如果syn的比例远大于ack的比例,则视为攻击。


如果先启动22.134的程序,然后启动hping3,就检测不到。如果先启动hping3,再启动222.134程序,就可以检测到

复制代码
#include "ddos_w.h"
#include <math.h>



/*
二值商
H = -p*log2(p) - (1-p)*log2(1-p)
*/
static double ddos_entropy(double set_bits,double total_bits)
{
    return (-set_bits)*(log2(set_bits) - log2(total_bits))
    - (total_bits - set_bits) * (log2(total_bits - set_bits) - log2(total_bits))
    + log2(total_bits);
}
/*
原始数据
V1 = 0x00000000000000F0
每2位1组中1的个数
V2 = 0x00000000000000A0
每4位1组中1的个数
V3 = 0x0000000000000040
每8位1组中1的个数
V4 = 0x0000000000000004


F0 = 11110000
两位一组,分为四组
11  11  00  00
每一组,1的个数
10  10  00  00
就是A0

四位一组,分为两组
1111  0000
每一组,1的个数
0100  0000
就是40

*/
static uint64_t count_bit(uint8_t *msg, const uint32_t length){

	uint64_t v, set_bits = 0;
   	const uint64_t *ptr = (uint64_t *) msg;
   	const uint64_t *end = (uint64_t *) (msg + length);
   	
	do {
    // v1 原始数据
    v = *(ptr++);
    // v2 每2位1组中1的个数
    v = v - ((v >> 1) & 0x5555555555555555);  // reuse input as temporary
    // v3 每4位1组中1的个数
    v = (v & 0x3333333333333333) + ((v >> 2) & 0x3333333333333333); // temp
    // v4 每8位1组中1的个数
    v = (v + (v >> 4)) & 0x0F0F0F0F0F0F0F0F;
    // 每64位1组中1的个数    
    // *有优先级高于>> ,  (sizeof(v) - 1) * 8 = 56
    set_bits += (v * 0x0101010101010101) >> (sizeof(v) - 1) * 8; // count

    } while(end > ptr);

	return set_bits;
}

#define CAPTURE_WINDOWS		256

static double tresh = 1200.0;

static uint32_t p_setbits[CAPTURE_WINDOWS] = {0};
static uint32_t p_totbits[CAPTURE_WINDOWS] = {0};
static double p_entropy[CAPTURE_WINDOWS] = {0};
static int pkt_idx = 0;

// 滑动窗口(环形覆盖)  熵检测
int ddos_detect(struct rte_mbuf *pkt){
    static char flag = 0; // 1:ddos   0:正常
    uint8_t *msg = rte_pktmbuf_mtod(pkt, uint8_t * );
    uint32_t set_bits = count_bit(msg,pkt->buf_len);
    uint32_t tot_bits = pkt->buf_len * 8;

	p_setbits[pkt_idx % CAPTURE_WINDOWS] = set_bits;
	p_totbits[pkt_idx % CAPTURE_WINDOWS] = tot_bits;
	p_entropy[pkt_idx % CAPTURE_WINDOWS] = ddos_entropy(set_bits, tot_bits);

    if(pkt_idx >= CAPTURE_WINDOWS) // 窗口已满,检测
    {
        static int i =0;
        uint32_t total_set = 0;
        uint32_t total_bit = 0;
        double sum_entropy = 0.0;

        for(i = 0;i<CAPTURE_WINDOWS;i++){
            total_set += p_setbits[i];
            total_bit += p_totbits[i];
            sum_entropy += p_entropy[i];
        }
        // 计算所有数据包的熵
        double entropy = ddos_entropy(total_set,total_bit);
        printf("%u/%u sum_entropy(%f), entropy(%f)\n", total_set, total_bit, sum_entropy, entropy);
        printf("tresh=%f sum_entropy-entropy=%f\n",tresh,sum_entropy - entropy);
        // 正常流量各包熵之和应接近"合并熵 × 包数";
        // 若合并熵远小于各包熵之和,说明分布异常集中(大量重复 payload),是攻击特征。
        // 边沿检测,不是水平检测
        if( tresh < sum_entropy - entropy){
            printf("tresh < sum_entropy - entropy\n");

            if( !flag )// 首次检测到ddos攻击
            {
                // 应该是加入黑名单
                rte_exit(EXIT_FAILURE, "ddos attack !!! Entropy(%f) < Total_Entropy(%f)\n", 
					entropy, sum_entropy);
            }
            flag = 1;
        } else { // 没有检测到ddos攻击
            if( flag ){ // 应该恢复到正常状态
                printf( "attack ended !!! Entropy(%f) < Total_Entropy(%f)\n", 
					entropy, sum_entropy);    
            }
            flag = 0;
        }
        // 0 ~ N-1
        pkt_idx = (pkt_idx+1) % CAPTURE_WINDOWS;
        // N ~ 2N-1
        // pkt_idx = (pkt_idx+1) % CAPTURE_WINDOWS + CAPTURE_WINDOWS;
    }else {
        pkt_idx ++;
    }
    return 0 ;
}

文章参考<零声教育>的C/C++linux服务期高级架构系统教程学习:0voice · GitHub

相关推荐
2301_7807896612 小时前
SSL 卸载 + WAF + 抗 D:高防 CDN 一站式解决 HTTPS 性能与安全
网络·云原生·ddos
科技小登4 天前
网站和游戏怎么选高防?DDoS防护、高防IP与高防CDN接入方案解析与边界评估
tcp/ip·ddos
发量惊人的中年网工5 天前
抗DDoS服务哪家比较靠谱?选DDoS防护服务重点看哪几点?
运维·ddos
上海云盾-小余7 天前
真实案例:混合 DDoS+CC 攻击攻防,识别攻击源与规避防护绕过手段
ddos
2301_780789667 天前
IPv6 洪水猛兽:DDoS 攻击面 3 倍扩张下的精准清洗新战法
运维·安全·web安全·ddos·devops
上海云盾-小余7 天前
TCP 洪水与 UDP 反射 DDoS 原理对比:流量放大机制与检测逻辑详解
tcp/ip·udp·ddos
科技小登12 天前
网页防篡改与 WAF 方案怎么选?内容拦截、篡改监测与自动恢复实战测评
网络·web安全·ddos
科技小登12 天前
等保合规整改方案选型指南:技术整改、安全意识培训与应急演练实战测评
网络·安全·ddos
SDWAN_Cheap15 天前
网站与App攻击科普:从DDoS到应用层漏洞的完整解析
ddos·网络攻击