О чём заметка

Это полный текст видео номер 8 из серии о том, как работает Zapret 2, разбитый по сценам, с анимированными схемами. Каждую сцену можно читать отдельно.

Как читать пометки

«В нашем тесте» значит настоящий запуск в лаборатории проекта: клиент, роутер, сервер. «По коду» значит, что мы прочитали исходники, но не запускали. «По общим сведениям» значит, что это вне нашего кода и лаборатории. О настоящем оборудовании ТСПУ мы ничего не утверждаем: наш «инспектор» это модель.

Повтор и вопрос: резать и подделывать в одной серии

Добро пожаловать в выпуск «Резать и подделывать вместе». Сначала короткий повтор, чтобы эту часть можно было смотреть отдельно от остальных.

О настоящем оборудовании на пути пакетов здесь нет ни слова: мы не знаем, как оно устроено. У нас два участника, и оба наши: игрушечный инспектор в роутере лаборатории и сервер с Linux.

Слово «сработало» в этом выпуске значит одно: приём обошёл нашу игрушку, а сервер получил настоящие данные. Каждый вывод об эффекте относится только к этим двоим.

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

Сервер у нас на Linux, и в нём два слоя. Ядро принимает пакеты, может отвергнуть какие-то из них и записывает это в свои счётчики. Приложение получает только то, что ядро приняло, и запоминает, сколько байт и какие именно к нему пришли. Когда мы скажем «ядро сервера выбросило», речь о первом слое, а когда «приложение прочитало», о втором.

Теперь о словах про игрушки. Игрушечный инспектор из выпуска «Что видит наблюдатель» это правило в роутере: оно сравнивает пятнадцать байт имени на одном и том же месте каждого пакета и ничего не помнит. Читатели это другие наши игрушки: они читают запись пакетов, каждый по своему правилу, и в выпуске «Перемешать: disorder» их было пятеро. Нам пока нужны двое. «Пакетный» ищет имя в каждом пакете отдельно, но по всему пакету, а не на одном месте. «Склейщик» склеивает данные в порядке прихода. Остальных троих назовём, когда дойдём до таблицы. «Видит» значит: читатель нашёл имя, и приём его не обманул. «Слеп» значит: имя не нашлось, и для нас это хороший исход.

Первое напоминание, из выпусков «Где резать: метки» и «multisplit: резать на части». Приветствие, первое сообщение защищённого соединения, занимает в нашей лаборатории двести пятьдесят байт, и имя сайта лежит в нём с девяносто седьмого байта по сто одиннадцатый, считая с нуля. Стратегия multisplit с меткой midsld режет приветствие посередине слова example: уходят два пакета, сто четыре байта и сто сорок шесть.

Что из этого получилось, посмотрим на двух опытах нашей лаборатории. Без разреза игрушечный инспектор, который смотрит в одно и то же место каждого пакета, находит его в первом же пакете, и сервер не получает ни одного байта. С разрезом инспектор имени не находит, и сервер получает все двести пятьдесят.

Разрез и правило игрушки Приветствие в 250 байт с именем сайта на байтах 97–111 режется перед байтом 104 на пакеты в 104 и 146 байт, и в нашем тесте игрушечное правило, которое смотрит одно и то же место каждого пакета, без разреза находит имя и сервер получает 0 байт, а с разрезом не находит имени ни в одном пакете и сервер получает все 250 байт. опыт: одно приветствие, правило смотрит одно место игрушка, а не оборудование приветствие в нашей лаборатории: 250 байтномера байтов с нуля 0249 имя сайта: байты 97..111 разрез midsld = 104 пакет 1: 0..103, 104 байта…www.exa mple.com…пакет 2: 104..249, 146 байт 104 + 146 = 250: ни байта не потеряно и не добавлено без разреза: пакет целикомуходит один пакет, 250 байт 250 байт окошко 97..111 попало на имя правило совпало: пакет выброшенв окошке лежит имя сервер получил 0 байтдо приложения ничего не дошло это правило nft с фиксированным местом:пятнадцать байт на байтах 97..111 данных multisplit:pos=midsld: два пакетауходят пакеты в 104 и 146 байт 104 байта146 байт пунктир: окошко пакета 1 выходит за его конецлиния: в окошке пакета 2 лежат чужие байты правило не совпало ни разуни на одном пакете; счётчик правила: 0 пакетов сервер получил 250 байтони совпали с оригиналом по счёту: в первом пакете окошко выходит за конец,во втором лежат другие байты, а не имя имя сайта (15 байт)окошко правила: байты 97..111 каждого пакета

Проверь себя. Есть читатель нашей модели, который склеивает пакеты по порядку прихода. Увидит ли он имя после такого разреза?

Увидит: две части идут одна за другой, и в склеенном потоке имя снова целое. Такие читатели нам встречались в выпусках «multisplit: резать на части» и «Перемешать: disorder». Значит, из наших читателей разрез обманывает только пакетного, того, кто разбирает каждый пакет отдельно. Это слабое место разреза, и его надо назвать честно.

Кто видит имя после разреза В нашей модели над записью роутера после разреза на пакеты в 104 и 146 байт имя сайта не находит только читатель пакетный, который разбирает каждый пакет отдельно, а читатели склейщик, первый записал, последний записал и строго по порядку собирают куски вместе и видят имя на втором пакете из двух. модели над записью роутера: multisplit:pos=midsld наши модели, не оборудование что дошло до роутера, по порядку: пакет 1: 104 байта…www.exa mple.com…пакет 2: 146 байт каждый читатель берёт эти два пакета и по-своему решает, есть ли в них имя пакетныйсмотрит каждыйпакет отдельно у него получилось:www.example.comврозь: имени нетни в одном куске слепхороший исход склейщиксклеивает данныепо порядку прихода у него получилось:www.example.comнашёл на пакете2 из 2 видит имяприём не обманул первыйзаписалпо номерам байтов;при наложенииостаётся первое у него получилось:www.example.comнашёл на пакете2 из 2 видит имяприём не обманул последнийзаписалпо номерам байтов;при наложенииостаётся последнее у него получилось:www.example.comнашёл на пакете2 из 2 видит имяприём не обманул строго попорядкупринимает сегмент,начатый не позженужного байта у него получилось:www.example.comнашёл на пакете2 из 2 видит имяприём не обманул вывод: разрез обманывает только пакетного, того, кто смотрит каждый пакет отдельно красное: читатель нашёл имя; зелёное: имени не нашёл, это хорошо для нас. Слабое место разреза называем честно.

Второе напоминание, из выпуска «Фейк и его условия». Фейк это пакет, который программа сама вставляет рядом с настоящим. Если у фейка нет условия, из-за которого получатель его не примет, наш сервер на Linux принимает его всерьёз, и настоящие данные теряются. Условий в том выпуске было семь, а сегодня хватит трёх самых простых: опция эм-дэ-пять, срок жизни один и испорченная контрольная сумма. В программе такие настройки называются fooling. В выпуске «Фейк и его условия» мы звали их условиями подделки, а сегодня скажем коротко: условие. Это не то условие, которое отбирает пакеты для профиля, как в выпуске «Читаем командную строку zapret2». Здесь условие это намеренный дефект самого фейка: из-за него фейк либо умирает по дороге, либо сервер сам его выбрасывает.

Вопрос выпуска: что будет, если сделать и то и другое в одной серии? Какие пакеты уйдут в сеть, что ответит сервер и какие читатели нашей модели ослепнут? Функций, которые это делают, три. Первая называется «разрез с фейками», по-латински fakedsplit, с неё и начнём.

План такой. Сначала идём по проводу, пакет за пакетом: первый запуск, что лежит в фейке, как он умирает и что отвечает сервер. Потом смотрим, что будет без условия, и как выключать фейки по одному. Что каждый фейк даёт против нашей игрушки, увидим позже, когда дойдём до читателей. Код функции откроем ближе к концу выпуска, когда будем знать, что в нём искать.

Итак. Разрез прячет имя от пакетного читателя, а фейк с условием умирает по дороге. Остаётся выяснить, что получится, если взять оба приёма сразу, и что при этом получит наш сервер. Начинаем с первого запуска fakedsplit.

Первый запуск: шесть пакетов на одно приветствие

Вопрос сцены: что именно уходит в сеть, когда fakedsplit отрабатывает на нашем приветствии? Сначала идея, потом настоящий запуск, потом пакеты по одному.

Игрушка, выдуманная. Книга на двести пятьдесят страниц разрезана на две пачки: страницы с первой по сто четвёртую и со ста пятой по двести пятидесятую. Перед каждой пачкой и после неё курьер кладёт стопку чистых листов с теми же номерами страниц. Различается только то, что на листах.

Теперь настоящая строка запуска, по частям. Первая часть, фильтр вида данных: действуем только на пакет с приветствием, остальные не трогаем.

Вторая: вызов fakedsplit, наш «разрез с фейками». Он режет данные в одном месте, как multisplit, и добавляет фейки вокруг обеих частей.

К нему аргумент pos со значением midsld. Эта метка нам знакома: середина слова example, байт сто четыре.

Третья: условие эм-дэ-пять, в строке оно пишется «тэ-цэ-пэ, подчёркивание, эм-дэ-пять». Оно вешается на фейки как лишняя опция, настоящие части идут без неё, и наш сервер такой фейк выбросит. Как именно, посмотрим в следующей сцене. Сейчас читайте так: «фейки умрут».

Почему настоящие части идут без этой опции, увидим в коде в конце выпуска: у функции две таблицы настроек, одна для настоящих частей, другая для фейков.

Что сделала программа, видно в отладочном журнале нашего теста. Сначала найденная позиция: сто четыре. Потом шесть строк отправки, по строке на каждый пакет; их мы сейчас пройдём по одному. Последняя строка: оригинальное приветствие выброшено, как и в multisplit.

Команда и журнал первого запуска Строка запуска с функцией fakedsplit, меткой midsld и условием эм-дэ-пять разобрана на четыре части, а отладочный журнал нашего теста показывает найденную позицию 104, шесть отправок в порядке фейк, настоящая часть, фейк, фейк, настоящая часть, фейк и выброс оригинального пакета. опыт: первый запуск fakedsplit на нашем приветствии --payload=tls_client_hello1 1фильтр вида данныхдействуем только наприветствие,остальное не трогаем --lua-desync=fakedsplit2 2разрез с фейкамирежет в одном месте,как multisplit, и ставитфейки вокруг обеих частей :pos=midsld3 3метка: midsldсередина слова example,байт номер 104 :tcp_md54 4условие: опция MD5только на фейках,у настоящих частейеё нет отладочный журнал нашего теста, вырезкафейкнастоящая часть fakedsplit: resolved split pos: 104метка midsld стала числом 104 fakedsplit: sending fake part 1 (1) : 0-103 len=104фейк части 1: 104 байта fakedsplit: sending real part 1 : 0-103 len=104 seqovl=0настоящая часть 1: 104 байта fakedsplit: sending fake part 1 (2) : 0-103 len=104фейк части 1 ещё раз fakedsplit: sending fake part 2 (1) : 104-249 len=146фейк части 2: 146 байт fakedsplit: sending real part 2 : 104-249 len=146настоящая часть 2: 146 байт fakedsplit: sending fake part 2 (2) : 104-249 len=146фейк части 2 ещё раз packet: id=4 dropоригинальное приветствие выброшено строки sending печатаются только при отладке: без неё программа делает то же самое молча шесть отправок по одной строке на пакет: их мы и пройдём по проводу, пакет за пакетом

Теперь то же на проводе клиента, пакет за пакетом. Номера относительные, как в выпуске про multisplit: первый байт данных имеет номер один. Первый пакет: фейк первой части, номер один, сто четыре байта, внутри нули.

Второй пакет: настоящая первая часть. Номер тот же, один, длина та же, сто четыре, но внутри начало настоящего приветствия.

Третий: снова фейк первой части, номер один, сто четыре байта.

Четвёртый: фейк второй части. Номер сто пять, потому что один плюс сто четыре. Длина сто сорок шесть: от конца первой части до конца приветствия.

Пятый: настоящая вторая часть. Номер сто пять, длина сто сорок шесть, внутри «mple точка com».

Шестой: фейк второй части ещё раз, номер сто пять, сто сорок шесть байт.

Главное наблюдение. Каждый фейк стоит на тех же номерах и имеет ту же длину, что настоящая часть рядом. Три пакета с номером один, три с номером сто пять; различается только содержимое. Сто пять плюс сто сорок шесть дают двести пятьдесят один: это следующий номер после всех данных приветствия. Фейки границу не двигают, они лежат поверх тех же байтов. Это верно для нашего приветствия; дальше в этой части встретим случай, где длины разойдутся.

Шесть пакетов на проводе клиента Шесть пакетов на проводе клиента в порядке отправки: фейк, настоящая часть и снова фейк для первых 104 байт с номером 1, затем то же для остальных 146 байт с номером 105, причём каждый фейк стоит на тех же номерах и той же длины, что настоящая часть рядом, а опция MD5 есть только у фейков. провод клиента, порядок отправки; номера относительные: первый байт данных имеет номер 1 пакетномердлинаmd5внутри 1фейк1104MD5нули00 00 00 00 00 00… 2настоящая часть1104—начало приветствия16 03 01 00 f5 01… 3фейк1104MD5нули00 00 00 00 00 00… 4фейк105146MD5нули00 00 00 00 00 00… 5настоящая часть105146—mple.com…6d 70 6c 65 2e 63… 6фейк105146MD5нули00 00 00 00 00 00… клиентсервер номер 1три пакета номер 105три пакета те же номера на ленте: 250 байт приветствия фейки ×2: тот же размерфейки ×2: тот же размер настоящая часть 1: 104 байтанастоящая часть 2: 146 байт 1105251 1 + 104 = 105 ; 105 + 146 = 251: это следующий номер после всех данных приветствия различается только содержимое: фейки лежат поверх тех же байтов и границу не двигают

Проверь себя. Допустим, первая часть была бы не сто четыре байта, а пятьдесят. Какой номер у второй половины и сколько таких пакетов?

Один плюс пятьдесят, пятьдесят один. Пакетов три, и у каждого длина двести: двести пятьдесят минус пятьдесят. Это по счёту, такого запуска мы не делали.

Итак. Одна строка, один разрез, шесть пакетов: фейк, настоящая, фейк, потом снова фейк, настоящая, фейк. Каждый фейк лежит на тех же номерах и той же длины, что настоящая часть рядом. Что внутри фейка и как он умирает, расскажет следующая сцена.

Что лежит в фейке и как он умирает

Вопрос сцены: что лежит в фейке, и почему сервер его не принимает?

Игрушка, выдуманная. Подложное письмо: чистый лист в конверте. Погибнуть оно может двумя способами. На конверте печать, которую адресат не признаёт: письмо доехало, но не принято. Или марка, годная на один перегон: письмо погибает в пути.

Сначала лист. В выпуске «Фейк и его условия» у стратегии fake по умолчанию лежала заготовка приветствия на шестьсот восемьдесят байт. У fakedsplit другое умолчание: нули, а длину задаёт разрез. В нашем запуске первый фейк это сто четыре нуля, второй сто сорок шесть.

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

Узором может быть и готовая заготовка приветствия: тогда в нашем тесте фейк начинается с заголовка записи TLS. Но это только лист. Дойдёт ли письмо, решает не лист, а условие.

Что лежит в фейке В нашем тесте фейки по умолчанию целиком из нулей, 104 нулевых байта в первом и 146 во втором, с узором из трёх букв они читаются как один бесконечный текст, разрезанный там же, где данные, а с готовой заготовкой приветствия первый фейк начинается с заголовка записи TLS. чем заполнен фейк: три случая из нашего теста 1. по умолчанию: нулидлину фейка задаёт разрез 00 00 00 00 00 00 …00 00 00 00 00 00 … фейк части 1: 104 нулевых байтафейк части 2: 146 нулевых байт это не приветствие и не заголовок TLS в выпуске про условия у стратегии fake по умолчанию была заготовка приветствия на 680 байт 2. аргумент pattern: узор из трёх буквpattern=0x414243: буквы А Б В, в кодировке 41 42 43 ABCABC… 34 узора …AB CABCAB… и дальше по кругу разрез: тот же, что у данных фейк 1: 41 42 43 41 42 43 …фейк 2: 43 41 42 43 41 42 … фейк 1 это первые 104 буквы узора: 104 = 34 · 3 + 2, то есть 34 полных узора и ещё две буквы,поэтому фейк 2 начинается с третьей буквы: 43 41 42 … вместе два фейка это один бесконечный текст, разрезанный там же, где данные 3. готовая заготовка приветствия: pattern=fake_default_tlsиз выпуска про условия 680 байт фейк 1фейк 2 фейк 1 с байта 0: 16 03 01 02 a3 01 …фейк 2 с байта 104: 00 9c 00 9d 00 2f … 16 03 01 это тип записи и версия: фейк начинается как заголовок записи TLS но это только лист: дойдёт ли письмо, решает не содержимое, а условие

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

Второе: срок жизни один. Роутер получает фейк, вычитает единицу, получает ноль, выбрасывает пакет и отправляет клиенту сообщение ICMP «время вышло». В нашем тесте таких сообщений на клиенте четыре, а на выходе из роутера и на сервере видны только две настоящие части.

Третье: испорченная контрольная сумма. Фейки доходят до сетевой карты сервера, и ядро их выбрасывает: счётчик ошибок контрольной суммы равен четырём.

Это в нашем тесте. По общим сведениям, именно по этим причинам стек Linux выбрасывает такие пакеты; другие системы мы не проверяли.

Теперь заголовок. У настоящей части заголовок TCP занимает тридцать два байта: двадцать основных и двенадцать на опции. Опция эм-дэ-пять добавляет ещё восемнадцать. Двенадцать плюс восемнадцать дают тридцать, а опции, по общим сведениям, выравниваются до кратного четырём, поэтому тридцать два. Заголовок TCP у фейка стал пятьдесят два байта: на двадцать длиннее. Запомните эти двадцать байт, они понадобятся в конце части.

Отсюда размер пакета целиком. Настоящая первая часть: двадцать байт заголовка IP, тридцать два заголовка TCP и сто четыре данных, всего сто пятьдесят шесть, мы считали это в выпуске про multisplit. У фейка той же части на те же двадцать байт больше: сто семьдесят шесть.

Где и как умирает фейк Три способа смерти фейка в нашем тесте: с опцией эм-дэ-пять четыре фейка доходят до сервера и ядро их выбрасывает, счётчик растёт с 0 до 4, со сроком жизни один они гаснут в роутере и клиенту приходят четыре сообщения время вышло, с испорченной контрольной суммой ядро сервера насчитывает четыре ошибки, а фейк с опцией длиннее настоящей части на 20 байт. в нашем тесте: что происходит с четырьмя фейками, настоящие части доходят всегда эм-дэ-пятьфейки с опцией MD5доходят до сервераклиентроутер 6 пакетов 6 пакетов ядро выбросило 4 фейкаTCPMD5Unexpected 0 → 4 приложение: 250 байт подпись, которой не ждали срок жизни 1фейки гаснут в роутере,клиенту приходит ICMPтип 11, код 0клиентроутерсрок 1 → 0 6 пакетов 2 пакета 4 × время вышло ядро: фейков не виделодошли 2 настоящие части приложение: 250 байт испорченная суммафейки доходятдо сервераклиентроутер 6 пакетов 6 пакетов ядро выбросило 4 фейкаTcp InCsumErrors 0 → 4 приложение: 250 байт сумма пакета не сходится по общим сведениям, так такие пакеты выбрасывает стек Linux; другие системы мы не проверяли почему фейк с опцией MD5 длиннее: настоящая часть 1 и её фейк настоящая частьIP 20TCP 32данные 10420 + 32 + 104 = 156 байт фейк с MD5IP 20TCP 32+20данные 10420 + 52 + 104 = 176 байт заголовок TCP: настоящий 32 байта, у фейка 52. Опции настоящего 12 байт, у фейка 12 + 18 = 30, выравнивание до 32 заголовок TCP стал на 20 байт длиннее: эти 20 байт нам ещё пригодятся

Проверь себя. Два запуска: в одном условие эм-дэ-пять, в другом срок жизни один. В каком счётчик «подпись, которой не ждали» вырастет, на сколько, и сколько пакетов с данными дойдёт до сервера во втором запуске?

Только в первом, на четыре, по одному на фейк. Во втором счётчик останется нулём: фейки умерли в роутере, и до сервера дошли два пакета с данными, настоящие части.

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

Что отвечает сервер на шесть пакетов

Вопрос сцены: что скажет сервер на эти шесть пакетов и что прочитает его приложение?

Игрушка, выдуманная. Помните кладовщика из выпуска про disorder? У него один вопрос: какая буква нужна следующей. Письма с печатью, которую он не признаёт, кладовщик выбрасывает молча и ничего не отвечает.

Теперь запись нашего теста, пакет за пакетом, в порядке отправки. Первый пакет, фейк первой части. Ответа нет: сервер выбросил его молча.

Второй пакет, настоящая первая часть. На него сервер ответил подтверждением сто пять: жду байт номер сто пять. Следом отправил свои четырнадцать байт ответа. Лабораторный сервер отвечает, как только получил первые данные, не дожидаясь всего приветствия.

Третий пакет, повтор фейка первой части. Ответа нет.

Четвёртый, фейк второй части. У него номер сто пять, ровно тот, которого ждёт сервер. Если бы сервер принял этот пакет, подтверждение подскочило бы вперёд. Подтверждения нет.

Пятый, настоящая вторая часть, и шестой, повтор фейка второй части. Отдельного подтверждения нет ни на тот, ни на другой. По общим сведениям, получатель не обязан подтверждать каждый пакет сразу и может отложить подтверждение до своего следующего пакета; почему так вышло в нашем тесте, мы отдельно не проверяли.

Следующее число от сервера, двести пятьдесят два, приходит уже в пакете закрытия. Двести пятьдесят один плюс один, потому что, по общим сведениям, флаг закрытия занимает один номер.

Сравним с обычным разрезом: multisplit с той же меткой, без единого фейка. Сервер в нашем тесте ответил так же: сто пять, четырнадцать байт ответа, потом двести пятьдесят два при закрытии. По ответам сервера серия из шести пакетов неотличима от обычного разреза из двух. Это в нашем тесте и на одном получателе, Linux.

Что отвечает сервер на шесть пакетов Шесть пакетов клиента в порядке отправки и ответы нашего сервера: на фейки ответа нет, на настоящую часть 1 приходят подтверждение 105 и 14 байт ответа, на остальные пакеты отдельных подтверждений нет, номер 252 приходит только в пакете закрытия, и обычный разрез без фейков получает те же ответы. опыт с эм-дэ-пять: пакеты клиента и ответы сервера, по порядку клиентсервер 1фейк части 1номер 1, 104 байта ядро выбросило молчаответа нет 2настоящая часть 1номер 1, 104 байта принят подтверждение 105 14 байт ответа сервера 3фейк части 1, повторномер 1, 104 байта выброшен молчаответа нет 4фейк части 2номер 105, 146 байт выброшен молчахотя номер 105 ожидаемый 5настоящая часть 2номер 105, 146 байт принятотдельного ответа нет 6фейк части 2, повторномер 105, 146 байт выброшен молчаотдельного ответа нет закрытие: FIN + ACK, ack 252пакет закрытия от сервера 251 + 1 = 252: по общим сведениям, флаг закрытия занимает один номер по общим сведениям, получатель может отложить подтверждение, поэтому на пакеты 5 и 6 отдельных ответов нет ответы сервера у обычного разреза и у серии с фейками multisplit, 2 пакетаACK 10514 байт ответаACK 252 при закрытии fakedsplit, 6 пакетовACK 10514 байт ответаACK 252 при закрытии по ответам серия из шести пакетов неотличима от разреза на два (наш тест, Linux)

Теперь скажем, где в нашей лаборатории стоят игрушки. В выпуске «Фейк и его условия» инспектор стоял на входе в роутер, раньше проверки срока жизни, и видел даже фейк со сроком жизни один. В этом выпуске мест два. Запись на входе в роутер содержит всё, что туда дошло, и фейки со сроком жизни один тоже: по этой записи работают читатели. А игрушка, которая стоит внутри роутера на пути вперёд, уже после проверки срока жизни, такой фейк не увидит: роутер выбросит его раньше. Слова «на пересылке роутера» значат именно это второе место.

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

Теперь приложение на сервере. Оно прочитало двести пятьдесят байт, они совпали с оригиналом, а сервер нашёл в приветствии имя www.example.com. Сколькими чтениями приложение это получило, мы не называем: границы чтений зависят от времени.

Где фейк виден на пути В нашем тесте на четырёх точках захвата при опции эм-дэ-пять шесть пакетов видны везде, а при сроке жизни один фейки видны только на клиенте и на входе в роутер и до пересылки не доходят, поэтому до сервера идут два пакета, а приложение сервера в обоих случаях читает 250 байт и находит имя. четыре точки захвата: сколько пакетов клиента с данными видно на каждой эм-дэ-пять: фейки доходят до серверавсе шесть пакетов проходят сквозь все четыре точки; игрушка на пересылке увидела бы и фейки, и настоящие части клиентвход в роутервыход из роутеракарта сервера проверка срока жизни 6 6 6 6 запись на входе: по нейработают читателиживая игрушкана пересылке срок жизни один: фейки гаснут в роутерефейки видны на клиенте и на входе, а до выхода и до сервера доходят только две настоящие части клиентвход в роутервыход из роутеракарта сервера срок 1 → 0: выброшены 6 6 2 2 запись на входе: по нейработают читателиживая игрушкана пересылке приложение сервера: 250 байт, совпали с оригиналом, в приветствии найдено имя сайтаэто верно в обоих запусках; сколькими чтениями пришло, не называем: границы чтений зависят от времени тишина сервера не значит, что фейков не было: при эм-дэ-пять ядро насчитало 4 выброшенных фейка счётчик TCPMD5Unexpected вырос с 0 до 4; доказывает захват или счётчик, а не молчание

Проверь себя. Сервер на фейки молчит. Значит ли это, что фейки до сервера не дошли?

Нет. С условием эм-дэ-пять фейки дошли до сетевой карты сервера, и ядро выбросило их молча: счётчик насчитал четыре. Тишина ничего не доказывает, доказывает захват или счётчик. А фейки со сроком жизни один до сервера действительно не дошли: их остановил роутер. Ряд ответов сервера при этом получился тот же, и так же вышло с испорченной суммой.

Итак. Сервер отвечает один раз, подтверждением сто пять, после настоящей первой части, и молчит на все фейки. Приложение читает оригинал целиком. Для сервера серия неотличима от обычного разреза, а игрушечный инспектор на пересылке роутера в запуске с эм-дэ-пять видел бы все шесть пакетов.

Где упадёт разрез: позиция и края

Вопрос сцены: где падает разрез у fakedsplit и что бывает на краях?

Игрушка, выдуманная. Пачка листов и ножницы. «Режь перед тридцатой страницей» даёт двадцать девять листов и остальное. «Режь перед самой первой страницей» даёт пустую пачку и целую: резать нечего.

Из выпуска «Где резать: метки» мы знаем: позиция это номер байта с нуля, разрез стоит перед этим байтом. Одна оговорка про fakedsplit: в аргументе pos у него одна метка, а не список, как у multisplit. Чем это грозит, покажем дальше в этом выпуске, а пока пишем по одной метке.

Первый опыт: аргумент pos вообще не задан. По умолчанию у fakedsplit позиция два, разрез после двух байтов. Части в два байта и в двести сорок восемь, номер второй части три, и всё имя целиком лежит во второй. Сервер в нашем тесте ответил: жду байт три.

Второй: pos равно host. Части в девяносто семь байт и в сто пятьдесят три. Вторая часть начинается с самого имени, её номер девяносто восемь.

