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

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

相关推荐
承渊政道14 分钟前
Linux网络学习【Reactor反应堆模式】
linux·网络·学习·ubuntu·reactor
且从容.3 小时前
ubuntu安装flink
linux·ubuntu·flink
爱和冰阔落5 小时前
【Linux网络】TCP 服务器如何并发处理多个客户端?从 fork、僵尸进程到双重 fork
linux·运维·服务器·网络
程序员沉梦听雨5 小时前
WSL2的安装与使用
linux·wsl
微小的鱼5 小时前
Linux的渲染与显示系统链路
android·java·linux
lisanmengmeng5 小时前
alertmanger 标签 rules 打上分组标签
linux·运维·服务器
Android系统攻城狮6 小时前
Linux FFmpeg深度解析之av_write_frame调用流程与实战(三十三)
linux·运维·服务器·ffmpeg·音视频进阶·ffmpeg音视频
Linux-lucky18 小时前
45-Linux学习之旅之防火墙与WEB加固
linux·前端·网络·学习·ubuntu
禁默18 小时前
启元 Q1 二次开发实践:Ubuntu 部署与仿真验证,从 PrimeConsole 到 ROS 2 Humble + RViz
linux·运维·ubuntu
skywalk816318 小时前
把 去也网站 从 Ubuntu 搬到 FreeBSD:一次 Service Jail + nginx 的部署实录
linux·运维·nginx·ubuntu·freebsd