1. 背景介绍
为了防范SYN Flood攻击,等人提出了SYN Cookie机制,主要思想就是收到SYN报文时,在服务器端不保存任何信息,构造特殊的序列号后回复SYN-ACK报文,减少这种拒绝服务攻击对服务器的压力。收到ACK报文后,通过序列号解析判断其是否合法,决定连接是否建立。关于SYN Cookie的详细资料,请参考wikipedia的说明[1]。
本文主要描述IPV4协议栈收到SYN包后回复SYN-ACK报文、收到ACK包时检验其合法性时,计算与校验Cookie值的方法。参考源码为Linux 2.6.28的net/ipv4/syncookies.c。
2. 实现分析
目前的cookie是一个__u32的值,相关的算法实现主要包括两部分:
计算Cookie值做为回复SYN-ACK的序列号,在处理SYN报文的tcp_v4_conn_request()中调用,入口为cookie_v4_init_sequence ();
检验Cookie值是否合法,在tcp_v4_hnd_req ()中调用cookie_v4_check()->cookie_check()检查cookie值是否合法;
此外,在初始化时,需要调用init_syncookies()初始化数组__u32 syncookie_secret[2][16-4+SHA_DIGEST_WORDS],以备计算cookie时使用,通过调用random.c的get_random_bytes()实现,此处不再缀述。
2.1 Cookie的计算
函数调用关系主要为:
cookie_v4_init_sequence()=>secure_tcp_syn_cookie()=>cookie_hash()
根据secure_tcp_syn_cookie ()中的代码,我们可以得出,Cookie主要是由一些信息及其hash值相加得到的。代码内容如下:
return (cookie_hash(saddr, daddr, sport, dport, 0, 0) +
sseq + (count << COOKIEBITS) +
((cookie_hash(saddr, daddr, sport, dport, count, 1) + data)
& COOKIEMASK)); |
其中,COOKIEBITS为24,COOKIEMASK为低24位的掩码,即((__u32)1 << COOKIEBITS) - 1。而cookie_hash()的前四个参数为地址、端口信息,第五个参数count是系统的分钟数,用jiffies/(HZ*60)计算得到,第六个参数为0或1,指明使用syncookie_secret[0]还是syncookie_secret[1]来计算hash值。
Cookie的组成由图1所示:
图1 Cookie的组成
如图1说明,Cookie一共由三部分加和而成:
以源/目的地址和端口、0以及syncookie_secret[0]为输入的hash值
sseq序列号
高八位为当前分钟数,即jiffies/(60*HZ),低24位为hash值+data后的24位,其中,hash值以源/目的地址和端口、当前分钟数和syncookie_secret[1]为输入。
在cookie中加入的data只包括了低24位信息,在当前版本(8-3-0-3)的BVS中,data其实只保存了协商后的MSS值在msstab中的索引值。
2.2 Cookie的计算
如图1所示,三部分加和中,第一和三部分所用的hash算法相同。同时,显然可以得出,收到ACK报文时,第一个hash值是不变的,sseq是很容易求出的(ntohl(ack_th->ack_seq) - 1)即可)。而count值可以取出,但不是现在的系统分钟数。设发送SYNACK时时间jiffies,系统分钟数为count,收到ACK时时间为jiffies,系统分钟数为count,即
count = 向下取整(jiffies/(60*HZ)),count = 向下取整(jiffies/(60*HZ))
那么,分钟数的差值diff=count-count
据此,我们可以进行cookie的第一步校验——检查时间值,代码与分析如下:
//首先,去掉cookie三部分加和中的前两部分
cookie -= cookie_hash(saddr, daddr, sport, dport, 0, 0) + sseq;
//接下来,取出cookie的高八位,即发送SYN-ACK时编码进去的当时的系统分钟数,用
//当前分钟数去减,即为前后时间的差值,精确到分钟。
diff = (count - (cookie >> COOKIEBITS)) & ((__u32) - 1 >> COOKIEBITS);
//如果diff值过大,则认定cookie非法
if (diff >= maxdiff)
return (__u32)-1; |
如果diff值合理,则进一步解出data的低24位:
return (cookie -
cookie_hash(saddr, daddr, sport, dport, count - diff, 1))
& COOKIEMASK; /* Leaving the data behind */ |
接下来,判断data的低24位是否合法,即判断data的低24位是否属于msstab的合法索引,如果合法,则通过校验,否则,校验失败,判断ACK报文非法。
return mssind < NUM_MSS ? msstab[mssind] + 1 : 0; |
从上面的分析可以看出,cookie将一段数据编码进序列号,然后通过拆解ACK报文的序列号,确定tcp协商的选项MSS的协商结果。data可用的位一共24位,全部用来存储mssind以便解析检验。
2.3 其他TCP选项的处理
Linux 2.6.26中的syncookie机制实现了对MSS外的一些TCP选项的支持,但并未像MSS一样编码进cookie,即序列号,而是在支持timestamp的情况下,放入了timestamp的低9位。
收到SYN,在构造序列号完成后回复SYNACK时,调用如下函数处理其他TCP选项支持的问题:
__tcp_v4_send_synack()
=>__tcp_v4_send_synack()
=>tcp_make_synack()
=>cookie_init_timestamp()
在cookie_init_timestamp()中,将TCP选项支持写入了timestamp的低九位。
在校验时的调用cookie_v4_check()校验完MSS后,调用cookie_check_timestamp()从timestamp中拆出TCP选项。参考[2]中给出了当年这个实现的patch。
3. 参考资料
4.主要函数
-
阅读(1459) | 评论(3) | 转发(0) |