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

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

相关推荐
HIT_Weston1 天前
84、【Ubuntu】【Hugo】搭建私人博客:文章目录(三)
linux·运维·ubuntu
qq_5470261791 天前
Linux 常用快捷键及文本编辑器
linux·运维·服务器
埃伊蟹黄面1 天前
磁盘级文件系统核心原理解析
linux·文件
醇氧1 天前
【Linux】 安装 Azul Zulu JDK
java·linux·运维
一直跑1 天前
查看显卡驱动版本,查看哪个用户使用显卡(GPU)进程
linux·服务器
滴水之功1 天前
Windows远程桌面(非图形化界面)连接Ubuntu22.04
linux
借你耳朵说爱你1 天前
在Linux上挂载磁盘
linux
小成202303202651 天前
Linux高级
linux·开发语言
ICT系统集成阿祥1 天前
Linux运维最万能的三条指令
linux·运维·服务器
CAU界编程小白1 天前
Linux系统编程系列之模拟文件操作
linux·算法