前置说明:核心前提与组件
- 网络拓扑:假设Linux主机有1块外网网卡(eth0,公网IP:203.0.113.10)、1块内网网卡(eth1,内网IP:192.168.1.1),开启IP转发(
net.ipv4.ip_forward=1),iptables默认策略为INPUT DROP、FORWARD DROP、OUTPUT ACCEPT。 - 关键组件:网卡驱动、数据链路层(LLC/MAC)、网络层(IP)、传输层(TCP/UDP)、应用层、内核协议栈(sk_buff结构体)、conntrack(连接跟踪)、路由表、ARP缓存、iptables(五链四表)、NAT模块。
- 数据包载体:内核用
sk_buff(socket buffer)存储数据包,贯穿整个处理流程,记录IP、端口、状态、iptables标记等所有信息。
场景1:入站数据包(外部主机→本机应用,例:SSH连接本机22端口)
假设外部主机(IP:198.51.100.20)向本机(203.0.113.10)发起SSH连接(TCP协议,目标端口22),数据包处理流程如下:
第一步:物理层 + 数据链路层(网卡接收与帧处理)
- 网卡硬件接收:外部数据包通过网线传输到本机eth0网卡,网卡的PHY芯片(物理层)将电信号转换为数字信号,检查物理层校验(如曼彻斯特编码同步)。
- 帧校验与解封装:
- 网卡驱动(数据链路层)接收数字信号,组成以太网帧(Frame),检查帧头的
目的MAC地址是否与本机eth0的MAC一致(不一致则丢弃,广播帧除外)。 - 校验帧尾的FCS(循环冗余校验),若校验失败(数据损坏),直接丢弃;校验通过则剥离帧头(源MAC、目的MAC、帧类型)和帧尾FCS,将帧内的“IP数据包”(网络层数据)交给内核协议栈。
- 网卡驱动(数据链路层)接收数字信号,组成以太网帧(Frame),检查帧头的
- MTU检查:若IP数据包长度超过网卡MTU(默认1500字节),且IP头未设置“分片标志”,则丢弃数据包并返回ICMP“需要分片”错误。
第二步:网络层(IP协议处理,内核ip_rcv函数)
- IP头校验:
- 检查IP头的版本(IPv4/IPv6)、校验和(IP头校验和,仅校验头信息),若无效则丢弃。
- 递减IP头的TTL(生存时间),若TTL减为0,丢弃数据包并返回ICMP“TTL过期”错误。
- 分片处理:若IP数据包是分片包,先缓存所有分片,重组为完整的IP数据包后再继续处理(分片重组由内核
ip_defrag模块完成)。 - 路由决策前准备:记录数据包的
源IP(198.51.100.20)、目的IP(203.0.113.10),准备进入路由子系统。
第三步:iptables PREROUTING链(路由前处理)
数据包此时进入iptables的PREROUTING链,按“raw→mangle→nat”的表顺序处理(表的优先级:raw > mangle > nat > filter):
- raw表处理:
- 匹配raw表的PREROUTING规则,若规则设置
-j NOTRACK,则告知conntrack模块“不跟踪此连接”,后续conntrack不会记录该连接状态。 - 若未匹配NOTRACK规则,数据包继续向下。
- 匹配raw表的PREROUTING规则,若规则设置
- mangle表处理:
- 修改数据包的TOS(服务类型)、TTL、标记(MARK)等属性,或进行流量整形(如限速标记)。
- 例:
iptables -t mangle -A PREROUTING -p tcp --dport 22 -j MARK --set-mark 10(给SSH数据包打标记10)。
- nat表处理(DNAT):
- 若需将外部请求转发到本机内网IP(如端口映射),则通过DNAT修改数据包的
目的IP/端口。 - 例:
iptables -t nat -A PREROUTING -p tcp --dport 2222 -j DNAT --to-destination 192.168.1.10:22(将公网2222端口转发到内网192.168.1.10的22端口)。 - 注意:nat表的规则仅在“新连接”的第一个数据包时生效,后续数据包会通过conntrack的状态记录直接应用DNAT结果,无需重复匹配。
- 若需将外部请求转发到本机内网IP(如端口映射),则通过DNAT修改数据包的
图解说明:
- 入口:数据包首先进入
PREROUTING链。 - raw 表:这是数据包遇到的第一个表。它的主要作用是决定是否要让连接跟踪系统(conntrack)处理这个数据包。如果匹配了
NOTRACK规则,数据包就会被“豁免”,不再进行状态跟踪。 - mangle 表:无论是否被
NOTRACK,数据包都会经过mangle表。这个表可以用来修改数据包的元数据,比如服务类型(TOS)、生存时间(TTL)或者打上一个内核内部使用的标记(MARK),常用于高级路由或流量整形。 - nat 表:这是
PREROUTING链中最后一个关键环节,主要负责目标地址转换(DNAT)。- 新连接:对于一个新连接的第一个数据包,
nat表会查找匹配的 DNAT 规则来修改其目标 IP 和端口。这个转换关系会被conntrack模块记录下来。 - 后续包:对于该连接的后续数据包,系统会通过
conntrack中记录的状态,直接应用之前已经确定的 DNAT 转换,而无需重复查询nat表规则,大大提高了效率。
- 新连接:对于一个新连接的第一个数据包,
- 出口:完成所有
PREROUTING链中的处理后,数据包将进入下一个环节:路由决策,系统将根据目标地址决定数据包的下一跳。
第四步:连接跟踪(conntrack)
- 内核的
nf_conntrack模块介入,根据数据包的源IP、目的IP、协议(TCP/UDP)、源端口、目的端口,查询连接跟踪表(/proc/net/nf_conntrack可查看)。 - 对SSH连接的第一个数据包(SYN包):标记为
NEW状态,记录连接信息(包括后续可能的NAT映射关系)。 - 对后续数据包(如SYN-ACK、ACK):匹配已存在的连接记录,标记为
ESTABLISHED状态。 - 作用:为后续iptables的
state模块、路由转发提供状态依据。
第五步:路由决策(内核ip_route_input函数)
- 内核根据数据包的
目的IP(可能已被DNAT修改)查询路由表(route -n可查看),判断数据包的“去向”:- 若目的IP是本机的某个网卡IP(如203.0.113.10)或本地回环地址(127.0.0.1):路由决策结果为“发给本机”,数据包进入
INPUT链。 - 若目的IP是其他网络(如192.168.1.0/24):路由决策结果为“需要转发”,数据包进入
FORWARD链(本场景是入站,所以走INPUT)。
- 若目的IP是本机的某个网卡IP(如203.0.113.10)或本地回环地址(127.0.0.1):路由决策结果为“发给本机”,数据包进入
- 路由决策的依据:路由表中的“目标网络”“子网掩码”“网关”“出口网卡”字段,优先匹配最长前缀(如/24比/0优先)。
好的,这是根据您提供的“第五步:路由决策”的描述所绘制的详细 Mermaid 图。
这张图清晰地展示了内核如何根据数据包的目的地址来决定其下一步的走向。
图解说明:
- 入口:数据包在完成了
PREROUTING和连接跟踪后,进入路由决策阶段。 - 查询核心:内核会提取数据包的最终目的IP地址(请注意,如果之前经过了 DNAT,这里使用的就是被修改后的新地址),然后在系统的路由表中进行查找。
- 决策分支:
- 发往本机 (Local Delivery):如果路由表查询结果表明,该目的 IP 就是本机某个网络接口上配置的 IP 地址之一(或者是
127.0.0.1),那么内核就认为这个数据包是给自己的。因此,数据包的下一站是INPUT链,准备被本地的应用程序处理。 - 需要转发 (Forwarding):如果目的 IP 不属于本机,但路由表指示本机知道如何将这个数据包发送到目标网络(通常通过一个网关),那么内核就扮演路由器的角色。数据包的下一站是
FORWARD链,准备被转发出去。
- 发往本机 (Local Delivery):如果路由表查询结果表明,该目的 IP 就是本机某个网络接口上配置的 IP 地址之一(或者是
- 决策依据:这个决策过程并非随意进行,而是严格遵循最长前缀匹配原则。在多个路由规则都能匹配目的 IP 的情况下,网络掩码最长(即网络范围最精确)的那条规则会被选中。
- 最终去向:
- 进入
INPUT链的数据包最终会被本地的某个套接字(Socket)接收。 - 进入
FORWARD链的数据包则会继续走向POSTROUTING链,并从相应的网卡发送出去。
- 进入
第六步:iptables INPUT链(入站过滤)
数据包进入INPUT链,按“mangle→filter”的表顺序处理(raw表在INPUT链无作用,nat表仅PREROUTING/OUTPUT/POSTROUTING生效):
- mangle表处理:再次修改数据包属性(如调整TTL、标记),与PREROUTING链的mangle表功能一致,可针对入站数据做二次调整。
- filter表处理(核心过滤):
- 按规则顺序匹配数据包,一旦匹配则执行动作(ACCEPT/DROP/REJECT),停止后续检查;无匹配则执行默认策略(本场景是DROP)。
- 例:本场景的SSH数据包会匹配规则
iptables -A INPUT -p tcp --dport 22 -m state --state NEW,ESTABLISHED -j ACCEPT,被ACCEPT。 - 若未匹配任何允许规则(如未开放22端口),则被默认策略DROP,数据包至此终止(无返回信息,外部表现为“连接超时”)。
图解说明:
- 入口:经过路由决策,确定是发往本机的数据包,进入了
INPUT链。 - mangle 表:首先经过
mangle表,这里可以对数据包进行第二次“修饰”,例如打上特定的标记,供后续的程序或规则使用。 - filter 表(核心):这是
INPUT链最关键的部分,负责真正的“过滤”工作。- 顺序匹配:防火墙规则是严格按照顺序从上到下进行检查的。
- 首次匹配即生效:一旦数据包的特征(如协议、端口、状态等)与某条规则完全匹配,就会立刻执行该规则指定的动作(
ACCEPT,DROP,REJECT),并且不再继续检查filter表中的后续规则。 - 处理动作:
ACCEPT:放行。数据包被认为是安全的,允许它访问本机的应用程序。在本例中,SSH 数据包会匹配到允许 22 端口的ACCEPT规则。DROP:悄无声息地丢弃。数据包就像石沉大海,发送方不会收到任何回应,直到连接超时。REJECT:明确拒绝。系统会丢弃数据包,但会向发送方返回一个错误消息(如 “port unreachable”)。
- 默认策略:如果数据包从头到尾检查完所有规则,都没有找到任何一条能够匹配上,那么它就会接受“默认策略”的处置。在安全的配置中,默认策略通常是
DROP,即“凡是未被明确允许的,一律禁止”。
这个流程确保了只有符合预设安全策略的数据包才能最终访问到服务器上的服务。
第七步:传输层(TCP/UDP协议处理)
- 数据包被INPUT链ACCEPT后,内核将其交给传输层,根据IP头的“协议字段”(TCP=6,UDP=17)转发到对应协议模块:
- TCP模块:
- 检查TCP头的校验和、序列号、端口号,若端口号对应本机正在监听的服务(如sshd监听22端口),则将数据包交给对应的socket(应用层与内核的通信接口)。
- 若为SYN包(新连接),则回复SYN-ACK包(完成三次握手的第二步);若为数据报文,则放入socket的接收缓冲区。
- UDP模块:
- 检查UDP头的校验和、端口号,若端口对应监听的UDP服务(如DNS的53端口),则交给对应socket;无对应端口则丢弃,可能返回ICMP“端口不可达”。
- TCP模块:
第八步:应用层处理
- 应用程序(如sshd)通过socket接口从内核接收数据包,解析数据内容(如SSH的认证信息、命令),处理后生成响应数据(如认证通过、命令输出),响应数据会作为“出站数据包”重新进入内核协议栈(流程见场景2)。
好的,这是根据您提供的第七步(传输层处理)和第八步(应用层处理)的描述,绘制的详细 Mermaid 流程图。
这张图将两个步骤融合在一起,完整地展示了数据包从防火墙放行到被应用程序处理,再到生成响应的全过程。

图解说明:
第七步:传输层
- 分发:数据包通过
INPUT链后,内核网络栈的核心部分接管。它会检查 IP 头部的协议字段,像一个智能分拣员,将包发给对应的处理模块(TCP 或 UDP)。 - TCP 模块(可靠的连接):
- 首先进行严格的检查,确保数据包没有损坏。
- 然后检查目标端口。如果一个应用程序(如 SSH 服务器)正在监听这个端口,内核就知道这个包是给谁的。
- 对于新连接(SYN 包),内核会自动处理三次握手,回复一个 SYN-ACK,此时应用层还未介入。
- 对于已建立连接的数据,内核会将其放入一个专属的“接收缓冲区”,等待应用程序来读取。
- UDP 模块(无连接的数据报):
- 处理流程更简单。检查数据包完整性后,直接看端口。
- 如果端口有程序在监听,数据就直接被放入接收缓冲区。
- 如果端口没有程序在监听,数据包会被丢弃,并且系统通常会回复一个 ICMP “端口不可达”消息,告知发送方“这里没人接收你的数据”。
第八步:应用层
- 数据到达:当内核将数据放入 Socket 的接收缓冲区后,应用程序(如
sshd)会被唤醒。 - 读取与处理:应用程序通过标准的系统调用(如
read())从内核的缓冲区中取出数据。这时数据才真正从内核态“拷贝”到了用户态。应用程序随后会根据其自身逻辑(如 SSH 协议)来解析这些二进制数据。 - 生成响应:处理完请求后,应用程序会生成需要返回给客户端的数据。
- 发送响应:应用程序将响应数据通过系统调用(如
write())写回同一个 Socket。这个动作会触发一个新的流程:出站数据包的封装和发送,它将再次经过iptables的OUTPUT和POSTROUTING链,然后从网卡发出。
场景2:出站数据包(本机应用→外部主机,例:本机ping外部百度)
假设本机应用(ping命令)向百度(IP:180.101.49.11)发送ICMP请求包(协议类型1),处理流程如下:
第一步:应用层发起请求
- 应用程序(ping)通过系统调用(如
sendto)向内核传递数据(ICMP请求包内容),并指定目标IP(180.101.49.11)和协议(ICMP)。 - 内核为应用程序创建socket,将数据封装为“应用层数据”,交给传输层(ICMP属于网络层协议,跳过传输层直接到网络层)。
第二步:传输层处理(TCP/UDP/ICMP)
- 若为TCP/UDP协议:
- TCP模块:添加TCP头(源端口、目的端口、序列号、确认号、标志位如SYN),计算校验和。
- UDP模块:添加UDP头(源端口、目的端口),计算校验和。
- 若为ICMP协议(如ping):直接跳过传输层,进入网络层。
第三步:网络层(IP协议封装)
- IP头封装:
- 内核添加IP头,设置
源IP(本机出口网卡IP,如eth0的203.0.113.10)、目的IP(180.101.49.11)、协议类型(ICMP=1)、TTL(默认64)、校验和。 - 检查数据包总长度,若超过出口网卡MTU(1500),则进行IP分片(添加分片标志、片偏移)。
- 内核添加IP头,设置
- 路由决策:
- 查询路由表,找到前往目标网络(180.101.49.0/24)的路由条目,确定“出口网卡”(eth0)和“网关”(如203.0.113.1,运营商网关)。
图解说明:
- 应用层发起:一切始于应用程序。它通过系统调用将数据和目的地信息“委托”给操作系统内核进行处理。
- 传输层(条件性跳过):
- 内核首先检查这是一个什么类型的请求。对于
ping使用的 ICMP 协议,它在网络模型中与 IP 层同级,因此直接跳过了传统的传输层(TCP/UDP)。 - 如果是普通的网络应用(如 Web 浏览器),则会在这里被添加上 TCP 或 UDP 头部,包含了端口号等关键信息。
- 内核首先检查这是一个什么类型的请求。对于
- 网络层(核心封装与寻路):
- IP 头封装:这是数据包“穿上外套”的关键步骤。内核会创建一个 IP 头部,填入所有必要信息,如源/目的IP、协议类型和 TTL(生存时间)。
- MTU 检查:在封装后,内核会检查整个数据包的大小是否超过了出口网卡的最大传输单元(MTU)。如果超过了,就需要将一个大包分割成多个小包(IP分片)才能发送。
- 路由决策:这是数据包的“导航”步骤。内核查询自己的路由表,就像查地图一样,找到去往目标 IP 的最佳路径。查询结果会告诉它:
- 应该从哪个物理网卡(出口网卡)把包发出去。
- 应该把包发给谁(下一跳网关),通常是局域网内的路由器或运营商的设备。
完成这三步后,一个结构完整的 IP 数据包就准备好了,接下来它将被交给数据链路层进行最后的封装(添加 MAC 地址)并发送到物理网络中。
第四步:iptables OUTPUT链(出站处理)
数据包进入OUTPUT链,按“raw→mangle→nat→filter”的表顺序处理:
- raw表处理:可设置
NOTRACK,禁止conntrack跟踪此连接。 - mangle表处理:修改数据包属性(如TOS、MARK),或进行流量控制。
- nat表处理(SNAT/MASQUERADE):
- 若本机是NAT网关(内网主机通过本机上网),则通过SNAT修改
源IP为外网网卡IP(如iptables -t nat -A OUTPUT -s 192.168.1.0/24 -j SNAT --to-source 203.0.113.10)。 - 若外网IP是动态获取(如拨号上网),用MASQUERADE自动适配IP(
iptables -t nat -A OUTPUT -s 192.168.1.0/24 -j MASQUERADE)。 - 若为本地应用(如本机ping百度),源IP已为外网IP,无需SNAT。
- 若本机是NAT网关(内网主机通过本机上网),则通过SNAT修改
- filter表处理:
- 匹配OUTPUT链的filter规则,允许或拒绝数据包。本场景默认策略是ACCEPT,所以直接通过。
图解说明:
- 入口:在内核确定了数据包的路由(即从哪个网卡发出)之后,数据包被送入
OUTPUT链。这是专门为本机进程生成的出站流量设计的关卡。 - raw & mangle 表:与
PREROUTING和INPUT链类似,数据包首先经过raw表(决定是否进行连接跟踪)和mangle表(修改数据包元数据)。 - nat 表(核心功能:SNAT):
- 这是
OUTPUT链中最关键的一步,用于处理源地址转换(Source Network Address Translation)。 - 判断是否需要SNAT:
- 需要:最常见的场景是,本机作为一台路由器或网关,内网的其他机器通过它来上网。此时,来自内网的、源地址为私有IP(如
192.168.1.x)的数据包,必须将其源地址“伪装”成本机的公网IP,否则外部网络将无法回应。- 如果公网IP是固定的,使用
SNAT。 - 如果公网IP是动态变化的(如家庭宽带拨号),则使用
MASQUERADE,它能自动获取当前出口的IP地址来进行转换。
- 如果公网IP是固定的,使用
- 不需要:在本机直接
ping百度这种场景下,内核在第三步(网络层封装)时就已经将数据包的源IP设置为出口网卡的公网IP。因此,在这里无需进行任何地址转换。
- 需要:最常见的场景是,本机作为一台路由器或网关,内网的其他机器通过它来上网。此时,来自内网的、源地址为私有IP(如
- 这是
- filter 表:
- 这是出站数据包的最后一道防火墙检查。你可以设置规则来限制本机上的某些应用程序访问外部网络(例如,禁止某个程序访问互联网)。
- 在许多服务器配置中,为了简化管理,对出站流量的限制较少,默认策略通常是
ACCEPT,意味着除非有明确的DROP规则,否则所有出站包都被允许。
通过 OUTPUT 链的检查和处理后,数据包就准备好进入最后一个环节 POSTROUTING 链了。
第五步:连接跟踪(conntrack)和POSTROUTING
nf_conntrack模块记录此连接,标记为NEW状态(ping的第一个ICMP请求包),后续的请求包标记为ESTABLISHED。- 若启用了NAT,conntrack会记录“原始IP/端口”与“NAT后IP/端口”的映射关系,以便后续接收响应包时还原。
好的,这是根据您提供的“第五步:连接跟踪(conntrack)”出站流程的描述,为您绘制的详细Mermaid图。
此图清晰地展示了 conntrack 模块如何为出站连接建立状态记录,特别是当涉及到 NAT 时的关键映射关系。
图解说明:
- 入口:当数据包通过了
OUTPUT链的过滤和可能的地址转换后,它会经过conntrack模块。 - 状态判断:
- 新连接:对于一个新发起的连接(比如
ping命令的第一个 ICMP 请求包),conntrack会为其创建一个全新的状态记录,并标记为NEW。 - 现有连接:对于该连接的后续数据包,
conntrack只需找到已有的记录并将其状态更新为ESTABLISHED即可。
- 新连接:对于一个新发起的连接(比如
- NAT 映射记录(核心):
- 这是
conntrack在出站流程中至关重要的一个功能。如果在之前的OUTPUT链中,数据包的源 IP 地址被SNAT或MASQUERADE修改了,conntrack必须像一个细心的记账员,精确地记录下这个“转换关系”。 - 它会记下:“原始的私网IP A 和端口 X” 对应 “被转换后的公网IP B 和端口 Y”。
- 这个记录是双向通信能够成功的关键。没有这个记录,当服务器的响应包返回时,防火墙将不知道应该将这个包转发给内网的哪台机器。
- 这是
- 出口:完成状态记录后,数据包带着它的状态信息,继续前往
iptables的最后一站:POSTROUTING链。
您完全正确,POSTROUTING 链是出站流程中至关重要、不可或缺的一环,我非常抱歉在之前的流程中遗漏了它。它是数据包离开 Netfilter 之前的最后一个关卡。
下面我为您详细补充出站流程的第六步 POSTROUTING 链,并提供相应的解释和 Mermaid 图。
补充:出站流程:iptables POSTROUTING 链
在内核确定了数据包的路由,并且数据包已经通过了 OUTPUT 链(本地发出)或 FORWARD 链(转发)之后,它在被交给数据链路层进行帧封装之前,必须经过 POSTROUTING 链。
这是 Netfilter 对一个即将离开本机的数据包进行修改的最后机会。
POSTROUTING 链按“mangle→nat”的表顺序处理:
-
mangle 表处理:
- 与其它链中的
mangle表功能一致,它提供了最后一次修改数据包属性(如 TOS、TTL、MARK)的机会。这通常用于一些高级的流量控制或策略路由场景。
- 与其它链中的
-
nat 表处理(核心功能:SNAT / MASQUERADE):
- 这是
POSTROUTING链最核心、最常用的功能。 几乎所有的源地址转换(SNAT)都在这里完成。 - 为什么在这里做 SNAT? 因为直到这一步,内核才百分之百地确定了数据包将从哪个出口网卡(
Iface)离开。OUTPUT链在路由决策之后,但POSTROUTING在路由决策的最终确认之后。对于被转发的流量(从FORWARD链过来),这是唯一能进行 SNAT 的地方,因为它需要知道出口网卡的 IP 来做地址伪装。 - 场景一(本机是网关):从内网(如
192.168.1.0/24)转发过来的数据包,其源 IP 是私网 IP。在POSTROUTING链,nat表会根据SNAT或MASQUERADE规则,将其源 IP 地址修改为路由器的公网 IP 地址。 - 场景二(本机应用出站):虽然
OUTPUT链的nat表也能做 SNAT,但将所有 SNAT 规则统一放在POSTROUTING链是更常见、更规范的做法,这样可以集中管理所有离开本机(无论是本地产生还是转发)的流量的地址转换策略。
- 这是
POSTROUTING 链的 Mermaid 图
这张图清晰地展示了 POSTROUTING 链在整个流程中的位置和其内部处理逻辑。
总结与解释
POSTROUTING 链就像是网络出口的最后一个“化妆师”和“安检员”。
- 化妆师 (SNAT):它负责为需要“伪装”的数据包(主要是来自内网的包)换上一个公网的“面具”(源 IP 地址),这样它们才能在互联网上正常通信和接收回复。
- 安检员 (mangle):它进行最后的检查和标记,确保数据包带着正确的“身份标识”(TOS、MARK 等)离开。
一旦数据包通过了 POSTROUTING 链,它在 IP 层的形态就最终确定了。接下来,它将被完整地交给数据链路层,封装成以太网帧,最终通过物理网卡发送出去。
第六步:数据链路层封装(ARP解析+帧封装)
- ARP解析网关MAC:
- 路由决策确定网关为203.0.113.1,内核查询ARP缓存(
arp -n),若没有网关的MAC地址,则发送ARP广播(“谁是203.0.113.1?请回复MAC”)。 - 网关收到ARP请求后,回复自己的MAC地址,本机将“网关IP→MAC”存入ARP缓存(默认超时120秒)。
- 路由决策确定网关为203.0.113.1,内核查询ARP缓存(
- 以太网帧封装:
- 内核添加以太网帧头,
目的MAC为网关的MAC地址,源MAC为eth0的MAC地址,帧类型为“IP协议(0x0800)”。 - 添加帧尾FCS校验码。
- 内核添加以太网帧头,
展示了 IP 数据包在发送到物理网络之前的最后两个关键步骤:找到下一跳的“物理地址”(MAC),以及如何将数据包打包成一个完整的“快递包裹”(以太网帧)。
图解说明:
-
ARP 解析(问路过程):
- IP 地址是逻辑地址,用于在整个互联网上寻址,但数据在局域网(如以太网)中传输时,设备之间是依靠物理地址(MAC 地址)来识别对方的。
- 内核知道要把包发给网关(IP:
203.0.113.1),但它需要知道这个 IP 对应的网卡的物理 MAC 地址。 - 先查缓存:为了效率,内核会先查自己的 “ARP 缓存” 小本本,看看之前是否问过这个 IP 的 MAC 地址。
- 缓存命中:如果查到了,就直接使用。
- 缓存未命中:如果没查到,内核就会在局域网里“大喊一声”(发送 ARP 广播):“谁的 IP 是
203.0.113.1?快把你的 MAC 地址告诉我!” - 获取并记录:网关设备听到广播后,会“私聊”回复(单播 ARP 应答)它的 MAC 地址。内核收到后,赶紧记在 ARP 缓存里,方便下次使用,然后进行下一步。
-
以太网帧封装(打包过程):
- 一旦知道了下一跳的 MAC 地址,内核就开始了“打包”工作。
- 贴上快递单(帧头):
- 收件人地址 (
目的MAC):这里填的是网关的 MAC 地址,而不是最终目的地的 MAC 地址。因为在局-域网内,数据是先发给网关,由网关再转发出去。 - 寄件人地址 (
源MAC):本机网卡的 MAC 地址。 - 包裹内容说明 (
类型):告诉接收方,这个数据帧里面装的是一个 IP 数据包。
- 收件人地址 (
- 放入货物(数据):将之前构建好的整个 IP 数据包(包含了 ICMP 数据)放进去。
- 封箱胶带(帧尾):在最后加上 FCS 校验码,用于接收方检查数据在传输过程中是否出错。
至此,一个可以在物理链路上传输的数据帧就完全准备好了,它将被送往网卡,转换成电信号或光信号,踏上真正的网络之旅。
第七步:网卡发送数据包
- 网卡驱动将以太网帧转换为电信号,通过网线发送到网关,网关再转发到互联网,最终到达百度服务器。
- 百度服务器的响应包(ICMP应答)会按“入站流程”返回本机,被conntrack识别为
ESTABLISHED状态,通过INPUT链的ESTABLISHED规则被允许,最终交给ping应用程序,显示“64 bytes from 180.101.49.11: icmp_seq=1 ttl=56 time=10ms”。
好的,当然可以。下面我将为您详细说明 conntrack 的几种主要状态,并绘制一个状态转换的 Mermaid 图,最后结合您提供的第七步来解释这个过程。
Conntrack 的主要连接状态
连接跟踪(conntrack)是 Netfilter 的核心功能,它为通过防火墙的每个连接维护一个状态记录。理解这些状态对于编写高效且安全的防火墙规则至关重要。
-
NEW- 说明:表示一个新连接的第一个数据包。当系统看到一个不属于任何现有连接的数据包,并且该数据包是合法的连接发起包时,就会将其标记为
NEW。 - 示例:
- TCP 连接的第一个
SYN包。 - 一个 UDP 连接(无状态协议)的第一个数据包。
ping命令发出的第一个 ICMPecho-request包。
- TCP 连接的第一个
- 说明:表示一个新连接的第一个数据包。当系统看到一个不属于任何现有连接的数据包,并且该数据包是合法的连接发起包时,就会将其标记为
-
ESTABLISHED- 说明:表示一个已经建立并正在进行双向通信的连接。一旦初始的
NEW状态数据包得到了合法的响应,连接状态就会变为ESTABLISHED。 - 示例:
- TCP 三次握手完成后,后续的所有数据传输包(包括客户端的 ACK 和服务器的 SYN-ACK)。
- 收到了对第一个 UDP 包的响应包之后,后续的双向 UDP 通信。
- 收到了对 ICMP
echo-request的echo-reply响应包。这正是您在第七步中描述的场景。
- 说明:表示一个已经建立并正在进行双向通信的连接。一旦初始的
-
RELATED- 说明:表示一个与现有
ESTABLISHED连接相关联的新连接。这种状态比较特殊,通常用于那些需要“辅助连接”的复杂协议。 - 示例:
- FTP 协议:控制连接在 21 端口是
ESTABLISHED的,当需要传输文件时,会协商一个新的端口来建立数据连接,这个新的数据连接就是RELATED。 - ICMP 错误消息:当一个
ESTABLISHED的 UDP 连接收到一个 ICMP “Port Unreachable” 的错误回报时,这个 ICMP 包的状态就是RELATED。
- FTP 协议:控制连接在 21 端口是
- 说明:表示一个与现有
-
INVALID- 说明:表示一个无法识别或格式不正确的数据包。它不属于任何已知连接,也不是一个合法的新连接发起包。这些数据包通常应该被丢弃,因为它们可能是网络攻击的迹象或网络故障。
- 示例:
- 收到了一个没有对应连接的 TCP
ACK包。 - 数据包的校验和错误。
- 收到了一个没有对应连接的 TCP
-
UNTRACKED- 说明:这是一个特殊状态,表示数据包被明确地从连接跟踪中豁免了。这通常是在
raw表中使用-j NOTRACK目标来实现的,用于对性能要求极高且不需要状态化检查的流量(如高负载均衡器的心跳检查)。
- 说明:这是一个特殊状态,表示数据包被明确地从连接跟踪中豁免了。这通常是在
Conntrack 状态转换
这是一个状态机图,展示了连接如何在这些状态之间转换:
结合第七步进行说明
第七步中描述的场景完美地诠释了这个状态转换过程:
ping发出请求:当您的主机第一次向百度服务器发送 ICMPecho-request时,conntrack模块会检查连接跟踪表。由于这是第一个包,它会创建一个新条目,并将此连接的状态标记为NEW。- 百度服务器返回响应:当百度的 ICMP
echo-reply响应包返回到您的主机时,conntrack再次检查。它发现这个响应包与刚才那个NEW状态的连接是匹配的。 - 状态变为 ESTABLISHED:
conntrack确认这是一个合法的响应,于是将该连接的状态更新为ESTABLISHED。 - 防火墙高效放行:当这个
ESTABLISHED状态的响应包到达INPUT链时,它会非常快速地匹配到iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT这类规则,从而被立即放行,无需再经过后面更复杂的端口、IP 检查。最终,这个响应包被交给ping程序,您便在屏幕上看到了延迟信息。
这个机制是所有状态化防火墙能够兼顾安全与性能的基石。
场景3:转发数据包(本机作为路由器,内网→外网)
假设内网主机(192.168.1.100)通过本机(eth1:192.168.1.1,eth0:203.0.113.10)访问外网百度(180.101.49.11),本机开启IP转发(net.ipv4.ip_forward=1),处理流程如下:
第一步:内网主机发送数据包到本机eth1网卡
- 内网主机192.168.1.100的数据包(源IP:192.168.1.100,目的IP:180.101.49.11,协议:TCP,目的端口:80)通过网线到达本机eth1网卡。
- 数据链路层处理:eth1网卡校验帧的MAC地址(目的MAC是eth1的MAC),解封装后交给网络层。
第二步:网络层+PREROUTING链+conntrack(同场景1的第二→第四步)
- IP头校验、分片处理,进入PREROUTING链的raw→mangle→nat表(无DNAT则不修改)。
- conntrack标记连接为
NEW状态,记录源IP、目的IP、端口等信息。
第三步:路由决策(转发判定)
- 内核查询路由表,目的IP 180.101.49.11不属于本机,也不属于内网,路由决策结果为“需要转发”,数据包进入
FORWARD链。
第四步:iptables FORWARD链(转发过滤)
数据包进入FORWARD链,按“mangle→filter”的表顺序处理:
- mangle表处理:修改数据包属性(如TTL递减1,避免环路)。
- filter表处理:
- 匹配FORWARD链的规则,允许转发则继续,否则丢弃。例:
iptables -A FORWARD -i eth1 -o eth0 -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT(允许内网→外网的新连接及相关连接)。 - 若未匹配允许规则,被默认策略DROP,转发失败。
- 匹配FORWARD链的规则,允许转发则继续,否则丢弃。例:
图解说明:
-
入口:当一个数据包的目的地不是本机,但本机知道如何将它发送到目的地时,路由决策就会将这个包送入
FORWARD链。这是所有“路过”本机流量的必经之路。 -
mangle 表:
- 在转发场景下,一个非常重要的默认动作就是将数据包的 TTL(Time To Live,生存时间)减 1。TTL 是一个计数器,数据包每经过一个路由器,该值就减 1。当 TTL 减到 0 时,数据包就会被丢弃。这个机制可以有效防止数据包在网络中因路由配置错误而无限循环,从而耗尽网络资源。
-
filter 表(核心安检站):
FORWARD链的filter表是实现网络安全策略的核心。它决定了什么样的数据流可以穿过这台路由器。- 规则匹配:与
INPUT链一样,规则是顺序匹配,首次匹配即生效。 - 常见的转发规则:
iptables -P FORWARD DROP:首先,将默认策略设置为DROP。这是一个安全的基准,意味着“所有未经明确允许的转发都是禁止的”。iptables -A FORWARD -i eth1 -o eth0 -m state --state ESTABLISHED,RELATED -j ACCEPT:允许所有从外网(eth0)到内网(eth1)的、属于已建立连接的响应包通过。这是保证内网用户能够正常上网的关键。iptables -A FORWARD -i eth0 -o eth1 -j ACCEPT:允许所有从内网(eth0)到外网(eth1)的主动连接请求通过。
- 结果:
- 如果数据包匹配了
ACCEPT规则,它就会被放行,继续前往POSTROUTING链。 - 如果数据包没有匹配任何
ACCEPT规则,它就会被默认的DROP策略无情地丢弃,转发失败。
- 如果数据包匹配了
通过 FORWARD 链的精细控制,Linux 主机可以扮演一个强大而灵活的路由器和防火墙角色。
第五步:POSTROUTING链(SNAT/MASQUERADE)
- 数据包通过FORWARD链后,进入
POSTROUTING链,按“mangle→nat”的表顺序处理:- mangle表:最后一次修改数据包属性(如流量标记)。
- nat表(SNAT核心):修改数据包的
源IP为外网网卡eth0的IP(203.0.113.10),让外网服务器认为请求来自本机。例:iptables -t nat -A POSTROUTING -o eth0 -j SNAT --to-source 203.0.113.10。 - 注意:SNAT必须在POSTROUTING链(路由决策之后),因为只有确定了出口网卡,才能知道要替换的源IP。
好的,我们来完成转发流程的最后关键一步。当数据包成功通过 FORWARD 链的“安检”后,就来到了离开防火墙前的最后一个“化妆间”——POSTROUTING 链。
图解说明:
-
入口:通过了
FORWARD链审查的数据包,现在进入了它在 Netfilter 旅程的最后一站——POSTROUTING。 -
mangle 表:提供最后一次修改数据包元数据的机会。虽然不常用,但在需要基于最终出口网卡信息做一些高级标记时会很有用。
-
nat 表(SNAT 的主场):
- 核心功能:这几乎是
POSTROUTING链存在的唯一理由——执行源地址转换(SNAT)。 - “伪装”:它将来自内网的、使用私有 IP 地址的数据包的“发件人地址”撕掉,换上一个新的、公网可见的“发件人地址”(即路由器
eth0网卡的公网 IP)。 - 为什么必须在这里? 这是整个
iptables流程设计中最巧妙的一点。内核必须首先完成路由决策(即,决定这个包应该从eth0网卡发出去,而不是eth2或者其它网卡),然后才能知道应该把源地址换成哪个网卡的 IP。POSTROUTING正是处在“路由决策已定,但尚未进行物理层封装”的完美时机。 - conntrack 的角色:执行 SNAT 的同时,
conntrack模块会 diligently 记录下这个地址转换关系(192.168.1.100:port_A<->203.0.113.10:port_B)。当外部服务器的响应包回来时,conntrack会根据这个记录,在PREROUTING链自动地、反向地将目标地址从公网 IP 换回原来的内网 IP,从而确保数据能准确送达内网的原始主机。
- 核心功能:这几乎是
一旦数据包完成了 POSTROUTING 链的处理,它在 IP 层的形态就最终定型了。接下来,它将被完整地交给数据链路层,封装成以太网帧,最终踏上前往互联网的旅程。
第六步:数据链路层封装+发送(同场景2的第六→第七步)
- ARP解析外网网关(203.0.113.1)的MAC地址,封装以太网帧,通过eth0网卡发送到网关,最终转发到百度服务器。
第七步:百度响应包的转发流程
- 百度的响应包(源IP:180.101.49.11,目的IP:203.0.113.10)按“入站流程”到达本机eth0网卡。
- PREROUTING链:conntrack根据连接跟踪表,识别该数据包是“已建立连接的响应”,自动将目的IP还原为内网主机192.168.1.100(NAT反向映射)。
- 路由决策:目的IP是内网192.168.1.100,进入FORWARD链,匹配
ESTABLISHED,RELATED规则被允许。 - POSTROUTING链:无额外处理,封装帧后通过eth1网卡发送到内网主机192.168.1.100,完成转发。
核心总结:三大场景的关键差异与共性
共性流程
- 数据包始终以
sk_buff为载体,贯穿内核协议栈。 - iptables的处理顺序:raw→mangle→nat→filter(不同链的表生效范围不同)。
- conntrack在raw表之后、其他表之前工作,为状态匹配提供依据。
- 路由决策是“分流关键”:决定数据包走INPUT、FORWARD还是OUTPUT链。
关键差异
| 场景 | 核心链路 | NAT作用 | 路由决策结果 |
|---|---|---|---|
| 入站 | PREROUTING→INPUT | DNAT(端口映射) | 发给本机 |
| 出站 | OUTPUT→POSTROUTING | SNAT(本地应用无需求) | 从本机发出 |
| 转发 | PREROUTING→FORWARD→POSTROUTING | SNAT(内网→外网) | 需要转发(跨网卡) |
不可忽视的细节
- 本地回环(127.0.0.1):数据包不经过物理网卡,直接在内核协议栈内循环,处理流程为“应用→OUTPUT链→lo网卡→INPUT链→应用”,无需路由和ARP。
- TCP状态处理:三次握手的SYN包标记为NEW,SYN-ACK标记为ESTABLISHED,FIN包标记为TIME_WAIT,conntrack会跟踪连接生命周期(默认超时:TCP 120秒,UDP 30秒)。
- iptables规则顺序:按添加顺序匹配,一旦命中动作则停止,因此“具体规则”需在“宽泛规则”之前(如允许22端口的规则在拒绝所有TCP规则之前)。
好的,您提到了一个非常特殊且重要的网络通信场景——本地回环(Loopback)。这是一种纯粹在内核中完成的数据交换,效率极高。
下面是根据您的描述,为您绘制的本地回环通信的详细 Mermaid 流程图和解释。
本地回环(127.0.0.1)通信流程
图解详细说明
本地回环通信是本机进程间通信(IPC)的一种高效方式,其流程被大大简化:
-
应用层发起:
- 一个应用程序(客户端进程)像访问远程主机一样,向
127.0.0.1(或localhost)的一个特定端口发起请求。
- 一个应用程序(客户端进程)像访问远程主机一样,向
-
进入
OUTPUT链:- 数据包被创建并进入内核,首先经过
OUTPUT链。这意味着,即便是本地回环流量,也受iptablesOUTPUT链规则的管控。例如,您可以设置一条规则来阻止本机某个程序访问本机的另一个服务。
- 数据包被创建并进入内核,首先经过
-
内核“短路”(Loopback):
- 在
OUTPUT链之后,内核进行路由判断。当它发现数据包的目的地址是127.0.0.1时,它会识别出这是一个“自己发给自己”的特殊情况。 - 此时,数据包不会被发送到
POSTROUTING链,更不会被交给数据链路层去进行 ARP 解析或以太网帧封装。 - 取而代之的是,内核通过一个高效的内部路径,将这个数据包直接“绕回”或“短路”到网络协议栈的接收端。这个绕回的逻辑接口就是
lo(Loopback)虚拟网卡。
- 在
-
进入
INPUT链:- 被绕回的数据包,现在就像一个从外部网络进来的数据包一样,出现在了
INPUT链的入口。 - 这意味着,
iptables的INPUT链规则同样对本地回环流量生效。您可以设置规则来过滤哪些端口允许被本机访问。
- 被绕回的数据包,现在就像一个从外部网络进来的数据包一样,出现在了
-
到达目标应用:
- 数据包通过
INPUT链的检查后,被内核递交给正在监听相应端口的应用程序(服务端进程)。
- 数据包通过
总结:
本地回环流量的整个旅程都在内核的“高速公路”上完成,从未进入过物理世界的“普通公路”(物理网卡和网络介质)。它只走了 OUTPUT 和 INPUT 这两个 Netfilter 关卡,跳过了所有与外部通信相关的复杂步骤,因此速度非常快,是测试网络服务或在本机部署客户端/服务端架构的理想选择。

被折叠的 条评论
为什么被折叠?



