Я не ожидал протокола TCP, а там такой фарс!

задняя часть Сетевой протокол

Всем привет, меня зовут Сяолинь.

Вчера читатель задал мне этот вопрос:

Это, вероятно, означает, что установленное TCP-соединение, клиент не работает посередине, и сервер не имеет данных для отправки в это время, и он был в состоянии установления.После восстановления клиента он устанавливает соединение с сервером. В это время сервер будет Как с этим бороться?

Читатели, которые видели мою иллюстрированную сеть, знают, что TCP-соединение однозначно подтверждается «четверкой».

Затем в этом сценарии IP-адрес клиента, IP-адрес сервера и порт назначения не изменились, поэтому ключ к этой проблеме зависит от того, совпадает ли исходный порт в пакете SYN, отправленном клиентом, с исходным портом последнего соединения. .

1. Номер порта в SYN-сообщении клиента отличается от исторического соединения.

Если номер порта источника в сообщении SYN, отправленном клиентом после восстановления, отличается от номера порта источника предыдущего соединения, сервер будет считать, что должно быть установлено новое соединение, поэтому он установит новое соединение через три рукопожатие. .

Что произойдет с сервером в состоянии установления при старом соединении?

Если сервер отправляет пакет данных клиенту, поскольку соединение клиента было закрыто, ядро ​​клиента вернет сообщение RST, и сервер разорвет соединение после его получения.

Если сервер не отправил пакеты данных клиенту, через некоторое время будет активирован механизм TCP keep-alive, после обнаружения того, что клиент неактивен, сервер разорвет соединение.

2. Номер порта в сообщении SYN клиента совпадает с историческим соединением.

Если номер порта источника в сообщении SYN, отправленном клиентом, совпадает с номером порта источника последнего соединения после восстановления клиента, то есть сервер в состоянии установления получает сообщение SYN.

Как вы думаете, что сервер будет делать в это время?

  • Отбрасывать пакеты SYN?
  • Ответить на сообщение RST?
  • Ответить на сообщение ACK?

Когда я впервые увидел этот вопрос, я понятия не имел, потому что раньше не обращал на него внимания, и этот вопрос нельзя было угадать, поэтому я прочитал спецификацию RFC и исходный код ядра Linux и, наконец, узнал ответ.

Мне плевать, я сначала отвечу прямо.

Если сервер в состоянии «установить» получает сообщение SYN от клиента (обратите внимание, что сообщение SYN в это время фактически не соответствует порядку, поскольку порядковый номер инициализации сообщения SYN на самом деле является случайным числом), он ответит сообщением SYN. сообщение ACK с номером и номером подтверждения, этот ACK называется Challenge ACK.

Затем клиент получает запрос ACK и обнаруживает, что серийный номер не соответствует ожидаемому, поэтому возвращает сообщение RST.После того как сервер его получает, он разрывает соединение.

Объяснение документа RFC

Этот пример упоминается на странице 34 документа rfc793.

Я также разместил оригинальное объяснение для всеобщего обозрения.

  • When the SYN arrives at line 3, TCP B, being in a synchronized state,

and the incoming segment outside the window, responds with an acknowledgment indicating what sequence it next expects to hear (ACK 100).

  • TCP A sees that this segment does not acknowledge anything it

sent and, being unsynchronized, sends a reset (RST) because it has detected a half-open connection.

  • TCP B aborts at line 5.
  • TCP A willcontinue to try to establish the connection;

Я не буду переводить вслепую, смысл аналогичен объяснению, которое я объяснял ранее на китайском языке.

Анализ исходного кода

Если сервер в состоянии install получает сообщение SYN от клиента, ядро ​​вызовет следующие функции:

tcp_v4_rcv
  -> tcp_v4_do_rcv
    -> tcp_rcv_established
      -> tcp_validate_incoming
        -> tcp_send_ack

Мы сосредоточимся только на том, как функция tcp_validate_incoming обрабатывает SYN-пакеты.Упрощенный код выглядит следующим образом:

Как видно из приведенной выше реализации кода, сервер в состоянии install сначала определит, есть ли серийный номер в окне после получения сообщения, если нет, то проверит, установлен ли флаг RST, если да, то сбросит . Затем, если нет флага RST, он определит, есть ли флаг SYN, если есть флаг SYN, он перейдет к метке syn_challenge, а затем выполнит функцию tcp_send_challenge_ack.

