您的位置:首页 > 运维架构 > Linux

【转帖LINUX】netfilter中的conntrack内核阅读笔记(1)

2010-02-11 22:29 459 查看
2008-07-07 22:04状 态检测(stateful inspection)是由CheckPoint公司最先提出的,可算是防火墙技术的一项突破性变革,把包过滤的快速性和代理的安全性很好地结合在一起, 目前已经是防火墙最流行的检测方式。状态检测的根本思想是对所有网络数据建立“连接”的概念,此“连接”是面向“连接”的协议之“连接”的扩展,对非连接 协议数据也可以建立虚拟连接。既然是连接,必然是有一定的顺序的,通信两边的连接状态也是有一定顺序进行变化的。防火墙的状态检测就是事先确定好连接的合 法过程模式,如果数据过程符合这个模式,则说明数据是合法正确的,否则就是非法数据,应该被丢弃。
2.6内核的Linux中的防火墙代码netfilter中实现了状态检测 (stateful inspection)检测技术:Linux为每一个经过网络堆栈的数据包,生成一个新的连接记录项(Connection entry)。此后,所有属于此连接的数据包都被唯一地分配给这个连接,并标识连接的状态。linux在netfilter的hook点上为 contrack定义了如下几个挂接点,用来处理流经的ip包:
NF_IP_PRE_ROUTING : ip_conntrack_defrag -> ip_conntrack_in
NF_IP_LOCAL_IN : ip_conntrack_help -> ip_confirm
NF_IP_LOCAL_OUT : ip_conntrack_defrag -> ip_conntrack_local
NF_IP_POST_ROUTING :ip_conntrack_help -> ip_confirm
其中ip_contrack_defrag用来处理报文分 片;ip_conntrack_in和ip_conntrack_local(内部调用ip_conntrack_in)用于conntrack为每个连 接建立模式记录,ip_conntrack,并判断报文是否符合合法的模式,不符合则丢弃;ip_conntrack_help是针对使用动态协议和端口 的连接设计的数据结构,如一个ftp连接针对数据流和控制流分别用到了两个端口,;ip_confirm判断报文所属的模式ip_conntrack是否 已经存在系统哈希中,否则加入到系统的hash中。

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;

};

/* The protocol-specific manipulable parts of the tuple: always in

network order! */

union ip_conntrack_manip_proto

{

/* Add other protocols here. */

u_int16_t all;

struct {

__be16 port;

} tcp;

struct {

u_int16_t port;

} udp;

struct {

u_int16_t id;

} icmp;

struct {

u_int16_t port;

} sctp;

struct {

__be16 key; /* key is 32bit, pptp only uses 16 */

} gre;

};

/* The manipulable part of the tuple. */

struct ip_conntrack_manip

{

u_int32_t ip;

union ip_conntrack_manip_proto u;
};

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协议等
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: