Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1864405
  • 博文数量: 283
  • 博客积分: 10141
  • 博客等级: 上将
  • 技术积分: 2931
  • 用 户 组: 普通用户
  • 注册时间: 2005-12-21 14:33
文章分类

全部博文(283)

文章存档

2013年(2)

2012年(2)

2011年(17)

2010年(36)

2009年(17)

2008年(18)

2007年(66)

2006年(105)

2005年(20)

分类: LINUX

2009-01-09 16:46:31

Linux 2.6.26 cookie计算与校验分析

1. 背景介绍

  为了防范SYN Flood攻击,等人提出了SYN Cookie机制,主要思想就是收到SYN报文时,在服务器端不保存任何信息,构造特殊的序列号后回复SYN-ACK报文,减少这种拒绝服务攻击对服务器的压力。收到ACK报文后,通过序列号解析判断其是否合法,决定连接是否建立。关于SYN Cookie的详细资料,请参考wikipedia的说明[1]

  本文主要描述IPV4协议栈收到SYN包后回复SYN-ACK报文、收到ACK包时检验其合法性时,计算与校验Cookie值的方法。参考源码为Linux 2.6.26的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. 参考资料

[1]     

[2]     

 
阅读(1419) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~