一?书上讲tcp?连接初始seq是随机取的,这里分析一下流程。
二?代码流程梳理
want_cookie?不在本文讨论范围,洪泛攻击的情况这里就不做分析了。
linux内核通过tcp_conn_request?完成握手动作。
初始syn的seq分为两种情况。
2.1?复用之前的timewait端口连接的最后一次的序列号。
__u32?isn?=?TCP_SKB_CB(skb)->tcp_tw_isn;
这样在接受连接一端,就会判断seq是符合递增的逻辑的,不会拒绝这次syn请求。
2.2?之前没有过连接的端口
isn?=?af_ops->init_seq(skb);
.init_seq??=???tcp_v4_init_seq,
分析一下tcp_v4_init_seq?函数。
static?u32?tcp_v4_init_seq(const?struct?sk_buff?*skb)
{
????return?secure_tcp_seq(ip_hdr(skb)->daddr,
??????????????????ip_hdr(skb)->saddr,
??????????????????tcp_hdr(skb)->dest,
??????????????????tcp_hdr(skb)->source);
}
tcp_v4_init_seq?参数是链接四元组
u32?secure_tcp_seq(__be32?saddr,?__be32?daddr,
???????????__be16?sport,?__be16?dport)
{
????u32?hash;
????net_secret_init();?//?获取随机数,用随机数生成密钥,存入net_secret
????hash?=?siphash_3u32((__force?u32)saddr,?(__force?u32)daddr,
????????????????(__force?u32)sport?<<?16?|?(__force?u32)dport,
????????????????&net_secret);//全局变量?net_secret?
//通过net_secret?得到一个hash值
????return?seq_scale(hash);?
}
static?u32?seq_scale(u32?seq)
{
????/*
?????*??As?close?as?possible?to?RFC?793,?which
?????*??suggests?using?a?250?kHz?clock.
?????*??Further?reading?shows?this?assumes?2?Mb/s?networks.
?????*??For?10?Mb/s?Ethernet,?a?1?MHz?clock?is?appropriate.
?????*??For?10?Gb/s?Ethernet,?a?1?GHz?clock?should?be?ok,?but
?????*??we?also?need?to?limit?the?resolution?so?that?the?u32?seq
?????*??overlaps?less?than?one?time?per?MSL?(2?minutes).
?????*??Choosing?a?clock?of?64?ns?period?is?OK.?(period?of?274?s)
?????*/
????return?seq?+?(ktime_get_real_ns()?>>?6);
}
尽可能接近RFC?793
*建议使用250?kHz时钟。
*进一步的阅读表明,这是假设2?Mb/s的网络。
*对于10?Mb/s以太网,1?MHz时钟是合适的。
*对于10?Gb/s以太网,1?GHz时钟应该可以,但是
*我们还需要限制分辨率,以便u32-seq
*每个MSL重叠少于一次(2分钟)。
*选择64?ns周期的时钟是可以的。(274?s周期)
通过上面的seq_scale?生成最终的随机数seq