Зачем нам эти два опыта? Посмотрите, где лежит имя. И при позиции по умолчанию, и при host оно целиком в одной настоящей части.

При host в нашей игрушечной модели пакетный читатель находит имя во второй настоящей части, что бы ни делали фейки. При позиции по умолчанию имя тоже целиком в одной части, но это по счёту: отдельной модели для него мы не запускали. Чтобы спрятать имя и от пакетного читателя, разрез надо ставить внутрь имени, как midsld.

Где падает разрез Аргумент pos у fakedsplit это одна метка: по умолчанию разрез после 2 байт даёт части в 2 и 248 байт и ответ сервера 3, при host части в 97 и 153 байт и пакетный читатель нашей модели находит имя в начале второй части, а midsld режет имя пополам, и этот читатель его не находит. три запуска fakedsplit: где лежит разрез относительно имени приветствие, 250 байт; разрез стоит перед байтом с номером pos (с нуля) имя сайта: байты 97..1110249 pos не задан: по умолчанию 2 248 байт части 2 и 248 байт, номер второй части 3, ответ сервера: ACK 3 имя целиком во второй части (по счёту, модели для этого запуска нет) pos=host 97 байт153 байта части 97 и 153 байта, номер второй части 98, ответ сервера: ACK 98 пакетный читатель видит имя в начале второй части (наша модель) pos=midsld 104 байта146 байт части 104 и 146 байт, номер второй части 105, ответ сервера: ACK 105 пакетный читатель слеп: имя разрезано пополам (наша модель) у fakedsplit в pos одна метка, не списокв multisplit список работал; ловушку разберём позже в этом выпускеpos=midsldpos=1,midsld

Теперь края. Позиция ноль значит «режь перед самым первым байтом»: в первой части не осталось бы ничего. В коде это одна проверка: внутри функции позиции считаются с единицы, и если получилась единица, перед первым байтом резать нечего, и функция выходит. В журнале строка «не могу разрезать», сама функция ничего не отправляет, и оригинальное приветствие уходит целым.

Позиция девятьсот девяносто девять лежит за концом приветствия. Функция не может её найти, пишет «не могу найти позицию» и тоже ничего не делает. В нашем тесте в обоих случаях на проводе один пакет в двести пятьдесят байт, и сервер читает приветствие без изменений.

Это важный урок: стратегия может молча не сработать. Строки журнала видны только при отладке, а приветствие уходит целым, как будто стратегии нет.

Позиция один режет после одного байта: части в один байт и в двести сорок девять.

А резать на самом краю тоже можно: позиции двести сорок девять и минус один в прогоне функций дают части в двести сорок девять байт и в один. В лаборатории такого опыта у нас нет.

Проверь себя. Позиция host минус один. Какие длины у частей и какой номер у второй?

Первая часть девяносто шесть байт, вторая сто пятьдесят четыре. Номер второй: один плюс девяносто шесть, девяносто семь. Вторая часть начинается на один байт раньше имени. В нашем тесте на проводе именно такие длины.

Края разреза и молчаливые случаи Позиция 0 и позиция 999 за концом приветствия молча отключают fakedsplit, потому что на проводе остаётся один пакет в 250 байт и сервер читает приветствие без изменений, а позиции 1, 249 и минус 1 режут по самому краю на части в 1 и 249 байт, и позиция host минус 1 даёт части 96 и 154 байта. два значения pos, при которых стратегия молчит: приветствие уходит целым pos=0перед 1-м байтом:первая часть пуста 843 if pos == 1 thenжурнал: fakedsplit: split pos resolved to 0. cannot split. на проводе один пакет250 байт, как без стратегиисервер читает без изменений pos=999за концом данных:такой позиции нет 909 DLOG("fakedsplit: cannot resolve pos '"..spos.."'")журнал: fakedsplit: cannot resolve pos '999' на проводе один пакет250 байт, как без стратегиисервер читает без изменений в функции позиции считаются с единицы: 1 значит «перед первым байтом»; код из lua/zapret-antidpi.lua вокруг краёв: резать можно по самому краю pos=1части 1 и 249 байт, номер второй части 2, ACK 2 249 байт лаборатория pos=249 и pos=-1части 249 и 1 байт 249 байт прогон функций, лаборатории нет pos=host-1части 96 и 154 байта, номер второй части 97, ACK 97; вторая часть начинается на байт раньше имени 96 байт154 байта лаборатория может молча не сработать: журнал виден только при отладке, а приветствие уходит целым синий блок: имя сайта, байты 97..111

Итак. Разрез задаёт аргумент pos, это одна метка. По умолчанию это два байта, и имя целиком лежит во второй части. В нашем тесте ноль и значение за концом приветствия молча отключают стратегию: приветствие уходит целым.

Без условия: фейки побеждают

Вопрос сцены: что будет, если забыть условие?

Игрушка, выдуманная. Кладовщик кладёт на каждое место полки первую пришедшую стопку, а всё, что приходит потом на то же место, называет дублем. Если первой пришла стопка чистых листов, на полке лежит чистая бумага, как бы ни выглядела настоящая.

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

Читаем ответы сервера по порядку, пакет за пакетом. Первый пакет, фейк первой части. Ответ: сто пять. Сервер принял сто четыре нулевых байта за первую часть приветствия.

Второй пакет, настоящая первая часть. Ответ снова сто пять, и к нему блок: байты с первого по сто четвёртый. Это дублирующий блок, он значит: «такие байты у меня уже лежат». Настоящая часть пришла второй и оказалась повтором. Третий пакет, повтор фейка первой части, получает тот же ответ: сто пять и тот же блок.

Четвёртый, фейк второй части. Ответ двести пятьдесят один: сервер считает, что приветствие получено целиком, хотя настоящей второй части ещё не видел.

Пятый, настоящая вторая часть, и шестой, последний фейк. Оба с ответом двести пятьдесят один и блоком: байты со ста пятого по двести пятидесятый. Опять повторы.

Счётчик ядра сервера насчитал ровно четыре дублирующих ответа, по одному на пакеты два, три, пять и шесть. А счётчики эм-дэ-пять и контрольной суммы остались нулевыми: по этим двум причинам ядро не выбросило ничего.

Запуск без условия Запуск fakedsplit с позицией midsld без условия подделки: в игрушке кладовщик оставляет на полке первую пришедшую стопку, а вторую называет дублем; на проводе те же шесть пакетов, фейк и настоящая первая часть по 104 байта, затем фейк и настоящая вторая часть по 146 байт, у всех обычный срок жизни 64, верная сумма и нет опции MD5; сервер ответил подтверждением 105 на первый пакет, на второй и третий тем же подтверждением с блоком дубля от 1 до 105, на четвёртый подтверждением 251, на пятый и шестой подтверждением 251 с блоком дубля от 105 до 251, счётчик дублирующих ответов равен 4, счётчики MD5 и ошибок суммы равны 0, ядро ничего не выбросило. тот же запуск, но без условия подделки --payload=tls_client_hello --lua-desync=fakedsplit:pos=midsldнет tcp_md5: условия нет игрушка (выдуманный пример): кладовщик и полкапервой пришластопка чистых листовместо занято:лежит чистая бумагапотом настоящаястопка на то же местоэто дубль,её откладывают настоящий запуск: шесть пакетов на проводе и ответы сервера 1фейк 1-й части · 104 байтаF104@0 ACK 105 2настоящая 1-я часть · 104R104@0 ACK 105 + блок [1,105) 3фейк 1-й части ещё разF104@0 ACK 105 + блок [1,105) 4фейк 2-й части · 146 байтF146@104 ACK 251 5настоящая 2-я часть · 146R146@104 ACK 251 + блок [105,251) 6фейк 2-й части ещё разF146@104 ACK 251 + блок [105,251) у всех шести: MD5 нет, срок жизни 64, контрольная сумма верна: для нашего сервера обычные пакеты счётчики ядра сервера за запуск TCPDSACKOldSent: 4TCPMD5Unexpected: 0Tcp InCsumErrors: 0 четыре дубля на пакеты 2, 3, 5, 6; по MD5 и по сумме ядро не выбросило ничегосервер ещё отправил свои 14 байт ответа; на схеме их нет

Что прочитало приложение? Двести пятьдесят байт, и все нулевые. Не приветствие и не имя сайта.

Похожую картину мы видели в выпуске «Фейк и его условия»: запуск без условия тоже кончился тем, что сервер принял фейк за данные. Там фейк был длиннее приветствия, сервер подтвердил шестьсот восемьдесят один, а клиент не получил ответа. Здесь фейки лежат на тех же номерах, подтверждения не выходят за отправленное, соединение живёт и закрывается обычным образом, но данные нулевые.

Это в нашем тесте. По общим сведениям, Linux оставляет первую копию диапазона байтов, и здесь мы видим это своими глазами; как поведёт себя другая система, мы не проверяли. Вывод для fakedsplit: без условия имя пропадает не только у инспектора, но и у сервера, который получает нули. Значит, приём не «сработал» в нашем смысле: он портит данные.

И ещё одна оговорка про нашу игрушечную модель. Читатель «первый записал» в этом запуске имени не находит: он слеп. Но сервер получил нули. Слепой читатель и испорченные данные это разные вещи, и важно не путать их.

Проверь себя. Посмотрите на ответы сервера в запуске с условием и в запуске без него. В каком были дублирующие блоки и сколько?

Без условия, четыре. С условием блоков нет вовсе: сервер выбросил фейки молча. Дублирующий блок это ответ «такие байты у меня уже лежат»: пришла вторая копия места, которое уже занято.

Нули в приложении Что прочитало приложение сервера в двух запусках и что увидела игрушечная модель: с условием все 250 клеток настоящие и имя сайта найдено, без условия все 250 байт нулевые, имя не найдено и ненулевых байт 0 из 250; игрушечный читатель, который записывает первое, не нашёл имя ни в одном из шести пакетов, но сервер получил 250 байт, не равных оригиналу, то есть читатель слеп, а данные испорчены; ответ на проверку: без условия дублирующих блоков четыре, с условием их нет, сервер молча выбросил фейки. что прочитало приложение сервера с условием: фейки выброшены250 байт, равны оригиналуимя в приветствии: www.example.com250 клеток: настоящие байты без условия: фейки приняты как данные250 байт, все нулевыеимя в приветствии: нетненулевых байт: 0 из 250 наша игрушечная модель: читатель «первый записал»пакет 1нет именипакет 2нет именипакет 3нет именипакет 4нет именипакет 5нет именипакет 6нет имениnever foundв шести пакетаха сервер при этом получил 250 байт, не равных оригиналу читатель слеп: имени не нашёлданные испорчены: сервер получил нули слеп не значит цел проверь себя: в каком запуске были дублирующие блоки и сколько с условиеммолчитACK 105молчитмолчит—молчитблоков: 0 без условияACK 105блокблокACK 251блокблокблоков: 4 блок значит: такие байты у меня уже лежат; пришла вторая копия занятого местаквадраты по порядку шести пакетов; с условием сервер выбросил фейки молча

Итак. Без условия фейки обычные пакеты, наш сервер принимает первую копию каждого места, и приложение получает нули. В нашем тесте условие в fakedsplit обязательно: без него стратегия портит собственные данные.

Четыре фейка поодиночке

Вопрос сцены: нужны ли все четыре фейка, и что будет, если убрать один?

Игрушка, выдуманная. Две настоящие пачки и четыре пустышки вокруг них: две перед пачками и две после. Пронумеруем пустышки по порядку отправки: первая перед первой настоящей пачкой, вторая после неё, третья перед второй настоящей пачкой, четвёртая после неё.

Теперь настоящие выключатели: nofake один, два, три и четыре. Номер в имени это номер фейка по порядку отправки. Ключ работает как рычажок: есть ключ значит убрать, а какое у него значение, не важно. Даже ноль считается: в прогоне функций nofake один равно нулю тоже убирает фейк.

Почему так, видно в коде. Перед отправкой каждого фейка стоит проверка «если у аргументов нет ключа nofake с таким номером»: перед первым фейком с единицей, перед вторым с двойкой, перед третьим с тройкой, перед четвёртым с четвёркой. Проверяется только наличие ключа, а в Lua ложными считаются лишь nil и false, поэтому ноль тоже выключает. Нумерация по порядку отправки это просто порядок строк в функции.

Четыре фейка, четыре выключателя Четыре фейка fakedsplit пронумерованы по порядку отправки и у каждого свой выключатель: в игрушке с двумя пачками и четырьмя пустышками пустышка 1 стоит перед первой пачкой, 2 после неё, 3 перед второй, 4 после второй; в настоящей функции шесть пакетов идут как фейк 1, настоящая первая часть, фейк 2 в смысле повтора, фейк второй части, настоящая вторая часть и последний фейк, а выключатели называются nofake1, nofake2, nofake3 и nofake4; в коде перед отправкой каждого фейка стоит проверка наличия ключа с таким номером, поэтому значение ключа не важно, даже ноль убирает фейк, ведь в Lua ложны только nil и false, а настоящие части выключатели не трогают. четыре фейка по порядку отправки и их выключатели игрушка (выдуманный пример): две пачки и четыре пустышкипустышка 1перед первойпачка 1настоящаяпустышка 2после первойпустышка 3перед второйпачка 2настоящаяпустышка 4после второй настоящая функция: шесть пакетов по порядку отправки F104@01R104@0F104@02F146@1043R146@104F146@1044 nofake1остаётсяnofake2nofake3остаётсяnofake4 номер в имени выключателя: номер фейка по порядку отправки; настоящие части остаются код функцииfakedsplitlua/zapret-antidpi.lua858if not desync.arg.nofake1 thenперед первой настоящей882if not desync.arg.nofake2 thenпосле первой настоящей889if not desync.arg.nofake3 thenперед второй настоящей900if not desync.arg.nofake4 thenпосле второй настоящейпорядок строк в функции и есть нумерация проверяется только наличиеключа, а не его значениеключ есть: фейк убранв Lua ложны только nil и false,поэтому даже ноль убирает фейкпрогон функцийnofake1=0

Выключаем первый фейк, тот, что шёл перед первой настоящей частью. На проводе нашего теста пять пакетов: настоящая первая часть идёт первой, потом фейк первой части, фейк второй части, настоящая вторая часть и фейк второй.

Выключаем второй, тот, что шёл после первой настоящей части. Пять пакетов: фейк первой части, настоящая первая часть, потом сразу фейк второй, настоящая вторая и ещё фейк второй. Фейка первой части после настоящей нет.

Выключаем третий, тот, что шёл перед второй настоящей частью. Фейк первой части, настоящая первая, снова фейк первой части, и дальше сразу настоящая вторая часть и фейк после неё. Перед второй настоящей частью фейка нет.

Выключаем четвёртый, последний. Фейк первой части, настоящая, фейк, фейк второй части, и настоящая вторая часть замыкает серию. После неё фейка нет.

А если выключить все четыре? Остаются две настоящие части: сто четыре байта с номером один и сто сорок шесть с номером сто пять. Это в точности то, что уходит от обычного multisplit с той же меткой. Такой запуск называется fakedsplit, но фейков не посылает. При любых выключателях настоящие части остаются на месте: выключатели трогают только фейки.

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

Проверь себя. Выключаем первый и третий фейки одновременно. Какие пакеты уйдут и в каком порядке?

Настоящая первая часть, фейк первой части, настоящая вторая часть, фейк второй части. То есть остались только фейки, которые идут после настоящих частей. В нашем тесте на проводе именно так.

Пять запусков с выключателями Пять запусков fakedsplit с выключенными фейками: без фейка 1 на проводе настоящая первая часть идёт первой и остаются пять пакетов, без фейка 2, без фейка 3 и без фейка 4 тоже по пять пакетов с пустым местом убранного фейка, а когда выключены все четыре, остаются только настоящие части по 104 и 146 байт, как у обычного multisplit с той же меткой; во всех запусках приложение сервера получило 250 байт, равных оригиналу; в проверке выключатели nofake1 и nofake3 вместе дают четыре пакета: настоящая первая часть, фейк первой части, настоящая вторая часть и фейк второй части, то есть остаются только фейки после настоящих частей. пять запусков: какой фейк убран и что осталось на проводе фейк с MD5настоящая частьубранный фейк на своём местеприложение сервера nofake1убранR104@0F104@0F146@104R146@104F146@104250 байт: оригинал nofake2F104@0R104@0убранF146@104R146@104F146@104250 байт: оригинал nofake3F104@0R104@0F104@0убранR146@104F146@104250 байт: оригинал nofake4F104@0R104@0F104@0F146@104R146@104убран250 байт: оригинал все четыреубранR104@0убранубранR146@104убран250 байт: оригинал multisplitR104@0R146@104250 байт: оригинал = проверь себя: выключаемnofake1 и nofake3вместе --lua-desync=fakedsplit:pos=midsld:tcp_md5:nofake1:nofake3 nofake1, 3 ???? убранR104@0F104@0убранR146@104F146@104250 байт: оригинал остались только фейки после настоящих частей: четыре пакета

Итак. У fakedsplit четыре фейка, пронумерованные по порядку отправки, и четыре выключателя nofake. Убрав все четыре, получаем обычный разрез на две части. Что каждый фейк даёт, покажут игрушечные читатели.

Накладка числом, nodrop, повторы и номера пакетов

Вопрос сцены: что делают остальные настройки fakedsplit?

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

Это накладка, seqovl, она знакома по выпуску про multisplit. В fakedsplit она относится к первой настоящей части и записывается только числом. Запуск с seqovl равно пять: первая настоящая часть выросла на пять нулевых байт, сто девять байт вместо ста четырёх, и начинается она на пять номеров раньше. Один минус пять, минус четыре.

Сервер в нашем тесте ответил подтверждением сто пять и дублирующим блоком от минус четырёх до нуля: пять лишних байт он назвал повтором. Приложение прочитало оригинал.

Для пятидесяти получается сто пятьдесят четыре байта, начало на пятьдесят номеров раньше и блок от минус сорока девяти до нуля.

Байты накладки по умолчанию нули. Свой узор для них в коде задаётся отдельным аргументом; в лаборатории такого запуска у нас нет.

Теперь ловушка. Если вместо числа написать слово, например host, функция упадёт с ошибкой. В коде накладка проверяется сравнением числа с нулём, у слова числа нет, и сравнение падает. Но к этому моменту первый фейк уже ушёл. На проводе нашего теста фейк первой части, а потом оригинальное приветствие целиком, двести пятьдесят байт, с тем же идентификатором IP, что у фейка. В журнале: ошибка и «пакет проходит без изменений».

Запомните: в fakedsplit seqovl только число. В одной из функций дальше то же слово будет меткой, как в multidisorder.

Накладка: число и слово Накладка seqovl в fakedsplit записывается только числом: в игрушке перед первой пачкой подшиты пять лишних листов с номерами раньше первой страницы и получатель их откладывает; при seqovl равном 5 первая настоящая часть растёт на пять нулевых байт до 109 байт и начинается с номера минус 4, сервер отвечает подтверждением 105 и блоком дубля от минус 4 до 1, при seqovl равном 50 получается 154 байта с номером минус 49 и блоком от минус 49 до 1, а приложение в обоих запусках читает все 250 байт оригинала; если вместо числа написать слово, функция падает на сравнении числа с пустым значением уже после первого фейка, на проводе остаются фейк первой части и оригинал целиком с тем же ip id, а в журнале ошибка и запись о том, что пакет проходит без изменений. накладкаseqovlв fakedsplit: только число игрушка (выдуманный пример): лишние листы перед первой страницейпять лишних листовраньше первой страницыполучатель знает:в книге таких нетпоэтому он откладываетлишние листы в сторону на ленте номеров: относительные номера, первый байт данных это 1 -49-41105251 seqovl=5пакет 109 байт = 5 + 104, номер 1 - 5 = -4вторая часть: 146 байтнастоящая часть: 104 нули × 5 (лишние)ответ сервера: ACK 105 и блок [-4,1): пять байт перед окном названы повтором seqovl=50пакет 154 байта = 50 + 104, номер 1 - 50 = -49вторая часть: 146 байтнастоящая часть: 104 нули × 50 (лишние)ответ сервера: ACK 105 и блок [-49,1); приложение в обоих запусках: 250 байт, оригинал ловушка: слово вместо числаseqovl=host на проводе нашего тестаF104@0потомR250@0 целикомодинip id журнал программыLUA ERROR: ...attempt to compare number with nildesync ERROR. passing packet unmodified. 866:if desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 thenу слова нет числа один фейк уже ушёл, потом оригинал целиком; в другой функции выпуска это слово метка, как в multidisorder

Теперь nodrop. Обычно оригинал выбрасывается. С nodrop после шести пакетов уходит ещё и оригинал, двести пятьдесят байт, и несёт идентификатор первого фейка: помните правило, первый вышедший пакет берёт идентификатор исходного. Сервер в нашем тесте ответил подтверждением двести пятьдесят один и дублирующим блоком от первого до двести пятидесятого байта: «всё это у меня уже есть».

Теперь repeats. Запуск с repeats равно два: каждый фейк уходит дважды, а настоящие части по разу. Всего десять пакетов: четыре фейка по два и две настоящих. В коде повторы стоят только в настройках фейков, поэтому настоящие части всегда уходят по разу. Идентификаторы IP идут подряд в порядке отправки, как в выпуске про multisplit.

Это правило можно отменить аргументом, который в строке пишется «ай-пи, подчёркивание, ид», со значением zero: в нашем запуске все шесть идентификаторов оказались нулями.

Проверь себя. В запуске repeats равно два десять пакетов. Сколько разных идентификаторов IP на проводе?

Шесть. Повтор фейка носит тот же идентификатор, что и сам фейк, поэтому разных значений столько же, сколько пакетов без повторов. В нашем тесте идентификаторы шли подряд, шесть значений.

Nodrop, repeats, ip id Три настройки fakedsplit на проводе нашего теста: с nodrop после шести пакетов уходит ещё и оригинал в 250 байт с тем же ip id, что у первого фейка, и сервер отвечает подтверждением 251 с блоком дубля от 1 до 251; с repeats равным 2 каждый фейк идёт дважды, настоящие части по разу, всего десять пакетов, а повтор фейка несёт тот же ip id, поэтому на десять пакетов приходится шесть разных значений подряд; аргумент ip_id со значением zero делает все шесть идентификаторов нулями; ответ на проверку про десять пакетов: шесть разных ip id. сnodropоригинал уходит следом за шестью пакетами F104@065337R104@065338F104@065339F146@10465340R146@10465341F146@10465342R250@065337ip id: оригинал несёт идентификатор первого фейка (значения меняются от запуска к запуску) ответ сервера: ACK 251 и блок [1,251): всё это у меня уже есть сrepeats=2каждый фейк дважды, настоящие части по разу F104@057930F104@057930R104@057931F104@057932F104@057932F146@10457933F146@10457933R146@10457934F146@10457935F146@10457935 шесть разных значений подряд: 57930 … 57935; в коде повторы только у фейков аргументip_id=zeroвсе шесть идентификаторов нули F104@0ip id 0R104@0ip id 0F104@0ip id 0F146@104ip id 0R146@104ip id 0F146@104ip id 0 проверь себя: десять пакетов приrepeats=2сколько разных ip id ваш ответ? шесть: повтор фейка носит тот же ip id, что и сам фейк

Итак. Накладка в fakedsplit это число и относится к первой настоящей части. С nodrop оригинал идёт следом, с repeats фейки повторяются, а идентификаторы IP идут подряд, если их не отменить. А слово вместо числа ломает стратегию уже после первого фейка.

Длинное приветствие и запрос HTTP; когда длины фейка и настоящей части расходятся

Вопрос сцены: что изменится, если данных больше одного пакета или это не TLS?

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

Теперь настоящие опыты. Сначала большое приветствие на тысячу четыреста восемьдесят четыре байта, с той же меткой midsld. Оно длиннее одного пакета, поэтому программа сначала задерживает куски, собирает приветствие целиком и проигрывает его заново: это разбирает выпуск «Сборка и повторный проигрыш» в конце серии. Для нас важно одно: функция получает все байты сразу.

На проводе в нашем тесте те же шесть пакетов: фейк в сто четыре байта, настоящая часть, фейк, потом фейк в тысячу триста восемьдесят байт, настоящая часть и ещё фейк. Сервер прочитал приветствие целиком, и оно совпало с оригиналом. Запрос HTTP на восемьдесят один байт с меткой midsld в заголовке Host даёт те же шесть пакетов, части в тридцать девять и сорок два байта, и сервер читает запрос целиком с верным Host.

Большое приветствие и HTTP Длинное приветствие и запрос HTTP с fakedsplit и условием MD5: в игрушке фургон вмещает десять коробок, а с наклейкой только восемь, поэтому одну стопку делят в разных местах; приветствие в 1484 байта с меткой midsld уходит теми же шестью пакетами, фейк и настоящая часть по 104 байта, затем фейк, настоящая часть и фейк по 1380 байт, перед этим программа удерживает куски, собирает приветствие целиком и проигрывает его заново, сервер читает 1484 байта, равных оригиналу; запрос HTTP в 81 байт с меткой midsld внутри имени в заголовке Host даёт те же шесть пакетов с частями по 39 и 42 байта, и сервер читает запрос целиком с верным именем. данных больше или это не TLS: тот же рисунок из шести пакетов игрушка (выдуманный пример): фургон и коробки с наклейкойбез наклейки: влезает 10с наклейкой: влезает 8одну стопку делят на фургоны в разных местах, смотря с наклейкой коробки или без приветствие 1484 байта, метка midsld F104@0R104@0F104@0F1380@104R1380@104F1380@104 вторая часть: 1380 байтпервая часть: 104сервер: 1484 байта, равны оригиналу приветствие длиннее одного пакета: программа сначала удерживает куски, собирает его целикоми проигрывает заново (отдельный выпуск в конце серии); функция получает все байты сразу запрос HTTP 81 байт, метка midsld внутри имени F39@0R39@0F39@0F42@39R42@39F42@39 Host: www.example.com, байты 32..4639 байт42 байтаразрез на 39: внутри именисервер: 81 байт, равны оригиналу, Host верный

А теперь случай, где длины расходятся. То же большое приветствие, но разрез у самого начала: pos равно два, части в два байта и в тысячу четыреста восемьдесят два. Вторая часть длиннее предела, и её режут на ломтики, как в выпуске про multisplit.

Предел мы считали в выпусках про multisplit и про фейки. Порция тысяча четыреста шестьдесят. У настоящего пакета опции двенадцать байт: тысяча четыреста шестьдесят минус двенадцать, тысяча четыреста сорок восемь. Остаток второй части, тысяча четыреста восемьдесят два минус тысяча четыреста сорок восемь, тридцать четыре.

У фейка с эм-дэ-пять опции тридцать два байта: тысяча четыреста шестьдесят минус тридцать два, тысяча четыреста двадцать восемь. Остаток пятьдесят четыре.

Вот что в нашем тесте на проводе. Фейк второй части идёт ломтиками в тысячу четыреста двадцать восемь и пятьдесят четыре байта, настоящая часть ломтиками в тысячу четыреста сорок восемь и тридцать четыре. Фейки по-прежнему лежат на тех же байтах, но второй ломтик фейка начинается с номера тысяча четыреста тридцать один, а второй ломтик настоящей части с номера тысяча четыреста пятьдесят один.

Сервер всё равно прочитал тысячу четыреста восемьдесят четыре байта, равных оригиналу. А оба больших пакета, и фейк, и настоящий, занимают ровно полторы тысячи байт: у фейка лишние двадцать байт опций съели те самые двадцать байт данных.

Проверь себя. То же самое, но условие не эм-дэ-пять, а срок жизни один: лишних опций нет. Какие ломтики у фейка второй части?

Те же, что у настоящей части: тысяча четыреста сорок восемь и тридцать четыре. В нашем тесте так и вышло: границы совпали. Условие, которое не добавляет опций, ломтики не сдвигает.

Границы ломтиков расходятся Метка pos равная 2 на приветствии в 1484 байта даёт части в 2 и 1482 байта и девять пакетов, потому что вторая часть длиннее предела и режется на ломтики по-разному: у настоящего пакета опции занимают 12 байт, максимум 1460 минус 12 равен 1448 и остаток 34, у фейка с MD5 опции занимают 32 байта, максимум 1460 минус 32 равен 1428 и остаток 54, поэтому граница нарезки у фейков на 1430, у настоящих на 1450, второй ломтик начинается с номера 1431 у фейка и 1451 у настоящей части, оба больших пакета занимают по 1500 байт, а сервер всё равно читает 1484 байта, равных оригиналу; при условии срок жизни 1 лишних опций нет и у фейка с настоящей частью границы совпадают, обе части режутся на 1448 и 34 байта. меткаpos=2на том же приветствии: части 2 и 1482 байта F2@0R2@0F2@0F1428@2F54@1430R1448@2R34@1450F1428@2F54@1430 на ленте из 1484 байт: где нарезано фейк 2-й части: 1428 + 54граница на 1430142854 настоящая 2-я часть: 1448 + 34граница на 1450144834 границы разошлись: второй ломтик фейка с номера 1431, настоящей части с номера 1451 настоящий пакетпорция (MSS) 1460опции 12 байт: NOP NOP TS1460 - 12 = 1448 байт данных1482 - 1448 = 34 байта остаток фейк с tcp_md5порция (MSS) 1460опции 12 + 18 (MD5) = 30, до 321460 - 32 = 1428 байт данных1482 - 1428 = 54 байта остаток длина IP у обоих больших пакетов 1500: 20 + 52 + 1428 у фейка, 20 + 32 + 1448 у настоящего сервер всё равно прочитал 1484 байта, равных оригиналу проверь себя: условиеip_ttl=1лишних опций нет, какие ломтики у фейка фейк 2-й частикакие куски? фейк 2-й части144834 настоящая 2-я часть144834 те же, что у настоящей части: 1448 и 34; условие без лишних опций границы не сдвигает

Итак. Правило «тот же номер и та же длина» верно, пока ни одну часть не режут заново по пределу размера. Для нашего приветствия с разрезом у имени оно верно, у самого начала длинного приветствия нет. Фейки всё равно лежат на тех же байтах, а сервер читает оригинал.

Что мы знаем: приёмник и фейки одной таблицей

Остановимся и сведём всё, что мы узнали о fakedsplit. Всё это относится к нашему тесту, одному приёмнику, Linux, и нашей игрушечной модели. О настоящем оборудовании мы по-прежнему ничего не знаем.

Первое. Шесть пакетов: фейк, настоящая часть, фейк, потом снова фейк, настоящая часть, фейк. Оригинальное приветствие выброшено. Фейк лежит на тех же номерах и той же длины, что настоящая часть рядом, пока ни одну часть не режут заново по пределу размера. Тот же рисунок получается и на запросе HTTP, и на длинном приветствии.

Второе. В фейке по умолчанию нули, но можно задать узор. Фейк умирает от эм-дэ-пять или испорченной суммы на самом сервере, от срока жизни один в роутере. Нарезка по пределу размера сдвигает границы у фейка с опцией эм-дэ-пять: это измерено. У фейка со сроком жизни один границы те же: это измерено тоже. Для испорченной суммы запуска на длинном приветствии нет, по счёту она опций не добавляет, и границы не сдвинет.

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

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

Пятое. Четыре выключателя убирают фейки по одному, а когда выключены все четыре, остаётся обычный разрез. Накладка в fakedsplit записывается только числом, слово даёт ошибку после первого фейка. Ещё есть nodrop, repeats и идентификаторы IP подряд.

Шестое. Позиция pos это одна метка. В нашем тесте позиция ноль или значение за концом приветствия: стратегия молчит, и оригинал уходит целым.

Теперь о том, чего мы не знаем. Мы не знаем, как поведёт себя другой получатель: Windows, BSD или встроенная система. Мы проверили только Linux. Мы не знаем, как устроен настоящий инспектор: что он читает, видит ли фейки и какую копию считает главной. И мы пока не знаем, как справятся с этой серией наши игрушечные читатели: это ближе к концу выпуска.

Итог по fakedsplit Что мы знаем про fakedsplit по нашему тесту, одному приёмнику на Linux и нашей игрушечной модели, девятью строками: шесть пакетов и выброшенный оригинал; фейк лежит на тех же номерах и той же длины, пока часть не режут заново по пределу; в фейке по умолчанию нули, но можно задать узор; MD5 и испорченная сумма убивают фейк на сервере, срок жизни 1 убивает его в роутере; сервер отвечает подтверждением 105 и читает оригинал; без условия в приложении нули и четыре дублирующих блока; четыре выключателя убирают фейки по одному, при всех выключенных остаётся обычный разрез; накладка только числом; метка pos одна, ноль и значение за концом приветствия оставляют оригинал целым; внизу три серые плашки с замками о том, чего мы не знаем: другие получатели, настоящий инспектор и игрушечные читатели на этой серии. итог дляfakedsplitнаш тест, один приёмник на Linux, наша игрушечная модель 1шесть пакетов: фейк, настоящая, фейк, фейк, настоящая, фейк; оригинал выброшенв нашем тесте 2фейк на тех же номерах и той же длины, пока часть не режут заново по пределуломтики: MD5 сдвигает, срок жизни 1 нет (измерено); плохая сумма: по счётув нашем тестепо счёту 3по умолчанию в фейке нули; можно задать узорв нашем тесте 4MD5, плохая сумма: фейк умирает на сервере (счётчик 4); TTL 1: в роутере (ICMP 4)в нашем тесте 5сервер: ACK 105, молчит на фейки, читает оригинал; ответы как у обычного разрезав нашем тесте 6без условия: нули в приложении, дублирующих блоков 4в нашем тесте 7четыре выключателя nofake1..4; выключены все: обычный разрезв нашем тесте 8накладка только числом, слово даёт ошибку; nodrop, repeats, ip id подрядв нашем тесте 9pos одна метка; ноль или значение за концом: стратегия молчит, оригинал целв нашем тесте чего мы не знаем другие получателиWindows, BSD, встроенныене проверялинастоящий инспекторчто читает, видит ли фейкинеизвестноигрушечные читателикак справятся с этой сериейвпереди в выпуске

Проверь себя по этой таблице. Запуск: fakedsplit с позицией host, условием эм-дэ-пять и выключателями nofake один и nofake четыре. Какие пакеты уйдут?

Позиция host даёт части в девяносто семь и сто пятьдесят три байта. Первый выключатель убирает фейк перед первой настоящей частью, четвёртый убирает последний. Остаются четыре пакета: настоящая первая часть, фейк первой части, фейк второй и настоящая вторая. Это расчёт по правилам: такого запуска в лаборатории не было.

Теперь мы знаем, что отправил fakedsplit и что ответил сервер. Следующий вопрос: что, если отправить вторую половину раньше первой, да ещё между фейками? Для этого есть следующая функция, «перемешивание с фейками», по-латински fakeddisorder, ей посвящена следующая часть выпуска.

Проверка и мостик Проверка по итоговой таблице и мостик к следующей функции: запуск fakedsplit с позицией host, условием MD5 и выключателями nofake1 и nofake4 даёт части 97 и 153 байта и четыре пакета, настоящая первая часть, фейк первой части, фейк второй части и настоящая вторая часть, это расчёт по правилам выключателей, такого запуска в лаборатории не было; ниже две строки с шестью пакетами, у разреза с фейками первой уходит первая часть, у перемешивания с фейками fakeddisorder первой уходит вторая часть, и вопрос, что будет, если отправить вторую половину раньше первой, разбирается дальше в выпуске. проверь себя по таблице --lua-desync=fakedsplit:pos=host:tcp_md5:nofake1:nofake4pos=host: части 97 и 153 байта ???? убранnofake1R97@0F97@0F153@97R153@97убранnofake4 остаются четыре пакета: настоящая 1-я часть, фейк 1-й, фейк 2-й, настоящая 2-я часть расчёт по правилам выключателей: такого запуска в лаборатории не было что дальше разрез с фейкамиfakedsplitпервая часть уходит первойF104@0R104@0F104@0F146@104R146@104F146@104 перемешивание с фейкамиfakeddisorderвторая часть уходит первойF146@104R146@104F146@104F104@0R104@0F104@0 что, если отправить вторую половину раньше первой?дальше в выпуске

Итак. Мы прошли первый запуск, содержимое и смерть фейка, ответы сервера, пограничные значения pos, запуск без условия, четыре выключателя и несколько тонких настроек. Все выводы об эффекте относятся к нашему приёмнику и нашей игрушечной модели.

Повтор и вопрос: три вопроса, которые остались после разреза с фейками

Продолжаем выпуск «Резать и подделывать вместе». Начнём с короткого повтора того, что нам понадобится.

Сразу оговорка, она будет повторяться. О настоящем оборудовании на пути пакетов мы не знаем ничего. У нас два участника, и оба наши: игрушечный инспектор в роутере лаборатории и сервер на Linux. Слово «сработало» значит только одно: приём обошёл нашу игрушку, а сервер получил настоящие данные.

Первое напоминание, из выпусков «multisplit: резать на части» и «Фейк и его условия». Приветствие в нашей лаборатории занимает двести пятьдесят байт, и разрез делит его на куски. Фейк это лишний пакет рядом с настоящим. Условие это дефект фейка, из-за которого получатель его выбросит: лишняя опция эм-дэ-пять, время жизни один или испорченная контрольная сумма.

Договоримся о числах. Смещение это сколько байт стоит перед нужным, считая с нуля. Номер на единицу больше. Имя сайта лежит со смещения девяносто семь, а его первый байт имеет номер девяносто восемь.

Как читать ответы сервера. Ответ «жду байт номер сто» значит: девяносто девять байт у сервера уже есть. К ответу может прилагаться блок: это байты, которые лежат у сервера в стороне. Если блок дублирующий, эти байты у него уже были.

Повтор: участники, числа и ответы Повтор перед выпуском: в роутере стоит наша игрушка-инспектор, а сервер на Linux, и слово «сработало» значит только то, что приём обошёл игрушку, а данные дошли до сервера целыми; приветствие в 250 байт разрезано на 104 и 146 байт, имя сайта занимает смещения с 97 по 111, смещение 97 равно номеру 98, а ответ сервера «жду байт номер 100» значит, что 99 байт у него уже есть, блок лежит в стороне, а дублирующий блок состоит из байт, которые уже были. повтор: кто участвует, как считать байты, как читать ответ сервера клиент роутер лабораторииигрушечный инспектор сервернаш приёмник: Linux игрушка: наша модель, не оборудование сработало = обошли нашу игрушку и данные дошли до сервера целыми приветствие в нашей лаборатории: 250 байт, разрез делит его на куски первая часть: 104вторая часть: 1460250 www.example.com: смещения 97…111 104 104 + 146 = 250 смещение: сколько байт стоит перед нужнымсчёт с нуля: имя на смещении 97 номер: на единицу больше смещенияпервый байт имеет номер 1: имя с номера 98 как читать ответ сервера 99 байт уже у сервера: номера 1…99 ответ: жду байт номер 100 блок: лежит в стороне (пример) уже было блок дублирующий: эти байты у сервера уже были

Второе напоминание, из начала этого выпуска. Разрез с фейками, функция fakedsplit, режет приветствие на сто четыре байта и сто сорок шесть и отправляет шесть пакетов: фейк, настоящая первая часть, фейк, потом фейк, настоящая вторая часть и фейк. Номера и длины у фейка те же, что у настоящей части рядом. Четыре фейка можно выключать по одному ключами nofake.

Сервер в нашем тесте на такие фейки молчит, а приложение читает оригинал. Без условия всё наоборот: в нашем тесте сервер принял фейки за настоящие данные, настоящие части оказались лишними, и приложение получило одни нули.

Третье напоминание, из выпуска «Перемешать: disorder». Стратегия multidisorder отправляет части с последней до первой. Сервер отвечает: байт номер один жду по-прежнему, но конец у меня уже лежит. Когда приходит начало, он отвечает, что ждёт байт номер двести пятьдесят один, и приложение читает все двести пятьдесят байт одним чтением.

С этим остались три вопроса. Игрушка, выдуманная: книга на двести пятьдесят страниц, две пачки, а вокруг каждой пачки пустые листы с теми же номерами. Что, если вторую пачку отправить раньше первой? Что, если подкладывать не пустые листы, а подложное имя вместо настоящего? И что, если разрез и фейк делают две отдельные стратегии, одна за другой?

Повтор запусков и три вопроса Повтор двух запусков и три вопроса: разрез с фейками отправляет шесть пакетов, фейк, настоящая первая часть 104 байта, фейк, потом фейк, настоящая вторая часть 146 байт и фейк, сервер молчит на фейки и отвечает «жду байт номер 105», приложение получает 250 байт, равных оригиналу, а без условия приложение получает 250 нулевых байт; перемешивание отправляет настоящие части с конца, 146 байт, потом 104, и сервер отвечает «жду байт номер 1» с блоком со 105-го по 250-й, а затем «жду байт номер 251»; остались три вопроса, что если вторая пачка идёт первой, что если подкладывать только подложное имя и что если разрез и фейк идут двумя стратегиями подряд. повтор: что уходит в сеть в двух прошлых запусках разрез с фейками, шесть пакетов по порядку отправкипунктир: фейк, сплошная: настоящая часть фейкномер 1 · 104 настоящаяномер 1 · 104 фейкномер 1 · 104 фейкномер 105 · 146 настоящаяномер 105 · 146 фейкномер 105 · 146 ответ: ack 105 nofake1 nofake2 nofake3 nofake4 с условием: приложение 250 байт, равны без условия: приложение 250 байт, все нулевые перемешивание (multidisorder), части с конца настоящаяномер 105 · 146ack 1 + блок [105,251) настоящаяномер 1 · 104ack 251 в стороне лежит конец приложение: 250 байт, равныжду байт номер 251: всё на месте остались три вопроса 1что, если вторая пачкаидёт первой?перемешивание с фейкамиfakeddisorder 2что, если подкладыватьтолько подложное имя?имя между двойникамиhostfakesplit 3что, если разрез и фейкэто две стратегии подряд?пара: два экземпляраfake, затем multisplit

Ответы такие. Перемешивание с фейками, в программе функция fakeddisorder. Имя между двойниками, функция hostfakesplit. И пара: две стратегии в одной строке, сначала fake, потом multisplit. Идём по проводу, пакет за пакетом, а код откроем в самом конце выпуска, когда будем знать, что в нём искать.

Итак. У нас есть разрез с фейками из шести пакетов, обязательное условие и четыре выключателя. Дальше три новые конструкции, и начнём с той, где вторая половина данных уходит первой.

Перемешивание с фейками: вторая половина идёт первой

Вопрос сцены: что уходит в сеть, когда вторая половина приветствия идёт первой, а каждая настоящая половина стоит между двумя фейками? Идём по проводу, как в начале выпуска.

Игрушка, выдуманная. Та же книга на две пачки, но курьер везёт первой вторую пачку, страницы со ста пятой по двести пятидесятую, а потом первую. Вокруг каждой пачки лежат чистые листы с теми же номерами.

Перемешивание с фейками. В программе эта функция называется fakeddisorder. На проводе это то же, что multidisorder из выпуска «Перемешать: disorder», плюс фейки вокруг каждой части; при всех выключенных фейках провод совпадает. Разрез по-прежнему один. Строка запуска та же, что в начале выпуска: фильтр на приветствие, метка midsld и условие, которое в записи называется tcp_md5, то есть опция эм-дэ-пять. Меняется только имя функции.

Перемешивание с фейками: шесть пакетов Перемешивание с фейками, шесть пакетов клиента по порядку: фейк второй половины с номером 105 и длиной 146, настоящая вторая половина с теми же номером и длиной, ещё фейк второй половины, потом фейк первой половины с номером 1 и длиной 104, настоящая первая половина и ещё фейк первой, сервер молчит на фейки, на настоящую вторую отвечает «жду байт номер 1» с блоком со 105-го по 250-й, а когда приходит первая половина, отвечает «жду байт номер 251», и приложение читает 250 байт, равных оригиналу, с именем сайта. перемешивание с фейками: что уходит в сеть и что отвечает сервер --payload=tls_client_helloтолько приветствие TLS --lua-desync=fakeddisorderперемешивание с фейками :pos=midsldразрез :tcp_md5условие игрушка: пачка 105…250 едет первой, потом 1…104; вокруг каждой чистые листы с теми же номерами клиентроутерсервер 1фейк второй половиныномер 105 · длина 146 · нули · MD5IP 218 Б ответа нет 2настоящая вторая половинаномер 105 · длина 146 · начало «mple.com»IP 198 Б ack 1 + блок [105,251)жду байт 1, в стороне 105…250 3тот же фейк ещё разномер 105 · длина 146 · нули · MD5IP 218 Б ответа нет 4фейк первой половиныномер 1 · длина 104 · нули · MD5IP 176 Б ответа нет 5настоящая первая половинаномер 1 · длина 104 · начало приветствияIP 156 Б ack 251жду байт 251, блока нет 6тот же фейк первой половиныномер 1 · длина 104 · нули · MD5IP 176 Б ответа нет фейк: сервер отбросил из-за MD5настоящая часть дошла что лежит у сервера1250 блок 105…250 в сторонедыра 1…104 настоящая 1…104настоящая 105…250 сервер ждёт байт номер 1 251 приложение сервера: 250 байт, одно чтение, хэш совпал с оригиналомсервер нашёл в приветствии имя www.example.comпо общим сведениям: пока в начале дыра, приложению нечего отдать

Пакеты нашего теста по порядку. Первый: фейк второй половины. Номер сто пять, длина сто сорок шесть, внутри нули и опция эм-дэ-пять. Сервер молчит.

Второй: настоящая вторая половина, тот же номер сто пять и те же сто сорок шесть байт, они начинаются с mple.com. Сервер отвечает: байт номер один жду по-прежнему, а байты со ста пятого по двести пятидесятый у меня лежат в стороне. Это ответ с блоком, как в выпуске «Перемешать: disorder».

Третий: тот же фейк второй половины ещё раз. Ответа нет.

Четвёртый: фейк первой половины. Номер один, длина сто четыре, внутри нули и опция эм-дэ-пять. Ответа нет, дыра в начале остаётся.

Пятый: настоящая первая половина, номер один, сто четыре байта начала приветствия. Дыра закрыта, и сервер отвечает: жду байт номер двести пятьдесят один.

Шестой: повтор фейка первой половины, снова тишина. В итоге на сервере остались только настоящие байты.

Приложение в нашем тесте прочитало двести пятьдесят байт одним чтением. Байты равны оригиналу, а сервер нашёл в приветствии имя www.example.com. Одно чтение: пока в начале дыра, приложению нечего отдать; так обычно работает приём в Linux, по общим сведениям.

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

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

Как умирают фейки и что видит игрушка Как умирают фейки перемешивания и что видит игрушка в роутере: с опцией MD5 до сервера доходят все шесть пакетов, а счётчик ядра сервера насчитывает четыре отброшенных, с временем жизни 1 фейки гибнут в роутере, до сервера доходят только два настоящих пакета, а клиент получает четыре сообщения «время истекло», с испорченной суммой счётчик ошибок суммы показывает четыре, и во всех трёх запусках приложение получает 250 байт, равных оригиналу; все пять игрушечных читателей в роутере не нашли имя, а если выключить все фейки, сервер ответит «жду байт номер 1» с блоком со 105-го по 250-й и затем «жду байт номер 251». три способа умереть для фейка, и что видят читатели в роутере опция MD5tcp_md5клиентроутерсервердо сервера дошли все 6 пакетовсчётчик ядра: отброшено по MD5 = 4 время жизни 1ip_ttl=1клиентроутерсервердо сервера дошли 2 настоящих пакетана клиенте 4 сообщения «время истекло» испорченная суммаbadsumклиентроутерсервердо сервера дошли все 6 пакетовсчётчик ошибок суммы = 4 во всех трёх запусках приложение получило 250 байт, равных оригиналу игрушечная модель: пять читателей в роутере принимают фейк за обычные данные пакетныйне нашёл имя склейщикне нашёл имя первый записалне нашёл имя последний записалне нашёл имя строго по порядкуне нашёл имя на сервер дошли 250 байт, равные оригиналу; подробнее о читателях дальше в этом выпуске проверь себявсе четыре фейка выключены: что сервер ответит на первый пакет? 1настоящая вторая: номер 105 · длина 146ack 1 + блок [105,251) 2настоящая первая: номер 1 · длина 104ack 251 так и вышло в нашем тесте: на фейки сервер не отвечает, он их выбрасывает

Проверь себя. Все четыре фейка выключены, остаются две настоящие части. Что сервер ответит на первый пакет?

То же самое: жду байт номер один и блок со ста пятого байта, потом жду байт номер двести пятьдесят один. В нашем тесте так и вышло. Фейки на ответы сервера не влияют: он их выбрасывает и не отвечает.

Итак. Перемешивание с фейками отправляет шесть пакетов: фейк второй половины, настоящая вторая, ещё фейк второй, потом фейк первой, настоящая первая и ещё фейк первой. Сервер молчит на фейки, держит вторую половину в стороне и, когда приходит первая, ждёт байт номер двести пятьдесят один. Это в нашем тесте, на одном приёмнике, Linux.

Перемешивание с фейками: без условия, выключатели и другие данные

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

Игрушка, выдуманная. Кладовщик кладёт на место полки первую пришедшую стопку, а всё, что приходит позже на то же место, называет дублем. Сначала приходят чистые листы с номерами второй половины, и настоящая вторая половина оказывается дублем. С первой половиной то же.

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

Без условия фейки принимаются как данные Перемешивание с фейками без условия: шесть пакетов те же по номерам и длинам, но у фейков нет опции MD5, и для сервера это обычные пакеты, поэтому фейк второй половины принят за настоящий, настоящая вторая половина и повтор фейка получают ответ с дублирующим блоком со 105-го по 250-й, фейк первой половины закрывает дыру нулями и сервер отвечает «жду байт номер 251», настоящая первая половина тоже становится дублем, дублирующих ответов четыре, приложение читает 250 нулевых байт без приветствия и без имени сайта, с условием сервер ответил два раза, а без условия шесть, и общего правила побеждает первый мы не выводим. перемешивание с фейками без условия: для сервера фейки обычные пакеты игрушка: кладовщик кладёт на место первую пришедшую стопку, всё позже на то же место называет дублем пустые 105…250 настоящая 105…250дубль пустые 1…104 настоящая 1…104дубль клиентроутерсервер 1фейк второй половиныномер 105 · длина 146 · нули · без MD5IP 198 Б ack 1 + блок [105,251)принят как настоящий 2настоящая вторая половинаномер 105 · длина 146 · начало «mple.com»IP 198 Б ack 1 + дубль [105,251)эти байты уже были 3тот же фейк ещё разномер 105 · длина 146 · нули · без MD5IP 198 Б ack 1 + дубль [105,251)снова дубль 4фейк первой половиныномер 1 · длина 104 · нули · без MD5IP 156 Б ack 251дыра закрыта нулями 5настоящая первая половинаномер 1 · длина 104 · начало приветствияIP 156 Б ack 251 + дубль [1,105)и она стала дублем 6тот же фейк первой половиныномер 1 · длина 104 · нули · без MD5IP 156 Б ack 251 + дубль [1,105)дубль фейк принят сервером как обычный пакетнастоящая часть что лежит у сервера1250 нули 105…250 нули 1…104 настоящая 105…250: дубль настоящая 1…104: дубль сервер ждёт байт номер 1 251 приложение сервера: 250 байт, все нулевыени приветствия, ни имени сайта: настоящие части оказались лишними с условием сервер ответил 2 раза, без условия 6; дублирующих ответов 0 против 4 правило «побеждает первый» мы не выводим, другой приёмник не проверялидальше будет запуск, где нули пришли первыми, а приложение прочитало настоящие байты

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

Фейк первой половины закрывает дыру ста четырьмя нулями, и сервер отвечает: жду байт номер двести пятьдесят один. Настоящая первая половина приходит пятой и тоже становится дублем. Всего дублирующих ответов четыре, и приложение прочитало двести пятьдесят байт, все нулевые: ни приветствия, ни имени сайта.

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

Это в нашем тесте. Что именно остаётся у сервера на месте, зависит от порядка прихода: дальше будет запуск, где нули пришли раньше, а приложение всё равно прочитало настоящие байты. Общего правила «побеждает первый» мы не выводим, и как поведёт себя другая система, не проверяли.

Теперь выключатели. Их четыре, и нумеруются они по порядку отправки, а первой теперь едет вторая половина. Nofake один убирает фейк второй половины перед настоящей второй, nofake два убирает его после неё. Nofake три и nofake четыре делают то же с первой половиной. В разрезе с фейками один и два относились к первой половине, здесь ко второй. Номера с одной функции на другую переносить нельзя.

Выключатели перемешивания с фейками Выключатели перемешивания с фейками нумеруются по порядку отправки, и первой едет вторая половина: nofake1 убирает фейк второй половины перед настоящей, nofake2 после неё, nofake3 и nofake4 делают то же с первой половиной, а у разреза с фейками один и два относились к первой половине, поэтому номера с функции на функцию не переносятся; ответы сервера при любых выключателях те же, а когда выключены все четыре, на проводе остаются две настоящие части, 146 байт и 104 байта, как у multidisorder; остальные настройки такие же, как у разреза с фейками, а в проверке без условия и с выключенными nofake3 и nofake4 приложение получило бы 104 настоящих байта и 146 нулей по расчёту, запуска такого нет. выключатели нумеруются по порядку отправки: у каждой функции своя нумерация fakedsplit, начало выпуска: первой едет первая половина фейк первойnofake1 настоящаяпервая фейк первойnofake2 фейк второйnofake3 настоящаявторая фейк второйnofake4 fakeddisorder: первой едет вторая половина фейк второйnofake1 настоящаявторая фейк второйnofake2 фейк первойnofake3 настоящаяпервая фейк первойnofake4 номера не переносятся с функции на функцию выключаем по одному: длины пакетов по порядку, пунктир: пакета нет nofake1 146146146104104104 нет первого пакета:настоящая вторая едет первой nofake2 146146146104104104 нет фейка сразу посленастоящей второй nofake3 146146146104104104 нет фейка сразу переднастоящей первой nofake4 146146146104104104 серию замыкает настоящаяпервая, фейка после неё нет все четыре 146146146104104104 остались две настоящие части:провод multidisorder ответы сервера во всех запусках те же: блок 105…250 в стороне, потом «жду байт 251» остальное как у разреза с фейками, только вторая половина впереди pos не заданпо умолчанию 2:части 248 и 2,длинная первой pos=0ничего не режет:один пакет 250 Б nodropседьмым идёторигинал 250 Б;ответ: дубль-блок длинное, 1484 Бчасти 1380 и 104,ломтиков нет;приложение 1484 Б запрос HTTP, 81 Бчасти 42 и 39,Host верный,приложение 81 Б проверь себяусловия нет и выключены nofake3 и nofake4: что прочитает приложение? настоящие 104 байтанули, 146 байт имя разорвано; это расчёт по увиденному, такого запуска у нас нет

Выключаем первый: серия теряет самый первый пакет, и настоящая вторая половина уходит самой первой. Выключаем четвёртый: серию замыкает настоящая первая половина, фейка после неё нет. Второй и третий убирают фейк сразу после настоящей второй и сразу перед настоящей первой. Ответы сервера в нашем тесте во всех четырёх запусках те же: блок «в стороне», потом жду байт номер двести пятьдесят один.

Выключены все четыре: остаются две настоящие части, сначала сто сорок шесть байт, потом сто четыре. Это провод multidisorder с той же меткой, и приложение сервера получило оригинал. При любых выключателях настоящие части остаются на месте, меняются только фейки.

Позиция по умолчанию здесь два: части в два байта и в двести сорок восемь, длинная идёт первой. Позиция ноль ничего не режет, и оригинал уходит целым.

Остальное как у разреза с фейками из начала выпуска. Nodrop добавляет седьмым пакетом оригинал, и сервер отвечает на него дублирующим блоком. Длинное приветствие в тысячу четыреста восемьдесят четыре байта функция получает уже собранным: программа собирает его заранее, это разбирает выпуск «Сборка и повторный проигрыш». Обе части, по счёту, короче предела размера пакета, ломтиков нет, и сервер прочитал приветствие целиком. В запросе HTTP метка midsld падает в середину слова example, первыми уходят сорок два байта, и Host у сервера верный.

Проверь себя. Условия нет, и выключены ещё оба фейка первой половины, третий и четвёртый. Что прочитает приложение?

Фейки второй половины придут первыми и займут свои номера, настоящая вторая половина станет дублем, как в запуске без условия. Настоящая первая половина придёт по порядку и закроет дыру в начале. Приложение получит сто четыре настоящих байта и сто сорок шесть нулей, имя будет разорвано. Это расчёт по увиденному, такого запуска у нас нет.

Итак. Без условия перемешивание с фейками не прячет имя, а разрушает данные. Выключатели нумеруются по порядку отправки, начиная со второй половины, и когда выключены все четыре, остаётся провод multidisorder. Остальные настройки ведут себя как у разреза с фейками, только вторая половина впереди.

Накладка в перемешивании: метка внутри окна

Вопрос сцены: что делает накладка seqovl в перемешивании с фейками и почему в разрезе с фейками то же слово значило другое?

Повтор из выпуска «Перемешать: disorder». Накладка это байты поверх чужого места, которые потом перекрываются настоящими. В multidisorder seqovl был меткой, а не числом: накладок столько, на сколько байт метка отстоит от начала, а начало пакета равно разрезу минус накладки.

Игрушка, выдуманная. Вторая пачка уезжает первой, и в начало её подшиты черновые листы с номерами последних листов первой пачки. На эти номера теперь два варианта: черновой, пришедший первым, и настоящий, пришедший позже.

Правило то же. Накладку получает настоящая вторая половина, та, что идёт первой, а метка должна стоять левее разреза: накладка ложится на номера хвоста первой половины.

Запуск с seqovl равно host. Метка host стоит на смещении девяносто семь, значит, накладок девяносто семь.

Накладка seqovl равно host Накладка seqovl равно host у перемешивания с фейками: метка host стоит на смещении 97, значит накладок 97, настоящая вторая половина вырастает до 243 байт, 97 плюс 146, а начинается на смещении 7, это номер 8, потому что 104 минус 97 равно 7, первые 97 байт пакета нулевые и лежат поверх хвоста первой половины, сервер отвечает «жду байт номер 1» с блоком с 8-го по 250-й, когда приходит настоящая первая половина, отвечает «жду байт номер 251» с дублирующим блоком с 8-го по 104-й, и приложение читает оригинал в 250 байт, а при seqovl равно 20 пакет имеет 166 байт и начинается с номера 85. накладка в перемешивании: метка внутри окна, пакет начинается раньше начало пакета = разрез минус накладка игрушка: в начало второй пачки подшиты черновики с номерами хвоста первой пачки host = 97seqovl=host: накладок 97 97 + 146 = 243вторая выросла до 243 байт 104 − 97 = 7начало: смещение 7, номер 8 оригинал, разрез на 104первая часть 0…103вторая часть 104…249 пакет 2 на проводе: 243 байта, начало со смещения 7накладка: 97 нулейнастоящая вторая: 146 байт7104250 клиентроутерсервер 1фейк второй половиныномер 105 · длина 146 · нули · MD5IP 218 Б ответа нет 2настоящая вторая с накладкойномер 8 · длина 243 · начало нулиIP 295 Б ack 1 + блок [8,251)жду байт 1, в стороне 8…250 3тот же фейк ещё разномер 105 · длина 146 · нули · MD5IP 218 Б ответа нет 4фейк первой половиныномер 1 · длина 104 · нули · MD5IP 176 Б ответа нет 5настоящая первая половинаномер 1 · длина 104 · начало приветствияIP 156 Б ack 251 + дубль [8,105)дубль: 105 − 8 = 97 байт 6тот же фейк первой половиныномер 1 · длина 104 · нули · MD5IP 176 Б ответа нет первые байты пакета 2:00 00 00 00 … 0097 нулей, затем6d 70 6c 65начало «mple» приложение сервера: 250 байт, равны оригиналунули пришли раньше, но настоящая первая половина пришла по порядку и перекрыла их второй запуск, seqovl=20: пакет 2 в 166 байт с номера 85 (20 + 146 = 166, 104 − 20 = 84)ответы: блок [85,251), потом дубль [85,105); приложение 250 байт, равны

Настоящая вторая половина выросла: девяносто семь плюс сто сорок шесть, всего двести сорок три байта.

Начало пакета: сто четыре минус девяносто семь, смещение семь, это номер восемь. В нашем тесте пакет начинается с нулей.

Ответ сервера на этот пакет: байт номер один жду, а байты с восьмого по двести пятидесятый лежат у меня. Когда приходит настоящая первая половина, сервер отвечает, что ждёт байт номер двести пятьдесят один, и добавляет дублирующий блок с восьмого по сто четвёртый байт.

Приложение прочитало оригинал. Здесь нули пришли раньше, но настоящая первая половина пришла по порядку и перекрыла то, что лежало в стороне, и приложение прочитало настоящие байты. Как это у другого приёмника, мы не проверяли.

Второй запуск: seqovl равно двадцати. Число здесь тоже метка, абсолютное смещение, накладок двадцать. Пакет теперь в сто шестьдесят шесть байт: двадцать плюс сто сорок шесть. Он начинается на смещении восемьдесят четыре, это номер восемьдесят пять.

Теперь отмены. Метка midsld, сто четыре, равна разрезу: накладка не меньше разреза, и функция её отменяет. В журнале строка об этом, а на проводе обычные шесть пакетов. Так же отменяется метка, которую функция не нашла, например method на приветствии TLS.

Отмены, границы и два смысла seqovl Границы накладки seqovl у перемешивания с фейками: метка, равная разрезу, и метка, которую функция не нашла, отменяют накладку с записью в журнале, и на проводе уходят обычные шесть пакетов, метка midsld минус один даёт 103 накладки и пакет в 249 байт со смещения 1, метка 1 даёт один байт накладки и пакет в 147 байт со смещения 103, а текст вроде abc это ошибка функции после первого фейка; у разреза с фейками seqovl только число и лежит перед потоком, а здесь это метка внутри потока, слово host там ошибка, а здесь метка, текст abc ошибка в обеих; по расчёту при seqovl равно 80 вторая половина имела бы 226 байт, начало со смещения 24 и дублирующий блок с 25-го по 104-й, такого запуска у нас нет. seqovl у перемешивания с фейками: отмены, границы и два смысла слова seqovl=midsldметка равна разрезу 104накладка отмененаfakeddisorder: seqovl cancelled because seqovl 104 is not less than the split pos 104на проводе обычные шесть пакетов: настоящая вторая 146 байт, без накладки seqovl=methodфункция не нашла метку на приветствиинакладка отмененаfakeddisorder: seqovl cancelled because could not resolve marker 'method'на проводе обычные шесть пакетов: настоящая вторая 146 байт, без накладки границы: накладок от 1 до 103, то есть меньше разреза 104 метканакладокнастоящая вторая половина на проводе midsld минус 1103249 байт со смещения 1самая большая допустимая 11147 байт со смещения 103 abc—ошибка после первого фейка, на проводе один пакет одно слово, два смысла fakedsplitseqovl: только числонакладка перед потокомseqovl=5: 109 байт со смещения −5слово host: ошибка после первого фейкатекст abc: ошибка fakeddisorderseqovl: метканакладка внутри потокаseqovl=host: 243 байта со смещения 7слово host: метка, 97 байттекст abc: ошибка проверь себяseqovl=80: какой длины вторая половина и с какого смещения? 80 + 146 = 226байт в пакете 104 − 80 = 24смещение 24, номер 25 дубль [25,105)80 номеров, 105 − 25 = 80 расчёт по правилу, такого запуска у нас нет: запускали 97 и 20

Прогон функций показывает границы. Метка midsld минус один даёт сто три накладки: пакет в двести сорок девять байт со смещения один, это самое большое допустимое значение. Метка один даёт один байт накладки: пакет в сто сорок семь байт со смещения сто три.

Текст, который вообще не метка, например abc, это ошибка функции, и случается она уже после первого фейка: прогон функций показал на проводе один фейк, потом ошибку.

Запомним разницу. В разрезе с фейками накладка число и лежит перед потоком. В перемешивании с фейками накладка метка и лежит внутри потока, поверх хвоста первой половины. Слово host там ошибка, здесь метка. А текст abc ошибка в обеих.

Проверь себя. Допустим, seqovl равно восьмидесяти. Какой длины будет настоящая вторая половина и с какого смещения она начнётся?

Восемьдесят плюс сто сорок шесть, двести двадцать шесть байт. Начало: сто четыре минус восемьдесят, смещение двадцать четыре. Дублирующий блок покроет восемьдесят номеров, с двадцать пятого по сто четвёртый. Это расчёт по правилу, такого запуска у нас нет: мы запускали девяносто семь и двадцать.

Итак. В перемешивании с фейками seqovl это метка: накладка лежит внутри первой половины и начинает пакет раньше на столько байт, сколько накладок. Метка не меньше разреза отменяется с записью в журнале. В нашем тесте приложение получает оригинал.

Имя между двойниками: первый запуск и выключатели

Вопрос сцены: что будет, если подкладывать не копии частей, а только подложное имя?

Игрушка, выдуманная. Письмо, и адрес в нём в отдельной строке. Курьер вырезает её на листок, а перед ним и после него кладёт листки с подложным адресом той же длины. Адресат примет только настоящий, а сортировщик прочитает первый попавшийся.

Имя между двойниками. В программе эта функция называется hostfakesplit. Места разреза она находит сама, по имени сайта.

Начало и конец имени это знакомые метки host и endhost из выпуска «Где резать: метки». В нашем приветствии имя занимает байты со смещения девяносто семь до смещения сто одиннадцать, считая с нуля. Это пятнадцать байт.

Двойник это подложное имя той же длины. Функция кладёт его перед настоящим именем и после него. Строка запуска короткая: фильтр на приветствие, функция и условие tcp_md5.

Имя между двойниками: пять пакетов Имя между двойниками, функция сама ставит разрезы по меткам host и endhost и не читает pos: на проводе пять пакетов, настоящая часть до имени с номером 1 и длиной 97, двойник с номером 98 и длиной 15, настоящее имя с тем же номером и теми же 15 байтами, тот же двойник ещё раз и настоящий хвост с номером 113 и длиной 138, сервер отвечает «жду байт номер 98» после первого пакета и «жду байт номер 251» после последнего, на двойников не отвечает, 97 плюс 15 плюс 138 дают 250 байт, пакетов пять, а не шесть, потому что двойник один и отправлен дважды, приложение читает оригинал, а счётчик ядра насчитал два отброшенных пакета. имя между двойниками: функция сама находит имя и режет вокруг него --payload=tls_client_helloтолько приветствие TLS --lua-desync=hostfakesplitимя между двойниками :tcp_md5условие pos не читается до имени: 97 байтхвост: 138 байт150250 host: смещение 9797 endhost: смещение 112112 имя www.example.com: смещения 97…111, номер 98; разрезы функция ставит сама на эти два флажка клиентроутерсервер 1настоящая часть до имениномер 1 · длина 97 · начало приветствияIP 149 Б ack 98жду байт номер 98 2двойник: подложное имяномер 98 · длина 15 · случайное имя · MD5IP 87 Б ответа нет 3настоящее имяномер 98 · длина 15 · www.example.comIP 67 Б в этом запуске ответа нет 4тот же двойник ещё разномер 98 · длина 15 · то же случайное имяIP 87 Б ответа нет 5настоящий хвостномер 113 · длина 138 · после имениIP 190 Б ack 251жду байт номер 251 97 + 15 + 138 = 250, ровно всё приветствие; пакетов пять: двойник один, отправлен дважды приложение сервера: 250 байт, равны оригиналу; сервер нашёл имя www.example.comдвойники умерли из-за условия: счётчик ядра сервера насчитал 2 отброшенных пакета имя двойника случайное: в другом запуске другое; в пакетах 2 и 4 одно и то же

Пакеты нашего теста по порядку. Первый: настоящая часть до имени. Номер один, девяносто семь байт, начало приветствия. Сервер отвечает: жду байт номер девяносто восемь. Девяносто семь байт у него уже есть.

Второй: двойник. Номер девяносто восемь, пятнадцать байт случайного имени и опция эм-дэ-пять. Ответа нет.

Третий: настоящее имя, www точка example точка com. Тот же номер девяносто восемь и те же пятнадцать байт. Имя занимает этот пакет целиком, и больше в пакете ничего нет.

Четвёртый: тот же двойник ещё раз. Ответа нет.

Пятый: настоящий хвост, номер сто тринадцать и сто тридцать восемь байт. Сервер отвечает: жду байт номер двести пятьдесят один.

Сложим: девяносто семь, пятнадцать и сто тридцать восемь дают двести пятьдесят, ровно всё приветствие. Пакетов пять, а не шесть: двойник один, но отправлен дважды.

Приложение прочитало двести пятьдесят байт, равных оригиналу, и сервер нашёл имя www.example.com. Двойники умерли из-за условия: счётчик ядра насчитал два отброшенных пакета.

Выключателей здесь два, потому что двойников два. Nofake один убирает двойника перед настоящим именем, nofake два убирает его после. Выключены оба: остаются три настоящих куска подряд, и больше ничего.

Выключатели, pos и игрушечные читатели Выключатели, то чего функция не умеет, и игрушечные читатели в роутере для имени между двойниками: выключателей два, потому что двойников два, без первого нет двойника перед настоящим именем, без второго нет его после, а когда выключены оба, остаются три настоящих куска подряд, 97, 15 и 138 байт; pos функция не читает, а если имени в данных нет, ничего не отправляется; настоящее имя лежит в своём пакете целиком, поэтому пакетный читатель, склейщик и читатель последний записал нашли его на третьем пакете и остановили соединение, и до сервера дошло 97 байт, а читатели первый записал и строго по порядку держали двойника, имени не нашли, и сервер получил 250 байт; в проверке запрос HTTP в 81 байт даёт пакеты в 32, 15, 15, 15 и 34 байта. выключателей два, потому что двойников два длины пакетов по порядку, пунктир: пакета нет nofake1 97151515138 нет двойника переднастоящим именем nofake2 97151515138 нет двойника посленастоящего имени оба выкл. 97151515138 три настоящих кускаи больше ничего выключателей три и четыре у этой функции нет остальные настройки и то, чего функция не умеет nodropшестым идёторигинал 250 Б;ответ: дубль-блок repeats=2каждый двойникдважды: всегосемь пакетов длинное, 1484 Бхвост однимпакетом 1372 Б;приложение 1484 Б pos не читаетсяpos=midsld иpos=method: те жепять пакетов имени нетничего не уходит,вердикт«пропустить» игрушечная модель: пять читателей в роутере, стоп при находке имени 97151515138двойникимядвойник пакетныйимя! склейщикимя! последний записалимя! первый записал строго по порядку нашли имя на третьем пакете,остановили соединение: на сервер 97 байт в руках двойник, имени не нашли:на сервер 250 байт, равны оригиналу это наша модель, а не измерение какого-либо устройства; пунктир: пакеты после остановки игрушка выбросила проверь себязапрос HTTP на 81 байт, имя в Host на смещении 32, 15 байт: какие пять пакетов? 32 Бдо имени 15 Бдвойник 15 Бимя 15 Бдвойник 34 Бхвост 32 + 15 + 34 = 81

Nodrop добавляет шестым пакетом оригинал, а repeats равно два повторяет каждого двойника, и всего уходит семь пакетов. Длинное приветствие функция получает уже собранным, это разбирает выпуск «Сборка и повторный проигрыш»; хвост после имени тогда один пакет в тысячу триста семьдесят два байта.

Теперь то, чего функция не умеет. Она не читает pos: с pos равным midsld на проводе вышли те же пять пакетов, места разреза определяет только имя.

А если программа не определила, что в данных есть имя, функция ничего не отправляет и возвращает «пропустить». Так бывает, например, когда данные помечены как неопознанные: как определяется тип, рассказывает выпуск «Тип нагрузки и имя сайта». Так же с простым набором байтов. Прогон функций показал именно это; что оригинал уйдёт целым, следует из правила, отдельного запуска у нас нет.

Теперь наша игрушечная модель. В выпуске «Перемешать: disorder» читатели разбирали готовый захват, а здесь пять читателей стоят в роутере и останавливают соединение, как только находят имя. Настоящее имя лежит в своём пакете целиком, поэтому «пакетный», «склейщик» и «последний записал» нашли его на третьем пакете, и до сервера дошло девяносто семь байт.

«Первый записал» и «строго по порядку» имени не нашли: у них в руках двойник, и сервер получил приветствие целиком. Подробнее о читателях дальше в этом выпуске.

Проверь себя. Запрос HTTP на восемьдесят один байт, имя в Host на смещении тридцать два, пятнадцать байт. Какие пять пакетов уйдут?

Тридцать два байта до имени, затем двойник и настоящее имя по пятнадцать байт, ещё раз двойник и хвост в тридцать четыре байта. В нашем тесте так и вышло, и сервер прочитал запрос целиком.

Итак. Имя между двойниками отправляет пять пакетов: часть до имени, двойник, настоящее имя, тот же двойник и хвост. Места разреза функция выбирает сама, по имени, а pos не читает. Сервер молчит на двойников и читает оригинал, это в нашем тесте. Настоящее имя при этом лежит целиком в отдельном пакете, и это нужно помнить.

Двойник: длина, случайность и шаблон

Вопрос сцены: из чего состоит двойник, какой он длины и можно ли выбрать его самому?

Игрушка, выдуманная. В окошке сортировщика строка из пятнадцати клеток. Подложная карточка из десяти клеток или из двадцати выдаст себя сразу тому, кто сверяет длины, незаметна только карточка ровно в пятнадцать.

Двойник той же длины, что имя Двойник той же длины, что настоящее имя, и он случайный: в игрушке сортировщик с окошком на пятнадцать клеток выдаёт подложную карточку из десяти и из двадцати клеток и не замечает карточку ровно в пятнадцать, в приветствии на 250 байт имя занимает смещения с 97 по 111, это 111 минус 97 плюс 1, то есть 15 байт, двойник встаёт на то же место, а всё вокруг остаётся настоящим, поэтому поля длины по счёту сходятся, двойник создаётся один раз за вызов и отправляется дважды, поэтому в пакетах 2 и 4 одни и те же 15 байт, а в другом запуске другие. двойник: той же длины, что имя, создаётся один раз и уходит дважды игрушка (выдуманный пример): сортировщик сверяет длину карточки с окошком на 15 клеток окошко: 15 клеток карточка, 10 клеток10короче окошка: выдаёт себя карточка, 20 клеток20длиннее окошка: выдаёт себя карточка, 15 клеток15ровно по окошку: незаметна наше приветствие на 250 байт, смещения от 0 до 249до имени: 97 байтпосле имени: 138 байт097111249 настоящее имя: смещения 97…111 15двойник той же ширинывстаёт на место имени 111 − 97 + 1 = 15длина имени и двойника всё вокруг имени настоящеепо счёту поля длины в приветствии сходятся один двойник на вызов, отправлен дважды: байты в пакетах 2 и 4в нашем тесте запуск 1пакет 2787a7079673437336f73622e6e6574 пакет 4787a7079673437336f73622e6e6574xzpyg473osb.netто же самое запуск 2пакет 27536637166326477676c612e656475 пакет 47536637166326477676c612e656475u6cqf2dwgla.eduто же самое в другом запуске другие: буквы случайные, мы их не читаем вслух

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

Двойник создаётся один раз за вызов и отправляется дважды, поэтому оба фейка в нашем тесте несут одни и те же пятнадцать байт. А в другом запуске имя другое: двойник случайный. Буквы из наших двух запусков мы не называем, они ничего не значат.

Если шаблона нет, для имён от семи байт двойник собран так: одна случайная буква, потом случайные буквы и цифры, точка и одно из шести окончаний: com, org, net, edu, gov, biz. В прогоне функций на две тысячи вызовов длина ни разу не сбилась, а каждое окончание выпало от трёхсот до четырёхсот раз.

Двойник по умолчанию и шаблон host Как собран двойник по умолчанию и как работает шаблон host: без шаблона для имён от семи байт это одна случайная буква, десять случайных букв и цифр, точка и одно из шести окончаний, в прогоне функций на две тысячи вызовов длина ни разу не сбилась, а каждое окончание выпало от 300 до 400 раз; шаблон подгоняется под нужную длину в 15 байт, короче больше чем на один символ дают случайные символы, точку и шаблон, короче ровно на один дают точку впереди, такой же длины даёт сам шаблон, длиннее дают его хвост; провод с шаблоном такой же, как без него, а в проверке шаблон из десяти символов при нужных 11 даёт точку впереди, а при нужных 16 даёт пять случайных символов, точку и шаблон. двойник по умолчанию: из чего он собран xzpyg473osb.net случайнаябуква 10 случайных букв и цифр точка окончание 1 + 10 + 1 + 3 = 15 байт, как у настоящего имени; пример из нашего запуска, буквы случайные так для имён от 7 байт; окончание одно из шести:comorgnetedugovbiz прогон функций: 2000 вызовов с длиной 15прогон функций biz330com384edu318gov318net313org337рамка: 400 выпадений, черта: 300 длина не сбилась ни разу:ошибок длины 0 из 2000каждое окончание 300 – 400 раз зачем шаблон host?чтобы двойник выглядел как имя, которое пропускает читательпо общим сведениям шаблон под нужную длину 15: четыре правила короче больше чем на одинслучайные + точка + шаблонfo0i9dtrp.ya.ruшаблон ya.ru, 5 символов9 + 6 = 15в нашем тесте короче ровно на одинточка впереди.www.decoy.testшаблон www.decoy.test, 14 символов1 + 14 = 15в нашем тесте той же длинысам шаблонwww.example.comшаблон www.example.com, 15 символов15прогон функций длиннеехвост нужной длиныa.example.com.ru.xпервые 3 байта отброшены: остаётся xample.com.ru.x15 из 18прогон функций случайные символыточкашаблон провод запусков с шаблоном такой же, как без него: 97 Бчасть15 Бдвойник15 Бимя15 Бдвойник138 Бхвост= то же число, номера, длины проверь себя: шаблон google.com, 10 символовпрогон функций нужно 1111 − 10 = 1: ровно на один короче .google.comточка впереди нужно 1616 − 10 = 6, 6 − 1 = 5 случайных zm4vd.google.comбуквы случайные

Зачем двойнику шаблон? По общим сведениям, читатель может пропускать только то, что выглядит как имя сайта, и шаблон нужен, чтобы двойник так выглядел. Задаётся он ключом host. Все правила про одно: имя должно получиться ровно нужной длины.

Первое правило: шаблон короче нужного больше чем на один символ. Перед ним ставятся случайные символы и точка. В нашем тесте шаблон из пяти символов дал девять случайных символов, точку и сам шаблон. Девять плюс шесть, ровно пятнадцать.

Второе правило: шаблон короче нужного ровно на один символ. Впереди ставится одна точка. Шаблон из четырнадцати символов дал в нашем тесте двойник из точки и этого шаблона.

Третье правило: шаблон нужной длины. Двойник это сам шаблон. Если шаблон равен настоящему имени, двойник с ним совпадёт: прогон функций показал, что www.example.com даёт www.example.com. Тогда фейк и настоящее имя одинаковы.

Четвёртое правило: шаблон длиннее нужного. Берётся его хвост нужной длины. Шаблон в восемнадцать символов дал хвост в пятнадцать.

Провод в обоих наших запусках с шаблоном такой же, как без шаблона: пять пакетов с теми же номерами и длинами. Меняются только байты двойника. Годится ли имя настоящего сайта в качестве шаблона, мы не проверяли: настоящих сайтов в лаборатории нет.

Проверь себя. Шаблон google.com, десять символов, а нужно одиннадцать. Какой получится двойник?

Ровно на один символ длиннее шаблона, значит, впереди точка: .google.com. Прогон функций показал именно это.

Ещё пример. Тот же шаблон, но нужно шестнадцать символов. Что получится?

Шестнадцать минус десять, шесть. Одна позиция уходит на точку, остаётся пять случайных символов. Итого пять случайных символов, точка и google.com. Прогон функций показал такую форму, буквы в ней случайные.

Итак. Двойник той же длины, что настоящее имя, создаётся один раз за вызов и уходит дважды. По умолчанию он случайный, с одним из шести окончаний. Шаблон host подгоняется под нужную длину: добавляются случайные символы и точка, или одна точка, или берётся сам шаблон, или его хвост.

Без условия: сервер получит чужое имя

Вопрос сцены: что будет с именем между двойниками, если забыть условие?

Игрушка, выдуманная. Кладовщик, как раньше, принимает на место первую пришедшую карточку, а остальные называет дублями. Первой приходит карточка с подложным адресом: письмо уйдёт по нему, а настоящая карточка окажется дублем.

Без условия сервер получает чужое имя Имя между двойниками без условия: в игрушке кладовщик принимает на место первую пришедшую карточку, поэтому подложный адрес побеждает, а настоящая карточка становится дублем; на проводе те же пять пакетов, но двойники теперь обычные пакеты, сервер на часть до имени отвечает «жду байт номер 98», на двойника отдельного ответа нет, на настоящее имя и на повтор двойника отвечает «жду байт номер 113» с дублирующим блоком с 98-го по 112-й, на хвост отвечает «жду байт номер 251», приложение сервера прочитало 250 байт, но 15 байт имени заменены двойником, и сервер нашёл в приветствии случайное имя, а не настоящее; с условием ответов было два, а без условия четыре. без условия: двойник приходит первым и по порядку игрушка (выдуманный пример): кладовщик принимает на место первую пришедшую карточку карточка 1: подложный адреспринята на местописьмо уйдёт по подложному адресу карточка 2: настоящий адресштамп «дубль»настоящая карточка лишняя --payload=tls_client_hello --lua-desync=hostfakesplitусловия tcp_md5 нет клиентроутерсервер 1часть до имениномер 1 · длина 97IP 149 Б ack 98жду байт номер 98 2двойник: случайное имяномер 98 · длина 15 · u6cqf2dwgla.eduIP 67 Б отдельного ответа нет 3настоящее имяномер 98 · длина 15 · www.example.comIP 67 Б ack 113 + блок [98,113)жду 113; блок: байты уже были 4тот же двойник ещё разномер 98 · длина 15IP 67 Б ack 113 + блок [98,113)жду 113; блок: байты уже были 5хвостномер 113 · длина 138IP 190 Б ack 251жду байт номер 251 двойник без MD5 для сервера обычный пакет; отдельного ответа на него в нашем тесте нет:Linux иногда откладывает подтверждения что сервер собрал в приветствии на 250 байтдо именихвост097249 15здесь двойник: u6cqf2dwgla.edu настоящее имя отскочило: дубльwww.example.com приложение сервера: 250 байт, но хэш не равен оригиналуимя в приветствии: u6cqf2dwgla.edu (в другом запуске другое), а не www.example.comдвойник закрыл только 15 байт имени: всё остальное настоящее с условием ответов сервера: 2без условия в нашем тесте: 4 число ответов может зависеть от того, как Linux откладывает подтверждения

