Chinaunix首页 | 论坛 | 博客
  • 博客访问: 146502
  • 博文数量: 24
  • 博客积分: 791
  • 博客等级: 军士长
  • 技术积分: 350
  • 用 户 组: 普通用户
  • 注册时间: 2010-02-22 11:00
文章存档

2011年(18)

2010年(6)

分类: LINUX

2010-11-15 14:00:15

现在我们来分析一下,syncookies的基本原理。
由于syncookies机制不要求建立半连接,当第三次握手ack到来的时候,正常情况下会查找半连接队列,此时我们在半连接队列里找不到储存的半连接信息,那么这又将如何根据ack建立正常的连接呢?
首先我们来看下,主机回的synack有什么特点:上节中我们看到tcp_rsk(req)->snt_isn = isn,将计算的isn值赋给了snt_isn成员;在函数tcp_make_synack中,

    tcp_init_nondata_skb(skb, tcp_rsk(req)->snt_isn,
             TCPCB_FLAG_SYN | TCPCB_FLAG_ACK);
    th->seq = htonl(TCP_SKB_CB(skb)->seq);
    th->ack_seq = htonl(tcp_rsk(req)->rcv_isn + 1);

上图中可以看出调用了函数tcp_init_nondata_skb,

static void tcp_init_nondata_skb(struct sk_buff *skb, u32 seq, u8 flags)
{
    skb->csum = 0;

    TCP_SKB_CB(skb)->flags = flags;
    TCP_SKB_CB(skb)->sacked = 0;

    skb_shinfo(skb)->gso_segs = 1;
    skb_shinfo(skb)->gso_size = 0;
    skb_shinfo(skb)->gso_type = 0;

    TCP_SKB_CB(skb)->seq = seq;
    if (flags & (TCPCB_FLAG_SYN | TCPCB_FLAG_FIN))
        seq++;
    TCP_SKB_CB(skb)->end_seq = seq;
}

可以看到函数将tcp_rsk(req)->snt_isn的值赋给了TCP_SKB_CB(skb)->seq;最后,
th->seq = htonl(TCP_SKB_CB(skb)->seq),则th->seq的值就等于tcp_rsk(req)->snt_isn也就是我们在上一节计算的isn值;这就是在syncookies机制下的synack包的特殊之处。

下面来看下isn的计算过程:

#define COOKIEBITS 24    /* Upper bits store count */
#define COOKIEMASK (((__u32)1 << COOKIEBITS) - 1)

static __u16 const msstab[] = {
    64 - 1,
    256 - 1,
    512 - 1,
    536 - 1,
    1024 - 1,
    1440 - 1,
    1460 - 1,
    4312 - 1,
    (__u16)-1
};

__u32 cookie_v4_init_sequence(struct sock *sk, struct sk_buff *skb, __u16 *mssp)//*mssp为协商后的mss值,这在tcp_v4_conn_request函数中根据解析接收到的syn包tcp选项中的mss值与本机mss值协商较小值。
{
    struct tcp_sock *tp = tcp_sk(sk);
    const struct iphdr *iph = ip_hdr(skb);
    const struct tcphdr *th = tcp_hdr(skb);
    int mssind;
    const __u16 mss = *mssp;

    tp->last_synq_overflow = jiffies;//这个设置是为了当发送synack后3秒(内核初始化的RTO)内没有收到ack就认为此ack不合法

    /* XXX sort msstab[] by probability? Binary search? */
    for (mssind = 0; mss > msstab[mssind + 1]; mssind++)
        ;
    *mssp = msstab[mssind] + 1;//mssind为协商的mss在msstab中的位置

    NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_SYNCOOKIESSENT);

    return secure_tcp_syn_cookie(iph->saddr, iph->daddr,
                 th->source, th->dest, ntohl(th->seq),
                 jiffies / (HZ * 60), mssind);
}


static __u32 secure_tcp_syn_cookie(__be32 saddr, __be32 daddr, __be16 sport, __be16 dport, __u32 sseq, __u32 count,__u32 data)
{
    return (cookie_hash(saddr, daddr, sport, dport, 0, 0) +
        sseq + (count << COOKIEBITS) +
        ((cookie_hash(saddr, daddr, sport, dport, count, 1) + data)
         & COOKIEMASK));//count=jiffies/(HZ*60),表示密钥一分钟更新一次
}

我们来分析下这个cookie值是怎么计算的。从函数secure_tcp_syn_cookie中可以看出,cookie值有三部分组成:32位的cookie_hash函数返回值+32位的syn包的序列号(seq)+高8位的count值+低24位的cookie_hash+data。data值为mssind的值。

    计算完后cookie值,就将它作为synack的seq值,发送synack;那么如何通过接收到的ack包来建立正常的连接呢,我们应该知道此时半连接队列中没有记录该syn包的信息,如果没有syncookie机制,即使有收到第三次握手的ack包也会毫不留情的丢弃。

    我们知道三次握手的序列号关系是这样的:第一次握手(用户发送syn包,th为tcp头)th->seq=t;第二次握手(服务器发送synack包)th->seq=s,th->ack_seq=t+1;第三次握手(用户发送ack包)th->seq=t+1,th->ack_seq=s+1;那么我们显然可以根据收到的ack包中的seq和ack_seq来恢复协商后的mss值。现在来看下,是如何判断ack的合法性的呢。


 

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