Прямий проксі не зберігає межі TCP-сегментів
Відокремлюйте сегментацію TCP, читання із сокета й кадрування HTTP, коли досліджуєте трафік з обох боків прямого проксі.
Припустімо, що HTTP-відповідь після проходження через Squid з’являється в кількох записаних TCP-сегментах. Це може бути звичайна поведінка TCP, а не доказ того, що відповідь поділено неправильно.
Прямий проксі зазвичай має два з’єднання:
client ⇄ TCP connection A ⇄ proxy ⇄ TCP connection B ⇄ origin
Кожне з’єднання має власний стан TCP, свої порядкові номери й свою пакетизацію. Проксі може читати дані з одного з’єднання й записувати їх в інше, не зберігаючи початкові розміри сегментів. Буферизація, момент надсилання, перевантаження й обмеження розміру шляху можуть дати інше групування.
Три межі, які варто тримати окремо
| Межа | Що її визначає |
|---|---|
| TCP-сегмент | Транспортний і мережевий шлях |
| Результат читання із сокета | Доступні байти потоку й буфер виклику |
| Повідомлення або кадр HTTP | Правила кадрування протоколу HTTP |
Одне читання може містити частину заголовка, увесь заголовок разом із байтами тіла або дані, що перетинають більше ніж одну межу прикладного рівня. TCP не прив’язує «кінець HTTP-відповіді» до кінця успішного читання.
Тому аналізатор HTTP/1.1 накопичує заголовки й застосовує відповідні правила кадрування тіла, зокрема довжину, кодування передавання або дозволене закриття з’єднання. Кадр HTTP/2 — це структура протоколу, яка сама може перетинати TCP-сегменти; це не інша назва мережевого пакета.
Успішний тунель CONNECT зберігає тунельований потік байтів, але все ще використовує дві ділянки TCP. Межі його сегментів можуть відрізнятися навіть тоді, коли проксі не змінював байти всередині тунелю.
Розслідуючи пошкодження, порівнюйте повторно зібрані дані застосунку. Порівняння кількості пакетів або очікування однакових довжин пакетів з обох боків вимагає від TCP гарантії меж, якої він не дає.