Netfilter协议过滤功能

时间:2022-02-03 18:29:16

Netfilter中的5个钩子点:

1]:NF_IP_PRE_ROUTING:刚刚进入网络层的数据包通过此点(刚刚进行完版本号,校验和等检测),源地址转换在此点进行;
[2]:NF_IP_LOCAL_IN:经路由查找后,送往本机的通过此检查点,INPUT包过滤在此点进行;
[3]:NF_IP_FORWARD:要转发的包通过此检测点,FORWORD包过滤在此点进行;
[4]:NF_IP_POST_ROUTING:所有马上便要通过网络设备出去的包通过此检测点,内置的目的地址转换功能(包括地址伪装)在此点进行;
[5]:NF_IP_LOCAL_OUT:本机进程发出的包通过此检测点,OUTPUT包过滤在此点进行。

 

#include <linux/init.h>
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/netdevice.h>
#include <linux/skbuff.h>
#include <linux/netfilter_ipv4.h>
#include <linux/in.h>
#include <linux/proc_fs.h>
#include <linux/fs.h>
#include <linux/netfilter_bridge.h>

static unsigned int PacketMonitor(unsigned int hook,
                      
struct sk_buff *skb,
                      
const struct net_device *in,
                      
const struct net_device *out,
                      
int (*okfn)(struct sk_buff *)
                      
)
{
    
struct iphdr *iph=ip_hdr(skb);
    
struct ethhdr *eth=eth_hdr(skb);
    
if(!skb || !iph || !eth)
        
return NF_ACCEPT;
    
if(skb->pkt_type==PACKET_BROADCAST)
            
return NF_ACCEPT;
    
if(skb->protocol==htons(ETH_P_IP))&&skb->len>=sizeof(struct ethhdr))
    
{
        
if(iph->version!=4)
            
return NF_ACCEPT;
        
switch(iph->protocol) {
            
case IPPROTO_ESP:
            
case IPPROTO_AH:
                
printk(“protocol is ESP AND AH\n”);
                
break;
            
case IPPROTO_GRE:
                
printk(“protocol is GRE\n”);
                
break;
            
case IPPROTO_ICMP:
                
printk(“protocol is ICMP\n”);
                
break;
            
case IPPROTO_IGMP:
                
printk(“protocol is IGMP\n”);
                
break;
            
default:
                
break;
        
}
    
}
    
return NF_ACCEPT;
}
static struct nf_hook_ops icmpsrv_ops[] __read_mostly ={
    
{
      
.hook = PacketMonitor,
      
.pf = PF_BRIDGE,
      
.hooknum = NF_BR_PRE_ROUTING,
      
.priority = NF_BR_PRI_FIRST,
    
},
    
{
      
.hook = PacketMonitor,
      
.pf = PF_INET,
      
.hooknum = NF_INET_FORWARD,
      
.priority = NF_IP_PRI_FIRST,
    
},
};
static int init_hook_icmp(void)
{
    
nf_register_hooks(icmpsrv_ops,ARRAY_SIZE(icmpsrv_ops));
    return 0;
}
 
static void fini_hook_icmp(void)
{
    
nf_unregister_hooks(icmpsrv_ops,ARRAY_SIZE(icmpsrv_ops));
}

MODULE_LICENSE("GPL");
module_init(init_hook_icmp);
module_exit(fini_hook_icmp);

在程序中用到了nf_register_hooks函数,同时注册多个hook函数,通过nf_unregister_hooks来卸载hook

也可以用nf_register_hook函数来单个注册hook点,如:

static struct nf_hook_ops icmpsrv_ops={
      
.hook = PacketMonitor,
      
.pf = PF_BRIDGE,
      
.hooknum = NF_BR_PRE_ROUTING,
      
.priority = NF_BR_PRI_FIRST,
};

然后调用nf_register_hook(&icmpsrv_ops);

通过nf_unregister_hook(&icmpsrv_ops)来写在hook;

 

在netfilter的hook中还隐藏了一个钩子点,如:NF_BR_PRE_ROUTING;此点是在网桥下用的,如果不做网桥,程序中用到这个钩子也不会发现数据包,这个钩子的定义如下:

static struct nf_hook_ops icmpsrv_ops ={
      
.hook = PacketMonitor,
      
.pf = PF_BRIDGE,
      
.hooknum = NF_BR_PRE_ROUTING,
      
.priority = NF_BR_PRI_FIRST,
    
};

这个点使用于vlan网桥环境,其他的点在这上面获取不到vlan网桥时的数据;