• netfilter&iptables探讨(1)——基本原理


    网络数据的收发和处理是操作系统的核心功能之一,一般在内核中直接实现。要修改内核中的网络处理功能,就需要对内核的网络处理逻辑进行修改,之后经过内核编译、升级,才能生效。这个过程的代价很大,显然不能用于需要频繁定制内核网络行为的场景。因此,需要一种可以对内核网络行为进行灵活定制的机制,在不用修改内核核心代码,不升级内核的前提下实现对内核网络处理逻辑的自定义修改。

    在Linux内核中,netfilter和iptables就提供了这样一套内核网络定制机制。本文将简单介绍netfilter和iptables的原理、用途以及两者的关系,从而说明这套机制是如何实现通过用户态的简单配置,就能修改linux内核网络行为的。对netfilter和iptables的具体实现和用法将在后续的文章中讨论。

    问题

    1. netfilter的原理是什么,它是如何改变内核网络行为的?
    2. netfilter提供哪些功能和接口?如何通过netfilter来修改网络行为?
    3. iptables是在内核态还是用户态实现的?
    4. iptables是如何基于netfilter来修改网络行为的?
    5. iptables命令工具运行在用户态,它是如何将配置传入内核中,来改变内核网络行为的?
    6. 常用的netfilter+iptables机制都会涉及到哪些模块和组件,这些模块和组件间都是如何交互来实现最终的功能的?

    概述

    netfilter和iptables的应用非常广泛,linux系统上的防火墙、NAT,docker的bridge模式容器网络,都会基于这套机制实现。网上也有很多介绍netfilter和iptables机制的文章,其中一些为了简化概念,会将两者统称为iptables。但netfilter与iptables其实是有依赖关系的两套扩展机制,netfilter依赖内核提供内核态的基本网络扩展能力,iptables则基于netfilter提供了跨内核与用户态的网络定制能力。通过netfilter和iptables的组合,用户可以通过用户态的iptables配置工具下发网络行为规则,实现对网络功能的灵活定制。

    上图是netfilter和iptables机制的整体结构示意图。可以看到其中主要包含了3个部分:内核协议栈中的netfilter,内核中的iptables相关模块,以及用户态的iptables工具。

    netfilter

    如上图中所示,netfilter是内核协议栈基本功能的一部分,是不能作为模块动态加载的。内核协议栈在ip报文的处理路径上选择了5个关键位置,在这些位置上可以调用预先注册的一系列函数指针,来修改报文内容和后续处理路径。图中所画的是其中的LOCAL_IN位置,处于ip_local_deliver和ip_local_deliver_finish这两个处理函数之间。netfilter模块提供了nf_register_net_hook接口,用于注册处理函数指针。

    此外,netfilter提供了在setsockopt和getsockopt系统调用中添加option和相应处理函数的接口,便于网络功能模块和用户态进行交互。

    每个网络名空间netns中的netfilter是独立的,开发者需要为需要定制行为的每个netns分别调用注册接口来注册自己的回调函数。

    netfilter与iptables功能和模块之间没有必然的联系。基于netfilter提供的函数注册接口,可以通过内核模块的方式实现自己的网络定制功能,而不需要和iptables有任何关系。很多厂商都会通过netfilter接口实现自己的NAT、ACL、QoS等功能,而不会通过iptables配置的方式。

    但是,在内核中开发网络模块并实现和用户态的规则同步毕竟是一个非常复杂的工作。对于绝大部分应用场景(例如小流量的NAT、firewall等)来说,为了并不复杂的需求专门实现一整套内核与用户态机制显然是不现实的。iptables正是为了满足这些需求而产生的。

    iptables

    iptables是包含了用户态工具和内核态模块在内的一整套功能体系。用户态的iptables工具主要负责下发和获取内核的网络处理规则。iptables工具通过getsockopt/setsockopt系统调用,和内核的ip_tables模块进行交互,同步规则信息。这里使用的getsockopt/setsockopt,也是ip_tables模块使用netfilter提供的接口注册实现的。

    内核态的iptables功能被解耦成了多个不同的模块来完成,解耦的原因是内核中支持的网络规则表类型在不断增加,而这些表操作的逻辑大部分是相同的,因此需要将这些公共逻辑提取出来供相关表操作共享,减少代码的重复和冗余。上图中只画了3个模块,事实上iptables(以及ip6tables等)的相关模块非常多,大致可以分为3类,图中画出的3个是其中的典型代表:

    1. x_tables,包含各类表的公共数据结构和表操作的逻辑实现。狭义的说,iptables只实现了对IPv4报文的规则处理,其他类型的网络报文例如IPv6同样需要处理。而IPv4和IPv6报文处理规则在很大程序上是类似的,因此可以把相关的结构和处理逻辑提取出来供两类表使用。这里的x就代表了不同类型的表,例如iptables、ip6tables、arptables等等。
    2. ip_tables,包含ipv4相关的表操作的接口和公共逻辑实现。与之对应的还有ip6_tables等。与用户态交互的getsockopt/setsockopt,以及与netfilter交互的函数指针注册等操作都在这个模块中实现。
    3. iptable_filter,iptables中filter表专用逻辑的实现模块。iptables支持多种类型的表用于不同用途,例如filter、mangle、nat、raw等,每类表会有一些特有的数据结构和规则,就实现在各自的模块中,例如iptable_filter、iptable_raw等。

    下面以上图中展示的iptable filter表的功能为例,介绍iptables的主要功能逻辑:

    1. iptable_filter模块向netfilter中注册filter表的匹配处理回调函数iptable_filter_hook
    2. ip_tables模块从用户态的调用中获得filter表规则,保存在net.ipv4.iptable_filter表中
    3. 内核协议栈处理报文时,执行到netfilter的hook位置,调用filter的回调函数,在回调函数中会匹配filter表中的每条规则,并执行规则指定的操作。

    通过上述方式,iptables就能将用户态下发的规则通过netfilter机制作用到内核协议栈中。

    小结

    本文介绍了netfilter和iptables机制存在的意义、最基本的实现原理、以及相关的模块架构。最后来回答一下文章起始时的问题作为总结:

    1. netfilter是一个内核功能,netfilter在内核协议栈的关键执行路径上插入了hook点,会在这些hook点位置执行其他内核模块注册的网络处理函数,通过这些函数可以修改网络报文的处理逻辑和协议栈的后续行为。
    2. netfilter提供的主要接口有两个:hook点处理函数注册接口,以及setsockopt/getsockopt处理函数注册接口。通过这两个接口,可以修改内核协议栈的报文处理逻辑,并从用户态动态获取配置信息,动态修改网络行为。
    3. iptables是由用户态和内核态模块协同实现的机制。
    4. iptables相关的内核模块会调用netfilter的接口在协议栈的多个位置注册多种网络处理函数,在这些处理函数中根据用户态配置的规则来决定网络报文的处理方式。
    5. 用户态的iptables工具和内核态模块通过getsockopt/setsockopt系统调用来下发规则和获取规则执行情况。这两个系统调用的扩展是ip_tables模块基于netfilter提供的接口实现的。
    6. 如文中图片所示,netfilter是内核协议栈的一部分,iptables则由用户态工具和内核态的3类模块构成。
  • 相关阅读:
    mysql安装,安装mysql配置教程(超级详细图解)
    DevOps与CI/CD的最佳实践
    【QML】QML中的动画总结
    Kubernetes常用命令
    嵌入式分享合集4
    PASS计算样本量(1)---完全随机设计时两样本率比较
    vue中websocket使用(客户端)
    SkyWalking快速上手(四)——SkyWalking运用Java Agent插件对应用程序进行增强和监控
    次时代终端工具:WindTerm(含下载)
    Netty 系列之编解码器和 handler 的调用机制
  • 原文地址:https://blog.csdn.net/dillanzhou/article/details/126112173