Запуск тот же, но без tcp_md5. Пять пакетов те же по номерам и длинам, только двойники теперь обычные пакеты. На первый пакет, часть до имени, сервер отвечает: жду байт номер девяносто восемь.

Второй пакет, двойник. Сервер принимает его за настоящее имя, но отдельного ответа на него в нашем тесте нет: подтверждения Linux иногда откладывает. Следующий ответ покажет, что имя получено.

Третий пакет, настоящее имя. Ответ: жду байт номер сто тринадцать, имя получено, и к нему дублирующий блок в пятнадцать байт с девяносто восьмого: эти байты у меня уже есть. Повтор двойника получает тот же ответ. Пятый пакет, хвост, и ответ: жду байт номер двести пятьдесят один.

Приложение прочитало двести пятьдесят байт, но имя в них чужое: пятнадцать байт имени заменены двойником. Сервер разобрал приветствие и нашёл в нём случайное имя, а не www.example.com.

С условием ответов два, на двойников молчание. Без условия в нашем тесте четыре: два раза с дублирующим блоком. Они показывают, что настоящее имя пришло позже двойника. Число таких ответов может зависеть от того, как Linux откладывает подтверждения.

У разреза с фейками и перемешивания с фейками приложение без условия получало нули, потому что фейк лежал на целой половине. Здесь двойник закрывает только пятнадцать байт имени, всё остальное настоящее, и сервер получает приветствие с чужим именем.

То же с запросом HTTP. Без условия сервер прочитал запрос на восемьдесят один байт, и в заголовке Host у него случайное имя двойника. Ответы шли так: жду байт тридцать три, потом сорок восемь с дублирующим блоком, ещё раз то же, и восемьдесят два.

Запрос HTTP и другие функции без условия Запрос HTTP без условия, другие функции без условия и проверка: запрос в 81 байт идёт пакетами 32, 15, 15, 15 и 34 байта, сервер отвечает «жду байт номер 33», потом «жду 48» с дублирующим блоком со 33-го по 47-й два раза и «жду 82», приложение читает 81 байт, но в заголовке Host у сервера случайное имя двойника; у разреза с фейками и перемешивания с фейками без условия приложение получает 250 нулей, потому что фейк лежит на целой половине, а у имени между двойниками настоящее приветствие с чужим именем, потому что двойник закрывает только 15 байт; с временем жизни 1 оба двойника умирают в роутере, клиент получает два сообщения «время истекло», с испорченной суммой счётчик ошибок суммы равен двум, и в обоих запусках приложение получает 250 байт, равных оригиналу; в проверке без условия, но с выключенным первым выключателем настоящее имя приходит первым и по порядку, а двойник после него становится дублем, это расчёт, такого запуска нет. то же с запросом HTTP, другие функции и другие формы условия запрос HTTP на 81 байт, без условия: имя в заголовке Hostв нашем тесте 32 Бдо имени 15 Бдвойник 15 Бимя 15 Бдвойник 34 Бхвост ack 33жду байт номер 33 ответа нет ack 48 + блок[33,48): дубль ack 48 + блок[33,48): дубль ack 82жду байт номер 82 пакеты: 32 + 15 + 15 + 15 + 34; ответы сервера по порядку приложение сервера: 81 байт, не равны оригиналув заголовке Host у сервера случайное имя двойника: t4r10dl8o6g.com (в другом запуске другое) без условия приложение получает разноев нашем тесте разрез с фейками (fakedsplit) и перемешивание с фейками (fakeddisorder)0000000000000000000000000000000приложение: 250 нулейфейк лежит на целой половине имя между двойниками (hostfakesplit)15настоящее приветствиенастоящее приветствиеприложение: приветствие с чужим именемдвойник закрывает только 15 байт две другие формы условия работают как раньшев нашем тесте время жизни 1: двойники умирают в роутереклиент: 2 сообщения «время истекло»испорченная сумма: двойники отброшенысчётчик ошибок суммы у сервера: 2 в обоих запусках приложение получило оригинал: 250 байт, равны чем грозит? многие серверы выбирают сайт по этому имени:соединение ушло бы к другому сайту или было бы отвергнутов нашей лаборатории таких сайтов нет, мы это не проверялипо общим сведениям проверь себя: условия нет, но выключен первый выключателькакое имя прочитает приложение? пустая лента, 4–5 секунд 97 Бдо имени 15 Бнастоящее имя 15 Бдвойник: дубль 138 Бхвост настоящее имя расчёт по увиденному: такого запуска у нас нет

Чем это грозит? По общим сведениям, многие серверы выбирают, какой сайт показать, по этому имени, так что соединение ушло бы к другому сайту или было бы отвергнуто. В нашей лаборатории таких сайтов нет, мы это не проверяли.

Две другие формы условия работают как раньше. С временем жизни один оба двойника умирают в роутере, на клиенте два сообщения «время истекло». С испорченной суммой счётчик ошибок суммы показал два. В обоих запусках приложение получило оригинал.

Проверь себя. Условия нет, но выключен первый выключатель: двойника перед настоящим именем нет. Какое имя прочитает приложение?

Настоящее имя приходит первым и по порядку, двойник после него приходит позже и становится дублем. По тому, что мы видели, должно остаться настоящее имя. Это расчёт, такого запуска у нас нет, и другие приёмники мы не проверяли.

Итак. Без условия двойник приходит первым и по порядку, сервер в нашем тесте оставляет его, и приложение получает чужое имя. Это не нули, как у разреза с фейками и перемешивания с фейками, а подмена, и она тоже ломает соединение. Условие в этой функции обязательно.

Разрезать настоящее имя и отправить хвост наоборот

Вопрос сцены: что дают два необязательных ключа, midhost, «разрез имени», и disorder_after, «хвост наоборот», и где у них границы?

Игрушка, выдуманная. Сортировщик читает каждый листок отдельно и узнаёт адрес на листке, который лежит целиком. Чтобы не узнал, листок режут пополам. А хвост письма можно отправить наоборот: сначала последнюю строку, потом остальное.

Ключ midhost режет настоящее имя Ключ midhost режет настоящее имя на два пакета, а двойники остаются целыми: в игрушке листок с адресом целиком сортировщик узнаёт, а листок, разрезанный пополам, не узнаёт; метка midsld режет имя в середине слова example на семь байт и восемь байт, на проводе нашего теста идут часть до имени в 97 байт, двойник в 15 байт, семь байт, восемь байт, двойник и хвост в 138 байт, а приложение читает оригинал в 250 байт; в нашей игрушечной модели читатель пакетный имени уже не находит, а склейщик находит по-прежнему; значение midhost должно лежать на смещениях от 98 до 111, метка в начале имени, за его концом или вне имени отвергается с записью в журнале, а на проводе остаются обычные пять пакетов. midhost, «разрез имени»: настоящее имя режется на два пакета, двойники остаются целыми игрушка (выдуманный пример): сортировщик читает каждый листок отдельно листок с адресом целикомадрес узнан на листке листок режут пополамни на одной половине адреса нет --lua-desync=hostfakesplit:tcp_md5:midhost=midsldmidsld: метка «середина слова» приветствие в 250 байт: имя на смещениях 97…111 www.example.comхвост979899100101102103104105106107108109110111112 midsld: смещение 104 www.exa: 7 байт (97…103)mple.com: 8 байт (104…111) провод нашего теста по порядкув нашем тесте 97 Бдо имени 15 Бдвойник 7 Бwww.exa 8 Бmple.com 15 Бдвойник 138 Бхвост ack 98ack 113MD5: сервервыброситMD5: сервервыбросит приложение сервера: 250 байт, равны оригиналу наша игрушечная модель (разбор готового захвата)наша игрушечная модель читатель «пакетный»: имени не видитни в одном пакете нет имени целикомчитатель «склейщик»: имя видитwww.exa и mple.com идут встык зелёное: имя спрятано, красное: найдено; модель, не оборудование, настоящий ТСПУ мы не измеряли допустимые значения midhostпрогон функций 979899100101102103104105106107108109110111112 hostendhostнельзя: начало именинельзя: уже после имениможно: метка от 98 до 111 midhost=2: в журнале «hostfakesplit: midhost is not inside the host range»на проводе обычные пять пакетов: 97, двойник, имя, двойник, 138 края, прогон функций: host + 1 режет имя на 1 и 14 байт, endhost − 1 на 14 и 1

Настоящее имя в наших запусках лежит в своём пакете целиком. Ключ midhost режет это имя на два пакета, двойники остаются целыми. С midhost равным midsld имя режется в середине слова example: www.exa в семь байт и mple.com в восемь. На проводе нашего теста: часть до имени, двойник, семь байт, восемь байт, двойник и хвост. Приложение прочитало оригинал.

В нашей игрушечной модели при midhost читатель «пакетный» имени уже не находит, а «склейщик» находит по-прежнему. Подробнее о них дальше в этом выпуске.

Границы midhost. Метка должна стоять строго после первого байта имени и не дальше его последнего байта: на нашем приветствии это смещения от девяносто восьмого до ста одиннадцатого. Метка в начале имени, за его концом или вне имени отвергается: в журнале запись, на проводе обычные пять пакетов. В нашем тесте так вышло с меткой два.

Прогон функций показал края: метка host плюс один режет имя на один байт и четырнадцать, метка endhost минус один на четырнадцать и один.

Теперь disorder_after. Он работает с хвостом, то есть с частью после имени. Хвост режется на два куска, и поздний кусок уходит первым. Зачем? Как в выпуске «Перемешать: disorder»: приёмнику приходится держать конец в стороне и ждать начало, а читателю склеивать данные не по порядку.

Ключ disorder_after: хвост наоборот Ключ disorder_after, «хвост наоборот», режет хвост после имени на два куска и отправляет поздний кусок первым: с пустым значением, то есть меткой «последний байт», первым уходит один байт номер 250, потом 137 байт с номера 113, сервер отвечает «жду байт номер 113» с блоком в стороне из одного байта номер 250 и затем «жду байт номер 251»; со значением endhost плюс 20 это смещение 132, первыми уходят 118 байт с номера 133, потом 20 байт с номера 113, блок на сервере начинается с номера 133; метка должна быть не раньше смещения 113, а host и endhost отвергаются с записью в журнале, и хвост уходит целым; оба ключа вместе дают имя на 7 и 8 байт и хвост с последним байтом впереди, приложение читает оригинал, а в проверке со значением endhost плюс 2 первыми идут 136 байт со смещения 114, потом 2 байта со смещения 112. disorder_after, «хвост наоборот»: хвост режется на два куска, поздний уходит первым игрушка (выдуманный пример): хвост письма отправляем наоборот 1. последняя строка2. всё остальное как в выпуске «Перемешать: disorder»: приёмнику держать конец в стороне и ждать начало,а читателю склеивать данные не по порядку хвост: смещения 112…249, 138 байт; первые четыре пакета те же: 97, двойник, имя, двойник disorder_after пустой: метка «последний байт», смещение 24912пакеты по порядку: 1 Б с номера 250, потом 137 Б с номера 113ответы сервера: ack 113 + блок [250,251)затем ack 251в нашем тесте disorder_after=endhost+20: смещение 13212пакеты по порядку: 118 Б с номера 133, потом 20 Б с номера 113ответы сервера: ack 113 + блок [133,251)затем ack 251в нашем тесте ранний кусок 2 синий, поздний кусок 1 жёлтый, красная черта: где режет метка допустимые значения disorder_afterпрогон функций нельзяможно: метка не раньше смещения 113 host 97endhost 112249: «последний байт»endhost + 1 = 113: самое раннее disorder_after=host отвергнут, в журнале:disorder_after marker '97' resolved to pos not after after_host pos 112на проводе обычные пять пакетов, хвост целым в 138 байтв нашем тесте прогон функций: endhost + 1 даёт 137 Б со смещения 113, потом 1 Б со смещения 112 оба ключа вместе: midhost=midsld и disorder_after пустойв нашем тесте 97 Бдо имени 15 Бдвойник 7 Бwww.exa 8 Бmple.com 15 Бдвойник 1 Ббайт 250 137 Бс номера 113 семь пакетов; приложение сервера прочитало 250 байт, равны оригиналу проверь себя: disorder_after=endhost+2, какие два куска и в каком порядке? 4–5 секунд 1: 136 Б со смещения 114250 − 114 = 1362: 2 Б со смещения 112114 − 112 = 2прогон функций

Пустое значение disorder_after означает метку «последний байт».

Запуск с пустым disorder_after. Хвост в сто тридцать восемь байт делится на два куска. Первым уходит последний байт, номер двести пятьдесят. За ним остальные сто тридцать семь, начиная с номера сто тринадцать. На последний байт сервер ответил: жду байт номер сто тринадцать, а двести пятидесятый у меня лежит в стороне. Потом пришёл основной кусок, и сервер ответил: жду байт двести пятьдесят один.

Запуск с disorder_after равным endhost плюс двадцать. Это смещение сто тридцать два. Первым уходит всё, что идёт с этого места: сто восемнадцать байт, с номера сто тридцать три. Вторым двадцать байт, с номера сто тринадцать. Блок на сервере начинается с номера сто тридцать три.

Граница. Хвост должен остаться в двух непустых кусках: метка не раньше смещения сто тринадцать. Метка endhost, сразу за именем, и метка host отвергаются с записью в журнале, и хвост уходит целым. Метка endhost плюс один допустима: сто тридцать семь байт со смещения сто тринадцать, потом один байт со смещения сто двенадцать. Вместе оба ключа в нашем тесте дали: имя на семь и восемь байт, хвост с последним байтом впереди, и приложение прочитало оригинал.

Проверь себя. Ключ disorder_after равен endhost плюс два. Какие два куска хвоста и в каком порядке?

Поздний кусок первым: сто тридцать шесть байт со смещения сто четырнадцать, потом два байта со смещения сто двенадцать. Двести пятьдесят минус сто четырнадцать дают сто тридцать шесть. Прогон функций показал именно так.

Итак. Midhost режет настоящее имя на два пакета, и его значение должно лежать внутри имени. Disorder_after режет хвост на два куска и отправляет поздний первым, и его значение должно лежать не раньше смещения сто тринадцать. Всё, что вне границ, отвергается с записью в журнале.

Два экземпляра на одном пакете: fake, а после него multisplit

Вопрос сцены: что будет, если фейк подкладывает не та функция, что режет, а отдельная стратегия, которая стоит в строке первой?

Игрушка, выдуманная. Конвейер из двух станков. Деталь проходит их по порядку: первый станок кладёт на ленту подложное письмо, второй режет настоящее, и у каждого станка своя табличка настроек. В программе станок это экземпляр: одна запись lua-desync в строке запуска, как мы читали в выпуске «Читаем командную строку zapret2».

Два экземпляра в одном профиле Два экземпляра в одном профиле: в игрушке на конвейере первый станок кладёт подложное письмо, второй режет настоящее, и у каждого станка своя табличка настроек; в строке запуска первый экземпляр это fake с заготовкой fake_default_tls и условием tcp_md5, второй это multisplit со списком из двух меток, один и midsld, они идут в порядке командной строки; журнал называет их функцией, профилем и позицией, поэтому fake стоит на позиции 2, а multisplit на позиции 3, потому что позицию 1 занимает запись трафика лаборатории; у каждого экземпляра свои аргументы, и условие tcp_md5 написано у fake, поэтому не переходит к multisplit, а настоящие части идут без опции MD5, тогда как условие у самого multisplit попало бы на настоящие части. два экземпляра в одном профиле: fake, а после него multisplit игрушка (выдуманный пример): конвейер из двух станков, у каждого своя табличка настроек станок 1кладёт подложное письмотабличка: заготовка, условие затем станок 2режет настоящее письмотабличка: где резать станок= экземпляр = одна записьlua-desync в строке запуска строка запуска по кускамв нашем тесте 1--lua-desync=fakeфункция:blob=fake_default_tlsзаготовка:tcp_md5условие разделитель экземпляров: следующая опция lua-desync 2--lua-desync=multisplitфункция:pos=1,midsldсписок из двух меток: 1 и midsld экземпляры идут в порядке командной строки журнал называет экземпляр: функция, профиль, позицияв нашем тесте * lua 'fake_1_2' : desyncфункция fake, профиль 1, позиция 2 * lua 'multisplit_1_3' : desyncфункция multisplit, профиль 1, позиция 3 позицию 1 занимает запись трафика лаборатории, поэтому fake на позиции 2, multisplit на позиции 3 у каждого экземпляра свои аргументы fakeblob, tcp_md5условие касается только фейка multisplitposнастоящие части без опции MD5 tcp_md5не переходит ловушка из выпуска «multisplit: резать на части»:условие, написанное у самого multisplit, попало бы на настоящие части

В программе это два экземпляра в одном профиле. Строка запуска: fake с заготовкой fake_default_tls и условием tcp_md5, а после неё multisplit со списком из двух меток: один и midsld. Экземпляры идут в порядке командной строки.

Журнал называет их по формуле из того же выпуска: функция, профиль, позиция. В нашей лаборатории позицию один занимает запись трафика, поэтому fake стоит на позиции два, а multisplit на позиции три.

У каждого экземпляра свои аргументы. Условие tcp_md5 написано у fake, поэтому касается только фейка: настоящие части идут без опции эм-дэ-пять. Помните ловушку из выпуска «multisplit: резать на части»: условие, написанное у самого multisplit, попало бы на настоящие части.

Теперь провод нашего теста. Первым уходит один фейк, шестьсот восемьдесят байт, готовая заготовка из выпуска «Фейк и его условия», с номером один, как у оригинала. Внутри него другое имя, www.microsoft.com. За ним три настоящие части: один байт, сто три байта и сто сорок шесть.

Фейк, а после него multisplit Что отправляют два экземпляра и что отвечает сервер: первым уходит один фейк в 680 байт с номером 1, внутри него другое имя, а за ним три настоящие части в 1, 103 и 146 байт; фейк длиннее настоящего приветствия на 430 байт и накрывает все настоящие байты; сервер выбросил фейк по MD5, ответил «жду байт номер 2» после первой части и «жду байт номер 251» в конце, приложение прочитало 250 байт, равных оригиналу, а счётчик MD5 показал один пакет; фейк ничего не возвращает, multisplit говорит выбросить оригинал, каждый экземпляр выполняется, и оригинал выброшен один раз; в нашей игрушечной модели читатели пакетный, первый записал и строго по порядку имени не нашли, а склейщик и последний записал остановили соединение на четвёртом пакете, и до сервера дошло 104 байта; в проверке экземпляры поменяны местами, и фейк в 680 байт уходит после трёх настоящих частей. fake, а после него multisplit: что на проводе и что отвечает сервер клиентроутерсерверв нашем тесте 1фейк: готовая заготовканомер 1 · длина 680 · MD5IP 752 Б ответа нет 2настоящая часть 1номер 1 · длина 1 · первый байтIP 53 Б ack 2жду байт номер 2 3настоящая часть 2номер 2 · длина 103IP 155 Б ответа нет 4настоящая часть 3номер 105 · длина 146IP 198 Б ack 251жду байт номер 251 идентификаторы IP идут подряд по всем четырём пакетам: счётчик общий для обоих экземпляров фейк длиннее настоящего приветствия и накрывает его целикомфейк: 680 байт www.microsoft.com: байты 125…141 настоящее приветствие: 250 байт430 байт выходят за правый край 680 − 250 = 430 три настоящие части: 1 + 103 + 146 = 2501 Б103 Б146 Б сервер выбросил фейк по MD5: счётчик показал 1 пакетприложение: 250 байт, равны оригиналу, имя www.example.com что с оригиналом: движок собирает ответы всех экземпляровпрогон функций fakeничего не вернул multisplitоригинал выбросить каждый экземплярвыполняется оригинал выброшенодин раз как именно, в выпуске «Lua внутри программы»; нам достаточно: оригинала на проводе нет наша игрушечная модель: шесть читателей в роутеренаша игрушечная модель имени не нашли:«пакетный», «первый записал»,«строго по порядку»на сервере 250 байт, равны оригиналу нашли и остановили на 4-м пакете:«склейщик», «последний записал»до сервера дошло 104 байта фейк лёг первым, а настоящее разрезано; модель, не оборудование проверь себя: те же экземпляры, порядок обратный; какой провод? 4–5 секунд 1 Бчасть 1 103 Бчасть 2 146 Бчасть 3 680 Бфейк, MD5 фейк после трёх настоящих частей так и вышло в нашем тесте: приложение 250 байт, равны; ответы «жду 2», затем «жду 251»

Заметьте длину. Фейк в шестьсот восемьдесят байт длиннее настоящего приветствия в двести пятьдесят: он накрывает все настоящие байты и ещё четыреста тридцать сверху. Идентификаторы IP идут подряд по всем четырём пакетам: счётчик общий для обоих экземпляров.

Сервер в нашем тесте выбросил фейк по эм-дэ-пять, счётчик показал один пакет. Он ответил: жду байт номер два после первой части и жду байт номер двести пятьдесят один в конце. Приложение прочитало двести пятьдесят байт, равных оригиналу, с именем www.example.com.

Что с оригиналом? Каждый экземпляр обычно выполняется, даже если раньше стоящий уже сказал «выбросить»: движок, то есть часть программы на Си, собирает ответы всех. Фейк ничего не возвращает, а multisplit говорит: оригинал выбросить. Если хотя бы один сказал «выбросить», оригинал выбрасывается один раз; как именно, объясняет выпуск «Lua внутри программы». Нам достаточно, что оригинала на проводе нет, а пакетов с данными четыре.

Теперь наша игрушечная модель. Эта пара прячет имя от читателей «первый записал», «строго по порядку» и «пакетный»: фейк лёг первым, а настоящее разрезано. «Склейщик» и «последний записал» имя находят и останавливают соединение на четвёртом пакете: до сервера дошло сто четыре байта. Подробнее о читателях дальше в этом выпуске.

Проверь себя. Поменяем экземпляры местами: сначала multisplit, потом fake. Где окажется фейк?

Экземпляры идут в порядке командной строки, и выполняются все. Значит, фейк уйдёт после трёх настоящих частей. В нашем тесте так и вышло: один байт, сто три, сто сорок шесть, потом фейк в шестьсот восемьдесят. Другие порядки разберём дальше в этом выпуске.

Итак. Два экземпляра на одном пакете работают по порядку командной строки, и у каждого свои аргументы. Fake отправляет один фейк в шестьсот восемьдесят байт, потом multisplit три настоящие части, а оригинал выбрасывается один раз. В нашем тесте сервер читает оригинал, а в нашей игрушечной модели часть читателей имя находит.

Что мы знаем: перемешивание, имя между двойниками и пара

Вопрос сцены: что мы теперь знаем про три конструкции? Сведём, что мы узнали за последние сцены. Это всё в нашем тесте, на одном приёмнике, Linux, и в нашей игрушечной модели. О настоящем оборудовании мы по-прежнему ничего не знаем.

Перемешивание с фейками, fakeddisorder: шесть пакетов, фейк второй половины, настоящая вторая, ещё фейк второй, потом то же с первой половиной. Выключатели нумеруются со второй половины, а при всех выключенных остаётся провод multidisorder. Без условия приложение получает нули. Накладка seqovl здесь метка внутри окна.

Три конструкции: сводка Сводка по трём конструкциям: перемешивание с фейками отправляет шесть пакетов, фейк второй половины в 146 байт, настоящая вторая, ещё фейк второй, потом то же с первой половиной в 104 байта, сервер сначала держит вторую половину в стороне и ждёт байт номер 251, выключатели нумеруются со второй половины, при всех выключенных остаётся провод multidisorder, без условия приложение получает 250 нулей, а seqovl здесь метка внутри окна; имя между двойниками отправляет пять пакетов, 97, двойник в 15, имя в 15, тот же двойник и хвост в 138 байт, сервер ждёт байт номер 98, потом 251, двойник той же длины один на вызов, шаблон подгоняется под длину, без условия сервер видит чужое имя, midhost режет настоящее имя, disorder_after отправляет хвост наоборот, а pos функция не читает; пара из двух экземпляров, fake и после него multisplit, отправляет фейк в 680 байт и три настоящие части в 1, 103 и 146 байт, сервер ждёт байт номер 2 и затем 251, условие у fake не касается частей, а оригинал выбрасывается один раз; все числа относятся к нашему приёмнику и нашей игрушечной модели. три конструкции: что отправляют, что отвечает сервер, что запомнить 1перемешивание с фейками (fakeddisorder)146 Бфейк второй146 Бвторая146 Бфейк второй104 Бфейк первой104 Бпервая104 Бфейк первойсервер:ack 1 + блок [105,251), затем ack 251сервер молчит на фейки; выключатели 1…4 нумеруются со второй половинывсе четыре выключены: провод multidisorder; без условия 250 нулейseqovl здесь метка внутри окна: 243 байта со смещения 7в нашем тесте 2имя между двойниками (hostfakesplit)97 Бдо имени15 Бдвойник15 Бимя15 Бдвойник138 Бхвостсервер:ack 98, затем ack 251двойник той же длины, один на вызов, уходит дважды; шаблон host под длинубез условия сервер видит чужое имя; pos функция не читаетmidhost режет настоящее имя (смещения 98…111); disorder_after: хвост наоборот (с 113)в нашем тесте 3два экземпляра: fake, а после него multisplit680 Бфейк1 Бчасть 1103 Бчасть 2146 Бчасть 3сервер:ack 2, затем ack 251условие у fake не касается частей: настоящие части идут без MD5оригинал выбрасывается один раз, поэтому его на проводе нетв нашем тесте откуда знаем в нашем тестепровод и ответы сервера в нашем тесте прогон функцийграницы значений по общим сведениямпро настоящие серверы и настоящее оборудование проверить нечем всё про наш приёмник (Linux) и нашу игрушечную модель; другие приёмники и настройки не проверены

Имя между двойниками, hostfakesplit: пять пакетов, двойник той же длины, один на вызов, уходит дважды. Шаблон подгоняется под длину. Без условия сервер видит чужое имя. Midhost режет настоящее имя, disorder_after отправляет хвост наоборот, у обоих есть границы, а pos функция не читает.

Два экземпляра, fake и после него multisplit: один фейк в шестьсот восемьдесят байт и три настоящие части. Условие у fake не касается частей, а оригинал выбрасывается один раз, поэтому его на проводе нет.

Что отвечает сервер. На перемешивание с фейками он сначала держит вторую половину в стороне, потом ждёт байт номер двести пятьдесят один. На имя между двойниками ждёт байт номер девяносто восемь, потом двести пятьдесят один. На пару ждёт байт номер два после первой части и двести пятьдесят один в конце.

Три вещи с одной функции на другую переносить нельзя. Нумерацию выключателей. Смысл seqovl: у одной функции это число, у другой метка. И то, что бывает без условия: нули, чужое имя или, как в выпуске «Фейк и его условия», фейк в шестьсот восемьдесят байт, который сервер принимает всерьёз.

Что не переносить и проверка по таблице Три вещи нельзя переносить с одной функции на другую: нумерацию выключателей, которая у разреза с фейками начинается с первой половины, а у перемешивания с фейками со второй, смысл seqovl, который у одной функции число, а у другой метка, и то, что бывает без условия, то есть нули, чужое имя или фейк в 680 байт, который сервер принимает всерьёз и подтверждает 681; в проверке запуск перемешивания с фейками с условием и с выключенными первым и четвёртым выключателями оставляет четыре пакета, настоящую вторую половину в 146 байт, фейк второй, фейк первой в 104 байта и настоящую первую, это расчёт по правилам, такого запуска у нас нет; дальше в выпуске порядки пар, ловушка со списком меток в pos, пара без условия и игрушечные читатели, которые прозреют, когда фейки выключают по одному. три вещи нельзя переносить с одной функции на другую нумерация выключателейразрез с фейками:nofake 1, 2 → первая половинаперемешивание:nofake 1, 2 → вторая половина смысл seqovlfakedsplit:число байт (строка 867)fakeddisorder:метка (строка 971) что бывает без условиянули:разрез и перемешиваниечужое имя:имя между двойникамифейк 680 Б:сервер подтвердил 681 фейк 680 Б без условия: выпуск «Фейк и его условия»; для нашей пары то же, ответ 681в нашем тесте проверь себя по таблицеfakeddisorder:pos=midsld:tcp_md5:nofake1:nofake4, какие пакеты уйдут? 4–5 секунд полный провод: шесть пакетов 146 Бфейк 1 146 Бвторая 146 Бфейк 2 104 Бфейк 3 104 Бпервая 104 Бфейк 4 nofake1: убранnofake4: убран остаются четыре пакета: 146 Бвторая 146 Бфейк 2 104 Бфейк 3 104 Бпервая расчёт по правилам расчёт по правилам выключателей, такого запуска у нас нет дальше в выпуске:а если порядок пары обратный? а если пара без условия? а что если в pos написать список?потом самое интересное: кто из игрушечных читателей прозреет, когда выключать фейки по одному

Откуда мы это знаем. Провод и ответы сервера мы видели в нашем тесте. Границы значений показал прогон функций. Всё, что про настоящие серверы и настоящее оборудование, мы называли только по общим сведениям, и проверить его нам нечем. Другие приёмники и другие значения настроек мы не проверяли.

Проверь себя по этой таблице. Запуск fakeddisorder с условием, с nofake один и nofake четыре. Какие пакеты уйдут?

Первый выключатель убирает фейк второй половины перед настоящей второй, четвёртый убирает фейк первой половины после настоящей первой. Остаются четыре пакета: настоящая вторая половина, фейк второй, фейк первой и настоящая первая. Это расчёт по правилам, такого запуска у нас нет.

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

Итак. У нас есть перемешивание с фейками, имя между двойниками и пара из двух стратегий, и для каждой мы знаем, что она отправляет, что отвечает сервер и какие у неё границы. Всё это относится к нашему приёмнику и нашей игрушечной модели. Дальше посмотрим, как эти конструкции видят игрушечные читатели.

Повтор и вопрос: три функции, что осталось выяснить

Добро пожаловать в заключительную часть выпуска «Резать и подделывать вместе». Сначала короткий повтор, чтобы эту часть можно было смотреть отдельно от остальных.

О настоящем оборудовании на пути пакетов здесь по-прежнему ни слова: мы не знаем, как оно устроено. Участников двое, и оба наши: игрушечный инспектор в роутере лаборатории и сервер с Linux. Слово «сработало» в этом выпуске значит одно: приём обошёл нашу игрушку, а сервер получил настоящие данные.

Фейк это поддельный пакет, который программа вставляет рядом с настоящим. Условие это его намеренный дефект: опция MD5, срок жизни один или испорченная контрольная сумма. Из-за дефекта фейк не доходит до приложения: пакет с MD5 или с плохой суммой выбрасывает ядро получателя, а пакет со сроком жизни один гибнет в роутере. Как это устроено, объяснил выпуск «Фейк и его условия».

Три функции этого выпуска, пока с рабочими прозвищами. Fakedsplit, «разрез с фейками»: шесть пакетов, фейк, настоящая часть, фейк, потом ещё фейк, настоящая часть и фейк. Fakeddisorder, «перемешивание с фейками»: те же шесть, но вторая половина идёт первой. Hostfakesplit, «имя между двойниками»: пять пакетов, и настоящее имя лежит один в пакете между двумя копиями выдуманного имени, двойниками. Первые две режут по метке, как в выпуске «Где резать: метки»: метка midsld, середина слова example, делит наше приветствие в двести пятьдесят байт на сто четыре и сто сорок шесть.

Как читать записи на экране. Буква «эф» это фейк, буква «эр» настоящая часть, число после значка «собака» это смещение: с какого байта пакет начинается, считая от нуля. Рядом длина, а «эм» в конце значит опцию MD5. Запись «эф сто четыре, собака ноль, эм»: фейк в сто четыре байта с нулевого байта, с опцией MD5. В ответах сервера байты считаются с единицы: смещение ноль это номер один. Мы всегда скажем, какой счёт имеем в виду.

Три функции и три провода Повтор выпуска, три функции и что уходит в сеть в порядке отправки: разрез с фейками шлёт шесть пакетов, фейк в 104 байта со смещения 0, настоящую часть в 104 байта, ещё фейк, потом фейк в 146 байт со смещения 104, настоящую часть в 146 байт и ещё фейк; перемешивание с фейками шлёт те же шесть пакетов, но часть со смещения 104 идёт первой; имя между двойниками шлёт пять пакетов, настоящую часть в 97 байт, двойник в 15 байт, настоящее имя в 15 байт, тот же двойник и настоящий хвост в 138 байт со смещения 112; у всех фейков опция MD5, поэтому они умирают в ядре сервера, а приложение сервера читает 250 байт, равных оригиналу, в трёх запусках. три функции: что уходит в сеть, в порядке отправки F: фейк («эф»)R: настоящая часть («эр»)запись длина@смещение: смещение считаем с нуляm в конце: опция MD5 на фейке, он умирает в ядре серверав ответах сервера номера с единицы: смещение 0 это номер 1 fakedsplit«разрез с фейками»разрез midsld: 104 и 146 1F104@0m104 2R104@0104 3F104@0m104 4F146@104m146 5R146@104146 6F146@104m146 приложение сервера: 250 байт, равны оригиналу; ядро сервера выбросило фейков с MD5: 4 fakeddisorder«перемешивание с фейками»те же части, вторая идёт первой 1F146@104m146 2R146@104146 3F146@104m146 4F104@0m104 5R104@0104 6F104@0m104 приложение сервера: 250 байт, равны оригиналу; ядро сервера выбросило фейков с MD5: 4 hostfakesplit«имя между двойниками»режет вокруг имени: 97, 15, 138 1R97@097 2F15@97m15 3R15@9715 4F15@97m15 5R138@112138 приложение сервера: 250 байт, равны оригиналу; ядро сервера выбросило фейков с MD5: 2 выделенная полоса: имя www.example.com, смещения 97…111; пунктир: места разреза

Что ответил сервер. Во всех трёх запусках в нашем тесте приложение сервера прочитало настоящие двести пятьдесят байт, а фейки умерли на сервере из-за опции MD5. Без условия всё хуже: в двух функциях приложение получило двести пятьдесят нулевых байтов, а в третьей имя сайта заменил двойник.

Проверь себя. В какой из трёх функций без условия сервер получит не нули, а двойника имени, и почему?

В hostfakesplit. Её двойник подменяет только пятнадцать байт имени, всё остальное приветствие настоящее. В двух других функциях фейк накрывает целую часть, и вместо неё приходят нули.

Судья, фейк и таблица без условия Повтор договорённостей: в роутере стоит наша игрушка-инспектор, а у сервера наш приёмник на Linux, и слово «сработало» значит, что приём обошёл игрушку, а данные дошли до сервера целыми; фейк с опцией MD5 или с испорченной суммой умирает в ядре получателя, а фейк со сроком жизни один умирает в роутере; с условием во всех трёх функциях приложение сервера читает 250 байт, равных оригиналу, а без условия в разрезе с фейками и в перемешивании с фейками приложение получает 250 нулевых байт, в имени между двойниками имя сайта заменено выдуманным, потому что двойник подменяет только 15 байт имени, а остальное приветствие настоящее. повтор: двое участников, фейк с условием и что бывает без него клиентшлёт приветствиероутеригрушечный инспекторнаша модель, не оборудованиесервернаш приёмник: Linux сработало = обошли нашу игрушку, и данные дошли до сервера целыми фейк с условием: намеренный дефект, из-за него фейк не доходит до приложения опция MD5умирает в ядре получателя испорченная суммаумирает в ядре получателя срок жизни одинумирает в роутере в выпуске «Фейк и его условия» дефект называется условием функцияс условием (MD5)без условия fakedsplit«разрез с фейками»250 байт, равны оригиналу250 байт: все нули fakeddisorder«перемешивание с фейками»250 байт, равны оригиналу250 байт: все нули hostfakesplit«имя между двойниками»250 байт, равны оригиналу250 байт: имя заменено выдуманным проверь себяв какой из трёх функций без условия не нули, а двойник имени, и почему? в hostfakesplit: её двойник подменяет только 15 байт имени, остальное приветствие настоящеев двух других фейк накрывает целую часть, и вместо неё приходят нули

Осталось выяснить четыре вещи. Что будет, если в строку поставить две стратегии, например фейк и multisplit. Почему список меток, который работает в multisplit, в fakedsplit молча становится одним числом. Кого из шести игрушечных читателей что обманет. И как это написано в коде: его мы откроем в конце.

Итак. Разрез прячет имя от читателя, который смотрит пакеты по одному, а фейк с условием не доходит до приложения. Три функции собирают это в одну серию. Дальше пары стратегий, ловушки, читатели и код.

Другие порядки и пары; пара без условия

Вопрос сцены: какие ещё порядки и пары мы пробовали, и что станет с парой, в которой у фейка нет условия?

Игрушка, выдуманная. Две записки лежат на столе, и их читают в том порядке, в каком положили. Если сверху записка с неправильным адресом, первым прочтёт тот, кто верит первой записке. Порядок записок это и есть порядок пакетов.

Напоминание из предыдущей части. Два экземпляра на одном пакете выполняются в порядке записи, и аргументы у каждого свои. Fake впереди кладёт фейк в шестьсот восемьдесят байт перед тремя настоящими частями multisplit. Если поставить fake после multisplit, фейк уйдёт после данных, а сервер в нашем тесте его выбросит.

Теперь пары с условием tcp_md5, то есть с опцией MD5, на фейке; всё в нашем тесте. Фейк и fakedsplit: фейк в шестьсот восемьдесят байт и за ним шесть пакетов разреза с фейками, всего семь.

Проверь себя. Пара «фейк и multidisorder» с метками один и midsld: части уходят задом наперёд, как в выпуске «Перемешать: disorder». Какой пакет уйдёт последним и с какого смещения?

Настоящая часть в один байт, со смещения ноль. Сначала фейк, потом части в сто сорок шесть байт, в сто три и в один. Приложение сервера в нашем тесте прочитало оригинал.

Фейк и hostfakesplit: фейк в шестьсот восемьдесят байт и пять пакетов имени между двойниками. Фейки здесь двух видов: один накрывает всё приветствие, два двойника только имя.

Четвёртая пара: у фейка не MD5, а срок жизни один. Он умирает в роутере, клиент получает одно сообщение ICMP, а настоящие части проходят. А пара с multisplit и опцией MD5 справляется и с длинным приветствием в тысячу четыреста восемьдесят четыре байта. Во всех этих запусках приложение сервера в нашем тесте прочитало настоящие байты без изменений.

Пары стратегий с условием Пары стратегий с условием, порядок пакетов на проводе: фейк в 680 байт впереди трёх частей multisplit, он же после частей, перед семью пакетами разреза с фейками, перед частями перемешивания, где последней уходит часть в один байт со смещения 0, перед пятью пакетами имени между двойниками, где фейки двух видов, фейк со сроком жизни один, который гаснет в роутере, а клиент получает одно сообщение ICMP, и пара с длинным приветствием в 1484 байта; во всех запусках приложение сервера читает настоящие байты, равные оригиналу. две стратегии подряд: порядок строк запуска это порядок пакетов игрушка (выдуманный пример): записки читают в порядке укладки; слева направо порядок отправки fake + multisplit250 Б, равны оригиналуF680@0mфейкR1@0настоящаяR103@1настоящаяR146@104настоящаяфейк впереди данных multisplit + fake250 Б, равны оригиналуR1@0настоящаяR103@1настоящаяR146@104настоящаяF680@0mфейкфейк после данных:сервер его выбросил fake + fakedsplit250 Б, равны оригиналуF680@0mфейкF104@0mфейкR104@0настоящаяF104@0mфейкF146@104mфейкR146@104настоящаяF146@104mфейк fake + multidisorder250 Б, равны оригиналуF680@0mфейкпроверь себя: какой пакет уйдёт последним и с какого смещения? ??? R146@104настоящаяR103@1настоящаяR1@0настоящаяпоследним уходитчасть в 1 байт с нуля fake + hostfakesplit250 Б, равны оригиналуF680@0mфейк: всёR97@0настоящаяF15@97mдвойникR15@97имяF15@97mдвойникR138@112настоящаяфейки двух видов: фейк на всё приветствие (680) и два двойника только на имя (15) fake t1 + multisplit250 Б, равны оригиналуF680@0t1гаснетR1@0настоящаяR103@1настоящаяR146@104настоящаягаснет в роутере; ICMP«срок жизни истёк» клиенту fake + multisplit1484 Б, равны оригиналуF680@0mфейкR1@0настоящаяR103@1настоящаяR1380@104настоящаядлинное приветствиев 1484 байта фейки с MD5 сервер выбросил, настоящие части дошли; всё это наш тест

Теперь главное: пара без условия. Берём ту же заготовку и multisplit, но tcp_md5 убираем. Фейк без условия это обычный пакет с номером один и длиной шестьсот восемьдесят. Без условия мы пробовали только пару с multisplit.

Сервер принял этот пакет и ответил: жду шестьсот восемьдесят первый байт. Это значит, что первые шестьсот восемьдесят у него есть. Но клиент отправил только двести пятьдесят и ждёт ответа на двести пятьдесят первый. Подтверждение байтов, которых клиент не отправлял, он принять не может. Это объяснение по общим сведениям о TCP, но подтверждение с таким номером и неизменное «жду первый байт» от клиента мы видим на проводе. Приложение сервера получило шестьсот восемьдесят байт фейкового приветствия с именем www точка microsoft точка com.

Сервер при этом свой короткий ответ отправил, это видно в захвате, но клиент его не принял. Клиент повторял приветствие: в захвате шесть кругов, в каждом фейк и три настоящие части. Каждый раз сервер отвечал тем же «жду шестьсот восемьдесят первый». О паузах между кругами мы ничего не утверждаем.

Пара без условия Пара фейк и multisplit без условия: фейк в 680 байт с номером 1 без опции MD5 для сервера обычный пакет, он отвечает жду байт 681, то есть первые 680 байт у него есть, и отправляет свой короткий ответ в 14 байт, затем приходят три настоящие части в 1, 103 и 146 байт, и на каждую сервер снова отвечает жду байт 681, клиент отправил только 250 байт, его следующий байт 251, и он по-прежнему ждёт байт 1, ответ сервера не принимает, поэтому приветствие повторяется шесть кругов, а приложение сервера получило 680 байт фейкового приветствия с именем другого сайта, и у клиента нет ответа на приветствие. пара без условия: фейк принят сервером как обычные данные --lua-desync=fake:blob=fake_default_tls--lua-desync=multisplit:pos=1,midsldбез tcp_md5 клиентроутерсервер 1фейк без условияномер 1 · длина 680 · без MD5 ack 681жду байт 681: 680 байт есть 2свой короткий ответ сервера, 14 байтсервер отправил, клиент его не принял 3настоящая частьномер 1 · длина 1 ack 681, дубль: байт 1 4настоящая частьномер 2 · длина 103 ack 681, дубль: байты 2…104 5настоящая частьномер 105 · длина 146 ack 681, дубль: байты 105…250 что видит клиентотправил 250 байт, его следующий байт 251по-прежнему ждёт байт 1: ответ не принятв его пакетах номер подтверждения 1 что видит сервер680 байт фейкового приветствияждёт байт 681; клиент прислал только 250байты, которых клиент не слал, не подтвердит шесть кругов: в каждом фейк 680 и три настоящие части круг 1 круг 2 круг 3 круг 4 круг 5 круг 6 первый круг оригинал клиента, остальные повторы; сервер каждый раз отвечает «жду байт 681» приложение сервера: 680 байт, имя www.microsoft.com, не оригиналу клиента ответа на приветствие нет в нашем тесте; объяснение про подтверждение по общим сведениям о TCP, номера и повторы на проводе

Вывод про стратегии простой: опасный пакет в паре это фейк. Разрезанные части безвредны, а фейк без условия в нашем тесте сломал соединение.

Итак. Порядок экземпляров решает, где лежит фейк: впереди данных или после них. С условием фейк в нашем тесте умирает рядом с четырьмя разрезающими стратегиями, настоящие части доходят, и на длинном приветствии тоже. Без условия в паре с multisplit приложение получило фейк, а соединение встало.

Ловушки: список меток и аргументы, которые молчат

Вопрос сцены: почему список меток, который работает в multisplit, в fakedsplit молча становится одним числом, и какие ещё аргументы молчат?

Игрушка, выдуманная. Анкета с одной клеткой «номер места». Клерк читает клетку до первой запятой и дальше не смотрит. Напишете «семь, у окна», он запишет семь и не скажет, что про окно не узнал.

Список с метками один и midsld знаком по выпуску «multisplit: резать на части»: две метки, три части. Поставим тот же список в fakedsplit: pos равно один, запятая, midsld. Смотрим на провод нашего теста.

Первый пакет: фейк в один байт, смещение ноль. Второй: настоящая часть, тоже один байт. Третий: тот же фейк. Дальше три пакета по двести сорок девять байт со смещения один: фейк, настоящая часть, фейк.

В записях журнала о самом разрезе про midsld нет ни слова: сначала строка, что найденная позиция равна одному, потом шесть строк об отправке. Строки об ошибке нет. Потерю видно только по проводу или по счёту.

Разрез один, после первого байта, а в multisplit тот же список даёт три части. Имя сайта начинается со смещения девяносто семь и целиком лежит в настоящей части на двести сорок девять байт. Для нашей модели это значит: «пакетный», который ищет имя в каждом пакете отдельно, находит его, и единственное, чем разрез его обманывал, потеряно.

Список меток становится числом Список меток в fakedsplit молча становится одним числом: в игрушке клерк читает клетку анкеты до первой запятой и записывает семь, а про окно не говорит; список один и midsld в multisplit даёт три части в 1, 103 и 146 байт, а в fakedsplit на проводе шесть пакетов, фейк в один байт, настоящая часть в один байт, ещё фейк, потом фейк в 249 байт со смещения 1, настоящая часть в 249 байт и ещё фейк, имя сайта на смещениях с 97 по 111 целиком лежит в настоящей части на 249 байт, а в журнале нет ни одной строки об ошибке. список меток в fakedsplit молча становится одним числом игрушка (выдуманный пример): анкета с одной клеткой «номер места» написано: 7, у окнаклерк записал:7, у окнапро окно не сказал один и тот же список pos=1,midsldmultisplit:pos=1,midsldfakedsplit:pos=1,midsld:tcp_md5мы смотрим на провод второй провод fakedsplit: что уходит клиентусмещ.длинаMD50250 имя 97…111 1фейк01MD5 2настоящая01- 3фейк01MD5 4фейк1249MD5249 5настоящая1249-249 6фейк1249MD5249 multisplit: три части1031461104 журнал fakedsplit: о разрезе ни слова про midsldfakedsplit: resolved split pos: 1fakedsplit: sending fake part 1 (1) : 0-0 len=1 : 00 … и ещё пять строк sendingстрок с ERROR в журнале: 0 потерю видно только по проводу или по счёту пакетов имя целиком лежит в настоящей части на 249 байт: в одном пакете оно находитсяединственное, чем разрез его прятал, потеряно; две линейки: смещение с нуля, позиция Lua с единицы

Другие значения ведут себя так же. Два, запятая, midsld даёт разрез после двух байт. Midsld плюс один, запятая, host даёт разрез после ста пяти байт, а host пропадает. Напомню две линейки из выпуска «Где резать: метки»: смещение считается с нуля, позиция Lua с единицы. Прогон функций превращает «один, midsld» в позицию два, то есть в смещение один.

Вторая ловушка громкая. Если сразу за именем метки стоит запятая, как в «midsld, host», функция не узнаёт такое имя и останавливается с ошибкой «плохая метка». Программа пишет в журнал, что пакет пропущен без изменений, и приветствие уходит целым, двести пятьдесят байт одним пакетом. Сервер в нашем тесте его прочитал.

Правило целиком. Список начинается с числа: число читается, остальное молча теряется. Начинается с имени, за которым плюс или минус: читается одна метка, остальное тоже теряется. Начинается с имени, за которым сразу запятая: ошибка.

Проверь себя. Что сделает pos равное host минус один, запятая, midsld?

Имя host стоит перед минусом, значит это одна метка host минус один, а остаток после запятой потерян. Разрез после девяноста шести байт, части в девяносто шесть и сто пятьдесят четыре, midsld пропал молча. Это расчёт по коду; запуск с одним host минус один даёт именно такие части.

Правило списка меток и ошибка Как читается список меток и что делает ошибка: функция читает число до первой запятой, остаток после запятой теряется, и один, midsld превращается в позицию 2 по счёту Lua, то есть в смещение 1; два, midsld даёт части 2 и 248, midsld плюс один, host даёт части 105 и 145, а midsld, host функция не узнаёт, пишет плохая метка, программа пропускает пакет без изменений и приветствие в 250 байт уходит целым; правило из трёх случаев: с числа число читается и остальное теряется, с имени и знака читается одна метка, с имени и сразу запятой ошибка; расчёт для host минус один, midsld даёт части 96 и 154, как запуск с одним host минус один. как функция читает pos: одна метка, а остаток теряется 1 , m i d s l d курсор читает «1» на запятой стоп: остаток «,midsld» теряется молча позиция 2 (Lua)= смещение 1 списокпозиция Luaчасти в запуске 1,midsld21 и 249 2,midsld32 и 248 midsld+1,host106105 и 145; host пропал midsld,hostошибка: плохая меткацелое приветствие, 250 байт позиции получены прогоном настоящей функции; части взяты с провода ошибка громкая: приветствие уходит целымbad marker : 'midsld,host'desync ERROR. passing packet unmodified.R250@0сервер: 250 байт правило списка: три случая с числа1,midsldчисло читается, остальное теряется с имени и знакаhost-1,midsldчитается одна метка, остальное теряется с имени и сразу запятаяmidsld,hostошибка: уходит целое приветствие проверь себячто сделает pos=host-1,midsld? где разрез? 96 байт154 байта0250 host стоит перед минусом: метка host−1 (смещение 96), остаток после запятой потерян, midsld пропал молчарасчёт по коду: такого запуска нет опыт с одним pos=host-1, без списка:F96@0mR96@0F96@0mF154@96mR154@96F154@96m

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

Второй: ipfrag, нарезка на фрагменты IP, о ней выпуск «Другие слои». Мы дали его всем трём функциям, и на проводе клиента в нашем тесте ни одного фрагмента, а multisplit с тем же ipfrag дал четыре. В таблицах настроек этих функций для ipfrag пустое значение, и нарезчик не запускается. Руководство это подтверждает, а комментарий внутри hostfakesplit им противоречит.

Третий: repeats и badsum касаются только фейков. С repeats равным два каждый фейк уходит дважды, а настоящие части один раз: в нашем тесте десять пакетов вместо шести.

Четвёртый: seqovl словом. В fakedsplit накладка задаётся только числом. С seqovl равным host функция остановилась с ошибкой уже после первого фейка, программа пропустила оригинал, и на проводе фейк в сто четыре байта, а следом приветствие целиком. Числом seqovl в нашем тесте работает: равное пяти, оно даёт настоящую часть в сто девять байт, которая начинается на пять байт раньше первого байта приветствия.

Аргументы, которые молчат Аргументы, которые молчат: pos у hostfakesplit не читается, потому что функция сама ищет имя метками host и endhost минус один, и с pos равным два на проводе те же пять пакетов, что и без него; ipfrag не работает у fakedsplit, fakeddisorder и hostfakesplit, на проводе клиента ноль фрагментов IP, а у multisplit с тем же ipfrag четыре фрагмента, потому что в таблицах настроек этих функций для ipfrag пустое значение; repeats равное двум отправляет каждый фейк дважды, а настоящие части один раз, получается десять пакетов вместо шести; seqovl словом host даёт ошибку после первого фейка и приветствие уходит целым, а числом пять даёт настоящую часть в 109 байт, начатую на пять байт раньше приветствия. четыре аргумента, которые молчат по-разному 1. pos у hostfakesplit: функция его не читает hostfakesplit:pos=2:tcp_md5R97@0F15@97mR15@97F15@97mR138@112 hostfakesplit:tcp_md5R97@0F15@97mR15@97F15@97mR138@112 те же пятьпакетов= lua/zapret-antidpi.lua:721 local pos = resolve_range(data, desync.l7payload, "host,endhost-1", true) 2. ipfrag: у трёх функций фрагментов IP нет что на проводе клиентафрагментов IP fakedsplit:ipfrag6 пакетов целиком0 fakeddisorder:ipfrag6 пакетов целиком0 hostfakesplit:ipfrag5 пакетов целиком0 multisplit:ipfragдля сравнения: нарезка работает4 lua/zapret-antidpi.lua:850-851 ipfrag = {} (в таблицах настроек пустое значение)lua/zapret-lib.lua:1198 if options and options.ipfrag and options.ipfrag.ipfrag ... нарезчик запускаетсяdocs/manual.en.md:4189 ipfrag_opts are not used for either fakes or originals комментарий в hostfakesplit (строка 754) этому противоречит; на проводе фрагментов нет 3. repeats и badsum касаются только фейков: repeats=2, десять пакетов вместо шести F104F104R104F104F104F146F146R146F146F146 пары фейков идут с одним номером в заголовке IP, у настоящих частей по одному пакету 4. seqovl словом: накладка задаётся только числом seqovl=hostF104@0mошибка после первого фейка, оригинал идёт целым:R250@0 lua/zapret-antidpi.lua:866 if desync.arg.seqovl and tonumber(desync.arg.seqovl)>0 thenattempt to compare number with nil / desync ERROR. passing packet unmodified. seqovl=5F104@0mR109@-5F104@0mF146@104mR146@104F146@104m вторая часть: длина 109, начало на 5 байт раньше первого байта приветствия

Итак. В fakedsplit и fakeddisorder pos это одна метка: список с числа молча становится числом, а список с имени и запятой даёт ошибку и целое приветствие. Pos у hostfakesplit не читается, ipfrag не работает у всех трёх, repeats и badsum касаются только фейков. Первые три случая молчат и видны только на проводе, а у seqovl словом ошибка в журнале есть, но первый фейк уже ушёл.

Шесть читателей и таблица: кого обманули разрез и фейки

Вопрос сцены: кого из наших игрушечных читателей обманывают эти стратегии? Напоминание: это модели проекта, а не оборудование, и «сработало» значит «обошло игрушку».

Игрушка, выдуманная. Шесть клерков получили один и тот же ворох бумажек с кусками письма и ищут в нём адрес. У каждого своё правило, и каждое придумали мы.

Читатели читают запись пакетов у входа в роутер: ровно то, что туда дошло, вместе с фейками. Они принимают любой пакет как есть: ни опцию MD5, ни контрольную сумму, ни срок жизни не проверяют. Поэтому фейк с условием для них обычные данные. «Видит» значит, что имя нашлось и читателя не обманули. «Слеп» значит, что имя не нашлось: для нас это хороший исход.

Пять читателей знакомы по выпуску «Перемешать: disorder». «Пакетный» ищет имя в каждом пакете отдельно. «Склейщик» клеит данные в порядке прихода. «Первый записал» собирает по номерам, у перекрытых байтов остаётся первая запись. «Последний записал» то же, но остаётся последняя. «Строго по порядку» берёт сегмент, только если он начинается не позже ожидаемого байта. Все пятеро решают после каждого пакета.

