Zapret: what's new

Появился blockcheck2.
Его основное отличие от blockcheck1 - модульность.
Есть директория blockcheck2.d . В ней субдиректории. Каждое имя субдиректории - это имя теста.
Тест выбирается в процессе запуска blockcheck2.
Внутри директории теста в алфавитном порядке выполняются все скрипты. Каждый скрипт может иметь функции, предназначенные для проверки http, tls1.2, tls1.3 и quic.

standard - это тестилка стратегий, похожая на blockcheck1, но разнесенная по файлам.
Все блоки тестов имеют соответствующую переменную для отказа от данного теста. См код *sh скриптов.
Поддерживается передача кастомных блобов на разные случаи жизни. Так же см код скриптов

custom - тестилка стратегий из простого списка из файла. файлы разнесены по протоколам. можно заменить к ним путь.

Параметры PKTWS_EXTRA и PKTWS_EXTRA_N переименованы в PKTWS_EXTRA_POST и PKTWS_EXTRA_POST_N.
PKTWS_EXTRA_PRE и PKTWS_EXTRA_PRE_N остались как есть. В zapret2 порядок вызова lua инстансов имеет принципиальное значение !

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

Сделал пример кастома для обслуживания типичного веб сервера.
Бывает сложно пробиться только с клиента, потому что секут ответы сервера.
Если сервер под контролем, можно и с него обманывать DPI. Конечно, это не замена клиентскому дурению, а дополнение для точечного пробива. По понятным причинам это невозможно применить ко всем серверам.

В дефолтной стратегии применяется техника tcp split handshake - разбив ответа SYN,ACK на отдельные пакеты SYN и ACK. По http reply и server hello отрабатывает fake+multisplit

Параметр ‘–server’ заменяет логику интерпретации ip/port источника приемника, чтобы корректно матчились ipset-ы и --filter-tcp/–filter-udp. Так же инвертируются логические направления tcp : out по умолчанию считается от источника пакета SYN, а в серверном режиме - наоборот. in, соответственно, тоже инвертируется

# this custom script runs nfqws2 in server mode for typical webserver

WEBSERVER_DEFAULT_STRATEGY="
--server
--payload http_reply,tls_server_hello --lua-desync=fake:blob=0x00000000000000000000000000000000:badsum:repeats=2 --lua-desync=multisplit
--payload empty --lua-desync=synack_split"

# can override in config :
NFQWS_OPT_DESYNC_WEBSERVER="${NFQWS_OPT_DESYNC_WEBSERVER:-$WEBSERVER_DEFAULT_STRATEGY}"
WEBSERVER_PORTS="${WEBSERVER_PORTS:-80,443}"
WEBSERVER_PKT_OUT="${WEBSERVER_PKT_OUT:-15}"

alloc_dnum DNUM_WEBSERVER
alloc_qnum QNUM_WEBSERVER

zapret_custom_daemons()
{
	# $1 - 1 - add, 0 - stop

	local opt="--qnum=$QNUM_WEBSERVER $NFQWS_OPT_DESYNC_WEBSERVER"
	do_nfqws $1 $DNUM_WEBSERVER "$opt"
}
zapret_custom_firewall()
{
        # $1 - 1 - run, 0 - stop

	local PORTS=$(replace_char - : $WEBSERVER_PORTS)
	local first_packets=$(ipt_first_packets $WEBSERVER_PKT_OUT)
	local f="-p tcp -m multiport --sports $PORTS $first_packets"
	fw_nfqws_post $1 "$f" "$f" $QNUM_WEBSERVER
}
zapret_custom_firewall_nft()
{
        # stop logic is not required

	local first_packets=$(nft_first_packets $WEBSERVER_PKT_OUT)
	local f="tcp sport {$WEBSERVER_PORTS} $first_packets"
	nft_fw_nfqws_post "$f" "$f" $QNUM_WEBSERVER
}

Инсталятор и скрипты запуска адаптированы.
Осталась дока.

Задали вопрос как сделать автоматию.
Если что-то там происходит, то применять одну стратегию, а если происходит другое - другое.
Конечно, это все можно написать на LUA.
Но хотелось бы использовать существующие функции без правки.
Придумал вот такую схему. Называется desync orchestration.

C функция execution_plan(ctx) возвращает таблицу с информацией о предстоящих вызовах (имена и номера функций, имена инстансов, аргументы инстансов).
lua-desync функция может отменить текущий execution plan C функцией execution_plan_cancel(ctx). После отмены по текущему пакету все последующие инстансы не будут вызваны.
Функция, отменяющая план выполнения, берет на себя функции планирования (оркестрации) дальнейших действий. Она знает как и с какими параметрами что вызывать (или не вызывать по собственному решению). Конечно, при этом отваливаются фильтры по range и payload на уровне C кода. Точнее, C код ничего не знает об оркестрации, для него все функции идентичны, поэтому по реально вызываемым инстансам будет работать последний фильтр.
Но оркестратор может взять эту функцию на себя, благо ему доступно состояние conntrack и тип пейлоада.
А что делать с cutoff ? cutoff можно вызывать либо по инстансу/направлению индивидуально (только по текущему инстансу) через instance_cutoff(ctx), либо отрубить все направление по соединению через C функцию lua_cutoff(ctx).

Допустим, надо сечь ретрансмисии. Ретрансмиссия - это повторная передача пакетов в том же диапазоне sequence numbers.
Для анализа sequence numbers есть desync.track.tcp, для подсчета ретрансмиссий можно использовать desync.track.lua_state - persistent таблицу по соединению.
Для пометки инстансов одной стратегии использовать тэг-аргументы типа --lua-desync=func:args...:tag=strategy1

Оркестратор считает ретрансмиссии. Пока счетчик не превысил порог - вызывает инстансы с аргументом tag=strategy1, после - инстансы с tag=strategy2.
Если еще что-то случается, и он решает, что дальше делать нечего, делает соединению lua_cutoff. Так рубится вся цепочка инстансов по соединению. Но можно использовать и range/payload фильтры из C кода перед оркестратором - они так же будут работать. Не будут работать только индивидуальные range/payload фильтры по истансам после оркестратора, поскольку они не вызываются из C кода.

Пример простейшего оркестратора добавлен в zapret-lib.lua. Он ничего не делает, просто вызывает все последующие инстансы, подготавливая для них корректную desync таблицу.

MDIG cache был давно сломан в blockcheck1, проблема перешла и в blockcheck2
fixed now

Вопрос комьюнити по около-запрету.
Я не знаю как пробиваться к разработчикам подсистем linux. Надо пробиться к разрабам wireless subsystem. На багтрак никто не реагирует. Куда стучать ?

С ядра 5.19 сломалась выдача SSID через nl80211, хотя через wext работает.
но wext скоро совсем отдохнет, --filter-ssid превратится в тыкву. он уже превратился на дистрибутивах, где выключают wext. На android это легко может случиться по мере обновления ядер, спасает только пока, что в основном ядра там достаточно старые

# iwgetid
wlan0     ESSID:"my_cool_wifi"

# iw dev wlan0 info
Interface wlan0
        ifindex 4
        wdev 0x1
        addr 00:11:22:33:44:55
        type managed
        wiphy 0
        channel 13 (2472 MHz), width: 20 MHz, center1: 2472 MHz
        txpower 20.00 dBm
        multicast TXQ:
                qsz-byt qsz-pkt flows   drops   marks   overlmt hashcol tx-bytes        tx-packets
                0       0       0       0       0       0       0       0               0

На более старых ядрах на том же железе во-второй команде выдается ssid. 6.17 - все еще сломано

Реализована поддержка имен профилей (names) и шаблонов профилей (templates).
template - это тоже профиль, принимающий в себя все настройки профиля, но он не идет в список рабочих профилей. Профиль является шаблонными, если в пределах его определения (между --new) присутствует параметр --template.
templates выносятся в отдельный список, чтобы потом из него можно было импортировать настройки. Шаблонному профилю обязательно назначается уникальное имя (–name), после чего его можно импортировать в рабочий профиль (–import=name). Процедура импорта стирает все данные текущего профиля, замещая данными шаблона (включая имя), поэтому --import надо указывать в самом начале после --new. Остальные настройки добавляются к импортированным.

Импорт нескольких шаблонов с наложением не реализован. Однако, шаблоны - тоже полноправные профили и могут импортировать другие шаблоны. Здесь будет 2 шаблона и 1 рабочий профиль, который выполнит 3 инстанса

--template --name t1 --lua-desync=pass --new
--template --import t1 --name t2 --lua-desync=posdebug --new
--import t2 --name template_test --lua-desync=argdebug:test1=1:test2=2
profile 1 (template_test) lua pass( range_in=x0-x0 range_out=a0-a0 payload_type= all)
profile 1 (template_test) lua posdebug( range_in=x0-x0 range_out=a0-a0 payload_type= all)
profile 1 (template_test) lua argdebug(test2="2",test1="1" range_in=x0-x0 range_out=a0-a0 payload_type= all)
template 1 (t1) lua pass( range_in=x0-x0 range_out=a0-a0 payload_type= all)
template 2 (t2) lua pass( range_in=x0-x0 range_out=a0-a0 payload_type= all)
template 2 (t2) lua posdebug( range_in=x0-x0 range_out=a0-a0 payload_type= all)

Убрана детализация пейлоада stun_binding_req.
Любые stun сообщения теперь имеют пейлоад “stun”.

Первое практическое применение концепции оркестраторов.
Пришлось кое-что еще добавить. Поскольку ctx передавать оркестрируемым функциям нельзя, т.к. они будут действовать от имени оркестратора, им передается nil.
Но тогда они не могут делать instance cutoff, на котором основана часть их логики.
Пришлось заменить везде вызовы instance_cutoff на instance_cutoff_shim.
shim вызывает instance_cutoff(ctx), если ctx есть, а иначе откатывается на альтернативный вариант собственной lua реализации через desync.track.lua_state

Файл zapret-auto.lua. Орекстратор circular.
Он делает примерно то же самое, что автолист чекер в C коде.
Но в случае обнаружения “неоткрывшегося” сайта происходит переход от стратегии 1 к 2. Если и там не открылся - к стратегии 3. Если номера стратегий закончились, идет переход снова к 1. От этого и название - circular. Но можно поставить в последней стратегии “final”, и тогда перехода к 1 не будет.
Это если очень по-пользовательски, по-понятному обьяснять.
Технически же еще можно много слов тут настрочить.

Простейший тест-пример, иллюстрирующий работу.

nfqws2 --qnum 200 --debug
--lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua
--in-range=-s1
--lua-desync=circular
--lua-desync=argdebug:strategy=1
--lua-desync=argdebug:strategy=2

circular берет на себя выполнение execution plan.
он имеет дело с двумя хранилищами stateful данных.
1 - глобальное с индексом по имени хоста или ip в случае отсутствия хоста.
2 - привязанное к соединению в desync.track.lua_state

круговой обход стратегий осуществляется индивидуально по хостам. по каждому хосту хранится состояние какая для него текущая стратегия.
стратегии разделяются через задание номера в параметре strategy всех последующих за оркестратором desync инстансов. так он знает какая функция относится к какому номеру.

есть понятие неудачи (failure). неудача - это когда условно говоря сайт не открылся, подает признаки блокировки.

  1. Ретрансмиссии в указанных пределах sequence numbers (64K от начала соединения по умолчанию). Это уже выходит за рамки возможностей чекера автолиста и позволяет сечь 16к блоки.
  2. RST в пределах указанных ack sequence (1 по умолчанию, то есть RST без входящих данных)
  3. Традиционно - http редирект на домен второго уровня, не совпадающий с доменом второго уровня исходного хоста

Для 2 и 3 ему нужны входящие данные, поэтому ставиться --in-range, пропускающий до первого пакета данных (включительно). Естественно, трафик нужен перенаправить средствами firewall / windivert фильтра.
Конструктор windivert фильтров и так пропускает входящие RST,FIN,SYN и пакеты данных tcp с http ответом redirect. Специально ничего делать не надо. --wf-tcp-in был бы большой глупостью, грузящий проц без толку.

Ведется счетчик неудач. Если происходят fails неудач (3 по умолчанию) и между ними не более time секунд (60 по умолчанию), то происходит ротация стратегии. Если с предыдущей неудачи прошло больше времени - счетчик неудач сбрасывается

Параметры орекстратора

-- arg: fails=N - failture count threshold. default is 3
-- arg: retrans=N - retrans count threshold. default is 3
-- arg: seq=<rseq> - if packet is beyond this relative sequence number treat this connection as successful. default is 64K
-- arg: rst=<rseq> - maximum relative sequence number to treat incoming RST as DPI reset. default is 1
-- arg: time=<sec> - if last failure happened earlier than `maxtime` seconds ago - reset failure counter. default is 60.

Практический пример автолиста в памяти , без записи в файл.

nfqws2 --qnum 200 --debug
--lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua --lua-init=@zapret-auto.lua
--in-range=-s1
--payload tls_client_hello,http_req,http_reply
--lua-desync=circular
--in-range=x
--lua-desync=pass:strategy=1
--payload tls_client_hello --lua-desync=fake:blob=fake_default_tls:badsum:strategy=2
--payload http_req --lua-desync=fake:blob=fake_default_http:badsum:strategy=2

Сначала применяется стратегия, не делающая ничего.
Если сайт не открывается, применяется стратегия с фейком.

–in-range нужен только для окестратора. дальше он гасится через --in-range=x.
payload http_reply так же нужен только для орекстратора, чтобы он видел http redirect

Логи

* lua 'circular_1_1' : in pos a0 s1 in range a0-s1
* lua 'circular_1_1' : payload_type 'http_reply' satisfy filter
* lua 'circular_1_1' : desync
execution plan cancel from 'circular_1_1'
LUA: circular: http redirect 302 to 'https://www.ПРОВАЙДЕР/ЗАГЛУШКА'
LUA: automate: failure counter 3/3
LUA: circular: rotate strategy to 2
LUA: circular: current strategy 2
LUA: circular: not calling 'fake_1_3' because payload 'http_reply' does not match filter 'tls_client_hello'
LUA: circular: not calling 'fake_1_4' because payload 'http_reply' does not match filter 'http_req'
* lua 'circular_1_1' : out pos a0 a0 in range a0-a0
* lua 'circular_1_1' : payload_type 'http_req' satisfy filter
* lua 'circular_1_1' : desync
execution plan cancel from 'circular_1_1'
LUA: circular: current strategy 2
LUA: circular: not calling 'fake_1_3' because payload 'http_req' does not match filter 'tls_client_hello'
LUA: circular: executing 'fake_1_4'
LUA: instance_cutoff_shim: cutoff 'fake_1_4' in=true out=false
LUA: fake: 47 45 54 20 2F 20 48 54 54 50 2F 31 2E 31 0D 0A 48 6F 73 74 3A 20 77 77 77 2E 69 61 6E 61 2E 6F ... GET / HTTP/1.1..Host: www.iana.o ...
rawsend_dissect repeats=1 size=315 badsum=0 ifout=br0 fwmark=40000000

Переработана, упрощена и унифицирована схема детекта ретрансмиссий.
Точки детекта 2 : C код автолистов и lua код орекестраторов.

Если ранее в C коде автолистов считались ретрансмиссии только в диапазоне TLS запроса (вместе с кибер пакетами всеми), то теперь они считаются в диапазоне relative seq от 0 до нового параметра nfqws2 --hostlist-auto-retrans-threshold , конфиг AUTOHOSTLIST_RETRANS_MAXSEQ. По умолчанию 65536.
То есть в диапазоне первых 64 кбайт переданных данных. После чего соединение считается успешным и ретрансмиссии не детектятся.
Это позволяет работать по блокам 16к и регулируется.

В оркестраторе circular аналогичная схема с похожими параметрами.

Для упрощения детекта ретрансмиссий добавлено отслеживание в conntrack значений “uppos” по направлениям orig,reply. uppos - это максимальный сиквенс, на который когда-либо залезали передаваемые по направлению данные. Под “залезали” считается seq за последним байтом последнего переданного пакета. Так же сохраняется предыдущее значение uppos.
Поэтому всегда легко сравнить pos с uppos_prev. Если он меньше uppos_prev, значит это ретрансмиссия.

Вычисление разницы sequence требует особой логики. Sequence - это 32 битные unsigned номера.
Просто сравнивать их нельзя как числа. Они увеличиваются без учета переноса за разрядную сетку 32 бит.
Например, значение 0xFFFFFFF0 (более 4 миллиардов) не больше, а меньше 5.

В zapret-lib.lua сделана функция для определения является ли текущий диссект ретрансмиссией.

function is_retransmission(desync)
	return desync.track and desync.track.tcp and 0==bitand(u32add(desync.track.tcp.uppos_orig_prev, -desync.track.tcp.pos_orig), 0x80000000)
end

Кто понимает в машинной арифметике - поймет

Сделана поддержка udp в standard_failure_detector и как следствие в оркестраторе circular.
Она работает очень просто.
Если на выход ушло >=udp_out пакетов, а на входе пришло <=udp_in пакетов, значит неудача.
Мы шлем, нам не отвечают.
По умолчанию 3 ушло, <=1 пришло

На quic вполне себе работает с параметрами по умолчанию.

Реализована система вложенной оркестрации.
Для этого первый оркестратор выполняет execution_plan/execution_plan_cancel
и запоминает таблицу plan в desync.
Если последующий оркестратор видит desync.plan, он берет его оттуда. Он и не сможет выполнить cancel, потому что ему передается ctx=nil. Инстансы имеют ctx только до тех пор, пока их вызывает C код. ctx - это связь с C кодом. После cancel она обрывается, nfqws2 забывает о последующих инстансах, и lua код должен уметь работать в таких условиях.
Для этого в zapret-lib предусматриваются различные прокладки (shims), которые прозрачно заменяют механизмы C кода на дублирующие механизмы lua.

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

Оркестратор condition. Выполняет replay_execution_plan, если функция “iff”, имя которой передается в аргументе, возвращает значение true (или false, если задан аргумент ‘neg’). В противном случае очищает execution plan.
Может быть полезен для протокольных детекторов lua. “iff” функция может детектить какой-то протокол, детект которого не зашит в nfqws2.

тест-пример

nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua
--lua-desync=condition:iff=cond_random
--lua-desync=argdebug:testarg=1
--lua-desync=argdebug:testarg=2:morearg=blablabla

Оркестратор stopif. Очищает execution plan, если функция “iff”, имя которой передается в аргументе, возвращает значение true (или false, если задан аргумент ‘neg’).
Чем это отличается от condition ? Оркестраторы ничего не знают друг о друге. Если, допустим, у вас circular , и в какой-то стратегии вы захотите поставить условие на эту стратегию, то condition вопрос не решит. Он либо прекратит выполнение, либо выполнит все оставшиеся функции от всех стратегий, потому что ничего не знает о параметре “strategy” оркестратора circular. Но stopif вопрос решает. Если выполняется условие, сносится plan, circular прекращает выполнение инстансов. А если не выполняется, то circular продолжает выполнять plan дальше, как будто бы stopif не существовало. Надо только самому stopif поставить strategy=N, чтобы circular его считал частью стратегии.

nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua
--in-range=-s1
--lua-desync=circular
--in-range=x
--lua-desync=stopif:iff=cond_random:strategy=1 --lua-desync=argdebug:strategy=1
--lua-desync=argdebug:strategy=2

Цель создания подобных кирпичиков - универсализировать создание кастомных стратегий и избавить от необходимости переписывания/дублирования не относящегося к стратегиии кода.
Чтобы добавить фильтр протокола “openvpn” без доделывания nfqws2, вам нужно лишь написать протокольный детектор и применить condition/stopif в зависимости от ситуации

Пример протокольного детектора. Ищет подстроку в пейлоаде, заданную в аругменте “pattern”.

function cond_payload_str(desync)
	if not desync.arg.pattern then
		error("cond_payload_str: missing 'pattern'")
	end
	return string.find(desync.dis.payload,desync.arg.pattern,1,true)
end
nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua
--lua-desync=condition:iff=cond_payload_str:pattern=1234
--lua-desync=argdebug:testarg=1

echo aaz1234zzz | ncat -4u 1.1.1.1 443
echo aaze124zzz | ncat -4u 1.1.1.1 443

Конечно, можно пойти и иным путем. Можно вызвать подобную функцию в формате --lua-desync.
Она перепишет desync.l7payload и desync.l7proto, чтобы дальнейшие инстансы могли проверять новый тип пейлоада и протокола сеанса. В стандартных antidpi функциях есть аргументы “standard payload”. Они как раз и работают с desync.l7payload. (правда, о новом типе пейлоада C код не узнает, --payload не станет его принимать, но на уровне lua функций фильтр будет работать)

Но кто сказал, что здесь может быть только протокольный детектор ? Здесь может быть что угодно. Любое вообразимое условие, которое можно запрограммировать в lua коде.
Например, вам надо поймать SYN,ACK в ответ на SYN. Можно через range, а можно написать iif функцию

Несовместимое изменение на lua_compat_ver 3.

Полностью переработано представление позиций в desync.track.
Набор позиций по направлению выделен в отдельную структуру.
Всего передается 2 набора через desync.track.pos, представленные 4 полями таблице.
2 набора - это client и server. Они определяются по роли в установлении соединения.
client для tcp - тот, кто отсылает SYN или принимает SYN,ACK
server для tcp - тот, кто отсылает SYN,ACK или принимает SYN
client для udp - тот, кто отсылает первый пакет по двум парам ip/port или тот, от кого принимается первый пакет
server для udp - тот, кто принимает первый пакет по двум парам ip/port или тот, кому он отсылается

с client и server не всегда удобно иметь дело, потому что существует еще и серверный режим, в котором поле “desync.outgoing” ставновится true для ответов сервера, то есть для того, что он должен отсылать. для клиента out - это запрос (http_req). для сервера out- это ответ (http_reply)

Поэтому те же самые таблицы представляются и под другими именами - direct и reverse.
direct относится к текущему направлению - in или out, reverse - к обратному.
Текущее направление определяется признаком desync.outgoing.
Так сделано, чтобы не вшивать в LUA код везде однотипные проверки. Какой блок позиций брать - client или server зависит от признака desync.outgoing и параметра --server. Чтобы не думать и не дублировать логику - те же таблицы разнесены под именами direct и reverse.
В большинстве случаев вам понадобится direct

Так выглядит новый вариант desync.track

LUA: .track
LUA:   .l7proto
LUA:     string http
LUA:   .hostname_is_ip
LUA:     boolean false
LUA:   .lua_in_cutoff
LUA:     boolean false
LUA:   .lua_out_cutoff
LUA:     boolean false
LUA:   .t_start
LUA:     number 170000000
LUA:   .pos
LUA:     .reverse
LUA:       .pbcounter
LUA:         number 69
LUA:       .tcp
LUA:         .mss
LUA:           number 1460
LUA:         .rseq
LUA:           number 71
LUA:         .scale
LUA:           number 8
LUA:         .seq
LUA:           number 3333333333
LUA:         .pos
LUA:           number 71
LUA:         .seq0
LUA:           number 4444444444
LUA:         .uppos
LUA:           number 70
LUA:         .uppos_prev
LUA:           number 0
LUA:         .winsize
LUA:           number 1026
LUA:         .winsize_calc
LUA:           number 262656
LUA:       .pcounter
LUA:         number 6
LUA:       .pdcounter
LUA:         number 1
LUA:     .server
LUA:       .pbcounter
LUA:         number 4278
LUA:       .tcp
LUA:         .mss
LUA:           number 1460
LUA:         .rseq
LUA:           number 3588
LUA:         .scale
LUA:           number 10
LUA:         .seq
LUA:           number 2222222222
LUA:         .pos
LUA:           number 3588
LUA:         .seq0
LUA:           number 1111111111
LUA:         .uppos
LUA:           number 3588
LUA:         .uppos_prev
LUA:           number 3588
LUA:         .winsize
LUA:           number 64
LUA:         .winsize_calc
LUA:           number 65536
LUA:       .pcounter
LUA:         number 7
LUA:       .pdcounter
LUA:         number 4
LUA:     .client
LUA:       .pbcounter
LUA:         number 69
LUA:       .tcp
LUA:         .mss
LUA:           number 1460
LUA:         .rseq
LUA:           number 71
LUA:         .scale
LUA:           number 8
LUA:         .seq
LUA:           number 3333333333
LUA:         .pos
LUA:           number 71
LUA:         .seq0
LUA:           number 4444444444
LUA:         .uppos
LUA:           number 70
LUA:         .uppos_prev
LUA:           number 0
LUA:         .winsize
LUA:           number 1026
LUA:         .winsize_calc
LUA:           number 262656
LUA:       .pcounter
LUA:         number 6
LUA:       .pdcounter
LUA:         number 1
LUA:     .dt
LUA:       number 0
LUA:     .direct
LUA:       .pbcounter
LUA:         number 4278
LUA:       .tcp
LUA:         .mss
LUA:           number 1460
LUA:         .rseq
LUA:           number 3588
LUA:         .scale
LUA:           number 10
LUA:         .seq
LUA:           number 2222222222
LUA:         .pos
LUA:           number 3588
LUA:         .seq0
LUA:           number 1111111111
LUA:         .uppos
LUA:           number 3588
LUA:         .uppos_prev
LUA:           number 3588
LUA:         .winsize
LUA:           number 64
LUA:         .winsize_calc
LUA:           number 65536
LUA:       .pcounter
LUA:         number 7
LUA:       .pdcounter
LUA:         number 4
LUA:   .hostname
LUA:     string blablabla.com
LUA:   .incoming_ttl
LUA:     number 128
LUA:   .lua_state

dt - время в секундах с момента прохождения первого пакета по потоку

Изменен механизм детекта автолистом заблокированных сайтов по входящим.
Это RST и http redirect.

Введен параметр --hostlist-auto-incoming-maxseq . Содержит максимальный входящий relative sequence, после которого конект считается успешным и все механизмы детекта сбоев отключаются, включая и подсчет ретрансмиссий. По умолчанию 4096.
В этом диапазоне считаются все RST и все пейлоады http_reply c редиректом на другой домен 2 уровня вне зависимости от протокола сеанса (некоторые DPI возвращают http redirect на 443 порту после TLS HELLO).
DPI может чем-то плюнуть и потом послать RST. Например, он может выдать TLS alert message + RST.
Старый алгоритм это бы посчитал за “website works”. Новый посчитает только, если DPI выплюнул более incoming-maxseq байт.
4096 выбрано как значение, больше которого DPI вряд ли плюнет. А меньше реальный веб сайт вряд ли вернет.
Бывает и так, что DPI плюется какой-то ерундой, потом блокирует поток, не посылая RST. Этот вариант скорее всего вызовет у клиента отсылку TLS alert, который будет ретрансмиттиться и сработает триггер на ретрансмиссии. В старом варианте триггер работал только по диапазону sequence tls hello, поэтому он бы не сработал

Если рассматривать 16 кб блок, то там может быть такая ситуевина. Протокол TLS со стороны клиента вошел в фазу ожидания ответа сервера. Сам он ничего не шлет. Сервер шлет блоки encrypted сообщений, клиент их принимает. И вдруг сервер перестает их слать, потому что DPI рубанул поток. Клиент ничего не ретрансмиттит, потому что нет непринятых сервером данных. И так соединение может висеть очень очень очень долго. Минуты или часы. Если только tcp keepalive не убьет соединение или клиент по таймауту.
В этом случае детект сбоя не представляется возможным. Для этого нужно было бы понять передано ли сервером его сообщение полностью. А понять можно только на L7 уровне под TLS, анализируя http протокол или что там под TLS. Понять может только клиентское приложение, сторонний наблюдатель, которым является zapret, - нет. В разумные сроки хотя бы

В рамках продолжающейся пьянки.
Переписана логика детекта сбоя по quic.
Все равно старая логика практически не работала. Ловились повторные передачи quic initial с crypto фреймом. Так делали старые криптолибы, новые шлют пинг, в итоге ничерта не работало на практике.

Детект сбоя quic стал просто детектом сбоя udp, логика которого скопирована с LUA функции standard_failure_detector. Однако, в отличие от LUA функции, работа идет только если есть hostname, ибо какой хостлист без хоста ? Что туда заносить ?
Как таковой это больше не детектор сбоя quic, а универсальный детектор сбоя udp. Но на практике он работает только на quic, потому что это единственный известный nfqws2 протокол с хостом.

Если ушло >= --hostlist-auto-udp-out пакетов , при этом пришло <= --hostlist-auto-udp-in пакетов, значит имеет место сбой.
Раз сбой, два сбой, три сбой (--hostlist-auto-fail-threshold) => в лист

По умолчанию udp_in - 1, udp_out - 4
На curl работает, на броузерах может и не работать, потому что они не любят долбиться, они любят
быстро открывать страницы. И если начинается дятлинг, они переключаются на tcp, пробуют ipv4, ipv6.

Вообщем как ни крути, а полезность автолиста на quic под большим вопросом.
Вернее он полезен только как потребитель - без функции auto. Поэтому в дефолтном конфиге и ставится в раздел udp 443 маркер <HOSTLIST_NOAUTO>

И заодно комментарии по standard_failure_detector.
Он работает даже без хоста - по умолчанию.
Количество фейлов хранится в таблице host record, получаемой через функцию automate_host_record.
Она берет 2 параметра : reqhost и key.
reqhost заставляет работать только если есть хост и не работать иначе. по умолчанию идет работа в любом случае. если нет хоста - используется ip в качестве индекса. поэтому будет перескок host record при обнаружении хоста, номер стратегии поменяется. это нужно учитывать или сразу писать reqhost в оркестратор. но тогда нулевка (нулевая фаза) отлетит, если стратегии нулевки под оркестратором.
standard_failure_detector имеет 4 варианта детекта сбоя, и только один из них - http redirect - привязан жестко к типу пейлоада. Остальные могут работать по любому протоколу, если логика подходит для него. Но только по IP адресу. Для circular - номер стратегии будет привязан к ip.
Если нужно, чтобы он еще был привязан к портам, нужно использовать разные профили с фильтрами по портам.

key - это индекс хранилища в таблице autostate.
host record находится в autostate.<askey>.<hostkey>
askey по умолчанию определяется как название текущего инстанса - как правило это оркестратор
потому что каждый оркестратор хранит там свои структуры данных, в общем случае несовместимые с другими оркестраторами. даже для разных инстансов одного оркестратора нужны разные host record в общем случае. они могут быть в разных профилях, у них могут быть иные подопечные с иным количеством стратегий, поэтому они должны иметь отдельные данные.
но что если используется один оркестратор в разных профилях с тем же набором стратегий ? Нельзя ли сделать так, чтобы они использовали общую базу ? Если на одном профиле произойдет перескок на следующую стратегию, чтобы это сразу же отразилось на другом профиле ?
Можно. Надо задать key=<уникальная строка>. Строка дожна быть совместима с названиями переменных LUA, не содержать левых символов. Забота о совместимости контекста между инстансами оркестраторов ложится целиком на юзера. Если там отличается количество стратегий или логика окажется нелогичной - будет бред. Комп, конечно, не взорвется, но могут посыпаться ERRORы, а следовательно сбой стратегии и пропуск пакетов без дурения, либо может просто логика нарушиться, и получиться что-то не то, что задумывалось

Вышел FreeBSD 15.
Как там дела с pf ? Не починили divert-to ?

pass out on vmx0 proto tcp from any to port { 80,443 } divert-to 127.0.0.1 port 989

kldunload ipfw
kldload pf
pfctl -f /etc/pf.conf
pfctl -e

dvtws2 …

curl

KERNEL PANIC

стабильно

чудесно

при апгрейде не хватило какой-то so, требующейся для нового libc, из-за чего пришлось копировать ее руками с бутабельного iso. иначе только реинсталл - в шелл не зайти, ничего не запустить

Наконец-то разобрался что же такого поменялось в ядре 5.19, что перестал выдаваться SSID
в iw dev wlan0 info.

Очень специфическая тема, никто не знает и не отвечает.
Где-то нагуглил, что работает iw dev wlan0 link.
Так и раскопал по исходникам iw как его вытаскивать с нетлинка

Дублирующий запрос через wireless ext удалил, бэкпортнул на nfqws1

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

Слишком не хочу его изолировать, чтобы можно было при необходимости собрать под динамику и использовать подгружаемые модули.
Может завтра понадобится сложная криптография из openssl. Биндинги есть под LUA.
Но никаких EXE запусканий и неограниченного админского аксеса.
Во избежание распространения всякой дряни в скриптах.

Новый оркестратор repeater.

Его суть заключена в названии - повторить несколько раз выполнение выбранного количества следующих инстансов, а последующие выполнить обычным способом 1 раз.
Сколько раз - в параметре repeats, сколько следующих инстансов - в параметре instances.

nfqws2 --lua-desync=repeater:repeats=2:instances=2 --lua-desync=argdebug:v=33 --lua-desync=argdebug:v=44 --lua-desync=argdebug:v=55

Будет 33,44,33,44,55

Практическое применение ? Например, параметр repeats в фейках относится к rawsend opts. rawsend - это операция на стороне C кода, которая может послать пакет N раз. Но она ничего не знает об ip_id, она шлет как есть. И нас за это банят при обращении к GGC. Функция fake не имеет встроенной возможности повторить несколько раз на своей стороне, каждый раз увеличивая ip_Id.
Загромождать код не хочется. Может понадобится повторить что угодно, и что теперь каждую функцию загромождать ?

Этот вариант делает multisplit,fake 3 раза с линейным увеличением ip_Id

nfqws2
--lua-desync=repeater:repeats=3:instances=2
--lua-desync=multisplit:ip_id=seq:ip_id_conn
--lua-desync=fake:blob=0x10000000:ip_id=seq:ip_id_conn:badsum

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

А что если надо после однократного multisplit продолжить линейный ip_id ?
На винде просто ставите ip_id=zero, а винда всунет туда свой линейный счетчик.
На остальных так не пройдет. Не получится менять ip_id в отпускаемых пакетах.
Но можно некоторые из них переслать заново с изменением ip_id.

nfqws2
--lua-desync=multisplit:ip_id=seq:ip_id_conn
--out-range=-n15 --payload=unknown,empty
--lua-desync=send:ip_id=seq:ip_id_conn --lua-desync=drop

Обнаружилось, что nfqws2 не работает на модеме huawei E8372

LUA INIT
LUA INIT ERROR

	if (!(params.L = luaL_newstate()))
	{
		DLOG_ERR("LUA INIT ERROR\n");
		return false;
	}
Processor       : ARMv7 Processor rev 1 (v7l)
BogoMIPS        : 1196.85
Features        : swp half thumb fastmult vfp edsp vfpv3 vfpv3d16 tls 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x4
CPU part        : 0xc09
CPU revision    : 1

Hardware        : Hisilicon hi6930
Revision        : 0000
Serial          : 0000000000000000

вероятнее всего luajit не нравится процессор.
vfp есть, но только 3-й.

На таком работает :

 cat /proc/cpuinfo
Processor       : ARMv7 Processor rev 4 (v7l)
processor       : 0
model name      : ARMv7 Processor rev 4 (v7l)
BogoMIPS        : 7.24
Features        : half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt vfpd32 lpae evtstrm sha2 
CPU implementer : 0x41
CPU architecture: 7
CPU variant     : 0x0
CPU part        : 0xd03
CPU revision    : 4

Hardware        : MT8735D
Revision        : 0000

нужно тестирование nfqws2 на разных arm устройствах, особенно на роутерах с arm 32 bit
результат + cpuinfo

UPD. В github actions сделал отдельный target arm-old с LUA 5.4 classic. Ожидаемо работает

Прощаемся с zapret-info и rublacklist.
Роскомсвобода все.

Убираются скрипты ipset get_reestr_resolve.sh и get_reestr_hostlist.sh как работающие напрямую с z-i.
bol-van/rulist переориентируется на другой источник доменов. заполнение ipban уходит, поскольку формировалось на основе csv от z-i