
MTR, Path MTU и детект блокировок по SNI на iOS без entitlements
tischenkod 24 минуты назад MTR, Path MTU и детект блокировок по SNI на iOS без entitlements Средний 5 мин 191 Swift * iOS * Сетевые технологии * Разработка мобильных приложений * Информационная безопасность * Кейс В...
GPT-5.6 31 Temmuz 2026'da yayınlanacak mı?
В сфере искусственного интеллекта произошло заметное событие. tischenkod 24 минуты назад MTR, Path MTU и детект блокировок по SNI на iOS без entitlements Средний 5 мин 191 Swift * iOS * Сетевые технологии * Разработка мобильных приложений * Информационная безопасность * Кейс В апреле я выложил в App Store NetDiag+ — набор сетевых инструментов для iOS: ping, traceroute, DNS, whois, сканер портов и LAN. Главная фишка была в том, что всё это работает без приватных entitlements — на чистом BSD-сокете через C-interop. В мае я написал об этом на Habr, статья зашла в основные хабы, дала всплеск установок.
За следующие полтора месяца я добавил 9 новых инструментов. Изначально казалось, что это будет «ещё немного того же» — обернуть пару сокетов в SwiftUI. На деле почти каждый тул оказался отдельной технической задачей: где-то пришлось разбирать сырые ICMP-пакеты, где-то выяснилось, что «очевидный» подход просто не работает в реальной сети, а где-то — что TCP-проба врёт про доступность.
Технические детали
Расскажу про самые интересные. MTR — непрерывный traceroute, который не должен тормозитьmtr (My TraceRoute) — это traceroute, который не делает один проход и останавливается, а гоняет пробы по кругу, накапливая по каждому хопу статистику: потери, min/avg/max RTT, джиттер. Сетевики живут в нём, потому что «ping says OK but feels slow» — это как раз про потери на промежуточном хопе, которые видны только в динамике.
Первая наивная версия делала пробы последовательно: проба на TTL=1, ждём ответ или таймаут, TTL=2, ждём… На 12 хопах, где пара роутеров режет ICMP rate-limit, один цикл занимал 5-7 секунд. Пользователь ставит интервал «1 секунда», а счётчик циклов тикает раз в пять. Решение — слать все пробы цикла разом, а ответы собирать в одном окне.
Хитрость в том, как сопоставить пришедший ICMP-ответ с конкретным TTL. Я даю каждой пробе уникальный UDP-порт назначения (base + ttl + cycle_offset). Когда роутер возвращает ICMP Time Exceeded, он прикладывает первые байты исходного пакета — включая UDP-заголовок с этим портом.
Отраслевые последствия
Демультиплексируем по нему:/// Pull the destination port out of the UDP header embedded in an ICMP /// Time-Exceeded error so we know which outstanding probe this reply is for. static func extractInnerDestPort(from data: Data) -> UInt16? { let bytes = Array(data) let icmpHeader = 8 guard bytes.
count > icmpHeader let ihlBytes = Int(bytes & 0x0F) * 4 // inner IP header length guard ihlBytes >= 20 let innerUDP = icmpHeader + ihlBytes guard bytes. count >= innerUDP + 4 return (UInt16(bytes) << 8) | UInt16(bytes) } Теперь время цикла ≈ probeTimeout, а не сумма ожиданий по всем хопам. Второй нюанс — статистика.
Считать stddev «в лоб» (хранить все RTT и пересчитывать) для бесконечно идущего инструмента — плохая идея: память течёт линейно. Берём онлайн-алгоритм Уэлфорда — он обновляет среднее и дисперсию за O(1) на отсчёт и численно стабилен:mutating func recordReply(rttMs: Double) { recv += 1 lastMs = rttMs bestMs = bestMs ?? rttMs worstMs = worstMs ??
Событие, по словам экспертов, усилит конкуренцию в сфере ИИ.