В функции tcp_send_challenge_ack функция tcp_send_ack будет вызываться для ответа на сообщение ACK с правильным серийным номером и номером подтверждения.

Как закрыть TCP-соединение?

Вопрос вот такой вопрос, как закрыть TCP соединение?

Может быть, первая реакция каждого — «убить процесс», верно?

Да, это самый грубый способ, убийство клиентского процесса и серверного процесса по-разному повлияет на область видимости:

  • Если клиент завершает процесс, будет отправлено сообщение FIN для отключения всех TCP-соединений, установленных между клиентским процессом и сервером.Этот метод влияет только на соединения, установленные клиентским процессом и другими клиентами.В противном случае процесс не будет затронут .
  • Уничтожение процесса на сервере будет иметь большее влияние.В это время все соединения TCP будут закрыты, и сервер не сможет продолжать предоставлять услуги доступа.

Поэтому закрывать процесс не рекомендуется, лучше всего закрыть определенное TCP-соединение.

Некоторые друзья могут сказать, что недостаточно подделать RST-сообщение с той же четверкой?

Эта идея очень хороша, но не забывайте, что есть еще одна проблема с серийным номером, будет ли принят серийный номер вашего поддельного RST-сообщения другой стороной?

Если порядковый номер пакета RST не может попасть в скользящее окно другой стороны, пакет RST будет отброшен другой стороной, и эффект закрытия соединения не будет достигнут.

так,Чтобы подделать RST-сообщение, которое может закрыть TCP-соединение, должны одновременно выполняться два условия: «четверка одинакова» и «порядковый номер попадает в скользящее окно другой стороны».

Трудно напрямую подделать порядковый номер, который соответствует ожиданиям, потому что, если TCP-соединение передает данные, скользящее окно все время меняется, поэтому трудно подделать сообщение RST с порядковым номером, который просто попадает в допустимые пределы. раздвижное окно другой стороны.

Есть еще способ,Мы можем подделать SYN-пакет с той же четверкой, чтобы получить «законный» порядковый номер!

Как мы узнали в начале, если сервер в состоянии install получает SYN-сообщение с той же четверкой,Он ответит вызовом ACK. «Номер подтверждения» в этом сообщении ACK — это именно тот серийный номер, который сервер хочет получить в следующий раз. Грубо говоря, этот шаг можно использовать для получения серийного номера, который ожидает сервер. получать дальше.

Затем используйте этот номер подтверждения в качестве серийного номера сообщения RST и отправьте его на сервер.В это время сервер будет думать, что серийный номер в сообщении RST является допустимым, поэтому он разорвет соединение!

В Linux есть инструмент killcx, основанный на описанном выше методе: он будет активно отправлять пакет SYN для получения номера SEQ/ACK, а затем использовать номер SEQ/ACK для подделки двух сообщений RST для отправки клиенту. и службы соответственно.Таким образом, как активные, так и неактивные TCP-соединения могут быть уничтожены.

Использование также очень простое, просто укажите IP-адрес клиента и номер порта.

./killcx <IP地址>:<端口号>

Принцип работы инструмента killcx показан на следующем рисунке.

Он подделывает клиента для отправки сообщения SYN, и после того, как сервер его получит, он ответит сообщением ACK (Challenge ACK) с правильным «серийным номером и номером подтверждения», а затем он может использовать информацию в сообщении ACK для подделать два сообщения RST:

  • Используйте номер подтверждения в запросе ACK, чтобы подделать сообщение RST и отправить его на сервер, и сервер разорвет соединение после получения сообщения RST.
  • Используйте серийный номер в запросе ACK, чтобы подделать сообщение RST и отправить его клиенту, и клиент также разорвет соединение, когда получит RST.

Именно таким образом успешно закрывается TCP-соединение!

Вот диаграмма перехвата пакетов с помощью инструмента killcx для закрытия соединения Давайте посмотрим на изменения в серийном номере и номере подтверждения.

Следовательно, в будущем захвате пакетов, если пакет SYN появляется необъяснимым образом, возможно, что другая сторона хочет запустить RST-атаку на вас в следующий раз и напрямую разорвать ваше TCP-соединение!

Как, очень умно!