OpenWrt内核模块开发(五)-通过linux netfilter框架实现ip地址过滤

文章目录

ip_filter

功能简介

通过内核模块的方式向netfilter框架注册钩子函数,分析ip头部信息,提取源ip和目的ip,匹配到指定ip地址后进行过滤。

网络层

网络层引入了IP协议,制定了一套新地址,使得我们能够区分两台主机是否同属一个网络,这套地址就是网络地址,也就是所谓的IP地址。IP协议将这个32位的地址分为两部分,前面部分代表网络地址,后面部分表示该主机在局域网中的地址。如果两个IP地址在同一个子网内,则网络地址一定相同。为了判断IP地址中的网络地址,IP协议还引入了子网掩码,IP地址和子网掩码通过按位与运算后就可以得到网络地址。

OpenWrt内核模块开发(五)-通过linux netfilter框架实现ip地址过滤

通俗点讲,网络层就是以ip地址为唯一标识进行数据转发的,ip地址可以唯一标识一台主机。因此我们如果过滤局域网的ip地址,可以达到限制某台设备上网的效果,而如果过滤公网的ip地址,就可以限制所有设备访问特定资源的效果。

netfilter注册钩子函数

这里我们将hooknum设置为NF_INET_FORWARD

static struct nf_hook_ops ip_filter_ops[] __read_mostly = {
    {
        .hook = ip_filter_hook,
        .pf = PF_INET,
        .hooknum = NF_INET_FORWARD,
        .priority = NF_IP_PRI_FIRST + 1,
    },
};

static int __init ip_filter_init(void)
{
    printk("ip filter...init\n");
    nf_register_net_hooks(&init_net, ip_filter_ops, ARRAY_SIZE(ip_filter_ops));
    return 0;
}

ip过滤钩子函数分析

源码

static u_int32_t ip_filter_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
    struct nf_conn *ct = (struct nf_conn *)skb->_nfct;
    struct udphdr *udph = NULL;
    struct iphdr *iph = NULL;
    int i;
    char *black_ip_list[] = {
        "192.168.66.167",
        "8.8.8.8",
        "114.114.114.114",
        NULL
    };

    if (ct == NULL || !nf_ct_is_confirmed(ct))
    {
        return NF_ACCEPT;
    }

    iph = ip_hdr(skb);
    if (!iph)
        return NF_ACCEPT;
    char src_ip[32] = {0};
    char dst_ip[32] = {0};
    sprintf(src_ip, "%pI4", &iph->saddr);
    sprintf(dst_ip, "%pI4", &iph->daddr);
    printk("src_ip = %s, dst_ip = %s\n", src_ip, dst_ip);
    for (i = 0; black_ip_list[i] != NULL; i++)
    {
        if (0 == strcmp(src_ip, black_ip_list[i]) ||
            0 == strcmp(dst_ip, black_ip_list[i]))
        {
            printk("drop ippacket %pI4--->%pI4\n", &iph->saddr, &iph->daddr);
            return NF_DROP;
        }
    }

    return NF_ACCEPT;
}

分析
源码中提取了ip头部的源ip和目的ip,并查询我们配置的过滤ip列表,匹配成功将返回NF_DROP进行丢包处理。

编译运行

参考前面章节

测试结果

root@OpenWrt:/fros# 
root@OpenWrt:/fros# insmod ip_filter.ko 
root@OpenWrt:/fros# <4>[52786.030458] ip filter...init
<4>[52797.584631] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52797.589199] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52798.585038] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52798.588543] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52799.585729] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52799.588981] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52800.586586] src_ip = 192.168.66.167, dst_ip = 8.8.8.8
<4>[52800.590504] drop ippacket 192.168.66.167--->8.8.8.8
<4>[52816.371851] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52816.376783] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52817.373089] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52817.378449] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52818.373501] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52818.379103] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52819.374765] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52819.376784] drop ippacket 192.168.66.167--->39.156.69.79
<4>[52820.376567] src_ip = 192.168.66.167, dst_ip = 39.156.69.79
<4>[52820.380384] drop ippacket 192.168.66.167--->39.156.69.79

作者简介

OpenWrt应用过滤插件作者(应用过滤用于控制app联网,可以过滤游戏、视频、聊天等几百款app)
从事嵌入式Linux开发近10年,主要负责路由器网通产品研发,精通OpenWrt系统,包括luci、消息机制、内核模块等。擅长模块:路由器上网行为管理、智能流控、上网认证、防火墙、虚拟服务器、多wan负载均衡等

开源作品地址:
https://github.com/destan19/OpenAppFilter

源码和文档

关注微信公众号可以获取更多技术文档、固件、源码等
微信扫码关注:
OpenWrt内核模块开发(五)-通过linux netfilter框架实现ip地址过滤

OpenWrt内核模块开发(五)-通过linux netfilter框架实现ip地址过滤

OpenWrt内核模块开发(五)-通过linux netfilter框架实现ip地址过滤

上一篇:图像插值:理论与Python实现


下一篇:PotPlayer:当前音频无法播放。DirectX 驱动程序未正确安装或音像设备被禁用的解决办法