Шестой новый: «последний записал, судит в конце». Правила те же, но решение он принимает один раз, когда поток закончился.

Шесть игрушечных читателей Шесть игрушечных читателей как модели проекта, а не настоящее оборудование: пакетный ищет имя в каждом пакете отдельно, склейщик клеит данные в порядке прихода, первый записал собирает по номерам и оставляет первую запись, последний записал оставляет последнюю запись, последний записал с решением в конце принимает то же самое решение один раз, когда поток закончился, а строго по порядку берёт сегмент, только если он начинается не позже ожидаемого байта; все читают запись пакетов на входе роутера вместе с фейками, принимают любой пакет как есть, не проверяют опцию MD5, контрольную сумму и срок жизни, слово видит значит что имя найдено, а слеп значит что имя не найдено и приём сработал. шесть игрушечных читателей: наши модели в лаборатории нет настоящего ТСПУ: читатели это модели проекта«сработало» значит только «обошло нашу модель» читатели читают запись пакетов у входа в роутер: всё, что дошло, вместе с фейкамилюбой пакет они принимают как есть: опцию MD5, сумму и срок жизни не проверяют видит: имя найдено, нас не обманулислеп: имя не найдено, приём сработал пять знакомых по выпуску «Перемешать: disorder» и один новый пакетныйодин пакетищет имя в каждом пакетеотдельнорешает: после каждого пакета склейщик123по приходуклеит данные в порядкеприходарешает: после каждого пакета первый записалзанятая клетка закрытапо номерам, у перекрытыхбайтов первая записьрешает: после каждого пакета последний записалновая запись затирает старуюпо номерам, у перекрытыхбайтов последняя записьрешает: после каждого пакета последний записал,судит в конценов.глазок мигает один раз, в концете же правила, но решает одинраз, когда поток закончилсярешает: один раз, в самом конце строго по порядкуворота: будущее выброшеноберёт сегмент, начинающийсяне позже ожидаемого байтарешает: после каждого пакета

Строки таблицы. Первая, multisplit с midsld: слеп только «пакетный», потому что имя разрезано. Остальные пятеро видят, ведь части идут по возрастанию.

Вторая, fakedsplit с midsld и условием: слепы все шесть. Фейки не дают собрать имя ни тому, кто верит первой записи, ни тому, кто последней, а разрез прячет имя от «пакетного». В нашем тесте то же у fakeddisorder.

Третья, fakedsplit с pos равным host: имя целиком лежит в одной настоящей части. «Пакетный», «склейщик» и «последний записал» видят его, слепы остальные трое. Такая же картина у hostfakesplit.

Четвёртая, наш список один и midsld в fakedsplit: имя целиком внутри длинной настоящей части. Картина та же, что при host. Потеря midsld для «пакетного» значит: имя осталось целым.

Пятая, hostfakesplit с midhost равным midsld: настоящее имя разрезано пополам. Теперь слеп и «пакетный». Видят «склейщик» и «последний записал».

Пары. Фейк и multisplit: фейк в шестьсот восемьдесят байт идёт первым, поэтому «первый записал» и «строго по порядку» берут его нули. «Пакетный» слеп из-за разреза. А «склейщик» и оба «последних записал» видят: настоящие байты ложатся поверх.

Обратный порядок: фейк приходит последним и затирает настоящие байты. Слепы «судит в конце» и «пакетный», остальные успели увидеть имя раньше. А фейк и fakedsplit ослепляют всех шестерых.

Проверь себя. В паре «фейк и multidisorder» видит ли имя «склейщик»?

Нет. Части приходят задом наперёд: хвост «mple точка com» раньше начала «www точка exa», и в склейке по порядку прихода имя не собирается. Фейк тут ни при чём: слепой «склейщик» и у multidisorder без фейков, как мы видели в выпуске «Перемешать: disorder». Видят в этой строке только оба «последних записал».

Кого обманули разрез и фейки Таблица: кого из шести игрушечных читателей обманули разрез и фейки, это модели над записью пакетов, а не измерение какого-либо устройства: при multisplit с midsld слеп только пакетный; при fakedsplit и fakeddisorder с четырьмя фейками и разрезом внутри имени слепы все шесть; при pos равном host и при hostfakesplit, а также при списке один и midsld, который стал числом, пакетный, склейщик и последний записал видят имя, остальные трое слепы; при midhost равном midsld слепы пакетный, первый записал, судит в конце и строго по порядку; в паре фейк и multisplit слепы пакетный, первый записал и строго по порядку, в обратном порядке слепы пакетный и судит в конце, в паре фейк и fakedsplit слепы все шесть, а в паре фейк и multidisorder склейщик слеп, потому что хвост приходит раньше начала. кого из шести читателей обманули разрез и фейки видит: нас не обманулислеп: имя не найдено, приём сработалмодели над записью, не оборудование запускпакетныйсклейщикпервыйзаписалпоследнийзаписалпоследнийзаписал,судит в концестрогопо порядку multisplit, midsldимя разрезано, порядок прямойслепвидитвидитвидитвидитвидит fakedsplit, fakeddisorder4 фейка и разрез внутри именислепслепслепслепслепслеп pos=host и hostfakesplitимя целиком в настоящей частивидитвидитслепвидитслепслеп fakedsplit:pos=1,midsldсписок стал числом: 1 и 249видитвидитслепвидитслепслеп hostfakesplit + midhostmidhost=midsld, имя разрезанослепвидитслепвидитслепслеп fake + multisplitфейк 680 первым: занял местослепвидитслепвидитвидитслеп multisplit + fakeфейк 680 последним: затираетслепвидитвидитвидитслепвидит fake + fakedsplitфейки ослепляют всех шестерыхслепслепслепслепслепслеп fake + multidisorderчасти идут с концаслепслепвидитвидитслеп ? слеп проверь себя: видит ли имя «склейщик» в этой паре? fake + hostfakesplitкак hostfakesplitвидитвидитслепвидитслепслеп в порядкеприхода после фейкаR146@104«mple.com»R103@1«www.exa»R1@0первый байт хвост «mple.com» приходит раньше начала «www.exa»: в склейке по порядку прихода имя не собираетсяэто так и без фейка: слепой «склейщик» есть и у multidisorder в выпуске «Перемешать: disorder»

Итак. Разрез ослепляет «пакетного». В fakedsplit с четырьмя фейками и разрезом внутри имени слепы все шесть, а один фейк в паре ослепляет не всех. Если имя целиком в одной настоящей части, «пакетный» и «склейщик» видят его во всех наших запусках. Всё это про наши модели и больше ни про что.

Живые игрушки в роутере: кто на каком пакете остановил соединение

Вопрос сцены: что будет, если читатель стоит не над записью, а прямо в роутере и выбрасывает пакеты, найдя имя?

Игрушка, выдуманная. Вахтёр на входе читает письма. Найдя нужное слово, он выбрасывает это письмо и все следующие письма того же отправителя.

В выпуске «Перемешать: disorder» мы ставили в роутер второй nfqws2 с нашим читателем. Он читает данные клиента по одному из способов, и в том выпуске их было четыре. Сегодня добавлен пятый, пакетный: он ищет имя в каждом пакете отдельно, как наш читатель с тем же прозвищем. Найдя имя, игрушка выбрасывает этот пакет и все следующие пакеты клиента с данными. Результат мы считаем по числу байт, которые получил сервер.

Номер пакета здесь это номер клиентского пакета с данными, который игрушка увидела: пакеты без данных, например подтверждения, не считаются.

Без стратегии «пакетный» и «первый записал» находят имя на первом же пакете, и сервер получает ноль байт. Это контрольная строка: приветствие без всяких приёмов. Остальных трёх читателей без стратегии мы не запускали.

С multisplit «пакетный» имя не находит, и сервер получает все двести пятьдесят байт. Четыре читателя, которые собирают данные, находят имя на втором пакете, выбрасывают его, и сервер получает только первые сто четыре байта.

Почему именно на втором. После первой части в сто четыре байта имя ещё не собрано, а после второй уже собрано целиком. Вторую часть игрушка выбрасывает, и сервер остаётся с одной первой.

С fakedsplit и условием tcp_md5 не находит имя ни один из пяти, и приложение сервера получает все двести пятьдесят байт, равных оригиналу. С fakeddisorder так же. Это наш тест и наши игрушки: разрез и фейки не дали никому из пяти собрать имя.

С hostfakesplit картина смешанная. Первый пакет это часть в девяносто семь байт, второй двойник, третий настоящее имя. «Первый записал» и «строго по порядку» держат в руках двойника и не находят настоящее имя: сервер получает всё. А «пакетный», «склейщик» и «последний записал» находят имя на третьем пакете, выбрасывают его, и сервер получает только девяносто семь байт.

Проверь себя. Пара «фейк и multisplit»: на каком пакете остановится «последний записал» и сколько байт получит сервер?

На четвёртом, на последней настоящей части: до неё имя не собрано. Фейк в шестьсот восемьдесят байт сервер выбросил по MD5, так что дошли часть в один байт и часть в сто три: сто четыре байта. Так же на четвёртом пакете останавливается «склейщик». А «пакетный», «первый записал» и «строго по порядку» имени не находят, и сервер получает всё.

Игрушка в роутере выбрасывает пакеты Живая игрушка в роутере, которая найдя имя выбрасывает этот пакет и все следующие данные клиента, это модель проекта и в лаборатории нет настоящего ТСПУ: без стратегии пакетный находит имя на первом пакете и сервер получает ноль байт; с multisplit склейщик находит имя на втором пакете, и до сервера доходят 104 байта; с hostfakesplit пакетный находит настоящее имя на третьем пакете, пакеты в 15 и 138 байт выбрасываются, и сервер получает 97 байт; в паре фейк и multisplit последний записал останавливает соединение на четвёртом пакете, фейк в 680 байт сервер выбросил по MD5, поэтому сервер получает 1 плюс 103, то есть 104 байта. живая игрушка в роутере: кто на каком пакете остановил соединение модели проекта; в лаборатории нет настоящего ТСПУ игрушка (выдуманный пример): вахтёр, найдя слово, выбрасывает письмо и все следующие клиентшлёт данныероутернаша игрушка: читатель на Luaсерверсчитаем байты номер пакета: номер клиентского пакета с данными, который увидела игрушкапакеты без данных, например подтверждения, не считаются без стратегии«пакетный»пакет 1R250@0DROP сервер получил0 байт multisplit, midsld«склейщик»пакет 1R104@0не собранопакет 2R146@104имя найденоDROP сервер получил104 байта hostfakesplit«пакетный»пакет 1R97@0имени нетпакет 2F15@97mдвойникпакет 3R15@97имя найденопакет 4F15@97mвыброшенпакет 5R138@112выброшенDROP сервер получил97 байт fake + multisplit«последний записал»пакет 1F680@0mфейкпакет 2R1@0настоящаяпакет 3R103@1настоящаяпакет 4R146@104имя найденоDROP сервер получил104 байта фейк 680 сервер выбросил по MD5: 1 + 103 журнал игрушки (hostfakesplit, «пакетный»)TOY mode=perpacket seq_off=97 len=15 host_found=falseTOY mode=perpacket seq_off=97 len=15 host_found=trueTOY host name seen: dropping this packet and all later client data of the connection

Последняя строка самая поучительная. Fakedsplit без условия: ни один читатель имя не нашёл. Но сервер получил двести пятьдесят байт, и все они нули. Читатель слеп, а соединение разрушено: это разные вещи.

Таблица остановок живых игрушек Таблица живых игрушек в роутере, которые выбрасывают пакеты: без стратегии пакетный и первый записал останавливают соединение на первом пакете и сервер получает 0 байт; с multisplit пакетный имя не находит и сервер получает 250 байт, четыре собирающих читателя останавливают на втором пакете и сервер получает 104 байта; с fakedsplit и fakeddisorder и условием MD5 ни один из пяти не нашёл имя и сервер получил 250 байт, равных оригиналу; с hostfakesplit пакетный, склейщик и последний записал останавливают на третьем пакете и сервер получает 97 байт, а первый записал и строго по порядку не находят имя; в паре фейк и multisplit склейщик и последний записал останавливают на четвёртом пакете и сервер получает 104 байта; у fakedsplit без условия ни один читатель не нашёл имя, но сервер получил 250 байт, и все они нули, поэтому слеп читатель не значит цело соединение. кто остановил соединение и сколько байт получил сервер модели проекта, не оборудование; «стоп, пакет N»: игрушка нашла имя на N-м клиентском пакете с данными запускпакетныйсклейщикпервыйзаписалпоследнийзаписалстрогопо порядку без стратегииконтрольная строкастоп, пакет 1сервер: 0 Бне запускалистоп, пакет 1сервер: 0 Бне запускалине запускали multisplit, midsldчасти 104 и 146не нашёлсервер: 250 Бстоп, пакет 2сервер: 104 Бстоп, пакет 2сервер: 104 Бстоп, пакет 2сервер: 104 Бстоп, пакет 2сервер: 104 Б fakedsplit, fakeddisorderMD5; байты равны оригиналуне нашёлсервер: 250 Бне нашёлсервер: 250 Бне нашёлсервер: 250 Бне нашёлсервер: 250 Бне нашёлсервер: 250 Б hostfakesplitимя в своём пакетестоп, пакет 3сервер: 97 Бстоп, пакет 3сервер: 97 Бне нашёлсервер: 250 Бстоп, пакет 3сервер: 97 Бне нашёлсервер: 250 Б fake + multisplitфейк 680, потом три части проверь себя: где остановит «последний записал» и сколько байт? не нашёлсервер: 250 Бстоп, пакет 4сервер: 104 Бне нашёлсервер: 250 Бстоп, пакет 4сервер: 104 Бне нашёлсервер: 250 Б фейк 680 сервер выбросил по MD5, поэтому дошли 1 + 103 = 104 байта fakedsplit без условияфейки без MD5не нашёлсервер: нулине нашёлсервер: нулине нашёлсервер: нулине нашёлсервер: нулине нашёлсервер: нули читатель слеп, а соединение разрушено: сервер получил 250 байт, и все они нули слепота читателя и целостность данных это два разных вопроса; всё это наш тест и наши игрушки

Итак. В нашей игрушечной модели живые читатели подтверждают таблицу: разрез с фейками и условием доводит до сервера все байты, а hostfakesplit и пара «фейк и multisplit» обманывают одних читателей и не обманывают других. Слепота читателя и целостность данных это два разных вопроса. Всё это наш тест и наши игрушки.

У каждого фейка своя работа: четыре выключателя против шести читателей

Вопрос сцены: зачем в fakedsplit целых четыре фейка, и какую работу делает каждый?

Игрушка, выдуманная. На двери четыре замка. Чтобы понять, какой замок от какого вора, снимаем их по одному и смотрим, кто войдёт.

Фейки номер один и три стоят перед настоящей частью, назовём их «фейки до». Фейки номер два и четыре стоят после неё, назовём их «фейки после». Выключатели nofake один, два, три и четыре убирают их по одному. Эта нумерация записана в коде; у fakeddisorder она другая, о ней дальше.

Четыре фейка и клетки имени Четыре фейка fakedsplit на проводе по порядку отправки и что остаётся в клетках имени у двух читателей после каждого пакета: фейк 1 до первой части, настоящая первая часть в 104 байта, фейк 2 после неё, фейк 3 до второй части в 146 байт, настоящая вторая часть и фейк 4 после неё; при всех четырёх фейках читатель последний записал ни разу не собирает имя, потому что фейк 2 затирает нулями конец первой части раньше, чем приходит вторая; без фейка 2 этот читатель после четвёртого пакета видит имя целиком, а после пятого фейк 4 его затирает; если убрать фейки 1 и 3, читатель первый записал держит настоящие байты и собирает имя на третьем пакете. www.example.com0 четыре фейка fakedsplit в порядке отправки: разрез midsld, условие MD5 фейк 1 · до104 Б, с 0nofake1строка 858 настоящая 1104 Б, с 0 фейк 2 · после104 Б, с 0nofake2строка 882 фейк 3 · до146 Б, с 104nofake3строка 889 настоящая 2146 Б, с 104 фейк 4 · после146 Б, с 104nofake4строка 900 номер в названии это порядок фейка в коде: «до» и «после» значит до и после своей настоящей части «последний записал»: все фейкибайты 97…103байты 104…111 1фейк 1: нули на 0…103нет имени 2настоящая 1: www.exaчасть имени 3фейк 2: нули на 0…103снова нули 4фейк 3: нули на 104…249нули 5настоящая 2: mple.comв начале нули 6фейк 4: нули на 104…249нули «последний записал»: nofake2байты 97…103байты 104…111 1фейк 1: нули на 0…103нет имени 2настоящая 1: www.exaчасть имени 3фейк 3: нули на 104…249нет имени 4настоящая 2: mple.comИМЯ СОБРАНО 5фейк 4: нули на 104…249затёрто «первый записал»: nofake1 и nofake3байты 97…103байты 104…111 1настоящая 1: www.exaчасть имени 2фейк 2: нули на 0…103уже занято 3настоящая 2: mple.comИМЯ СОБРАНО 4фейк 4: нули на 104…249имя осталось при всех четырёх фейк 1 ложится первым и занимает 0…103 нулями: «первый записал» держит нули и слеп «судит в конце» смотрит только на последнюю строку: там нули. Это наша игрушечная модель

Разрез посередине имени, midsld, все четыре фейка на месте: слепы все шесть читателей. Уберём фейк один: всё то же, потому что фейк два всё равно затирает конец первой части.

Уберём фейк два. Теперь после второй настоящей части имя на миг собрано целиком, и «последний записал», который решает после каждого пакета, его видит. Фейк четыре придёт уже после проверки. По пакетам: после четвёртого, настоящей второй части, имя собрано целиком, после пятого, фейка после неё, затёрто. Читатель, который судит один раз в конце, видит уже затёртое. Это единственный случай, когда одиночное отключение меняет картину: без фейка три или четыре слепы по-прежнему все шесть.

Теперь уберём оба фейка до. В нашем тесте остаются только фейки после, и имя видят «первый записал» и «строго по порядку». Фейк, который лежит до настоящей части, занимает место первым, и тот, кто верит первой записи, берёт его. Без него настоящие байты ложатся первыми, и имя собирается целиком.

Уберём оба фейка после. Остаются фейки до, и имя видят оба «последних записал». Фейк после затирает настоящие байты нулями, и тот, кто верит последней записи, получает нули. Без него настоящие байты остаются на месте, и имя в конце потока цело.

Уберём все четыре: остаётся обычный разрез, и имя видят все, кроме «пакетного». Значит, всё, что мы видели выше, делают именно фейки: замки это фейки, а воры это читатели.

Теперь тот же опыт с pos равным host: имя целиком лежит в настоящей второй части. Когда все четыре фейка на месте, имя видят «пакетный», «склейщик» и «последний записал». От первых двух целый настоящий пакет ни один фейк в наших запусках не спрятал.

Проверь себя. Fakedsplit с pos равным host, tcp_md5 и nofake три. Кто видит имя?

К «пакетному», «склейщику» и «последнему записал» добавляются «первый записал» и «строго по порядку»: фейк три, который их ослеплял, убран. «Судит в конце» остаётся слеп: фейк четыре стоит после второй части и затирает её. Это строка нашего теста, про нашу модель, не про настоящее оборудование. А если убрать фейк четыре, «судит в конце» тоже увидит имя.

Выключатели против шести читателей Таблица игрушечных читателей для fakedsplit с разрезом посередине имени и условием MD5: при всех четырёх фейках слепы все шесть читателей, без фейка 1, 3 или 4 тоже все шесть, без фейка 2 имя видит один читатель последний записал, без фейков 1 и 3 видят первый записал и строго по порядку, без фейков 2 и 4 видят оба последних записал, а без всех фейков видят все, кроме пакетного; при pos равном host, когда имя целиком в настоящей второй части, с четырьмя фейками видят пакетный, склейщик и последний записал, без фейка 3 добавляются первый записал и строго по порядку, а без фейка 4 добавляется судит в конце. видит или слеп: выключаем фейки fakedsplit по одному и по парам, разрез midsld, MD5 пакетныйсклейщикпервыйзаписалпоследнийзаписалсудитв концестрого попорядку все четыре фейкаслепслепслепслепслепслеп nofake1нет фейка 1слепслепслепслепслепслеп nofake2нет фейка 2слепслепслепвидитслепслеп nofake3нет фейка 3слепслепслепслепслепслеп nofake4нет фейка 4слепслепслепслепслепслеп nofake1+3остались «после»слепслепвидитслепслепвидит nofake2+4остались «до»слепслепслепвидитвидитслеп nofake1…4обычный разрезслепвидитвидитвидитвидитвидит то же с pos=host: имя целиком лежит в настоящей второй части все четыре фейкавидитвидитслепвидитслепслеп nofake3ответ на «проверь себя»видитвидитвидитвидитслепвидит nofake4после ответавидитвидитслепвидитвидитслеп фейк до настоящей части ослепляет «первый записал» и «строго по порядку»фейк после ослепляет «последний записал»: затирает настоящие байты нулямиразрез ослепляет «пакетного»; целое имя в одном пакете видят «пакетный» и «склейщик»всё это строки нашего теста и нашей игрушечной модели, не измерение какого-либо устройства

Итак. В нашей игрушечной модели фейк перед настоящей частью ослепляет читателей, которые верят первой записи, фейк после неё тех, кто верит последней, а разрез ослепляет «пакетного». Целый настоящий пакет в наших запусках не спрятан ни от «пакетного», ни от «склейщика». Для настоящего оборудования мы этого не знаем.

Где стоит читатель: фейки, которые не доходят, и правило с фиксированным местом

Вопрос сцены: всегда ли читатель видит фейки? Напоминание: все эти результаты про наши модели и наш приёмник.

Игрушка, выдуманная. Письмо с просроченной маркой возвращают с полпути. Вахтёр, который стоит дальше места возврата, такого письма не увидит. Важно не только что лежит в письме, но и где стоит вахтёр.

Наши онлайн-игрушки стоят в роутере на пути вперёд. Фейк со сроком жизни один доходит до входа в роутер, роутер отвечает клиенту сообщением ICMP и выбрасывает фейк. До игрушки он не добирается.

Срок жизни 1: фейки не доходят до игрушек Фейки со сроком жизни 1 доходят до входа в роутер, где стоит запись, и там умирают, а игрушки стоят за роутером и их не видят: у fakedsplit на проводе клиента шесть пакетов, четыре из них фейки, на входе роутера четыре сообщения «время истекло», игрушка получает только две настоящие части в 104 и 146 байт, четыре читателя находят имя на втором пакете и сервер получает 104 байта, а пакетный не находит имя и сервер получает 250; у hostfakesplit игрушка получает части в 97 и 15 байт, все пять находят имя на втором пакете и сервер получает 97 байт; всё это наша игрушечная модель, о настоящем оборудовании данных нет. срок жизни 1: фейк умирает на роутере, до игрушек за ним не доходит (модель проекта) клиентвход роутераза роутеромсерверздесь записьздесь игрушки fakedsplit:ip_ttl=1шесть пакетов клиента 1фейк 104 Б, срок 1ICMP назад 2настоящая 104 Бдошла 3фейк 104 Б, срок 1 4фейк 146 Б, срок 1 5настоящая 146 Бне дошлаигрушка нашла имя 6фейк 146 Б, срок 1 hostfakesplit:ip_ttl=1пять пакетов клиента 1настоящая до имени 97 Бдошла 2двойник 15 Б, срок 1 3настоящее имя 15 Бне дошлаигрушка нашла имя 4двойник 15 Б, срок 1 5настоящий хвост 138 Бне дошла запись у входа в роутер содержит и фейки со сроком жизни 1: они дошли и умерли на роутереигрушка за роутером видит только то, что пропустил роутер; клиент получил 4 и 2 сообщения ICMP пакетныйсклейщикпервыйзаписалпоследнийзаписалстрого попорядкуживые игрушки за роутером fakedsplit:ip_ttl=1не нашёлсервер 250пакет 2сервер 104пакет 2сервер 104пакет 2сервер 104пакет 2сервер 104 hostfakesplit:ip_ttl=1пакет 2сервер 97пакет 2сервер 97пакет 2сервер 97пакет 2сервер 97пакет 2сервер 97 после фейков клиент ещё повторяет вторую часть: это не свойство стратегиигде стоит настоящий инспектор относительно места смерти фейка, неизвестно

Fakedsplit со сроком жизни один: игрушки видят только две настоящие части, как при обычном разрезе. Четыре читателя, которые собирают данные, находят имя на втором пакете, и сервер получает сто четыре байта. «Пакетный» имя не находит, и сервер получает всё.

Hostfakesplit со сроком жизни один: настоящее имя лежит в своём пакете, а фейков игрушки не видят. Все пять находят имя на втором пакете, и сервер получает девяносто семь байт.

Урок про модель. Помогает ли фейк, зависит от того, видит ли его читатель, то есть от места читателя относительно точки, где фейк умирает. Где стоит настоящее оборудование, мы не знаем.

Заметьте разницу с таблицей читателей. Запись у входа в роутер, которую читали все шесть, содержит и фейки со сроком жизни один: они доходят до входа и умирают на роутере. Живая игрушка стоит дальше, за роутером, и их не видит.

Теперь второй вид читателя: правило из выпуска «multisplit: резать на части». Оно смотрит одно фиксированное место в пакете, там, где в обычной отправке нашего приветствия начинается имя: в нашем тесте заголовок TCP занимает тридцать два байта, и правило читает со сто двадцать девятого байта от его начала. Без стратегии в нашем тесте счётчик правила равен шести: приветствие и пять повторов клиента. Сервер не получил ничего.

С multisplit, fakedsplit, fakeddisorder, fakedsplit с pos равным host и hostfakesplit счётчик равен нулю, а сервер получил все двести пятьдесят байт.

Проверь себя. Правило не сработало на hostfakesplit и на fakedsplit с pos равным host, хотя «пакетный» там видит имя. Почему?

Настоящее имя лежит в начале своего пакета. «Пакетный» ищет по всему пакету и находит его. Правило смотрит на место девяносто седьмого байта данных пакета. В пакете с настоящим именем имя начинается с нулевого байта, а на девяносто седьмом лежат другие байты или данных там уже нет.

Правило с фиксированным местом Правило с одним фиксированным местом смотрит 15 байт на смещении 129 от начала заголовка TCP, то есть 32 байта заголовка плюс 97 байт данных, 1032 бита: оно срабатывает на все шесть пакетов приветствия без стратегии, по 302 байта, и сервер получает 0 байт, а при multisplit, fakedsplit, fakeddisorder, fakedsplit с pos равным host и hostfakesplit счётчик правила равен нулю и сервер получает все 250 байт; у hostfakesplit настоящий пакет с именем несёт только 15 байт данных, а у fakedsplit с pos равным host вторая часть в 153 байта начинается с имени, поэтому правило смотрит мимо имени; игрушки ищут фиксированные 15 байт, не проверяют MD5, сумму и номера и не имеют таймеров. правило с одним фиксированным местом смотрит 15 байт на смещении 97 данных IPTCP 32данные: 250 байт приветствияпакет без стратегии: 20 + 32 + 250 = 302 байта правило: @th,1032,120 = 129 байт от начала TCP = 32 + 97, длина 15 байт в обычной отправке имя лежит ровно там: правило находит его и останавливает соединение стратегиясчётчик правиласервер получил без стратегии6 пакетов0 байт multisplit0250 байт fakedsplit0250 байт fakeddisorder0250 байт fakedsplit:pos=host0250 байт hostfakesplit0250 байт шесть пакетов: приветствие и пять повторов клиента, по 302 байта проверь себя: почему правило не сработало там, где «пакетный» видит имя? hostfakesplit: настоящий пакет с именемимя097данных всего 15 байт, на проводе 67на смещении 97 ничего нет fakedsplit:pos=host: вторая настоящая частьимя097данных 153 байта, имя с нулевого байтана смещении 97 лежат другие байты границы игрушекищут фиксированные 15 байт, TLS и HTTP не разбираютдействие одно, выбросить: таймеров и предела буфера у них нетMD5, сумму и номера на правдоподобие не проверяют: «слепы все шесть» верно для таких читателейгде стоит настоящий инспектор относительно точки смерти фейка: неизвестно

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

