防止内核处理绑定到原始套接字的 TCP 段

Prevent kernel from processing TCP segments bound to a raw socket

根据 http://linux.die.net/man/7/rawraw_socket = socket(AF_INET, SOCK_RAW, int protocol); 是创建原始套接字的方式。

  1. 我假设 raw-sockets 是在第 3 层创建的,因此协议不应该是 IPPROTO_TCP / IPPROTO_UDP 但它应该是 IPPROTO_IP.这个理解对吗?

  2. 但是当我使用 IPPROTO_IP (*socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_IP);) 协议创建原始套接字时,套接字创建失败并显示错误 不支持协议

  3. 当我创建协议为 IPPROTO_RAW (*socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);) 的原始套接字时,我的应用程序没有收到任何数据包

  4. 当我创建协议为 IPPROTO_TCP (socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);) 的原始套接字时,我的应用程序接收到 TCP 数据包,但内核也响应这些数据包(在我的如果它 RSTs link)。我认为这是因为内核认为没有人在监听该数据包的目标端口。

我的意图只是使用假 IP 和 TCP header 发送对进入我的应用程序的消息的响应。由于上述 none 尝试对我有效,我应该如何创建原始套接字并使内核 TCP 层仅对该连接保持安静?

编辑: 请跳过问题 1-3。 Filipe 已经回答了他们。对于问题 4,我们确实有解决方法。但请保持问题开放,如果这里有人有答案并愿意回答。

以下link这里 http://www.tenouk.com/Module43a.html 从这个问题的答案中检索 Simple raw socket server in C/C++ on Linux 它建议您必须是 root 或 运行 作为 setuid0 才能使用原始套接字

/* Must be root or SUID 0 to open RAW socket */
...
 /* Create RAW socket */

   if((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0)

   {

    perror("socket() error");

    /* If something wrong, just exit */

    exit(1);

   }

I assume that raw sockets are created on layer-3 and so protocol shouldn't be IPPROTO_TCP / IPPROTO_UDP but it should be IPPROTO_IP. Is this understanding correct?

没有。你是对的,原始套接字基本上是第 3 层数据包,但协议不应该是 IPPROTO_IP。在原始套接字的情况下,协议参数指示您有兴趣在该套接字上接收哪种类型的数据包。请记住,协议本质上执行 transport-level 多路分解,因此您需要指定您的原始套接字感兴趣的协议类型。这在 man 7 raw:

中明确说明

All packets or errors matching the protocol number specified for the raw socket are passed to this socket. For a list of the allowed protocols see RFC 1700 assigned numbers and getprotobyname(3).

由于您对接收 TCP 连接的 IP 数据包感兴趣,因此您应该使用 IPPROTO_TCP

But when I create the raw socket with protocol as IPPROTO_IP (*socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_IP);), socket creation fails with the error Protocol not supported.

是的,这是可以预料的:IP 协议不是第 4 层协议。正如我所说,协议字段用于 transport-layer 多路分解,因此使用 IPPROTO_IP.

意义不大

When I create the raw socket with protocol as IPPROTO_RAW (*socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);), my application doesn't receive any of packets

那是因为IPPROTO_RAW意味着您有兴趣发送所有类型的协议数据包(TCP、UDP 或任何其他协议)。但是使用 IPPROTO_RAW 你不能做相反的事情:IPPROTO_RAW 意味着你可以在这个原始套接字中接收任何协议,这是不支持的。这在 man 7 raw:

中也有明确说明

A protocol of IPPROTO_RAW implies enabled IP_HDRINCL and is able to send any IP protocol that is specified in the passed header. Receiving of all IP protocols via IPPROTO_RAW is not possible using raw sockets.

换句话说,IPPROTO_RAW 赋予您发送匹配任何协议的数据包的能力,但代价是您永远得不到回复。作为变通方法,您可以创建与协议绑定的其他特定原始套接字以获得回复,但这会使设计复杂化,因为您必须管理原始套接字池,这绝对不是您想要在此处执行的操作。

When I create the raw socket with protocol as IPPROTO_TCP (socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);), my application receives the TCP packets, but kernel also responds to these packets (and in my case it RSTs the link). I assume it is because kernel thinks there isn't anybody listening to the port to which that packet is intended to.

您无法阻止内核执行其工作。来自原始套接字联机帮助页:

When a packet is received, it is passed to any raw sockets which have been bound to its protocol before it is passed to other protocol handlers (e.g., kernel protocol modules).

所以你是对的,内核发送了一个 RST 数据包,因为它不知道指定端口上的活动 TCP 套接字或连接。正如我所说,你不能阻止内核完成它的工作,但是一个相对快速(也许是丑陋)的 hack 是使用 iptables 丢弃 RST 数据包:

iptables -A OUTPUT -p tcp --tcp-flags RST RST -j DROP

是的,不是很优雅,但我认为我们在这里无能为力。

如评论中所建议,您还可以创建一个虚拟 TCP 套接字,绑定到您刚刚接收和丢弃消息的相同端口和地址。这样内核就不会发送 RST 回复,你也不需要搞乱 iptables。

还请记住,由于您需要为原始套接字指定 IPPROTO_TCP,因此您应该在带有 setsockopts(2) 的套接字上设置 IP_HDRINCL,以便您可以构建自定义 IP header.

最后,确保 运行 进程的有效用户 ID 为 0 或 CAP_NET_RAW 能力(实际上:运行 它是 root)。

[这是对 Jonathon Reinhart 的评论的评论,但我没有足够的声誉]

关于 AF-PACKET 插座

man packet 中描述了使用 AF_PACKET 创建原始套接字。 "protocol" 变量的值应该是网络字节顺序中的 ethertype 的值。这些值在 <linux/if_ether.h> 中定义(以主机字节顺序)。所以要打开一个原始套接字,你需要做

socketFd = socket ( AF_PACKET , SOCK_RAW , htons ( ETH_P_IP ) );

如果需要 AF_PACKET 个套接字,也可以使用 libpcap/tcpdump。它将允许您捕获以太网帧并发送原始以太网帧。对于捕获,您可以根据需要的帧设置过滤器(例如,TCP 端口 X)。 (基本上使用 libpcap 你可以做与 AF_PACKET 套接字相同的事情,但更容易)

链接到 guide for capturing and man page for sending