您的位置:首页 > 职场人生

netfilter知识

2010-12-22 19:16 253 查看
netfilter整体架构解析初步

本文档的Copyleft归yfydz所有,使用GPL发布,可以自由拷贝,转载,转载时请保持文档的完整性,严禁用于任何商业用途。

msn: yfydz_no1@hotmail.com

来源:http://yfydz.cublog.cn

1. 挂接点

netfilter是Linux2.4/2.6内核中自带的防火墙架构,定义了5个挂接点:

NF_IP_PRE_ROUTING-------->NF_IP_FORWARD--------->NF_IP_POST_ROUTING

| ^

| |

V |

NF_IP_LOCAL_IN NF_IP_LOCAL_OUT

netfilter定义了一个二维的链表头数组struct list_head nf_hooks[NPROTO][NF_MAX_HOOKS]来表示所有协议族的各个挂接点,NPROTO值为32,可表示linux所支持所有32个协议族(include/linux/socket.h文件中定义),也就是使用socket(2)函数的第一个参数的值,如互联网的TCP/IP协议族PF_INET(2)。每个协议族有NF_MAX_HOOKS(8)个挂接点,但实际只用了如上所述的5个,数组中每个元素表示一个协议族在一个挂接点的处理链表头,。

以下分析使用2.4.26内核中的netfilter代码。

在IPv4(PF_INET协议族)下,各挂接点定义在:

NF_IP_PRE_ROUTING,在IP栈成功接收sk_buff包后处理,挂接点在在net/ipv4/ip_input.c的函数

int ip_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt)

中定义:

return NF_HOOK(PF_INET, NF_IP_PRE_ROUTING, skb, dev, NULL,

ip_rcv_finish);

NF_IP_LOCAL_IN,在对接收的sk_buff包完成路由分类判断是到达自身的包后进行处理,挂接点在在net/ipv4/ip_input.c的函数int ip_local_deliver(struct sk_buff *skb)中定义:

return NF_HOOK(PF_INET, NF_IP_LOCAL_IN, skb, skb->dev, NULL,

ip_local_deliver_finish);

NF_IP_FORWARD,在对接收的sk_buff包完成路由分类判断是需要进行转发的包进行处理,挂接点在在net/ipv4/ip_input.c的函数int ip_forward(struct sk_buff *skb)中定义:

return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, dev2,

ip_forward_finish);

NF_IP_LOCAL_OUT,在对自身发出的包进行处理,挂接点在在net/ipv4/ip_output.c的函数

int ip_build_and_send_pkt(struct sk_buff *skb, struct sock *sk,

u32 saddr, u32 daddr, struct ip_options *opt)

中定义:

return NF_HOOK(PF_INET, NF_IP_LOCAL_OUT, skb, NULL, rt->u.dst.dev,

output_maybe_reroute);

NF_IP_POST_ROUTING,在IP栈成功接收sk_buff包后处理,挂接点在在net/ipv4/ip_output.c的函数

__inline__ int ip_finish_output(struct sk_buff *skb)中定义:

return NF_HOOK(PF_INET, NF_IP_POST_ROUTING, skb, NULL, dev,

ip_finish_output2);

2. 挂接点操作

挂接点的操作由结构struct nf_hook_ops定义:

include/linux/netfilter.h

struct nf_hook_ops

{

struct list_head list;

/* User fills in from here down. */

nf_hookfn *hook;

int pf;

int hooknum;

/* Hooks are ordered in ascending priority. */

int priority;

};

数组中的元素说明如下:

struct list_head list: 链表头,用于将此结构接入操作链表

nf_hookfn *hook:用户定义的挂接处理函数

int pf:协议族

hooknum:挂接点

priority:优先级

每个struct nf_hook_ops结构需要挂接到nf_hooks数组中的某个链表中才起作用,每个协议族的各种处理形成一个处理链表,链表上可以挂接多个节点,每个节点是一个数据处理结构(struct nf_hook_ops),用来描述对数据包进行如何处理,这些节点根据优先级顺序进行排序处理,优先级是有符号的32位数,值越小优先级越高,如果优先级相同,则按挂接的顺序依次处理,netfilter预定义了以下优先级:

NF_IP_PRI_FIRST = INT_MIN,

NF_IP_PRI_CONNTRACK = -200,

NF_IP_PRI_MANGLE = -150,

NF_IP_PRI_NAT_DST = -100,

NF_IP_PRI_FILTER = 0,

NF_IP_PRI_NAT_SRC = 100,

NF_IP_PRI_LAST = INT_MAX,

由此可见,netfilter的处理顺序是先连接跟踪、然后是mangle处理,再目的NAT(PREROUTING),然后是过滤(FILTER),然后是源NAT(POSTROUTING),这就是为什么mangle链的规则会先执行。

在各个处理点处理数据包时,如果发现需要丢弃数据包,那么数据包就被立即释放而不再进入后面的处理点;如果该处理点的最终结论是接受,那该数据包还会继续进入下一处理点进行匹配检查,所以对于最终通过防火墙的数据包,是经过了所有处理点的匹配的。

3. 连接跟踪

连接跟踪的struct nf_hook_ops结构在net/ipv4/netfilter/ip_conntrack_standalone.c中定义,

这是对用户隐藏的,也就是用户不能通过iptables规则对此操作点进行配置,是有系统自动完成的。

定义如下:

static struct nf_hook_ops ip_conntrack_in_ops

= { { NULL, NULL }, ip_conntrack_in, PF_INET, NF_IP_PRE_ROUTING,

NF_IP_PRI_CONNTRACK };

