章节大纲

  • 在本任务中,我们将通过 LKM 编写一个数据包过滤程序,并将其插入到内核中的数据包处理路径中。在 Netfilter 被引入 Linux 之前,这种操作很难实现。

    Netfilter 的设计目的是帮助授权用户操作数据包。它通过在 Linux 内核中实现多个钩子(hooks)来实现这一目标。这些钩子分布在不同的位置,包括数据包的输入和输出路径。如果我们想操作输入的数据包,只需将我们的程序(通过 LKM 实现)连接到相应的钩子上。一旦有输入数据包到达,我们的程序就会被调用。通过我们的程序,可以决定是否允许数据包经过,此外,还可以修改数据包内容。

    在本任务中,你需要使用 LKM 和 Netfilter 实现一个数据包过滤模块。该模块将从一个数据结构中获取防火墙策略,并使用这些策略决定是否阻止数据包。为了让学生专注于过滤部分(即防火墙的核心功能),允许学生直接把防火墙策略写在程序中(在真正的防火墙软件中,策略和代码是分开的)。关于如何使用 Netfilter,请参考下面的示例。
     
    完整的示例代码名为 seedFilter.c,包含在实验设置文件的  Files/packet_filter  文件夹中。请完成以下任务(分别完成每个任务):
     
    • 使用提供的 Makefile 编译代码。将结果加载到内核中,并演示防火墙是否按预期工作。你可以使用以下命令生成到  8.8.8.8 的UDP数据包,即 Google 的 DNS 服务器。如果你的防火墙工作正常,请求将被阻止;否则,你将收到响应。
      dig @8.8.8.8 www.example.com
    • 将 printInfo 函数挂接到所有 Netfilter 钩子上。以下是钩子编号的宏定义。 通过实验结果解释每个钩子函数在何种条件下会被调用。
      NF_INET_PRE_ROUTING
      NF_INET_LOCAL_IN        
      NF_INET_FORWARD
      NF_INET_LOCAL_OUT
      NF_INET_POST_ROUTING 
    • 实现另外两个钩子以实现以下功能:(1) 阻止其他计算机 ping 虚拟机,(2) 阻止其他计算机 telnet 到虚拟机。请实现两个不同的钩子函数,但将它们注册到相同的 Netfilter 钩子上。你需要决定使用哪个钩子。Telnet 的默认端口为 TCP 端口 23。为了测试,你可以启动容器,进入 10.9.0.5,运行以下命令 (10.9.0.1 是分配给虚拟机的IP地址。为了简化,可以将此 IP 地址写在到防火墙规则中):
      ping 10.9.0.1
      telnet 10.9.0.1

    重要提示。由于我们对内核进行了修改,系统可能会崩溃。请务必经常备份文件,以免丢失数据。系统崩溃的常见原因之一是忘记取消注册的钩子。当模块被移除时,这些钩子仍然会被触发,但模块已经不存在于内核中,从而导致系统崩溃。为避免这种情况,请确保在 removeFilter 中添加相应的代码,以便在移除模块时删除所有注册的钩子函数。