使用SOCK_RAW套接字类型和AF_INET协议族时的混淆,与使用SOCK_DGRAM和SOCK_RAW套接字类型的AF_PACKET协议族的区别。

8

我是一名新手网络编程,已经花费了相当长的时间来理解这个问题。在浏览了互联网上无数的资源之后,我得出了以下结论,接着是我的困惑。

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

s = socket(AF_INET, SOCK_RAW, 0);

我们基本上是要创建一个原始套接字。通过这种方式创建的原始套接字可以绕过OSI堆栈中的TCP/UDP层。也就是说,当应用程序通过此套接字接收数据包时,该应用程序将拥有包含网络层(第3层)头部包装实际数据的第2层头部的数据包。因此,应用程序可以自由地处理此数据包,超越第3层,并以任何方式进行处理。
同样,当通过此套接字发送数据包时,应用程序也可以自由处理数据包的创建,直到第4层,然后将其传递到第3层,从此处开始内核将处理事务。
结论2:当我们谈论创建套接字时:
s = socket(AF_PACKET, SOCK_RAW, 0);

我们再次尝试创建一个原始套接字。通过这种方式创建的原始套接字将能够完全绕过OSI的所有层。用户应用程序可以获得纯粹的原始数据包,并且可以自由地对该数据包进行任何操作。通过这样的套接字接收到的数据包将保留所有标头,应用程序也可以访问所有这些标头。
同样,在使用这样的套接字发送数据时,用户应用程序需要处理有关创建数据包以及将实际数据与每个层的标头包装起来的所有内容,然后才能将其放置在物理介质上进行传输。
结论3:当我们谈论创建套接字时:
s = socket(AF_PACKET, SOCK_DGRAM, 0);

我们再次尝试创建原始套接字。通过这种方式创建的原始套接字,可以绕过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/

{{link1:'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

1个回答

2

你已经接近他们的真实解释了。这里我有一些东西告诉你,我认为你可能遗漏或错误的地方。

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

其次,s = socket(AF_PACKET, SOCK_RAW, 0);

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

第三,对于s = socket(AF_PACKET, SOCK_DGRAM, 0);的情况,你的结论是正确的。在这种类型的数据包套接字中,您不需要考虑Ethernet头。它比前一种类型高一层。

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

  1. 原始套接字访问:

| 第3层头 | 第4层头 | 负载 |

  1. 数据包套接字访问:

| 第2层头 | 第3层头 | 第4层头 | 负载 | 第2层尾部 |


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接