static struct nf_hook_ops ip_conntrack_local_out_ops

= { { NULL, NULL }, ip_conntrack_local, PF_INET, NF_IP_LOCAL_OUT,

NF_IP_PRI_CONNTRACK };

分别挂接在外部数据包进入(NF_IP_PRE_ROUTING)和自身数据发出(NF_IP_LOCAL_OUT)时进行处理,其功能就是判断该数据包是什么状态,填充该数据包struct sk_buff结构中struct nf_ct_info *nfct项的值,维护连接状态表,从而实现状态检测,具体处理过程分析可见另一篇文章:Linux下如何实现状态检测。

4. 规则表(table)

为了定义每个处理点上要执行哪些规则,netfilter定义了表(table)的概念,每个表由一个struct ipt_table来描述,如缺省的filter/nat/mangle表,每个表可单独分成几个规则链,分别在几个挂接点起作用,如filter表是在只在NF_IP_LOCAL_IN/NF_IP_LOCAL_OUT/NF_IP_FORWARD上起作用,然后通过函数ipt_do_table()来实现对某个表中某个hooknum的规则集进行匹配处理。而由结构struct nf_hook_ops所定义的各个处理点的处理函数都是直接或间接的调用了ipt_do_table()函数来实现对规则集的调用。

下面是系统缺省的三个表的定义情况:

-------+---------------------------------+-------------------------------------

table | table definition | file name

-------+---------------------------------+-------------------------------------

filter | struct ipt_table packet_filter | net/ipv4/netfilter/iptable_filter.c

|

hook | NF_IP_LOCAL_IN、NF_IP_LOCAL_OUT、NF_IP_FORWARD

|

ops | struct nf_hook_ops ipt_ops[]

| net/ipv4/netfilter/iptable_filter.c

|

|NF_IP_LOCAL_IN: ipt_hook()

| 调用ipt_do_table()函数与filter表的INPUT链挂钩

|

|NF_IP_LOCAL_FORWARD: ipt_hook()

| 调用ipt_do_table()函数与filter表的FORWARD链挂钩

|

|NF_IP_LOCAL_OUT: ipt_local_out_hook()

| 调用ipt_do_table()函数与filter表的OUTPUT链挂钩

|

-------+---------------------------------+-------------------------------------

nat | struct ipt_table nat_table | net/ipv4/netfilter/ip_nat_rule.c

|

hook | NF_IP_PRE_ROUTING_IN、NF_IP_LOCAL_OUT、NF_IP_POST_ROUTING

|

ops | net/ipv4/netfilter/ip_nat_standalone.c

|

|NF_IP_PRE_ROUTING:

| struct nf_hook_ops ip_nat_in_ops, ip_nat_fn()

| 调用ip_nat_rule_find()函数

| 调用ipt_do_table()函数与nat表的PREROUTING链挂钩

|

|NF_IP_POST_ROUTING:

| struct nf_hook_ops ip_nat_out_ops,ip_nat_out()

| 调用ip_nat_fn()

| 调用ip_nat_rule_find()函数

| 调用ipt_do_table()函数与nat表的POSTROUTING链挂钩

|

-------+---------------------------------+-------------------------------------

mangle | struct ipt_table packet_mangler | net/ipv4/netfilter/iptable_mangle.c

| |

hook | 全部五个都有

|

ops | struct nf_hook_ops ipt_ops[]

| net/ipv4/netfilter/iptable_mangle.c

|

|NF_IP_PRE_ROUTING: ip_route_hook()

| 调用ipt_do_table()函数与mangle表的PREROUTING链挂钩

|

|NF_IP_LOCAL_IN: ip_route_hook()

| 调用ipt_do_table()函数与mangle表的INPUT链挂钩

|

|NF_IP_FORWARD: ipt_hook()

| 调用ipt_do_table()函数与mangle表的FORWARD链挂钩

|

|NF_IP_LOCAL_OUT: ipt_local_hook()

| 调用ipt_do_table()函数与mangle表的OUTPUT链挂钩

|

|NF_IP_POST_ROUTING: ip_route_hook()

| 调用ipt_do_table()函数与mangle表的POSTROUTING链挂钩

|

-------+---------------------------------+-------------------------------------

每个数据处理表(table)中就是定义各自的规则集,是用动态长度的数组的形式保存,每个数组节点是一个规则,规则用struct ipt_entry结构进行描述,每条规则除了基本项外,其他附加匹配条件项还形成一个动态长度的匹配数组,struct ipt_entry中保存数组头的地址,每个匹配用结构struct ipt_match描述。规则的动作如果是扩展动作的话,用struct ipt_target描述。

用户可以自己定义自己的新的表,可以以缺省表为蓝本,然后定义新的struct nf_hook_ops操作节点,在该操作节点中调用ipt_do_table()函数将该ops和新表联系起来,这样就可以用iptables定义新的规则集。如果不定义新表,用户也可以在ops处理函数中对包直接进行判断处理,适合需要对包进行固定方式处理的场合。

5. 总结

netfilter架构以nf_hooks数组为基点,挂接在内核的协议处理的几个基本点上,通过链表方式链接struct nf_hook_ops处理结构,这些处理结构可以是在内核内部自动固定处理,如状态检测;也可以通过和struct ipt_table联系,通过iptables来动态配置处理规则,实现了一个扩展性很高的防火墙处理架构,不过实现细节部分仍然很复杂,各种细节功能将在后续文章里分析。

--

tech blog: http://yfydz.cublog.cn
※ 来源:·水木社区 newsmth.net·[FROM: 218.247.216.*]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  职场 netfilter 休闲