Теперь границы наших игрушек. Они ищут фиксированные пятнадцать байт и не разбирают ни TLS, ни HTTP. Они выбрасывают пакет, а настоящее устройство могло бы сбросить соединение или замедлить его; у наших игрушек нет ни таймеров, ни предела буфера. Читатель, который проверяет MD5, сумму или правдоподобие номеров, был бы другой моделью. Такие игрушки мы строили в выпуске «Фейк и его условия»: каждая из них видела причину, по которой получатель выбросит фейк. Здесь мы их не запускали, поэтому «слепы все шесть» верно только для читателей, которые условие фейка не проверяют.

Итак. Положение читателя решает, увидит ли он фейк. Наши модели ничего не говорят о настоящем ТСПУ.

Код: fakedsplit, fakeddisorder и hostfakesplit

Вопрос сцены: как fakedsplit, fakeddisorder и hostfakesplit устроены в коде? Теперь, когда мы знаем, что искать, код читается быстро.

Игрушка, выдуманная. Карточка с рецептом из шести шагов: пустышка, настоящая половина, пустышка, и то же для второй половины. Код и есть эта карточка.

Функция получает два параметра, ctx и desync, как всякая стратегия. Дальше ворота: не TCP, не то направление, не то содержимое, и функция выходит. Ворота знакомы по выпуску «multisplit: резать на части».

Позиция. Первая строка берёт аргумент pos, а если его нет, строку «два». Вторая отдаёт её переводчику меток, и тот возвращает одно число по счёту Lua, с единицы. Если оно равно единице, перед первым байтом резать нечего: функция пишет «разрезать нельзя» и ничего не отправляет. Так pos равное нулю даёт целое приветствие.

Код fakedsplit: шесть отправок Код fakedsplit в zapret2 по настоящим строкам файла стратегий: метка pos читается строкой 840 и переводится в число строкой 841, настоящие части получают только условие tcp_ts_up, а фейки весь набор условий, шесть вызовов отправки идут по порядку, фейк 1 с байта 0 длиной 104, настоящая первая часть, фейк 1 ещё раз, фейк 2 с байта 104 длиной 146, настоящая вторая часть и фейк 2 ещё раз, и это ровно шесть пакетов нашего теста; перед каждым фейком стоит проверка ключа nofake с номером 1, 2, 3 или 4, в конце функция запоминает отправку частями и возвращает ответ выбросить оригинал, а с nodrop пропустить; fakeddisorder использует те же шесть кусков в другом порядке, сначала фейк второй части, и номера выключателей идут по новому порядку. код fakedsplit: настоящие строки файла lua/zapret-antidpi.lua 826function fakedsplit(ctx, desync)ворота: строки 827 до 839840local spos = desync.arg.pos or "2"аргумент pos, по умолчанию «2»841local pos = resolve_pos(data, desync.l7payload, spos)метка превращается в число Lua843if pos == 1 thenединица: до первого байта844DLOG("fakedsplit: split pos resolved to 0. cannot split.")pos=0 даёт целое приветствие850local opts_orig = {…fooling = {tcp_ts_up = desync.arg.tcp_ts_up}}настоящие: только tcp_ts_up851local opts_fake = {…fooling = desync.arg}фейки: весь набор условий856fake = pattern(fakepat,1,pos-1)узор длиной pos минус 1858if not desync.arg.nofake1 thenключ есть: фейка нет860if not rawsend_payload_segmented(desync,fake,0, opts_fake) then …фейк 1 на байты 0 до 103864part = string.sub(data,1,pos-1)до позиции, не включая её879if not rawsend_payload_segmented(desync,part,-seqovl, opts_orig) …настоящая часть 1882if not desync.arg.nofake2 then884if not rawsend_payload_segmented(desync,fake,0, opts_fake) then …фейк 1 ещё раз888fake = pattern(fakepat,pos,#data-pos+1)узор с фазы pos, на остаток889if not desync.arg.nofake3 then891if not rawsend_payload_segmented(desync,fake,pos-1, opts_fake) then …фейк 2 на байты 104 до 249895part = string.sub(data,pos)от позиции до конца897if not rawsend_payload_segmented(desync,part,pos-1, opts_orig) then …настоящая часть 2900if not desync.arg.nofake4 then902if not rawsend_payload_segmented(desync,fake,pos-1, opts_fake) then …фейк 2 ещё раз905replay_drop_set(desync)запоминает отправку частями906return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROPответ: выбросить оригинал шесть вызовов отправки: ровно шесть пакетов нашего теста 1фейк 1строка 860с 0, длина 104nofake1 · 858 2настоящая 1строка 879с 0, длина 104 3фейк 1строка 884с 0, длина 104nofake2 · 882 4фейк 2строка 891с 104, длина 146nofake3 · 889 5настоящая 2строка 897с 104, длина 146 6фейк 2строка 902с 104, длина 146nofake4 · 900 fakeddisorder: те же шесть кусков, порядок другойвыключатели идут в новом порядке фейк 2строка 961с 104, длина 146nofake1 · 962 настоящая 2строка 968с 104, длина 146 фейк 2строка 997с 104, длина 146nofake2 · 997 фейк 1строка 1003с 0, длина 104nofake3 · 1004 настоящая 1строка 1010с 0, длина 104 фейк 1строка 1015с 0, длина 104nofake4 · 1015 здесь nofake1 это первый фейк второй части; достаточно, чтобы ключ был: nofake1=0 тоже выключает

Две таблицы настроек. Первая для настоящих частей: из набора условий в ней только tcp_ts_up, условие про метку времени. Вторая для фейков: весь набор, и условия, и повторы, и испорченная сумма. Вот почему условие и repeats касаются только фейков.

Первая половина. Фейк первой части: функция pattern берёт узор с начала и режет на длину «позиция минус один»; он отправляется со смещением ноль. Настоящая первая часть: срез данных от первого байта до позиции, не включая её. Потом тот же фейк ещё раз.

Вторая половина. Фейк второй части берёт узор с фазы позиции и режет на остаток, затем настоящая вторая часть и фейк ещё раз. Шесть вызовов отправки: ровно шесть пакетов нашего теста. Перед каждым фейком стоит проверка ключа nofake; достаточно, чтобы ключ был, даже nofake равное нулю выключает фейк.

Конец, первое. Вызов запоминает, что сообщение уже отправлено частями; это нужно для длинных приветствий, которые программа собирала сама, и о нём говорит выпуск «Сборка и повторный проигрыш».

Конец, второе. Функция возвращает программе ответ, «вердикт»: выбросить оригинал, а с nodrop пропустить. Как программа сводит ответы нескольких экземпляров, расскажет выпуск «Lua внутри программы».

Fakeddisorder: те же шесть кусков, порядок другой. Фейк второй части, настоящая вторая, фейк второй, фейк первой, настоящая первая, фейк первой. Номера выключателей идут в новом порядке: nofake один это первый фейк второй части.

Главное отличие в порядке, второе в seqovl: здесь это метка, а в fakedsplit только число. Метка идёт к тому же переводчику, и полученное смещение становится длиной накладки. Если накладка не меньше разреза, её отменяют. Иначе по умолчанию перед второй частью кладутся нули, и пакет уходит на столько байт раньше. В нашем тесте с seqovl равным host накладка в девяносто семь байт, пакет в двести сорок три байта начинается со смещения семь, и сервер прочитал настоящее приветствие.

Накладка как метка и hostfakesplit Две особенности кода: в fakeddisorder накладка seqovl это метка, её переводят в число строкой 971, вычитают единицу и отменяют, если она не меньше разреза, так что при seqovl равном host получается 98 минус 1, то есть 97 нулевых байт перед второй частью, пакет в 243 байта со смещения 7, а при seqovl равном midsld 105 минус 1 равно 104, накладка не меньше разреза и отменяется, остаются шесть обычных пакетов; hostfakesplit строкой 721 просит диапазон имени по меткам host и endhost минус один, получает 98 и 112, это 15 знаков, и отправляет пять пакетов, часть до имени в 97 байт, двойник в 15 байт, настоящее имя, тот же двойник ещё раз и хвост в 138 байт, midhost принимается только внутри имени, от 99 до 112, а в disorder_after метка endhost отвергается, endhost плюс один принимается, и неизвестное слово даёт ошибку после первого фейка, а известное, но не найденное, только строку в журнале. fakeddisorder: накладка seqovl это метка, а не число 971seqovl = resolve_pos(data, desync.l7payload, desync.arg.seqovl)метка в число Lua973seqovl = seqovl - 1минус один: длина накладки974if seqovl>=(pos-1) thenне меньше разреза976seqovl = 0накладку отменяют986part = pattern(pat,1,seqovl)..partнули перед второй частью994if not rawsend_payload_segmented(desync,part,pos-1-seqovl, opts_orig) …пакет уходит раньше seqovl=hostresolve_pos = 98, 98 минус 1 = 97, 97 меньше 104: накладка 97 нулевых байт 97 нулей накладкинастоящая вторая часть, 146 байт07104250 пакет в 243 байта (146 + 97) со смещения 7; сервер прочитал настоящее приветствие, 250 байт проверь себяseqovl=midsld: что уйдёт в сеть? midsld даёт 105, минус 1 это 104: не меньше разреза, накладка отменена (974–976)шесть обычных пакетов: 146, 146, 146, 104, 104, 104 байт, как без seqovl hostfakesplit: имя ищется двумя неизменными метками 721local pos = resolve_range(data, …, "host,endhost-1", true)метки в коде: pos не читается734fakehost = genhost(pos[2]-pos[1]+1, desync.arg.host)двойник строится один раз746if midhost<=pos[1] or midhost>pos[2] thenmidhost вне имени: отказ776disorder_after_pos = resolve_pos(data, …=="" and "-1" or …)пустое значение: «-1»779if disorder_after_pos<=(pos[2]+1) thenне после имени: отказ диапазон {98, 112} по счёту Lua, 15 знаков; пять отправокдвойник один, отправлен дважды до имени97 Б, с 0строка 730 двойник15 Б, с 97строка 736 настоящее имя15 Б, с 97строка 764 двойник15 Б, с 97строка 769 хвост138 Б, с 112строка 796 midhost: позиции Lua внутри имени от 99 до 112 979899100101102103104105106107108109110111112113 зелёное принятокрасное отвергнуто 97 перед именем, 98 его начало (host), 113 это endhost: все три отвергнуты disorder_after:endhost (113) отвергнут, endhost+1 (114) принятпустое значение читается как последний байт midhost=method: слово есть, не найденов журнале строка, пять пакетовcannot resolve midhost marker midhost=foo: такого слова нетошибка после первого фейка, два пакетаbad marker : foo

Проверь себя. Fakeddisorder с pos равным midsld и seqovl равным midsld. Что уйдёт в сеть?

Накладка равна разрезу, значит её отменяют: шесть обычных пакетов, как без seqovl. Так и было в нашем тесте.

Теперь hostfakesplit. Одна строка просит у программы диапазон по двум меткам, host и endhost минус один, с признаком «строго»: если хоть один конец не нашёлся, диапазона нет. Прогон функций даёт на нашем приветствии девяносто восьмой и сто двенадцатый байт по счёту Lua, это пятнадцать знаков имени. Аргумент pos сюда не попадает: строка меток записана в самом коде.

Дальше пять отправок: часть до имени, двойник, настоящее имя, двойник ещё раз и часть после. Двойник строится один раз и уходит дважды, поэтому копии совпадают. Как он собирается, мы разобрали по проводу в предыдущей части.

Два необязательных ключа проверяются на место. Midhost должен лежать внутри имени, для нашего приветствия от девяносто девятого до сто двенадцатого по счёту Lua; иначе при включённой отладке в журнале строка, а имя остаётся целым. Disorder_after пустой читается как последний байт; метку endhost, сразу за именем, программа отвергает, а endhost плюс один принимает. Слово, которого программа не знает, даёт ошибку, как в fakedsplit.

Итак. Fakedsplit и fakeddisorder это шесть вызовов отправки и две таблицы настроек: настоящим частям почти ничего, фейкам всё. Fakeddisorder меняет порядок и превращает seqovl в метку. Hostfakesplit ищет имя двумя неизменными метками и проверяет midhost и disorder_after на место.

Код: почему список стал числом, и как программа выполняет пару стратегий

Вопрос сцены: как в коде текст «один, midsld» превращается в число один, и как программа выполняет пару стратегий?

Игрушка, выдуманная. Счётчик читает цифры слева направо и останавливается на первом знаке, который не цифра. «Двенадцать, потом сорок» он читает как двенадцать.

Метка приходит в переводчика resolve_pos, тот вызывает разборщик метки, и разборщик первым делом пробует прочитать всю строку как число.

Как текст метки становится числом Как в коде текст метки превращается в число: переводчик resolve_pos вызывает разборщик метки posmarker_parse, тот сначала пробует прочитать всю строку функцией parse_int16, которая принимает строку, только если первый знак плюс, минус или цифра, и отдаёт её стандартной функции atoi, а atoi читает цифры и молча останавливается на первом другом знаке, поэтому строка один, запятая, midsld становится единицей, а после прибавления единицы позицией 2 по счёту Lua, midsld плюс один, запятая, host даёт 106, потому что остаток читается как плюс один, а host не виден, midsld, запятая, host даёт ошибку плохая метка, потому что имя метки это текст до первого плюса или минуса и значит вся строка, а такого имени нет; fakedsplit и fakeddisorder зовут переводчика одной метки, multisplit и multidisorder переводчика списка, hostfakesplit переводчика диапазона из ровно двух меток. цепочка вызовов: от метки в аргументе до числа resolve_poslua.c, 3291–3320 posmarker_parseprotocol.c, 123–148 parse_int16helpers.c, 720–729 atoiстандартная функция Си 3310if (!posmarker_parse(smarker,&marker))lua.c: разбор метки3311luaL_error(L, "bad marker : '%s'", smarker);lua.c: «плохая метка»125if (parse_int16(s, &m->pos))protocol.c: вся строка числом136for (p = s; *p && *p != '+' && *p != '-'; p++);protocol.c: имя до плюса или минуса141if (m->marker==PM_INVALID) return false;protocol.c: такого имени нет722if (*p == '+' || *p == '-' || *p >= '0' && *p <= '9')helpers.c: первый знак724int i = atoi(p);helpers.c: читает цифры3317lua_pushinteger(L,pos+!bZeroBased);lua.c: плюс один: позиция Lua как читаются три строки 1,midsldatoi читает «1» и молча останавливается на запятой;остаток не виден, число 1, плюс один: позиция 2 midsld,hostпервый знак буква: parse_int16 отказывает; имя до плюса илиминуса это вся строка, такого имени нет: ошибка «плохая метка» midsld+1,hostимя midsld (105), остаток «+1,host» читается как плюс один,host не виден: 105 + 1 = 106 прочитано числомatoi остановилсяимя меткиимя, которого нетне видно прогон функций над нашим приветствием 1,midsld→ 2 2,midsld→ 3 -3,midsld→ 248 2.5→ 3 midsld+1,host→ 106 midsld,host→ ошибка кто какого переводчика зовёт fakedsplit, fakeddisorderresolve_posодна метка (строки 841, 946) multisplit, multidisorderresolve_multi_posсписок через запятую (500, 614) hostfakesplitresolve_rangeровно две метки (721)

Функция разбора числа принимает строку, только если первый знак плюс, минус или цифра, и отдаёт её стандартной функции языка Си atoi. Atoi читает цифры и останавливается на первом знаке, который цифрой не является. Всё, что после, она не видит и об этом не сообщает. Так «один, midsld» становится единицей.

Ещё примеры из прогона функций. «Два, запятая, midsld» даёт два. «Минус три, запятая, midsld» даёт минус три, то есть счёт от конца. «Два точка пять» даёт два, потому что точка не цифра.

Если первый знак не цифра, начинается второй путь. Имя метки это текст до первого плюса или минуса. В «midsld, host» ни плюса, ни минуса нет, значит именем считается вся строка вместе с запятой, а такого имени нет. Разборщик отвечает «не вышло», и переводчик останавливается с ошибкой «плохая метка».

А в «midsld плюс один, запятая, host» имя midsld, и остаток «плюс один, запятая, host» читается как плюс один: atoi остановится на запятой. Host уже не виден. Последняя строка переводчика прибавляет единицу, и получается позиция по счёту Lua.

Почему multisplit список принимает? Он зовёт переводчика списка, который режет строку по запятым и разбирает каждую метку отдельно, как в выпуске «multisplit: резать на части». А hostfakesplit зовёт переводчика диапазона: ему нужны ровно две метки, host и endhost минус один.

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

Пара стратегий внутри программы Как программа выполняет пару стратегий на одном пакете: экземпляры профиля идут по порядку записи и вызываются по имени строкой 1055, перед каждым вызовом заново записываются аргументы и имя экземпляра, а запись о пакете одна общая, поэтому счётчик идентификатора IP продолжается, и в паре fake и multisplit четыре пакета получили идентификаторы подряд, фейк в 680 байт, потом три настоящих куска в 1, 103 и 146 байт; ответы сводятся так, что если хоть один сказал выбросить, оригинал выбрасывается, а остальные экземпляры всё равно выполняются; если функция упала с ошибкой, цепочка для этого пакета обрывается, остальные экземпляры не запускаются и уходит оригинал, это следует из кода, а лабораторной пары с такой ошибкой не было; с nodrop седьмым пакетом уходит оригинал в 250 байт с тем же идентификатором, что у первого фейка, и сервер отвечает блоком, которым говорит, что этот кусок у него уже был. пара: fake, а после него multisplit на одном пакете одна общая запись о пакете (desync)счётчик идентификатора IP продолжается экземпляр fake_1_2без ответа: «пропустить» экземпляр multisplit_1_3возвращает «выбросить» перед каждым вызовом заново:аргументы, func, func_n,func_instance (строки 1064–1072) id IP 27076фейк, 680 Б id IP 27077настоящая, 1 Б id IP 27078настоящая, 103 Б id IP 27079настоящая, 146 Б вызов: desync.c, 1055; счётчик: zapret-lib.lua, 1098–1099; числа из прогона, в другом они другие первый пакет отправил fake_1_2, три следующих отправил multisplit_1_3 как сводятся ответы: если хоть один «выбросить», оригинал выбрасывается первыйвторойитог пропуститьпропуститьпропустить пропуститьвыброситьвыбросить выброситьпропуститьвыбросить наша пара: fake «пропустить»,multisplit «выбросить»: оригинал выброшеностальные экземпляры тоже выполняютсяdesync.c, 875–888; zapret-lib.lua, 182–198 если функция упала с ошибкой: цепочка для этого пакета обрывается 1076status = lua_pcall(params.L, 2, LUA_MULTRET, 0);1079if (status)ошибка в функции1081lua_dlog_error();1082goto err;выход из цикла экземпляров1142err:сюда ведёт goto err1143DLOG_ERR("desync ERROR. passing packet unmodified.\n");1145verdict = VERDICT_PASS;оригинал уходит целым так следует из кода; в лаборатории такой пары, где первый экземпляр падает, не было проверь себяfakedsplit с nodrop: что уйдёт в сеть? фейк 104 часть 104 фейк 104 фейк 146 часть 146 фейк 146 оригинал 250 седьмым уходит оригинал: «пропустить» его не выбрасывает; id IP тот же, что у первого фейкасервер ответил «жду 105», потом «жду 251» с блоком [1, 251): этот кусок уже был (дублирующий блок)

Ответы. Fake ничего не возвращает, multisplit возвращает «выбросить». Если хоть один сказал «выбросить», оригинал выбрасывается, а остальные экземпляры всё равно выполняются. Но если функция упала с ошибкой, как в ловушке списка, оставшиеся экземпляры для этого пакета не запускаются, и уходит оригинал. Для пары это значит: ошибка в первом экземпляре отменяет второй; так следует из кода, в лаборатории такой пары не было.

Проверь себя. Fakedsplit с nodrop: что уйдёт в сеть?

Шесть пакетов, а следом оригинальное приветствие: ответ «пропустить» оригинал не выбрасывает. В нашем тесте так и вышло, а сервер ответил на оригинал блоком, которым говорит: этот кусок у меня уже был.

Итак. Список превращается в число потому, что разбор числа читает цифры и молча останавливается. Пара работает, потому что программа выполняет экземпляры по порядку и выбрасывает оригинал, если так ответил хоть один.

Итог выпуска и что дальше

Остановимся и сведём всё, что мы узнали в этой части. Всё это в нашем тесте, на одном приёмнике, Linux, и в нашей игрушечной модели. О настоящем оборудовании мы по-прежнему ничего не знаем.

Первое. Две стратегии на одном пакете выполняются по порядку записи, и аргументы у каждой свои. Фейк впереди кладёт подделку перед данными, фейк в конце после них. Без условия фейк в паре ломает соединение, а с условием он в нашем тесте умирает рядом с четырьмя разрезающими стратегиями.

Второе. Pos в fakedsplit и fakeddisorder это одна метка: список с числа молча становится числом, список с имени и запятой даёт ошибку и целое приветствие. Hostfakesplit pos не читает, ipfrag не работает у всех трёх, repeats и badsum касаются только фейков.

Третье. Шесть игрушечных читателей. Разрез ослепляет «пакетного». Если имя целиком в одной настоящей части, «пакетный» и «склейщик» видят его во всех наших запусках. Слепота читателя не значит целость данных: без условия сервер получал нули.

Четвёртое. У каждого фейка своя работа: фейк до настоящей части ослепляет тех, кто верит первой записи, фейк после неё тех, кто верит последней.

Пятое. Положение читателя решает: фейк, который умер раньше, чем дошёл до читателя, ему не виден. А правило с одним местом и читатель, который ищет по всему пакету, это разные инспекторы.

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

Шпаргалка части: восемь строк Шпаргалка части из восьми строк с источником каждой: пары стратегий идут по порядку записи, у каждой свои аргументы, и с условием фейк умирает рядом с четырьмя разрезающими функциями; фейк без условия в паре с multisplit ломает соединение, и приложение получает 680 байт чужого приветствия; pos в fakedsplit и fakeddisorder это одна метка, список с числа становится числом, а с имени и запятой даёт ошибку и целое приветствие; pos у hostfakesplit не читается, ipfrag не работает у трёх функций, repeats и badsum касаются только фейков, seqovl словом у fakedsplit даёт ошибку после первого фейка; из шести читателей разрез ослепляет пакетного, целое имя видят пакетный и склейщик во всех наших запусках, а слепота читателя не значит целость данных; фейк до настоящей части против первый записал и строго по порядку, фейк после против последних записал; положение читателя решает, видит ли он фейк со сроком жизни 1, а правило с фиксированным местом не видит имя у hostfakesplit и fakedsplit с pos равным host; в коде шесть отправок, две таблицы настроек, диапазон имени, разбор метки и цикл экземпляров, где ошибка отменяет остальные. что мы теперь знаем: всё в нашем тесте и в игрушечной модели 1пары: экземпляры идут по порядку записи, у каждого свои аргументыс условием фейк умирает рядом с четырьмя разрезающими функцияминаш тест 2фейк без условия в паре с multisplit: соединение всталоприложение получило 680 байт чужого приветствиянаш тест 3pos у fakedsplit и fakeddisorder: одна меткас числа список становится числом; с имени и запятой: ошибканаш тестпо кодупрогон функций 4тихие места: pos у hostfakesplit не читается, ipfrag мёртв у трёхrepeats и badsum только у фейков; seqovl словом: ошибка после фейканаш тестпо коду 5шесть читателей: разрез ослепляет «пакетного»целое имя видят «пакетный» и «склейщик»; слепота не значит целостьнаша модель 6фейк до против «первый записал» и «строго по порядку»фейк после против «последних записал»наша модель 7положение читателя: срок жизни 1 до игрушки не доходитправило с одним местом не видит имя у hostfakesplit и pos=hostнаш тестнаша модель 8код: шесть отправок и две таблицы настроек; диапазон имениmidhost и disorder_after; число из списка; ошибка отменяет остальныепо кодупрогон функций о настоящем оборудовании мы по-прежнему ничего не знаем

Проверь себя. Вы хотите спрятать имя от «пакетного» и запускаете hostfakesplit без midhost. Получится?

Нет. Настоящее имя лежит целым в своём пакете, и «пакетный» находит его там. Чтобы спрятать имя от него, имя нужно разрезать: pos в fakedsplit, указывающий внутрь имени, или midhost в hostfakesplit.

Теперь о том, чего мы не знаем. Мы не знаем, как устроен настоящий инспектор: что он читает, где стоит, видит ли фейки и какую копию считает главной. Мы не знаем, как поведёт себя другой получатель: мы проверили только Linux, а Windows, BSD и встроенные системы нет. Мы не пробовали IPv6 и не запускали версию для Windows. И мы пробовали лишь три условия: опцию MD5, срок жизни один и испорченную сумму; остальные условия и их сочетания остались без запусков.

Чего мы не знаем и что дальше Проверка, спрячет ли hostfakesplit без midhost имя от пакетного читателя: нет, настоящее имя лежит целым в своём пакете в 15 байт и пакетный его находит, а с midhost равным midsld имя режется на 7 и 8 байт и пакетный слеп, затем три серые плашки с замками о том, чего мы не знаем, настоящий инспектор и ТСПУ, другие получатели, IPv6 и версия для Windows, и условия кроме MD5, срока жизни 1 и испорченной суммы; следующий выпуск называется «Фокусы рукопожатия» и разбирает приёмы вокруг начала соединения, до первого байта данных, срочный байт и ложное окно, а итог выпуска одной фразой такой: разрез прячет имя от читателя, который смотрит пакеты по одному, фейк с условием не доходит до приложения, а условие обязательно. проверь себя: спрячет ли hostfakesplit без midhost имя от «пакетного»? без midhostR97F15R15 имяF15R138видит midhost=midsldR97F15R7R8F15R138слеп R настоящая часть, F двойник, число это длина в байтах имя лежит целым в своём пакете: «пакетный» находит его; чтобы спрятать, имя нужно разрезать чего мы не знаем настоящий инспектори ТСПУ: что читает, где стоит,видит ли фейки, какую копиюсчитает главной другие получателине Linux 6.18: Windows,BSD, встроенные системы;IPv6; версия для Windows другие условияпробовали только MD5, срокжизни 1 и испорченную сумму;остальные условия не запускали следующий выпуск «Фокусы рукопожатия»вокруг начала соединения: до первого байта данных, срочный байт, ложное окнодо сих пор мы работали с данными, когда соединение уже установлено весь выпуск в одной фразе Разрез прячет имя от читателя, который смотрит пакеты по одному;фейк с условием не доходит до приложения;три функции склеивают это в серию, а условие обязательно:без него сервер в нашем тесте принимает фейк всерьёз. Всё сказанное про эффект относится к нашему приёмнику и нашим игрушкам.

Следующий выпуск называется «Фокусы рукопожатия». До сих пор мы работали с данными, когда соединение уже установлено. Теперь посмотрим на приёмы вокруг самого начала соединения: что можно сделать до первого байта данных, срочный байт и ложное окно.

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

См. также


🤖 Эти статьи открыты — можно обучать на них ИИ

При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: исходник этой заметки · скачать весь репозиторий одним zip-архивом.