首先,什么是对端信息块?
在linux内核源码剖析——tcp/ip实现这本书中是真么介绍的:对端信息块主要用于组装ip数据包时防止分片攻击,在建立tcp连接时检测连接请求段是否有效以及其序列号是否回绕
在linux内核中是通过inet_peer结构体描述的:
struct inet_peer
{
/* group together avl_left,avl_right,v4daddr to speedup lookups */
/*
* avl_left、avl_right、avl_height用来将对端信息
* 块组成AVL树。AVL树的根为peer_root。
*/
struct inet_peer *avl_left, *avl_right;
/*
* 对端的IP地址。
*/
__be32 v4daddr; /* peer's address */
__u16 avl_height;
/*
* 一个单调递增值,用来设置IP分片首部中
* 的id域。根据对端地址初始化为随机值。
*/
__u16 ip_id_count; /* IP ID for the next packet */
/*
* 用来链接到inet_peer_unused_head链表上。该
* 链表上的对端信息块都是当前闲置的,
* 可回收的。
*/
struct list_head unused;
/*
* 记录该对端信息块引用计数为0的时间。
* 当闲置的时间超出指定的时间时,
* 就会被回收。
*/
__u32 dtime; /* the time of last use of not
* referenced entries */
/*
* 引用计数器,标识当前被使用的次数。
* 当引用计数为0,表示该对端信息块
* 没有被使用。
*/
atomic_t refcnt;
/*
* 递增ID,对端发送分片的计数器。
* 参见ipq结构中的rid成员。
*/
atomic_t rid; /* Frag reception counter */
/*
* TCP中,记录最后一个ACK段到达的
* 时间。参见tcp_options_received结构中
* 的ts_recent成员。
*/
__u32 tcp_ts;
/*
* TCP中,记录接收到的段中的时间戳,
* 设置ts_recent的时间。参见tcp_options_received
* 结构中的ts_recent_stamp成员。
*/
unsigned long tcp_ts_stamp;
};代码中都有注释,其中注释来自于:http://blog.youkuaiyun.com/justlinux2010
对端信息块主要是以ip地址为关键字,peer_root为根,组织成AVL树。
对端信息块的创建和查询都是通过inet_getpeer来完成的,如果查询到了,自然会返回查询到的结果,但是如果查询到的结果在没有使用的对端信息块的链表(没用使用的对端信息块会被组织到一个链表中,也就是ient_peer_unused_head)中,会将它从其中删除,如果没有找到结果,会根据参数create来判断是否创建。
对端信息块的删除其实只是减小对端信息块的引用计数,如果减到0,就会把该对端信息块添加到inet_peer_unused_head中。真正删除对端信息块是通过cleanup_once这个函数。
清除对端信息块有两种方式-----同步和异步;同步的方式其实就是在inet_geetpeer中:
if (peer_total >= inet_peer_threshold)
/* Remove one less-recently-used entry. */
cleanup_once(0);如果peer_total大于inet_peer_threadhold就会调用cleanup_once删除。peer_total在每次创建对端信息块的时候就会增加,而inet_peer_threadhold是一个系统参数。
而异步方式也就是所谓的定时器实现的,也就是调用peer_check_expire,初始时间是通过inet_initpeers中设置。
static void peer_check_expire(unsigned long dummy)
{
unsigned long now = jiffies;
int ttl;
/*
* 根据当前对端信息块数计算本次垃圾回收
* 的对端信息块生存期阈值。当前对端信息
* 块数大于inet_peer_threshold时,使用inet_peer_minttl
* 作为本次垃圾回收的对端信息块生存期
* 阈值,否则根据inet_peer_maxttl来计算本次垃圾
* 回收的对端信息块生存期阈值。
*/
if (peer_total >= inet_peer_threshold)
ttl = inet_peer_minttl;
else
ttl = inet_peer_maxttl
- (inet_peer_maxttl - inet_peer_minttl) / HZ *
peer_total / inet_peer_threshold * HZ;
while (!cleanup_once(ttl)) {
if (jiffies != now)
break;
}
}
本文介绍了Linux内核中的对端信息块,主要用于防止IP数据包分片攻击和TCP连接验证。对端信息块由inet_peer结构体表示,组织成AVL树,并通过inet_getpeer进行创建和查询。当引用计数为0时,对端信息块会被移到未使用链表,清理工作可通过同步或异步(定时器)方式进行。
590

被折叠的 条评论
为什么被折叠?



