netfilter 学习练习一:通过目的端口过滤发出去的数据包

kernel版本 3.10.0-514.el7.x86_64

netfilter框架通过在内核网络协议栈五个数据包处理点注册回调函数,调用这些回调函数实现数据包过滤、修改、转发。

表示回调函数的hook结构体如下:

struct nf_hook_ops {
    struct list_head list;    //hook钩子函数双向列表,每一个hook点可以注册多个钩子函数

    /* User fills in from here down. */
    nf_hookfn   *hook;  //hook点的钩子函数
    struct module   *owner;  //所属模块指针
    void        *priv;        //猜测应该是私有数据,2.6.37版本没有这个字段
    u_int8_t    pf;  //协议族编号,如ipv4协议: PF_INET
    unsigned int    hooknum; //hook点编号,如 NF_INET_POST_ROUTING
    /* Hooks are ordered in ascending priority. */
    int     priority; //优先级,hook点注册的钩子函数列表按照优先级由高到底插入

    //2.6.37版本还没有下列字段
    /* Reserved for use in the future RHEL versions. Set to zero. */
    unsigned long   __rht_reserved1;
    unsigned long   __rht_reserved2;
    unsigned long   __rht_reserved3;
    unsigned long   __rht_reserved4;
    unsigned long   __rht_reserved5;
};

hook钩子函数原型如下:

3.10.0 与 2.6.37在参数上有区别:
3.10.0版本:
typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops,
                   struct sk_buff *skb,
                   const struct net_device *in,
                   const struct net_device *out,
#ifndef __GENKSYMS__
                   const struct nf_hook_state *state
#else
                   int (*okfn)(struct sk_buff *)
#endif
                   );  


2.6.37版本:
typedef unsigned int nf_hookfn(const struct nf_hook_ops *ops,
                   struct sk_buff *skb,
                   const struct net_device *in,
                   const struct net_device *out,
                   int (*okfn)(struct sk_buff *)
                   );  

示例功能:通过在内核协议栈的出口点,注册钩子函数,过滤出包的目的端口,如果端口为80即http端口则阻止数据包发出。hook函数返回NF_DROP即丢弃数据包达到此目的。

#include 
#include 
#include 
#include 
#include 
#include 
#include 

MODULE_LICENSE("Dual BSD/GPL");

static struct nf_hook_ops nfops;

unsigned short dport = 80; 

//hook钩子函数,不同的kernel版本,该参数格式可能不一样
//2.6.37与3.10.0不一样
unsigned int hook_filter_dport(const struct nf_hook_ops *ops, 
        struct sk_buff *skb,
        const struct net_device *in,
        const struct net_device *out,
#ifndef __GENKSYMS__
        const struct nf_hook_state *state
#else
        int (*okfn)(struct sk_buff *)
#endif
    )   
{
    struct iphdr *ip = ip_hdr(skb); //ip头
    struct tcphdr *tcp = tcp_hdr(skb); //tcp头

    if(!skb)
        return NF_ACCEPT;
    if(!tcp)
        return NF_ACCEPT;
    if(ip->protocol != IPPROTO_TCP)
        return NF_ACCEPT;
    // 判断目的端口,如果符合条件,则通过返回NF_DROP丢弃数据包
    // 模块安装之后,所有和目的端口通信的数据包都不会发出去,即表现为连不上或者超时
    if(ntohs(tcp->dest) == dport)
    {
        printk("drop out packet dest port %d\n", ntohs(tcp->dest));
        return NF_DROP;
    }
    else
    {
        printk("allowed out packet dest port %d\n", ntohs(tcp->dest));
        return NF_ACCEPT;
    }
}

static int __init hook_init(void)
{
    nfops.hook = hook_filter_dport; //设置hook函数,在其中进行端口判断 
    nfops.hooknum = NF_INET_POST_ROUTING; //ipv4的最后一个hook,数据包发出去前调用hook函数
    nfops.pf = PF_INET; //ipv4
    nfops.priority = NF_IP_PRI_FIRST; //优先级

    nf_register_hook(&nfops);//netfilter的注册函数,对hook结构体注册

    return 0;
}

static void __exit hook_exit(void)
{
    nf_unregister_hook(&nfops); //netfilter反注册函数,去掉hook函数注册
}

module_init(hook_init);
module_exit(hook_exit);

Makefile

obj-m += filter_port.o
all:
     make -C /lib/modules/`uname -r`/build M=`pwd`
install:
     /sbin/insmod filter_port.ko
remove:
     /sbin/rmmod filter_port.ko
clean:
     make -C /lib/modules/`uname -r`/build M=`pwd` clean

编译之后生成模块文件  filter_port.ko

安装模块 sudo insmod filter_port.ko

通过telnet 网站80端口可查看阻断情况,比如 baidu.com ,安装模块之前是可以telnet 80端口的,安装模块之后80端口连不上了如下:

telnet baidu.com 80
Trying 220.181.38.148...
telnet: connect to address 220.181.38.148: Connection timed out
Trying 39.156.69.79...
 

通过dmesg可以看到阻断日志如下,目的端口80的数据吧丢弃了,其它端口的数据包允许发出。

[ljq@ljqc7 netfilter_study]$ dmesg | tail
[35896.698765] allowed out packet dest port 52543
[35920.653114] drop out packet dest port 80
[35921.655736] drop out packet dest port 80
[35923.659353] drop out packet dest port 80
[35927.668318] drop out packet dest port 80
[35928.558176] allowed out packet dest port 51306
[35928.631088] allowed out packet dest port 52543
 

实验成功!

加油!

努力!

 

你可能感兴趣的:(c/c++)