Template
1
0
mirror of https://github.com/bol-van/zapret2.git synced 2026-03-21 16:55:49 +00:00

15 Commits
v0.8 ... v0.8.1

Author SHA1 Message Date
bol-van
5bc65c3b91 update docs 2025-12-30 15:20:49 +03:00
bol-van
6bf7f2c7c0 nfqws2: use luaL_loadbuffer 2025-12-30 15:11:15 +03:00
bol-van
44a80abb3f nfqws2: use luaL_loadbuffer 2025-12-30 15:05:42 +03:00
bol-van
89f0f39b83 update docs 2025-12-30 13:27:07 +03:00
bol-van
ad6f1db149 blockcheck2: http_unixeol test 2025-12-30 13:26:51 +03:00
bol-van
9154fe1677 zapret-lib, zapret-antidpi: http_reconstruct_req, http_unixeol 2025-12-30 13:26:15 +03:00
bol-van
5e63a0f5c5 update docs 2025-12-30 11:24:08 +03:00
bol-van
0521053991 github actions: use pigz -11 instead of gzip 2025-12-30 11:10:10 +03:00
bol-van
7b7ed1ad60 update docs 2025-12-30 10:51:07 +03:00
bol-van
2915647c63 update docs 2025-12-30 10:50:19 +03:00
bol-van
958a4e918b update docs 2025-12-30 10:48:11 +03:00
bol-van
cb332dad74 update docs 2025-12-30 10:44:05 +03:00
bol-van
17e9e0a8e6 update docs 2025-12-29 20:40:50 +03:00
bol-van
78b348a193 nfqws2: bu48 crash fix 2025-12-29 19:25:28 +03:00
bol-van
8103a02689 nfqws2: fix wrong bitset on 32-bit platforms 2025-12-29 19:14:25 +03:00
7 changed files with 124 additions and 18 deletions

View File

@@ -75,11 +75,11 @@ jobs:
sudo dpkg --add-architecture i386 sudo dpkg --add-architecture i386
sudo apt update -qq sudo apt update -qq
if [[ "$ARCH" == lexra ]]; then if [[ "$ARCH" == lexra ]]; then
sudo apt install -y libcap-dev libc6:i386 zlib1g:i386 sudo apt install -y pigz libcap-dev libc6:i386 zlib1g:i386
URL=https://github.com/$REPO/raw/refs/heads/master/$DIR.txz URL=https://github.com/$REPO/raw/refs/heads/master/$DIR.txz
else else
# luajit buildvm requires 32 bit executable on host platform for 32 bit cross targets # luajit buildvm requires 32 bit executable on host platform for 32 bit cross targets
sudo apt install -y libcap-dev libc6-dev gcc-multilib sudo apt install -y pigz libcap-dev libc6-dev gcc-multilib
URL=https://github.com/$REPO/releases/download/latest/$TOOL.tar.xz URL=https://github.com/$REPO/releases/download/latest/$TOOL.tar.xz
fi fi
mkdir -p $HOME/tools mkdir -p $HOME/tools
@@ -553,7 +553,7 @@ jobs:
rm -rf binaries/{android*,freebsd*,win*} \ rm -rf binaries/{android*,freebsd*,win*} \
init.d/{openrc,pfsense,runit,s6,systemd,windivert.filter.examples} \ init.d/{openrc,pfsense,runit,s6,systemd,windivert.filter.examples} \
nfq2 ip2net mdig docs Makefile nfq2 ip2net mdig docs Makefile
gzip lua/*.lua pigz -11 lua/*.lua
) )
tar --owner=0 --group=0 -czf ${{ env.repo_dir }}-openwrt-embedded.tar.gz ${{ env.repo_dir }} tar --owner=0 --group=0 -czf ${{ env.repo_dir }}-openwrt-embedded.tar.gz ${{ env.repo_dir }}

View File

@@ -6,7 +6,7 @@ pktws_check_http()
[ "$NOTEST_BASIC_HTTP" = 1 ] && { echo "SKIPPED"; return; } [ "$NOTEST_BASIC_HTTP" = 1 ] && { echo "SKIPPED"; return; }
for s in 'http_hostcase' 'http_hostcase:spell=hoSt' 'http_domcase' 'http_methodeol'; do for s in 'http_hostcase' 'http_hostcase:spell=hoSt' 'http_domcase' 'http_methodeol' 'http_unixeol'; do
pktws_curl_test_update $1 $2 --payload http_req --lua-desync=$s pktws_curl_test_update $1 $2 --payload http_req --lua-desync=$s
done done
} }

View File

@@ -144,3 +144,11 @@ v0.8.0
* zapret-antidpi: tls_client_hello_clone * zapret-antidpi: tls_client_hello_clone
* zapret-antidpi: "optional" arg to blob taking functions * zapret-antidpi: "optional" arg to blob taking functions
* nfqws2: support gzipped lua file. auto use script.lua.gz * nfqws2: support gzipped lua file. auto use script.lua.gz
v0.8.1
* nfqws2: fix bu48 crash and wrong results in bitset
* zapret-lib: http_reconstruct_req
* zapret-antidpi: http_unixeol
* blockcheck2: http_unixeol test

View File

@@ -158,6 +158,7 @@
- [http\_hostcase](#http_hostcase) - [http\_hostcase](#http_hostcase)
- [http\_domcase](#http_domcase) - [http\_domcase](#http_domcase)
- [http\_methodeol](#http_methodeol) - [http\_methodeol](#http_methodeol)
- [http\_unixeol](#http_unixeol)
- [Замена window size](#замена-window-size) - [Замена window size](#замена-window-size)
- [wsize](#wsize) - [wsize](#wsize)
- [wssize](#wssize) - [wssize](#wssize)
@@ -1834,7 +1835,9 @@ nfqws2 не использует никакие криптобиблиотеки
function bcryptorandom(size) function bcryptorandom(size)
``` ```
Генерирует raw строку - криптографически стойкий блок случайных данных указанного размера. Источник - `/dev/random` Генерирует raw строку - криптографически стойкий блок случайных данных указанного размера. Источник - `/dev/random`.
Если пул энтропии исчерпывается, может вызывать зависания. Чтобы этого не было - установите haveged или rngd.
Не стоит использовать для получения случайных данных, не требующих крипто-стойкости.
#### hash #### hash
@@ -2373,8 +2376,12 @@ function blob_or_def(desync, name, def)
``` ```
function barray(a, packer) function barray(a, packer)
function btable(a, packer)
``` ```
- barray использует только числовые индексы, начиная с 1. порядок соблюдается
- btable использует все индексы, но не гарантирует порядок
Упаковка элементов массива a в порядке возрастания индекса от 1 до последнего. Упаковка элементов массива a в порядке возрастания индекса от 1 до последнего.
`packer` - функция, берущая элемент a и возвращающая raw string. `packer` - функция, берущая элемент a и возвращающая raw string.
Для числовых массивов в качестве packer можно использовать [функции паковки чисел](#bux). Для числовых массивов в качестве packer можно использовать [функции паковки чисел](#bux).
@@ -2463,6 +2470,7 @@ function dissect_nld(domain, level)
``` ```
function http_dissect_req(http) function http_dissect_req(http)
function http_dissect_reply(http) function http_dissect_reply(http)
function http_reconstruct_req(hdis)
``` ```
Разборка HTTP запроса или ответа http. http представляет собой многострочный текст. Разборка HTTP запроса или ответа http. http представляет собой многострочный текст.
@@ -2470,6 +2478,8 @@ function http_dissect_reply(http)
В заголовках выдаются позиции начала и конца названия заголовка и самого значения. В заголовках выдаются позиции начала и конца названия заголовка и самого значения.
Названия полей в таблице headers соответствуют названию заголовков в нижнем регисте. Все позиции - внутри строки http. Названия полей в таблице headers соответствуют названию заголовков в нижнем регисте. Все позиции - внутри строки http.
Реконструктор http запроса берет таблицу-разбор и воссоздает raw string.
<details> <details>
<summary><b>Пример разборки http запроса `http://testhost.com/testuri`</b></summary> <summary><b>Пример разборки http запроса `http://testhost.com/testuri`</b></summary>
<pre> <pre>
@@ -2558,7 +2568,9 @@ function tls_reconstruct(tdis)
7. Если есть record layer, реконструкция выполняется согласно длинам отдельных records. Если последняя часть не влезает, tls record расширяется под оставшиеся данные. 7. Если есть record layer, реконструкция выполняется согласно длинам отдельных records. Если последняя часть не влезает, tls record расширяется под оставшиеся данные.
8. При отсутствии изменений dissect+reconstruct дают бинарно идентичные блобы. 8. При отсутствии изменений dissect+reconstruct дают бинарно идентичные блобы.
Функции не работают с DTLS. В случае ошибки возвращается nil. Функции не работают с DTLS.
`tls_dissect` возвращает таблицу - разбор raw строки tls со смещения offset (начиная с 1), `reconstruct_dissect` возвращает raw строку собранного разбора tdis. В случае ошибки возвращается nil.
Простейший способ получить образец диссекта : `--payload=tls_client_hello --lua-desync=luaexec:code="var_debug(tls_dissect(desync.reasm_data))"`. Простейший способ получить образец диссекта : `--payload=tls_client_hello --lua-desync=luaexec:code="var_debug(tls_dissect(desync.reasm_data))"`.
И вызвать TLS запрос. И вызвать TLS запрос.
@@ -2876,9 +2888,11 @@ function tls_reconstruct(tdis)
Множество констант, связанных с TLS, определено в `zapret-lib.lua`. Прежде чем писать фиксированные значения, посмотрите нет ли нужной константы. Множество констант, связанных с TLS, определено в `zapret-lib.lua`. Прежде чем писать фиксированные значения, посмотрите нет ли нужной константы.
Таблица handshake индексируется по типу hadnshake. Самыми типичными являются `TLS_HANDSHAKE_TYPE_CLIENT` и `TLS_HANDSHAKE_TYPE_SERVER`. Таблица handshake индексируется по типу handshake. Самыми типичными являются `TLS_HANDSHAKE_TYPE_CLIENT` и `TLS_HANDSHAKE_TYPE_SERVER`.
Они имеют значения 1 и 2 соответственно, поэтому может показаться, что элементы handshake идут от 1 и по возрастающей. Это не так. Они имеют значения 1 и 2 соответственно, поэтому может показаться, что элементы handshake идут от 1 и по возрастающей. Это не так.
extensions и другие списки индексируются по номеру с 1, а не по типу, потому что важен порядок их следования, и может быть несколько элементов одного типа.
Если вы что-то добавляете свое, вам нужно воспроизвести минимальный вариант исходной структуры. Если вы что-то добавляете свое, вам нужно воспроизвести минимальный вариант исходной структуры.
Можно заполнить только raw data field. Если нет подтаблицы dis - при реконструкции будет взято оно. Можно заполнить только raw data field. Если нет подтаблицы dis - при реконструкции будет взято оно.
Если есть dis, то он должен быть заполнен корректно согласно рассматриваемому элементу данных. Если есть dis, то он должен быть заполнен корректно согласно рассматриваемому элементу данных.
@@ -3448,6 +3462,16 @@ function http_methodeol(ctx, desync)
Вставляет '\r\n' перед методом, отрезая 2 последних символа из содержимого заголовка `User-Agent:`. Работает только на nginx, остальные сервера ломает. Вставляет '\r\n' перед методом, отрезая 2 последних символа из содержимого заголовка `User-Agent:`. Работает только на nginx, остальные сервера ломает.
### http_unixeol
```
function http_unixeol(ctx, desync)
```
- arg: [standard direction](#standard-direction)
Заменяет перевод строки 0D0A на 0A. Разницу в длине добавляет пробелами в конец хедера "User-Agent". Работает только на nginx, остальные сервера ломает.
## Замена window size ## Замена window size
### wsize ### wsize
@@ -4451,6 +4475,10 @@ NOTEST_QUIC=1 - отмена тестов 90-quic.sh
Простой тестировщик по списку стратегий из файлов. Стратегии должны быть на отдельных строчках, переносы строки не допускаются. Используются отдельные списки для протоколов - `list_http.txt`, `list_https_tls12.txt`, `list_https_tls13.txt`, `list_quic.sh`. В файлах поддерживаются комментарии, начинающиеся на `#`. Простой тестировщик по списку стратегий из файлов. Стратегии должны быть на отдельных строчках, переносы строки не допускаются. Используются отдельные списки для протоколов - `list_http.txt`, `list_https_tls12.txt`, `list_https_tls13.txt`, `list_quic.sh`. В файлах поддерживаются комментарии, начинающиеся на `#`.
При записи параметров следует учитывать, что они будут интерпретироваься как параметры shell. Специальные символы нужно экранировать по правилам shell.
Если вы оставите "<" без кавычек на всем параметре или возьмете в кавычки параметр `--luaexec=code=print("abc")`, будет ошибка. Если в lua коде используются строки - их стоит заключать в одинарные кавычки, а вокруг параметра - двойные.
blockcheck2 будет выдавать параметры стратегий без экранирования.
Самый правильный способ применения - скопировать в свою поддиректорию внутри `blockcheck2.d` и заполнить txt файлы с тестами. Выбрать свое имя теста в диалоге. Самый правильный способ применения - скопировать в свою поддиректорию внутри `blockcheck2.d` и заполнить txt файлы с тестами. Выбрать свое имя теста в диалоге.
## Summary ## Summary
@@ -4588,6 +4616,9 @@ ip листы разделяются на ipv4 и ipv6. ipv6 листы имею
В зависимости от режима хостлисты могут ресолвиться в ip листы через [mdig](#mdig) или применяться как есть. Если хостлисты применяются как есть в nfqws2, учитываются только имена доменов, а IP адреса и подсети - нет. В зависимости от режима хостлисты могут ресолвиться в ip листы через [mdig](#mdig) или применяться как есть. Если хостлисты применяются как есть в nfqws2, учитываются только имена доменов, а IP адреса и подсети - нет.
Включающие ip листы загоняются в сеты ядра и применяются в правилах таблиц только, если указан [MODE_FILTER=ipset](#файл-config).
Исключающий ip лист загоняется в сеты ядра и применяется всегда в правилах таблиц.
| Хостлист | Тип | Назначение | ip листы | | Хостлист | Тип | Назначение | ip листы |
| :---------------------------- | :--------------- | :-------------- | :---------------------------------------------------- | | :---------------------------- | :--------------- | :-------------- | :---------------------------------------------------- |
| zapret-hosts-user.txt | пользовательский | включающий | zapret-ip-user.txt<br>zapret-ip-user6.txt | | zapret-hosts-user.txt | пользовательский | включающий | zapret-ip-user.txt<br>zapret-ip-user6.txt |

View File

@@ -185,6 +185,40 @@ function http_methodeol(ctx, desync)
end end
end end
-- nfqws1 : not available
-- tpws : --unixeol
-- standard args : direction
function http_unixeol(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
return
end
direction_cutoff_opposite(ctx, desync)
if desync.l7payload=="http_req" and direction_check(desync) then
local hdis = http_dissect_req(desync.dis.payload)
if hdis then
if hdis.headers["user-agent"] then
local http = http_reconstruct_req(hdis, true)
if #http < #desync.dis.payload then
hdis.headers["user-agent"].value = hdis.headers["user-agent"].value .. string.rep(" ", #desync.dis.payload - #http)
end
local http = http_reconstruct_req(hdis, true)
if #http==#desync.dis.payload then
desync.dis.payload = http
DLOG("http_unixeol: applied")
return VERDICT_MODIFY
else
DLOG("http_unixeol: reconstruct differs in size from original: "..#http.."!="..#desync.dis.payload)
end
else
DLOG("http_unixeol: user-agent header absent")
end
else
DLOG("http_unixeol: could not dissect http")
end
end
end
-- nfqws1 : "--synack-split" -- nfqws1 : "--synack-split"
-- standard args : rawsend, reconstruct, ipfrag -- standard args : rawsend, reconstruct, ipfrag
-- arg : mode=syn|synack|acksyn . "synack" by default -- arg : mode=syn|synack|acksyn . "synack" by default

View File

@@ -304,7 +304,7 @@ function pos_str(desync, pos)
return pos.mode..pos_get(desync, pos.mode) return pos.mode..pos_get(desync, pos.mode)
end end
-- convert array a to packed string using 'packer' function -- convert array a to packed string using 'packer' function. only numeric indexes starting from 1, order preserved
function barray(a, packer) function barray(a, packer)
if a then if a then
local s="" local s=""
@@ -314,6 +314,16 @@ function barray(a, packer)
return s return s
end end
end end
-- convert table a to packed string using 'packer' function. any indexes, any order
function btable(a, packer)
if a then
local s=""
for k,v in pairs(a) do
s = s .. packer(v)
end
return s
end
end
-- sequence comparision functions. they work only within 2G interval -- sequence comparision functions. they work only within 2G interval
-- seq1>=seq2 -- seq1>=seq2
@@ -1423,19 +1433,22 @@ function http_dissect_header(header)
end end
-- make table with structured http header representation -- make table with structured http header representation
function http_dissect_headers(http, pos) function http_dissect_headers(http, pos)
local eol,pnext,header,value,idx,headers,pos_endheader,pos_startvalue local eol,pnext,header,value,idx,headers,pos_endheader,pos_startvalue,pos_headers_next
headers={} headers={}
while pos do while pos do
eol,pnext = find_next_line(http,pos) eol,pnext = find_next_line(http,pos)
header = string.sub(http,pos,eol) header = string.sub(http,pos,eol)
if #header == 0 then break end if #header == 0 then
pos_headers_end = pnext
break
end
header,value,pos_endheader,pos_startvalue = http_dissect_header(header) header,value,pos_endheader,pos_startvalue = http_dissect_header(header)
if header then if header then
headers[string.lower(header)] = { header = header, value = value, pos_start = pos, pos_end = eol, pos_header_end = pos+pos_endheader-1, pos_value_start = pos+pos_startvalue-1 } headers[string.lower(header)] = { header = header, value = value, pos_start = pos, pos_end = eol, pos_header_end = pos+pos_endheader-1, pos_value_start = pos+pos_startvalue-1 }
end end
pos=pnext pos=pnext
end end
return headers return headers, pos_headers_end
end end
-- make table with structured http request representation -- make table with structured http request representation
function http_dissect_req(http) function http_dissect_req(http)
@@ -1457,9 +1470,21 @@ function http_dissect_req(http)
pos = string.find(req,"[^ \t]",pos+1) pos = string.find(req,"[^ \t]",pos+1)
if not pos then return nil end if not pos then return nil end
pnext = string.find(req,"[ \t]",pos+1) pnext = string.find(req,"[ \t]",pos+1)
if not pnext then pnext = #http + 1 end if not pnext then pnext = #req + 1 end
local uri = string.sub(req,pos,pnext-1) local uri = string.sub(req,pos,pnext-1)
return { method = method, uri = uri, headers = http_dissect_headers(http,hdrpos) } pos = string.find(req,"[^ \t]",pnext)
local http_ver
if pos then
pnext = string.find(req,"[\r\n]",pos)
if not pnext then pnext = #req + 1 end
http_ver = string.sub(req,pos,pnext-1)
end
local hdis = { method = method, uri = uri, http_ver = http_ver }
hdis.headers, hdis.pos_headers_end = http_dissect_headers(http,hdrpos)
if hdis.pos_headers_end then
hdis.body = string.sub(http, hdis.pos_headers_end)
end
return hdis
end end
function http_dissect_reply(http) function http_dissect_reply(http)
if not http then return nil; end if not http then return nil; end
@@ -1472,6 +1497,14 @@ function http_dissect_reply(http)
pos = find_next_line(http,pos) pos = find_next_line(http,pos)
return { code = code, headers = http_dissect_headers(http,pos) } return { code = code, headers = http_dissect_headers(http,pos) }
end end
function http_reconstruct_headers(headers, unixeol)
local eol = unixeol and "\n" or "\r\n"
return headers and btable(headers, function(a) return a.header..": "..a.value..eol end) or ""
end
function http_reconstruct_req(hdis, unixeol)
local eol = unixeol and "\n" or "\r\n"
return hdis.method.." "..hdis.uri..(hdis.http_ver and (" "..hdis.http_ver) or "")..eol..http_reconstruct_headers(hdis.headers, unixeol)..eol..(hdis.body or "")
end
function dissect_url(url) function dissect_url(url)
local p1,pb,pstart,pend local p1,pb,pstart,pend

View File

@@ -193,7 +193,7 @@ static int luacall_bitset(lua_State *L)
if (from>to || from>47 || to>47) if (from>to || from>47 || to>47)
luaL_error(L, "bit range invalid"); luaL_error(L, "bit range invalid");
lua_Integer mask = ~((lua_Integer)-1 << (to-from+1)); uint64_t mask = ~((uint64_t)-1 << (to-from+1));
set = (set & mask) << from; set = (set & mask) << from;
mask <<= from; mask <<= from;
what = what & ~mask | set; what = what & ~mask | set;
@@ -401,7 +401,7 @@ static int luacall_bu48(lua_State *L)
int64_t i = (int64_t)luaL_checklint(L,1); int64_t i = (int64_t)luaL_checklint(L,1);
if (i>0xFFFFFFFFFFFF || i<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range"); if (i>0xFFFFFFFFFFFF || i<-(int64_t)0xFFFFFFFFFFFF) luaL_error(L, "out of range");
uint8_t v[4]; uint8_t v[6];
phton48(v,(uint64_t)i); phton48(v,(uint64_t)i);
lua_pushlstring(L,(char*)v,6); lua_pushlstring(L,(char*)v,6);
return 1; return 1;
@@ -2961,13 +2961,13 @@ static int luaL_doZfile(lua_State *L, const char *filename)
FILE *F = fopen(fname, "rb"); FILE *F = fopen(fname, "rb");
if (!F) if (!F)
luaL_error(L, "could not open lua file '%s'", fname); luaL_error(L, "could not open lua file '%s'", fname);
r = z_readfile(F, &buf, &size, 1); r = z_readfile(F, &buf, &size, 0);
fclose(F); fclose(F);
if (r != Z_OK) if (r != Z_OK)
luaL_error(L, "could not unzip lua file '%s'", fname); luaL_error(L, "could not unzip lua file '%s'", fname);
buf[size] = 0; r = luaL_loadbuffer(L, buf, size, fname);
r = luaL_dostring(L, buf);
free(buf); free(buf);
if (!r) r=lua_pcall(L, 0, LUA_MULTRET, 0);
return r; return r;
} }
else else