Техническое: разные сетевые задержки и TCP с портами

Сейчас много околотехнических обсуждений по теме методов определения того, пришёл ли веб-клиент на некий крупный веб-сервис “c VPN или без VPN”. Оставим за скобками набравшую сейчас популярность трактовку того, что такое VPN – термин обобщили до невозможности. Но в технической стороне процесса “определения” сетевых настроек есть пара занятных моментов, которые как-то пропускают.

Момент первый: измерение параметров времени для TCP-соединения. Например, к некоторому веб-сервису подключается клиент, скажем, браузер. При помощи выполнения некоторых скриптов не очень трудно померить время “сетевой задержки” между средой веб-страниц этого браузера и серверной средой. То есть, это будет время доставки запроса, измеренное от контекста DOM в браузере до веб-сервера. Предположим, это 50 ms. Но это всё по HTTP, а HTTP-соединение использует TCP.

TCP-соединение устанавливается не с браузером, а с логически ближайшим к серверному сетевому стеку узлом. Это может быть клиентский компьютер, то есть, ОС на этом компьютере. Но может быть и выходной узел, выполняющий трансляцию адресов, например. Обычно – именно так и есть: клиентский компьютер редко стоит прямо за маршрутизируемым IP-адресом. Тогда, если измерять и задержку в браузере, и задержку на серверном TCP, то получится, скажем, что, в рамках одной логической HTTP-сессии, TCP-задержка – 10 ms, а браузерная задержка, до DOM в HTTP-клиенте, – 50 ms. Большая разница – 40 ms. Это означает, что от клиента транслированные запросы ещё где-то там внутри долго ходят, пока доберутся до выходного узла, который к нам по TCP подключился.

Если же выходной TCP-узел примерно совпадает с логическим узлом, где работает клиентский браузер, то разница между двумя задержками будет минимальной, например: 10 ms TCP и 11 ms – браузерная задержка, читай – Javascript в DOM-контексте. Здесь под “примерно совпадает” имеется в виду, что между клиентским компьютером и выходным узлом нет большого сетевого плеча: компьютер и выходной узел стоят технически рядом (простейший случай: локальный пограничный “роутер” с NAT и подключенный к этому “роутеру” по локальному порту компьютер в локальной IP-сети над Ethernet-ом).

Естественно, измерять задержки TCP-стека для веб-сервиса (не веб-сервера) – несколько сложнее, чем померить что-то внутри веб-логики. Для таких измерений нужно зацепить “щупы” прямо в сетевой стек, причём, на входном узле, а не на бэкенде, куда проксируются HTTP-запросы. Очевидно, что на “веб-уровне”, даже для сервера, TCP в таких деталях не виден. Но измерять всё равно можно – это не суперсложная задача, и решение вполне под силу специализированной компании, сохранившей инженерный подход среди своих разработчиков. Мы же тут, как раз, речь ведём о крупных профильных компаниях, где, вполне возможно, понимающие инженеры есть – верно?

Понятно, что сравнение задержек по времени на уровне браузерного движка с задержками на уровне TCP-стека не является каким-то волшебным зеркалом, которое всё показывает: большие задержки бывают при использовании радиоканалов, из-за перегруженного оборудования, из-за потерь пакетов на стороне клиента и т.д. Тем не менее – фактор это достаточно важный, чтобы о нём не забывать.

Момент второй: геометрия сетевых подключений. Если наш гипотетический веб-сервис имеет только одно подключение к общему Интернету, – которое называют “аплинк”, – то этот веб-сервис не может различить пути поступления сетевых пакетов извне в локальную сеть, в рамках какой-то веб-сессии. Ну, как не может – путь для таких пакетов тут один, потому что один “аплинк”. Соответственно, различать нечего. Однако в совсем крупных компаниях, связанных с веб-сервисами, есть несколько подключений, несколько “аплинков”, своя автономная система (или несколько) и свой центр управления сетью, населённый инженерами NOC.

Для опытного инженера NOC, IP-адрес – это сетевой номер, идентификатор, а не “интернет-узел”. С точки зрения физической организаци сети, IP-адрес может указывать куда угодно, а доставка IP-пакетов – просто происходит на другом уровне, чем работает сама вверенная сеть. Поэтому IP-пакеты можно различать по физическим портам коммутаторов или по логическим маршрутам, которые ниже IP и связаны с внутренним устройством сетей оператора (см. MPLS и пр.). Так что для IP-пакетов, с разными адресами источника, и разными правилами, могут использоваться разные порты подключения – эти пакеты, проще говоря, приходят “с разных сторон”, что создаёт внутренний различительный признак. Как ни странно, но этот признак зависит от внешних факторов (где какие фильтры, кто к кому подключен и пр.).

Сюда же попадает и повсеместная путаница, связанная с распределением блоков IP-адресов (префиксов). У всякого IP-префикса есть администратор – автономная система (AS). Это верно. Но ещё есть маршрутизация и BGP. И вот в рамках BGP, технически, быть источником (origin) для данного IP-префикса может любая (подчёркиваю: технически – любая, даже с тестовым номером) автономная система. То есть, административно, префикс принадлежит одной AS, но анонсирует его в Интернет – совсем другая. Или даже несколько других AS – в зависимости от того, какой оператор из какой точки сети смотрит на BGP. Да, для штатного анонсирования префикса должно быть разрешение от его администратора, сейчас это даже подтверждается в RPKI. Да, конкретная ситуация с приёмом IP-пакетов зависит от фильтров, настроенных оператором. Но это только подчёркивает то, что одно дело – административная принадлежность, другое – BGP и маршрутизация в реальности.

BGP – это хорошо, но при чём здесь сетевые задержки? Вот при чём: даже во внешнем BGP, например, не видны многие и многие внутренние каналы между операторами, более того, административная принадлежность префикса не позволяет судить о реальных характеристиках сетевой связности вообще никак; однако разные пути доставки тут всё равно образуются, и разное время доставки, наблюдаемое внутри, вполне себе может служить признаком для классификации.

Адрес записки: https://dxdt.blog/2026/04/27/18069/

Похожие записки:



Далее - мнения и дискуссии

(Сообщения ниже добавляются читателями сайта, через форму, расположенную в конце страницы.)

