TCP如何在多路分解中读取IP地址?
How can the TCP read the IP address in demultiplexing?
大多数计算机网络书籍在解释 TCP/IP 堆栈时都提到:当一个层收到其 PDU(无论是帧还是段...)时,执行以下操作:
- 检查字段,做一些事情并决定是否将消息传递到它上面的层。
- 如果该层决定将消息传递到它上面的层,则上面的层将在(移除上一层 header )之后再次执行相同的前一步。
如果这是真的,那么问题来了:TCP 如何知道源 IP 地址(网络层 header 中的地址),它将用于将段移动到它们适当的套接字。
提前致谢!
他们在(介绍性)教科书中所说的关于网络堆栈中数据包遍历的内容只是教学。如果我们看一下它是如何实现的,就会复杂得多。让我们考虑一下 Linux。
- Harald Welte 的文章 The journey of a packet through the Linux 2.4 network stack 总结了不同阶段的数据包遍历。
我引用文章的相关部分来回答你的问题。
IP 数据包处理程序通过从 net/ipv4/ip_output.c:ip_init() 调用的 net/core/dev.c:dev_add_pack() 进行注册。
IPv4包处理函数是net/ipv4/ip_input.c:ip_rcv()。经过一些初始检查(如果数据包是针对该主机的,...)计算 ip 校验和。对长度和 IP 协议版本 4 进行了额外检查。此时将丢弃未通过其中一项健全性检查的每个数据包。
遍历成功后,调用net/ipv4/ipv_input.c:ip_rcv_finish()。在 ip_rcv_finish() 内部,数据包的目的地是通过调用路由函数 net/ipv4/route.c:ip_route_input() 来确定的。此外,如果我们的 IP 数据包有 IP 选项,它们现在会被处理。根据 net/ipv4/route.c:ip_route_input_slow() 做出的路由决定,我们的数据包的旅程在以下功能之一中继续:
net/ipv4/ip_input.c:ip_local_deliver() :数据包的目的地是本地的,我们必须处理第 4 层协议并将其传递给用户空间进程。
net/ipv4/ip_forward.c:ip_forward() : 数据包的目的地不是本地的,我们必须将它转发到另一个网络
net/ipv4/route.c:ip_error() :发生错误,我们无法为该数据包找到合适的路由 table 条目。
net/ipv4/ipmr.c:ip_mr_input() :这是一个多播数据包,我们必须做一些多播路由。
注意: 跳过了一些与 Netfilter 挂钩相关的遍历阶段。所有阶段请参考原文
net/ipv4/in_input.c:ip_local_deliver()
是我们感兴趣的函数。如上所述,它处理第 4 层协议并将其传递给用户空间。从 Linux 内核代码中可以看出它是如何实现的,简而言之,假设 ip_local_deliver()
了解第 3 层细节并没有什么坏处。
大多数计算机网络书籍在解释 TCP/IP 堆栈时都提到:当一个层收到其 PDU(无论是帧还是段...)时,执行以下操作:
- 检查字段,做一些事情并决定是否将消息传递到它上面的层。
- 如果该层决定将消息传递到它上面的层,则上面的层将在(移除上一层 header )之后再次执行相同的前一步。
如果这是真的,那么问题来了:TCP 如何知道源 IP 地址(网络层 header 中的地址),它将用于将段移动到它们适当的套接字。
提前致谢!
他们在(介绍性)教科书中所说的关于网络堆栈中数据包遍历的内容只是教学。如果我们看一下它是如何实现的,就会复杂得多。让我们考虑一下 Linux。
- Harald Welte 的文章 The journey of a packet through the Linux 2.4 network stack 总结了不同阶段的数据包遍历。
我引用文章的相关部分来回答你的问题。
IP 数据包处理程序通过从 net/ipv4/ip_output.c:ip_init() 调用的 net/core/dev.c:dev_add_pack() 进行注册。
IPv4包处理函数是net/ipv4/ip_input.c:ip_rcv()。经过一些初始检查(如果数据包是针对该主机的,...)计算 ip 校验和。对长度和 IP 协议版本 4 进行了额外检查。此时将丢弃未通过其中一项健全性检查的每个数据包。
遍历成功后,调用net/ipv4/ipv_input.c:ip_rcv_finish()。在 ip_rcv_finish() 内部,数据包的目的地是通过调用路由函数 net/ipv4/route.c:ip_route_input() 来确定的。此外,如果我们的 IP 数据包有 IP 选项,它们现在会被处理。根据 net/ipv4/route.c:ip_route_input_slow() 做出的路由决定,我们的数据包的旅程在以下功能之一中继续:
net/ipv4/ip_input.c:ip_local_deliver() :数据包的目的地是本地的,我们必须处理第 4 层协议并将其传递给用户空间进程。
net/ipv4/ip_forward.c:ip_forward() : 数据包的目的地不是本地的,我们必须将它转发到另一个网络
net/ipv4/route.c:ip_error() :发生错误,我们无法为该数据包找到合适的路由 table 条目。
net/ipv4/ipmr.c:ip_mr_input() :这是一个多播数据包,我们必须做一些多播路由。
注意: 跳过了一些与 Netfilter 挂钩相关的遍历阶段。所有阶段请参考原文
net/ipv4/in_input.c:ip_local_deliver()
是我们感兴趣的函数。如上所述,它处理第 4 层协议并将其传递给用户空间。从 Linux 内核代码中可以看出它是如何实现的,简而言之,假设 ip_local_deliver()
了解第 3 层细节并没有什么坏处。