c++ - 如何处理套接字中的网络端口滥用

标签 c++ c sockets networking tcp

我有一个用 C++ 编写的 Web 应用程序,使用 TCP/IP 通过标准网络套接字在 Linux 上运行。该服务对狂野和困惑的互联网开放。

我时不时地收到来自运行自动脚本的垃圾邮件发送者的大量滥用请求。我可以检测到这些并关闭套接字。现在我只是礼貌地关闭套接字,就像我对任何已完成的有效请求所做的那样,使用这样的套接字库关闭:

close( mSocket );

但有时关闭套接字通常会通知垃圾邮件脚本套接字连接已终止,它们会立即发起另一个欺诈请求。

终止 TCP/IP 连接的最佳方法是什么,该连接会清除我系统上打开的套接字,但会使远程方挂起。那就是我想以对我来说成本最低但对他们来说成本最高的方式关闭套接字。

@尼古拉斯·威尔逊:

使用 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 );

如果可行,我会报告。 (@edit:下面经过测试的答案)

@“让套接字保持打开状态”的想法:

这可行,但不是最优的。攻击者有能力用打开的套接字使您的系统饱和。每个请求都会创建一个保持打开状态的新套接字。对于 DOS 攻击,您最终会耗尽套接字。

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

  1. 只是不要关闭它。打开的套接字永远存在。攻击者的成本:高——他们没有鳍。我的成本:更高。我所有的文件描述符最终都会被使用。
  2. 为每个套接字生成一个线程休眠 10 分钟,然后关闭套接字。攻击者的成本:高——他们没有鳍。我的成本:更高。虽然我最终确实关闭了套接字,但对于每个请求,我都有一个套接字用完的时间比攻击者更长,而且我有一个线程的开销。
  3. 产生一个线程来处理所有滥用套接字的过期。攻击者的成本:高——他们没有鳍。我的成本:更高。像 2,许多套接字保持打开状态。管理它的单个线程的开销。代码复杂、烦人。

最佳答案

好的,做了一些研究,我有一个基于 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 );

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

我们想默默地关闭连接,让他们等着意识到你没有回答......因为我们是报复性的。

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

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

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

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

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

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

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

效果很好,将浏览器指向这里:

http://oroboro.com/fail

Chrome 至少会在那里停留 5-10 秒。查看我的日志,我每秒可以点击 10 次——他只能每 10 秒左右点击一次。从此加载我的系统:0。

再见!

关于c++ - 如何处理套接字中的网络端口滥用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14146187/

相关文章:

c++ - 轻量级C++图像库

http - 使用 Berkeley Sockets 接收未知大小的数据

java - 如何将 Java 类转换为其子类之一(SocketAddress 和 InetSocketAddress)

c++ - 链接器如何决定使用哪个实现

c++ - 错误 : SymGetLineFromAddr64, GetLastError:487(地址:)

c++ - 读取 txt 文件并从第二列中找到第一列给定值的最小值

c++ - 使用工厂方法合并不同的类(c++)

c - 在指向结构的指针中访问数组

c - 填充结构数组的数组?

sockets - 在套接字上设置读取超时