Почему веб-сервер должен очищать буфер приема сокета перед отправкой ответа? - PullRequest
0 голосов
/ 26 октября 2018

Я изучаю крошечный веб-сервер, он может получить GET-запрос от браузера и вернуть HTML-файл. Функция serve_file отправляет ответные сообщения в браузер, а функция get_line получает строку из буфера сокета. Я не знаю, почему читает и отбрасывает заголовки запроса . Я пытаюсь прокомментировать две строки, и браузер показывает страницу сброса соединения. Я предполагаю, что буфер приема сокета сервера заполнен, но я не знаю конкретной причины. Кто-нибудь может это объяснить?
исходный код

/* Send a regular file to the client.  Use headers, and report */

void serve_file(int client, const char *filename) {
    FILE *resource = NULL;
    int numchars = 1;
    char buf[1024];

    buf[0] = 'A'; buf[1] = '\0';

    //why?
    while ((numchars > 0) && strcmp("\n", buf))  /* read & discard request headers */
        numchars = get_line(client, buf, sizeof(buf));

    resource = fopen(filename, "r");
    if (resource == NULL)
        not_found(client);
    else {
        headers(client, filename); //send headers to tcp buffer
        cat(client, resource); //send index.html to tcp buffer
    }
    fclose(resource);
}

1 Ответ

0 голосов
/ 27 октября 2018

Наблюдаемое вами поведение - это стандартное поведение сокета.

Если данные, полученные от однорангового узла, не были прочитаны приложением, и приложение вызывает close в сокете, то ОС не выполняет обычное завершение соединения TCP. Это сбрасывает соединение сразу вместо завершения. Если приложение действительно хочет изящно закрыть соединение, когда в полученном буфере есть непрочитанные данные, оно должно вызвать shutdown(socket, SHUT_WR) перед вызовом close.

А почему API сокетов реализован таким образом? Потому что эта обработка может избежать DOS-атак. Если close выполняет обычное завершение сеанса TCP, то возможна следующая атака:

  • Злонамеренный клиент открывает TCP-соединение
  • Сервер принимает соединение и начинает получать данные
  • Клиент отправляет непрерывный поток, скажем, случайных данных
  • Сервер быстро обнаруживает, что полученные данные неверны, и вызывает close в сокете.
  • close просто отправляет FIN и затем ждет закрытия пира. Ресурсы сервера остаются выделенными, потому что обычно FIN просто закрывают направление к клиенту. Клиент по-прежнему может отправлять данные, и буфер recv не будет освобожден.

Но когда закрытие инициирует сброс соединения, ресурсы, связанные с этим соединением TCP, немедленно освобождаются. Атака дос тогда немного сложнее.

Подробнее см. https://www.spinics.net/lists/linux-c-programming/msg01345.html.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...