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

时间:2015-08-01 13:20:54

标签: c raw-sockets ubuntu-15.04

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

  1. 我假设在第3层创建了原始套接字,因此协议不应该是IPPROTO_TCP / IPPROTO_UDP,而应该是IPPROTO_IP。这种理解是否正确?

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

    < / LI>
  3. 当我使用IPPROTO_RAW*socketFd = socket(AF_INET, SOCK_RAW, IPPROTO_RAW);)协议创建原始套接字时,我的应用程序不会收到任何数据包

  4. 当我使用协议IPPROTO_TCPsocketFd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);)创建原始套接字时,我的应用程序接收TCP数据包,但内核也响应这些数据包(在我的情况下,它是RST链接)。我认为这是因为内核认为没有任何人收听该数据包所针对的端口。

  5. 我的目的只是使用虚假的IP和TCP标头发送对应用程序的消息的响应。由于上述尝试都没有对我有用,我应该如何创建原始套接字并使内核TCP层只为该连接安静?

    编辑: 请跳过问题1-3。他们已经被菲利普回答了。对于问题4,我们确实有一个解决方法。但是如果有人在这里有答案并希望回答它,请保持问题公开。

3 个答案:

答案 0 :(得分:5)

  

我假设原始套接字是在第3层等协议上创建的   不应该是IPPROTO_TCP / IPPROTO_UDP,但它应该是IPPROTO_IP。是   这种理解是否正确?

没有。你是对的,原始套接字基本上是第3层数据包,但协议不应该是IPPROTO_IP。原始套接字的协议参数指示您有兴趣在该套接字上接收的数据包类型。请记住,协议本质上执行传输级解复用,因此您需要指定原始套接字感兴趣的协议类型。这在man 7 raw中已明确:

  

与为其指定的协议号匹配的所有数据包或错误   原始套接字传递给此套接字。对于允许的列表   协议参见RFC 1700分配的号码和getprotobyname(3)。

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

  

但是当我用协议创建原始套接字为IPPROTO_IP时   (* socketFd = socket(AF_INET,SOCK_RAW,IPPROTO_IP);),套接字创建   失败,错误协议不受支持。

是的,这是可以预期的:IP协议不是第4层协议。正如我所说,协议字段用于传输层解复用,因此使用IPPROTO_IP毫无意义。

  

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

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

中也很清楚
  

IPPROTO_RAW的协议意味着启用了IP_HDRINCL并且能够   发送传递标头中指定的任何IP协议。接收   使用原始套接字无法通过IPPROTO_RAW实现所有IP协议。

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

  

当我使用协议创建原始套接字为IPPROTO_TCP(socketFd =   socket(AF_INET,SOCK_RAW,IPPROTO_TCP);),我的应用程序收到了   TCP数据包,但内核也响应这些数据包(在我的情况下   它RSTs链接)。我认为这是因为内核认为没有   任何人都在听那个数据包所针对的端口。

您无法阻止内核完成其工作。从原始套接字联机帮助页:

  

收到数据包后,会将其传递给任何具有的原始套接字   在传递给其他协议之前已被绑定到其协议   处理程序(例如,内核协议模块)。

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

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

是的,不是很优雅,但我认为我们在这里做的不多。

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

另请记住,由于您需要为原始套接字指定IPPROTO_TCP,因此应在IP_HDRINCL的套接字上设置setsockopts(2),以便您可以构建自定义IP标头。

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

答案 1 :(得分:0)

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

关于AF-PACKET插座

man packet中描述了使用AF_PACKET创建原始套接字。 &#34; protocol&#34;的值变量应该是网络字节顺序中的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 capturingman page for sending

的链接

答案 2 :(得分:-2)

以下链接 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);

   }