Netfilter使用一张全局hash表来定义报文的连接状态,它定义在ip_conntrack_core.c中,用指针struct list_head *ip_conntrack_hash来描述该表。这个hash表的大小是有限制的,在模块装载的时候确定,可以由用户指定,由ip_conntrack_htable_size记录,其默认值是根据当前内存的大小计算出来,采用了tcp协议栈中确定hash表大小的算法。每个hash节点均是一个链表的首部,该链表存放了该hash值的所有冲突项。连接跟踪表就由ip_conntrack_htable_size 条链表构成,整个连接跟踪表大小使用全局变量ip_conntrack_max描述,与hash表的关系是ip_conntrack_max = 8 * ip_conntrack_htable_size。
每个hash链表的节点都是一个ip_conntrack_tuple_hash结构:
struct ip_conntrack_tuple_hash
{
struct list_head list;
struct ip_conntrack_tuple tuple;
};
其中list用于链接冲突链表,tuple则用于存放标识连接的最基本信息,如果两个数据包的tuple完全相同,则它们属于同一个连接。因为每一个连接上的数据流都是双向的,所以需要两个tuple来分别标识不同方向上的流量。从Socket套接字角度来讲,连接两端用“地址+端口”的形式来唯一标识一个连接(对于没有端口的协议,如ICMP,可以使用其它办法替代),因此tuple保存了“来源地址/来源端口+目的地址/目的端口”来标识一个连接。
Netfilter用结构struct ip_conntrack_tuple 结构来封装这个“来源”和“目的”:
struct ip_conntrack_tuple { struct ip_conntrack_manip src; /* These are the parts of the tuple which are fixed. */ struct { u_int32_t ip; union { /* Add other protocols here. */ u_int16_t all; struct { u_int16_t port; } tcp; struct { u_int16_t port; } udp; struct { u_int8_t type, code; } icmp; struct { u_int16_t port; } sctp; struct { __be16 key; /* key is 32bit, * pptp only uses 16 */ } gre; } u; /* The protocol. */ u_int8_t protonum; /* The direction (for tuplehash) */ u_int8_t dir;/*描述数据流方向*/ } dst; }; |
tuple 结构仅仅用来标识一个连接,并不是描述一条完整的连接状态,netfilter将数据包转换成tuple结构,并根据其计算hash,在相应的链表上查询,获取相应的连接状态,如果没有查到,则表示是一个新的连接。
内核中,描述一个包的连接状态,使用了struct ip_conntrack 结构,可以在ip_conntrack.h中看到它的定义:
struct ip_conntrack { /* Usage count in here is 1 for hash table/destruct timer, 1 per skb, plus 1 for any connection(s) we are `master' for */ struct nf_conntrack ct_general; 结构的引用计数 /* Have we seen traffic both ways yet? (bitset) */ unsigned long status; 结构的状态, /* Timer function; drops refcnt when it goes off. */ struct timer_list timeout; 结构的老化定时器,避免过分暂用内存 #ifdef CONFIG_IP_NF_CT_ACCT /* Accounting Information (same cache line as other written members) */ struct ip_conntrack_counter counters[IP_CT_DIR_MAX]; 计数器,分别统计两个方向上的流量 #endif /* If we were expected by an expectation, this will be it */ struct ip_conntrack *master; 指向创建本结构的expect,关于expect后续会介绍 /* Current number of expected connections */ unsigned int expecting; 与本结构关联的expect的数量 /* Unique ID that identifies this conntrack*/ unsigned int id; /* Helper, if any. */ struct ip_conntrack_helper *helper; 与本结构相关的helper,与expect相关 /* Storage reserved for other modules: */ union ip_conntrack_proto proto; union ip_conntrack_help help; #ifdef CONFIG_IP_NF_NAT_NEEDED struct { struct ip_nat_info info; union ip_conntrack_nat_help help; #if defined(CONFIG_IP_NF_TARGET_MASQUERADE) || \ defined(CONFIG_IP_NF_TARGET_MASQUERADE_MODULE) int masq_index; #endif } nat; nat相关数据结构 #endif /* CONFIG_IP_NF_NAT_NEEDED */
#if defined(CONFIG_IP_NF_CONNTRACK_MARK) u_int32_t mark; #endif
#ifdef CONFIG_IP_NF_CONNTRACK_SECMARK u_int32_t secmark; #endif
/* Traversed often, so hopefully in different cacheline to top */ /* These are my tuples; original and reply */ struct ip_conntrack_tuple_hash tuplehash[IP_CT_DIR_MAX]; 不同方向的tuple }
|
union ip_conntrack_proto proto:对不同的协议,连接所需记录的参数不同,proto记录了和协议相关的私有内容。
union ip_conntrack_help help:记录了协议相关的内容,如ftp协议,h.323协议等
阅读(2163) | 评论(0) | 转发(0) |