简体   繁体   English

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

[英]How do I generate a connection reset programatically?

I'm sure you've seen the " the connection was reset " message displayed when trying to browse web pages. 我确定您在尝试浏览网页时看到“ 连接已重置 ”消息。 (The text is from Firefox, other browsers differ.) (该文本来自Firefox,其他浏览器不同。)

I need to generate that message/error/condition on demand, to test workarounds. 我需要根据需要生成该消息/错误/条件,以测试变通方法。

So, how do I generate that condition programmatically? 那么,我如何以编程方式生成该条件? ( How to generate a TCP RST from PHP -- or one of the other web-app languages? ) 如何从PHP生成TCP RST - 或其他一种Web应用程序语言?

Caveats and Conditions: 警告和条件:

  1. It cannot be a general IP block. 它不能是一般的IP块。 The test client must still be able to see the test server when not triggering the condition. 测试客户端在未触发条件时仍必须能够看到测试服务器。

  2. Ideally, it would be done at the web-application level (Python, PHP, Coldfusion, Javascript, etc.). 理想情况下,它将在Web应用程序级别(Python,PHP,Coldfusion,Javascript等)完成。 Access to routers is problematic. 访问路由器是有问题的。 Access to Apache config is a pain. 访问Apache配置很痛苦。

  3. Ideally, it would be triggered by fetching a specific web-page. 理想情况下,它将通过获取特定的网页来触发。

  4. Bonus if it works on a standard, commercial web host. 如果它适用于标准的商业网络主机,则可获得奖励。

Update: 更新:

Sending RST is not enough to cause this condition. 发送RST不足以导致此情况。 See my partial answer, below. 请参阅下面的部分答案。

I've a solution that works on a local machine, Now need to get it working on a remote host. 我有一个适用于本地计算机的解决方案,现在需要让它在远程主机上运行。

I would recommend doing this via a custom socket via CLI as messing with the apache process could be messy: 我建议通过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");
?>

This will generate the desired error in Firefox as the connection is closed before read. 这将在Firefox中生成所需的错误,因为在读取之前连接已关闭。

If you feel insanely daring, you could throw this into a web script but I wouldn't even venture trying that unless you own the box and know what you're doing admin wise. 如果你觉得疯狂大胆,你可以把它扔进一个网络脚本,但我甚至不敢冒险尝试,除非你拥有这个盒子,并知道你在做什么管理员明智。

I believe you need to close the low-level socket fairly abruptly. 我相信你需要相当突然地关闭低级套接字。 You won't be able to do it from Javascript. 您将无法通过Javascript执行此操作。 For the other languages you'll generally need to get a handle on the underlying socket object and close() it manually. 对于其他语言,您通常需要获取底层套接字对象的句柄并手动关闭()。

I also doubt you can do this through Apache since it is Apache and not your application holding the socket. 我也怀疑你可以通过Apache做到这一点,因为它是Apache而不是你的应用程序持有套接字。 At best your efforts are likely to generate a HTTP 500 error which is not what you're after. 充其量,您的努力可能会产生HTTP 500错误,这不是您所追求的。

Update: 更新:

This script worked well enough to test our connection-reset workaround, so it's a partial answer. 这个脚本运行良好,足以测试我们的连接重置解决方法,所以这是一个部分答案。

If someone comes up with the full solution that works on a remote host, I'll gladly mark that as the answer. 如果有人提出在远程主机上运行的完整解决方案,我很乐意将其标记为答案。


The following script works every time when running and tested on the same machine. 每次在同一台机器上运行和测试时,以下脚本都可以运行。 But when running on a remote host, the browser gets the following last 3 packets: 但是当在远程主机上运行时,浏览器会获得以下最后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

As you can see, the RST flag is set and sent. 如您所见, RST标志已设置并发送。 But Firefox fails silently with a blank page -- no messages of any kind. 但Firefox无声地用空白页面失败 - 没有任何类型的消息。

Script: 脚本:

<?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>";
?>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM