Some checks failed
Published content check / validate (push) Failing after 7s
Полный текст выпусков с анимированными SVG-схемами: «Резать и подделывать вместе». Список видео в Zapret2/Zapret2.md обновлён. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1093 lines
184 KiB
Markdown
Executable file
1093 lines
184 KiB
Markdown
Executable file
---
|
||
title: "Видео 8. Резать и подделывать вместе"
|
||
date: 2026-10-26
|
||
tags:
|
||
- zapret2
|
||
- видео
|
||
- сценарий
|
||
- fakedsplit
|
||
- fakeddisorder
|
||
- hostfakesplit
|
||
aliases:
|
||
- "Видео 8"
|
||
description: "Видео 8 серии о Zapret 2: fakedsplit, fakeddisorder, hostfakesplit: разрез и подделка в одной стратегии, с анимированными схемами."
|
||
---
|
||
|
||
> [!info] О чём заметка
|
||
> Это полный текст видео номер 8 из серии о том, как работает [[Zapret2/Zapret2|Zapret 2]], разбитый по сценам, с анимированными схемами. Каждую сцену можно читать отдельно.
|
||
|
||
> [!tip] Как читать пометки
|
||
> **«В нашем тесте»** значит настоящий запуск в лаборатории проекта: клиент, роутер, сервер. **«По коду»** значит, что мы прочитали исходники, но не запускали. **«По общим сведениям»** значит, что это вне нашего кода и лаборатории. О настоящем оборудовании ТСПУ мы ничего не утверждаем: наш «инспектор» это модель.
|
||
|
||
|
||
## Повтор и вопрос: резать и подделывать в одной серии
|
||
|
||
Добро пожаловать в выпуск «Резать и подделывать вместе». Сначала короткий повтор, чтобы эту часть можно было смотреть отдельно от остальных.
|
||
|
||
О настоящем оборудовании на пути пакетов здесь нет ни слова: мы не знаем, как оно устроено. У нас два участника, и оба наши: игрушечный инспектор в роутере лаборатории и сервер с Linux.
|
||
|
||
Слово «сработало» в этом выпуске значит одно: приём обошёл нашу игрушку, а сервер получил настоящие данные. Каждый вывод об эффекте относится только к этим двоим.
|
||
|
||
Теперь четыре договорённости, они повторяются из выпуска в выпуск. «В нашем тесте» значит: мы запустили настоящую программу в нашей лаборатории, с клиентом, роутером и сервером, и посмотрели, что ушло на провод. «По общим сведениям» значит: это общее знание, а не наш опыт и не наш код. «По счёту» значит: арифметика на бумаге, такого запуска у нас не было. «Прогон функций» значит: мы запустили настоящие функции программы без сети и подали им числа. И ещё одно выражение: отладочный журнал. Это подробная запись самой программы о каждом пакете; мы включаем её во всех опытах с программой и читаем из неё найденные позиции и отправленные пакеты.
|
||
|
||
Сервер у нас на Linux, и в нём два слоя. Ядро принимает пакеты, может отвергнуть какие-то из них и записывает это в свои счётчики. Приложение получает только то, что ядро приняло, и запоминает, сколько байт и какие именно к нему пришли. Когда мы скажем «ядро сервера выбросило», речь о первом слое, а когда «приложение прочитало», о втором.
|
||
|
||
Теперь о словах про игрушки. Игрушечный инспектор из выпуска «Что видит наблюдатель» это правило в роутере: оно сравнивает пятнадцать байт имени на одном и том же месте каждого пакета и ничего не помнит. Читатели это другие наши игрушки: они читают запись пакетов, каждый по своему правилу, и в выпуске «Перемешать: disorder» их было пятеро. Нам пока нужны двое. «Пакетный» ищет имя в каждом пакете отдельно, но по всему пакету, а не на одном месте. «Склейщик» склеивает данные в порядке прихода. Остальных троих назовём, когда дойдём до таблицы. «Видит» значит: читатель нашёл имя, и приём его не обманул. «Слеп» значит: имя не нашлось, и для нас это хороший исход.
|
||
|
||
Первое напоминание, из выпусков «Где резать: метки» и «multisplit: резать на части». Приветствие, первое сообщение защищённого соединения, занимает в нашей лаборатории двести пятьдесят байт, и имя сайта лежит в нём с девяносто седьмого байта по сто одиннадцатый, считая с нуля. Стратегия multisplit с меткой midsld режет приветствие посередине слова example: уходят два пакета, сто четыре байта и сто сорок шесть.
|
||
|
||
Что из этого получилось, посмотрим на двух опытах нашей лаборатории. Без разреза игрушечный инспектор, который смотрит в одно и то же место каждого пакета, находит его в первом же пакете, и сервер не получает ни одного байта. С разрезом инспектор имени не находит, и сервер получает все двести пятьдесят.
|
||
|
||
![[wiki-anim-video08-s01-cut-and-two-runs.svg|Разрез и правило игрушки]]
|
||
|
||
Проверь себя. Есть читатель нашей модели, который склеивает пакеты по порядку прихода. Увидит ли он имя после такого разреза?
|
||
|
||
Увидит: две части идут одна за другой, и в склеенном потоке имя снова целое. Такие читатели нам встречались в выпусках «multisplit: резать на части» и «Перемешать: disorder». Значит, из наших читателей разрез обманывает только пакетного, того, кто разбирает каждый пакет отдельно. Это слабое место разреза, и его надо назвать честно.
|
||
|
||
![[wiki-anim-video08-s01-readers-after-cut.svg|Кто видит имя после разреза]]
|
||
|
||
Второе напоминание, из выпуска «Фейк и его условия». Фейк это пакет, который программа сама вставляет рядом с настоящим. Если у фейка нет условия, из-за которого получатель его не примет, наш сервер на Linux принимает его всерьёз, и настоящие данные теряются. Условий в том выпуске было семь, а сегодня хватит трёх самых простых: опция эм-дэ-пять, срок жизни один и испорченная контрольная сумма. В программе такие настройки называются fooling. В выпуске «Фейк и его условия» мы звали их условиями подделки, а сегодня скажем коротко: условие. Это не то условие, которое отбирает пакеты для профиля, как в выпуске «Читаем командную строку zapret2». Здесь условие это намеренный дефект самого фейка: из-за него фейк либо умирает по дороге, либо сервер сам его выбрасывает.
|
||
|
||
Вопрос выпуска: что будет, если сделать и то и другое в одной серии? Какие пакеты уйдут в сеть, что ответит сервер и какие читатели нашей модели ослепнут? Функций, которые это делают, три. Первая называется «разрез с фейками», по-латински fakedsplit, с неё и начнём.
|
||
|
||
План такой. Сначала идём по проводу, пакет за пакетом: первый запуск, что лежит в фейке, как он умирает и что отвечает сервер. Потом смотрим, что будет без условия, и как выключать фейки по одному. Что каждый фейк даёт против нашей игрушки, увидим позже, когда дойдём до читателей. Код функции откроем ближе к концу выпуска, когда будем знать, что в нём искать.
|
||
|
||
Итак. Разрез прячет имя от пакетного читателя, а фейк с условием умирает по дороге. Остаётся выяснить, что получится, если взять оба приёма сразу, и что при этом получит наш сервер. Начинаем с первого запуска fakedsplit.
|
||
|
||
|
||
## Первый запуск: шесть пакетов на одно приветствие
|
||
|
||
Вопрос сцены: что именно уходит в сеть, когда fakedsplit отрабатывает на нашем приветствии? Сначала идея, потом настоящий запуск, потом пакеты по одному.
|
||
|
||
Игрушка, выдуманная. Книга на двести пятьдесят страниц разрезана на две пачки: страницы с первой по сто четвёртую и со ста пятой по двести пятидесятую. Перед каждой пачкой и после неё курьер кладёт стопку чистых листов с теми же номерами страниц. Различается только то, что на листах.
|
||
|
||
Теперь настоящая строка запуска, по частям. Первая часть, фильтр вида данных: действуем только на пакет с приветствием, остальные не трогаем.
|
||
|
||
Вторая: вызов fakedsplit, наш «разрез с фейками». Он режет данные в одном месте, как multisplit, и добавляет фейки вокруг обеих частей.
|
||
|
||
К нему аргумент pos со значением midsld. Эта метка нам знакома: середина слова example, байт сто четыре.
|
||
|
||
Третья: условие эм-дэ-пять, в строке оно пишется «тэ-цэ-пэ, подчёркивание, эм-дэ-пять». Оно вешается на фейки как лишняя опция, настоящие части идут без неё, и наш сервер такой фейк выбросит. Как именно, посмотрим в следующей сцене. Сейчас читайте так: «фейки умрут».
|
||
|
||
Почему настоящие части идут без этой опции, увидим в коде в конце выпуска: у функции две таблицы настроек, одна для настоящих частей, другая для фейков.
|
||
|
||
Что сделала программа, видно в отладочном журнале нашего теста. Сначала найденная позиция: сто четыре. Потом шесть строк отправки, по строке на каждый пакет; их мы сейчас пройдём по одному. Последняя строка: оригинальное приветствие выброшено, как и в multisplit.
|
||
|
||
![[wiki-anim-video08-s02-command-and-log.svg|Команда и журнал первого запуска]]
|
||
|
||
Теперь то же на проводе клиента, пакет за пакетом. Номера относительные, как в выпуске про multisplit: первый байт данных имеет номер один. Первый пакет: фейк первой части, номер один, сто четыре байта, внутри нули.
|
||
|
||
Второй пакет: настоящая первая часть. Номер тот же, один, длина та же, сто четыре, но внутри начало настоящего приветствия.
|
||
|
||
Третий: снова фейк первой части, номер один, сто четыре байта.
|
||
|
||
Четвёртый: фейк второй части. Номер сто пять, потому что один плюс сто четыре. Длина сто сорок шесть: от конца первой части до конца приветствия.
|
||
|
||
Пятый: настоящая вторая часть. Номер сто пять, длина сто сорок шесть, внутри «mple точка com».
|
||
|
||
Шестой: фейк второй части ещё раз, номер сто пять, сто сорок шесть байт.
|
||
|
||
Главное наблюдение. Каждый фейк стоит на тех же номерах и имеет ту же длину, что настоящая часть рядом. Три пакета с номером один, три с номером сто пять; различается только содержимое. Сто пять плюс сто сорок шесть дают двести пятьдесят один: это следующий номер после всех данных приветствия. Фейки границу не двигают, они лежат поверх тех же байтов. Это верно для нашего приветствия; дальше в этой части встретим случай, где длины разойдутся.
|
||
|
||
![[wiki-anim-video08-s02-six-packets-ladder.svg|Шесть пакетов на проводе клиента]]
|
||
|
||
Проверь себя. Допустим, первая часть была бы не сто четыре байта, а пятьдесят. Какой номер у второй половины и сколько таких пакетов?
|
||
|
||
Один плюс пятьдесят, пятьдесят один. Пакетов три, и у каждого длина двести: двести пятьдесят минус пятьдесят. Это по счёту, такого запуска мы не делали.
|
||
|
||
Итак. Одна строка, один разрез, шесть пакетов: фейк, настоящая, фейк, потом снова фейк, настоящая, фейк. Каждый фейк лежит на тех же номерах и той же длины, что настоящая часть рядом. Что внутри фейка и как он умирает, расскажет следующая сцена.
|
||
|
||
|
||
## Что лежит в фейке и как он умирает
|
||
|
||
Вопрос сцены: что лежит в фейке, и почему сервер его не принимает?
|
||
|
||
Игрушка, выдуманная. Подложное письмо: чистый лист в конверте. Погибнуть оно может двумя способами. На конверте печать, которую адресат не признаёт: письмо доехало, но не принято. Или марка, годная на один перегон: письмо погибает в пути.
|
||
|
||
Сначала лист. В выпуске «Фейк и его условия» у стратегии fake по умолчанию лежала заготовка приветствия на шестьсот восемьдесят байт. У fakedsplit другое умолчание: нули, а длину задаёт разрез. В нашем запуске первый фейк это сто четыре нуля, второй сто сорок шесть.
|
||
|
||
Чем заполнить фейк, можно попросить аргументом pattern. Возьмём игрушечный узор из трёх букв: а, бэ, цэ. В нашем тесте первый фейк начинается так: а, бэ, цэ, а, бэ, цэ, и дальше по кругу. Второй начинается с цэ, потом а, бэ: в первых ста четырёх буквах тридцать четыре полных узора и ещё две буквы, следующая третья. Значит, оба фейка вместе это один бесконечный текст, разрезанный там же, где данные.
|
||
|
||
Узором может быть и готовая заготовка приветствия: тогда в нашем тесте фейк начинается с заголовка записи TLS. Но это только лист. Дойдёт ли письмо, решает не лист, а условие.
|
||
|
||
![[wiki-anim-video08-s03-fake-contents.svg|Что лежит в фейке]]
|
||
|
||
Теперь как фейк умирает. Из условий прошлого выпуска берём три самых простых, и здесь мы только называем, что происходит с пакетом. Первое: эм-дэ-пять, наш запуск. Все четыре фейка доходят до сервера, и его ядро их выбрасывает: счётчик «подпись, которой не ждали» равен четырём, по одному на фейк.
|
||
|
||
Второе: срок жизни один. Роутер получает фейк, вычитает единицу, получает ноль, выбрасывает пакет и отправляет клиенту сообщение ICMP «время вышло». В нашем тесте таких сообщений на клиенте четыре, а на выходе из роутера и на сервере видны только две настоящие части.
|
||
|
||
Третье: испорченная контрольная сумма. Фейки доходят до сетевой карты сервера, и ядро их выбрасывает: счётчик ошибок контрольной суммы равен четырём.
|
||
|
||
Это в нашем тесте. По общим сведениям, именно по этим причинам стек Linux выбрасывает такие пакеты; другие системы мы не проверяли.
|
||
|
||
Теперь заголовок. У настоящей части заголовок TCP занимает тридцать два байта: двадцать основных и двенадцать на опции. Опция эм-дэ-пять добавляет ещё восемнадцать. Двенадцать плюс восемнадцать дают тридцать, а опции, по общим сведениям, выравниваются до кратного четырём, поэтому тридцать два. Заголовок TCP у фейка стал пятьдесят два байта: на двадцать длиннее. Запомните эти двадцать байт, они понадобятся в конце части.
|
||
|
||
Отсюда размер пакета целиком. Настоящая первая часть: двадцать байт заголовка IP, тридцать два заголовка TCP и сто четыре данных, всего сто пятьдесят шесть, мы считали это в выпуске про multisplit. У фейка той же части на те же двадцать байт больше: сто семьдесят шесть.
|
||
|
||
![[wiki-anim-video08-s03-fake-death-lanes.svg|Где и как умирает фейк]]
|
||
|
||
Проверь себя. Два запуска: в одном условие эм-дэ-пять, в другом срок жизни один. В каком счётчик «подпись, которой не ждали» вырастет, на сколько, и сколько пакетов с данными дойдёт до сервера во втором запуске?
|
||
|
||
Только в первом, на четыре, по одному на фейк. Во втором счётчик останется нулём: фейки умерли в роутере, и до сервера дошли два пакета с данными, настоящие части.
|
||
|
||
Итак. По умолчанию фейк состоит из нулей, а при желании из узора, разрезанного там же, где данные. Из трёх простых условий два убивают фейк на самом сервере, эм-дэ-пять и испорченная сумма, а третье, срок жизни один, в роутере. Что ответит сервер на всю серию, посмотрим дальше.
|
||
|
||
|
||
## Что отвечает сервер на шесть пакетов
|
||
|
||
Вопрос сцены: что скажет сервер на эти шесть пакетов и что прочитает его приложение?
|
||
|
||
Игрушка, выдуманная. Помните кладовщика из выпуска про disorder? У него один вопрос: какая буква нужна следующей. Письма с печатью, которую он не признаёт, кладовщик выбрасывает молча и ничего не отвечает.
|
||
|
||
Теперь запись нашего теста, пакет за пакетом, в порядке отправки. Первый пакет, фейк первой части. Ответа нет: сервер выбросил его молча.
|
||
|
||
Второй пакет, настоящая первая часть. На него сервер ответил подтверждением сто пять: жду байт номер сто пять. Следом отправил свои четырнадцать байт ответа. Лабораторный сервер отвечает, как только получил первые данные, не дожидаясь всего приветствия.
|
||
|
||
Третий пакет, повтор фейка первой части. Ответа нет.
|
||
|
||
Четвёртый, фейк второй части. У него номер сто пять, ровно тот, которого ждёт сервер. Если бы сервер принял этот пакет, подтверждение подскочило бы вперёд. Подтверждения нет.
|
||
|
||
Пятый, настоящая вторая часть, и шестой, повтор фейка второй части. Отдельного подтверждения нет ни на тот, ни на другой. По общим сведениям, получатель не обязан подтверждать каждый пакет сразу и может отложить подтверждение до своего следующего пакета; почему так вышло в нашем тесте, мы отдельно не проверяли.
|
||
|
||
Следующее число от сервера, двести пятьдесят два, приходит уже в пакете закрытия. Двести пятьдесят один плюс один, потому что, по общим сведениям, флаг закрытия занимает один номер.
|
||
|
||
Сравним с обычным разрезом: multisplit с той же меткой, без единого фейка. Сервер в нашем тесте ответил так же: сто пять, четырнадцать байт ответа, потом двести пятьдесят два при закрытии. По ответам сервера серия из шести пакетов неотличима от обычного разреза из двух. Это в нашем тесте и на одном получателе, Linux.
|
||
|
||
![[wiki-anim-video08-s04-server-answers-ladder.svg|Что отвечает сервер на шесть пакетов]]
|
||
|
||
Теперь скажем, где в нашей лаборатории стоят игрушки. В выпуске «Фейк и его условия» инспектор стоял на входе в роутер, раньше проверки срока жизни, и видел даже фейк со сроком жизни один. В этом выпуске мест два. Запись на входе в роутер содержит всё, что туда дошло, и фейки со сроком жизни один тоже: по этой записи работают читатели. А игрушка, которая стоит внутри роутера на пути вперёд, уже после проверки срока жизни, такой фейк не увидит: роутер выбросит его раньше. Слова «на пересылке роутера» значат именно это второе место.
|
||
|
||
А что на пути? У нас четыре точки захвата: на клиенте, на входе в роутер, на выходе из роутера и на сетевой карте сервера. В запуске с эм-дэ-пять все шесть пакетов видны во всех четырёх точках, и игрушечный инспектор, который стоит на пересылке роутера, увидел бы и фейки, и настоящие части. В запуске со сроком жизни один фейки видны только на клиенте и на входе в роутер, а до пересылки не доходят: их выбрасывает сам роутер.
|
||
|
||
Теперь приложение на сервере. Оно прочитало двести пятьдесят байт, они совпали с оригиналом, а сервер нашёл в приветствии имя www.example.com. Сколькими чтениями приложение это получило, мы не называем: границы чтений зависят от времени.
|
||
|
||
![[wiki-anim-video08-s04-capture-points-and-app.svg|Где фейк виден на пути]]
|
||
|
||
Проверь себя. Сервер на фейки молчит. Значит ли это, что фейки до сервера не дошли?
|
||
|
||
Нет. С условием эм-дэ-пять фейки дошли до сетевой карты сервера, и ядро выбросило их молча: счётчик насчитал четыре. Тишина ничего не доказывает, доказывает захват или счётчик. А фейки со сроком жизни один до сервера действительно не дошли: их остановил роутер. Ряд ответов сервера при этом получился тот же, и так же вышло с испорченной суммой.
|
||
|
||
Итак. Сервер отвечает один раз, подтверждением сто пять, после настоящей первой части, и молчит на все фейки. Приложение читает оригинал целиком. Для сервера серия неотличима от обычного разреза, а игрушечный инспектор на пересылке роутера в запуске с эм-дэ-пять видел бы все шесть пакетов.
|
||
|
||
|
||
## Где упадёт разрез: позиция и края
|
||
|
||
Вопрос сцены: где падает разрез у fakedsplit и что бывает на краях?
|
||
|
||
Игрушка, выдуманная. Пачка листов и ножницы. «Режь перед тридцатой страницей» даёт двадцать девять листов и остальное. «Режь перед самой первой страницей» даёт пустую пачку и целую: резать нечего.
|
||
|
||
Из выпуска «Где резать: метки» мы знаем: позиция это номер байта с нуля, разрез стоит перед этим байтом. Одна оговорка про fakedsplit: в аргументе pos у него одна метка, а не список, как у multisplit. Чем это грозит, покажем дальше в этом выпуске, а пока пишем по одной метке.
|
||
|
||
Первый опыт: аргумент pos вообще не задан. По умолчанию у fakedsplit позиция два, разрез после двух байтов. Части в два байта и в двести сорок восемь, номер второй части три, и всё имя целиком лежит во второй. Сервер в нашем тесте ответил: жду байт три.
|
||
|
||
Второй: pos равно host. Части в девяносто семь байт и в сто пятьдесят три. Вторая часть начинается с самого имени, её номер девяносто восемь.
|
||
|
||
Зачем нам эти два опыта? Посмотрите, где лежит имя. И при позиции по умолчанию, и при host оно целиком в одной настоящей части.
|
||
|
||
При host в нашей игрушечной модели пакетный читатель находит имя во второй настоящей части, что бы ни делали фейки. При позиции по умолчанию имя тоже целиком в одной части, но это по счёту: отдельной модели для него мы не запускали. Чтобы спрятать имя и от пакетного читателя, разрез надо ставить внутрь имени, как midsld.
|
||
|
||
![[wiki-anim-video08-s05-cut-positions.svg|Где падает разрез]]
|
||
|
||
Теперь края. Позиция ноль значит «режь перед самым первым байтом»: в первой части не осталось бы ничего. В коде это одна проверка: внутри функции позиции считаются с единицы, и если получилась единица, перед первым байтом резать нечего, и функция выходит. В журнале строка «не могу разрезать», сама функция ничего не отправляет, и оригинальное приветствие уходит целым.
|
||
|
||
Позиция девятьсот девяносто девять лежит за концом приветствия. Функция не может её найти, пишет «не могу найти позицию» и тоже ничего не делает. В нашем тесте в обоих случаях на проводе один пакет в двести пятьдесят байт, и сервер читает приветствие без изменений.
|
||
|
||
Это важный урок: стратегия может молча не сработать. Строки журнала видны только при отладке, а приветствие уходит целым, как будто стратегии нет.
|
||
|
||
Позиция один режет после одного байта: части в один байт и в двести сорок девять.
|
||
|
||
А резать на самом краю тоже можно: позиции двести сорок девять и минус один в прогоне функций дают части в двести сорок девять байт и в один. В лаборатории такого опыта у нас нет.
|
||
|
||
Проверь себя. Позиция host минус один. Какие длины у частей и какой номер у второй?
|
||
|
||
Первая часть девяносто шесть байт, вторая сто пятьдесят четыре. Номер второй: один плюс девяносто шесть, девяносто семь. Вторая часть начинается на один байт раньше имени. В нашем тесте на проводе именно такие длины.
|
||
|
||
![[wiki-anim-video08-s05-edges-and-silent-cases.svg|Края разреза и молчаливые случаи]]
|
||
|
||
Итак. Разрез задаёт аргумент pos, это одна метка. По умолчанию это два байта, и имя целиком лежит во второй части. В нашем тесте ноль и значение за концом приветствия молча отключают стратегию: приветствие уходит целым.
|
||
|
||
|
||
## Без условия: фейки побеждают
|
||
|
||
Вопрос сцены: что будет, если забыть условие?
|
||
|
||
Игрушка, выдуманная. Кладовщик кладёт на каждое место полки первую пришедшую стопку, а всё, что приходит потом на то же место, называет дублем. Если первой пришла стопка чистых листов, на полке лежит чистая бумага, как бы ни выглядела настоящая.
|
||
|
||
Теперь настоящий запуск, тот же самый, но без эм-дэ-пять. Шесть пакетов те же по номерам и длинам. Только у фейков теперь нет лишней опции, срок жизни обычный и контрольная сумма верная: для нашего сервера это самые обычные пакеты.
|
||
|
||
Читаем ответы сервера по порядку, пакет за пакетом. Первый пакет, фейк первой части. Ответ: сто пять. Сервер принял сто четыре нулевых байта за первую часть приветствия.
|
||
|
||
Второй пакет, настоящая первая часть. Ответ снова сто пять, и к нему блок: байты с первого по сто четвёртый. Это дублирующий блок, он значит: «такие байты у меня уже лежат». Настоящая часть пришла второй и оказалась повтором. Третий пакет, повтор фейка первой части, получает тот же ответ: сто пять и тот же блок.
|
||
|
||
Четвёртый, фейк второй части. Ответ двести пятьдесят один: сервер считает, что приветствие получено целиком, хотя настоящей второй части ещё не видел.
|
||
|
||
Пятый, настоящая вторая часть, и шестой, последний фейк. Оба с ответом двести пятьдесят один и блоком: байты со ста пятого по двести пятидесятый. Опять повторы.
|
||
|
||
Счётчик ядра сервера насчитал ровно четыре дублирующих ответа, по одному на пакеты два, три, пять и шесть. А счётчики эм-дэ-пять и контрольной суммы остались нулевыми: по этим двум причинам ядро не выбросило ничего.
|
||
|
||
![[wiki-anim-video08-s06-answers-without-condition.svg|Запуск без условия]]
|
||
|
||
Что прочитало приложение? Двести пятьдесят байт, и все нулевые. Не приветствие и не имя сайта.
|
||
|
||
Похожую картину мы видели в выпуске «Фейк и его условия»: запуск без условия тоже кончился тем, что сервер принял фейк за данные. Там фейк был длиннее приветствия, сервер подтвердил шестьсот восемьдесят один, а клиент не получил ответа. Здесь фейки лежат на тех же номерах, подтверждения не выходят за отправленное, соединение живёт и закрывается обычным образом, но данные нулевые.
|
||
|
||
Это в нашем тесте. По общим сведениям, Linux оставляет первую копию диапазона байтов, и здесь мы видим это своими глазами; как поведёт себя другая система, мы не проверяли. Вывод для fakedsplit: без условия имя пропадает не только у инспектора, но и у сервера, который получает нули. Значит, приём не «сработал» в нашем смысле: он портит данные.
|
||
|
||
И ещё одна оговорка про нашу игрушечную модель. Читатель «первый записал» в этом запуске имени не находит: он слеп. Но сервер получил нули. Слепой читатель и испорченные данные это разные вещи, и важно не путать их.
|
||
|
||
Проверь себя. Посмотрите на ответы сервера в запуске с условием и в запуске без него. В каком были дублирующие блоки и сколько?
|
||
|
||
Без условия, четыре. С условием блоков нет вовсе: сервер выбросил фейки молча. Дублирующий блок это ответ «такие байты у меня уже лежат»: пришла вторая копия места, которое уже занято.
|
||
|
||
![[wiki-anim-video08-s06-app-zeros-blind-reader.svg|Нули в приложении]]
|
||
|
||
Итак. Без условия фейки обычные пакеты, наш сервер принимает первую копию каждого места, и приложение получает нули. В нашем тесте условие в fakedsplit обязательно: без него стратегия портит собственные данные.
|
||
|
||
|
||
## Четыре фейка поодиночке
|
||
|
||
Вопрос сцены: нужны ли все четыре фейка, и что будет, если убрать один?
|
||
|
||
Игрушка, выдуманная. Две настоящие пачки и четыре пустышки вокруг них: две перед пачками и две после. Пронумеруем пустышки по порядку отправки: первая перед первой настоящей пачкой, вторая после неё, третья перед второй настоящей пачкой, четвёртая после неё.
|
||
|
||
Теперь настоящие выключатели: nofake один, два, три и четыре. Номер в имени это номер фейка по порядку отправки. Ключ работает как рычажок: есть ключ значит убрать, а какое у него значение, не важно. Даже ноль считается: в прогоне функций nofake один равно нулю тоже убирает фейк.
|
||
|
||
Почему так, видно в коде. Перед отправкой каждого фейка стоит проверка «если у аргументов нет ключа nofake с таким номером»: перед первым фейком с единицей, перед вторым с двойкой, перед третьим с тройкой, перед четвёртым с четвёркой. Проверяется только наличие ключа, а в Lua ложными считаются лишь nil и false, поэтому ноль тоже выключает. Нумерация по порядку отправки это просто порядок строк в функции.
|
||
|
||
![[wiki-anim-video08-s07-four-fakes-switches.svg|Четыре фейка, четыре выключателя]]
|
||
|
||
Выключаем первый фейк, тот, что шёл перед первой настоящей частью. На проводе нашего теста пять пакетов: настоящая первая часть идёт первой, потом фейк первой части, фейк второй части, настоящая вторая часть и фейк второй.
|
||
|
||
Выключаем второй, тот, что шёл после первой настоящей части. Пять пакетов: фейк первой части, настоящая первая часть, потом сразу фейк второй, настоящая вторая и ещё фейк второй. Фейка первой части после настоящей нет.
|
||
|
||
Выключаем третий, тот, что шёл перед второй настоящей частью. Фейк первой части, настоящая первая, снова фейк первой части, и дальше сразу настоящая вторая часть и фейк после неё. Перед второй настоящей частью фейка нет.
|
||
|
||
Выключаем четвёртый, последний. Фейк первой части, настоящая, фейк, фейк второй части, и настоящая вторая часть замыкает серию. После неё фейка нет.
|
||
|
||
А если выключить все четыре? Остаются две настоящие части: сто четыре байта с номером один и сто сорок шесть с номером сто пять. Это в точности то, что уходит от обычного multisplit с той же меткой. Такой запуск называется fakedsplit, но фейков не посылает. При любых выключателях настоящие части остаются на месте: выключатели трогают только фейки.
|
||
|
||
Во всех пяти запусках приложение сервера в нашем тесте получило оригинал целиком. Зачем нужен каждый из четырёх фейков, зависит от читателя: об этом в части про игрушечных читателей, где мы будем выключать их по очереди и смотреть, кто прозреет.
|
||
|
||
Проверь себя. Выключаем первый и третий фейки одновременно. Какие пакеты уйдут и в каком порядке?
|
||
|
||
Настоящая первая часть, фейк первой части, настоящая вторая часть, фейк второй части. То есть остались только фейки, которые идут после настоящих частей. В нашем тесте на проводе именно так.
|
||
|
||
![[wiki-anim-video08-s07-five-runs-switched-off.svg|Пять запусков с выключателями]]
|
||
|
||
Итак. У fakedsplit четыре фейка, пронумерованные по порядку отправки, и четыре выключателя nofake. Убрав все четыре, получаем обычный разрез на две части. Что каждый фейк даёт, покажут игрушечные читатели.
|
||
|
||
|
||
## Накладка числом, nodrop, повторы и номера пакетов
|
||
|
||
Вопрос сцены: что делают остальные настройки fakedsplit?
|
||
|
||
Игрушка, выдуманная. Перед первой пачкой подшиты пять лишних листов с номерами раньше первой страницы. Получатель знает, что в книге таких страниц нет, и откладывает их в сторону.
|
||
|
||
Это накладка, seqovl, она знакома по выпуску про multisplit. В fakedsplit она относится к первой настоящей части и записывается только числом. Запуск с seqovl равно пять: первая настоящая часть выросла на пять нулевых байт, сто девять байт вместо ста четырёх, и начинается она на пять номеров раньше. Один минус пять, минус четыре.
|
||
|
||
Сервер в нашем тесте ответил подтверждением сто пять и дублирующим блоком от минус четырёх до нуля: пять лишних байт он назвал повтором. Приложение прочитало оригинал.
|
||
|
||
Для пятидесяти получается сто пятьдесят четыре байта, начало на пятьдесят номеров раньше и блок от минус сорока девяти до нуля.
|
||
|
||
Байты накладки по умолчанию нули. Свой узор для них в коде задаётся отдельным аргументом; в лаборатории такого запуска у нас нет.
|
||
|
||
Теперь ловушка. Если вместо числа написать слово, например host, функция упадёт с ошибкой. В коде накладка проверяется сравнением числа с нулём, у слова числа нет, и сравнение падает. Но к этому моменту первый фейк уже ушёл. На проводе нашего теста фейк первой части, а потом оригинальное приветствие целиком, двести пятьдесят байт, с тем же идентификатором IP, что у фейка. В журнале: ошибка и «пакет проходит без изменений».
|
||
|
||
Запомните: в fakedsplit seqovl только число. В одной из функций дальше то же слово будет меткой, как в multidisorder.
|
||
|
||
![[wiki-anim-video08-s08-seqovl-number-and-word.svg|Накладка: число и слово]]
|
||
|
||
Теперь nodrop. Обычно оригинал выбрасывается. С nodrop после шести пакетов уходит ещё и оригинал, двести пятьдесят байт, и несёт идентификатор первого фейка: помните правило, первый вышедший пакет берёт идентификатор исходного. Сервер в нашем тесте ответил подтверждением двести пятьдесят один и дублирующим блоком от первого до двести пятидесятого байта: «всё это у меня уже есть».
|
||
|
||
Теперь repeats. Запуск с repeats равно два: каждый фейк уходит дважды, а настоящие части по разу. Всего десять пакетов: четыре фейка по два и две настоящих. В коде повторы стоят только в настройках фейков, поэтому настоящие части всегда уходят по разу. Идентификаторы IP идут подряд в порядке отправки, как в выпуске про multisplit.
|
||
|
||
Это правило можно отменить аргументом, который в строке пишется «ай-пи, подчёркивание, ид», со значением zero: в нашем запуске все шесть идентификаторов оказались нулями.
|
||
|
||
Проверь себя. В запуске repeats равно два десять пакетов. Сколько разных идентификаторов IP на проводе?
|
||
|
||
Шесть. Повтор фейка носит тот же идентификатор, что и сам фейк, поэтому разных значений столько же, сколько пакетов без повторов. В нашем тесте идентификаторы шли подряд, шесть значений.
|
||
|
||
![[wiki-anim-video08-s08-nodrop-repeats-ip-id.svg|Nodrop, repeats, ip id]]
|
||
|
||
Итак. Накладка в fakedsplit это число и относится к первой настоящей части. С nodrop оригинал идёт следом, с repeats фейки повторяются, а идентификаторы IP идут подряд, если их не отменить. А слово вместо числа ломает стратегию уже после первого фейка.
|
||
|
||
|
||
## Длинное приветствие и запрос HTTP; когда длины фейка и настоящей части расходятся
|
||
|
||
Вопрос сцены: что изменится, если данных больше одного пакета или это не TLS?
|
||
|
||
Игрушка, выдуманная. Фургон вмещает десять коробок, но на коробке с лишней наклейкой места занято больше, и в фургон входит восемь. Одну и ту же стопку товара разделят на фургоны в разных местах, смотря с наклейкой коробки или без.
|
||
|
||
Теперь настоящие опыты. Сначала большое приветствие на тысячу четыреста восемьдесят четыре байта, с той же меткой midsld. Оно длиннее одного пакета, поэтому программа сначала задерживает куски, собирает приветствие целиком и проигрывает его заново: это разбирает выпуск «Сборка и повторный проигрыш» в конце серии. Для нас важно одно: функция получает все байты сразу.
|
||
|
||
На проводе в нашем тесте те же шесть пакетов: фейк в сто четыре байта, настоящая часть, фейк, потом фейк в тысячу триста восемьдесят байт, настоящая часть и ещё фейк. Сервер прочитал приветствие целиком, и оно совпало с оригиналом. Запрос HTTP на восемьдесят один байт с меткой midsld в заголовке Host даёт те же шесть пакетов, части в тридцать девять и сорок два байта, и сервер читает запрос целиком с верным Host.
|
||
|
||
![[wiki-anim-video08-s09-large-hello-and-http.svg|Большое приветствие и HTTP]]
|
||
|
||
А теперь случай, где длины расходятся. То же большое приветствие, но разрез у самого начала: pos равно два, части в два байта и в тысячу четыреста восемьдесят два. Вторая часть длиннее предела, и её режут на ломтики, как в выпуске про multisplit.
|
||
|
||
Предел мы считали в выпусках про multisplit и про фейки. Порция тысяча четыреста шестьдесят. У настоящего пакета опции двенадцать байт: тысяча четыреста шестьдесят минус двенадцать, тысяча четыреста сорок восемь. Остаток второй части, тысяча четыреста восемьдесят два минус тысяча четыреста сорок восемь, тридцать четыре.
|
||
|
||
У фейка с эм-дэ-пять опции тридцать два байта: тысяча четыреста шестьдесят минус тридцать два, тысяча четыреста двадцать восемь. Остаток пятьдесят четыре.
|
||
|
||
Вот что в нашем тесте на проводе. Фейк второй части идёт ломтиками в тысячу четыреста двадцать восемь и пятьдесят четыре байта, настоящая часть ломтиками в тысячу четыреста сорок восемь и тридцать четыре. Фейки по-прежнему лежат на тех же байтах, но второй ломтик фейка начинается с номера тысяча четыреста тридцать один, а второй ломтик настоящей части с номера тысяча четыреста пятьдесят один.
|
||
|
||
Сервер всё равно прочитал тысячу четыреста восемьдесят четыре байта, равных оригиналу. А оба больших пакета, и фейк, и настоящий, занимают ровно полторы тысячи байт: у фейка лишние двадцать байт опций съели те самые двадцать байт данных.
|
||
|
||
Проверь себя. То же самое, но условие не эм-дэ-пять, а срок жизни один: лишних опций нет. Какие ломтики у фейка второй части?
|
||
|
||
Те же, что у настоящей части: тысяча четыреста сорок восемь и тридцать четыре. В нашем тесте так и вышло: границы совпали. Условие, которое не добавляет опций, ломтики не сдвигает.
|
||
|
||
![[wiki-anim-video08-s09-slices-borders-diverge.svg|Границы ломтиков расходятся]]
|
||
|
||
Итак. Правило «тот же номер и та же длина» верно, пока ни одну часть не режут заново по пределу размера. Для нашего приветствия с разрезом у имени оно верно, у самого начала длинного приветствия нет. Фейки всё равно лежат на тех же байтах, а сервер читает оригинал.
|
||
|
||
|
||
## Что мы знаем: приёмник и фейки одной таблицей
|
||
|
||
Остановимся и сведём всё, что мы узнали о fakedsplit. Всё это относится к нашему тесту, одному приёмнику, Linux, и нашей игрушечной модели. О настоящем оборудовании мы по-прежнему ничего не знаем.
|
||
|
||
Первое. Шесть пакетов: фейк, настоящая часть, фейк, потом снова фейк, настоящая часть, фейк. Оригинальное приветствие выброшено. Фейк лежит на тех же номерах и той же длины, что настоящая часть рядом, пока ни одну часть не режут заново по пределу размера. Тот же рисунок получается и на запросе HTTP, и на длинном приветствии.
|
||
|
||
Второе. В фейке по умолчанию нули, но можно задать узор. Фейк умирает от эм-дэ-пять или испорченной суммы на самом сервере, от срока жизни один в роутере. Нарезка по пределу размера сдвигает границы у фейка с опцией эм-дэ-пять: это измерено. У фейка со сроком жизни один границы те же: это измерено тоже. Для испорченной суммы запуска на длинном приветствии нет, по счёту она опций не добавляет, и границы не сдвинет.
|
||
|
||
Третье. Сервер отвечает один раз, подтверждением сто пять, молчит на все фейки и читает оригинал. По ответам серия неотличима от обычного разреза. Игрушечный инспектор на пересылке роутера в запуске с эм-дэ-пять видел бы все шесть пакетов, а фейк со сроком жизни один до него не дошёл бы.
|
||
|
||
Четвёртое. Без условия фейки побеждают: приложение получает нули, и сервер присылает дублирующие блоки. В нашем тесте условие в этой функции обязательно.
|
||
|
||
Пятое. Четыре выключателя убирают фейки по одному, а когда выключены все четыре, остаётся обычный разрез. Накладка в fakedsplit записывается только числом, слово даёт ошибку после первого фейка. Ещё есть nodrop, repeats и идентификаторы IP подряд.
|
||
|
||
Шестое. Позиция pos это одна метка. В нашем тесте позиция ноль или значение за концом приветствия: стратегия молчит, и оригинал уходит целым.
|
||
|
||
Теперь о том, чего мы не знаем. Мы не знаем, как поведёт себя другой получатель: Windows, BSD или встроенная система. Мы проверили только Linux. Мы не знаем, как устроен настоящий инспектор: что он читает, видит ли фейки и какую копию считает главной. И мы пока не знаем, как справятся с этой серией наши игрушечные читатели: это ближе к концу выпуска.
|
||
|
||
![[wiki-anim-video08-s10-what-we-know-table.svg|Итог по fakedsplit]]
|
||
|
||
Проверь себя по этой таблице. Запуск: fakedsplit с позицией host, условием эм-дэ-пять и выключателями nofake один и nofake четыре. Какие пакеты уйдут?
|
||
|
||
Позиция host даёт части в девяносто семь и сто пятьдесят три байта. Первый выключатель убирает фейк перед первой настоящей частью, четвёртый убирает последний. Остаются четыре пакета: настоящая первая часть, фейк первой части, фейк второй и настоящая вторая. Это расчёт по правилам: такого запуска в лаборатории не было.
|
||
|
||
Теперь мы знаем, что отправил fakedsplit и что ответил сервер. Следующий вопрос: что, если отправить вторую половину раньше первой, да ещё между фейками? Для этого есть следующая функция, «перемешивание с фейками», по-латински fakeddisorder, ей посвящена следующая часть выпуска.
|
||
|
||
![[wiki-anim-video08-s10-check-and-bridge.svg|Проверка и мостик]]
|
||
|
||
Итак. Мы прошли первый запуск, содержимое и смерть фейка, ответы сервера, пограничные значения pos, запуск без условия, четыре выключателя и несколько тонких настроек. Все выводы об эффекте относятся к нашему приёмнику и нашей игрушечной модели.
|
||
|
||
|
||
## Повтор и вопрос: три вопроса, которые остались после разреза с фейками
|
||
|
||
Продолжаем выпуск «Резать и подделывать вместе». Начнём с короткого повтора того, что нам понадобится.
|
||
|
||
Сразу оговорка, она будет повторяться. О настоящем оборудовании на пути пакетов мы не знаем ничего. У нас два участника, и оба наши: игрушечный инспектор в роутере лаборатории и сервер на Linux. Слово «сработало» значит только одно: приём обошёл нашу игрушку, а сервер получил настоящие данные.
|
||
|
||
Первое напоминание, из выпусков «multisplit: резать на части» и «Фейк и его условия». Приветствие в нашей лаборатории занимает двести пятьдесят байт, и разрез делит его на куски. Фейк это лишний пакет рядом с настоящим. Условие это дефект фейка, из-за которого получатель его выбросит: лишняя опция эм-дэ-пять, время жизни один или испорченная контрольная сумма.
|
||
|
||
Договоримся о числах. Смещение это сколько байт стоит перед нужным, считая с нуля. Номер на единицу больше. Имя сайта лежит со смещения девяносто семь, а его первый байт имеет номер девяносто восемь.
|
||
|
||
Как читать ответы сервера. Ответ «жду байт номер сто» значит: девяносто девять байт у сервера уже есть. К ответу может прилагаться блок: это байты, которые лежат у сервера в стороне. Если блок дублирующий, эти байты у него уже были.
|
||
|
||
![[wiki-anim-video08-s11-recap-roles-numbers.svg|Повтор: участники, числа и ответы]]
|
||
|
||
Второе напоминание, из начала этого выпуска. Разрез с фейками, функция fakedsplit, режет приветствие на сто четыре байта и сто сорок шесть и отправляет шесть пакетов: фейк, настоящая первая часть, фейк, потом фейк, настоящая вторая часть и фейк. Номера и длины у фейка те же, что у настоящей части рядом. Четыре фейка можно выключать по одному ключами nofake.
|
||
|
||
Сервер в нашем тесте на такие фейки молчит, а приложение читает оригинал. Без условия всё наоборот: в нашем тесте сервер принял фейки за настоящие данные, настоящие части оказались лишними, и приложение получило одни нули.
|
||
|
||
Третье напоминание, из выпуска «Перемешать: disorder». Стратегия multidisorder отправляет части с последней до первой. Сервер отвечает: байт номер один жду по-прежнему, но конец у меня уже лежит. Когда приходит начало, он отвечает, что ждёт байт номер двести пятьдесят один, и приложение читает все двести пятьдесят байт одним чтением.
|
||
|
||
С этим остались три вопроса. Игрушка, выдуманная: книга на двести пятьдесят страниц, две пачки, а вокруг каждой пачки пустые листы с теми же номерами. Что, если вторую пачку отправить раньше первой? Что, если подкладывать не пустые листы, а подложное имя вместо настоящего? И что, если разрез и фейк делают две отдельные стратегии, одна за другой?
|
||
|
||
![[wiki-anim-video08-s11-recap-two-wires-questions.svg|Повтор запусков и три вопроса]]
|
||
|
||
Ответы такие. Перемешивание с фейками, в программе функция fakeddisorder. Имя между двойниками, функция hostfakesplit. И пара: две стратегии в одной строке, сначала fake, потом multisplit. Идём по проводу, пакет за пакетом, а код откроем в самом конце выпуска, когда будем знать, что в нём искать.
|
||
|
||
Итак. У нас есть разрез с фейками из шести пакетов, обязательное условие и четыре выключателя. Дальше три новые конструкции, и начнём с той, где вторая половина данных уходит первой.
|
||
|
||
|
||
## Перемешивание с фейками: вторая половина идёт первой
|
||
|
||
Вопрос сцены: что уходит в сеть, когда вторая половина приветствия идёт первой, а каждая настоящая половина стоит между двумя фейками? Идём по проводу, как в начале выпуска.
|
||
|
||
Игрушка, выдуманная. Та же книга на две пачки, но курьер везёт первой вторую пачку, страницы со ста пятой по двести пятидесятую, а потом первую. Вокруг каждой пачки лежат чистые листы с теми же номерами.
|
||
|
||
Перемешивание с фейками. В программе эта функция называется fakeddisorder. На проводе это то же, что multidisorder из выпуска «Перемешать: disorder», плюс фейки вокруг каждой части; при всех выключенных фейках провод совпадает. Разрез по-прежнему один. Строка запуска та же, что в начале выпуска: фильтр на приветствие, метка midsld и условие, которое в записи называется tcp_md5, то есть опция эм-дэ-пять. Меняется только имя функции.
|
||
|
||
![[wiki-anim-video08-s12-six-packets-ladder.svg|Перемешивание с фейками: шесть пакетов]]
|
||
|
||
Пакеты нашего теста по порядку. Первый: фейк второй половины. Номер сто пять, длина сто сорок шесть, внутри нули и опция эм-дэ-пять. Сервер молчит.
|
||
|
||
Второй: настоящая вторая половина, тот же номер сто пять и те же сто сорок шесть байт, они начинаются с mple.com. Сервер отвечает: байт номер один жду по-прежнему, а байты со ста пятого по двести пятидесятый у меня лежат в стороне. Это ответ с блоком, как в выпуске «Перемешать: disorder».
|
||
|
||
Третий: тот же фейк второй половины ещё раз. Ответа нет.
|
||
|
||
Четвёртый: фейк первой половины. Номер один, длина сто четыре, внутри нули и опция эм-дэ-пять. Ответа нет, дыра в начале остаётся.
|
||
|
||
Пятый: настоящая первая половина, номер один, сто четыре байта начала приветствия. Дыра закрыта, и сервер отвечает: жду байт номер двести пятьдесят один.
|
||
|
||
Шестой: повтор фейка первой половины, снова тишина. В итоге на сервере остались только настоящие байты.
|
||
|
||
Приложение в нашем тесте прочитало двести пятьдесят байт одним чтением. Байты равны оригиналу, а сервер нашёл в приветствии имя www.example.com. Одно чтение: пока в начале дыра, приложению нечего отдать; так обычно работает приём в Linux, по общим сведениям.
|
||
|
||
Фейки умирают теми же тремя способами, что и в начале выпуска. С опцией эм-дэ-пять счётчик ядра сервера насчитал четыре отброшенных пакета. С временем жизни один фейки до сервера не дошли: на клиенте четыре сообщения роутера «время истекло». С испорченной суммой счётчик ошибок суммы показал четыре. Во всех трёх запусках приложение получило оригинал.
|
||
|
||
Теперь наша игрушечная модель. В роутере лаборатории стоят пять читателей, они склеивают пакеты по-разному и принимают фейк за обычные данные. Против этой серии в нашем тесте ни один из пяти не нашёл имя, и сервер получил приветствие целиком. Подробнее о них дальше в этом выпуске.
|
||
|
||
![[wiki-anim-video08-s12-deaths-and-readers.svg|Как умирают фейки и что видит игрушка]]
|
||
|
||
Проверь себя. Все четыре фейка выключены, остаются две настоящие части. Что сервер ответит на первый пакет?
|
||
|
||
То же самое: жду байт номер один и блок со ста пятого байта, потом жду байт номер двести пятьдесят один. В нашем тесте так и вышло. Фейки на ответы сервера не влияют: он их выбрасывает и не отвечает.
|
||
|
||
Итак. Перемешивание с фейками отправляет шесть пакетов: фейк второй половины, настоящая вторая, ещё фейк второй, потом фейк первой, настоящая первая и ещё фейк первой. Сервер молчит на фейки, держит вторую половину в стороне и, когда приходит первая, ждёт байт номер двести пятьдесят один. Это в нашем тесте, на одном приёмнике, Linux.
|
||
|
||
|
||
## Перемешивание с фейками: без условия, выключатели и другие данные
|
||
|
||
Вопрос сцены: что будет с перемешиванием с фейками, если забыть условие, и что в нём ещё можно переключать?
|
||
|
||
Игрушка, выдуманная. Кладовщик кладёт на место полки первую пришедшую стопку, а всё, что приходит позже на то же место, называет дублем. Сначала приходят чистые листы с номерами второй половины, и настоящая вторая половина оказывается дублем. С первой половиной то же.
|
||
|
||
Теперь настоящий запуск, но без tcp_md5. Шесть пакетов те же по номерам и длинам. Только у фейков теперь нет опции эм-дэ-пять, время жизни обычное и сумма верная: для сервера это обычные пакеты.
|
||
|
||
![[wiki-anim-video08-s13-no-condition-wire.svg|Без условия фейки принимаются как данные]]
|
||
|
||
Фейк второй половины сервер принимает за вторую половину и отвечает так, как раньше на настоящую: жду байт номер один, байты со ста пятого лежат у меня. Настоящая вторая половина и повтор фейка получают тот же ответ, но блок в нём теперь дублирующий: эти байты у меня уже есть.
|
||
|
||
Фейк первой половины закрывает дыру ста четырьмя нулями, и сервер отвечает: жду байт номер двести пятьдесят один. Настоящая первая половина приходит пятой и тоже становится дублем. Всего дублирующих ответов четыре, и приложение прочитало двести пятьдесят байт, все нулевые: ни приветствия, ни имени сайта.
|
||
|
||
С условием сервер ответил два раза. Без условия шесть, по ответу на каждый пакет, потому что каждый для него настоящий. Так же кончился разрез с фейками без условия в начале выпуска, меняется только порядок нулей.
|
||
|
||
Это в нашем тесте. Что именно остаётся у сервера на месте, зависит от порядка прихода: дальше будет запуск, где нули пришли раньше, а приложение всё равно прочитало настоящие байты. Общего правила «побеждает первый» мы не выводим, и как поведёт себя другая система, не проверяли.
|
||
|
||
Теперь выключатели. Их четыре, и нумеруются они по порядку отправки, а первой теперь едет вторая половина. Nofake один убирает фейк второй половины перед настоящей второй, nofake два убирает его после неё. Nofake три и nofake четыре делают то же с первой половиной. В разрезе с фейками один и два относились к первой половине, здесь ко второй. Номера с одной функции на другую переносить нельзя.
|
||
|
||
![[wiki-anim-video08-s13-switches-numbering.svg|Выключатели перемешивания с фейками]]
|
||
|
||
Выключаем первый: серия теряет самый первый пакет, и настоящая вторая половина уходит самой первой. Выключаем четвёртый: серию замыкает настоящая первая половина, фейка после неё нет. Второй и третий убирают фейк сразу после настоящей второй и сразу перед настоящей первой. Ответы сервера в нашем тесте во всех четырёх запусках те же: блок «в стороне», потом жду байт номер двести пятьдесят один.
|
||
|
||
Выключены все четыре: остаются две настоящие части, сначала сто сорок шесть байт, потом сто четыре. Это провод multidisorder с той же меткой, и приложение сервера получило оригинал. При любых выключателях настоящие части остаются на месте, меняются только фейки.
|
||
|
||
Позиция по умолчанию здесь два: части в два байта и в двести сорок восемь, длинная идёт первой. Позиция ноль ничего не режет, и оригинал уходит целым.
|
||
|
||
Остальное как у разреза с фейками из начала выпуска. Nodrop добавляет седьмым пакетом оригинал, и сервер отвечает на него дублирующим блоком. Длинное приветствие в тысячу четыреста восемьдесят четыре байта функция получает уже собранным: программа собирает его заранее, это разбирает выпуск «Сборка и повторный проигрыш». Обе части, по счёту, короче предела размера пакета, ломтиков нет, и сервер прочитал приветствие целиком. В запросе HTTP метка midsld падает в середину слова example, первыми уходят сорок два байта, и Host у сервера верный.
|
||
|
||
Проверь себя. Условия нет, и выключены ещё оба фейка первой половины, третий и четвёртый. Что прочитает приложение?
|
||
|
||
Фейки второй половины придут первыми и займут свои номера, настоящая вторая половина станет дублем, как в запуске без условия. Настоящая первая половина придёт по порядку и закроет дыру в начале. Приложение получит сто четыре настоящих байта и сто сорок шесть нулей, имя будет разорвано. Это расчёт по увиденному, такого запуска у нас нет.
|
||
|
||
Итак. Без условия перемешивание с фейками не прячет имя, а разрушает данные. Выключатели нумеруются по порядку отправки, начиная со второй половины, и когда выключены все четыре, остаётся провод multidisorder. Остальные настройки ведут себя как у разреза с фейками, только вторая половина впереди.
|
||
|
||
|
||
## Накладка в перемешивании: метка внутри окна
|
||
|
||
Вопрос сцены: что делает накладка seqovl в перемешивании с фейками и почему в разрезе с фейками то же слово значило другое?
|
||
|
||
Повтор из выпуска «Перемешать: disorder». Накладка это байты поверх чужого места, которые потом перекрываются настоящими. В multidisorder seqovl был меткой, а не числом: накладок столько, на сколько байт метка отстоит от начала, а начало пакета равно разрезу минус накладки.
|
||
|
||
Игрушка, выдуманная. Вторая пачка уезжает первой, и в начало её подшиты черновые листы с номерами последних листов первой пачки. На эти номера теперь два варианта: черновой, пришедший первым, и настоящий, пришедший позже.
|
||
|
||
Правило то же. Накладку получает настоящая вторая половина, та, что идёт первой, а метка должна стоять левее разреза: накладка ложится на номера хвоста первой половины.
|
||
|
||
Запуск с seqovl равно host. Метка host стоит на смещении девяносто семь, значит, накладок девяносто семь.
|
||
|
||
![[wiki-anim-video08-s14-overlap-host-run.svg|Накладка seqovl равно host]]
|
||
|
||
Настоящая вторая половина выросла: девяносто семь плюс сто сорок шесть, всего двести сорок три байта.
|
||
|
||
Начало пакета: сто четыре минус девяносто семь, смещение семь, это номер восемь. В нашем тесте пакет начинается с нулей.
|
||
|
||
Ответ сервера на этот пакет: байт номер один жду, а байты с восьмого по двести пятидесятый лежат у меня. Когда приходит настоящая первая половина, сервер отвечает, что ждёт байт номер двести пятьдесят один, и добавляет дублирующий блок с восьмого по сто четвёртый байт.
|
||
|
||
Приложение прочитало оригинал. Здесь нули пришли раньше, но настоящая первая половина пришла по порядку и перекрыла то, что лежало в стороне, и приложение прочитало настоящие байты. Как это у другого приёмника, мы не проверяли.
|
||
|
||
Второй запуск: seqovl равно двадцати. Число здесь тоже метка, абсолютное смещение, накладок двадцать. Пакет теперь в сто шестьдесят шесть байт: двадцать плюс сто сорок шесть. Он начинается на смещении восемьдесят четыре, это номер восемьдесят пять.
|
||
|
||
Теперь отмены. Метка midsld, сто четыре, равна разрезу: накладка не меньше разреза, и функция её отменяет. В журнале строка об этом, а на проводе обычные шесть пакетов. Так же отменяется метка, которую функция не нашла, например method на приветствии TLS.
|
||
|
||
![[wiki-anim-video08-s14-cancels-bounds-meanings.svg|Отмены, границы и два смысла seqovl]]
|
||
|
||
Прогон функций показывает границы. Метка midsld минус один даёт сто три накладки: пакет в двести сорок девять байт со смещения один, это самое большое допустимое значение. Метка один даёт один байт накладки: пакет в сто сорок семь байт со смещения сто три.
|
||
|
||
Текст, который вообще не метка, например abc, это ошибка функции, и случается она уже после первого фейка: прогон функций показал на проводе один фейк, потом ошибку.
|
||
|
||
Запомним разницу. В разрезе с фейками накладка число и лежит перед потоком. В перемешивании с фейками накладка метка и лежит внутри потока, поверх хвоста первой половины. Слово host там ошибка, здесь метка. А текст abc ошибка в обеих.
|
||
|
||
Проверь себя. Допустим, seqovl равно восьмидесяти. Какой длины будет настоящая вторая половина и с какого смещения она начнётся?
|
||
|
||
Восемьдесят плюс сто сорок шесть, двести двадцать шесть байт. Начало: сто четыре минус восемьдесят, смещение двадцать четыре. Дублирующий блок покроет восемьдесят номеров, с двадцать пятого по сто четвёртый. Это расчёт по правилу, такого запуска у нас нет: мы запускали девяносто семь и двадцать.
|
||
|
||
Итак. В перемешивании с фейками seqovl это метка: накладка лежит внутри первой половины и начинает пакет раньше на столько байт, сколько накладок. Метка не меньше разреза отменяется с записью в журнале. В нашем тесте приложение получает оригинал.
|
||
|
||
|
||
## Имя между двойниками: первый запуск и выключатели
|
||
|
||
Вопрос сцены: что будет, если подкладывать не копии частей, а только подложное имя?
|
||
|
||
Игрушка, выдуманная. Письмо, и адрес в нём в отдельной строке. Курьер вырезает её на листок, а перед ним и после него кладёт листки с подложным адресом той же длины. Адресат примет только настоящий, а сортировщик прочитает первый попавшийся.
|
||
|
||
Имя между двойниками. В программе эта функция называется hostfakesplit. Места разреза она находит сама, по имени сайта.
|
||
|
||
Начало и конец имени это знакомые метки host и endhost из выпуска «Где резать: метки». В нашем приветствии имя занимает байты со смещения девяносто семь до смещения сто одиннадцать, считая с нуля. Это пятнадцать байт.
|
||
|
||
Двойник это подложное имя той же длины. Функция кладёт его перед настоящим именем и после него. Строка запуска короткая: фильтр на приветствие, функция и условие tcp_md5.
|
||
|
||
![[wiki-anim-video08-s15-name-between-twins.svg|Имя между двойниками: пять пакетов]]
|
||
|
||
Пакеты нашего теста по порядку. Первый: настоящая часть до имени. Номер один, девяносто семь байт, начало приветствия. Сервер отвечает: жду байт номер девяносто восемь. Девяносто семь байт у него уже есть.
|
||
|
||
Второй: двойник. Номер девяносто восемь, пятнадцать байт случайного имени и опция эм-дэ-пять. Ответа нет.
|
||
|
||
Третий: настоящее имя, www точка example точка com. Тот же номер девяносто восемь и те же пятнадцать байт. Имя занимает этот пакет целиком, и больше в пакете ничего нет.
|
||
|
||
Четвёртый: тот же двойник ещё раз. Ответа нет.
|
||
|
||
Пятый: настоящий хвост, номер сто тринадцать и сто тридцать восемь байт. Сервер отвечает: жду байт номер двести пятьдесят один.
|
||
|
||
Сложим: девяносто семь, пятнадцать и сто тридцать восемь дают двести пятьдесят, ровно всё приветствие. Пакетов пять, а не шесть: двойник один, но отправлен дважды.
|
||
|
||
Приложение прочитало двести пятьдесят байт, равных оригиналу, и сервер нашёл имя www.example.com. Двойники умерли из-за условия: счётчик ядра насчитал два отброшенных пакета.
|
||
|
||
Выключателей здесь два, потому что двойников два. Nofake один убирает двойника перед настоящим именем, nofake два убирает его после. Выключены оба: остаются три настоящих куска подряд, и больше ничего.
|
||
|
||
![[wiki-anim-video08-s15-switches-readers.svg|Выключатели, pos и игрушечные читатели]]
|
||
|
||
Nodrop добавляет шестым пакетом оригинал, а repeats равно два повторяет каждого двойника, и всего уходит семь пакетов. Длинное приветствие функция получает уже собранным, это разбирает выпуск «Сборка и повторный проигрыш»; хвост после имени тогда один пакет в тысячу триста семьдесят два байта.
|
||
|
||
Теперь то, чего функция не умеет. Она не читает pos: с pos равным midsld на проводе вышли те же пять пакетов, места разреза определяет только имя.
|
||
|
||
А если программа не определила, что в данных есть имя, функция ничего не отправляет и возвращает «пропустить». Так бывает, например, когда данные помечены как неопознанные: как определяется тип, рассказывает выпуск «Тип нагрузки и имя сайта». Так же с простым набором байтов. Прогон функций показал именно это; что оригинал уйдёт целым, следует из правила, отдельного запуска у нас нет.
|
||
|
||
Теперь наша игрушечная модель. В выпуске «Перемешать: disorder» читатели разбирали готовый захват, а здесь пять читателей стоят в роутере и останавливают соединение, как только находят имя. Настоящее имя лежит в своём пакете целиком, поэтому «пакетный», «склейщик» и «последний записал» нашли его на третьем пакете, и до сервера дошло девяносто семь байт.
|
||
|
||
«Первый записал» и «строго по порядку» имени не нашли: у них в руках двойник, и сервер получил приветствие целиком. Подробнее о читателях дальше в этом выпуске.
|
||
|
||
Проверь себя. Запрос HTTP на восемьдесят один байт, имя в Host на смещении тридцать два, пятнадцать байт. Какие пять пакетов уйдут?
|
||
|
||
Тридцать два байта до имени, затем двойник и настоящее имя по пятнадцать байт, ещё раз двойник и хвост в тридцать четыре байта. В нашем тесте так и вышло, и сервер прочитал запрос целиком.
|
||
|
||
Итак. Имя между двойниками отправляет пять пакетов: часть до имени, двойник, настоящее имя, тот же двойник и хвост. Места разреза функция выбирает сама, по имени, а pos не читает. Сервер молчит на двойников и читает оригинал, это в нашем тесте. Настоящее имя при этом лежит целиком в отдельном пакете, и это нужно помнить.
|
||
|
||
|
||
## Двойник: длина, случайность и шаблон
|
||
|
||
Вопрос сцены: из чего состоит двойник, какой он длины и можно ли выбрать его самому?
|
||
|
||
Игрушка, выдуманная. В окошке сортировщика строка из пятнадцати клеток. Подложная карточка из десяти клеток или из двадцати выдаст себя сразу тому, кто сверяет длины, незаметна только карточка ровно в пятнадцать.
|
||
|
||
![[wiki-anim-video08-s16-twin-same-length.svg|Двойник той же длины, что имя]]
|
||
|
||
Двойник всегда той же длины, что и настоящее имя: в нашем приветствии пятнадцать байт. Всё вокруг имени остаётся настоящим, поэтому, по счёту, поля длины в приветствии продолжают сходиться.
|
||
|
||
Двойник создаётся один раз за вызов и отправляется дважды, поэтому оба фейка в нашем тесте несут одни и те же пятнадцать байт. А в другом запуске имя другое: двойник случайный. Буквы из наших двух запусков мы не называем, они ничего не значат.
|
||
|
||
Если шаблона нет, для имён от семи байт двойник собран так: одна случайная буква, потом случайные буквы и цифры, точка и одно из шести окончаний: com, org, net, edu, gov, biz. В прогоне функций на две тысячи вызовов длина ни разу не сбилась, а каждое окончание выпало от трёхсот до четырёхсот раз.
|
||
|
||
![[wiki-anim-video08-s16-default-and-template.svg|Двойник по умолчанию и шаблон host]]
|
||
|
||
Зачем двойнику шаблон? По общим сведениям, читатель может пропускать только то, что выглядит как имя сайта, и шаблон нужен, чтобы двойник так выглядел. Задаётся он ключом host. Все правила про одно: имя должно получиться ровно нужной длины.
|
||
|
||
Первое правило: шаблон короче нужного больше чем на один символ. Перед ним ставятся случайные символы и точка. В нашем тесте шаблон из пяти символов дал девять случайных символов, точку и сам шаблон. Девять плюс шесть, ровно пятнадцать.
|
||
|
||
Второе правило: шаблон короче нужного ровно на один символ. Впереди ставится одна точка. Шаблон из четырнадцати символов дал в нашем тесте двойник из точки и этого шаблона.
|
||
|
||
Третье правило: шаблон нужной длины. Двойник это сам шаблон. Если шаблон равен настоящему имени, двойник с ним совпадёт: прогон функций показал, что www.example.com даёт www.example.com. Тогда фейк и настоящее имя одинаковы.
|
||
|
||
Четвёртое правило: шаблон длиннее нужного. Берётся его хвост нужной длины. Шаблон в восемнадцать символов дал хвост в пятнадцать.
|
||
|
||
Провод в обоих наших запусках с шаблоном такой же, как без шаблона: пять пакетов с теми же номерами и длинами. Меняются только байты двойника. Годится ли имя настоящего сайта в качестве шаблона, мы не проверяли: настоящих сайтов в лаборатории нет.
|
||
|
||
Проверь себя. Шаблон google.com, десять символов, а нужно одиннадцать. Какой получится двойник?
|
||
|
||
Ровно на один символ длиннее шаблона, значит, впереди точка: .google.com. Прогон функций показал именно это.
|
||
|
||
Ещё пример. Тот же шаблон, но нужно шестнадцать символов. Что получится?
|
||
|
||
Шестнадцать минус десять, шесть. Одна позиция уходит на точку, остаётся пять случайных символов. Итого пять случайных символов, точка и google.com. Прогон функций показал такую форму, буквы в ней случайные.
|
||
|
||
Итак. Двойник той же длины, что настоящее имя, создаётся один раз за вызов и уходит дважды. По умолчанию он случайный, с одним из шести окончаний. Шаблон host подгоняется под нужную длину: добавляются случайные символы и точка, или одна точка, или берётся сам шаблон, или его хвост.
|
||
|
||
|
||
## Без условия: сервер получит чужое имя
|
||
|
||
Вопрос сцены: что будет с именем между двойниками, если забыть условие?
|
||
|
||
Игрушка, выдуманная. Кладовщик, как раньше, принимает на место первую пришедшую карточку, а остальные называет дублями. Первой приходит карточка с подложным адресом: письмо уйдёт по нему, а настоящая карточка окажется дублем.
|
||
|
||
![[wiki-anim-video08-s17-no-condition-wire.svg|Без условия сервер получает чужое имя]]
|
||
|
||
Запуск тот же, но без tcp_md5. Пять пакетов те же по номерам и длинам, только двойники теперь обычные пакеты. На первый пакет, часть до имени, сервер отвечает: жду байт номер девяносто восемь.
|
||
|
||
Второй пакет, двойник. Сервер принимает его за настоящее имя, но отдельного ответа на него в нашем тесте нет: подтверждения Linux иногда откладывает. Следующий ответ покажет, что имя получено.
|
||
|
||
Третий пакет, настоящее имя. Ответ: жду байт номер сто тринадцать, имя получено, и к нему дублирующий блок в пятнадцать байт с девяносто восьмого: эти байты у меня уже есть. Повтор двойника получает тот же ответ. Пятый пакет, хвост, и ответ: жду байт номер двести пятьдесят один.
|
||
|
||
Приложение прочитало двести пятьдесят байт, но имя в них чужое: пятнадцать байт имени заменены двойником. Сервер разобрал приветствие и нашёл в нём случайное имя, а не www.example.com.
|
||
|
||
С условием ответов два, на двойников молчание. Без условия в нашем тесте четыре: два раза с дублирующим блоком. Они показывают, что настоящее имя пришло позже двойника. Число таких ответов может зависеть от того, как Linux откладывает подтверждения.
|
||
|
||
У разреза с фейками и перемешивания с фейками приложение без условия получало нули, потому что фейк лежал на целой половине. Здесь двойник закрывает только пятнадцать байт имени, всё остальное настоящее, и сервер получает приветствие с чужим именем.
|
||
|
||
То же с запросом HTTP. Без условия сервер прочитал запрос на восемьдесят один байт, и в заголовке Host у него случайное имя двойника. Ответы шли так: жду байт тридцать три, потом сорок восемь с дублирующим блоком, ещё раз то же, и восемьдесят два.
|
||
|
||
![[wiki-anim-video08-s17-http-and-other-functions.svg|Запрос HTTP и другие функции без условия]]
|
||
|
||
Чем это грозит? По общим сведениям, многие серверы выбирают, какой сайт показать, по этому имени, так что соединение ушло бы к другому сайту или было бы отвергнуто. В нашей лаборатории таких сайтов нет, мы это не проверяли.
|
||
|
||
Две другие формы условия работают как раньше. С временем жизни один оба двойника умирают в роутере, на клиенте два сообщения «время истекло». С испорченной суммой счётчик ошибок суммы показал два. В обоих запусках приложение получило оригинал.
|
||
|
||
Проверь себя. Условия нет, но выключен первый выключатель: двойника перед настоящим именем нет. Какое имя прочитает приложение?
|
||
|
||
Настоящее имя приходит первым и по порядку, двойник после него приходит позже и становится дублем. По тому, что мы видели, должно остаться настоящее имя. Это расчёт, такого запуска у нас нет, и другие приёмники мы не проверяли.
|
||
|
||
Итак. Без условия двойник приходит первым и по порядку, сервер в нашем тесте оставляет его, и приложение получает чужое имя. Это не нули, как у разреза с фейками и перемешивания с фейками, а подмена, и она тоже ломает соединение. Условие в этой функции обязательно.
|
||
|
||
|
||
## Разрезать настоящее имя и отправить хвост наоборот
|
||
|
||
Вопрос сцены: что дают два необязательных ключа, midhost, «разрез имени», и disorder_after, «хвост наоборот», и где у них границы?
|
||
|
||
Игрушка, выдуманная. Сортировщик читает каждый листок отдельно и узнаёт адрес на листке, который лежит целиком. Чтобы не узнал, листок режут пополам. А хвост письма можно отправить наоборот: сначала последнюю строку, потом остальное.
|
||
|
||
![[wiki-anim-video08-s18-midhost-cut-and-bounds.svg|Ключ midhost режет настоящее имя]]
|
||
|
||
Настоящее имя в наших запусках лежит в своём пакете целиком. Ключ midhost режет это имя на два пакета, двойники остаются целыми. С midhost равным midsld имя режется в середине слова example: www.exa в семь байт и mple.com в восемь. На проводе нашего теста: часть до имени, двойник, семь байт, восемь байт, двойник и хвост. Приложение прочитало оригинал.
|
||
|
||
В нашей игрушечной модели при midhost читатель «пакетный» имени уже не находит, а «склейщик» находит по-прежнему. Подробнее о них дальше в этом выпуске.
|
||
|
||
Границы midhost. Метка должна стоять строго после первого байта имени и не дальше его последнего байта: на нашем приветствии это смещения от девяносто восьмого до ста одиннадцатого. Метка в начале имени, за его концом или вне имени отвергается: в журнале запись, на проводе обычные пять пакетов. В нашем тесте так вышло с меткой два.
|
||
|
||
Прогон функций показал края: метка host плюс один режет имя на один байт и четырнадцать, метка endhost минус один на четырнадцать и один.
|
||
|
||
Теперь disorder_after. Он работает с хвостом, то есть с частью после имени. Хвост режется на два куска, и поздний кусок уходит первым. Зачем? Как в выпуске «Перемешать: disorder»: приёмнику приходится держать конец в стороне и ждать начало, а читателю склеивать данные не по порядку.
|
||
|
||
![[wiki-anim-video08-s18-disorder-after-tail.svg|Ключ disorder after: хвост наоборот]]
|
||
|
||
Пустое значение disorder_after означает метку «последний байт».
|
||
|
||
Запуск с пустым disorder_after. Хвост в сто тридцать восемь байт делится на два куска. Первым уходит последний байт, номер двести пятьдесят. За ним остальные сто тридцать семь, начиная с номера сто тринадцать. На последний байт сервер ответил: жду байт номер сто тринадцать, а двести пятидесятый у меня лежит в стороне. Потом пришёл основной кусок, и сервер ответил: жду байт двести пятьдесят один.
|
||
|
||
Запуск с disorder_after равным endhost плюс двадцать. Это смещение сто тридцать два. Первым уходит всё, что идёт с этого места: сто восемнадцать байт, с номера сто тридцать три. Вторым двадцать байт, с номера сто тринадцать. Блок на сервере начинается с номера сто тридцать три.
|
||
|
||
Граница. Хвост должен остаться в двух непустых кусках: метка не раньше смещения сто тринадцать. Метка endhost, сразу за именем, и метка host отвергаются с записью в журнале, и хвост уходит целым. Метка endhost плюс один допустима: сто тридцать семь байт со смещения сто тринадцать, потом один байт со смещения сто двенадцать. Вместе оба ключа в нашем тесте дали: имя на семь и восемь байт, хвост с последним байтом впереди, и приложение прочитало оригинал.
|
||
|
||
Проверь себя. Ключ disorder_after равен endhost плюс два. Какие два куска хвоста и в каком порядке?
|
||
|
||
Поздний кусок первым: сто тридцать шесть байт со смещения сто четырнадцать, потом два байта со смещения сто двенадцать. Двести пятьдесят минус сто четырнадцать дают сто тридцать шесть. Прогон функций показал именно так.
|
||
|
||
Итак. Midhost режет настоящее имя на два пакета, и его значение должно лежать внутри имени. Disorder_after режет хвост на два куска и отправляет поздний первым, и его значение должно лежать не раньше смещения сто тринадцать. Всё, что вне границ, отвергается с записью в журнале.
|
||
|
||
|
||
## Два экземпляра на одном пакете: fake, а после него multisplit
|
||
|
||
Вопрос сцены: что будет, если фейк подкладывает не та функция, что режет, а отдельная стратегия, которая стоит в строке первой?
|
||
|
||
Игрушка, выдуманная. Конвейер из двух станков. Деталь проходит их по порядку: первый станок кладёт на ленту подложное письмо, второй режет настоящее, и у каждого станка своя табличка настроек. В программе станок это экземпляр: одна запись lua-desync в строке запуска, как мы читали в выпуске «Читаем командную строку zapret2».
|
||
|
||
![[wiki-anim-video08-s19-two-instances-command.svg|Два экземпляра в одном профиле]]
|
||
|
||
В программе это два экземпляра в одном профиле. Строка запуска: fake с заготовкой fake_default_tls и условием tcp_md5, а после неё multisplit со списком из двух меток: один и midsld. Экземпляры идут в порядке командной строки.
|
||
|
||
Журнал называет их по формуле из того же выпуска: функция, профиль, позиция. В нашей лаборатории позицию один занимает запись трафика, поэтому fake стоит на позиции два, а multisplit на позиции три.
|
||
|
||
У каждого экземпляра свои аргументы. Условие tcp_md5 написано у fake, поэтому касается только фейка: настоящие части идут без опции эм-дэ-пять. Помните ловушку из выпуска «multisplit: резать на части»: условие, написанное у самого multisplit, попало бы на настоящие части.
|
||
|
||
Теперь провод нашего теста. Первым уходит один фейк, шестьсот восемьдесят байт, готовая заготовка из выпуска «Фейк и его условия», с номером один, как у оригинала. Внутри него другое имя, www.microsoft.com. За ним три настоящие части: один байт, сто три байта и сто сорок шесть.
|
||
|
||
![[wiki-anim-video08-s19-fake-then-multisplit-wire.svg|Фейк, а после него multisplit]]
|
||
|
||
Заметьте длину. Фейк в шестьсот восемьдесят байт длиннее настоящего приветствия в двести пятьдесят: он накрывает все настоящие байты и ещё четыреста тридцать сверху. Идентификаторы IP идут подряд по всем четырём пакетам: счётчик общий для обоих экземпляров.
|
||
|
||
Сервер в нашем тесте выбросил фейк по эм-дэ-пять, счётчик показал один пакет. Он ответил: жду байт номер два после первой части и жду байт номер двести пятьдесят один в конце. Приложение прочитало двести пятьдесят байт, равных оригиналу, с именем www.example.com.
|
||
|
||
Что с оригиналом? Каждый экземпляр обычно выполняется, даже если раньше стоящий уже сказал «выбросить»: движок, то есть часть программы на Си, собирает ответы всех. Фейк ничего не возвращает, а multisplit говорит: оригинал выбросить. Если хотя бы один сказал «выбросить», оригинал выбрасывается один раз; как именно, объясняет выпуск «Lua внутри программы». Нам достаточно, что оригинала на проводе нет, а пакетов с данными четыре.
|
||
|
||
Теперь наша игрушечная модель. Эта пара прячет имя от читателей «первый записал», «строго по порядку» и «пакетный»: фейк лёг первым, а настоящее разрезано. «Склейщик» и «последний записал» имя находят и останавливают соединение на четвёртом пакете: до сервера дошло сто четыре байта. Подробнее о читателях дальше в этом выпуске.
|
||
|
||
Проверь себя. Поменяем экземпляры местами: сначала multisplit, потом fake. Где окажется фейк?
|
||
|
||
Экземпляры идут в порядке командной строки, и выполняются все. Значит, фейк уйдёт после трёх настоящих частей. В нашем тесте так и вышло: один байт, сто три, сто сорок шесть, потом фейк в шестьсот восемьдесят. Другие порядки разберём дальше в этом выпуске.
|
||
|
||
Итак. Два экземпляра на одном пакете работают по порядку командной строки, и у каждого свои аргументы. Fake отправляет один фейк в шестьсот восемьдесят байт, потом multisplit три настоящие части, а оригинал выбрасывается один раз. В нашем тесте сервер читает оригинал, а в нашей игрушечной модели часть читателей имя находит.
|
||
|
||
|
||
## Что мы знаем: перемешивание, имя между двойниками и пара
|
||
|
||
Вопрос сцены: что мы теперь знаем про три конструкции? Сведём, что мы узнали за последние сцены. Это всё в нашем тесте, на одном приёмнике, Linux, и в нашей игрушечной модели. О настоящем оборудовании мы по-прежнему ничего не знаем.
|
||
|
||
Перемешивание с фейками, fakeddisorder: шесть пакетов, фейк второй половины, настоящая вторая, ещё фейк второй, потом то же с первой половиной. Выключатели нумеруются со второй половины, а при всех выключенных остаётся провод multidisorder. Без условия приложение получает нули. Накладка seqovl здесь метка внутри окна.
|
||
|
||
![[wiki-anim-video08-s20-three-constructions-table.svg|Три конструкции: сводка]]
|
||
|
||
Имя между двойниками, hostfakesplit: пять пакетов, двойник той же длины, один на вызов, уходит дважды. Шаблон подгоняется под длину. Без условия сервер видит чужое имя. Midhost режет настоящее имя, disorder_after отправляет хвост наоборот, у обоих есть границы, а pos функция не читает.
|
||
|
||
Два экземпляра, fake и после него multisplit: один фейк в шестьсот восемьдесят байт и три настоящие части. Условие у fake не касается частей, а оригинал выбрасывается один раз, поэтому его на проводе нет.
|
||
|
||
Что отвечает сервер. На перемешивание с фейками он сначала держит вторую половину в стороне, потом ждёт байт номер двести пятьдесят один. На имя между двойниками ждёт байт номер девяносто восемь, потом двести пятьдесят один. На пару ждёт байт номер два после первой части и двести пятьдесят один в конце.
|
||
|
||
Три вещи с одной функции на другую переносить нельзя. Нумерацию выключателей. Смысл seqovl: у одной функции это число, у другой метка. И то, что бывает без условия: нули, чужое имя или, как в выпуске «Фейк и его условия», фейк в шестьсот восемьдесят байт, который сервер принимает всерьёз.
|
||
|
||
![[wiki-anim-video08-s20-do-not-carry-over-and-check.svg|Что не переносить и проверка по таблице]]
|
||
|
||
Откуда мы это знаем. Провод и ответы сервера мы видели в нашем тесте. Границы значений показал прогон функций. Всё, что про настоящие серверы и настоящее оборудование, мы называли только по общим сведениям, и проверить его нам нечем. Другие приёмники и другие значения настроек мы не проверяли.
|
||
|
||
Проверь себя по этой таблице. Запуск fakeddisorder с условием, с nofake один и nofake четыре. Какие пакеты уйдут?
|
||
|
||
Первый выключатель убирает фейк второй половины перед настоящей второй, четвёртый убирает фейк первой половины после настоящей первой. Остаются четыре пакета: настоящая вторая половина, фейк второй, фейк первой и настоящая первая. Это расчёт по правилам, такого запуска у нас нет.
|
||
|
||
Дальше в выпуске мы посмотрим другие порядки пар, ловушку со списком меток в pos и то, что бывает с парой без условия. Потом самое интересное: игрушечные читатели. Мы будем выключать фейки по одному и смотреть, кто из читателей прозреет. Код этих функций откроем в самом конце, чтобы понять, откуда берутся эти правила.
|
||
|
||
Итак. У нас есть перемешивание с фейками, имя между двойниками и пара из двух стратегий, и для каждой мы знаем, что она отправляет, что отвечает сервер и какие у неё границы. Всё это относится к нашему приёмнику и нашей игрушечной модели. Дальше посмотрим, как эти конструкции видят игрушечные читатели.
|
||
|
||
|
||
## Повтор и вопрос: три функции, что осталось выяснить
|
||
|
||
Добро пожаловать в заключительную часть выпуска «Резать и подделывать вместе». Сначала короткий повтор, чтобы эту часть можно было смотреть отдельно от остальных.
|
||
|
||
О настоящем оборудовании на пути пакетов здесь по-прежнему ни слова: мы не знаем, как оно устроено. Участников двое, и оба наши: игрушечный инспектор в роутере лаборатории и сервер с Linux. Слово «сработало» в этом выпуске значит одно: приём обошёл нашу игрушку, а сервер получил настоящие данные.
|
||
|
||
Фейк это поддельный пакет, который программа вставляет рядом с настоящим. Условие это его намеренный дефект: опция MD5, срок жизни один или испорченная контрольная сумма. Из-за дефекта фейк не доходит до приложения: пакет с MD5 или с плохой суммой выбрасывает ядро получателя, а пакет со сроком жизни один гибнет в роутере. Как это устроено, объяснил выпуск «Фейк и его условия».
|
||
|
||
Три функции этого выпуска, пока с рабочими прозвищами. Fakedsplit, «разрез с фейками»: шесть пакетов, фейк, настоящая часть, фейк, потом ещё фейк, настоящая часть и фейк. Fakeddisorder, «перемешивание с фейками»: те же шесть, но вторая половина идёт первой. Hostfakesplit, «имя между двойниками»: пять пакетов, и настоящее имя лежит один в пакете между двумя копиями выдуманного имени, двойниками. Первые две режут по метке, как в выпуске «Где резать: метки»: метка midsld, середина слова example, делит наше приветствие в двести пятьдесят байт на сто четыре и сто сорок шесть.
|
||
|
||
Как читать записи на экране. Буква «эф» это фейк, буква «эр» настоящая часть, число после значка «собака» это смещение: с какого байта пакет начинается, считая от нуля. Рядом длина, а «эм» в конце значит опцию MD5. Запись «эф сто четыре, собака ноль, эм»: фейк в сто четыре байта с нулевого байта, с опцией MD5. В ответах сервера байты считаются с единицы: смещение ноль это номер один. Мы всегда скажем, какой счёт имеем в виду.
|
||
|
||
![[wiki-anim-video08-s21-three-wires.svg|Три функции и три провода]]
|
||
|
||
Что ответил сервер. Во всех трёх запусках в нашем тесте приложение сервера прочитало настоящие двести пятьдесят байт, а фейки умерли на сервере из-за опции MD5. Без условия всё хуже: в двух функциях приложение получило двести пятьдесят нулевых байтов, а в третьей имя сайта заменил двойник.
|
||
|
||
Проверь себя. В какой из трёх функций без условия сервер получит не нули, а двойника имени, и почему?
|
||
|
||
В hostfakesplit. Её двойник подменяет только пятнадцать байт имени, всё остальное приветствие настоящее. В двух других функциях фейк накрывает целую часть, и вместо неё приходят нули.
|
||
|
||
![[wiki-anim-video08-s21-judge-fake-table.svg|Судья, фейк и таблица без условия]]
|
||
|
||
Осталось выяснить четыре вещи. Что будет, если в строку поставить две стратегии, например фейк и multisplit. Почему список меток, который работает в multisplit, в fakedsplit молча становится одним числом. Кого из шести игрушечных читателей что обманет. И как это написано в коде: его мы откроем в конце.
|
||
|
||
Итак. Разрез прячет имя от читателя, который смотрит пакеты по одному, а фейк с условием не доходит до приложения. Три функции собирают это в одну серию. Дальше пары стратегий, ловушки, читатели и код.
|
||
|
||
|
||
## Другие порядки и пары; пара без условия
|
||
|
||
Вопрос сцены: какие ещё порядки и пары мы пробовали, и что станет с парой, в которой у фейка нет условия?
|
||
|
||
Игрушка, выдуманная. Две записки лежат на столе, и их читают в том порядке, в каком положили. Если сверху записка с неправильным адресом, первым прочтёт тот, кто верит первой записке. Порядок записок это и есть порядок пакетов.
|
||
|
||
Напоминание из предыдущей части. Два экземпляра на одном пакете выполняются в порядке записи, и аргументы у каждого свои. Fake впереди кладёт фейк в шестьсот восемьдесят байт перед тремя настоящими частями multisplit. Если поставить fake после multisplit, фейк уйдёт после данных, а сервер в нашем тесте его выбросит.
|
||
|
||
Теперь пары с условием tcp_md5, то есть с опцией MD5, на фейке; всё в нашем тесте. Фейк и fakedsplit: фейк в шестьсот восемьдесят байт и за ним шесть пакетов разреза с фейками, всего семь.
|
||
|
||
Проверь себя. Пара «фейк и multidisorder» с метками один и midsld: части уходят задом наперёд, как в выпуске «Перемешать: disorder». Какой пакет уйдёт последним и с какого смещения?
|
||
|
||
Настоящая часть в один байт, со смещения ноль. Сначала фейк, потом части в сто сорок шесть байт, в сто три и в один. Приложение сервера в нашем тесте прочитало оригинал.
|
||
|
||
Фейк и hostfakesplit: фейк в шестьсот восемьдесят байт и пять пакетов имени между двойниками. Фейки здесь двух видов: один накрывает всё приветствие, два двойника только имя.
|
||
|
||
Четвёртая пара: у фейка не MD5, а срок жизни один. Он умирает в роутере, клиент получает одно сообщение ICMP, а настоящие части проходят. А пара с multisplit и опцией MD5 справляется и с длинным приветствием в тысячу четыреста восемьдесят четыре байта. Во всех этих запусках приложение сервера в нашем тесте прочитало настоящие байты без изменений.
|
||
|
||
![[wiki-anim-video08-s22-pairs-with-condition.svg|Пары стратегий с условием]]
|
||
|
||
Теперь главное: пара без условия. Берём ту же заготовку и multisplit, но tcp_md5 убираем. Фейк без условия это обычный пакет с номером один и длиной шестьсот восемьдесят. Без условия мы пробовали только пару с multisplit.
|
||
|
||
Сервер принял этот пакет и ответил: жду шестьсот восемьдесят первый байт. Это значит, что первые шестьсот восемьдесят у него есть. Но клиент отправил только двести пятьдесят и ждёт ответа на двести пятьдесят первый. Подтверждение байтов, которых клиент не отправлял, он принять не может. Это объяснение по общим сведениям о TCP, но подтверждение с таким номером и неизменное «жду первый байт» от клиента мы видим на проводе. Приложение сервера получило шестьсот восемьдесят байт фейкового приветствия с именем www точка microsoft точка com.
|
||
|
||
Сервер при этом свой короткий ответ отправил, это видно в захвате, но клиент его не принял. Клиент повторял приветствие: в захвате шесть кругов, в каждом фейк и три настоящие части. Каждый раз сервер отвечал тем же «жду шестьсот восемьдесят первый». О паузах между кругами мы ничего не утверждаем.
|
||
|
||
![[wiki-anim-video08-s22-pair-without-condition.svg|Пара без условия]]
|
||
|
||
Вывод про стратегии простой: опасный пакет в паре это фейк. Разрезанные части безвредны, а фейк без условия в нашем тесте сломал соединение.
|
||
|
||
Итак. Порядок экземпляров решает, где лежит фейк: впереди данных или после них. С условием фейк в нашем тесте умирает рядом с четырьмя разрезающими стратегиями, настоящие части доходят, и на длинном приветствии тоже. Без условия в паре с multisplit приложение получило фейк, а соединение встало.
|
||
|
||
|
||
## Ловушки: список меток и аргументы, которые молчат
|
||
|
||
Вопрос сцены: почему список меток, который работает в multisplit, в fakedsplit молча становится одним числом, и какие ещё аргументы молчат?
|
||
|
||
Игрушка, выдуманная. Анкета с одной клеткой «номер места». Клерк читает клетку до первой запятой и дальше не смотрит. Напишете «семь, у окна», он запишет семь и не скажет, что про окно не узнал.
|
||
|
||
Список с метками один и midsld знаком по выпуску «multisplit: резать на части»: две метки, три части. Поставим тот же список в fakedsplit: pos равно один, запятая, midsld. Смотрим на провод нашего теста.
|
||
|
||
Первый пакет: фейк в один байт, смещение ноль. Второй: настоящая часть, тоже один байт. Третий: тот же фейк. Дальше три пакета по двести сорок девять байт со смещения один: фейк, настоящая часть, фейк.
|
||
|
||
В записях журнала о самом разрезе про midsld нет ни слова: сначала строка, что найденная позиция равна одному, потом шесть строк об отправке. Строки об ошибке нет. Потерю видно только по проводу или по счёту.
|
||
|
||
Разрез один, после первого байта, а в multisplit тот же список даёт три части. Имя сайта начинается со смещения девяносто семь и целиком лежит в настоящей части на двести сорок девять байт. Для нашей модели это значит: «пакетный», который ищет имя в каждом пакете отдельно, находит его, и единственное, чем разрез его обманывал, потеряно.
|
||
|
||
![[wiki-anim-video08-s23-list-becomes-number.svg|Список меток становится числом]]
|
||
|
||
Другие значения ведут себя так же. Два, запятая, midsld даёт разрез после двух байт. Midsld плюс один, запятая, host даёт разрез после ста пяти байт, а host пропадает. Напомню две линейки из выпуска «Где резать: метки»: смещение считается с нуля, позиция Lua с единицы. Прогон функций превращает «один, midsld» в позицию два, то есть в смещение один.
|
||
|
||
Вторая ловушка громкая. Если сразу за именем метки стоит запятая, как в «midsld, host», функция не узнаёт такое имя и останавливается с ошибкой «плохая метка». Программа пишет в журнал, что пакет пропущен без изменений, и приветствие уходит целым, двести пятьдесят байт одним пакетом. Сервер в нашем тесте его прочитал.
|
||
|
||
Правило целиком. Список начинается с числа: число читается, остальное молча теряется. Начинается с имени, за которым плюс или минус: читается одна метка, остальное тоже теряется. Начинается с имени, за которым сразу запятая: ошибка.
|
||
|
||
Проверь себя. Что сделает pos равное host минус один, запятая, midsld?
|
||
|
||
Имя host стоит перед минусом, значит это одна метка host минус один, а остаток после запятой потерян. Разрез после девяноста шести байт, части в девяносто шесть и сто пятьдесят четыре, midsld пропал молча. Это расчёт по коду; запуск с одним host минус один даёт именно такие части.
|
||
|
||
![[wiki-anim-video08-s23-bad-marker-rule-check.svg|Правило списка меток и ошибка]]
|
||
|
||
Теперь аргументы, которые молчат по-другому. Первый: pos у hostfakesplit. Мы дали pos равное два, а на проводе те же пять пакетов, что и без него. По коду эта функция сама ищет имя двумя метками и pos не читает. По умолчанию она режет только вокруг имени, другие разрезы задают её собственные ключи.
|
||
|
||
Второй: ipfrag, нарезка на фрагменты IP, о ней выпуск «Другие слои». Мы дали его всем трём функциям, и на проводе клиента в нашем тесте ни одного фрагмента, а multisplit с тем же ipfrag дал четыре. В таблицах настроек этих функций для ipfrag пустое значение, и нарезчик не запускается. Руководство это подтверждает, а комментарий внутри hostfakesplit им противоречит.
|
||
|
||
Третий: repeats и badsum касаются только фейков. С repeats равным два каждый фейк уходит дважды, а настоящие части один раз: в нашем тесте десять пакетов вместо шести.
|
||
|
||
Четвёртый: seqovl словом. В fakedsplit накладка задаётся только числом. С seqovl равным host функция остановилась с ошибкой уже после первого фейка, программа пропустила оригинал, и на проводе фейк в сто четыре байта, а следом приветствие целиком. Числом seqovl в нашем тесте работает: равное пяти, оно даёт настоящую часть в сто девять байт, которая начинается на пять байт раньше первого байта приветствия.
|
||
|
||
![[wiki-anim-video08-s23-silent-arguments.svg|Аргументы, которые молчат]]
|
||
|
||
Итак. В fakedsplit и fakeddisorder pos это одна метка: список с числа молча становится числом, а список с имени и запятой даёт ошибку и целое приветствие. Pos у hostfakesplit не читается, ipfrag не работает у всех трёх, repeats и badsum касаются только фейков. Первые три случая молчат и видны только на проводе, а у seqovl словом ошибка в журнале есть, но первый фейк уже ушёл.
|
||
|
||
|
||
## Шесть читателей и таблица: кого обманули разрез и фейки
|
||
|
||
Вопрос сцены: кого из наших игрушечных читателей обманывают эти стратегии? Напоминание: это модели проекта, а не оборудование, и «сработало» значит «обошло игрушку».
|
||
|
||
Игрушка, выдуманная. Шесть клерков получили один и тот же ворох бумажек с кусками письма и ищут в нём адрес. У каждого своё правило, и каждое придумали мы.
|
||
|
||
Читатели читают запись пакетов у входа в роутер: ровно то, что туда дошло, вместе с фейками. Они принимают любой пакет как есть: ни опцию MD5, ни контрольную сумму, ни срок жизни не проверяют. Поэтому фейк с условием для них обычные данные. «Видит» значит, что имя нашлось и читателя не обманули. «Слеп» значит, что имя не нашлось: для нас это хороший исход.
|
||
|
||
Пять читателей знакомы по выпуску «Перемешать: disorder». «Пакетный» ищет имя в каждом пакете отдельно. «Склейщик» клеит данные в порядке прихода. «Первый записал» собирает по номерам, у перекрытых байтов остаётся первая запись. «Последний записал» то же, но остаётся последняя. «Строго по порядку» берёт сегмент, только если он начинается не позже ожидаемого байта. Все пятеро решают после каждого пакета.
|
||
|
||
Шестой новый: «последний записал, судит в конце». Правила те же, но решение он принимает один раз, когда поток закончился.
|
||
|
||
![[wiki-anim-video08-s24-six-readers.svg|Шесть игрушечных читателей]]
|
||
|
||
Строки таблицы. Первая, 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». Видят в этой строке только оба «последних записал».
|
||
|
||
![[wiki-anim-video08-s24-readers-table.svg|Кого обманули разрез и фейки]]
|
||
|
||
Итак. Разрез ослепляет «пакетного». В fakedsplit с четырьмя фейками и разрезом внутри имени слепы все шесть, а один фейк в паре ослепляет не всех. Если имя целиком в одной настоящей части, «пакетный» и «склейщик» видят его во всех наших запусках. Всё это про наши модели и больше ни про что.
|
||
|
||
|
||
## Живые игрушки в роутере: кто на каком пакете остановил соединение
|
||
|
||
Вопрос сцены: что будет, если читатель стоит не над записью, а прямо в роутере и выбрасывает пакеты, найдя имя?
|
||
|
||
Игрушка, выдуманная. Вахтёр на входе читает письма. Найдя нужное слово, он выбрасывает это письмо и все следующие письма того же отправителя.
|
||
|
||
В выпуске «Перемешать: disorder» мы ставили в роутер второй nfqws2 с нашим читателем. Он читает данные клиента по одному из способов, и в том выпуске их было четыре. Сегодня добавлен пятый, пакетный: он ищет имя в каждом пакете отдельно, как наш читатель с тем же прозвищем. Найдя имя, игрушка выбрасывает этот пакет и все следующие пакеты клиента с данными. Результат мы считаем по числу байт, которые получил сервер.
|
||
|
||
Номер пакета здесь это номер клиентского пакета с данными, который игрушка увидела: пакеты без данных, например подтверждения, не считаются.
|
||
|
||
Без стратегии «пакетный» и «первый записал» находят имя на первом же пакете, и сервер получает ноль байт. Это контрольная строка: приветствие без всяких приёмов. Остальных трёх читателей без стратегии мы не запускали.
|
||
|
||
С multisplit «пакетный» имя не находит, и сервер получает все двести пятьдесят байт. Четыре читателя, которые собирают данные, находят имя на втором пакете, выбрасывают его, и сервер получает только первые сто четыре байта.
|
||
|
||
Почему именно на втором. После первой части в сто четыре байта имя ещё не собрано, а после второй уже собрано целиком. Вторую часть игрушка выбрасывает, и сервер остаётся с одной первой.
|
||
|
||
С fakedsplit и условием tcp_md5 не находит имя ни один из пяти, и приложение сервера получает все двести пятьдесят байт, равных оригиналу. С fakeddisorder так же. Это наш тест и наши игрушки: разрез и фейки не дали никому из пяти собрать имя.
|
||
|
||
С hostfakesplit картина смешанная. Первый пакет это часть в девяносто семь байт, второй двойник, третий настоящее имя. «Первый записал» и «строго по порядку» держат в руках двойника и не находят настоящее имя: сервер получает всё. А «пакетный», «склейщик» и «последний записал» находят имя на третьем пакете, выбрасывают его, и сервер получает только девяносто семь байт.
|
||
|
||
Проверь себя. Пара «фейк и multisplit»: на каком пакете остановится «последний записал» и сколько байт получит сервер?
|
||
|
||
На четвёртом, на последней настоящей части: до неё имя не собрано. Фейк в шестьсот восемьдесят байт сервер выбросил по MD5, так что дошли часть в один байт и часть в сто три: сто четыре байта. Так же на четвёртом пакете останавливается «склейщик». А «пакетный», «первый записал» и «строго по порядку» имени не находят, и сервер получает всё.
|
||
|
||
![[wiki-anim-video08-s25-toy-in-router.svg|Игрушка в роутере выбрасывает пакеты]]
|
||
|
||
Последняя строка самая поучительная. Fakedsplit без условия: ни один читатель имя не нашёл. Но сервер получил двести пятьдесят байт, и все они нули. Читатель слеп, а соединение разрушено: это разные вещи.
|
||
|
||
![[wiki-anim-video08-s25-toy-results-table.svg|Таблица остановок живых игрушек]]
|
||
|
||
Итак. В нашей игрушечной модели живые читатели подтверждают таблицу: разрез с фейками и условием доводит до сервера все байты, а hostfakesplit и пара «фейк и multisplit» обманывают одних читателей и не обманывают других. Слепота читателя и целостность данных это два разных вопроса. Всё это наш тест и наши игрушки.
|
||
|
||
|
||
## У каждого фейка своя работа: четыре выключателя против шести читателей
|
||
|
||
Вопрос сцены: зачем в fakedsplit целых четыре фейка, и какую работу делает каждый?
|
||
|
||
Игрушка, выдуманная. На двери четыре замка. Чтобы понять, какой замок от какого вора, снимаем их по одному и смотрим, кто войдёт.
|
||
|
||
Фейки номер один и три стоят перед настоящей частью, назовём их «фейки до». Фейки номер два и четыре стоят после неё, назовём их «фейки после». Выключатели nofake один, два, три и четыре убирают их по одному. Эта нумерация записана в коде; у fakeddisorder она другая, о ней дальше.
|
||
|
||
![[wiki-anim-video08-s26-fakes-order-and-name-cells.svg|Четыре фейка и клетки имени]]
|
||
|
||
Разрез посередине имени, midsld, все четыре фейка на месте: слепы все шесть читателей. Уберём фейк один: всё то же, потому что фейк два всё равно затирает конец первой части.
|
||
|
||
Уберём фейк два. Теперь после второй настоящей части имя на миг собрано целиком, и «последний записал», который решает после каждого пакета, его видит. Фейк четыре придёт уже после проверки. По пакетам: после четвёртого, настоящей второй части, имя собрано целиком, после пятого, фейка после неё, затёрто. Читатель, который судит один раз в конце, видит уже затёртое. Это единственный случай, когда одиночное отключение меняет картину: без фейка три или четыре слепы по-прежнему все шесть.
|
||
|
||
Теперь уберём оба фейка до. В нашем тесте остаются только фейки после, и имя видят «первый записал» и «строго по порядку». Фейк, который лежит до настоящей части, занимает место первым, и тот, кто верит первой записи, берёт его. Без него настоящие байты ложатся первыми, и имя собирается целиком.
|
||
|
||
Уберём оба фейка после. Остаются фейки до, и имя видят оба «последних записал». Фейк после затирает настоящие байты нулями, и тот, кто верит последней записи, получает нули. Без него настоящие байты остаются на месте, и имя в конце потока цело.
|
||
|
||
Уберём все четыре: остаётся обычный разрез, и имя видят все, кроме «пакетного». Значит, всё, что мы видели выше, делают именно фейки: замки это фейки, а воры это читатели.
|
||
|
||
Теперь тот же опыт с pos равным host: имя целиком лежит в настоящей второй части. Когда все четыре фейка на месте, имя видят «пакетный», «склейщик» и «последний записал». От первых двух целый настоящий пакет ни один фейк в наших запусках не спрятал.
|
||
|
||
Проверь себя. Fakedsplit с pos равным host, tcp_md5 и nofake три. Кто видит имя?
|
||
|
||
К «пакетному», «склейщику» и «последнему записал» добавляются «первый записал» и «строго по порядку»: фейк три, который их ослеплял, убран. «Судит в конце» остаётся слеп: фейк четыре стоит после второй части и затирает её. Это строка нашего теста, про нашу модель, не про настоящее оборудование. А если убрать фейк четыре, «судит в конце» тоже увидит имя.
|
||
|
||
![[wiki-anim-video08-s26-switch-table.svg|Выключатели против шести читателей]]
|
||
|
||
Итак. В нашей игрушечной модели фейк перед настоящей частью ослепляет читателей, которые верят первой записи, фейк после неё тех, кто верит последней, а разрез ослепляет «пакетного». Целый настоящий пакет в наших запусках не спрятан ни от «пакетного», ни от «склейщика». Для настоящего оборудования мы этого не знаем.
|
||
|
||
|
||
## Где стоит читатель: фейки, которые не доходят, и правило с фиксированным местом
|
||
|
||
Вопрос сцены: всегда ли читатель видит фейки? Напоминание: все эти результаты про наши модели и наш приёмник.
|
||
|
||
Игрушка, выдуманная. Письмо с просроченной маркой возвращают с полпути. Вахтёр, который стоит дальше места возврата, такого письма не увидит. Важно не только что лежит в письме, но и где стоит вахтёр.
|
||
|
||
Наши онлайн-игрушки стоят в роутере на пути вперёд. Фейк со сроком жизни один доходит до входа в роутер, роутер отвечает клиенту сообщением ICMP и выбрасывает фейк. До игрушки он не добирается.
|
||
|
||
![[wiki-anim-video08-s27-ttl1-dies-before-toys.svg|Срок жизни 1: фейки не доходят до игрушек]]
|
||
|
||
Fakedsplit со сроком жизни один: игрушки видят только две настоящие части, как при обычном разрезе. Четыре читателя, которые собирают данные, находят имя на втором пакете, и сервер получает сто четыре байта. «Пакетный» имя не находит, и сервер получает всё.
|
||
|
||
Hostfakesplit со сроком жизни один: настоящее имя лежит в своём пакете, а фейков игрушки не видят. Все пять находят имя на втором пакете, и сервер получает девяносто семь байт.
|
||
|
||
Урок про модель. Помогает ли фейк, зависит от того, видит ли его читатель, то есть от места читателя относительно точки, где фейк умирает. Где стоит настоящее оборудование, мы не знаем.
|
||
|
||
Заметьте разницу с таблицей читателей. Запись у входа в роутер, которую читали все шесть, содержит и фейки со сроком жизни один: они доходят до входа и умирают на роутере. Живая игрушка стоит дальше, за роутером, и их не видит.
|
||
|
||
Теперь второй вид читателя: правило из выпуска «multisplit: резать на части». Оно смотрит одно фиксированное место в пакете, там, где в обычной отправке нашего приветствия начинается имя: в нашем тесте заголовок TCP занимает тридцать два байта, и правило читает со сто двадцать девятого байта от его начала. Без стратегии в нашем тесте счётчик правила равен шести: приветствие и пять повторов клиента. Сервер не получил ничего.
|
||
|
||
С multisplit, fakedsplit, fakeddisorder, fakedsplit с pos равным host и hostfakesplit счётчик равен нулю, а сервер получил все двести пятьдесят байт.
|
||
|
||
Проверь себя. Правило не сработало на hostfakesplit и на fakedsplit с pos равным host, хотя «пакетный» там видит имя. Почему?
|
||
|
||
Настоящее имя лежит в начале своего пакета. «Пакетный» ищет по всему пакету и находит его. Правило смотрит на место девяносто седьмого байта данных пакета. В пакете с настоящим именем имя начинается с нулевого байта, а на девяносто седьмом лежат другие байты или данных там уже нет.
|
||
|
||
![[wiki-anim-video08-s27-fixed-offset-rule.svg|Правило с фиксированным местом]]
|
||
|
||
Правило с одним местом и читатель, который ищет по всему пакету, это разные инспекторы. Приём может обмануть одного и не обмануть другого.
|
||
|
||
Теперь границы наших игрушек. Они ищут фиксированные пятнадцать байт и не разбирают ни TLS, ни HTTP. Они выбрасывают пакет, а настоящее устройство могло бы сбросить соединение или замедлить его; у наших игрушек нет ни таймеров, ни предела буфера. Читатель, который проверяет MD5, сумму или правдоподобие номеров, был бы другой моделью. Такие игрушки мы строили в выпуске «Фейк и его условия»: каждая из них видела причину, по которой получатель выбросит фейк. Здесь мы их не запускали, поэтому «слепы все шесть» верно только для читателей, которые условие фейка не проверяют.
|
||
|
||
Итак. Положение читателя решает, увидит ли он фейк. Наши модели ничего не говорят о настоящем ТСПУ.
|
||
|
||
|
||
## Код: fakedsplit, fakeddisorder и hostfakesplit
|
||
|
||
Вопрос сцены: как fakedsplit, fakeddisorder и hostfakesplit устроены в коде? Теперь, когда мы знаем, что искать, код читается быстро.
|
||
|
||
Игрушка, выдуманная. Карточка с рецептом из шести шагов: пустышка, настоящая половина, пустышка, и то же для второй половины. Код и есть эта карточка.
|
||
|
||
Функция получает два параметра, ctx и desync, как всякая стратегия. Дальше ворота: не TCP, не то направление, не то содержимое, и функция выходит. Ворота знакомы по выпуску «multisplit: резать на части».
|
||
|
||
Позиция. Первая строка берёт аргумент pos, а если его нет, строку «два». Вторая отдаёт её переводчику меток, и тот возвращает одно число по счёту Lua, с единицы. Если оно равно единице, перед первым байтом резать нечего: функция пишет «разрезать нельзя» и ничего не отправляет. Так pos равное нулю даёт целое приветствие.
|
||
|
||
![[wiki-anim-video08-s28-fakedsplit-code-six-sends.svg|Код fakedsplit: шесть отправок]]
|
||
|
||
Две таблицы настроек. Первая для настоящих частей: из набора условий в ней только tcp_ts_up, условие про метку времени. Вторая для фейков: весь набор, и условия, и повторы, и испорченная сумма. Вот почему условие и repeats касаются только фейков.
|
||
|
||
Первая половина. Фейк первой части: функция pattern берёт узор с начала и режет на длину «позиция минус один»; он отправляется со смещением ноль. Настоящая первая часть: срез данных от первого байта до позиции, не включая её. Потом тот же фейк ещё раз.
|
||
|
||
Вторая половина. Фейк второй части берёт узор с фазы позиции и режет на остаток, затем настоящая вторая часть и фейк ещё раз. Шесть вызовов отправки: ровно шесть пакетов нашего теста. Перед каждым фейком стоит проверка ключа nofake; достаточно, чтобы ключ был, даже nofake равное нулю выключает фейк.
|
||
|
||
Конец, первое. Вызов запоминает, что сообщение уже отправлено частями; это нужно для длинных приветствий, которые программа собирала сама, и о нём говорит выпуск «Сборка и повторный проигрыш».
|
||
|
||
Конец, второе. Функция возвращает программе ответ, «вердикт»: выбросить оригинал, а с nodrop пропустить. Как программа сводит ответы нескольких экземпляров, расскажет выпуск «Lua внутри программы».
|
||
|
||
Fakeddisorder: те же шесть кусков, порядок другой. Фейк второй части, настоящая вторая, фейк второй, фейк первой, настоящая первая, фейк первой. Номера выключателей идут в новом порядке: nofake один это первый фейк второй части.
|
||
|
||
Главное отличие в порядке, второе в seqovl: здесь это метка, а в fakedsplit только число. Метка идёт к тому же переводчику, и полученное смещение становится длиной накладки. Если накладка не меньше разреза, её отменяют. Иначе по умолчанию перед второй частью кладутся нули, и пакет уходит на столько байт раньше. В нашем тесте с seqovl равным host накладка в девяносто семь байт, пакет в двести сорок три байта начинается со смещения семь, и сервер прочитал настоящее приветствие.
|
||
|
||
![[wiki-anim-video08-s28-seqovl-label-and-hostfakesplit.svg|Накладка как метка и hostfakesplit]]
|
||
|
||
Проверь себя. 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, тот вызывает разборщик метки, и разборщик первым делом пробует прочитать всю строку как число.
|
||
|
||
![[wiki-anim-video08-s29-text-to-number.svg|Как текст метки становится числом]]
|
||
|
||
Функция разбора числа принимает строку, только если первый знак плюс, минус или цифра, и отдаёт её стандартной функции языка Си atoi. Atoi читает цифры и останавливается на первом знаке, который цифрой не является. Всё, что после, она не видит и об этом не сообщает. Так «один, midsld» становится единицей.
|
||
|
||
Ещё примеры из прогона функций. «Два, запятая, midsld» даёт два. «Минус три, запятая, midsld» даёт минус три, то есть счёт от конца. «Два точка пять» даёт два, потому что точка не цифра.
|
||
|
||
Если первый знак не цифра, начинается второй путь. Имя метки это текст до первого плюса или минуса. В «midsld, host» ни плюса, ни минуса нет, значит именем считается вся строка вместе с запятой, а такого имени нет. Разборщик отвечает «не вышло», и переводчик останавливается с ошибкой «плохая метка».
|
||
|
||
А в «midsld плюс один, запятая, host» имя midsld, и остаток «плюс один, запятая, host» читается как плюс один: atoi остановится на запятой. Host уже не виден. Последняя строка переводчика прибавляет единицу, и получается позиция по счёту Lua.
|
||
|
||
Почему multisplit список принимает? Он зовёт переводчика списка, который режет строку по запятым и разбирает каждую метку отдельно, как в выпуске «multisplit: резать на части». А hostfakesplit зовёт переводчика диапазона: ему нужны ровно две метки, host и endhost минус один.
|
||
|
||
Теперь пара в программе. Для одного пакета программа берёт экземпляры профиля по порядку записи и вызывает каждую функцию по имени. Перед каждым вызовом для экземпляра заново записываются его аргументы и имя, а запись о пакете одна общая. Поэтому счётчик идентификатора IP продолжается из экземпляра в экземпляр: в нашей паре четыре пакета получили четыре идентификатора подряд.
|
||
|
||
![[wiki-anim-video08-s29-pair-in-engine.svg|Пара стратегий внутри программы]]
|
||
|
||
Ответы. Fake ничего не возвращает, multisplit возвращает «выбросить». Если хоть один сказал «выбросить», оригинал выбрасывается, а остальные экземпляры всё равно выполняются. Но если функция упала с ошибкой, как в ловушке списка, оставшиеся экземпляры для этого пакета не запускаются, и уходит оригинал. Для пары это значит: ошибка в первом экземпляре отменяет второй; так следует из кода, в лаборатории такой пары не было.
|
||
|
||
Проверь себя. Fakedsplit с nodrop: что уйдёт в сеть?
|
||
|
||
Шесть пакетов, а следом оригинальное приветствие: ответ «пропустить» оригинал не выбрасывает. В нашем тесте так и вышло, а сервер ответил на оригинал блоком, которым говорит: этот кусок у меня уже был.
|
||
|
||
Итак. Список превращается в число потому, что разбор числа читает цифры и молча останавливается. Пара работает, потому что программа выполняет экземпляры по порядку и выбрасывает оригинал, если так ответил хоть один.
|
||
|
||
|
||
## Итог выпуска и что дальше
|
||
|
||
Остановимся и сведём всё, что мы узнали в этой части. Всё это в нашем тесте, на одном приёмнике, Linux, и в нашей игрушечной модели. О настоящем оборудовании мы по-прежнему ничего не знаем.
|
||
|
||
Первое. Две стратегии на одном пакете выполняются по порядку записи, и аргументы у каждой свои. Фейк впереди кладёт подделку перед данными, фейк в конце после них. Без условия фейк в паре ломает соединение, а с условием он в нашем тесте умирает рядом с четырьмя разрезающими стратегиями.
|
||
|
||
Второе. Pos в fakedsplit и fakeddisorder это одна метка: список с числа молча становится числом, список с имени и запятой даёт ошибку и целое приветствие. Hostfakesplit pos не читает, ipfrag не работает у всех трёх, repeats и badsum касаются только фейков.
|
||
|
||
Третье. Шесть игрушечных читателей. Разрез ослепляет «пакетного». Если имя целиком в одной настоящей части, «пакетный» и «склейщик» видят его во всех наших запусках. Слепота читателя не значит целость данных: без условия сервер получал нули.
|
||
|
||
Четвёртое. У каждого фейка своя работа: фейк до настоящей части ослепляет тех, кто верит первой записи, фейк после неё тех, кто верит последней.
|
||
|
||
Пятое. Положение читателя решает: фейк, который умер раньше, чем дошёл до читателя, ему не виден. А правило с одним местом и читатель, который ищет по всему пакету, это разные инспекторы.
|
||
|
||
Шестое. В коде это шесть отправок с двумя таблицами настроек, диапазон имени, генератор двойника и разбор метки, который читает число и молча останавливается. Пара в программе это все экземпляры по порядку, а ошибка в одном отменяет остальные для этого пакета.
|
||
|
||
![[wiki-anim-video08-s30-part-cheat-sheet.svg|Шпаргалка части: восемь строк]]
|
||
|
||
Проверь себя. Вы хотите спрятать имя от «пакетного» и запускаете hostfakesplit без midhost. Получится?
|
||
|
||
Нет. Настоящее имя лежит целым в своём пакете, и «пакетный» находит его там. Чтобы спрятать имя от него, имя нужно разрезать: pos в fakedsplit, указывающий внутрь имени, или midhost в hostfakesplit.
|
||
|
||
Теперь о том, чего мы не знаем. Мы не знаем, как устроен настоящий инспектор: что он читает, где стоит, видит ли фейки и какую копию считает главной. Мы не знаем, как поведёт себя другой получатель: мы проверили только Linux, а Windows, BSD и встроенные системы нет. Мы не пробовали IPv6 и не запускали версию для Windows. И мы пробовали лишь три условия: опцию MD5, срок жизни один и испорченную сумму; остальные условия и их сочетания остались без запусков.
|
||
|
||
![[wiki-anim-video08-s30-unknown-and-next.svg|Чего мы не знаем и что дальше]]
|
||
|
||
Следующий выпуск называется «Фокусы рукопожатия». До сих пор мы работали с данными, когда соединение уже установлено. Теперь посмотрим на приёмы вокруг самого начала соединения: что можно сделать до первого байта данных, срочный байт и ложное окно.
|
||
|
||
Весь выпуск в одной фразе. Разрез прячет имя от читателя, который смотрит пакеты по одному, фейк с условием не доходит до приложения, три функции склеивают это в серию, а условие обязательно: без него сервер в нашем тесте принимает фейк всерьёз. Всё сказанное про эффект относится к нашему приёмнику и нашим игрушкам.
|
||
|
||
## См. также
|
||
|
||
- [[07-fake-i-ego-usloviya|Фейк и его условия]] — предыдущее видео серии
|
||
- [[fakedsplit]] — справочная статья о функции
|
||
- [[fakeddisorder]] — справочная статья о функции
|
||
- [[hostfakesplit]] — справочная статья о функции
|
||
- [[ts-and-fooling]] — подмена полей пакета и условия
|
||
|
||
---
|
||
|
||
> [!quote] 🤖 Эти статьи открыты — можно обучать на них ИИ
|
||
> При желании вы можете натренировать ИИ на наших статьях. Исходное форматирование доступно в Forgejo: [исходник этой заметки](https://git2.zapret.moe/zapretdiscordyoutube/todo/src/branch/main/Zapret2/video/08-rezat-i-poddelyvat-vmeste.md) · [скачать весь репозиторий одним zip-архивом](https://git2.zapret.moe/zapretdiscordyoutube/todo/archive/main.zip).
|