如何处理套接字中的网络端口滥用问题

Raf*_*sta 11 c c++ sockets networking tcp

我有一个用c ++编写的web应用程序,使用TCP/IP通过标准网络套接字,在Linux上运行.该服务对野生和羊毛互联网开放.

我会定期收到来自运行自动脚本的垃圾邮件发送者的滥用请求.我可以检测到这些并关闭套接字.现在我只是做一个礼貌的套接字关闭,就像我对已经完成的任何有效请求所做的那样,套接字lib关闭如下:

close( mSocket );
Run Code Online (Sandbox Code Playgroud)

但有时关闭套接字通常会通知垃圾邮件脚本套接字连接已终止,并立即启动另一个欺诈请求.

什么是终止TCP/IP连接的最佳方法,该连接清理系统上的打开套接字,但让远程方挂起.那就是我希望以对我来说成本最低的方式关闭套接字,但是它们的成本最高.

@Nicholas Wilson:

使用TCP_REPAIR似乎是一个好主意.在TCP_REPAIR模式下关闭套接字时,不会发送FIN或RST数据包.远程插座悬空.我打算试试并报告.这是我的(未经测试的)代码:

if ( abuse )
{
   int aux = 1;
   if ( setsockopt( mSocket, SOL_TCP, TCP_REPAIR, &aux, sizeof( aux )) < 0 )
      reportError( "Tried to do a rude socket close... but could not turn on repair mode.\n" );
}
close( mSocket );
Run Code Online (Sandbox Code Playgroud)

我会报告这是否有效.(@edit:测试答案如下)

@"让插座保持开放"的想法:

这可行,但次优.攻击者可以使用开放式套接字使系统饱和.每个请求都会创建一个保持打开的新套接字.有了DOS攻击,你最终会耗尽套接字.

然后还有管理打开的套接字的问题:

  1. 只是不要关闭它.打开套接字永远存在.攻击者的代价:高 - 他们没有鳍.我的成本:更高.我的所有文件描述符最终都会被使用.
  2. 每个插槽生成一个线程以休眠10分钟然后关闭套接字.攻击者的代价:高 - 他们没有鳍.我的成本:更高.虽然我最终关闭了套接字,但是对于每个请求,我使用的套接字比攻击者使用的时间更长,并且我有一个线程的开销.
  3. 生成一个处理所有滥用套接字到期的线程.攻击者的代价:高 - 他们没有鳍.我的成本:更高.像2一样,很多插座都是敞开的.管理它的单个线程的开销.代码复杂,烦恼.

Raf*_*sta 4

好的,做了一些研究,我有一个基于 TCP_REPAIR 的适合我的答案。它比我一开始想象的要复杂一些:

if ( abuse )
{
   // read some bytes from the spammer - to establish the connection
   u32 tries = 20;
   while ( tries )
   {
      sleep( 1000 );
      char tmpBuf[32];
      s32 readCount = recv( mSocket, &tmpBuf[0], 32, 0 );
      if ( readCount > -1 ) break;
      tries--;
   }
#ifdef TCP_REPAIR
   int aux = 1;
   if ( setsockopt( mSocket, SOL_TCP, TCP_REPAIR, &aux, sizeof( aux )) < 0 )
   {
     reportError( "could not turn on repair mode" );
   }
#else // !TCP_REPAIR
   // no TCP REPAIR - best we can do is an abort close
   struct linger so_linger;
   so_linger.l_onoff = 1;
   so_linger.l_linger = 0;
   if ( setsockopt( mSocket, SOL_SOCKET, SO_LINGER, &so_linger, sizeof so_linger ) < 0  )
   {
      reportError( "Cannot turn off SO_LINGER" );
   }
#endif // TCP_REPAIR
}
close( mSocket );
Run Code Online (Sandbox Code Playgroud)

在内核级别,如果您关闭连接,TCP 堆栈将发送 FIN 或 RST 数据包,无论您如何执行此操作(使用 close 或 shutdown )。无论哪种方式,攻击者都会收到您关闭连接的通知。

我们想默默地关闭连接,让他们等着发现你没有回复……因为我们是报复性的。

TCP_REPAIR 是一个新的套接字 API,旨在允许您“冻结”套接字、保存其状态以及在另一个进程甚至另一个系统上重新加载套接字状态。在正常使用情况下,客户端永远不会知道他们的连接已转移到其他地方。

但是我们可以滥用这个API,我们将套接字置于修复模式,但不保存其状态并且从不恢复它。当我们在修复模式下关闭套接字时,它会被悄悄删除。

这适用于已经开始的滥用请求。也就是说,我们已经阅读了垃圾邮件发送者的请求,并确定这是欺诈行为,并且 TCP_REPAIR 将其杀死。

但是,如果您在连接后立即阻止 IP 请求,而没有先读取套接字,则远程方会以某种方式收到通知。他们得到了 RST。或者连接中的某些内容可能永远不会完全完成,并且远程系统几乎立即中止请求。

所以我们首先从黑客的套接字中读取几个字节。就我而言,套接字已经处于非阻塞模式。但如果不是,你想将套接字设置为非阻塞,否则你就向黑客开放连接,但不发送数据包并使你的服务器挂起 - 就像你计划对他做的那样。如果几微秒后你没有收到数据包,你无论如何都会关闭他。

但是,如果您从他那里读取了几个字节,那么他的程序就会等待您的响应,但永远不会到来。

TCP_REPAIR 仅适用于 Linux 内核 3.5 及更高版本。下面我能做的最好的事情就是关闭“脏”套接字。这里不是向他发送 FIN,而是向他发送 RST。在他看来,好像从未建立过有效的连接。为此,您需要关闭 SO_LINGER,以从本质上中断套接字连接关闭握手,然后调用 close。

就像一个魅力,将您的浏览器指向此处:

http://oroboro.com/fail

Chrome 至少会挂在那里 5-10 秒。查看我的日志,我每秒获得 10 次点击 - 他只能每隔 10 秒左右点击我一次。从这里加载我的系统:0。

又见傻瓜了!