Как сгенерировать сброс соединения программно? - PullRequest
7 голосов
/ 23 сентября 2010

Я уверен, что вы видели сообщение ", соединение было сброшено ", отображаемое при попытке просмотра веб-страниц.(Текст из Firefox, другие браузеры отличаются.)

Мне нужно сгенерировать это сообщение / ошибку / условие по требованию, чтобы протестировать обходные пути.

Итак, как мне сгенерировать это условие программно?( Как создать TCP RST из PHP - или одного из других языков веб-приложений? )

Предостережения и условия:

  1. Это не может быть общий блок IP.Тестовый клиент должен по-прежнему иметь возможность видеть тестовый сервер, не вызывая условие.

  2. В идеале это должно быть сделано на уровне веб-приложений (Python, PHP, Coldfusion, Javascript, так далее.).Доступ к роутерам проблематичен.Доступ к конфигурации Apache затруднен.

  3. В идеале, он будет запускаться при извлечении определенной веб-страницы.

  4. Бонус, если он работаетна стандартном коммерческом веб-хосте.

Обновление:

Отправка RST недостаточно, чтобы вызвать это условие.См. Мой частичный ответ ниже.

У меня есть решение, которое работает на локальной машине, теперь нужно, чтобы оно работало на удаленном хосте.

Ответы [ 3 ]

2 голосов
/ 23 сентября 2010

Я бы порекомендовал сделать это через пользовательский сокет через 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 голос
/ 24 сентября 2010

Обновление:

Этот скрипт работал достаточно хорошо, чтобы протестировать наш обходной путь сброса соединения, так что это частичный ответ.

Если кто-то придет с полным решением, которое работает на удаленном хосте, я с радостью отмечу это как ответ.


Следующий скрипт работает каждый раз при запуске и тестировании на одной машине. Но при работе на удаленном хосте браузер получает следующие 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>";
?>
1 голос
/ 23 сентября 2010

Полагаю, вам нужно довольно быстро закрыть сокет низкого уровня. Вы не сможете сделать это из Javascript. Для других языков вам обычно нужно получить указатель на базовый объект сокета и закрыть его () вручную.

Я также сомневаюсь, что вы можете сделать это через Apache, поскольку это Apache, а не ваше приложение, удерживающее сокет. В лучшем случае ваши усилия могут привести к ошибке HTTP 500, а это не то, что вам нужно.

...