|
还需要指出,在文件syncookies.c中定义有一个__u16组成的表static __u16 const msstab[],这个表中保存的是一些可能的MSS(Maximum Segment Size)值。
secure_tcp_syn_cookie函数的返回值就是计算得到的ISN值,即cookie。为了描述方便,我们给出如下定义:
tmp1 := saddr + daddr + ((sport<<16)+dport) + syncookie_secret[0]
tmp2 := saddr + daddr + ((sport<<16)+dport) + syncookie_secret[1]
tmp11 := HASH_TRANSFORM(tmp1[16], tmp1)
tmp22 := HASH_TRANSFORM(tmp2[16], tmp2)
A := tmp11[0][17]
B := tmp22[1][17]
|
sseq := ntohl(skb->h.th->seq) 这里的skb是携带TCP SYN的那个skb,count1 := jiffies/(HZ*60) 当前时间的分钟值,data1 := msstab, 从前往后最后一个小于skb中携带的MSS值的值的索引(值得注意的是两个密钥在第一次被初始化后,就不会再有改动,直到系统重新启动。因此可以认为它是一个常值。)
有了上面的定义我们可以得到cookie等于:
isn := A+sseq + (count1<<COOKIEBITS) + (B+data1)&COOKIEMASK
|
这个isn被赋予返回的TCP SYN+ACK包中,作为其中的ISN值。这就是cookie 的产生过程。在这个过程中,没有在本地为这个连接请求分配任何存储空间。
在TCP服务器收到TCP ACK包时,相应的要进行SYN Cookie的检查。这个检查过程在函数tcp_v4_hnd_req中的cookie_v4_check函数开始。cookie_v4_check调用cookie_check函数,cookie_check函数调用check_tcp_syn_cookie函数。
check_tcp_syn_cookie函数在random.c中定义,是与前面介绍的secure_tcp_syn_cookie函数对应的函数,检查从TCP ACK中提取出的ISN值。
在check_tcp_syn_cookie中假定ISN的值如下:
isn := A+sseq + (count2<<COOKIEBITS) + (B+data2)&COOKIEMASK
|
这里的A、B都是根据当前这个skb中的地址信息和syncookie_secret算出来的;sseq是根据这个skb中的seq值算出的。
有了上面这些值,TCP服务器就可以反算出count2和data2。理论上来说,只要这个isn是原来那个isn,应该有:
count2 == count1
data2 == data1
|
但是这种结论仅仅是一个理论情况。因为在TCP服务器端并没有保存原来的count1和data1,因此不能直接进行比较。TCP服务器采取的方法是:
1)计算出当前的分钟值
count3 := jiffies/(HZ*60)用count3与count2比较,如果差值超过COUNTER_TRIES(4)分钟,则认为这 个ACK包不合法。
2)看data2是不是一个合法的msstab的索引,也就是说是不是小于NUM_MSS, 即(sizeo(msstab)/sizeof(msstab[0]) - 1)。如果小于,则认为这个ACK 合法,否则认为非法。
上面介绍的就是Linux内核Linux2.4.20中对SYN Cookie的实现方式。下面讨论一下它的合理性。希望得到的结论是这种方案可以有效的实现一般TCP的连接,同时可以防止SYN Flood攻击。
从上面的介绍来说,合法的TCP连接请求一定可以通过SYN Cookie流程。 另一方面我们看SYN Cookie在系统受到各种SYN Flood攻击时会采取的行为。 最一般的SYN Flood攻击方式是攻击者作为TCP客户机发送大量TCP SYN包而不再发送其他的包。这时SYN Cookie会为每个SYN包计算出相应的ISN值,并返回SYN+ACK包,而在本地将不分配任何存储空间,因此不会被成功攻击。
根据SYN Cookie的原理,攻击者有可能直接发送大量ACK包。这时SYN Cookie提取出每个包的isn值,并假定它有下面的格式:
|