与AF_INET混淆,以SOCK_RAW为socket类型,V/S AF_PACKET,以SOCK_DGRAM和SOCK_RAW为socket类型

qre*_*0ct 6 unix sockets networking tcp

我对网络编程很陌生,并且已经尝试解决这个问题已经有一段时间了。在浏览了互联网上的大量资源后,我得出了以下结论并随之而来的困惑。

结论 1: 当我们谈论创建套接字时:

s = socket(AF_INET, SOCK_RAW, 0);
Run Code Online (Sandbox Code Playgroud)

我们基本上是在尝试创建一个原始套接字。通过以这种方式创建的原始套接字,人们将能够绕过 OSI 堆栈中的 TCP/UDP 层。意思是,当应用程序通过此套接字接收数据包时,应用程序将使包含网络层(第 3 层)标头的数据包包装第 2 层标头,从而包装实际数据。所以应用程序可以自由地处理这个数据包,超出第 3 层,以任何方式。

类似地,当也通过这个套接字发送数据包时,应用程序可以自由地处理数据包的创建,直到第 4 层,然后将其向下传递到第 3 层,内核将从该点开始处理事情。

结论 2:当我们谈论创建套接字时:

s = socket(AF_PACKET, SOCK_RAW, 0);
Run Code Online (Sandbox Code Playgroud)

我们再次尝试创建一个原始套接字。通过以这种方式创建的原始套接字,人们将能够完全绕过 OSI 的所有层。一个纯粹的原始数据包可供用户应用程序使用,并且可以自由地使用该数据包做任何它想做的事情。通过此类套接字接收的数据包将具有完整的所有标头,并且应用程序也可以访问所有这些标头。

类似地,当也通过这样的套接字发送数据时,用户应用程序必须处理与数据包的创建有关的所有事情,以及在实际放置数据之前用每一层的标头包装实际数据在要传输的物理介质上。

结论 3:当我们谈论创建套接字时:

s = socket(AF_PACKET, SOCK_DGRAM, 0);
Run Code Online (Sandbox Code Playgroud)

我们再次尝试创建一个原始套接字。通过以这种方式创建的原始套接字,人们将能够绕过 OSI 堆栈中的数据链路层(第 2 层)。这意味着,当用户陆地应用程序接收到通过此类套接字的数据包时,将从数据包中删除数据链路层标头。

类似地,当通过此套接字发送数据包时,根据 sockaddr_ll 目标地址中的信息,将合适的数据链路层标头添加到数据包中。

下面是我的疑问/困惑点:

  1. 我上面关于原始套接字的结论是否正确?
  2. 上面的结论3我不是很清楚。有人可以解释一下吗?就像,这是否意味着当用户土地应用程序通过此套接字接收数据包时,内核将只处理数据链路层标头?因此,数据包就像直接用第 3 层标头包装并随后由它上面的层包装的消息一样?
  3. 如果上面得出的结论是正确的,那么结论 1结论 2仍然有意义。但是,如果上面的结论 3(以及上面 2 中围绕它的推测)是正确的,那么任何应用程序究竟何时需要这样做?

我为了理解上述内容而提到的一些资源:

https://docs.freebsd.org/44doc/psd/21.ipc/paper.pdf

https://sock-raw.org/papers/sock_raw

https://www.quora.com/in/Whats-the-difference-between-the-AF_PACKET-and-AF_INET-in-python-socket

http://www.linuxcertif.com/man/7/PF_PACKET/

http://opensourceforu.com/2015/03/a-guide-to-using-raw-sockets/

“socket”系统调用中的“SOCK_RAW”选项

http://stevendanna.github.io/blog/2013/06/23/a-short-sock-raw-adventure/

https://www.intervalzero.com/library/RTX/WebHelp/Content/PROJECTS/Application%20Development/Understanding_Network/Using_RAW_Sockets.htm

Mat*_*een 2

你已经非常接近他们的真实解释了。在这里,我有一些事情要告诉你我认为你遗漏或错误的事情。

首先,对于s = socket(AF_INET, SOCK_RAW, 0);,当通过此类套接字接收数据包时,它将始终包含 IP 标头。如果未启用IP_HDRINCL,则发送时,数据包必须包含 IP 标头,TCP/IP 堆栈不会为您生成此标头。所有其他上层都可以通过该套接字接收。

第二,s = socket(AF_PACKET, SOCK_RAW, 0);

这是一种特殊类型的Raw Socket ,在Linux系统中称为Packet-socket 。这种类型的套接字允许在 OSI 第 2 层发送和接收数据包,这就是用于此类套接字的 API 被称为链路层 API的原因。通过使用此套接字,可以在物理层的顶部实现任何协议。有趣的是,我们还可以通过这个套接字与数据包的尾部进行交互,尽管我们并不经常需要。

第三,如果是s = socket(AF_PACKET, SOCK_DGRAM, 0);,你的结论是正确的。在这种类型的数据包套接字中,您不需要考虑以太网标头。它比以前的类型稍上一层。

因此,我们可以说这些类型的套接字之间的主要区别在于它们的访问可能性。总结一下:

  1. 原始套接字访问:

| Layer 3 header | Layer 4 header | Payload |

  1. 数据包套接字访问:

| Layer 2 header | Layer 3 header | Layer 4 header | Payload | Layer 2 trailer |