Комментарии читателей блога: 11

  • 1 <t> // 28th April 2026, 07:24 // Читатель Аноним написал:

    Вы имеете в виду ICMP-пинги? То есть через JS/CSS (можно и так) измеряется rouundtrip, а потом сервер по своей инициативе делает ICMP-пинг? А если узел на пинги не отвечает? А если комп за NATом, втч CGNATом? А если комп просто тормозной, и замеры браузером сильно замедлены?

  • 2 <t> // 28th April 2026, 07:34 // Читатель Аноним написал:

    Меня с этой историей больше беспокоит то, что когда официально административно вмешиваются во внутренние дела компаний, и обязывают внедрять вредоносное ПО в свои приложения на устройствах клиентов – это уже новые правила игры, в стиле КНР, для Запада это не то что неслыханно, но официальный статус такому стараюся не придавать, даже при Трампе. Awful optics.

    И не могли бы вы убрать поле для почты, оно бесполезно, и неудобно.

  • 3 <t> // 28th April 2026, 08:33 // Читатель maf написал:

    Кстати, в Nginx информацию о задержке можно получить достаточно просто, из коробки: https://nginx.org/en/docs/http/ngx_http_core_module.html#var_tcpinfo_

  • 4 <t> // 28th April 2026, 11:42 // Александр Венедюхин:

    > Вы имеете в виду ICMP-пинги?

    Нет. Тут речь именно про TCP – в TCP можно померить интервал задержки между клиентом и сервером средствами самого протокола.

    Соответственно, все остальные аспекты (CGNAT, медленный браузер) – отсюда выводятся.

    > А если комп просто тормозной

    Это, обычно, тоже можно определить из JS + CSS.

  • 5 <t> // 28th April 2026, 11:44 // Александр Венедюхин:

    > И не могли бы вы убрать поле для почты, оно бесполезно, и неудобно.

    Подумаю – там не так просто убрать.

  • 6 <t> // 28th April 2026, 16:25 // Читатель Аноним написал:

    1. Правильно ли я понимаю, что в настоящих решениях третьего и ниже уровней, вроде Wireguard, задержки будут именно до TCP/IP стека на той же стороне, где и браузер, а сильная дельта между задержками – это в случае прокси, не прокидывающих третий уровень в том или ином виде?
    2. Можно ли на эту задержку с клиента повлиять, напр. задействовав smoltcp?
    3. Можно ли организовать задержку меньше round-trip time, предсказав значения параметров, которые сервер пошлёт в будущем, и заблаговременно направив ответ? Что случится, если на сервер прилетит ответ на запрос, который он ещё не отправил?
    4. Можно ли эту задержку полнодуплексно модулировать полезным сигналом?
    5. Предположим, что атакующие модулируют задержку. Можно ли органиловать деструктивную интерференцию исключительно со стороны клиента, чтобы до сервера полезный сигнал не дошёл?
    6. Вам что-нибудь известно о финггерпринтинге TCP/IP стека, в том числе по задержкам? Можно ли меняя параметры на стороне сервера и измеряя отклик клиента, в том числе по задержке, определить реализацию TCP/IP-стека?

  • 7 <t> // 29th April 2026, 11:39 // Александр Венедюхин:

    В TCP интервал задержки виден между узлами, которые создают TCP-соединение, то есть, это неустранимое свойство. Однако, если внутрь виртуальной сети (на том же Wireguard) убрать всё – и TCP-клиента, и TCP-сервер, – то, соответственно, и измеряемые задержки переедут внутрь этой виртуальной сети. Но если есть какой-нибудь вариант NAT или что-то подобное, преобразующее _соединения_ наружу через внешний порт, то станут видны параметры TCP-стека этого внешнего порта. То есть, в общем случае – нет, это не свойство “проксей”, это свойство TCP.

    Модулирование/интерференция: со стороны TCP-клиента, который непосредственно подключается к TCP-серверу, тут, да, конечно, можно повлиять на наблюдаемую задержку, введя какие-то интервалы ожидания – отсюда выводятся и ответы в части возможности модулирования: то есть, да, можно модулировать, но ширина побочного канала будет небольшой; можно отправлять всякие “паразитные” конфигурации, вызывая исчерпание ресурсов сокета на стороне сервера (всякие SYN-флуды, имитация потери пакетов с вынужденной повторной отправкой, замораживание сессий, вынужденное изменение размеров окон и т.д., и т.п. – это очень большая тема).

    Что касается упреждающей отправки ответов/сигналов: вообще – нет, не получится, это сломает протокол, потому что там есть номера в заголовках, состояние сессии и т.д., и т.п., однако базовая идея – весьма верная, а развитие этой идеи называется TCP Fast Open (но к сокрытию свойств TCP-сессии Fast Open отношения не имеет).

    Профилирование по свойствам TCP, построение отпечатков по TCP-свойствам: да, это вполне себе разработанная тема – реализовано из коробки в некоторых сетевых сканерах, например, для фингерпринтинга ОС по параметрам TCP-стека; тут лучше всего начинать смотреть с TCP clock skew и пр. – там много работ и исследований.

  • 8 <t> // 29th April 2026, 14:33 // Читатель Аноним написал:

    Спасибо за ответ.
    1. То есть NAT делает свою TCP-сессию? Я всегда считал, что он поля в пакетах меняет по таблице на ASICе, а в основном пакеты идут как пришли, только с заменёнными адресами и портами, и почти на скорости провода.
    2,4,5 Полезный сигнал полезному сигналу рознь. Представьте, что атакующий на проводе к нескомпрометированному серверу берёт, и модулирует сигнал, а потом на ТСПУ его ловит. Тут много битов не надо. Можно ли свой на своей стороне активно адаптивно модулировать, не предполагая какого-либо конкретного механизма модуляции, и руководствуясь теорией информации, так, чтобы система сервер-модулятор на той стороне либо вышла за пределы SLA для данного соединения, что, я подозреваю, модулятор запрограммирован избегать, либо продолжила оставаться в пределах SLA, но модулятор тогда бы оказался более стеснён в той полосе, что он мог бы передавать, если бы не было ответной модуляции со стороны клиента.
    3. Разве номера в последовательности не предсказуемы внутри сессии, и точное предсказание и не требуется (неточное предсказание – это потеря пакетов, не проблема?), и это не баг, а фича?
    6. Я имел в виду не просто сравнивать параметры и наборы опций и их порядок с дефолтными различных стэков (это вообще можно проспуфить полностью?), а своими поманипулировать, а так же размерами, задержками и почим, и посмотреть, как это скажется на RTT, потом другим образом поманипулировать, и опять посмотреть. Разные манипуляции могут потребовать задействования разных кодовых путей стека на другой стороне, и из соотношений их таймингов попробовать вывести во-первых какая реализация стека (винда, линукс, мак, smoltcp, ещё что-нибудь), а уже зная стек, прикинуть количество инструкций процессора каждого типа, нужных конкретному стэку для ответа на конкретную манипуляцию, и по времени попробовать прикинуть, сколько каждая инструкция исполняется в среднем, а оттуда, на какой аппаратуре стэк исполняется. И адаптивно подбирать манипуляции, чтобы они давали максимум информации по типу акинатора.
    7. Что произойдёт с точностью измерения RTT, если отключить timestamp, или в каждый пакет абсолютно случайный (не на сессию случайный изначальный таймстамп, а вообще в каждом пакете случайный, через допустим чачу) timestamp класть, или искусственно таймстамп спуфить/загрублять/зашумлять в рамках определённого интервала? Реализации будут такие пакеты отклонять? Может ли реализациям от такого поплохеть?

  • 9 <t> // 29th April 2026, 18:32 // Александр Венедюхин:

    > То есть NAT делает свою TCP-сессию?

    Нет, не делает, но адрес-то подставляет – а это означает, что, если смотреть с внешней стороны, соединение установлено с IP-адресом, который на выходном порте NAT (внутренних сетевых адресов на сервере, в такой конфигурации, не видно). В NAT есть таблицы по сессиям, переключение состояния делается по наблюдению за хендшейком, как минимум, и т.д. Бывает довольно сложная логика. И это вовсе не отменяет возможностей измерения параметров времени для сессии, которая идёт через NAT-узел. Узлов с трансляцией может быть несколько, можно отправить несколько RST и т.д., и т.п.

    > Можно ли свой на своей стороне активно адаптивно модулировать

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

    > Разве номера в последовательности не предсказуемы внутри сессии

    Тут будет не понятно, что предсказывать: не получится же отправлять подтверждения на ещё неполученные запросы, а надёжно предсказать эти запросы – не выйдет. А так, ну, полезный-то трафик от клиента – он всё равно отправляется по инициативе клиента.

    > Разные манипуляции могут потребовать задействования разных кодовых путей стека на другой стороне, и из соотношений их таймингов попробовать вывести во-первых какая реализация стека

    Ну, вроде ж, всё примерно так и делается, и довольно давно. Вот самый простой пример старинной практической утилиты: https://nmap.org/book/man-os-detection.html

    > Что произойдёт с точностью измерения RTT, если отключить timestamp,

    Если с точки зрения штатного стека TCP, то точность ухудшится. Если же с точки зрения определения задержек в целом, то тут – ну, смотря, что и как измерять. Может, вообще ничего не произойдёт: это же не единственный способ измерения. Что там в конкретных реализациях стеков – это надо отдельно смотреть, я не готов сейчас расписывать.

  • 10 <t> // 30th April 2026, 10:55 // Читатель Mike написал:

    Александр, а какой способ измерения задержек средствами TCP имеется ввиду?
    Если TSval, так NAT не обязан его менять.

  • 11 <t> // 1st May 2026, 11:35 // Александр Венедюхин:

    Можно измерить время между отправкой SYN-ACK и получением ACK. Но, понятно, NAT это тоже транслирует без изменений. В общем, нужен сигнал, ответ на который формируется непосредственно транслирующим узлом (например, NAT), без трансляции в сторону “внутреннего плеча”, которое за этим узлом (то есть, не до точки “измерения в браузере”). Если такой сигнал найти не получается, то, да, схема с поиском разницы по времени работать не будет, как и обсуждается выше.

    Исходно – речь про то, что наличие таких сигналов нельзя упускать из виду, тем более, что, – для веба, – ситуацию по их использованию/измерению можно создать, задействуя браузер, который находится как раз на конце “внутреннего плеча”.

Написать комментарий

Ваш комментарий:

Введите ключевое слово "7GQFD" латиницей СПРАВА НАЛЕВО (<--) без кавычек: (это необходимо для защиты от спама).

Если видите "капчу", то решите её. Это необходимо для отправки комментария ("капча" не применяется для зарегистрированных пользователей). Обычно, комментарии поступают на премодерацию, которая нередко занимает продолжительное время.