Chinaunix首页 | 论坛 | 博客
  • 博客访问: 825356
  • 博文数量: 264
  • 博客积分: 592
  • 博客等级: 中士
  • 技术积分: 1574
  • 用 户 组: 普通用户
  • 注册时间: 2011-10-24 22:02
文章分类

全部博文(264)

文章存档

2019年(2)

2018年(1)

2017年(1)

2016年(4)

2015年(14)

2014年(57)

2013年(88)

2012年(97)

分类: LINUX

2013-03-06 22:57:46

转:http://blog.sina.com.cn/s/blog_a31ff26901013qlm.html

四、FILTER


FILTER表顾名思义,用来对数据包进行做过滤,它是Netfilter中的核心表,提供了Netfilter防火墙的主要功能。


本章将以以ipv4filter表为例,从FILTER表的建立,注册以及hook操作对表的匹配过程对FILTER进行详细的分析。


4.1、初始化与注册


首先是iptable_filter模块初始化时注册一个packet_filter表,及相应的hook操作


static struct xt_table packet_filter =
{


.name =
"filter",//
表名


.valid_hooks =
FILTER_VALID_HOOKS,//
有效的hooks#define FILTER_VALID_HOOKS ((1
<<


//NF_IP_LOCAL_IN)
| (1 << NF_IP_FORWARD) |


//
(1 << NF_IP_LOCAL_OUT))


.lock =
RW_LOCK_UNLOCKED, //
读写锁


.me =
THIS_MODULE, //
模块


.af =
AF_INET, //
所属协议族


};


然后初始化相应的hook操作,由于FILTER表只在三个挂载点注册了函数,故在ipt_ops中我们设置了三个hook操作。


static struct nf_hook_ops ipt_ops[] = {


{


.hook =
ipt_hook,//
具体的操作


.owner =
THIS_MODULE,//
模块


.pf =
PF_INET, //
协议族


.hooknum =
NF_IP_LOCAL_IN, //hook
的标号


.priority =
NF_IP_PRI_FILTER,//
操作的优先级


},


{


.hook =
ipt_hook,


.owner =
THIS_MODULE,


.pf =
PF_INET,


.hooknum =
NF_IP_FORWARD,


.priority =
NF_IP_PRI_FILTER,


},


{


.hook =
ipt_local_out_hook,


.owner =
THIS_MODULE,


.pf =
PF_INET,


.hooknum =
NF_IP_LOCAL_OUT,


.priority =
NF_IP_PRI_FILTER,


},


};


表和hook操作初始化完成后,调用相应的注册函数注册到相应的全局标量当中去,这个注册函数分别为:


ipt_register_tablenf_register_hooks,其中ipt_register_table会调用xt_register_table,完成对表的注册。


表注册完成后是还不够的,这相当于我们有了仓库,还没工具,各种各样的targetmatch就是我们需要的工具,各种各样的targetmatch注册后,一个防火墙的过滤报文功能就可以实现了。


4.2hook操作流程


相应的注册和初始化工作完成后,当有报文进入Netfilter时,我们就可以对报文进行处理了。图3.3中,没有详细的列出hook操作如何对报文进行处理,在这里将对图3.3中的最后一步,以IPV4filter表为例进行扩展。挂载点被触发,调用hook操作,hook操作会根据对应的规则来对报文进行处理。从hook操作开始后的函数调用流程如下:


Netfilter源码分析--4、FILTER



4.1 FILTER表对数据包处理流程


4.3、重要函数分析


unsigned int


ipt_do_table(struct sk_buff *skb,


unsigned
int hook,


const
struct net_device *in,


const
struct net_device *out,


struct
xt_table *table)


