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

文章目录

mac_filter

功能简介

通过内核模块的方式向netfilter框架注册钩子函数,由于mac在ip层以下,常规的做法是在二层设备进行mac地址过滤的(比如交换机),这里我们在ip层分析mac层数据,达到过滤效果。

网络接口层(MAC)

网络接口层在发送端将上层的IP数据报封装成帧后发送到网络上;数据帧通过网络到达接收端时,该结点的网络接口层对数据帧拆封,并检查帧中包含的MAC地址。如果该地址就是本机的MAC地址或者是广播地址,则上传到网络层,否则丢弃该帧。

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

简单点讲就是mac层,通常我们称之为二层,比如交换机就属于二层设备,而路由器属于三层设备(ip路由)。

netfilter注册钩子函数

这里我们将hooknum设置为NF_INET_FORWARD

static struct nf_hook_ops mac_filter_ops[] __read_mostly = {
    {
        .hook = mac_filter_hook,
        .pf = PF_INET,
        .hooknum = NF_INET_FORWARD,
        .priority = NF_IP_PRI_FILTER + 1,
    },
};

static int __init mac_filter_init(void)
{
    printk("mac filter....init\n");
    nf_register_net_hooks(&init_net, mac_filter_ops, ARRAY_SIZE(mac_filter_ops));
    return 0;
}

mac过滤钩子函数分析

源码

static u_int32_t mac_filter_hook(void *priv, struct sk_buff *skb, const struct nf_hook_state *state)
{
    u_int8_t smac[ETH_ALEN] = {0};
    struct ethhdr *ethhdr = NULL;
    u_int8_t filter_mac_buf[32] = "00:0C:29:F1:34:8F";
    u_int8_t mac_buf[32] = {0};
    ethhdr = eth_hdr(skb);
    if (!ethhdr)
    {
        return NF_ACCEPT;
    }
    memcpy(smac, ethhdr->h_source, ETH_ALEN);
    if (!skb->dev){
        return NF_ACCEPT;
    }

    printk("dev=%s, source mac = %02X:%02X:%02X:%02X:%02X:%02X\n",
           skb->dev->name, smac[0], smac[1], smac[2], smac[3], smac[4], smac[5]);
    if (0== memcmp(skb->dev->name, "br", 2)){
        sprintf(mac_buf, "%02X:%02X:%02X:%02X:%02X:%02X", smac[0], smac[1], smac[2], smac[3], smac[4], smac[5]);
        if (0 == strcmp(mac_buf, filter_mac_buf)){
            printk("----drop dev=%s, source mac = %02X:%02X:%02X:%02X:%02X:%02X\n",
                skb->dev->name, smac[0], smac[1], smac[2], smac[3], smac[4], smac[5]);
            return NF_DROP;
        }
    }
    return NF_ACCEPT;
}

分析

  • 获取以太网头部信息ethhdr
    虽然netfilter hook已经处于ip层,但skb保存了所有头部信息,可以通过指针偏移获取到以太网头部,从而获取到源mac地址
  • 判断数据的方向
    这里只对lan侧设备mac地址进行匹配,也就是从桥接口上来的数据才进行分析

编译运行

参考前面章节

insmod mac_filter.ko

测试结果

root@OpenWrt:/fros# insmod mac_filter.ko 
root@OpenWrt:/fros# <4>[38235.271118] mac filter....init

root@OpenWrt:/fros# <4>[38241.873151] dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38241.876006] ----drop dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38242.896581] dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38242.899173] ----drop dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38245.374032] dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38245.376519] ----drop dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38246.978437] dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38246.979705] ----drop dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38248.264021] dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38248.265541] ----drop dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38249.425204] dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38249.426521] ----drop dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38250.592095] dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38250.593375] ----drop dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38251.827786] dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38251.829108] ----drop dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38252.874176] dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38252.876592] ----drop dev=br-lan, source mac = 00:0C:29:F1:34:8F
<4>[38253.905311] dev=br-lan, source mac = 00:0C:29:F1:34:8F

作者简介

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

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

源码和文档

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

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

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

上一篇:OpenWrt 编译固件、云编译(Lean、Lienol、ssrplus、passwall、 Applications 添加插件应用说明)


下一篇:用openwrt编译工具链编译一个可执行文件