Linux Netfilter 之 如何完成一个自制的防火墙实例

完成内容

我将创建一个简单的防火墙demo,帮助你熟悉网络内核编程。这个demo将基于Linux的Netfilter框架实现。

基础框架

基础概念

Netfilter 框架

  • Netfilter 是 Linux 内核中的一个框架,用于对网络数据包进行过滤、修改和重定向。它提供了多个钩子点(hook points),允许用户在不同的网络层插入自定义逻辑。

Netfilter 主要功能

  1. 数据包过滤(如防火墙)。
  2. 网络地址转换(NAT,包括 SNAT 和 DNAT)。
  3. 数据包修改(如修改 TTL、TOS 等字段)。
  4. 数据包日志记录。

Netfilter 钩子点

  1. NF_INET_PRE_ROUTING:数据包进入网络栈后,但在路由决策之前。适合用于 DNAT(目标地址转换)或数据包标记。

    1)netfilter的内核挂载点在代码中的位置:内核代码路径 :/net/ipv4/ip_input.c

    2)具体函数 :在 ip_rcv()

    ip_rcv_finish是路由查找后的回调函数

  2. NF_INET_LOCAL_IN:数据包目标是本机(即目标地址是本机的 IP 地址)。适合用于过滤或修改进入本机的数据包。

    1)内核代码路径 :/net/ipv4/ip_input.c

    2)具体函数 :在 ip_local_deliver()

  3. NF_INET_FORWARD:数据包需要被转发到其他主机(即本机作为路由器)。适合用于过滤或修改转发的数据包。

    1)内核代码路径 :/net/ipv4/ip_forward.c

    2)具体函数 :在 ip_forward()

  4. NF_INET_LOCAL_OUT:数据包从本机发出。适合用于过滤或修改从本机发出的数据包。

    1)内核代码路径 :/net/ipv4/ip_output.c

    2)具体函数 :在 __ip_local_out()

  5. NF_INET_POST_ROUTING:数据包在路由决策之后,但在发送到网络接口之前。适合用于 SNAT(源地址转换)或数据包标记

    1)内核代码路径 :/net/ipv4/ip_output.c

    2)具体函数 :在 ip_output()

在NF_INET_PRE_ROUTING点进行实例实现

c 复制代码
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/netfilter.h>
#include <linux/netfilter_ipv4.h>
#include <linux/ip.h>
#include <linux/tcp.h>

staticunsignedintcustom_hook(void*priv,structsk_buff*skb,conststructnf_hook_state*state){
    structiphdr*ip_header =ip_hdr(skb);
    if(ip_header->protocol == IPPROTO_TCP){// 只处理 TCP 数据包
        structtcphdr*tcp_header =tcp_hdr(skb);
        printk(KERN_INFO "Custom Netfilter Hook: TCP packet to port %u\n",ntohs(tcp_header->dest));
        if(ntohs(tcp_header->dest)==22){   // 只处理目标端口为 22 的数据包
            printk(KERN_INFO "Custom Netfilter Hook: TCP packet to port 22\n");
                return NF_DROP;// 丢弃数据包
        }
    }
    return NF_ACCEPT;// 允许数据包继续传递
}

staticstructnf_hook_ops nfho ={
    .hook     = custom_hook,
    .pf       = NFPROTO_IPV4,          //作用在ip层
    .hooknum  = NF_INET_PRE_ROUTING,// 在 PRE_ROUTING 阶段处理数据包
    .priority = NF_IP_PRI_FIRST,      // 优先级
};

staticint __init pre_routing_module_init(void){
    nf_register_net_hook(&init_net,&nfho);
    printk(KERN_INFO "Custom Netfilter Hook registered\n");
    return0;
}

staticvoid __exit pre_routing_module_exit(void){
    nf_unregister_net_hook(&init_net,&nfho);
    printk(KERN_INFO "Custom Netfilter Hook unregistered\n");
}

module_init(pre_routing_module_init);
module_exit(pre_routing_module_exit);

MODULE_LICENSE("GPL");
MODULE_AUTHOR("pre_routing_module_init");
MODULE_DESCRIPTION("Netfilter hook example");

Makefile:

c 复制代码
obj-m += hook_NF_INET_PRE_ROUTING.o

all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules

clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

编译与验证

终端中运行以下命令来编译内核模块

c 复制代码
$ make 
make -C /lib/modules/5.4.0-150-generic/build M=/home/hook_netfilter modules
make[1]: Entering directory '/usr/src/linux-headers-5.4.0-150-generic'
  CC [M]  /homehook_netfilter/hook_NF_INET_PRE_ROUTING.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC [M]  /home/hook_netfilter/hook_NF_INET_PRE_ROUTING.mod.o
  LD [M]  /homehook_netfilter/hook_NF_INET_PRE_ROUTING.ko
make[1]: Leaving directory '/usr/src/linux-headers-5.4.0-150-generic'
c 复制代码
@ubuntu:hook_netfilter$ ls 
hook_NF_INET_PRE_ROUTING.c   hook_NF_INET_PRE_ROUTING.mod    hook_NF_INET_PRE_ROUTING.mod.o  Makefile       Module.symvers
hook_NF_INET_PRE_ROUTING.ko  hook_NF_INET_PRE_ROUTING.mod.c  hook_NF_INET_PRE_ROUTING.o      modules.order

加载模块

c 复制代码
$ sudo insmod hook_NF_INET_PRE_ROUTING.ko

查看模块

c 复制代码
$ lsmod |grep hook
hook_NF_INET_PRE_ROUTING    16384  0
c 复制代码
$ dmesg | tail
[716700.997388] Custom Netfilter Hook registered
[709907.950324] Custom Netfilter Hook: TCP packet to port 22
[709907.950325] Custom Netfilter Hook: TCP packet to port 22

验证结果

验证成功(无法连接)

我们可以用一个框图来简单罗列数据方向

意味着 custom_hook 函数被挂载到了 ip_rcv() 函数中的 NF_HOOK 调用点。

这是最早能抓到包的地方,所有进入的数据包(无论是发往本机还是需要转发的)都会经过这里,过滤规则会非常早地生效。

相关推荐
非凡ghost2 小时前
AOMEI Partition Assistant磁盘分区工具:磁盘管理的得力助手
linux·运维·前端·数据库·学习·生活·软件需求
山君爱摸鱼2 小时前
Linux网络配置
linux·运维
Galeoto2 小时前
how to setup k3s on an offline ubuntu
linux·运维·ubuntu
二进制coder3 小时前
深入解析 AST2600 H2B 接口:架构、原理与完整开发指南
linux·架构
sainty074 小时前
linux 宏 DEVICE_ATTR
linux
ajassi20004 小时前
linux C 语言开发 (六) 程序的编辑和编译(vim、gcc)
linux·运维·服务器
Murphy_lx4 小时前
vim指令
linux·编辑器·vim
小猪写代码4 小时前
vim 编辑器
linux·编辑器·vim
nmxiaocui4 小时前
Linux vi/vim
linux·运维·vim