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 调用点。

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

相关推荐
FoldWinCard2 小时前
D5 Linux 网络及端口命令
linux·运维·服务器
零涂毕业设计3 小时前
毕业设计模块开发-OLED显示屏(IIC协议0.96寸)STM32 ESP32 FPGA Linux驱动免费分享
linux·stm32·单片机·嵌入式·esp32·fpga·oled
tedcloud1234 小时前
OmniRoute怎么部署?开源AI模型路由平台Linux部署教程
linux·服务器·人工智能·开源·音视频
霸道流氓气质4 小时前
KMS 密钥管理服务(Key Management Service)原理与实践
linux·服务器·数据库
SakitamaX4 小时前
LVS(Linux Virtual Server)概念详解
linux·运维·lvs
小张同学a.4 小时前
Linux系统管理
linux·运维
阿龙的工作记录5 小时前
深入理解Linux设备驱动模型
linux·嵌入式硬件·工作记录
代码村新手5 小时前
Linux的基本指令
linux·运维·服务器
hkj88085 小时前
Ubuntu 切换java版本
java·linux·ubuntu
撩得Android一次心动7 小时前
Linux编程笔记3【个人用】
linux·笔记