如何以编程方式生成连接重置?

时间:2010-09-22 20:56:27

标签: php python sockets web-applications tcp

我确定您在尝试浏览网页时看到“连接已重置”消息。 (该文本来自Firefox,其他浏览器不同。)

我需要根据需要生成该消息/错误/条件,以测试变通方法。

那么,我该如何以编程方式生成该条件? (如何从PHP生成TCP RST - 或其他一种Web应用程序语言?

警告和条件:

  1. 它不能是一般的IP块。测试客户端在未触发条件时仍必须能够看到测试服务器。

  2. 理想情况下,它将在Web应用程序级别(Python,PHP,Coldfusion,Javascript等)完成。访问路由器是有问题的。访问Apache配置很痛苦。

  3. 理想情况下,它会通过提取特定网页来触发。

  4. 奖励,如果它适用于标准的商业网络主机。

  5. 更新

    发送RST不足以导致此情况。请参阅下面的部分答案。

    我有一个适用于本地计算机的解决方案,现在需要让它在远程主机上运行。

3 个答案:

答案 0 :(得分:2)

我建议通过CLI通过自定义套接字执行此操作,因为搞乱apache进程可能会很麻烦:

#!/usr/bin/php -q
<?php

set_time_limit (0);

$sock = socket_create(AF_INET, SOCK_STREAM, 0);

socket_bind($sock, '1.1.1.1', 8081) or die('Could not bind to address');

socket_listen($sock);

$client = socket_accept($sock);
sleep(1);
$pid = getmypid();
exec("kill -9 $pid");
?>

这将在Firefox中生成所需的错误,因为在读取之前连接已关闭。

如果你觉得疯狂大胆,你可以把它扔进一个网络脚本,但我甚至不敢冒险尝试,除非你拥有这个盒子,并知道你在做什么管理员。

答案 1 :(得分:1)

我相信你需要相当突然地关闭低级套接字。您将无法通过Javascript执行此操作。对于其他语言,您通常需要获取底层套接字对象的句柄并手动关闭()。

我也怀疑你可以通过Apache做到这一点,因为它是Apache,而不是你的应用程序持有套接字。最多你的努力可能会产生HTTP 500错误,这不是你想要的。

答案 2 :(得分:1)

更新

这个脚本运行良好,足以测试我们的连接重置解决方法,所以这是一个部分答案。

如果有人提出在远程主机上运行的完整解决方案,我很乐意将其标记为答案。


以下脚本每次在同一台计算机上运行和测试时都有效。但是当在远程主机上运行时,浏览器会获得以下最后3个数据包:

Source     Dest       Protocol  Info
<server>   <client>   TCP       8081 > 1835 [RST] Seq=2 Len=0
<server>   <client>   TCP       8081 > 1835 [RST] Seq=2 Len=0
<server>   <client>   TCP       http > 1834 [ACK] Seq=34 Ack=1 Win=6756 Len=0

如您所见,RST标志已设置并发送。但Firefox无声地失败,只有一个空白页面 - 没有任何消息。

脚本:

<?php
    $time_lim       = 30;
    $listen_port    = 8081;
    echo
       '<h1>Testing generation of a connection reset condition.</h1>
        <p><a target="_blank" href="http://' .$_SERVER["HTTP_HOST"]. ':' .$listen_port. '/">
        Click here to load page that gets reset. You have ' . $time_lim . ' seconds.</a>
        </p>
       '
    ;
    flush ();
?>
<?php
    //-- Warning!  If the script blocks, below, this is not counted against the time limit.
    set_time_limit ($time_lim);

    $socket     = @socket_create_listen ($listen_port);
    if (!$socket) {
        print "Failed to create socket!\n";
        exit;
    }

    socket_set_nonblock ($socket);  //-- Needed, or else script executes until a client interacts with the socket.

    while (true) {
        //-- Use @ to suppress warnings.  Exception handling didn't work.
        $client = @socket_accept ($socket);
        if ($client)
            break;
    }

    /*--- If l_onoff is non-zero and l_linger is zero, all the unsent data will be
        discarded and RST (reset) is sent to the peer in the case of a connection-
        oriented socket.
    */
    $linger     = array ('l_linger' => 0, 'l_onoff' => 1);
    socket_set_option ($socket, SOL_SOCKET, SO_LINGER, $linger);

    //--- If we just close, the Browser gets the RST flag but fails silently (completely blank).
    socket_close ($socket);

    echo "<p>Done.</p>";
?>