views:

126

answers:

3

Hi,

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.

A: 

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.

SpliFF
+1  A: 

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.

webbiedave
This is not suitable for a hosted deployment due to use of `getmypid()` and `exec()` (plus the attempt to kill the process!!!). Also, is `kill` a valid command on a windows machine? **BUT**, this script does works on my local dev machine with the following notes: (1) The time limit is best set to some highish value, 300 is plenty.   (2) the last 3 lines are not needed. It seems that the connection gets automatically reset, just after Firefox attempts to browse the port -- no PID kill needed. Haven't got this working on our dev host yet.
Brock Adams
Admin wisely refuses to allow this on the remote hosts. This approach also performs worse than the non-risky scheme of setting `SO_LINGER`.
Brock Adams
A: 

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