Template
1
0
mirror of https://github.com/bol-van/zapret2.git synced 2026-03-14 06:13:09 +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 apt update -qq
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
else
# 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
fi
mkdir -p $HOME/tools
@@ -553,7 +553,7 @@ jobs:
rm -rf binaries/{android*,freebsd*,win*} \
init.d/{openrc,pfsense,runit,s6,systemd,windivert.filter.examples} \
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 }}

View File

@@ -6,7 +6,7 @@ pktws_check_http()
[ "$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
done
}

View File

@@ -144,3 +144,11 @@ v0.8.0
* zapret-antidpi: tls_client_hello_clone
* zapret-antidpi: "optional" arg to blob taking functions
* 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\_domcase](#http_domcase)
- [http\_methodeol](#http_methodeol)
- [http\_unixeol](#http_unixeol)
- [Замена window size](#замена-window-size)
- [wsize](#wsize)
- [wssize](#wssize)
@@ -1834,7 +1835,9 @@ nfqws2 не использует никакие криптобиблиотеки
function bcryptorandom(size)
```
Генерирует raw строку - криптографически стойкий блок случайных данных указанного размера. Источник - `/dev/random`
Генерирует raw строку - криптографически стойкий блок случайных данных указанного размера. Источник - `/dev/random`.
Если пул энтропии исчерпывается, может вызывать зависания. Чтобы этого не было - установите haveged или rngd.
Не стоит использовать для получения случайных данных, не требующих крипто-стойкости.
#### hash
@@ -2373,8 +2376,12 @@ function blob_or_def(desync, name, def)
```
function barray(a, packer)
function btable(a, packer)
```
- barray использует только числовые индексы, начиная с 1. порядок соблюдается
- btable использует все индексы, но не гарантирует порядок
Упаковка элементов массива a в порядке возрастания индекса от 1 до последнего.
`packer` - функция, берущая элемент a и возвращающая raw string.
Для числовых массивов в качестве packer можно использовать [функции паковки чисел](#bux).
@@ -2463,6 +2470,7 @@ function dissect_nld(domain, level)
```
function http_dissect_req(http)
function http_dissect_reply(http)
function http_reconstruct_req(hdis)
```
Разборка HTTP запроса или ответа http. http представляет собой многострочный текст.
@@ -2470,6 +2478,8 @@ function http_dissect_reply(http)
В заголовках выдаются позиции начала и конца названия заголовка и самого значения.
Названия полей в таблице headers соответствуют названию заголовков в нижнем регисте. Все позиции - внутри строки http.
Реконструктор http запроса берет таблицу-разбор и воссоздает raw string.
<details>
<summary><b>Пример разборки http запроса `http://testhost.com/testuri`</b></summary>
<pre>
@@ -2558,7 +2568,9 @@ function tls_reconstruct(tdis)
7. Если есть record layer, реконструкция выполняется согласно длинам отдельных records. Если последняя часть не влезает, tls record расширяется под оставшиеся данные.
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))"`.
И вызвать TLS запрос.
@@ -2876,9 +2888,11 @@ function tls_reconstruct(tdis)
Множество констант, связанных с 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 и по возрастающей. Это не так.
extensions и другие списки индексируются по номеру с 1, а не по типу, потому что важен порядок их следования, и может быть несколько элементов одного типа.
Если вы что-то добавляете свое, вам нужно воспроизвести минимальный вариант исходной структуры.
Можно заполнить только raw data field. Если нет подтаблицы dis - при реконструкции будет взято оно.
Если есть dis, то он должен быть заполнен корректно согласно рассматриваемому элементу данных.
@@ -3448,6 +3462,16 @@ function http_methodeol(ctx, desync)
Вставляет '\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
### 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`. В файлах поддерживаются комментарии, начинающиеся на `#`.
При записи параметров следует учитывать, что они будут интерпретироваься как параметры shell. Специальные символы нужно экранировать по правилам shell.
Если вы оставите "<" без кавычек на всем параметре или возьмете в кавычки параметр `--luaexec=code=print("abc")`, будет ошибка. Если в lua коде используются строки - их стоит заключать в одинарные кавычки, а вокруг параметра - двойные.
blockcheck2 будет выдавать параметры стратегий без экранирования.
Самый правильный способ применения - скопировать в свою поддиректорию внутри `blockcheck2.d` и заполнить txt файлы с тестами. Выбрать свое имя теста в диалоге.
## Summary
@@ -4588,6 +4616,9 @@ ip листы разделяются на ipv4 и ipv6. ipv6 листы имею
В зависимости от режима хостлисты могут ресолвиться в ip листы через [mdig](#mdig) или применяться как есть. Если хостлисты применяются как есть в nfqws2, учитываются только имена доменов, а IP адреса и подсети - нет.
Включающие ip листы загоняются в сеты ядра и применяются в правилах таблиц только, если указан [MODE_FILTER=ipset](#файл-config).
Исключающий ip лист загоняется в сеты ядра и применяется всегда в правилах таблиц.
| Хостлист | Тип | Назначение | ip листы |
| :---------------------------- | :--------------- | :-------------- | :---------------------------------------------------- |
| 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
-- 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"
-- standard args : rawsend, reconstruct, ipfrag
-- 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)
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)
if a then
local s=""
@@ -314,6 +314,16 @@ function barray(a, packer)
return s
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
-- seq1>=seq2
@@ -1423,19 +1433,22 @@ function http_dissect_header(header)
end
-- make table with structured http header representation
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={}
while pos do
eol,pnext = find_next_line(http,pos)
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)
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 }
end
pos=pnext
end
return headers
return headers, pos_headers_end
end
-- make table with structured http request representation
function http_dissect_req(http)
@@ -1457,9 +1470,21 @@ function http_dissect_req(http)
pos = string.find(req,"[^ \t]",pos+1)
if not pos then return nil end
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)
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
function http_dissect_reply(http)
if not http then return nil; end
@@ -1472,6 +1497,14 @@ function http_dissect_reply(http)
pos = find_next_line(http,pos)
return { code = code, headers = http_dissect_headers(http,pos) }
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)
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)
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;
mask <<= from;
what = what & ~mask | set;
@@ -401,7 +401,7 @@ static int luacall_bu48(lua_State *L)
int64_t i = (int64_t)luaL_checklint(L,1);
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);
lua_pushlstring(L,(char*)v,6);
return 1;
@@ -2961,13 +2961,13 @@ static int luaL_doZfile(lua_State *L, const char *filename)
FILE *F = fopen(fname, "rb");
if (!F)
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);
if (r != Z_OK)
luaL_error(L, "could not unzip lua file '%s'", fname);
buf[size] = 0;
r = luaL_dostring(L, buf);
r = luaL_loadbuffer(L, buf, size, fname);
free(buf);
if (!r) r=lua_pcall(L, 0, LUA_MULTRET, 0);
return r;
}
else