1、Netfilter 架构分析- 基于 Linux 3.2.0一、全局图在文件 net/netfilter/core.c 中定义了一全局变量 nf_hooks,用于记录钩子点。nf_hooks 第一维代表协议数,第二维代表钩子数。struct list_head nf_hooksNFPROTO_NUMPROTONF_MAX_HOOKS _read_mostly;EXPORT_SYMBOL(nf_hooks);nf_hooksnf_register_hook() nf_hook_opslisthookownerpfhooknumprioritylistvalid_hooksprivatemeafp
2、rioritynamesizenumberinitial_entrieshook_entryunderflowstacksizestackptrjumpstackentrieslist listlistlistlistlistlistlistlistnet/netfilter/f_hooks 中每个元素都是一个链表 list_headinclude/linux/netfilter.h 钩子点结构体,其中的hook 是钩子函数net/netfilter/core.c 调用 nf_register_hook()将钩子点挂载到全局变量nf_hooks 的某个 list 上net/netfilter/
3、x_tables.c调用 xt_hook_link(table, fn)将xt_table 与 nf_hook_ops 关联起来,并挂载钩子点(xt_hook_link()内部调用了 nf_register_hooks()) 。include/linux/netfilter.h xt_table 结构体,用于管理过滤规则include/linux/netfilter.h xt_table_info 结构体,记录规则入口等信息net/ipv4/netfilter/ip_tables.c在 ipt_do_table()中,通过 hook_entry 与entries 获得 ipt_entry:ge
4、t_entry(entries, hook_entry);ipt_entryipnfcachetarget_offsetnext_offsetcomefromcounterselems0xt_entry_match xt_entry_targetunion uunion usermatch_sizenamerevision;union kernelmatch_sizematchmatch_sizeunion uunion usertarget_sizenamerevision;union kerneltarget_sizetargettarget_sizeunsigned char data0
5、 unsigned char data0xt_match xt_targetlist listname namerevision revisionbool (*match)() uint (*target)()int (*checkentry)() int (*checkentry)()void (*destroy)() void (*destroy)()me metable tablematchsize targetsizehooks hooksproto protofamily familyinclude/linux/netfilter_ipv4/ip_tables.hinclude/li
6、nux/netfilter/x_tables.h调用 ipt_get_target(ipt_entry)获得 xt_entry_target调用 xt_ematch_foreach()查找匹配信息include/linux/netfilter/x_tables.h二、钩子函数(hook)与过滤规则表(xt_table)前面已经提到,钩子函数与过滤规则的管理是通过全局变量 nf_hooks 来实现的,那么,什么时候会调用钩子函数呢?钩子函数又是如何利用已经注册好的过滤规则的呢?在 Linux 内核中定义了网络数据包的流动方向,数据包被网卡捕获后,它在内核网络子系统里的传输路径是:pre-rout
7、ingroute(in or forward)(out)post-routing。在netfilter 上注册的钩子函数如下所示(这些钩子函数按它们被调用的顺序排列 ):-PRE-ROUTE-FWD-POST-Conntrack | Mangle MangleMangle | Filter | NAT (Src)NAT (Dst) | | Conntrack(QDisc) | ROUTEv |IN Filter OUT Conntrack| Conntrack Mangle| Mangle | NAT (Dst)v | Filter共有五个位置设置了钩子点,PRE、IN、FWD、OUT、POS
8、T。钩子函数被注册到相应位置之后,它们就会那里等待数据包的到来,在接收数据包的地方,钩子函数被调用,数据包先由钩子函数捕获,进行处理,然后再转发或者丢弃。钩子函数的声明:include/ linux/netfilter.htypedef unsigned int nf_hookfn(unsigned int hooknum,struct sk_buff *skb,const struct net_device *in,const struct net_device *out,int (*okfn)(struct sk_buff *);下面围绕 iptable_filter为中心进行分析:1、
9、钩子函数2、 安全规则的应用net/ipv4/netfilter/iptable_filter.c定义一个钩子函数 iptable_filter_hook(),调用 ipt_do_table 来使用规则表里的规则。static unsigned int iptable_filter_hook()。 。 。 。 。 。net = dev_net(in != NULL) ? in : out);return ipt_do_table(skb, hook, in, out, net-ipv4.iptable_filter);static int _init iptable_filter_init(v
10、oid)。 。 。 。 。 。/* Register hooks */filter_ops = xt_hook_link(。 。 。 。 。 。unsigned int ipt_do_table()。 。 。 。 。 。table_base = private-entriescpu;e = get_entry(table_base, private-hook_entryhook);do 。 。 。 。 。 。xt_ematch_foreach(ematch, e) acpar.match = ematch-u.kernel.match;acpar.matchinfo = ematch-data
11、;if (!acpar.match-match(skb, 。 。 。 。 。 。t = ipt_get_target(e);。 。 。 。 。 。verdict = t-u.kernel.target-target(skb, 。 。 。 。 。 。 while (!acpar.hotdrop);。 。 。 。 。 。获得规则入口ipt_entry获得规则目标xt_entry_target遍历匹配表,匹配则执行下面动作调用目标方法xt_target.target()net/ipv4/netfilter/iptable_filter.c调用 xt_hook_link()使 xt_table与 nf
12、_hook_ops 关联起来,并挂载钩子点。从上面已经知道了过滤规则的使用是由钩子函数来实现的,那么,什么时候、在什么地方调用钩子函数呢?下面以 ip 数据包的接收为例进行分析:经过 N 次解封装,最后调用 nf_hook_slow()int ip_rcv()/ 数据包前期处理。 。 。 。 。 。return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL, ip_rcv_finish);。 。 。 。 。 。net/ipv4/ ip_input.c通过 NF_HOOK()来遍历钩子链表并调用钩子函数NF_HOOK() re
13、turn NF_HOOK_THRESH(pf, hook, skb, in, out, okfn, INT_MIN);include/linux/netfilter.hint nf_hook_slow()。 。 。 。 。 。verdict = nf_iterate(。 。 。 。 。 。net/netfilter/core.c调用 nf_hook_slow()处理钩子点unsigned int nf_iterate()。 。 。 。 。 。verdict = elem-hook(hook, skb, indev, outdev, okfn);。 。 。 。 。 。net/netfilter/
14、core.c调用 nf_iterate()遍历钩子链表钩子函数 hook()被调用三、规则的管理一条规则由三个结构体管理:ipt_entry、ipt_entry_match( 其中的 xt_match)、ipt_entry_target(其中的 xt_target)。在文件 net/netfilter/x_tables.c 中定义了一个全局变量 xt:struct xt_af struct mutex mutex;struct list_head match;struct list_head target;。 。 。 。 。 。;static struct xt_af *xt;其中的 matc
15、h 管理 xt_match,target 管理 xt_target,在 2.6.25 以后的 Linux 版本里少了对 xt_table 的管理,那么,xt_table 哪里去了呢?根据 xt_table 的注册函数xt_register_table()发现,xt_table 已交由 struct net 管理了。在文件 include/net/net_namespace.h 中定义了 net 结构体:struct net 。 。 。 。 。 。#ifdef CONFIG_NETFILTERstruct netns_xt xt;。 。 。 。 。 。#endif。 。 。 。 。 。;在文件
16、include/net/netns/x_tables.h 中定义了 netns_xt 结构体:struct netns_xt struct list_head tablesNFPROTO_NUMPROTO;。;就是通过上面这个 tables 变量来管理 xt_table 的。下图展现了这种规则管理的层次关系:匹配 xt_match 与动作 xt_target 的管理:定义一维全局变量 static struct xt_af *xt;xtfamilystruct list_head targetstruct list_head matchxt_match xt_targetlist listna
17、me namerevision revisionbool (*match)() uint (*target)()int (*checkentry)() int (*checkentry)()void (*destroy)() void (*destroy)()me metable tablematchsize targetsizehooks hooksproto protofamily family规则表 xt_table 的管理:定义一个 net 结构体 struct netstruct netns_xtstruct list_head tablesprotoxt_tablelistvali
18、d_hooksprivatemeafprioritynamext0 xt1 xtafnet/netfilter/x_tables.c调用 xt_register_match ()注册 xt_match 到全局变量 xt中net/netfilter/x_tables.c调用 xt_register_target()注册xt_target 到全局变量 xt 中net/netfilter/x_tables.c调用 xt_register_table()注册xt_table 到 net 结构体中四、ip table 内建的 filter 表定义在文件 net/ipv4/netfilter/iptabl
19、e_filter.c 中xt_table 表:static const struct xt_table packet_filter = .name = “filter“,/规则表默认的名字.valid_hooks = FILTER_VALID_HOOKS,/定义了三个钩子点 IN/FORWARD/OUT.me = THIS_MODULE,.af = NFPROTO_IPV4,/协议.priority = NF_IP_PRI_FILTER,/优先级;per network 操作:static struct pernet_operations iptable_filter_net_ops = .i
20、nit = iptable_filter_net_init,.exit = iptable_filter_net_exit,;初始化 filter 表:static int _init iptable_filter_init(void)。 。 。 。 。 。/* 注册 pernet_operations */ret = register_pernet_subsys(if (ret 0)return ret;/* 注册 hooks */filter_ops = xt_hook_link(。 。 。 。 。 。五、内核空间与用户空间的通信ip table 是一个基于 netfilter 框架的网络
21、数据包过滤工具,用户态下发的过滤规则通过套接字操作结构体 struct nf_sockopt_ops 里的相关系统调用使该规则能被内核识别,并更新过滤规则表。定义在文件 net/ipv4/netfilter/ip_tables.c 中static struct nf_sockopt_ops ipt_sockopts = .pf = PF_INET,.set_optmin = IPT_BASE_CTL,.set_optmax = IPT_SO_SET_MAX+1,.set = do_ipt_set_ctl,#ifdef CONFIG_COMPAT.compat_set = compat_do_i
22、pt_set_ctl,#endif.get_optmin = IPT_BASE_CTL,.get_optmax = IPT_SO_GET_MAX+1,.get = do_ipt_get_ctl,#ifdef CONFIG_COMPAT.compat_get = compat_do_ipt_get_ctl,#endif.owner = THIS_MODULE,;static int getsockopt(struct socket *sock,int lvl, int opt, char _user *ov, int _user *ol)static int setsockopt(struct
23、socket *sock,int lvl, int opt, char _user *ov, unsigned int ol)令 opt=IPT_BASE_CTL,调用 getsockopt 相当于调用 do_ipt_get_ctl,调用 setsockopt 相当于调用do_ipt_set_ctl。net/ipv4/netfilter/ip_tables.csocket 系统调用结构体net/tipc/socket.csocket 系统调用函数,在用户态下调用net/tipc/socket.csocket 系统调用函数,在用户态下调用六、参考文献1、 Linux netfilter Hack
24、ing HOWTO Rusty Russell and Harald Welte, mailing list netfilterlists.samba.org2、 Netfilter 框架图形化概要分析by shenguanghui, 2006-02-243、 iptables 内核框架和应用层 iptables 命令图形化概要分析by shenguanghui 2006-02-244、 sk_buff_head 图形化简介by shenguanghui()5、网络代码分析第二部分网络子系统在IP层的收发过程剖析R.wen ()6、 洞悉 linux 下的 Netfilter&iptableshttp:/ 实现机制分析2008-12 唐文