{


static const
char nulldevname[IFNAMSIZ]
__attribute__((aligned(sizeof(long))));


u_int16_t
offset;


struct iphdr
*ip;


u_int16_t
datalen;


bool hotdrop =
false;



unsigned int
verdict = NF_DROP;


const char
*indev, *outdev;


void
*table_base;


struct
ipt_entry *e, *back;


struct
xt_table_info *private;




ip =
ip_hdr(skb);//
获取ip


datalen =
skb->len - ip->ihl * 4;


indev = in ?
in->name : nulldevname;//
获得输入设备


outdev = out ?
out->name : nulldevname;//
获得输出设备



offset =
ntohs(ip->frag_off) & IP_OFFSET;



read_lock_bh(&table->lock);


IP_NF_ASSERT(table->valid_hooks
& (1 << hook));//
检验hook是否有效


private =
table->private;//
获取table的数据区


table_base =
(void *)private->entries[smp_processor_id()];//
获取相应cputable的所有规则, //match,target


e =
get_entry(table_base, private->hook_entry[hook]);//
获取特定hook相对应的所有规则




back =
get_entry(table_base, private->underflow[hook]);


do
{


IP_NF_ASSERT(e);


IP_NF_ASSERT(back);


// 标准的匹配,详细分析见下面


if
(ip_packet_match(ip, indev, outdev, &e->ip, offset))
{


// 代码分析


struct
ipt_entry_target *t;


if
(IPT_MATCH_ITERATE(e, do_match,//
匹配所有的match


skb,
in, out,


offset,
&hotdrop) != 0)


goto
no_match;



ADD_COUNTER(e->counters,
ntohs(ip->tot_len), 1);



t
= ipt_get_target(e);//
获得match对应的target


IP_NF_ASSERT(t->u.kernel.target);



#if defined(CONFIG_NETFILTER_XT_TARGET_TRACE) ||
\


defined(CONFIG_NETFILTER_XT_TARGET_TRACE_MODULE)



if
(unlikely(skb->nf_trace))


trace_packet(skb,
hook, in, out,


table->name,
private, e);


#endif



if
(!t->u.kernel.target->target) {//
判断是否是标准的target


int
v;



v
= ((struct ipt_standard_target *)t)->verdict;//
获得相应的target


if
(v < 0) {



if
(v != IPT_RETURN) {


verdict
= (unsigned)(-v) - 1;


break;


}


e
= back;


back
= get_entry(table_base,


back->comefrom);


continue;


}


if
(table_base + v != (void *)e + e->next_offset


&&
!(e->ip.flags & IPT_F_GOTO)) {



struct
ipt_entry *next


=
(void *)e + e->next_offset;


next->comefrom


=
(void *)back - table_base;



back
= next;


}



e
= get_entry(table_base, v);


}
else {//
不是标准的target,也就是说match定义了自己的target



#ifdef CONFIG_NETFILTER_DEBUG


((struct
ipt_entry *)table_base)->comefrom


=
0xeeeeeeec;


#endif


verdict
= t->u.kernel.target->target(skb,//
获得target标准的target


in,
out,


hook,


t->u.kernel.target,


t->data);



#ifdef CONFIG_NETFILTER_DEBUG


if
(((struct ipt_entry *)table_base)->comefrom


!=
0xeeeeeeec


&&
verdict == IPT_CONTINUE) {


printk("Target
%s reentered!\n",


t->u.kernel.target->name);


verdict
= NF_DROP;


}


((struct
ipt_entry *)table_base)->comefrom


=
0x57acc001;


#endif



ip
= ip_hdr(skb);


datalen
= skb->len - ip->ihl * 4;



if
(verdict == IPT_CONTINUE)


e
= (void *)e + e->next_offset;


else



break;


}


}
else {



no_match:


e
= (void *)e + e->next_offset;//
继续下个匹配


}


} while
(!hotdrop);



read_unlock_bh(&table->lock);



#ifdef DEBUG_ALLOW_ALL


return
NF_ACCEPT;


#else


if
(hotdrop)


return
NF_DROP;


else return
verdict;


#endif


}



static inline int


ip_packet_match(const struct iphdr *ip,


const
char *indev,


const
char *outdev,


const
struct ipt_ip *ipinfo,


int
isfrag)


{


size_t
i;


unsigned long
ret;



#define FWINV(bool,invflg)
((bool) ^ !!(ipinfo->invflags & invflg))//bool
invflg不同时为真//两个!为了使后面的表达式只能为1或0


//判断源地址和目的地址是否相等


  if (FWINV((ip->saddr&ipinfo->smsk.s_addr) !=
ipinfo->src.s_addr,


IPT_INV_SRCIP)


||
FWINV((ip->daddr&ipinfo->dmsk.s_addr) !=
ipinfo->dst.s_addr,


IPT_INV_DSTIP))
{


dprintf("Source
or dest mismatch.\n");


dprintf("SRC:
%u.%u.%u.%u. Mask: %u.%u.%u.%u. Target:
%u.%u.%u.%u.%s\n",


NIPQUAD(ip->saddr),


NIPQUAD(ipinfo->smsk.s_addr),


NIPQUAD(ipinfo->src.s_addr),


ipinfo->invflags
& IPT_INV_SRCIP ? " (INV)" : "");


dprintf("DST:
%u.%u.%u.%u Mask: %u.%u.%u.%u Target:
%u.%u.%u.%u.%s\n",


NIPQUAD(ip->daddr),


NIPQUAD(ipinfo->dmsk.s_addr),


NIPQUAD(ipinfo->dst.s_addr),


ipinfo->invflags
& IPT_INV_DSTIP ? " (INV)" : "");


return
0;


}


//接口是否匹配



for (i = 0, ret
= 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {


ret
|= (((const unsigned long *)indev)[i]


^
((const unsigned long *)ipinfo->iniface)[i])


&
((const unsigned long *)ipinfo->iniface_mask)[i];


}


if (FWINV(ret
!= 0, IPT_INV_VIA_IN)) {


dprintf("VIA
in mismatch (%s vs %s).%s\n",


indev,
ipinfo->iniface,


ipinfo->invflags&IPT_INV_VIA_IN
?" (INV)":"");


return
0;


}



for (i = 0, ret
= 0; i < IFNAMSIZ/sizeof(unsigned long); i++) {


ret
|= (((const unsigned long *)outdev)[i]


^
((const unsigned long *)ipinfo->outiface)[i])


&
((const unsigned long *)ipinfo->outiface_mask)[i];


}


if (FWINV(ret
!= 0, IPT_INV_VIA_OUT)) {


dprintf("VIA
out mismatch (%s vs %s).%s\n",


outdev,
ipinfo->outiface,


ipinfo->invflags&IPT_INV_VIA_OUT
?" (INV)":"");


return
0;


}



//协议是否匹配


if
(ipinfo->proto


&&
FWINV(ip->protocol != ipinfo->proto, IPT_INV_PROTO))
{


dprintf("Packet
protocol %hi does not match %hi.%s\n",


ip->protocol,
ipinfo->proto,


ipinfo->invflags&IPT_INV_PROTO
? " (INV)":"");


return
0;


}



//分片是否匹配


if
(FWINV((ipinfo->flags&IPT_F_FRAG) && !isfrag, IPT_INV_FRAG))
{


dprintf("Fragment
rule but not fragment.%s\n",


ipinfo->invflags
& IPT_INV_FRAG ? " (INV)" : "");


return
0;


}


return
1;



}




阅读(1095) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~