Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4842488
  • 博文数量: 930
  • 博客积分: 12070
  • 博客等级: 上将
  • 技术积分: 11448
  • 用 户 组: 普通用户
  • 注册时间: 2008-08-15 16:57
文章分类

全部博文(930)

文章存档

2011年(60)

2010年(220)

2009年(371)

2008年(279)

分类: LINUX

2009-02-16 16:23:13

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.主要函数
  1.    
阅读(1463) | 评论(3) | 转发(0) |
给主人留下些什么吧!~~

chinaunix网友2009-03-28 18:58:37

今天在看syn cookies的计算,逛逛就逛到你这里来了, 写的不错。

ubuntuer2009-03-25 10:16:16

一个变量.....功能看你怎么用它了

chinaunix网友2009-03-19 10:23:33

请问last_synq_overflow的功能是什么啊,谢谢