Brock Adams
Brock Adams

Reputation: 93613

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.)

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?)

Caveats and Conditions:

  1. It cannot be a general IP block. 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.). Access to routers is problematic. Access to Apache config is a pain.

  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. 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.

Upvotes: 9

Views: 4618

Answers (3)

Brock Adams
Brock Adams

Reputation: 93613

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:

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. But Firefox fails silently with a blank page -- no messages of any kind.

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

Upvotes: 2

webbiedave
webbiedave

Reputation: 48887

I would recommend doing this via a custom socket via CLI as messing with the apache process could be messy:

#!/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.

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.

Upvotes: 1

SpliFF
SpliFF

Reputation: 39014

I believe you need to close the low-level socket fairly abruptly. You won't be able to do it from 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. At best your efforts are likely to generate a HTTP 500 error which is not what you're after.

Upvotes: 1

Related Questions