mirror of
https://github.com/bol-van/zapret2.git
synced 2026-03-14 06:13:09 +00:00
Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
776155a326 | ||
|
|
30423596ca | ||
|
|
27ef67adf9 | ||
|
|
bb604f111c | ||
|
|
e5174bc9ad | ||
|
|
6c29bf6702 | ||
|
|
976033be37 | ||
|
|
f9b2135688 | ||
|
|
844fa6ab47 | ||
|
|
dc0fe70bd6 | ||
|
|
2752c26795 | ||
|
|
1600b41135 | ||
|
|
2017889207 | ||
|
|
146ab847df | ||
|
|
cf9059ed22 | ||
|
|
c94264c79e | ||
|
|
04cb71150a | ||
|
|
378ee514c4 | ||
|
|
1a190fcf9e | ||
|
|
0f8a788351 | ||
|
|
4c00f11c15 | ||
|
|
0f8cfd7022 | ||
|
|
4563b6ddcb | ||
|
|
9ae6927a0e | ||
|
|
8540278c9b | ||
|
|
76b9ab5075 | ||
|
|
3a153035e8 | ||
|
|
2b5eb3cd2d | ||
|
|
2c35e8949a | ||
|
|
7edd428508 | ||
|
|
7749fce7dc | ||
|
|
ea6e1e0853 | ||
|
|
7d2f12cbad | ||
|
|
f91c069a8b | ||
|
|
6961c013c5 | ||
|
|
e5736b5fdd | ||
|
|
efa675468d | ||
|
|
1073f03802 | ||
|
|
9125cb0205 | ||
|
|
9d5435f977 | ||
|
|
f17ab4c91e | ||
|
|
97aa261e14 | ||
|
|
813fece07a | ||
|
|
2a7b44b1d0 | ||
|
|
28e719d825 | ||
|
|
18725f6442 | ||
|
|
20b20fbb90 | ||
|
|
967b53b628 | ||
|
|
9cebc5cc37 | ||
|
|
0dc29c9c35 | ||
|
|
fd1eac2ef1 | ||
|
|
0c2abab6a9 | ||
|
|
efd8acb8de | ||
|
|
a147ebef61 | ||
|
|
7f4bdd5eb4 | ||
|
|
0588240d8d | ||
|
|
b9e03ef71b | ||
|
|
9c0c7cfa8c | ||
|
|
807ad5953b | ||
|
|
ee031db3a1 | ||
|
|
93e4df72e5 | ||
|
|
e62d3919f4 | ||
|
|
63414f8608 | ||
|
|
18974e6c1f | ||
|
|
e61967ac2b | ||
|
|
6010307667 | ||
|
|
04ceb589e0 |
2
.github/workflows/build.yml
vendored
2
.github/workflows/build.yml
vendored
@@ -108,7 +108,7 @@ jobs:
|
||||
export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig
|
||||
export STAGING_DIR=$RUNNER_TEMP
|
||||
|
||||
if [[ "$ARCH" == lexra ]] || [[ "$ARCH" == ppc ]]; then
|
||||
if [[ "$ARCH" == lexra ]] || [[ "$ARCH" == ppc ]] || [[ "$ARCH" == x86 ]]; then
|
||||
# use classic lua
|
||||
wget -qO- https://www.lua.org/ftp/lua-${LUA_RELEASE}.tar.gz | tar -xz
|
||||
(
|
||||
|
||||
49
blockcheck2.d/standard/24-syndata.sh
Normal file
49
blockcheck2.d/standard/24-syndata.sh
Normal file
@@ -0,0 +1,49 @@
|
||||
. "$TESTDIR/def.inc"
|
||||
|
||||
pktws_check_http()
|
||||
{
|
||||
# $1 - test function
|
||||
# $2 - domain
|
||||
|
||||
local PAYLOAD="--payload http_req" split
|
||||
|
||||
for split in '' multisplit multidisorder; do
|
||||
pktws_curl_test_update "$1" "$2" --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split}
|
||||
pktws_curl_test_update "$1" "$2" --lua-desync=syndata:blob=fake_default_http $PAYLOAD ${split:+$PAYLOAD --lua-desync=$split}
|
||||
done
|
||||
}
|
||||
|
||||
pktws_check_https_tls()
|
||||
{
|
||||
# $1 - test function
|
||||
# $2 - domain
|
||||
# $3 - PRE args for nfqws2
|
||||
|
||||
local PAYLOAD="--payload tls_client_hello" ok=0 pre="$3" split
|
||||
|
||||
for split in '' multisplit multidisorder; do
|
||||
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split} && ok=1
|
||||
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata:blob=0x1603 ${split:+$PAYLOAD --lua-desync=$split} && ok=1
|
||||
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,dupsid,rndsni ${split:+$PAYLOAD --lua-desync=$split} && ok=1
|
||||
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata:blob=fake_default_tls:tls_mod=rnd,dupsid,sni=google.com ${split:+$PAYLOAD --lua-desync=$split} && ok=1
|
||||
done
|
||||
|
||||
[ "$ok" = 1 ]
|
||||
}
|
||||
|
||||
pktws_check_https_tls12()
|
||||
{
|
||||
# $1 - test function
|
||||
# $2 - domain
|
||||
|
||||
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
|
||||
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
|
||||
}
|
||||
|
||||
pktws_check_https_tls13()
|
||||
{
|
||||
# $1 - test function
|
||||
# $2 - domain
|
||||
|
||||
pktws_check_https_tls "$1" "$2"
|
||||
}
|
||||
@@ -2,6 +2,6 @@ FOOLINGS46_TCP=${FOOLINGS46_TCP:-"tcp_md5 badsum tcp_seq=-3000 tcp_seq=1000000 t
|
||||
FOOLINGS6_TCP=${FOOLINGS6_TCP:-"ip6_hopbyhop ip6_hopbyhop:ip6_hopbyhop2 ip6_destopt ip6_routing ip6_ah"}
|
||||
FOOLINGS_TCP="$FOOLINGS46_TCP"
|
||||
[ "$IPV" = 6 ] && FOOLINGS_TCP="$FOOLINGS_TCP $FOOLINGS6_TCP"
|
||||
FOOLINGS_UDP="badsum"
|
||||
FOOLINGS_UDP="${FOOLINGS_UDP:-badsum}"
|
||||
|
||||
FAKE_REPEATS=${FAKE_REPEATS:-1}
|
||||
|
||||
@@ -26,7 +26,7 @@ CURL=${CURL:-curl}
|
||||
|
||||
TEST_DEFAULT=${TEST_DEFAULT:-standard}
|
||||
DOMAINS_DEFAULT=${DOMAINS_DEFAULT:-rutracker.org}
|
||||
QNUM=${QNUM:-59780}
|
||||
QNUM=${QNUM:-59781}
|
||||
SOCKS_PORT=${SOCKS_PORT:-1993}
|
||||
WS_UID=${WS_UID:-1}
|
||||
WS_GID=${WS_GID:-3003}
|
||||
@@ -275,44 +275,45 @@ mdig_cache()
|
||||
mdig_resolve()
|
||||
{
|
||||
# $1 - ip version 4/6
|
||||
# $2 - hostname, possibly with uri : rutracker.org/xxx/xxxx
|
||||
local hostvar cachevar countvar count ip n sdom
|
||||
# $2 - var to receive result
|
||||
# $3 - hostname, possibly with uri : rutracker.org/xxx/xxxx
|
||||
local hostvar cachevar countvar count n sdom
|
||||
|
||||
split_by_separator "$2" / sdom
|
||||
split_by_separator "$3" / sdom
|
||||
mdig_vars "$1" "$sdom"
|
||||
if [ -n "$count" ]; then
|
||||
n=$(random 0 $(($count-1)))
|
||||
eval ip=\$${cachevar}_$n
|
||||
echo $ip
|
||||
eval $2=\$${cachevar}_$n
|
||||
return 0
|
||||
else
|
||||
mdig_cache "$1" "$sdom" && mdig_resolve "$1" "$sdom"
|
||||
mdig_cache "$1" "$sdom" && mdig_resolve "$1" "$2" "$sdom"
|
||||
fi
|
||||
}
|
||||
mdig_resolve_all()
|
||||
{
|
||||
# $1 - ip version 4/6
|
||||
# $2 - hostname
|
||||
# $2 - var to receive result
|
||||
# $3 - hostname
|
||||
|
||||
local hostvar cachevar countvar count ip ips n sdom
|
||||
local hostvar cachevar countvar count ip__ ips__ n sdom
|
||||
|
||||
split_by_separator "$2" / sdom
|
||||
split_by_separator "$3" / sdom
|
||||
mdig_vars "$1" "$sdom"
|
||||
if [ -n "$count" ]; then
|
||||
n=0
|
||||
while [ "$n" -le $count ]; do
|
||||
eval ip=\$${cachevar}_$n
|
||||
if [ -n "$ips" ]; then
|
||||
ips="$ips $ip"
|
||||
eval ip__=\$${cachevar}_$n
|
||||
if [ -n "$ips__" ]; then
|
||||
ips__="$ips__ $ip__"
|
||||
else
|
||||
ips="$ip"
|
||||
ips__="$ip__"
|
||||
fi
|
||||
n=$(($n + 1))
|
||||
done
|
||||
echo "$ips"
|
||||
eval $2="\$ips__"
|
||||
return 0
|
||||
else
|
||||
mdig_cache "$1" "$sdom" && mdig_resolve_all "$1" "$sdom"
|
||||
mdig_cache "$1" "$sdom" && mdig_resolve_all "$1" "$2" "$sdom"
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -640,7 +641,7 @@ curl_with_dig()
|
||||
local sdom suri ip
|
||||
|
||||
split_by_separator "$dom" / sdom suri
|
||||
ip=$(mdig_resolve $1 $sdom)
|
||||
mdig_resolve $1 ip $sdom
|
||||
shift ; shift ; shift
|
||||
if [ -n "$ip" ]; then
|
||||
curl_with_subst_ip "$sdom" "$port" "$ip" "$@"
|
||||
@@ -965,7 +966,7 @@ check_domain_port_block()
|
||||
echo
|
||||
echo \* port block tests ipv$IPV $1:$2
|
||||
if netcat_setup; then
|
||||
ips=$(mdig_resolve_all $IPV $1)
|
||||
mdig_resolve_all $IPV ips $1
|
||||
if [ -n "$ips" ]; then
|
||||
for ip in $ips; do
|
||||
if netcat_test $ip $2; then
|
||||
@@ -1198,8 +1199,8 @@ test_runner()
|
||||
[ -f "$script" ] || continue
|
||||
unset -f $FUNC
|
||||
. "$script"
|
||||
echo
|
||||
existf $FUNC && {
|
||||
echo
|
||||
echo "* script : $TEST/$(basename "$script")"
|
||||
$FUNC "$@"
|
||||
}
|
||||
@@ -1254,7 +1255,7 @@ check_dpi_ip_block()
|
||||
|
||||
echo "> testing $UNBLOCKED_DOM on it's original ip"
|
||||
if curl_test $1 $UNBLOCKED_DOM; then
|
||||
unblocked_ip=$(mdig_resolve $IPV $UNBLOCKED_DOM)
|
||||
mdig_resolve $IPV unblocked_ip $UNBLOCKED_DOM
|
||||
[ -n "$unblocked_ip" ] || {
|
||||
echo $UNBLOCKED_DOM does not resolve. tests not possible.
|
||||
return 1
|
||||
@@ -1263,7 +1264,7 @@ check_dpi_ip_block()
|
||||
echo "> testing $blocked_dom on $unblocked_ip ($UNBLOCKED_DOM)"
|
||||
curl_test $1 $blocked_dom $unblocked_ip detail
|
||||
|
||||
blocked_ips=$(mdig_resolve_all $IPV $blocked_dom)
|
||||
mdig_resolve_all $IPV blocked_ips $blocked_dom
|
||||
for blocked_ip in $blocked_ips; do
|
||||
echo "> testing $UNBLOCKED_DOM on $blocked_ip ($blocked_dom)"
|
||||
curl_test $1 $UNBLOCKED_DOM $blocked_ip detail
|
||||
@@ -1314,6 +1315,8 @@ check_domain_http_tcp()
|
||||
# $3 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk
|
||||
# $4 - domain
|
||||
|
||||
local ips
|
||||
|
||||
# in case was interrupted before
|
||||
pktws_ipt_unprepare_tcp $2
|
||||
ws_kill
|
||||
@@ -1325,7 +1328,8 @@ check_domain_http_tcp()
|
||||
[ "$SKIP_PKTWS" = 1 ] || {
|
||||
echo
|
||||
echo preparing $PKTWSD redirection
|
||||
pktws_ipt_prepare_tcp $2 "$(mdig_resolve_all $IPV $4)"
|
||||
mdig_resolve_all $IPV ips $4
|
||||
pktws_ipt_prepare_tcp $2 "$ips"
|
||||
|
||||
pktws_check_domain_http_bypass $1 $3 $4
|
||||
|
||||
@@ -1339,6 +1343,8 @@ check_domain_http_udp()
|
||||
# $2 - port
|
||||
# $3 - domain
|
||||
|
||||
local ips
|
||||
|
||||
# in case was interrupted before
|
||||
pktws_ipt_unprepare_udp $2
|
||||
ws_kill
|
||||
@@ -1348,7 +1354,8 @@ check_domain_http_udp()
|
||||
[ "$SKIP_PKTWS" = 1 ] || {
|
||||
echo
|
||||
echo preparing $PKTWSD redirection
|
||||
pktws_ipt_prepare_udp $2 "$(mdig_resolve_all $IPV $3)"
|
||||
mdig_resolve_all $IPV ips $3
|
||||
pktws_ipt_prepare_udp $2 "$ips"
|
||||
|
||||
pktws_check_domain_http3_bypass $1 $3
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ filter_apply_hostlist_target()
|
||||
{
|
||||
# $1 - var name of nfqws params
|
||||
|
||||
local v parm parm1 parm2 parm3 parm4 parm5 parm6 parm7 parm8 parmNA
|
||||
local v parm parm1 parm2 parm3 parm4 parm5 parm6 parm7 parm8 parm9 parmNA
|
||||
eval v="\$$1"
|
||||
if contains "$v" "$HOSTLIST_MARKER" || contains "$v" "$HOSTLIST_NOAUTO_MARKER"; then
|
||||
[ "$MODE_FILTER" = hostlist -o "$MODE_FILTER" = autohostlist ] &&
|
||||
@@ -40,10 +40,11 @@ filter_apply_hostlist_target()
|
||||
parm5="${AUTOHOSTLIST_FAIL_THRESHOLD:+--hostlist-auto-fail-threshold=$AUTOHOSTLIST_FAIL_THRESHOLD}"
|
||||
parm6="${AUTOHOSTLIST_FAIL_TIME:+--hostlist-auto-fail-time=$AUTOHOSTLIST_FAIL_TIME}"
|
||||
parm7="${AUTOHOSTLIST_RETRANS_THRESHOLD:+--hostlist-auto-retrans-threshold=$AUTOHOSTLIST_RETRANS_THRESHOLD}"
|
||||
parm8="--hostlist=$HOSTLIST_AUTO"
|
||||
parm8="${AUTOHOSTLIST_RETRANS_MAXSEQ:+--hostlist-auto-retrans-maxseq=$AUTOHOSTLIST_RETRANS_MAXSEQ}"
|
||||
parm9="--hostlist=$HOSTLIST_AUTO"
|
||||
}
|
||||
parm="$parm1${parm2:+ $parm2}${parm3:+ $parm3}${parm4:+ $parm4}${parm5:+ $parm5}${parm6:+ $parm6}${parm7:+ $parm7}"
|
||||
parmNA="$parm1${parm2:+ $parm2}${parm3:+ $parm3}${parm8:+ $parm8}"
|
||||
parm="$parm1${parm2:+ $parm2}${parm3:+ $parm3}${parm4:+ $parm4}${parm5:+ $parm5}${parm6:+ $parm6}${parm7:+ $parm7}${parm8:+ $parm8}"
|
||||
parmNA="$parm1${parm2:+ $parm2}${parm3:+ $parm3}${parm9:+ $parm9}"
|
||||
}
|
||||
v="$(replace_str $HOSTLIST_NOAUTO_MARKER "$parmNA" "$v")"
|
||||
v="$(replace_str $HOSTLIST_MARKER "$parm" "$v")"
|
||||
|
||||
@@ -26,6 +26,7 @@ IPSET_OPT="hashsize 262144 maxelem $SET_MAXELEM"
|
||||
IP2NET_OPT4="--prefix-length=22-30 --v4-threshold=3/4"
|
||||
IP2NET_OPT6="--prefix-length=56-64 --v6-threshold=5"
|
||||
# options for auto hostlist
|
||||
AUTOHOSTLIST_RETRANS_MAXSEQ=65536
|
||||
AUTOHOSTLIST_RETRANS_THRESHOLD=3
|
||||
AUTOHOSTLIST_FAIL_THRESHOLD=3
|
||||
AUTOHOSTLIST_FAIL_TIME=60
|
||||
|
||||
@@ -36,6 +36,47 @@ v0.2
|
||||
* zapret-pcap
|
||||
|
||||
v0.3
|
||||
|
||||
* init.d launch scripts
|
||||
* init.d: 40-webserver custom script
|
||||
* install_easy
|
||||
|
||||
v0.4
|
||||
|
||||
* nfqws2: profile names and cookies
|
||||
* nfqws2: profile templates
|
||||
* nfqws2: remove stun_binding_req, replace to stun. no more message type details
|
||||
* nfqws2: proper conntack position for replayed packets
|
||||
* nfqws2: execution_plan, execution_plan_cancel
|
||||
* blockcheck2: fix broken dns cache
|
||||
* nfqws2: LUA_COMPAT_VER tracking
|
||||
|
||||
v0.5
|
||||
|
||||
* nfqws2: u8add,u16add,u24add,u32add luacalls
|
||||
* nfqws2: abandon any arithmetics beyond 32bit (because lua 5.1 does not support 64 bit integers, store everything as double)
|
||||
* nfqws2: fix issues with 32-bit lua_Integer in lua<5.3 on 32-bit platforms
|
||||
* nfqws2: instance_cutoff luacall just warns and do nothing if ctx is nil
|
||||
* actions: build nfqws2 x86 binary with LUA 5.4, not with luajit
|
||||
* zapret-lib: http_reply, url and nld dissectors
|
||||
* zapret-lib: instance_cutoff_shim
|
||||
* zapret-auto: circular orchestrator
|
||||
|
||||
v0.5.1
|
||||
|
||||
* zapret-auto: separate failure detection logic
|
||||
* blockcheck2: fix broken http3 test
|
||||
|
||||
v0.6
|
||||
|
||||
* zapret-lib,zapret-antidpi: tls_mod_shim supports sni=%var subst
|
||||
* blockcheck2: syndata tests
|
||||
* nfqws2: reasm support negative overlaps. gaps are not supported.
|
||||
* nfqws2,zapret-auto: changed retransmission detection scheme.
|
||||
* zapret-auto: udp_in/udp_out failure detection
|
||||
|
||||
v0.6.1
|
||||
|
||||
* zapret-lib, zapret-auto: condition and stopif orchestrators
|
||||
* zapret-lib: detect_payload_str - sample lua payload detector
|
||||
* blockcheck2: unterminated string fix
|
||||
|
||||
7
docs/changes_compat.txt
Normal file
7
docs/changes_compat.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Here listed all api breaking changes.
|
||||
When something changes capable of breaking things NFQWS2_COMPAT_VER increases.
|
||||
|
||||
v2
|
||||
* removed "stun_binding_req" specialized payload. replaced with common "stun" - any stun packets, not only binding request.
|
||||
every LUA relying on desync.l7payload should be revised.
|
||||
nfqws2 --payload option and init.d custom scripts must be updated.
|
||||
@@ -361,7 +361,7 @@ start "zapret: http,https,quic" /min "%~dp0winws2.exe" ^
|
||||
--new ^
|
||||
--filter-l7=wireguard,stun,discord ^
|
||||
--out-range=-d10 ^
|
||||
--payload=wireguard_initiation,wireguard_cookie,stun_binding_req,discord_ip_discovery ^
|
||||
--payload=wireguard_initiation,wireguard_cookie,stun,discord_ip_discovery ^
|
||||
--lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2
|
||||
```
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
|
||||
|
||||
# can override in config :
|
||||
NFQWS_OPT_DESYNC_STUN="${NFQWS_OPT_DESYNC_STUN:---payload stun_binding_req --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
|
||||
NFQWS_OPT_DESYNC_STUN="${NFQWS_OPT_DESYNC_STUN:---payload stun --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
|
||||
|
||||
alloc_dnum DNUM_STUN4ALL
|
||||
alloc_qnum QNUM_STUN4ALL
|
||||
|
||||
@@ -41,7 +41,7 @@ PIDDIR=/var/run
|
||||
|
||||
USEROPT="--user=$WS_USER"
|
||||
NFQWS2="${NFQWS2:-$ZAPRET_BASE/nfq2/nfqws2}"
|
||||
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua"
|
||||
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua --lua-init=@$ZAPRET_BASE/lua/zapret-auto.lua"
|
||||
NFQWS2_OPT_BASE="$USEROPT --fwmark=$DESYNC_MARK $LUAOPT"
|
||||
|
||||
run_daemon()
|
||||
|
||||
@@ -72,7 +72,7 @@ DESYNC_MARK_POSTNAT=${DESYNC_MARK_POSTNAT:-0x20000000}
|
||||
|
||||
QNUM=${QNUM:-300}
|
||||
NFQWS2="${NFQWS2:-$ZAPRET_BASE/nfq2/nfqws2}"
|
||||
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua"
|
||||
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua --lua-init=@$ZAPRET_BASE/lua/zapret-auto.lua"
|
||||
NFQWS2_OPT_BASE="$USEROPT --fwmark=$DESYNC_MARK $LUAOPT"
|
||||
|
||||
|
||||
|
||||
@@ -113,7 +113,7 @@ end
|
||||
-- standard args : direction
|
||||
function http_domcase(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -139,7 +139,7 @@ end
|
||||
-- arg : spell=<str> . spelling of the "Host" header. must be exactly 4 chars long
|
||||
function http_hostcase(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -164,7 +164,7 @@ end
|
||||
-- standard args : direction
|
||||
function http_methodeol(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -221,10 +221,10 @@ function synack_split(ctx, desync)
|
||||
error("synack_split: bad mode '"..mode.."'")
|
||||
end
|
||||
else
|
||||
instance_cutoff(ctx) -- mission complete
|
||||
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||
end
|
||||
else
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -238,10 +238,10 @@ function synack(ctx, desync)
|
||||
DLOG("synack: sending")
|
||||
rawsend_dissect_ipfrag(dis, desync_opts(desync))
|
||||
else
|
||||
instance_cutoff(ctx) -- mission complete
|
||||
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||
end
|
||||
else
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -256,10 +256,10 @@ function wsize(ctx, desync)
|
||||
return VERDICT_MODIFY
|
||||
end
|
||||
else
|
||||
instance_cutoff(ctx) -- mission complete
|
||||
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||
end
|
||||
else
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -270,7 +270,7 @@ end
|
||||
-- arg : forced_cutoff=<list> - comma separated list of payloads that trigger forced wssize cutoff. by default - any non-empty payload
|
||||
function wssize(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
local verdict = VERDICT_PASS
|
||||
@@ -281,7 +281,7 @@ function wssize(ctx, desync)
|
||||
end
|
||||
if #desync.dis.payload>0 and (not desync.arg.forced_cutoff or in_list(desync.arg.forced_cutoff, desync.l7payload)) then
|
||||
DLOG("wssize: forced cutoff")
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
end
|
||||
end
|
||||
return verdict
|
||||
@@ -290,7 +290,7 @@ end
|
||||
-- nfqws1 : "--dpi-desync=syndata"
|
||||
-- standard args : fooling, rawsend, reconstruct, ipfrag
|
||||
-- arg : blob=<blob> - fake payload. must fit to single packet. no segmentation possible. default - 16 zero bytes.
|
||||
-- arg : tls_mod=<list> - comma separated list of tls mods : rnd,rndsni,sni=<str>,dupsid,padencap
|
||||
-- arg : tls_mod=<list> - comma separated list of tls mods : rnd,rndsni,sni=<str>. sni=%var is supported
|
||||
function syndata(ctx, desync)
|
||||
if desync.dis.tcp then
|
||||
if bitand(desync.dis.tcp.th_flags, TH_SYN + TH_ACK)==TH_SYN then
|
||||
@@ -298,17 +298,17 @@ function syndata(ctx, desync)
|
||||
dis.payload = blob(desync, desync.arg.blob, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
|
||||
apply_fooling(desync, dis)
|
||||
if desync.arg.tls_mod then
|
||||
dis.payload = tls_mod(dis.payload, desync.arg.tls_mod, nil)
|
||||
dis.payload = tls_mod_shim(desync, dis.payload, desync.arg.tls_mod, nil)
|
||||
end
|
||||
if b_debug then DLOG("syndata: "..hexdump_dlog(dis.payload)) end
|
||||
if rawsend_dissect_ipfrag(dis, desync_opts(desync)) then
|
||||
return VERDICT_DROP
|
||||
end
|
||||
else
|
||||
instance_cutoff(ctx) -- mission complete
|
||||
instance_cutoff_shim(ctx, desync) -- mission complete
|
||||
end
|
||||
else
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -317,7 +317,7 @@ end
|
||||
-- arg : rstack - send RST,ACK instead of RST
|
||||
function rst(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -340,7 +340,7 @@ end
|
||||
-- nfqws1 : "--dpi-desync=fake"
|
||||
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
|
||||
-- arg : blob=<blob> - fake payload
|
||||
-- arg : tls_mod=<list> - comma separated list of tls mods : rnd,rndsni,sni=<str>,dupsid,padencap
|
||||
-- arg : tls_mod=<list> - comma separated list of tls mods : rnd,rndsni,sni=<str>,dupsid,padencap . sni=%var is supported
|
||||
function fake(ctx, desync)
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
-- by default process only outgoing known payloads
|
||||
@@ -351,7 +351,7 @@ function fake(ctx, desync)
|
||||
end
|
||||
local fake_payload = blob(desync, desync.arg.blob)
|
||||
if desync.reasm_data and desync.arg.tls_mod then
|
||||
fake_payload = tls_mod(fake_payload, desync.arg.tls_mod, desync.reasm_data)
|
||||
fake_payload = tls_mod_shim(desync, fake_payload, desync.arg.tls_mod, desync.reasm_data)
|
||||
end
|
||||
-- check debug to save CPU
|
||||
if b_debug then DLOG("fake: "..hexdump_dlog(fake_payload)) end
|
||||
@@ -371,7 +371,7 @@ end
|
||||
-- arg : nodrop - do not drop current dissect
|
||||
function multisplit(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -421,11 +421,11 @@ end
|
||||
-- arg : pos=<postmarker list> . position marker list. example : "1,host,midsld+1,-10"
|
||||
-- arg : seqovl=N . decrease seq number of the second segment in the original order by N and fill N bytes with pattern (default - all zero). N must be less than the first split pos.
|
||||
-- arg : seqovl_pattern=<blob> . override pattern
|
||||
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||
-- arg : blob=<blob> - use this data instead of reasm_data
|
||||
-- arg : nodrop - do not drop current dissect
|
||||
function multidisorder(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -491,7 +491,7 @@ end
|
||||
-- arg : nodrop - do not drop current dissect
|
||||
function hostfakesplit(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -600,11 +600,11 @@ end
|
||||
-- arg : pattern=<blob> . fill fake parts with this pattern
|
||||
-- arg : seqovl=N . decrease seq number of the first segment by N and fill N bytes with pattern (default - all zero)
|
||||
-- arg : seqovl_pattern=<blob> . override seqovl pattern
|
||||
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||
-- arg : blob=<blob> - use this data instead of reasm_data
|
||||
-- arg : nodrop - do not drop current dissect
|
||||
function fakedsplit(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -697,7 +697,7 @@ end
|
||||
-- arg : nodrop - do not drop current dissect
|
||||
function fakeddisorder(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -797,7 +797,7 @@ end
|
||||
-- arg : blob=<blob> - use this data instead of desync.dis.payload
|
||||
function tcpseg(ctx, desync)
|
||||
if not desync.dis.tcp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -841,7 +841,7 @@ end
|
||||
-- arg : pattern_offset=N . offset in the pattern. 0 by default
|
||||
function udplen(ctx, desync)
|
||||
if not desync.dis.udp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
@@ -877,7 +877,7 @@ end
|
||||
-- arg : dn=N - message starts from "dN". 2 by default
|
||||
function dht_dn(ctx, desync)
|
||||
if not desync.dis.udp then
|
||||
instance_cutoff(ctx)
|
||||
instance_cutoff_shim(ctx, desync)
|
||||
return
|
||||
end
|
||||
direction_cutoff_opposite(ctx, desync)
|
||||
|
||||
320
lua/zapret-auto.lua
Normal file
320
lua/zapret-auto.lua
Normal file
@@ -0,0 +1,320 @@
|
||||
-- standard automation/orchestration code
|
||||
-- this is related to making dynamic strategy decisions without rewriting or altering strategy function code
|
||||
-- orchestrators can decide which instances to call or not to call or pass them dynamic arguments
|
||||
-- failure detectors test potential block conditions for orchestrators
|
||||
|
||||
-- arg: reqhost - require hostname, do not work with ip
|
||||
function automate_host_record(desync)
|
||||
local key
|
||||
if desync.arg.reqhost then
|
||||
key = desync.track and desync.track.hostname
|
||||
else
|
||||
key = host_or_ip(desync)
|
||||
end
|
||||
if not key then
|
||||
DLOG("automate: host record key unavailable")
|
||||
return nil
|
||||
end
|
||||
DLOG("automate: host record key '"..key.."'")
|
||||
if not autostate then
|
||||
autostate = {}
|
||||
end
|
||||
if not autostate[key] then
|
||||
autostate[key] = {}
|
||||
end
|
||||
return autostate[key]
|
||||
end
|
||||
function automate_conn_record(desync)
|
||||
if not desync.track.lua_state.automate then
|
||||
desync.track.lua_state.automate = {}
|
||||
end
|
||||
return desync.track.lua_state.automate
|
||||
end
|
||||
|
||||
-- counts failure, optionally (if crec is given) prevents dup failure counts in a single connection
|
||||
-- if 'maxtime' between failures is exceeded then failure count is reset
|
||||
-- return true if threshold ('fails') is reached
|
||||
-- hres is host record. host or ip bound table
|
||||
-- cres is connection record. connection bound table
|
||||
function automate_failure_counter(hrec, crec, fails, maxtime)
|
||||
if crec and crec.failure then
|
||||
DLOG("automate: duplicate failure in the same connection. not counted")
|
||||
else
|
||||
if crec then crec.failure = true end
|
||||
local tnow=os.time()
|
||||
if not hrec.failure_time_last then
|
||||
hrec.failure_time_last = tnow
|
||||
end
|
||||
if not hrec.failure_counter then
|
||||
hrec.failure_counter = 0
|
||||
elseif tnow>(hrec.failure_time_last + maxtime) then
|
||||
DLOG("automate: failure counter reset because last failure was "..(tnow - hrec.failure_time_last).." seconds ago")
|
||||
hrec.failure_counter = 0
|
||||
end
|
||||
hrec.failure_counter = hrec.failure_counter + 1
|
||||
hrec.failure_time_last = tnow
|
||||
if b_debug then DLOG("automate: failure counter "..hrec.failure_counter..(fails and ('/'..fails) or '')) end
|
||||
if fails and hrec.failure_counter>=fails then
|
||||
hrec.failure_counter = nil -- reset counter
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- location is url compatible with Location: header
|
||||
-- hostname is original hostname
|
||||
function is_dpi_redirect(hostname, location)
|
||||
local ds = dissect_url(location)
|
||||
if ds.domain then
|
||||
local sld1 = dissect_nld(hostname,2)
|
||||
local sld2 = dissect_nld(ds.domain,2)
|
||||
return sld2 and sld1~=sld2
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
-- standard failure detector
|
||||
-- works with tcp and udp
|
||||
-- detected failures:
|
||||
-- incoming RST
|
||||
-- incoming http redirection
|
||||
-- outgoing retransmissions
|
||||
-- udp too much out with too few in
|
||||
-- arg: seq=<rseq> - tcp: if packet is beyond this relative sequence number treat this connection as successful. default is 64K
|
||||
-- arg: retrans=N - tcp: retrans count threshold. default is 3
|
||||
-- arg: rst=<rseq> - tcp: maximum relative sequence number to treat incoming RST as DPI reset. default is 1
|
||||
-- arg: no_http_redirect - tcp: disable http_reply dpi redirect trigger
|
||||
-- arg: udp_out - udp: >= outgoing udp packets. default is 3
|
||||
-- arg: udp_in - udp: with <= incoming udp packets. default is 1
|
||||
function standard_failure_detector(desync, crec, arg)
|
||||
if crec.nocheck then return false end
|
||||
|
||||
local seq_rst = tonumber(arg.rst) or 1
|
||||
local retrans = tonumber(arg.retrans) or 3
|
||||
local maxseq = tonumber(arg.seq) or 0x10000
|
||||
local udp_in = tonumber(arg.udp_in) or 1
|
||||
local udp_out = tonumber(arg.udp_out) or 3
|
||||
|
||||
local trigger = false
|
||||
if desync.dis.tcp then
|
||||
local seq = pos_get(desync,'s')
|
||||
if maxseq and seq>maxseq then
|
||||
DLOG("standard_failure_detector: s"..seq.." is beyond s"..maxseq..". treating connection as successful")
|
||||
crec.nocheck = true
|
||||
return false
|
||||
end
|
||||
|
||||
if desync.outgoing then
|
||||
if #desync.dis.payload>0 and retrans and (crec.retrans or 0)<retrans then
|
||||
if is_retransmission(desync) then
|
||||
crec.retrans = crec.retrans and (crec.retrans+1) or 1
|
||||
DLOG("standard_failure_detector: retransmission "..crec.retrans.."/"..retrans)
|
||||
trigger = crec.retrans>=retrans
|
||||
end
|
||||
end
|
||||
else
|
||||
if seq_rst and bitand(desync.dis.tcp.th_flags, TH_RST)~=0 then
|
||||
trigger = seq<=seq_rst
|
||||
if b_debug then
|
||||
if trigger then
|
||||
DLOG("standard_failure_detector: incoming RST s"..seq.." in range s"..seq_rst)
|
||||
else
|
||||
DLOG("standard_failure_detector: not counting incoming RST s"..seq.." beyond s"..seq_rst)
|
||||
end
|
||||
end
|
||||
elseif not arg.no_http_redirect and desync.l7payload=="http_reply" and desync.track.hostname then
|
||||
local hdis = http_dissect_reply(desync.dis.payload)
|
||||
if hdis and (hdis.code==302 or hdis.code==307) and hdis.headers.location and hdis.headers.location then
|
||||
trigger = is_dpi_redirect(desync.track.hostname, hdis.headers.location.value)
|
||||
if b_debug then
|
||||
if trigger then
|
||||
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'. looks like DPI redirect.")
|
||||
else
|
||||
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'. NOT a DPI redirect.")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif desync.dis.udp then
|
||||
if desync.outgoing then
|
||||
if udp_out then
|
||||
local udp_in = udp_in or 0
|
||||
trigger = desync.track.pcounter_orig>=udp_out and desync.track.pcounter_reply<=udp_in
|
||||
if trigger then
|
||||
crec.nocheck = true
|
||||
if b_debug then
|
||||
DLOG("standard_failure_detector: udp_out "..desync.track.pcounter_orig..">="..udp_out.." udp_in "..desync.track.pcounter_reply.."<="..udp_in)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return trigger
|
||||
end
|
||||
|
||||
-- circularily change strategy numbers when failure count reaches threshold ('fails')
|
||||
-- works with tcp only
|
||||
-- this orchestrator requires redirection of incoming traffic to cache RST and http replies !
|
||||
-- each orchestrated instance must have strategy=N arg, where N starts from 1 and increment without gaps
|
||||
-- if 'final' arg is present in an orchestrated instance it stops rotation
|
||||
-- arg: fails=N - failture count threshold. default is 3
|
||||
-- arg: time=<sec> - if last failure happened earlier than `maxtime` seconds ago - reset failure counter. default is 60.
|
||||
-- arg: reqhost - pass with no tampering if hostname is unavailable
|
||||
-- arg: detector - failure detector function name.
|
||||
-- args for failure detector - see standard_failure_detector or your own detector
|
||||
-- test case: 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
|
||||
function circular(ctx, desync)
|
||||
local function count_strategies(hrec)
|
||||
if not hrec.ctstrategy then
|
||||
local uniq={}
|
||||
local n=0
|
||||
for i,instance in pairs(desync.plan) do
|
||||
if instance.arg.strategy then
|
||||
n = tonumber(instance.arg.strategy)
|
||||
if not n or n<1 then
|
||||
error("circular: strategy number '"..tostring(instance.arg.strategy).."' is invalid")
|
||||
end
|
||||
uniq[tonumber(instance.arg.strategy)] = true
|
||||
if instance.arg.final then
|
||||
hrec.final = n
|
||||
end
|
||||
end
|
||||
end
|
||||
n=0
|
||||
for i,v in pairs(uniq) do
|
||||
n=n+1
|
||||
end
|
||||
if n~=#uniq then
|
||||
error("circular: strategies numbers must start from 1 and increment. gaps are not allowed.")
|
||||
end
|
||||
hrec.ctstrategy = n
|
||||
end
|
||||
end
|
||||
|
||||
-- take over execution. prevent further instance execution in case of error
|
||||
orchestrate(ctx, desync)
|
||||
|
||||
if not desync.track then
|
||||
DLOG_ERR("circular: conntrack is missing but required")
|
||||
return
|
||||
end
|
||||
|
||||
local hrec = automate_host_record(desync)
|
||||
if not hrec then
|
||||
DLOG("circular: passing with no tampering")
|
||||
return
|
||||
end
|
||||
|
||||
count_strategies(hrec)
|
||||
if hrec.ctstrategy==0 then
|
||||
error("circular: add strategy=N tag argument to each following instance ! N must start from 1 and increment")
|
||||
end
|
||||
if not hrec.nstrategy then
|
||||
DLOG("circular: start from strategy 1")
|
||||
hrec.nstrategy = 1
|
||||
end
|
||||
|
||||
local verdict = VERDICT_PASS
|
||||
if hrec.final~=hrec.nstrategy then
|
||||
local crec = automate_conn_record(desync)
|
||||
local fails = tonumber(desync.arg.fails) or 3
|
||||
local maxtime = tonumber(desync.arg.time) or 60
|
||||
local failure_detector
|
||||
if desync.arg.detector then
|
||||
if type(_G[desync.arg.detector])~="function" then
|
||||
error("circular: invalid failure detector function '"..desync.arg.detector.."'")
|
||||
end
|
||||
failure_detector = _G[desync.arg.detector]
|
||||
else
|
||||
failure_detector = standard_failure_detector
|
||||
end
|
||||
if failure_detector(desync,crec,desync.arg) then
|
||||
-- failure happened. count failures.
|
||||
if automate_failure_counter(hrec, crec, fails, maxtime) then
|
||||
-- counter reaches threshold. circular strategy change
|
||||
hrec.nstrategy = (hrec.nstrategy % hrec.ctstrategy) + 1
|
||||
DLOG("circular: rotate strategy to "..hrec.nstrategy)
|
||||
if hrec.nstrategy == hrec.final then
|
||||
DLOG("circular: final strategy "..hrec.final.." reached. will rotate no more.")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
DLOG("circular: current strategy "..hrec.nstrategy)
|
||||
local dcopy = desync_copy(desync)
|
||||
while true do
|
||||
local instance = plan_instance_pop(desync)
|
||||
if not instance then break end
|
||||
if instance.arg.strategy and tonumber(instance.arg.strategy)==hrec.nstrategy then
|
||||
verdict = plan_instance_execute(dcopy, verdict, instance)
|
||||
end
|
||||
end
|
||||
|
||||
return verdict
|
||||
end
|
||||
|
||||
-- test iff functions
|
||||
function cond_true(desync)
|
||||
return true
|
||||
end
|
||||
function cond_false(desync)
|
||||
return false
|
||||
end
|
||||
-- arg: percent - of true . 50 by default
|
||||
function cond_random(desync)
|
||||
return math.random(0,99)<(tonumber(desync.arg.percent) or 50)
|
||||
end
|
||||
-- this iif function detects packets having 'arg.pattern' string in their payload
|
||||
-- test case : 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 --lua-desync=argdebug:testarg=2:morearg=xyz
|
||||
-- test case (true) : echo aaz1234zzz | ncat -4u 1.1.1.1 443
|
||||
-- test case (false) : echo aaze124zzz | ncat -4u 1.1.1.1 443
|
||||
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
|
||||
-- check iff function available. error if not
|
||||
function require_iff(desync, name)
|
||||
if not desync.arg.iff then
|
||||
error(name..": missing 'iff' function")
|
||||
end
|
||||
if type(_G[desync.arg.iff])~="function" then
|
||||
error(name..": invalid 'iff' function '"..desync.arg.iff.."'")
|
||||
end
|
||||
end
|
||||
-- execute further desync instances only if user-provided 'iff' function returns true
|
||||
-- for example, this can be used by custom protocol detectors
|
||||
-- arg: iff - condition function. takes desync as arg and returns bool. (cant use 'if' because of reserved word)
|
||||
-- arg: neg - invert condition function result
|
||||
-- test case : 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=xyz
|
||||
function condition(ctx, desync)
|
||||
require_iff(desync, "condition")
|
||||
orchestrate(ctx, desync)
|
||||
if logical_xor(_G[desync.arg.iff](desync), desync.arg.neg) then
|
||||
DLOG("condition: true")
|
||||
return replay_execution_plan(desync)
|
||||
else
|
||||
DLOG("condition: false")
|
||||
plan_clear(desync)
|
||||
end
|
||||
end
|
||||
-- clear execution plan if user provided 'iff' functions returns true
|
||||
-- can be used with other orchestrators to stop execution conditionally
|
||||
-- arg: iff - condition function. takes desync as arg and returns bool. (cant use 'if' because of reserved word)
|
||||
-- arg: neg - invert condition function result
|
||||
-- test case : nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua --in-range=-s1 --lua-desync=circular --lua-desync=stopif:iff=cond_random:strategy=1 --lua-desync=argdebug:strategy=1 --lua-desync=argdebug:strategy=2
|
||||
function stopif(ctx, desync)
|
||||
require_iff(desync, "stopif")
|
||||
orchestrate(ctx, desync)
|
||||
if logical_xor(_G[desync.arg.iff](desync), desync.arg.neg) then
|
||||
DLOG("stopif: true")
|
||||
plan_clear(desync)
|
||||
else
|
||||
-- do not do anything. allow other orchestrator to finish the plan
|
||||
DLOG("stopif: false")
|
||||
end
|
||||
end
|
||||
@@ -1,8 +1,8 @@
|
||||
HEXDUMP_DLOG_MAX = HEXDUMP_DLOG_MAX or 32
|
||||
NOT3=bitnot(3)
|
||||
NOT7=bitnot(7)
|
||||
math.randomseed(os.time())
|
||||
|
||||
-- xor pid,tid,sec,nsec
|
||||
math.randomseed(bitxor(getpid(),gettid(),clock_gettime()))
|
||||
|
||||
-- basic desync function
|
||||
-- execute given lua code. "desync" is temporary set as global var to be accessible to the code
|
||||
@@ -35,8 +35,249 @@ function pktdebug(ctx, desync)
|
||||
DLOG("desync:")
|
||||
var_debug(desync)
|
||||
end
|
||||
-- basic desync function
|
||||
-- prints function args
|
||||
function argdebug(ctx,desync)
|
||||
var_debug(desync.arg)
|
||||
end
|
||||
|
||||
-- basic desync function
|
||||
-- prints conntrack positions to DLOG
|
||||
function posdebug(ctx,desync)
|
||||
local s="posdebug:"
|
||||
for i,pos in pairs({'n','d','b','s'}) do
|
||||
s=s.." "..pos..pos_get(desync,pos)
|
||||
end
|
||||
s=s.." payload "..#desync.dis.payload
|
||||
if desync.reasm_data then
|
||||
s=s.." reasm "..#desync.reasm_data
|
||||
end
|
||||
if desync.decrypt_data then
|
||||
s=s.." decrypt "..#desync.decrypt_data
|
||||
end
|
||||
if desync.replay_piece_count then
|
||||
s=s.." replay "..desync.replay_piece.."/"..desync.replay_piece_count
|
||||
end
|
||||
DLOG(s)
|
||||
end
|
||||
|
||||
-- basic desync function
|
||||
-- set l7payload to 'arg.payload' if reasm.data or desync.dis.payload contains 'arg.pattern' substring
|
||||
-- NOTE : this does not set payload on C code side !
|
||||
-- NOTE : C code will not see payload change. --payload args take only payloads known to C code and cause error if unknown.
|
||||
-- arg: pattern - substring for search inside reasm_data or desync.dis.payload
|
||||
-- arg: payload - set desync.l7payload to this if detected
|
||||
-- arg: undetected - set desync.l7payload to this if not detected
|
||||
-- test case : nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua --lua-init=@zapret-auto.lua --lua-desync=detect_payload_str:pattern=1234:payload=my --lua-desync=fake:blob=0x1234:payload=my
|
||||
function detect_payload_str(ctx, desync)
|
||||
if not desync.arg.pattern then
|
||||
error("detect_payload_str: missing 'pattern'")
|
||||
end
|
||||
local data = desync.reasm_data or desync.dis.payload
|
||||
local b = string.find(data,desync.arg.pattern,1,true)
|
||||
if b then
|
||||
DLOG("detect_payload_str: detected '"..desync.arg.payload.."'")
|
||||
if desync.arg.payload then desync.l7payload = desync.arg.payload end
|
||||
else
|
||||
DLOG("detect_payload_str: not detected '"..desync.arg.payload.."'")
|
||||
if desync.arg.undetected then desync.l7payload = desync.arg.undetected end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- this shim is needed then function is orchestrated. ctx services not available
|
||||
-- have to emulate cutoff in LUA using connection persistent table track.lua_state
|
||||
function instance_cutoff_shim(ctx, desync, dir)
|
||||
if ctx then
|
||||
instance_cutoff(ctx, dir)
|
||||
elseif not desync.track then
|
||||
DLOG("instance_cutoff_shim: cannot cutoff '"..desync.func_instance.."' because conntrack is absent")
|
||||
else
|
||||
if not desync.track.lua_state.cutoff_shim then
|
||||
desync.track.lua_state.cutoff_shim = {}
|
||||
end
|
||||
if not desync.track.lua_state.cutoff_shim[desync.func_instance] then
|
||||
desync.track.lua_state.cutoff_shim[desync.func_instance] = {}
|
||||
end
|
||||
if type(dir)=="nil" then
|
||||
-- cutoff both directions by default
|
||||
desync.track.lua_state.cutoff_shim[desync.func_instance][true] = true
|
||||
desync.track.lua_state.cutoff_shim[desync.func_instance][false] = true
|
||||
else
|
||||
desync.track.lua_state.cutoff_shim[desync.func_instance][dir] = true
|
||||
end
|
||||
if b_debug then DLOG("instance_cutoff_shim: cutoff '"..desync.func_instance.."' in="..tostring(type(dir)=="nil" and true or not dir).." out="..tostring(type(dir)=="nil" or dir)) end
|
||||
end
|
||||
end
|
||||
function cutoff_shim_check(desync)
|
||||
if not desync.track then
|
||||
DLOG("cutoff_shim_check: cannot check '"..desync.func_instance.."' cutoff because conntrack is absent")
|
||||
return false
|
||||
else
|
||||
local b=desync.track.lua_state.cutoff_shim and
|
||||
desync.track.lua_state.cutoff_shim[desync.func_instance] and
|
||||
desync.track.lua_state.cutoff_shim[desync.func_instance][desync.outgoing]
|
||||
if b and b_debug then
|
||||
DLOG("cutoff_shim_check: '"..desync.func_instance.."' "..(desync.outgoing and "out" or "in").." cutoff")
|
||||
end
|
||||
return b
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
-- applies # and $ prefixes. #var means var length, %var means var value
|
||||
function apply_arg_prefix(arg)
|
||||
for a,v in pairs(arg) do
|
||||
local c = string.sub(v,1,1)
|
||||
if v=='#' then
|
||||
arg[a] = #_G[string.sub(v,2)]
|
||||
elseif v=='%' then
|
||||
arg[a] = _G[string.sub(v,2)]
|
||||
elseif v=='\\' then
|
||||
c = string.sub(v,2,2);
|
||||
if c=='#' or c=='%' then
|
||||
arg[a] = string.sub(v,2)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
-- copy instance identification and args from execution plan to desync table
|
||||
function apply_execution_plan(desync, instance)
|
||||
desync.func = instance.func
|
||||
desync.func_n = instance.func_n
|
||||
desync.func_instance = instance.func_instance
|
||||
desync.arg = deepcopy(instance.arg)
|
||||
apply_arg_prefix(desync.arg)
|
||||
end
|
||||
-- produce resulting verdict from 2 verdicts
|
||||
function verdict_aggregate(v1, v2)
|
||||
local v
|
||||
v1 = v1 or VERDICT_PASS
|
||||
v2 = v2 or VERDICT_PASS
|
||||
if v1==VERDICT_DROP or v2==VERDICT_DROP then
|
||||
v=VERDICT_DROP
|
||||
elseif v1==VERDICT_MODIFY or v2==VERDICT_MODIFY then
|
||||
v=VERDICT_MODIFY
|
||||
else
|
||||
v=VERDICT_PASS
|
||||
end
|
||||
return v
|
||||
end
|
||||
function plan_instance_execute(desync, verdict, instance)
|
||||
apply_execution_plan(desync, instance)
|
||||
if cutoff_shim_check(desync) then
|
||||
DLOG("plan_instance_execute: not calling '"..desync.func_instance.."' because of voluntary cutoff")
|
||||
elseif not payload_match_filter(desync.l7payload, instance.payload_filter) then
|
||||
DLOG("plan_instance_execute: not calling '"..desync.func_instance.."' because payload '"..desync.l7payload.."' does not match filter '"..instance.payload_filter.."'")
|
||||
elseif not pos_check_range(desync, instance.range) then
|
||||
DLOG("plan_instance_execute: not calling '"..desync.func_instance.."' because pos "..pos_str(desync,instance.range.from).." "..pos_str(desync,instance.range.to).." is out of range '"..pos_range_str(instance.range).."'")
|
||||
else
|
||||
DLOG("plan_instance_execute: calling '"..desync.func_instance.."'")
|
||||
verdict = verdict_aggregate(verdict,_G[instance.func](nil, desync))
|
||||
end
|
||||
return verdict
|
||||
end
|
||||
function plan_instance_pop(desync)
|
||||
return (desync.plan and #desync.plan>0) and table.remove(desync.plan, 1)
|
||||
end
|
||||
function plan_clear(desync)
|
||||
while table.remove(desync.plan) do end
|
||||
end
|
||||
-- this approach allows nested orchestrators
|
||||
function orchestrate(ctx, desync)
|
||||
if not desync.plan then
|
||||
execution_plan_cancel(ctx)
|
||||
desync.plan = execution_plan(ctx)
|
||||
end
|
||||
end
|
||||
-- copy desync preserving lua_state
|
||||
function desync_copy(desync)
|
||||
local dcopy = deepcopy(desync)
|
||||
if desync.track then
|
||||
-- preserve lua state
|
||||
dcopy.track.lua_state = desync.track.lua_state
|
||||
end
|
||||
if desync.plan then
|
||||
-- preserve execution plan
|
||||
dcopy.plan = desync.plan
|
||||
end
|
||||
return dcopy
|
||||
end
|
||||
-- redo what whould be done without orchestration
|
||||
function replay_execution_plan(desync)
|
||||
local dcopy = desync_copy(desync)
|
||||
local verdict = VERDICT_PASS
|
||||
while true do
|
||||
local instance = plan_instance_pop(dcopy)
|
||||
if not instance then break end
|
||||
verdict = plan_instance_execute(dcopy, verdict, instance)
|
||||
end
|
||||
return verdict
|
||||
end
|
||||
-- this function demonstrates how to stop execution of upcoming desync instances and take over their job
|
||||
-- this can be used, for example, for orchestrating conditional processing without modifying of desync functions code
|
||||
-- test case : nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-desync=desync_orchestrator_example --lua-desync=pass --lua-desync=pass
|
||||
function desync_orchestrator_example(ctx, desync)
|
||||
DLOG("orchestrator: taking over upcoming desync instances")
|
||||
orchestrate(ctx, desync)
|
||||
return replay_execution_plan(desync)
|
||||
end
|
||||
|
||||
-- these functions duplicate range check logic from C code
|
||||
-- mode must be n,d,b,s,x,a
|
||||
-- pos is {mode,pos}
|
||||
-- range is {from={mode,pos}, to={mode,pos}, upper_cutoff}
|
||||
-- upper_cutoff = true means non-inclusive upper boundary
|
||||
function pos_get(desync, mode)
|
||||
if desync.track then
|
||||
if mode=='n' then
|
||||
return desync.outgoing and desync.track.pcounter_orig or desync.track.pcounter_reply
|
||||
elseif mode=='d' then
|
||||
return desync.outgoing and desync.track.pdcounter_orig or desync.track.pdcounter_reply
|
||||
elseif mode=='b' then
|
||||
return desync.outgoing and desync.track.pbcounter_orig or desync.track.pbcounter_reply
|
||||
elseif mode=='s' and desync.track.tcp then
|
||||
return desync.outgoing and u32add(desync.track.tcp.seq, -desync.track.tcp.seq0) or u32add(desync.track.tcp.ack, -desync.track.tcp.ack0)
|
||||
end
|
||||
end
|
||||
return 0
|
||||
end
|
||||
function pos_check_from(desync, range)
|
||||
if range.from.mode == 'x' then return false end
|
||||
if range.from.mode ~= 'a' then
|
||||
if desync.track then
|
||||
return pos_get(desync, range.from.mode) >= range.from.pos
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true;
|
||||
end
|
||||
function pos_check_to(desync, range)
|
||||
local ps
|
||||
if range.to.mode == 'x' then return false end
|
||||
if range.to.mode ~= 'a' then
|
||||
if desync.track then
|
||||
ps = pos_get(desync, range.to.mode)
|
||||
return (ps < range.to.pos) or not range.upper_cutoff and (ps == range.to.pos)
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true;
|
||||
end
|
||||
function pos_check_range(desync, range)
|
||||
return pos_check_from(desync,range) and pos_check_to(desync,range)
|
||||
end
|
||||
function pos_range_str(range)
|
||||
return range.from.mode..range.from.pos..(range.upper_cutoff and '<' or '-')..range.to.mode..range.to.pos
|
||||
end
|
||||
function pos_str(desync, pos)
|
||||
return pos.mode..pos_get(desync, pos.mode)
|
||||
end
|
||||
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
|
||||
|
||||
-- prepare standard rawsend options from desync
|
||||
-- repeats - how many time send the packet
|
||||
@@ -108,12 +349,15 @@ function str_or_hex(s)
|
||||
return s
|
||||
end
|
||||
end
|
||||
function logical_xor(a,b)
|
||||
return a and not b or not a and b
|
||||
end
|
||||
-- print to DLOG any variable. tables are expanded in the tree form, unprintables strings are hex dumped
|
||||
function var_debug(v)
|
||||
local function dbg(v,level)
|
||||
if type(v)=="table" then
|
||||
for key, value in pairs(v) do
|
||||
DLOG(string.rep(" ",2*level).."."..key)
|
||||
DLOG(string.rep(" ",2*level).."."..tostring(key))
|
||||
dbg(v[key],level+1)
|
||||
end
|
||||
elseif type(v)=="string" then
|
||||
@@ -301,6 +545,88 @@ function http_dissect_req(http)
|
||||
local uri = string.sub(req,pos,pnext-1)
|
||||
return { method = method, uri = uri, headers = http_dissect_headers(http,hdrpos) }
|
||||
end
|
||||
function http_dissect_reply(http)
|
||||
if not http then return nil; end
|
||||
local s, pos, code
|
||||
s = string.sub(http,1,8)
|
||||
if s~="HTTP/1.1" and s~="HTTP/1.0" then return nil end
|
||||
pos = string.find(http,"[ \t\r\n]",10)
|
||||
code = tonumber(string.sub(http,10,pos-1))
|
||||
if not code then return nil end
|
||||
pos = find_next_line(http,pos)
|
||||
return { code = code, headers = http_dissect_headers(http,pos) }
|
||||
end
|
||||
function dissect_url(url)
|
||||
local p1,pb,pstart,pend
|
||||
local proto, creds, domain, port, uri
|
||||
p1 = string.find(url,"[^ \t]")
|
||||
if not p1 then return nil end
|
||||
pb = p1
|
||||
pstart,pend = string.find(url,"[a-z]+://",p1)
|
||||
if pend then
|
||||
proto = string.sub(url,pstart,pend-3)
|
||||
p1 = pend+1
|
||||
end
|
||||
pstart,pend = string.find(url,"[@/]",p1)
|
||||
if pend and string.sub(url,pstart,pend)=='@' then
|
||||
creds = string.sub(url,p1,pend-1)
|
||||
p1 = pend+1
|
||||
end
|
||||
pstart,pend = string.find(url,"/",p1,true)
|
||||
if pend then
|
||||
if pend==pb then
|
||||
uri = string.sub(url,pb)
|
||||
else
|
||||
uri = string.sub(url,pend)
|
||||
domain = string.sub(url,p1,pend-1)
|
||||
end
|
||||
else
|
||||
if proto then
|
||||
domain = string.sub(url,p1)
|
||||
else
|
||||
uri = string.sub(url,p1)
|
||||
end
|
||||
end
|
||||
if domain then
|
||||
pstart,pend = string.find(domain,':',1,true)
|
||||
if pend then
|
||||
port = string.sub(domain, pend+1)
|
||||
domain = string.sub(domain, 1, pstart-1)
|
||||
end
|
||||
end
|
||||
return { proto = proto, creds = creds, domain = domain, port = port, uri=uri }
|
||||
end
|
||||
function dissect_nld(domain, level)
|
||||
if domain then
|
||||
local n=1
|
||||
for pos=#domain,1,-1 do
|
||||
if string.sub(domain,pos,pos)=='.' then
|
||||
if n==level then
|
||||
return string.sub(domain, pos+1)
|
||||
end
|
||||
n=n+1
|
||||
end
|
||||
end
|
||||
if n==level then
|
||||
return domain
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
-- support sni=%var
|
||||
function tls_mod_shim(desync, blob, modlist, payload)
|
||||
local p1,p2 = string.find(modlist,"sni=%%[^,]+")
|
||||
if p1 then
|
||||
local var = string.sub(modlist,p1+5,p2)
|
||||
local val = desync[var] or _G[var]
|
||||
if not val then
|
||||
error("tls_mod_shim: non-existent var '"..var.."'")
|
||||
end
|
||||
modlist = string.sub(modlist,1,p1+3)..val..string.sub(modlist,p2+1)
|
||||
end
|
||||
return tls_mod(blob,modlist,payload)
|
||||
end
|
||||
|
||||
-- convert comma separated list of tcp flags to tcp.th_flags bit field
|
||||
function parse_tcp_flags(s)
|
||||
@@ -513,10 +839,10 @@ function apply_fooling(desync, dis, fooling_options)
|
||||
if not dis then dis = desync.dis end
|
||||
if dis.tcp then
|
||||
if tonumber(fooling_options.tcp_seq) then
|
||||
dis.tcp.th_seq = dis.tcp.th_seq + fooling_options.tcp_seq
|
||||
dis.tcp.th_seq = u32add(dis.tcp.th_seq, fooling_options.tcp_seq)
|
||||
end
|
||||
if tonumber(fooling_options.tcp_ack) then
|
||||
dis.tcp.th_ack = dis.tcp.th_ack + fooling_options.tcp_ack
|
||||
dis.tcp.th_ack = u32add(dis.tcp.th_ack, fooling_options.tcp_ack)
|
||||
end
|
||||
if fooling_options.tcp_flags_unset then
|
||||
dis.tcp.th_flags = bitand(dis.tcp.th_flags, bitnot(parse_tcp_flags(fooling_options.tcp_flags_unset)))
|
||||
@@ -527,7 +853,7 @@ function apply_fooling(desync, dis, fooling_options)
|
||||
if tonumber(fooling_options.tcp_ts) then
|
||||
local idx = find_tcp_option(dis.tcp.options,TCP_KIND_TS)
|
||||
if idx and (dis.tcp.options[idx].data and #dis.tcp.options[idx].data or 0)==8 then
|
||||
dis.tcp.options[idx].data = bu32(u32(dis.tcp.options[idx].data)+fooling_options.tcp_ts)..string.sub(dis.tcp.options[idx].data,5)
|
||||
dis.tcp.options[idx].data = bu32(u32add(u32(dis.tcp.options[idx].data),fooling_options.tcp_ts))..string.sub(dis.tcp.options[idx].data,5)
|
||||
else
|
||||
DLOG("apply_fooling: timestamp tcp option not present or invalid")
|
||||
end
|
||||
@@ -744,7 +1070,6 @@ end
|
||||
-- send dissect with tcp segmentation based on mss value. appply specified rawsend options.
|
||||
function rawsend_dissect_segmented(desync, dis, mss, options)
|
||||
local discopy = deepcopy(dis)
|
||||
apply_ip_id(desync, discopy, options and options.ipid)
|
||||
apply_fooling(desync, discopy, options and options.fooling)
|
||||
|
||||
if dis.tcp then
|
||||
@@ -760,6 +1085,7 @@ function rawsend_dissect_segmented(desync, dis, mss, options)
|
||||
len = #payload - pos + 1
|
||||
if len > max_data then len = max_data end
|
||||
discopy.payload = string.sub(payload,pos,pos+len-1)
|
||||
apply_ip_id(desync, discopy, options and options.ipid)
|
||||
if not rawsend_dissect_ipfrag(discopy, options) then
|
||||
-- stop if failed
|
||||
return false
|
||||
@@ -770,6 +1096,7 @@ function rawsend_dissect_segmented(desync, dis, mss, options)
|
||||
return true
|
||||
end
|
||||
end
|
||||
apply_ip_id(desync, discopy, options and options.ipid)
|
||||
-- no reason to segment
|
||||
return rawsend_dissect_ipfrag(discopy, options)
|
||||
end
|
||||
@@ -796,23 +1123,27 @@ function direction_cutoff_opposite(ctx, desync, def)
|
||||
local dir = desync.arg.dir or def or "out"
|
||||
if dir=="out" then
|
||||
-- cutoff in
|
||||
instance_cutoff(ctx, false)
|
||||
instance_cutoff_shim(ctx, desync, false)
|
||||
elseif dir=="in" then
|
||||
-- cutoff out
|
||||
instance_cutoff(ctx, true)
|
||||
instance_cutoff_shim(ctx, desync, true)
|
||||
end
|
||||
end
|
||||
|
||||
-- return true if l7payload matches filter l7payload_filter - comma separated list of payload types
|
||||
function payload_match_filter(l7payload, l7payload_filter, def)
|
||||
local argpl = l7payload_filter or def or "known"
|
||||
local neg = string.sub(argpl,1,1)=="~"
|
||||
local pl = neg and string.sub(argpl,2) or argpl
|
||||
return neg ~= (in_list(pl, "all") or in_list(pl, l7payload) or in_list(pl, "known") and l7payload~="unknown" and l7payload~="empty")
|
||||
end
|
||||
-- check if desync payload type comply with payload type list in arg.payload
|
||||
-- if arg.payload is not present - check for known payload - not empty and not unknown (nfqws1 behavior without "--desync-any-protocol" option)
|
||||
-- if arg.payload is prefixed with '~' - it means negation
|
||||
function payload_check(desync, def)
|
||||
local b
|
||||
local argpl = desync.arg.payload or def or "known"
|
||||
local neg = string.sub(argpl,1,1)=="~"
|
||||
local pl = neg and string.sub(argpl,2) or argpl
|
||||
|
||||
b = neg ~= (in_list(pl, "all") or in_list(pl, desync.l7payload) or in_list(pl, "known") and desync.l7payload~="unknown" and desync.l7payload~="empty")
|
||||
if not b then
|
||||
local b = payload_match_filter(desync.l7payload, desync.arg.payload, def)
|
||||
if not b and b_debug then
|
||||
local argpl = desync.arg.payload or def or "known"
|
||||
DLOG("payload_check: payload '"..desync.l7payload.."' does not pass '"..argpl.."' filter")
|
||||
end
|
||||
return b
|
||||
@@ -883,6 +1214,14 @@ function genhost(len, template)
|
||||
end
|
||||
end
|
||||
|
||||
-- return hostname if present or ip address in text form otherwise
|
||||
function host_or_ip(desync)
|
||||
if desync.track and desync.track.hostname then
|
||||
return desync.track.hostname
|
||||
end
|
||||
return desync.target.ip and ntop(desync.target.ip) or desync.target.ip6 and ntop(desync.target.ip6)
|
||||
end
|
||||
|
||||
function is_absolute_path(path)
|
||||
if string.sub(path,1,1)=='/' then return true end
|
||||
local un = uname()
|
||||
@@ -1031,4 +1370,3 @@ function ipfrag2(dis, ipfrag_options)
|
||||
|
||||
return {dis1,dis2}
|
||||
end
|
||||
|
||||
|
||||
@@ -264,8 +264,8 @@ end
|
||||
function test_bit()
|
||||
local v, v2, v3, v4, b1, b2, pow
|
||||
|
||||
v = math.random(0,0xFFFFFFFFFFFF)
|
||||
b1 = math.random(1,15)
|
||||
v = math.random(0,0xFFFFFFFF)
|
||||
b1 = math.random(1,16)
|
||||
|
||||
v2 = bitrshift(v, b1)
|
||||
pow = 2^b1
|
||||
@@ -275,17 +275,17 @@ function test_bit()
|
||||
|
||||
v2 = bitlshift(v, b1)
|
||||
pow = 2^b1
|
||||
v3 = v * pow
|
||||
print(string.format("lshift(0x%X,%u) = 0x%X 0x%X*%u = 0x%X", v,b1,v2, v,pow,v3))
|
||||
v3 = (v * pow) % 0x100000000
|
||||
print(string.format("lshift(0x%X,%u) = 0x%X 0x%X*%u %% 0x10000000 = 0x%X", v,b1,v2, v,pow,v3))
|
||||
test_assert(v2==v3)
|
||||
|
||||
v2 = math.random(0,0xFFFFFFFFFFFF)
|
||||
v2 = math.random(0,0xFFFFFFFF)
|
||||
v3 = bitxor(v, v2)
|
||||
v4 = bitor(v, v2) - bitand(v, v2)
|
||||
print(string.format("xor(0x%X,0x%X) = %X or/and/minus = %X", v, v2, v3, v4))
|
||||
test_assert(v3==v4)
|
||||
|
||||
b2 = b1 + math.random(1,31)
|
||||
b2 = b1 + math.random(1,15)
|
||||
v2 = bitget(v, b1, b2)
|
||||
pow = 2^(b2-b1+1) - 1
|
||||
v3 = bitand(bitrshift(v,b1), pow)
|
||||
@@ -299,8 +299,32 @@ function test_bit()
|
||||
test_assert(v2==v3)
|
||||
end
|
||||
|
||||
function test_ux()
|
||||
local v1, v2, v3, usum, sum
|
||||
for k,test in pairs({
|
||||
{ add=u8add, fname="u8add", max = 0xFF },
|
||||
{ add=u16add, fname="u16add", max = 0xFFFF },
|
||||
{ add=u24add, fname="u24add", max = 0xFFFFFF },
|
||||
{ add=u32add, fname="u32add", max = 0xFFFFFFFF }
|
||||
}) do
|
||||
io.write(test.fname.." : ")
|
||||
for i=1,1000 do
|
||||
v1=math.random(-test.max,test.max)
|
||||
v2=math.random(-test.max,test.max)
|
||||
v3=math.random(-test.max,test.max)
|
||||
usum = test.add(v1,v2,v3)
|
||||
sum = bitand((v1+v2+v3)%(test.max+1),test.max)
|
||||
if sum~=usum then
|
||||
print("FAIL")
|
||||
end
|
||||
test_assert(sum==usum)
|
||||
end
|
||||
print("OK")
|
||||
end
|
||||
end
|
||||
|
||||
function test_bin(...)
|
||||
test_run({test_ub, test_bit},...)
|
||||
test_run({test_ub, test_bit, test_ux},...)
|
||||
end
|
||||
|
||||
|
||||
|
||||
151
nfq2/conntrack.c
151
nfq2/conntrack.c
@@ -102,8 +102,8 @@ static void ConntrackInitTrack(t_ctrack *t)
|
||||
{
|
||||
memset(t, 0, sizeof(*t));
|
||||
t->l7proto = L7_UNKNOWN;
|
||||
t->scale_orig = t->scale_reply = SCALE_NONE;
|
||||
time(&t->t_start);
|
||||
t->pos.scale_orig = t->pos.scale_reply = SCALE_NONE;
|
||||
time(&t->pos.t_start);
|
||||
rawpacket_queue_init(&t->delayed);
|
||||
lua_newtable(params.L);
|
||||
t->lua_state = luaL_ref(params.L, LUA_REGISTRYINDEX);
|
||||
@@ -136,86 +136,102 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
|
||||
|
||||
if (bReverse)
|
||||
{
|
||||
t->pcounter_reply++;
|
||||
t->pdcounter_reply += !!len_payload;
|
||||
t->pbcounter_reply += len_payload;
|
||||
t->pos.pcounter_reply++;
|
||||
t->pos.pdcounter_reply += !!len_payload;
|
||||
t->pos.pbcounter_reply += len_payload;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
t->pcounter_orig++;
|
||||
t->pdcounter_orig += !!len_payload;
|
||||
t->pbcounter_orig += len_payload;
|
||||
t->pos.pcounter_orig++;
|
||||
t->pos.pdcounter_orig += !!len_payload;
|
||||
t->pos.pbcounter_orig += len_payload;
|
||||
}
|
||||
|
||||
if (tcphdr)
|
||||
{
|
||||
if (tcp_syn_segment(tcphdr))
|
||||
{
|
||||
if (t->state != SYN) ConntrackReInitTrack(t); // erase current entry
|
||||
t->seq0 = ntohl(tcphdr->th_seq);
|
||||
if (t->pos.state != SYN) ConntrackReInitTrack(t); // erase current entry
|
||||
t->pos.seq0 = ntohl(tcphdr->th_seq);
|
||||
}
|
||||
else if (tcp_synack_segment(tcphdr))
|
||||
{
|
||||
// ignore SA dups
|
||||
uint32_t seq0 = ntohl(tcphdr->th_ack) - 1;
|
||||
if (t->state != SYN && t->seq0 != seq0)
|
||||
if (t->pos.state != SYN && t->pos.seq0 != seq0)
|
||||
ConntrackReInitTrack(t); // erase current entry
|
||||
if (!t->seq0) t->seq0 = seq0;
|
||||
t->ack0 = ntohl(tcphdr->th_seq);
|
||||
if (!t->pos.seq0) t->pos.seq0 = seq0;
|
||||
t->pos.ack0 = ntohl(tcphdr->th_seq);
|
||||
}
|
||||
else if (tcphdr->th_flags & (TH_FIN | TH_RST))
|
||||
{
|
||||
t->state = FIN;
|
||||
t->pos.state = FIN;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (t->state == SYN)
|
||||
if (t->pos.state == SYN)
|
||||
{
|
||||
t->state = ESTABLISHED;
|
||||
if (!bReverse && !t->ack0) t->ack0 = ntohl(tcphdr->th_ack) - 1;
|
||||
t->pos.state = ESTABLISHED;
|
||||
if (!bReverse && !t->pos.ack0) t->pos.ack0 = ntohl(tcphdr->th_ack) - 1;
|
||||
}
|
||||
}
|
||||
scale = tcp_find_scale_factor(tcphdr);
|
||||
mss = ntohs(tcp_find_mss(tcphdr));
|
||||
if (bReverse)
|
||||
{
|
||||
t->pos_orig = t->seq_last = ntohl(tcphdr->th_ack);
|
||||
t->ack_last = ntohl(tcphdr->th_seq);
|
||||
t->pos_reply = t->ack_last + len_payload;
|
||||
t->winsize_reply = ntohs(tcphdr->th_win);
|
||||
t->winsize_reply_calc = t->winsize_reply;
|
||||
if (t->scale_reply != SCALE_NONE) t->winsize_reply_calc <<= t->scale_reply;
|
||||
if (mss && !t->mss_reply) t->mss_reply = mss;
|
||||
if (scale != SCALE_NONE) t->scale_reply = scale;
|
||||
t->pos.ack_last = ntohl(tcphdr->th_seq);
|
||||
t->pos.pos_orig = t->pos.seq_last = ntohl(tcphdr->th_ack);
|
||||
t->pos.pos_reply = t->pos.ack_last + len_payload;
|
||||
if (t->pos.state == SYN)
|
||||
t->pos.uppos_reply_prev = t->pos.uppos_reply = t->pos.pos_reply;
|
||||
else if (len_payload)
|
||||
{
|
||||
t->pos.uppos_reply_prev = t->pos.uppos_reply;
|
||||
if (!((t->pos.pos_reply - t->pos.uppos_reply) & 0x80000000))
|
||||
t->pos.uppos_reply = t->pos.pos_reply;
|
||||
}
|
||||
t->pos.winsize_reply = ntohs(tcphdr->th_win);
|
||||
t->pos.winsize_reply_calc = t->pos.winsize_reply;
|
||||
if (t->pos.scale_reply != SCALE_NONE) t->pos.winsize_reply_calc <<= t->pos.scale_reply;
|
||||
if (mss && !t->pos.mss_reply) t->pos.mss_reply = mss;
|
||||
if (scale != SCALE_NONE) t->pos.scale_reply = scale;
|
||||
}
|
||||
else
|
||||
{
|
||||
t->seq_last = ntohl(tcphdr->th_seq);
|
||||
t->pos_orig = t->seq_last + len_payload;
|
||||
t->pos_reply = t->ack_last = ntohl(tcphdr->th_ack);
|
||||
t->winsize_orig = ntohs(tcphdr->th_win);
|
||||
t->winsize_orig_calc = t->winsize_orig;
|
||||
if (t->scale_orig != SCALE_NONE) t->winsize_orig_calc <<= t->scale_orig;
|
||||
if (mss && !t->mss_reply) t->mss_orig = mss;
|
||||
if (scale != SCALE_NONE) t->scale_orig = scale;
|
||||
t->pos.seq_last = ntohl(tcphdr->th_seq);
|
||||
t->pos.pos_orig = t->pos.seq_last + len_payload;
|
||||
t->pos.pos_reply = t->pos.ack_last = ntohl(tcphdr->th_ack);
|
||||
if (t->pos.state == SYN)
|
||||
t->pos.uppos_orig_prev = t->pos.uppos_orig = t->pos.pos_orig;
|
||||
else if (len_payload)
|
||||
{
|
||||
t->pos.uppos_orig_prev = t->pos.uppos_orig;
|
||||
if (!((t->pos.pos_orig - t->pos.uppos_orig) & 0x80000000))
|
||||
t->pos.uppos_orig = t->pos.pos_orig;
|
||||
}
|
||||
t->pos.winsize_orig = ntohs(tcphdr->th_win);
|
||||
t->pos.winsize_orig_calc = t->pos.winsize_orig;
|
||||
if (t->pos.scale_orig != SCALE_NONE) t->pos.winsize_orig_calc <<= t->pos.scale_orig;
|
||||
if (mss && !t->pos.mss_reply) t->pos.mss_orig = mss;
|
||||
if (scale != SCALE_NONE) t->pos.scale_orig = scale;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (bReverse)
|
||||
{
|
||||
t->ack_last = t->pos_reply;
|
||||
t->pos_reply += len_payload;
|
||||
t->pos.ack_last = t->pos.pos_reply;
|
||||
t->pos.pos_reply += len_payload;
|
||||
}
|
||||
else
|
||||
{
|
||||
t->seq_last = t->pos_orig;
|
||||
t->pos_orig += len_payload;
|
||||
t->pos.seq_last = t->pos.pos_orig;
|
||||
t->pos.pos_orig += len_payload;
|
||||
}
|
||||
}
|
||||
|
||||
time(&t->t_last);
|
||||
time(&t->pos.t_last);
|
||||
}
|
||||
|
||||
static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct ip *ip, const struct ip6_hdr *ip6, const struct tcphdr *tcphdr, const struct udphdr *udphdr, t_ctrack **ctrack, bool *bReverse)
|
||||
@@ -317,12 +333,12 @@ void ConntrackPoolPurge(t_conntrack *p)
|
||||
if ((tnow - p->t_last_purge) >= p->t_purge_interval)
|
||||
{
|
||||
HASH_ITER(hh, p->pool, t, tmp) {
|
||||
tidle = tnow - t->track.t_last;
|
||||
tidle = tnow - t->track.pos.t_last;
|
||||
if (t->track.b_cutoff ||
|
||||
(t->conn.l4proto == IPPROTO_TCP && (
|
||||
(t->track.state == SYN && tidle >= p->timeout_syn) ||
|
||||
(t->track.state == ESTABLISHED && tidle >= p->timeout_established) ||
|
||||
(t->track.state == FIN && tidle >= p->timeout_fin))
|
||||
(t->track.pos.state == SYN && tidle >= p->timeout_syn) ||
|
||||
(t->track.pos.state == ESTABLISHED && tidle >= p->timeout_established) ||
|
||||
(t->track.pos.state == FIN && tidle >= p->timeout_fin))
|
||||
) || (t->conn.l4proto == IPPROTO_UDP && tidle >= p->timeout_udp)
|
||||
)
|
||||
{
|
||||
@@ -349,21 +365,21 @@ void ConntrackPoolDump(const t_conntrack *p)
|
||||
printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu orig=d%llu/n%llu/b%llu reply=d%llu/n%llu/b%lld ",
|
||||
proto_name(t->conn.l4proto),
|
||||
sa1, t->conn.sport, sa2, t->conn.dport,
|
||||
t->conn.l4proto == IPPROTO_TCP ? connstate_s[t->track.state] : "-",
|
||||
(unsigned long long)t->track.t_start, (unsigned long long)(t->track.t_last - t->track.t_start), (unsigned long long)(tnow - t->track.t_last),
|
||||
(unsigned long long)t->track.pdcounter_orig, (unsigned long long)t->track.pcounter_orig, (unsigned long long)t->track.pbcounter_orig,
|
||||
(unsigned long long)t->track.pdcounter_reply, (unsigned long long)t->track.pcounter_reply, (unsigned long long)t->track.pbcounter_reply);
|
||||
t->conn.l4proto == IPPROTO_TCP ? connstate_s[t->track.pos.state] : "-",
|
||||
(unsigned long long)t->track.pos.t_start, (unsigned long long)(t->track.pos.t_last - t->track.pos.t_start), (unsigned long long)(tnow - t->track.pos.t_last),
|
||||
(unsigned long long)t->track.pos.pdcounter_orig, (unsigned long long)t->track.pos.pcounter_orig, (unsigned long long)t->track.pos.pbcounter_orig,
|
||||
(unsigned long long)t->track.pos.pdcounter_reply, (unsigned long long)t->track.pos.pcounter_reply, (unsigned long long)t->track.pos.pbcounter_reply);
|
||||
if (t->conn.l4proto == IPPROTO_TCP)
|
||||
printf("seq0=%u rseq=%u pos_orig=%u ack0=%u rack=%u pos_reply=%u mss_orig=%u mss_reply=%u wsize_orig=%u:%d wsize_reply=%u:%d",
|
||||
t->track.seq0, t->track.seq_last - t->track.seq0, t->track.pos_orig - t->track.seq0,
|
||||
t->track.ack0, t->track.ack_last - t->track.ack0, t->track.pos_reply - t->track.ack0,
|
||||
t->track.mss_orig, t->track.mss_reply,
|
||||
t->track.winsize_orig, t->track.scale_orig == SCALE_NONE ? -1 : t->track.scale_orig,
|
||||
t->track.winsize_reply, t->track.scale_reply == SCALE_NONE ? -1 : t->track.scale_reply);
|
||||
t->track.pos.seq0, t->track.pos.seq_last - t->track.pos.seq0, t->track.pos.pos_orig - t->track.pos.seq0,
|
||||
t->track.pos.ack0, t->track.pos.ack_last - t->track.pos.ack0, t->track.pos.pos_reply - t->track.pos.ack0,
|
||||
t->track.pos.mss_orig, t->track.pos.mss_reply,
|
||||
t->track.pos.winsize_orig, t->track.pos.scale_orig == SCALE_NONE ? -1 : t->track.pos.scale_orig,
|
||||
t->track.pos.winsize_reply, t->track.pos.scale_reply == SCALE_NONE ? -1 : t->track.pos.scale_reply);
|
||||
else
|
||||
printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u",
|
||||
t->track.seq_last, t->track.pos_orig,
|
||||
t->track.ack_last, t->track.pos_reply);
|
||||
t->track.pos.seq_last, t->track.pos.pos_orig,
|
||||
t->track.pos.ack_last, t->track.pos.pos_reply);
|
||||
printf(" req_retrans=%u cutoff=%u lua_in_cutoff=%u lua_out_cutoff=%u hostname=%s l7proto=%s\n",
|
||||
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_lua_in_cutoff, t->track.b_lua_out_cutoff, t->track.hostname, l7proto_str(t->track.l7proto));
|
||||
};
|
||||
@@ -394,17 +410,30 @@ bool ReasmResize(t_reassemble *reasm, size_t new_size)
|
||||
if (reasm->size_present > new_size) reasm->size_present = new_size;
|
||||
return true;
|
||||
}
|
||||
#define REASM_MAX_NEG 0x100000
|
||||
bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t len)
|
||||
{
|
||||
if (reasm->seq != seq) return false; // fail session if out of sequence
|
||||
|
||||
size_t szcopy;
|
||||
szcopy = reasm->size - reasm->size_present;
|
||||
if (len < szcopy) szcopy = len;
|
||||
memcpy(reasm->packet + reasm->size_present, payload, szcopy);
|
||||
reasm->size_present += szcopy;
|
||||
reasm->seq += (uint32_t)szcopy;
|
||||
uint32_t dseq = seq - reasm->seq;
|
||||
if (dseq && (dseq < REASM_MAX_NEG))
|
||||
return false; // fail session if a gap about to appear
|
||||
uint32_t neg_overlap = reasm->seq - seq;
|
||||
if (neg_overlap > REASM_MAX_NEG)
|
||||
return false; // too big minus
|
||||
|
||||
size_t szcopy, szignore;
|
||||
szignore = (neg_overlap > reasm->size_present) ? neg_overlap - reasm->size_present : 0;
|
||||
if (szignore>=len) return true; // everyting is before the starting pos
|
||||
szcopy = len - szignore;
|
||||
neg_overlap -= szignore;
|
||||
if ((reasm->size_present - neg_overlap + szcopy) > reasm->size)
|
||||
return false; // buffer overflow
|
||||
// in case of seq overlap new data replaces old - unix behavior
|
||||
memcpy(reasm->packet + reasm->size_present - neg_overlap, payload + szignore, szcopy);
|
||||
if (szcopy>neg_overlap)
|
||||
{
|
||||
reasm->size_present += szcopy - neg_overlap;
|
||||
reasm->seq += (uint32_t)szcopy - neg_overlap;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool ReasmHasSpace(t_reassemble *reasm, size_t len)
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/types.h>
|
||||
#include <time.h>
|
||||
#include <netinet/in.h>
|
||||
|
||||
#define __FAVOR_BSD
|
||||
@@ -17,6 +16,7 @@
|
||||
#include <netinet/tcp.h>
|
||||
#include <netinet/udp.h>
|
||||
|
||||
#include "conntrack_base.h"
|
||||
#include "packet_queue.h"
|
||||
#include "protocol.h"
|
||||
|
||||
@@ -43,43 +43,25 @@ typedef struct
|
||||
// this structure helps to reassemble continuous packets streams. it does not support out-of-orders
|
||||
typedef struct {
|
||||
uint8_t *packet; // allocated for size during reassemble request. requestor must know the message size.
|
||||
uint32_t seq; // current seq number. if a packet comes with an unexpected seq - it fails reassemble session.
|
||||
uint32_t seq; // current seq number. if a packet comes with unsupported seq overlap - it fails reassemble session.
|
||||
size_t size; // expected message size. success means that we have received exactly 'size' bytes and have them in 'packet'
|
||||
size_t size_present; // how many bytes already stored in 'packet'
|
||||
} t_reassemble;
|
||||
|
||||
// SYN - SYN or SYN/ACK received
|
||||
// ESTABLISHED - any except SYN or SYN/ACK received
|
||||
// FIN - FIN or RST received
|
||||
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache
|
||||
uint8_t ipproto;
|
||||
|
||||
// this block of data can change between delayed (queued) packets. need to remeber this data for each packet for further replay
|
||||
t_ctrack_position pos;
|
||||
|
||||
struct desync_profile *dp; // desync profile cache
|
||||
bool dp_search_complete;
|
||||
|
||||
// common state
|
||||
time_t t_start, t_last;
|
||||
uint64_t pcounter_orig, pcounter_reply; // packet counter
|
||||
uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload)
|
||||
uint64_t pbcounter_orig, pbcounter_reply; // transferred byte counter. includes retransmissions. it's not the same as relative seq.
|
||||
uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
|
||||
uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
|
||||
|
||||
// tcp only state, not used in udp
|
||||
t_connstate state;
|
||||
uint32_t seq0, ack0; // starting seq and ack
|
||||
uint16_t winsize_orig, winsize_reply; // last seen window size
|
||||
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
|
||||
uint32_t winsize_orig_calc, winsize_reply_calc; // calculated window size
|
||||
uint16_t mss_orig, mss_reply;
|
||||
|
||||
uint8_t req_retrans_counter; // number of request retransmissions
|
||||
bool req_seq_present,req_seq_finalized,req_seq_abandoned;
|
||||
uint32_t req_seq_start,req_seq_end; // sequence interval of the request (to track retransmissions)
|
||||
bool retrans_detect_finalized;
|
||||
|
||||
uint8_t incoming_ttl;
|
||||
|
||||
|
||||
34
nfq2/conntrack_base.h
Normal file
34
nfq2/conntrack_base.h
Normal file
@@ -0,0 +1,34 @@
|
||||
#pragma once
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#define CTRACK_T_SYN 60
|
||||
#define CTRACK_T_FIN 60
|
||||
#define CTRACK_T_EST 300
|
||||
#define CTRACK_T_UDP 60
|
||||
|
||||
// SYN - SYN or SYN/ACK received
|
||||
// ESTABLISHED - any except SYN or SYN/ACK received
|
||||
// FIN - FIN or RST received
|
||||
typedef enum {SYN=0, ESTABLISHED, FIN} t_connstate;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
time_t t_last, t_start;
|
||||
|
||||
uint64_t pcounter_orig, pcounter_reply; // packet counter
|
||||
uint64_t pdcounter_orig, pdcounter_reply; // data packet counter (with payload)
|
||||
uint64_t pbcounter_orig, pbcounter_reply; // transferred byte counter. includes retransmissions. it's not the same as relative seq.
|
||||
uint32_t pos_orig, pos_reply; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
|
||||
uint32_t uppos_orig, uppos_reply; // max seen position. useful to detect retransmissions
|
||||
uint32_t uppos_orig_prev, uppos_reply_prev; // previous max seen position. useful to detect retransmissions
|
||||
uint32_t seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
|
||||
|
||||
// tcp only state, not used in udp
|
||||
t_connstate state;
|
||||
uint32_t seq0, ack0; // starting seq and ack
|
||||
uint16_t winsize_orig, winsize_reply; // last seen window size
|
||||
uint8_t scale_orig, scale_reply; // last seen window scale factor. SCALE_NONE if none
|
||||
uint32_t winsize_orig_calc, winsize_reply_calc; // calculated window size
|
||||
uint16_t mss_orig, mss_reply;
|
||||
} t_ctrack_position;
|
||||
286
nfq2/desync.c
286
nfq2/desync.c
@@ -209,7 +209,7 @@ static struct desync_profile *dp_find(
|
||||
{
|
||||
if (dp_match(&dpl->dp, l3proto, ip, ip6, port, hostname, bNoSubdom, l7proto, ssid, bCheckDone, bCheckResult, bExcluded))
|
||||
{
|
||||
DLOG("desync profile %u matches\n", dpl->dp.n);
|
||||
DLOG("desync profile %u (%s) matches\n", dpl->dp.n, PROFILE_NAME(&dpl->dp));
|
||||
return &dpl->dp;
|
||||
}
|
||||
}
|
||||
@@ -234,12 +234,17 @@ static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const ch
|
||||
if (fail_counter)
|
||||
{
|
||||
HostFailPoolDel(&dp->hostlist_auto_fail_counters, fail_counter);
|
||||
DLOG("auto hostlist (profile %u) : %s : fail counter reset. website is working.\n", dp->n, hostname);
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : fail counter reset. website is working.", hostname, dp->n, client_ip_port, l7proto_str(l7proto));
|
||||
DLOG("auto hostlist (profile %u (%s)) : %s : fail counter reset. website is working.\n", dp->n, PROFILE_NAME(dp), hostname);
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : fail counter reset. website is working.", hostname, dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool is_retransmission(const t_ctrack *ctrack)
|
||||
{
|
||||
return !((ctrack->pos.uppos_orig_prev - ctrack->pos.pos_orig) & 0x80000000);
|
||||
}
|
||||
|
||||
// return true if retrans trigger fires
|
||||
static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int threshold, const char *client_ip_port, t_l7proto l7proto)
|
||||
{
|
||||
@@ -247,24 +252,28 @@ static bool auto_hostlist_retrans(t_ctrack *ctrack, uint8_t l4proto, int thresho
|
||||
{
|
||||
if (l4proto == IPPROTO_TCP)
|
||||
{
|
||||
if (!ctrack->req_seq_finalized || ctrack->req_seq_abandoned)
|
||||
if (ctrack->retrans_detect_finalized)
|
||||
return false;
|
||||
if (!seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end))
|
||||
if (!seq_within(ctrack->pos.seq_last, ctrack->pos.seq0, ctrack->pos.seq0 + ctrack->dp->hostlist_auto_retrans_maxseq))
|
||||
{
|
||||
DLOG("req retrans : tcp seq %u not within the req range %u-%u. stop tracking.\n", ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end);
|
||||
ctrack->retrans_detect_finalized = true;
|
||||
DLOG("retrans : tcp seq %u not within the req range %u-%u. stop tracking.\n", ctrack->pos.seq_last, ctrack->pos.seq0, ctrack->pos.seq0 + ctrack->dp->hostlist_auto_retrans_maxseq);
|
||||
ctrack_stop_retrans_counter(ctrack);
|
||||
auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname, client_ip_port, l7proto);
|
||||
return false;
|
||||
}
|
||||
if (!is_retransmission(ctrack))
|
||||
return false;
|
||||
}
|
||||
ctrack->req_retrans_counter++;
|
||||
if (ctrack->req_retrans_counter >= threshold)
|
||||
{
|
||||
DLOG("req retrans threshold reached : %u/%u\n", ctrack->req_retrans_counter, threshold);
|
||||
DLOG("retrans threshold reached : %u/%u\n", ctrack->req_retrans_counter, threshold);
|
||||
ctrack_stop_retrans_counter(ctrack);
|
||||
ctrack->retrans_detect_finalized = true;
|
||||
return true;
|
||||
}
|
||||
DLOG("req retrans counter : %u/%u\n", ctrack->req_retrans_counter, threshold);
|
||||
DLOG("retrans counter : %u/%u\n", ctrack->req_retrans_counter, threshold);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -283,19 +292,19 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
|
||||
}
|
||||
}
|
||||
fail_counter->counter++;
|
||||
DLOG("auto hostlist (profile %u) : %s : fail counter %d/%d\n", dp->n, hostname, fail_counter->counter, dp->hostlist_auto_fail_threshold);
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : fail counter %d/%d", hostname, dp->n, client_ip_port, l7proto_str(l7proto), fail_counter->counter, dp->hostlist_auto_fail_threshold);
|
||||
DLOG("auto hostlist (profile %u (%s)) : %s : fail counter %d/%d\n", dp->n, PROFILE_NAME(dp), hostname, fail_counter->counter, dp->hostlist_auto_fail_threshold);
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : fail counter %d/%d", hostname, dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto), fail_counter->counter, dp->hostlist_auto_fail_threshold);
|
||||
if (fail_counter->counter >= dp->hostlist_auto_fail_threshold)
|
||||
{
|
||||
DLOG("auto hostlist (profile %u) : fail threshold reached. about to add %s to auto hostlist\n", dp->n, hostname);
|
||||
DLOG("auto hostlist (profile %u (%s)) : fail threshold reached. about to add %s to auto hostlist\n", dp->n, PROFILE_NAME(dp), hostname);
|
||||
HostFailPoolDel(&dp->hostlist_auto_fail_counters, fail_counter);
|
||||
|
||||
DLOG("auto hostlist (profile %u) : rechecking %s to avoid duplicates\n", dp->n, hostname);
|
||||
DLOG("auto hostlist (profile %u (%s)) : rechecking %s to avoid duplicates\n", dp->n, PROFILE_NAME(dp), hostname);
|
||||
bool bExcluded = false;
|
||||
if (!HostlistCheck(dp, hostname, bNoSubdom, &bExcluded, false) && !bExcluded)
|
||||
{
|
||||
DLOG("auto hostlist (profile %u) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename);
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : adding to %s", hostname, dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
|
||||
if (!HostlistPoolAddStr(&dp->hostlist_auto->hostlist, hostname, 0))
|
||||
{
|
||||
DLOG_ERR("StrPoolAddStr out of memory\n");
|
||||
@@ -312,7 +321,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
|
||||
else
|
||||
{
|
||||
DLOG("auto hostlist (profile %u) : NOT adding %s\n", dp->n, hostname);
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : NOT adding, duplicate detected", hostname, dp->n, client_ip_port, l7proto_str(l7proto));
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : NOT adding, duplicate detected", hostname, dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -328,7 +337,7 @@ static void process_retrans_fail(t_ctrack *ctrack, uint8_t proto, const struct s
|
||||
*client_ip_port = 0;
|
||||
if (ctrack && ctrack->dp && ctrack->hostname && auto_hostlist_retrans(ctrack, proto, ctrack->dp->hostlist_auto_retrans_threshold, client_ip_port, ctrack->l7proto))
|
||||
{
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : retrans threshold reached", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : retrans threshold reached", ctrack->hostname, ctrack->dp->n, PROFILE_NAME(ctrack->dp), client_ip_port, l7proto_str(ctrack->l7proto));
|
||||
auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
|
||||
}
|
||||
}
|
||||
@@ -344,14 +353,14 @@ static bool send_delayed(t_ctrack *ctrack)
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool rawpacket_queue_csum_fix(struct rawpacket_tailhead *q, const struct dissect *dis, const struct sockaddr_storage* dst, uint32_t fwmark, uint32_t desync_fwmark, const char *ifin, const char *ifout)
|
||||
static bool rawpacket_queue_csum_fix(struct rawpacket_tailhead *q, const struct dissect *dis, const t_ctrack_position *pos, const struct sockaddr_storage* dst, uint32_t fwmark, uint32_t desync_fwmark, const char *ifin, const char *ifout)
|
||||
{
|
||||
// this breaks const pointer to l4 header
|
||||
if (dis->tcp)
|
||||
verdict_tcp_csum_fix(VERDICT_PASS, (struct tcphdr *)dis->tcp, dis->transport_len, dis->ip, dis->ip6);
|
||||
else if (dis->udp)
|
||||
verdict_udp_csum_fix(VERDICT_PASS, (struct udphdr *)dis->udp, dis->transport_len, dis->ip, dis->ip6);
|
||||
return rawpacket_queue(q, dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload);
|
||||
return rawpacket_queue(q, dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, pos);
|
||||
}
|
||||
|
||||
|
||||
@@ -360,7 +369,7 @@ static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, si
|
||||
ReasmClear(reasm);
|
||||
if (sz <= szMax)
|
||||
{
|
||||
uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->seq_last : 0;
|
||||
uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->pos.seq_last : 0;
|
||||
if (ReasmInit(reasm, sz, seq))
|
||||
{
|
||||
ReasmFeed(reasm, seq, data_payload, len_payload);
|
||||
@@ -382,7 +391,7 @@ static bool reasm_feed(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, con
|
||||
{
|
||||
if (ctrack && !ReasmIsEmpty(reasm))
|
||||
{
|
||||
uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->seq_last : (uint32_t)reasm->size_present;
|
||||
uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->pos.seq_last : (uint32_t)reasm->size_present;
|
||||
if (ReasmFeed(reasm, seq, data_payload, len_payload))
|
||||
{
|
||||
DLOG("reassemble : feeding data payload size=%zu. now we have %zu/%zu\n", len_payload, reasm->size_present, reasm->size);
|
||||
@@ -429,7 +438,7 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, const struct dissect *
|
||||
// if used in postnat chain, dropping initial packet will cause conntrack connection teardown
|
||||
// so we need to workaround this.
|
||||
// SYN and SYN,ACK checks are for conntrack-less mode
|
||||
if (ctrack && (params.server ? ctrack->pcounter_reply : ctrack->pcounter_orig) == 1 || dis->tcp && (tcp_syn_segment(dis->tcp) || tcp_synack_segment(dis->tcp)))
|
||||
if (ctrack && (params.server ? ctrack->pos.pcounter_reply : ctrack->pos.pcounter_orig) == 1 || dis->tcp && (tcp_syn_segment(dis->tcp) || tcp_synack_segment(dis->tcp)))
|
||||
{
|
||||
if (dis->len_pkt > *len_mod_pkt)
|
||||
DLOG_ERR("linux postnat conntrack workaround cannot be applied\n");
|
||||
@@ -458,60 +467,60 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, const struct dissect *
|
||||
}
|
||||
|
||||
|
||||
static uint64_t pos_get(const t_ctrack *ctrack, char mode, bool bReply)
|
||||
static uint64_t pos_get(const t_ctrack_position *pos, char mode, bool bReply)
|
||||
{
|
||||
if (ctrack)
|
||||
if (pos)
|
||||
{
|
||||
switch (mode)
|
||||
{
|
||||
case 'n': return bReply ? ctrack->pcounter_reply : ctrack->pcounter_orig;
|
||||
case 'd': return bReply ? ctrack->pdcounter_reply : ctrack->pdcounter_orig;
|
||||
case 's': return bReply ? (ctrack->ack_last - ctrack->ack0) : (ctrack->seq_last - ctrack->seq0);
|
||||
case 'b': return bReply ? ctrack->pbcounter_reply : ctrack->pbcounter_orig;
|
||||
case 'n': return bReply ? pos->pcounter_reply : pos->pcounter_orig;
|
||||
case 'd': return bReply ? pos->pdcounter_reply : pos->pdcounter_orig;
|
||||
case 's': return bReply ? (pos->ack_last - pos->ack0) : (pos->seq_last - pos->seq0);
|
||||
case 'b': return bReply ? pos->pbcounter_reply : pos->pbcounter_orig;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static bool check_pos_from(const t_ctrack *ctrack, bool bReply, const struct packet_range *range)
|
||||
static bool check_pos_from(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
|
||||
{
|
||||
uint64_t pos;
|
||||
uint64_t ps;
|
||||
if (range->from.mode == 'x') return false;
|
||||
if (range->from.mode != 'a')
|
||||
{
|
||||
if (ctrack)
|
||||
if (pos)
|
||||
{
|
||||
pos = pos_get(ctrack, range->from.mode, bReply);
|
||||
return pos >= range->from.pos;
|
||||
ps = pos_get(pos, range->from.mode, bReply);
|
||||
return ps >= range->from.pos;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static bool check_pos_to(const t_ctrack *ctrack, bool bReply, const struct packet_range *range)
|
||||
static bool check_pos_to(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
|
||||
{
|
||||
uint64_t pos;
|
||||
uint64_t ps;
|
||||
if (range->to.mode == 'x') return false;
|
||||
if (range->to.mode != 'a')
|
||||
{
|
||||
if (ctrack)
|
||||
if (pos)
|
||||
{
|
||||
pos = pos_get(ctrack, range->to.mode, bReply);
|
||||
return (pos < range->to.pos) || !range->upper_cutoff && (pos == range->to.pos);
|
||||
ps = pos_get(pos, range->to.mode, bReply);
|
||||
return (ps < range->to.pos) || !range->upper_cutoff && (ps == range->to.pos);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
static bool check_pos_cutoff(const t_ctrack *ctrack, bool bReply, const struct packet_range *range)
|
||||
static bool check_pos_cutoff(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
|
||||
{
|
||||
bool bto = check_pos_to(ctrack, bReply, range);
|
||||
return ctrack ? !bto : (!bto || !check_pos_from(ctrack, bReply, range));
|
||||
bool bto = check_pos_to(pos, bReply, range);
|
||||
return pos ? !bto : (!bto || !check_pos_from(pos, bReply, range));
|
||||
}
|
||||
static bool check_pos_range(const t_ctrack *ctrack, bool bReply, const struct packet_range *range)
|
||||
static bool check_pos_range(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
|
||||
{
|
||||
return check_pos_from(ctrack, bReply, range) && check_pos_to(ctrack, bReply, range);
|
||||
return check_pos_from(pos, bReply, range) && check_pos_to(pos, bReply, range);
|
||||
}
|
||||
|
||||
|
||||
@@ -638,10 +647,6 @@ err:
|
||||
lua_pop(params.L, rescount);
|
||||
return false;
|
||||
}
|
||||
static void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size)
|
||||
{
|
||||
snprintf(instance, inst_size, "%s_%u_%u", func, dp_n, func_n);
|
||||
}
|
||||
static uint8_t desync(
|
||||
struct desync_profile *dp,
|
||||
uint32_t fwmark,
|
||||
@@ -649,8 +654,11 @@ static uint8_t desync(
|
||||
const char *ifout,
|
||||
bool bIncoming,
|
||||
t_ctrack *ctrack,
|
||||
const t_ctrack_position *pos,
|
||||
t_l7payload l7payload,
|
||||
t_l7proto l7proto,
|
||||
const struct dissect *dis,
|
||||
const struct in_addr *sdp4, const struct in6_addr *sdp6, uint16_t sdport,
|
||||
uint8_t *mod_pkt, size_t *len_mod_pkt,
|
||||
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, const uint8_t *rdata_payload, size_t rlen_payload,
|
||||
const uint8_t *data_decrypt, size_t len_decrypt)
|
||||
@@ -659,7 +667,7 @@ static uint8_t desync(
|
||||
struct func_list *func;
|
||||
int ref_arg = LUA_NOREF, status;
|
||||
bool b, b_cutoff_all, b_unwanted_payload;
|
||||
t_lua_desync_context ctx = { .dp = dp, .ctrack = ctrack, .dis = dis };
|
||||
t_lua_desync_context ctx = { .dp = dp, .ctrack = ctrack, .dis = dis, .cancel = false, .incoming = bIncoming };
|
||||
const char *sDirection = bIncoming ? "in" : "out";
|
||||
struct packet_range *range;
|
||||
size_t l;
|
||||
@@ -678,17 +686,19 @@ static uint8_t desync(
|
||||
DLOG("lua out cutoff\n");
|
||||
return verdict;
|
||||
}
|
||||
if (!pos) pos = &ctrack->pos;
|
||||
}
|
||||
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
if (LIST_FIRST(&dp->lua_desync))
|
||||
{
|
||||
unsigned int func_n;
|
||||
|
||||
b_cutoff_all = b_unwanted_payload = true;
|
||||
func_n = 1;
|
||||
ctx.func_n = 1;
|
||||
LIST_FOREACH(func, &dp->lua_desync, next)
|
||||
{
|
||||
ctx.func = func->func;
|
||||
desync_instance(func->func, dp->n, func_n, instance, sizeof(instance));
|
||||
desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance));
|
||||
ctx.instance = instance;
|
||||
range = bIncoming ? &func->range_in : &func->range_out;
|
||||
|
||||
@@ -699,12 +709,12 @@ static uint8_t desync(
|
||||
{
|
||||
if (lua_instance_cutoff_check(&ctx, bIncoming))
|
||||
DLOG("* lua '%s' : voluntary cutoff\n", instance);
|
||||
else if (check_pos_cutoff(ctrack, bIncoming, range))
|
||||
else if (check_pos_cutoff(pos, bIncoming, range))
|
||||
{
|
||||
DLOG("* lua '%s' : %s pos %c%llu %c%llu is beyond range %c%u%c%c%u (ctrack %s)\n",
|
||||
instance, sDirection,
|
||||
range->from.mode, pos_get(ctrack, range->from.mode, bIncoming),
|
||||
range->to.mode, pos_get(ctrack, range->to.mode, bIncoming),
|
||||
range->from.mode, pos_get(pos, range->from.mode, bIncoming),
|
||||
range->to.mode, pos_get(pos, range->to.mode, bIncoming),
|
||||
range->from.mode, range->from.pos,
|
||||
range->upper_cutoff ? '<' : '-',
|
||||
range->to.mode, range->to.pos,
|
||||
@@ -713,7 +723,7 @@ static uint8_t desync(
|
||||
else
|
||||
b_cutoff_all = false;
|
||||
}
|
||||
func_n++;
|
||||
ctx.func_n++;
|
||||
}
|
||||
if (b_cutoff_all)
|
||||
{
|
||||
@@ -725,14 +735,24 @@ static uint8_t desync(
|
||||
else
|
||||
{
|
||||
// create arg table that persists across multiple desync function calls
|
||||
lua_createtable(params.L, 0, 12 + !!ctrack + !!dis->tcp + 3*!!replay_piece_count);
|
||||
lua_newtable(params.L);
|
||||
lua_pushf_dissect(dis);
|
||||
lua_pushf_ctrack(ctrack);
|
||||
lua_pushf_ctrack(ctrack, pos);
|
||||
lua_pushf_int("profile_n", dp->n);
|
||||
if (dp->name) lua_pushf_str("profile_name", dp->name);
|
||||
if (dp->n_tpl) lua_pushf_int("template_n", dp->n_tpl);
|
||||
if (dp->name_tpl) lua_pushf_str("template_name", dp->name_tpl);
|
||||
if (dp->cookie) lua_pushf_str("cookie", dp->cookie);
|
||||
lua_pushf_bool("outgoing", !bIncoming);
|
||||
lua_pushf_str("ifin", (ifin && *ifin) ? ifin : NULL);
|
||||
lua_pushf_str("ifout", (ifout && *ifout) ? ifout : NULL);
|
||||
lua_pushf_int("fwmark", fwmark);
|
||||
lua_pushf_lint("fwmark", fwmark);
|
||||
lua_pushf_table("target");
|
||||
lua_getfield(params.L,-1,"target");
|
||||
if (sdport) lua_pushf_int("port",sdport);
|
||||
if (sdp4) lua_pushf_lstr("ip",(const char*)sdp4,sizeof(*sdp4));
|
||||
if (sdp6) lua_pushf_lstr("ip6",(const char*)sdp6,sizeof(*sdp6));
|
||||
lua_pop(params.L,1);
|
||||
lua_pushf_bool("replay", !!replay_piece_count);
|
||||
if (replay_piece_count)
|
||||
{
|
||||
@@ -741,36 +761,37 @@ static uint8_t desync(
|
||||
lua_pushf_bool("replay_piece_last", (replay_piece+1)>=replay_piece_count);
|
||||
}
|
||||
lua_pushf_str("l7payload", l7payload_str(l7payload));
|
||||
lua_pushf_str("l7proto", l7proto_str(l7proto));
|
||||
lua_pushf_int("reasm_offset", reasm_offset);
|
||||
lua_pushf_raw("reasm_data", rdata_payload, rlen_payload);
|
||||
lua_pushf_raw("decrypt_data", data_decrypt, len_decrypt);
|
||||
if (ctrack) lua_pushf_reg("instance_cutoff", ctrack->lua_instance_cutoff);
|
||||
//if (ctrack) lua_pushf_reg("instance_cutoff", ctrack->lua_instance_cutoff);
|
||||
if (dis->tcp)
|
||||
{
|
||||
// recommended mss value for generated packets
|
||||
if (ctrack && ctrack->mss_orig)
|
||||
lua_pushf_int("tcp_mss", ctrack->mss_orig);
|
||||
if (pos && pos->mss_orig)
|
||||
lua_pushf_int("tcp_mss", pos->mss_orig);
|
||||
else
|
||||
lua_pushf_global("tcp_mss", "DEFAULT_MSS");
|
||||
}
|
||||
ref_arg = luaL_ref(params.L, LUA_REGISTRYINDEX);
|
||||
|
||||
func_n = 1;
|
||||
ctx.func_n = 1;
|
||||
LIST_FOREACH(func, &dp->lua_desync, next)
|
||||
{
|
||||
ctx.func = func->func;
|
||||
desync_instance(func->func, dp->n, func_n, instance, sizeof(instance));
|
||||
desync_instance(func->func, dp->n, ctx.func_n, instance, sizeof(instance));
|
||||
ctx.instance = instance;
|
||||
|
||||
if (!lua_instance_cutoff_check(&ctx, bIncoming))
|
||||
{
|
||||
range = bIncoming ? &func->range_in : &func->range_out;
|
||||
if (check_pos_range(ctrack, bIncoming, range))
|
||||
if (check_pos_range(pos, bIncoming, range))
|
||||
{
|
||||
DLOG("* lua '%s' : %s pos %c%llu %c%llu in range %c%u%c%c%u\n",
|
||||
instance, sDirection,
|
||||
range->from.mode, pos_get(ctrack, range->from.mode, bIncoming),
|
||||
range->to.mode, pos_get(ctrack, range->to.mode, bIncoming),
|
||||
range->from.mode, pos_get(pos, range->from.mode, bIncoming),
|
||||
range->to.mode, pos_get(pos, range->to.mode, bIncoming),
|
||||
range->from.mode, range->from.pos,
|
||||
range->upper_cutoff ? '<' : '-',
|
||||
range->to.mode, range->to.pos);
|
||||
@@ -789,7 +810,7 @@ static uint8_t desync(
|
||||
lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg);
|
||||
lua_pushf_args(&func->args, -1);
|
||||
lua_pushf_str("func", func->func);
|
||||
lua_pushf_int("func_n", func_n);
|
||||
lua_pushf_int("func_n", ctx.func_n);
|
||||
lua_pushf_str("func_instance", instance);
|
||||
int initial_stack_top = lua_gettop(params.L);
|
||||
status = lua_pcall(params.L, 2, LUA_MULTRET, 0);
|
||||
@@ -808,37 +829,6 @@ static uint8_t desync(
|
||||
case VERDICT_DROP:
|
||||
verdict = VERDICT_DROP;
|
||||
}
|
||||
|
||||
if (ctrack)
|
||||
{
|
||||
// lua cutoff
|
||||
lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg);
|
||||
lua_getfield(params.L, -1, "track");
|
||||
if (lua_istable(params.L, -1))
|
||||
{
|
||||
if (!ctrack->b_lua_in_cutoff)
|
||||
{
|
||||
lua_getfield(params.L, -1, "lua_in_cutoff");
|
||||
if (lua_toboolean(params.L, -1))
|
||||
{
|
||||
ctrack->b_lua_in_cutoff = true;
|
||||
DLOG("* lua in cutoff set\n");
|
||||
}
|
||||
lua_pop(params.L, 1);
|
||||
}
|
||||
if (!ctrack->b_lua_out_cutoff)
|
||||
{
|
||||
lua_getfield(params.L, -1, "lua_out_cutoff");
|
||||
if (lua_toboolean(params.L, -1))
|
||||
{
|
||||
ctrack->b_lua_out_cutoff = true;
|
||||
DLOG("* lua out cutoff set\n");
|
||||
}
|
||||
lua_pop(params.L, 1);
|
||||
}
|
||||
}
|
||||
lua_pop(params.L, 2);
|
||||
}
|
||||
}
|
||||
else
|
||||
DLOG("* lua '%s' : payload_type '%s' does not satisfy filter\n", instance, l7payload_str(l7payload));
|
||||
@@ -846,13 +836,14 @@ static uint8_t desync(
|
||||
else
|
||||
DLOG("* lua '%s' : %s pos %c%llu %c%llu out of range %c%u%c%c%u\n",
|
||||
instance, sDirection,
|
||||
range->from.mode, pos_get(ctrack, range->from.mode, bIncoming),
|
||||
range->to.mode, pos_get(ctrack, range->to.mode, bIncoming),
|
||||
range->from.mode, pos_get(pos, range->from.mode, bIncoming),
|
||||
range->to.mode, pos_get(pos, range->to.mode, bIncoming),
|
||||
range->from.mode, range->from.pos,
|
||||
range->upper_cutoff ? '<' : '-',
|
||||
range->to.mode, range->to.pos);
|
||||
}
|
||||
func_n++;
|
||||
if (ctx.cancel) break;
|
||||
ctx.func_n++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -894,6 +885,7 @@ static uint8_t desync(
|
||||
DLOG("no lua functions in this profile\n");
|
||||
ex:
|
||||
luaL_unref(params.L, LUA_REGISTRYINDEX, ref_arg);
|
||||
LUA_STACK_GUARD_LEAVE(params.L, 0)
|
||||
return verdict;
|
||||
err:
|
||||
DLOG_ERR("desync ERROR. passing packet unmodified.\n");
|
||||
@@ -940,7 +932,13 @@ static void setup_direction(
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, const struct dissect *dis, uint8_t *mod_pkt, size_t *len_mod_pkt)
|
||||
static uint8_t dpi_desync_tcp_packet_play(
|
||||
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset,
|
||||
uint32_t fwmark,
|
||||
const char *ifin, const char *ifout,
|
||||
const t_ctrack_position *pos,
|
||||
const struct dissect *dis,
|
||||
uint8_t *mod_pkt, size_t *len_mod_pkt)
|
||||
{
|
||||
uint8_t verdict = VERDICT_PASS;
|
||||
|
||||
@@ -979,7 +977,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
l7proto = ctrack_replay->l7proto;
|
||||
dp = ctrack_replay->dp;
|
||||
if (dp)
|
||||
DLOG("using cached desync profile %u\n", dp->n);
|
||||
DLOG("using cached desync profile %u (%s)\n", dp->n, PROFILE_NAME(dp));
|
||||
else if (!ctrack_replay->dp_search_complete)
|
||||
{
|
||||
dp = ctrack_replay->dp = dp_find(¶ms.desync_profiles, IPPROTO_TCP, sdip4, sdip6, sdport, ctrack_replay->hostname, ctrack_replay->hostname_is_ip, l7proto, ssid, NULL, NULL, NULL);
|
||||
@@ -1007,7 +1005,6 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
// in absence of conntrack guess direction by presence of interface names. won't work on BSD
|
||||
bReverseFixed = ctrack ? (bReverse ^ params.server) : (bReverse = ifin && ifin && (!ifout || !*ifout));
|
||||
setup_direction(dis, bReverseFixed, &src, &dst, &sdip4, &sdip6, &sdport);
|
||||
|
||||
ifname = bReverse ? ifin : ifout;
|
||||
#ifdef HAS_FILTER_SSID
|
||||
ssid = wlan_ssid_search_ifname(ifname);
|
||||
@@ -1015,7 +1012,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
#endif
|
||||
if (ctrack) l7proto = ctrack->l7proto;
|
||||
if (dp)
|
||||
DLOG("using cached desync profile %u\n", dp->n);
|
||||
DLOG("using cached desync profile %u (%s)\n", dp->n, PROFILE_NAME(dp));
|
||||
else if (!ctrack || !ctrack->dp_search_complete)
|
||||
{
|
||||
const char *hostname = NULL;
|
||||
@@ -1027,7 +1024,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
if (!hostname && !bReverse)
|
||||
{
|
||||
if (ipcache_get_hostname(sdip4, sdip6, host, sizeof(host), &hostname_is_ip) && *host)
|
||||
if (!(hostname = ctrack_replay->hostname = strdup(host)))
|
||||
if (!(hostname = ctrack->hostname = strdup(host)))
|
||||
DLOG_ERR("strdup(host): out of memory\n");
|
||||
}
|
||||
}
|
||||
@@ -1096,7 +1093,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
// process reply packets for auto hostlist mode
|
||||
// by looking at RSTs or HTTP replies we decide whether original request looks like DPI blocked
|
||||
// we only process first-sequence replies. do not react to subsequent redirects or RSTs
|
||||
if (!params.server && ctrack && ctrack->hostname && ctrack->hostname_ah_check && (ctrack->ack_last - ctrack->ack0) == 1)
|
||||
if (!params.server && ctrack && ctrack->hostname && ctrack->hostname_ah_check && (ctrack->pos.ack_last - ctrack->pos.ack0) == 1)
|
||||
{
|
||||
bool bFail = false;
|
||||
|
||||
@@ -1109,7 +1106,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
if (dis->tcp->th_flags & TH_RST)
|
||||
{
|
||||
DLOG("incoming RST detected for hostname %s\n", ctrack->hostname);
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : incoming RST", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(l7proto));
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : incoming RST", ctrack->hostname, ctrack->dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto));
|
||||
bFail = true;
|
||||
}
|
||||
else if (dis->len_payload && l7proto == L7_HTTP)
|
||||
@@ -1121,7 +1118,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
if (bFail)
|
||||
{
|
||||
DLOG("redirect to another domain detected. possibly DPI redirect.\n");
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u : client %s : proto %s : redirect to another domain", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(l7proto));
|
||||
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : redirect to another domain", ctrack->hostname, ctrack->dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto));
|
||||
}
|
||||
else
|
||||
DLOG("local or in-domain redirect detected. it's not a DPI redirect.\n");
|
||||
@@ -1181,17 +1178,6 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
DLOG("not applying tampering to HTTP without Host:\n");
|
||||
goto pass;
|
||||
}
|
||||
if (ctrack)
|
||||
{
|
||||
// we do not reassemble http
|
||||
if (!ctrack->req_seq_present)
|
||||
{
|
||||
ctrack->req_seq_start = ctrack->seq_last;
|
||||
ctrack->req_seq_end = ctrack->pos_orig - 1;
|
||||
ctrack->req_seq_present = ctrack->req_seq_finalized = true;
|
||||
DLOG("req retrans : tcp seq interval %u-%u\n", ctrack->req_seq_start, ctrack->req_seq_end);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (IsTLSClientHello(rdata_payload, rlen_payload, TLS_PARTIALS_ENABLE))
|
||||
{
|
||||
@@ -1210,31 +1196,16 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
if (ctrack && !(params.reasm_payload_disable && l7_payload_match(l7payload, params.reasm_payload_disable)))
|
||||
{
|
||||
// do not reasm retransmissions
|
||||
if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_orig) && !ctrack->req_seq_abandoned &&
|
||||
!(ctrack->req_seq_finalized && seq_within(ctrack->seq_last, ctrack->req_seq_start, ctrack->req_seq_end)))
|
||||
if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_orig) && !is_retransmission(ctrack))
|
||||
{
|
||||
// do not reconstruct unexpected large payload (they are feeding garbage ?)
|
||||
if (!reasm_orig_start(ctrack, IPPROTO_TCP, TLSRecordLen(dis->data_payload), TCP_MAX_REASM, dis->data_payload, dis->len_payload))
|
||||
goto pass_reasm_cancel;
|
||||
}
|
||||
if (!ctrack->req_seq_finalized)
|
||||
{
|
||||
if (!ctrack->req_seq_present)
|
||||
{
|
||||
// lower bound of request seq interval
|
||||
ctrack->req_seq_start = ctrack->seq_last;
|
||||
ctrack->req_seq_present = true;
|
||||
}
|
||||
// upper bound of request seq interval
|
||||
// it can grow on every packet until request is complete. then interval is finalized and never touched again.
|
||||
ctrack->req_seq_end = ctrack->pos_orig - 1;
|
||||
DLOG("req retrans : seq interval %u-%u\n", ctrack->req_seq_start, ctrack->req_seq_end);
|
||||
ctrack->req_seq_finalized |= bReqFull;
|
||||
}
|
||||
|
||||
if (!ReasmIsEmpty(&ctrack->reasm_orig))
|
||||
{
|
||||
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &dst, fwmark, desync_fwmark, ifin, ifout))
|
||||
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
|
||||
{
|
||||
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
|
||||
}
|
||||
@@ -1252,7 +1223,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ctrack && (ctrack->seq_last - ctrack->seq0)==1 && IsMTProto(dis->data_payload, dis->len_payload))
|
||||
else if (ctrack && (ctrack->pos.seq_last - ctrack->pos.seq0)==1 && IsMTProto(dis->data_payload, dis->len_payload))
|
||||
{
|
||||
DLOG("packet contains telegram mtproto2 initial\n");
|
||||
// mtproto detection requires aes. react only on the first tcp data packet. do not detect if ctrack unavailable.
|
||||
@@ -1271,12 +1242,6 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
};
|
||||
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ctrack, &l7proto, &l7payload);
|
||||
}
|
||||
if (ctrack && ctrack->req_seq_finalized)
|
||||
{
|
||||
uint32_t dseq = ctrack->seq_last - ctrack->req_seq_end;
|
||||
// do not react to 32-bit overflowed sequence numbers. allow 16 Mb grace window then cutoff.
|
||||
if (dseq >= 0x1000000 && !(dseq & 0x80000000)) ctrack->req_seq_abandoned = true;
|
||||
}
|
||||
|
||||
if (bHaveHost)
|
||||
{
|
||||
@@ -1339,7 +1304,6 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
|
||||
}
|
||||
}
|
||||
|
||||
if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp))
|
||||
{
|
||||
if (!bCheckDone)
|
||||
@@ -1379,7 +1343,7 @@ static uint8_t dpi_desync_tcp_packet_play(unsigned int replay_piece, unsigned in
|
||||
ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2));
|
||||
DLOG("dpi desync src=%s dst=%s track_direction=%s fixed_direction=%s connection_proto=%s payload_type=%s\n", s1, s2, bReverse ? "in" : "out", bReverseFixed ? "in" : "out", l7proto_str(l7proto), l7payload_str(l7payload));
|
||||
}
|
||||
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, l7payload, dis, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, rdata_payload, rlen_payload, NULL, 0);
|
||||
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, pos, l7payload, l7proto, dis, sdip4, sdip6, sdport, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, rdata_payload, rlen_payload, NULL, 0);
|
||||
|
||||
pass:
|
||||
return (!bReverseFixed && (verdict & VERDICT_MASK) == VERDICT_DROP) ? ct_new_postnat_fix(ctrack, dis, mod_pkt, len_mod_pkt) : verdict;
|
||||
@@ -1396,7 +1360,13 @@ static void quic_reasm_cancel(t_ctrack *ctrack, const char *reason)
|
||||
}
|
||||
|
||||
|
||||
static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout, const struct dissect *dis, uint8_t *mod_pkt, size_t *len_mod_pkt)
|
||||
static uint8_t dpi_desync_udp_packet_play(
|
||||
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset,
|
||||
uint32_t fwmark,
|
||||
const char *ifin, const char *ifout,
|
||||
const t_ctrack_position *pos,
|
||||
const struct dissect *dis,
|
||||
uint8_t *mod_pkt, size_t *len_mod_pkt)
|
||||
{
|
||||
uint8_t verdict = VERDICT_PASS;
|
||||
|
||||
@@ -1452,7 +1422,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
|
||||
l7proto = ctrack_replay->l7proto;
|
||||
dp = ctrack_replay->dp;
|
||||
if (dp)
|
||||
DLOG("using cached desync profile %u\n", dp->n);
|
||||
DLOG("using cached desync profile %u (%s)\n", dp->n, PROFILE_NAME(dp));
|
||||
else if (!ctrack_replay->dp_search_complete)
|
||||
{
|
||||
dp = ctrack_replay->dp = dp_find(¶ms.desync_profiles, IPPROTO_UDP, sdip4, sdip6, sdport, ctrack_replay->hostname, ctrack_replay->hostname_is_ip, l7proto, ssid, NULL, NULL, NULL);
|
||||
@@ -1488,7 +1458,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
|
||||
#endif
|
||||
if (ctrack) l7proto = ctrack->l7proto;
|
||||
if (dp)
|
||||
DLOG("using cached desync profile %u\n", dp->n);
|
||||
DLOG("using cached desync profile %u (%s)\n", dp->n, PROFILE_NAME(dp));
|
||||
else if (!ctrack || !ctrack->dp_search_complete)
|
||||
{
|
||||
const char *hostname = NULL;
|
||||
@@ -1500,7 +1470,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
|
||||
if (!hostname && !bReverse)
|
||||
{
|
||||
if (ipcache_get_hostname(sdip4, sdip6, host, sizeof(host), &hostname_is_ip) && *host)
|
||||
if (!(hostname = ctrack_replay->hostname = strdup(host)))
|
||||
if (!(hostname = ctrack->hostname = strdup(host)))
|
||||
DLOG_ERR("strdup(host): out of memory\n");
|
||||
}
|
||||
}
|
||||
@@ -1553,6 +1523,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
|
||||
t_protocol_probe testers[] = {
|
||||
{L7P_DNS_RESPONSE,L7_DNS,IsDNSResponse,false},
|
||||
{L7P_DHT,L7_DHT,IsDht,false},
|
||||
{L7P_STUN,L7_STUN,IsStunMessage,false},
|
||||
{L7P_WIREGUARD_INITIATION,L7_WIREGUARD,IsWireguardHandshakeInitiation,false},
|
||||
{L7P_WIREGUARD_RESPONSE,L7_WIREGUARD,IsWireguardHandshakeResponse,false},
|
||||
{L7P_WIREGUARD_COOKIE,L7_WIREGUARD,IsWireguardHandshakeCookie,false},
|
||||
@@ -1629,7 +1600,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
|
||||
}
|
||||
if (!ReasmIsEmpty(&ctrack->reasm_orig))
|
||||
{
|
||||
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &dst, fwmark, desync_fwmark, ifin, ifout))
|
||||
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
|
||||
{
|
||||
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
|
||||
}
|
||||
@@ -1669,7 +1640,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
|
||||
if (!reasm_orig_start(ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len))
|
||||
goto pass_reasm_cancel;
|
||||
}
|
||||
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &dst, fwmark, desync_fwmark, ifin, ifout))
|
||||
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
|
||||
{
|
||||
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ctrack->delayed));
|
||||
}
|
||||
@@ -1704,7 +1675,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
|
||||
|
||||
t_protocol_probe testers[] = {
|
||||
{L7P_DISCORD_IP_DISCOVERY,L7_DISCORD,IsDiscordIpDiscoveryRequest,false},
|
||||
{L7P_STUN_BINDING_REQ,L7_STUN,IsStunBindingRequest,false},
|
||||
{L7P_STUN,L7_STUN,IsStunMessage,false},
|
||||
{L7P_DNS_QUERY,L7_DNS,IsDNSQuery,false},
|
||||
{L7P_DHT,L7_DHT,IsDht,false},
|
||||
{L7P_WIREGUARD_INITIATION,L7_WIREGUARD,IsWireguardHandshakeInitiation,false},
|
||||
@@ -1828,7 +1799,7 @@ static uint8_t dpi_desync_udp_packet_play(unsigned int replay_piece, unsigned in
|
||||
ntop46_port((struct sockaddr *)&dst, s2, sizeof(s2));
|
||||
DLOG("dpi desync src=%s dst=%s track_direction=%s fixed_direction=%s connection_proto=%s payload_type=%s\n", s1, s2, bReverse ? "in" : "out", bReverseFixed ? "in" : "out", l7proto_str(l7proto), l7payload_str(l7payload));
|
||||
}
|
||||
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, l7payload, dis, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, NULL, 0, data_decrypt, len_decrypt);
|
||||
verdict = desync(dp, fwmark, ifin, ifout, bReverseFixed, ctrack_replay, pos, l7payload, l7proto, dis, sdip4, sdip6, sdport, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, NULL, 0, data_decrypt, len_decrypt);
|
||||
|
||||
pass:
|
||||
return (!bReverse && (verdict & VERDICT_MASK) == VERDICT_DROP) ? ct_new_postnat_fix(ctrack, dis, mod_pkt, len_mod_pkt) : verdict;
|
||||
@@ -1877,6 +1848,7 @@ static void packet_debug(bool replay, const struct dissect *dis)
|
||||
|
||||
static uint8_t dpi_desync_packet_play(
|
||||
unsigned int replay_piece, unsigned int replay_piece_count, size_t reasm_offset, uint32_t fwmark, const char *ifin, const char *ifout,
|
||||
const t_ctrack_position *pos,
|
||||
const uint8_t *data_pkt, size_t len_pkt,
|
||||
uint8_t *mod_pkt, size_t *len_mod_pkt)
|
||||
{
|
||||
@@ -1892,7 +1864,7 @@ static uint8_t dpi_desync_packet_play(
|
||||
case IPPROTO_TCP:
|
||||
if (dis.tcp)
|
||||
{
|
||||
verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, &dis, mod_pkt, len_mod_pkt);
|
||||
verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, pos, &dis, mod_pkt, len_mod_pkt);
|
||||
// we fix csum before pushing to replay queue
|
||||
if (!replay_piece_count) verdict_tcp_csum_fix(verdict, (struct tcphdr *)dis.tcp, dis.transport_len, dis.ip, dis.ip6);
|
||||
}
|
||||
@@ -1900,7 +1872,7 @@ static uint8_t dpi_desync_packet_play(
|
||||
case IPPROTO_UDP:
|
||||
if (dis.udp)
|
||||
{
|
||||
verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, &dis, mod_pkt, len_mod_pkt);
|
||||
verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, pos, &dis, mod_pkt, len_mod_pkt);
|
||||
// we fix csum before pushing to replay queue
|
||||
if (!replay_piece_count) verdict_udp_csum_fix(verdict, (struct udphdr *)dis.udp, dis.transport_len, dis.ip, dis.ip6);
|
||||
}
|
||||
@@ -1912,7 +1884,7 @@ static uint8_t dpi_desync_packet_play(
|
||||
uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifin, const char *ifout, const uint8_t *data_pkt, size_t len_pkt, uint8_t *mod_pkt, size_t *len_mod_pkt)
|
||||
{
|
||||
ipcachePurgeRateLimited(¶ms.ipcache, params.ipcache_lifetime);
|
||||
return dpi_desync_packet_play(0, 0, 0, fwmark, ifin, ifout, data_pkt, len_pkt, mod_pkt, len_mod_pkt);
|
||||
return dpi_desync_packet_play(0, 0, 0, fwmark, ifin, ifout, NULL, data_pkt, len_pkt, mod_pkt, len_mod_pkt);
|
||||
}
|
||||
|
||||
|
||||
@@ -1930,7 +1902,7 @@ static bool replay_queue(struct rawpacket_tailhead *q)
|
||||
{
|
||||
DLOG("REPLAYING delayed packet #%u offset %zu\n", i+1, offset);
|
||||
modlen = sizeof(mod);
|
||||
uint8_t verdict = dpi_desync_packet_play(i, count, offset, rp->fwmark_orig, rp->ifin, rp->ifout, rp->packet, rp->len, mod, &modlen);
|
||||
uint8_t verdict = dpi_desync_packet_play(i, count, offset, rp->fwmark_orig, rp->ifin, rp->ifout, rp->pos_present ? &rp->pos : NULL, rp->packet, rp->len, mod, &modlen);
|
||||
switch (verdict & VERDICT_MASK)
|
||||
{
|
||||
case VERDICT_MODIFY:
|
||||
|
||||
@@ -258,7 +258,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
|
||||
// return : true = apply fooling, false = do not apply
|
||||
bool HostlistCheck(const struct desync_profile *dp, const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck)
|
||||
{
|
||||
DLOG("* hostlist check for profile %u\n",dp->n);
|
||||
DLOG("* hostlist check for profile %u (%s)\n",dp->n,PROFILE_NAME(dp));
|
||||
return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, no_match_subdomains, excluded, bSkipReloadCheck);
|
||||
}
|
||||
|
||||
@@ -301,13 +301,34 @@ struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude,
|
||||
filename);
|
||||
}
|
||||
|
||||
static void HostlistsDebugProfile(const struct desync_profile *dp, const char *entity)
|
||||
{
|
||||
struct hostlist_item *hl_item;
|
||||
|
||||
LIST_FOREACH(hl_item, &dp->hl_collection, next)
|
||||
if (hl_item->hfile!=dp->hostlist_auto)
|
||||
{
|
||||
if (hl_item->hfile->filename)
|
||||
DLOG("%s %u (%s) include hostlist %s%s\n",entity, dp->n, PROFILE_NAME(dp), hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
|
||||
else
|
||||
DLOG("%s %u (%s) include fixed hostlist%s\n",entity, dp->n, PROFILE_NAME(dp), hl_item->hfile->hostlist ? "" : " (empty)");
|
||||
}
|
||||
LIST_FOREACH(hl_item, &dp->hl_collection_exclude, next)
|
||||
{
|
||||
if (hl_item->hfile->filename)
|
||||
DLOG("%s %u (%s) exclude hostlist %s%s\n",entity, dp->n,PROFILE_NAME(dp),hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
|
||||
else
|
||||
DLOG("%s %u (%s) exclude fixed hostlist%s\n",entity, dp->n,PROFILE_NAME(dp),hl_item->hfile->hostlist ? "" : " (empty)");
|
||||
}
|
||||
if (dp->hostlist_auto)
|
||||
DLOG("%s %u (%s) auto hostlist %s%s\n",entity, dp->n,PROFILE_NAME(dp),dp->hostlist_auto->filename,dp->hostlist_auto->hostlist ? "" : " (empty)");
|
||||
}
|
||||
void HostlistsDebug()
|
||||
{
|
||||
if (!params.debug) return;
|
||||
|
||||
struct hostlist_file *hfile;
|
||||
struct desync_profile_list *dpl;
|
||||
struct hostlist_item *hl_item;
|
||||
|
||||
LIST_FOREACH(hfile, ¶ms.hostlists, next)
|
||||
{
|
||||
@@ -319,22 +340,10 @@ void HostlistsDebug()
|
||||
|
||||
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||
{
|
||||
LIST_FOREACH(hl_item, &dpl->dp.hl_collection, next)
|
||||
if (hl_item->hfile!=dpl->dp.hostlist_auto)
|
||||
{
|
||||
if (hl_item->hfile->filename)
|
||||
DLOG("profile %u include hostlist %s%s\n",dpl->dp.n, hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
|
||||
else
|
||||
DLOG("profile %u include fixed hostlist%s\n",dpl->dp.n, hl_item->hfile->hostlist ? "" : " (empty)");
|
||||
}
|
||||
LIST_FOREACH(hl_item, &dpl->dp.hl_collection_exclude, next)
|
||||
{
|
||||
if (hl_item->hfile->filename)
|
||||
DLOG("profile %u exclude hostlist %s%s\n",dpl->dp.n,hl_item->hfile->filename,hl_item->hfile->hostlist ? "" : " (empty)");
|
||||
else
|
||||
DLOG("profile %u exclude fixed hostlist%s\n",dpl->dp.n,hl_item->hfile->hostlist ? "" : " (empty)");
|
||||
}
|
||||
if (dpl->dp.hostlist_auto)
|
||||
DLOG("profile %u auto hostlist %s%s\n",dpl->dp.n,dpl->dp.hostlist_auto->filename,dpl->dp.hostlist_auto->hostlist ? "" : " (empty)");
|
||||
HostlistsDebugProfile(&dpl->dp, "profile");
|
||||
}
|
||||
LIST_FOREACH(dpl, ¶ms.desync_templates, next)
|
||||
{
|
||||
HostlistsDebugProfile(&dpl->dp, "template");
|
||||
}
|
||||
}
|
||||
|
||||
37
nfq2/ipset.c
37
nfq2/ipset.c
@@ -235,7 +235,7 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip
|
||||
bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6)
|
||||
{
|
||||
if (PROFILE_IPSETS_ABSENT(dp)) return true;
|
||||
DLOG("* ipset check for profile %u\n",dp->n);
|
||||
DLOG("* ipset check for profile %u (%s)\n",dp->n,PROFILE_NAME(dp));
|
||||
return IpsetCheck_(&dp->ips_collection,&dp->ips_collection_exclude,ipv4,ipv6);
|
||||
}
|
||||
|
||||
@@ -287,13 +287,31 @@ static const char *dbg_ipset_fill(const ipset *ips)
|
||||
else
|
||||
return "empty";
|
||||
}
|
||||
void IpsetsDebugProfile(const struct desync_profile *dp, const char *entity)
|
||||
{
|
||||
struct ipset_item *ips_item;
|
||||
|
||||
LIST_FOREACH(ips_item, &dp->ips_collection, next)
|
||||
{
|
||||
if (ips_item->hfile->filename)
|
||||
DLOG("%s %u (%s) include ipset %s (%s)\n",entity,dp->n,PROFILE_NAME(dp),ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
|
||||
else
|
||||
DLOG("%s %u (%s) include fixed ipset (%s)\n",entity,dp->n,PROFILE_NAME(dp),dbg_ipset_fill(&ips_item->hfile->ipset));
|
||||
}
|
||||
LIST_FOREACH(ips_item, &dp->ips_collection_exclude, next)
|
||||
{
|
||||
if (ips_item->hfile->filename)
|
||||
DLOG("%s %u (%s) exclude ipset %s (%s)\n",entity,dp->n,PROFILE_NAME(dp),ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
|
||||
else
|
||||
DLOG("%s %u (%s) exclude fixed ipset (%s)\n",entity,dp->n,PROFILE_NAME(dp),dbg_ipset_fill(&ips_item->hfile->ipset));
|
||||
}
|
||||
}
|
||||
void IpsetsDebug()
|
||||
{
|
||||
if (!params.debug) return;
|
||||
|
||||
struct ipset_file *hfile;
|
||||
struct desync_profile_list *dpl;
|
||||
struct ipset_item *ips_item;
|
||||
|
||||
LIST_FOREACH(hfile, ¶ms.ipsets, next)
|
||||
{
|
||||
@@ -305,15 +323,10 @@ void IpsetsDebug()
|
||||
|
||||
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||
{
|
||||
LIST_FOREACH(ips_item, &dpl->dp.ips_collection, next)
|
||||
if (ips_item->hfile->filename)
|
||||
DLOG("profile %u include ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
|
||||
else
|
||||
DLOG("profile %u include fixed ipset (%s)\n",dpl->dp.n,dbg_ipset_fill(&ips_item->hfile->ipset));
|
||||
LIST_FOREACH(ips_item, &dpl->dp.ips_collection_exclude, next)
|
||||
if (ips_item->hfile->filename)
|
||||
DLOG("profile %u exclude ipset %s (%s)\n",dpl->dp.n,ips_item->hfile->filename,dbg_ipset_fill(&ips_item->hfile->ipset));
|
||||
else
|
||||
DLOG("profile %u exclude fixed ipset (%s)\n",dpl->dp.n,dbg_ipset_fill(&ips_item->hfile->ipset));
|
||||
IpsetsDebugProfile(&dpl->dp, "profile");
|
||||
}
|
||||
LIST_FOREACH(dpl, ¶ms.desync_templates, next)
|
||||
{
|
||||
IpsetsDebugProfile(&dpl->dp, "template");
|
||||
}
|
||||
}
|
||||
|
||||
467
nfq2/lua.c
467
nfq2/lua.c
@@ -19,6 +19,11 @@
|
||||
#include "crypto/aes-ctr.h"
|
||||
|
||||
|
||||
void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size)
|
||||
{
|
||||
snprintf(instance, inst_size, "%s_%u_%u", func, dp_n, func_n);
|
||||
}
|
||||
|
||||
static void lua_check_argc(lua_State *L, const char *where, int argc)
|
||||
{
|
||||
int num_args = lua_gettop(L);
|
||||
@@ -63,72 +68,100 @@ static int luacall_DLOG_CONDUP(lua_State *L)
|
||||
static int luacall_bitlshift(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"bitlshift",2);
|
||||
lua_pushinteger(L,luaL_checkinteger(L,1) << luaL_checkinteger(L,2));
|
||||
int64_t v=(int64_t)luaL_checklint(L,1);
|
||||
if (v>0xFFFFFFFF || v<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
lua_pushlint(L,((uint32_t)v) << luaL_checkinteger(L,2));
|
||||
return 1;
|
||||
}
|
||||
static int luacall_bitrshift(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"bitrshift",2);
|
||||
lua_pushinteger(L,((LUA_UNSIGNED)luaL_checkinteger(L,1)) >> luaL_checkinteger(L,2));
|
||||
int64_t v=(int64_t)luaL_checklint(L,1);
|
||||
if (v>0xFFFFFFFF || v<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
lua_pushlint(L,((uint32_t)v) >> luaL_checkinteger(L,2));
|
||||
return 1;
|
||||
}
|
||||
static int luacall_bitand(lua_State *L)
|
||||
{
|
||||
lua_check_argc_range(L,"bitand",2,100);
|
||||
int argc = lua_gettop(L);
|
||||
lua_Integer v=luaL_checkinteger(L,1);
|
||||
for(int i=2;i<=argc;i++) v&=luaL_checkinteger(L,i);
|
||||
lua_pushinteger(L,v);
|
||||
int64_t v;
|
||||
uint32_t sum=0xFFFFFFFF;
|
||||
for(int i=1;i<=argc;i++)
|
||||
{
|
||||
v=(int64_t)luaL_checklint(L,i);
|
||||
if (v>0xFFFFFFFF || v<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
sum&=(uint32_t)v;
|
||||
}
|
||||
lua_pushlint(L,sum);
|
||||
return 1;
|
||||
}
|
||||
static int luacall_bitor(lua_State *L)
|
||||
{
|
||||
lua_check_argc_range(L,"bitor",2,100);
|
||||
lua_check_argc_range(L,"bitor",1,100);
|
||||
int argc = lua_gettop(L);
|
||||
lua_Integer v=0;
|
||||
for(int i=1;i<=argc;i++) v|=luaL_checkinteger(L,i);
|
||||
lua_pushinteger(L,v);
|
||||
int64_t v;
|
||||
uint32_t sum=0;
|
||||
for(int i=1;i<=argc;i++)
|
||||
{
|
||||
v=(int64_t)luaL_checklint(L,i);
|
||||
if (v>0xFFFFFFFF || v<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
sum|=(uint32_t)v;
|
||||
}
|
||||
lua_pushlint(L,sum);
|
||||
return 1;
|
||||
}
|
||||
static int luacall_bitnot(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"bitnot",1);
|
||||
lua_pushinteger(L,~luaL_checkinteger(L,1));
|
||||
lua_pushlint(L,~(uint32_t)luaL_checklint(L,1));
|
||||
return 1;
|
||||
}
|
||||
static int luacall_bitxor(lua_State *L)
|
||||
{
|
||||
lua_check_argc_range(L,"bitxor",2,100);
|
||||
lua_check_argc_range(L,"bitxor",1,100);
|
||||
int argc = lua_gettop(L);
|
||||
lua_Integer v=0;
|
||||
for(int i=1;i<=argc;i++) v^=luaL_checkinteger(L,i);
|
||||
lua_pushinteger(L,v);
|
||||
int64_t v;
|
||||
uint32_t sum=0;
|
||||
for(int i=1;i<=argc;i++)
|
||||
{
|
||||
v=(int64_t)luaL_checklint(L,i);
|
||||
if (v>0xFFFFFFFF || v<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
sum^=(uint32_t)v;
|
||||
}
|
||||
lua_pushlint(L,sum);
|
||||
return 1;
|
||||
}
|
||||
static int luacall_bitget(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"bitget",3);
|
||||
|
||||
LUA_UNSIGNED what = (LUA_UNSIGNED)luaL_checkinteger(L,1);
|
||||
int64_t iwhat = (int64_t)luaL_checklint(L,1);
|
||||
if (iwhat>0xFFFFFFFF || iwhat<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
uint32_t what = (uint32_t)iwhat;
|
||||
lua_Integer from = luaL_checkinteger(L,2);
|
||||
lua_Integer to = luaL_checkinteger(L,3);
|
||||
if (from>to || from>63 || to>63)
|
||||
if (from>to || from>31 || to>31)
|
||||
luaL_error(L, "bit range invalid");
|
||||
|
||||
what = (what >> from) & ~((lua_Integer)-1 << (to-from+1));
|
||||
|
||||
lua_pushinteger(L,what);
|
||||
lua_pushlint(L,what);
|
||||
return 1;
|
||||
}
|
||||
static int luacall_bitset(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"bitset",4);
|
||||
|
||||
LUA_UNSIGNED what = (LUA_UNSIGNED)luaL_checkinteger(L,1);
|
||||
int64_t iwhat = (int64_t)luaL_checklint(L,1);
|
||||
if (iwhat>0xFFFFFFFF || iwhat<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
uint32_t what = (uint32_t)iwhat;
|
||||
lua_Integer from = luaL_checkinteger(L,2);
|
||||
lua_Integer to = luaL_checkinteger(L,3);
|
||||
LUA_UNSIGNED set = (LUA_UNSIGNED)luaL_checkinteger(L,4);
|
||||
if (from>to || from>63 || to>63)
|
||||
int64_t iset = (int64_t)luaL_checklint(L,4);
|
||||
if (iset>0xFFFFFFFF || iset<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
uint32_t set = (uint32_t)iset;
|
||||
if (from>to || from>31 || to>31)
|
||||
luaL_error(L, "bit range invalid");
|
||||
|
||||
lua_Integer mask = ~((lua_Integer)-1 << (to-from+1));
|
||||
@@ -136,7 +169,7 @@ static int luacall_bitset(lua_State *L)
|
||||
mask <<= from;
|
||||
what = what & ~mask | set;
|
||||
|
||||
lua_pushinteger(L,what);
|
||||
lua_pushlint(L,what);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -193,15 +226,15 @@ static int luacall_u32(lua_State *L)
|
||||
offset = (argc>=2 && lua_type(L,2)!=LUA_TNIL) ? luaL_checkinteger(L,2)-1 : 0;
|
||||
if (offset<0 || (offset+4)>l) luaL_error(L, "out of range");
|
||||
|
||||
lua_pushinteger(L,pntoh32(p+offset));
|
||||
lua_pushlint(L,pntoh32(p+offset));
|
||||
return 1;
|
||||
}
|
||||
static int luacall_swap16(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"swap16",1);
|
||||
|
||||
lua_Integer i = luaL_checkinteger(L,1);
|
||||
if (i>0xFFFF || i<-(lua_Integer)0xFFFF) luaL_error(L, "out of range");
|
||||
int64_t i = (int64_t)luaL_checklint(L,1);
|
||||
if (i>0xFFFF || i<-(int64_t)0xFFFF) luaL_error(L, "out of range");
|
||||
uint16_t u = (uint16_t)i;
|
||||
// __builtin_bswap16 is absent in ancient lexra gcc 4.6
|
||||
lua_pushinteger(L,(u>>8) | ((u&0xFF)<<8));
|
||||
@@ -211,17 +244,52 @@ static int luacall_swap32(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"swap32",1);
|
||||
|
||||
lua_Integer i = luaL_checkinteger(L,1);
|
||||
if (i>0xFFFFFFFF || i<-(lua_Integer)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
int64_t i =(int64_t)luaL_checklint(L,1);
|
||||
if (i>0xFFFFFFFF || i<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
uint32_t u = (uint32_t)i;
|
||||
lua_pushinteger(L,__builtin_bswap32(u));
|
||||
lua_pushlint(L,__builtin_bswap32(u));
|
||||
return 1;
|
||||
}
|
||||
static int lua_uxadd(lua_State *L, uint32_t max)
|
||||
{
|
||||
int64_t v;
|
||||
uint32_t sum=0;
|
||||
int argc = lua_gettop(L);
|
||||
for(int i=1;i<=argc;i++)
|
||||
{
|
||||
v = (int64_t)luaL_checklint(L,i);
|
||||
if (v>max || v<-(int64_t)max) luaL_error(L, "out of range");
|
||||
sum+=(uint32_t)v;
|
||||
}
|
||||
lua_pushlint(L, sum & max);
|
||||
return 1;
|
||||
}
|
||||
static int luacall_u8add(lua_State *L)
|
||||
{
|
||||
lua_check_argc_range(L,"u8add",1,100);
|
||||
return lua_uxadd(L, 0xFF);
|
||||
}
|
||||
static int luacall_u16add(lua_State *L)
|
||||
{
|
||||
lua_check_argc_range(L,"u16add",1,100);
|
||||
return lua_uxadd(L, 0xFFFF);
|
||||
}
|
||||
static int luacall_u24add(lua_State *L)
|
||||
{
|
||||
lua_check_argc_range(L,"u24add",1,100);
|
||||
return lua_uxadd(L, 0xFFFFFF);
|
||||
}
|
||||
static int luacall_u32add(lua_State *L)
|
||||
{
|
||||
lua_check_argc_range(L,"u32add",1,100);
|
||||
return lua_uxadd(L, 0xFFFFFFFF);
|
||||
}
|
||||
|
||||
static int luacall_bu8(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"bu8",1);
|
||||
|
||||
lua_Integer i = luaL_checkinteger(L,1);
|
||||
int64_t i = (int64_t)luaL_checklint(L,1);
|
||||
if (i>0xFF || i<-(lua_Integer)0xFF) luaL_error(L, "out of range");
|
||||
uint8_t v=(uint8_t)i;
|
||||
lua_pushlstring(L,(char*)&v,1);
|
||||
@@ -231,7 +299,7 @@ static int luacall_bu16(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"bu16",1);
|
||||
|
||||
lua_Integer i = luaL_checkinteger(L,1);
|
||||
int64_t i = (int64_t)luaL_checklint(L,1);
|
||||
if (i>0xFFFF || i<-(lua_Integer)0xFFFF) luaL_error(L, "out of range");
|
||||
uint8_t v[2];
|
||||
phton16(v,(uint16_t)i);
|
||||
@@ -242,7 +310,7 @@ static int luacall_bu24(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"bu24",1);
|
||||
|
||||
lua_Integer i = luaL_checkinteger(L,1);
|
||||
int64_t i = (int64_t)luaL_checklint(L,1);
|
||||
if (i>0xFFFFFF || i<-(lua_Integer)0xFFFFFF) luaL_error(L, "out of range");
|
||||
uint8_t v[3];
|
||||
phton24(v,(uint32_t)i);
|
||||
@@ -253,8 +321,8 @@ static int luacall_bu32(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"bu32",1);
|
||||
|
||||
lua_Integer i = luaL_checkinteger(L,1);
|
||||
if (i>0xFFFFFFFF || i<-(lua_Integer)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
int64_t i = (int64_t)luaL_checklint(L,1);
|
||||
if (i>0xFFFFFFFF || i<-(int64_t)0xFFFFFFFF) luaL_error(L, "out of range");
|
||||
uint8_t v[4];
|
||||
phton32(v,(uint32_t)i);
|
||||
lua_pushlstring(L,(char*)v,4);
|
||||
@@ -264,10 +332,10 @@ static int luacall_bu32(lua_State *L)
|
||||
static int luacall_divint(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"divint",2);
|
||||
lua_Integer v1=luaL_checkinteger(L,1);
|
||||
lua_Integer v2=luaL_checkinteger(L,2);
|
||||
int64_t v1=(int64_t)luaL_checklint(L,1);
|
||||
int64_t v2=(int64_t)luaL_checklint(L,2);
|
||||
if (v2)
|
||||
lua_pushinteger(L,v1/v2);
|
||||
lua_pushlint(L,v1/v2);
|
||||
else
|
||||
lua_pushnil(L);
|
||||
return 1;
|
||||
@@ -617,15 +685,15 @@ static int luacall_clock_gettime(lua_State *L)
|
||||
}
|
||||
else
|
||||
{
|
||||
lua_pushinteger(L, ts.tv_sec);
|
||||
lua_pushlint(L, ts.tv_sec);
|
||||
lua_pushinteger(L, ts.tv_nsec);
|
||||
}
|
||||
LUA_STACK_GUARD_RETURN(L,2)
|
||||
}
|
||||
static int luacall_instance_cutoff(lua_State *L)
|
||||
{
|
||||
// out : func_name.profile_number[0]
|
||||
// in : func_name.profile_number[1]
|
||||
// out : instance_name.profile_number[0]
|
||||
// in : instance_name.profile_number[1]
|
||||
|
||||
lua_check_argc_range(L,"instance_cutoff",1,2);
|
||||
|
||||
@@ -633,45 +701,51 @@ static int luacall_instance_cutoff(lua_State *L)
|
||||
|
||||
const t_lua_desync_context *ctx;
|
||||
|
||||
if (!lua_islightuserdata(L,1))
|
||||
luaL_error(L, "instance_cutoff expect desync context in the first argument");
|
||||
ctx = lua_touserdata(L,1);
|
||||
|
||||
int argc=lua_gettop(L);
|
||||
bool bIn,bOut;
|
||||
if (argc>=2)
|
||||
{
|
||||
luaL_checktype(L,2,LUA_TBOOLEAN);
|
||||
bOut = lua_toboolean(L,2);
|
||||
bIn = !bOut;
|
||||
}
|
||||
if (lua_isnil(L,1))
|
||||
// this can happen in orchestrated function. they do not have their own ctx and they cant cutoff
|
||||
DLOG("instance cutoff not possible because missing ctx\n");
|
||||
else
|
||||
bIn = bOut = true;
|
||||
|
||||
if (ctx->ctrack)
|
||||
{
|
||||
DLOG("instance cutoff for '%s' in=%u out=%u\n",ctx->instance,bIn,bOut);
|
||||
lua_rawgeti(L,LUA_REGISTRYINDEX,ctx->ctrack->lua_instance_cutoff);
|
||||
lua_getfield(L,-1,ctx->instance);
|
||||
if (!lua_istable(L,-1))
|
||||
if (!lua_islightuserdata(L,1))
|
||||
luaL_error(L, "instance_cutoff expect desync context in the first argument");
|
||||
ctx = lua_touserdata(L,1);
|
||||
|
||||
int argc=lua_gettop(L);
|
||||
bool bIn,bOut;
|
||||
if (argc>=2 && lua_type(L,2)!=LUA_TNIL)
|
||||
{
|
||||
lua_pop(L,1);
|
||||
lua_pushf_table(ctx->instance);
|
||||
luaL_checktype(L,2,LUA_TBOOLEAN);
|
||||
bOut = lua_toboolean(L,2);
|
||||
bIn = !bOut;
|
||||
}
|
||||
else
|
||||
bIn = bOut = true;
|
||||
|
||||
if (ctx->ctrack)
|
||||
{
|
||||
DLOG("instance cutoff for '%s' in=%u out=%u\n",ctx->instance,bIn,bOut);
|
||||
lua_rawgeti(L,LUA_REGISTRYINDEX,ctx->ctrack->lua_instance_cutoff);
|
||||
lua_getfield(L,-1,ctx->instance);
|
||||
}
|
||||
lua_rawgeti(L,-1,ctx->dp->n);
|
||||
if (!lua_istable(L,-1))
|
||||
{
|
||||
lua_pop(L,1);
|
||||
lua_pushi_table(ctx->dp->n);
|
||||
if (!lua_istable(L,-1))
|
||||
{
|
||||
lua_pop(L,1);
|
||||
lua_pushf_table(ctx->instance);
|
||||
lua_getfield(L,-1,ctx->instance);
|
||||
}
|
||||
lua_rawgeti(L,-1,ctx->dp->n);
|
||||
if (!lua_istable(L,-1))
|
||||
{
|
||||
lua_pop(L,1);
|
||||
lua_pushi_table(ctx->dp->n);
|
||||
lua_rawgeti(L,-1,ctx->dp->n);
|
||||
}
|
||||
if (bOut) lua_pushi_bool(0,true);
|
||||
if (bIn) lua_pushi_bool(1,true);
|
||||
lua_pop(L,3);
|
||||
}
|
||||
if (bOut) lua_pushi_bool(0,true);
|
||||
if (bIn) lua_pushi_bool(1,true);
|
||||
lua_pop(L,3);
|
||||
else
|
||||
DLOG("instance cutoff requested for '%s' in=%u out=%u but not possible without conntrack\n",ctx->instance,bIn,bOut);
|
||||
}
|
||||
else
|
||||
DLOG("instance cutoff requested for '%s' in=%u out=%u but not possible without conntrack\n",ctx->instance,bIn,bOut);
|
||||
|
||||
LUA_STACK_GUARD_RETURN(L,0)
|
||||
}
|
||||
@@ -705,6 +779,102 @@ bool lua_instance_cutoff_check(const t_lua_desync_context *ctx, bool bIn)
|
||||
return b;
|
||||
}
|
||||
|
||||
static int luacall_lua_cutoff(lua_State *L)
|
||||
{
|
||||
lua_check_argc_range(L,"lua_cutoff",1,2);
|
||||
|
||||
LUA_STACK_GUARD_ENTER(L)
|
||||
|
||||
t_lua_desync_context *ctx;
|
||||
|
||||
if (!lua_islightuserdata(L,1))
|
||||
luaL_error(L, "lua_cutoff expect desync context in the first argument");
|
||||
ctx = lua_touserdata(L,1);
|
||||
|
||||
int argc=lua_gettop(L);
|
||||
bool bIn,bOut;
|
||||
if (argc>=2 && lua_type(L,2)!=LUA_TNIL)
|
||||
{
|
||||
luaL_checktype(L,2,LUA_TBOOLEAN);
|
||||
bOut = lua_toboolean(L,2);
|
||||
bIn = !bOut;
|
||||
}
|
||||
else
|
||||
bIn = bOut = true;
|
||||
|
||||
if (ctx->ctrack)
|
||||
{
|
||||
DLOG("lua cutoff from '%s' in=%u out=%u\n",ctx->instance,bIn,bOut);
|
||||
// lua cutoff is one way transition
|
||||
if (bIn) ctx->ctrack->b_lua_in_cutoff = true;
|
||||
if (bOut) ctx->ctrack->b_lua_out_cutoff = true;
|
||||
}
|
||||
else
|
||||
DLOG("lua cutoff requested from '%s' in=%u out=%u but not possible without conntrack\n",ctx->instance,bIn,bOut);
|
||||
|
||||
LUA_STACK_GUARD_RETURN(L,0)
|
||||
}
|
||||
|
||||
static int luacall_execution_plan(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"execution_plan",1);
|
||||
|
||||
LUA_STACK_GUARD_ENTER(L)
|
||||
|
||||
const t_lua_desync_context *ctx;
|
||||
|
||||
if (!lua_islightuserdata(L,1))
|
||||
luaL_error(L, "execution_plan expect desync context in the first argument");
|
||||
ctx = lua_touserdata(L,1);
|
||||
|
||||
lua_newtable(L);
|
||||
|
||||
struct func_list *func;
|
||||
char instance[256], pls[2048];
|
||||
struct packet_range *range;
|
||||
unsigned int n=1;
|
||||
LIST_FOREACH(func, &ctx->dp->lua_desync, next)
|
||||
{
|
||||
if (n > ctx->func_n)
|
||||
{
|
||||
desync_instance(func->func, ctx->dp->n, n, instance, sizeof(instance));
|
||||
range = ctx->incoming ? &func->range_in : &func->range_out;
|
||||
lua_pushinteger(params.L, n - ctx->func_n);
|
||||
lua_createtable(params.L, 0, 6);
|
||||
lua_pushf_args(&func->args, -1);
|
||||
lua_pushf_str("func", func->func);
|
||||
lua_pushf_int("func_n", ctx->func_n);
|
||||
lua_pushf_str("func_instance", instance);
|
||||
lua_pushf_range("range", range);
|
||||
if (l7_payload_str_list(func->payload_type, pls, sizeof(pls)))
|
||||
lua_pushf_str("payload_filter", pls);
|
||||
else
|
||||
lua_pushf_nil("payload_filter");
|
||||
|
||||
lua_rawset(params.L,-3);
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
LUA_STACK_GUARD_RETURN(L,1)
|
||||
}
|
||||
static int luacall_execution_plan_cancel(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"execution_plan_cancel",1);
|
||||
|
||||
t_lua_desync_context *ctx;
|
||||
|
||||
if (!lua_islightuserdata(L,1))
|
||||
luaL_error(L, "execution_plan_cancel expect desync context in the first argument");
|
||||
ctx = lua_touserdata(L,1);
|
||||
|
||||
DLOG("execution plan cancel from '%s'\n",ctx->instance);
|
||||
|
||||
ctx->cancel = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int luacall_raw_packet(lua_State *L)
|
||||
{
|
||||
lua_check_argc(L,"raw_packet",1);
|
||||
@@ -738,13 +908,25 @@ void lua_pushi_nil(lua_Integer idx)
|
||||
void lua_pushf_int(const char *field, lua_Integer v)
|
||||
{
|
||||
lua_pushstring(params.L, field);
|
||||
lua_pushinteger(params.L, v);
|
||||
lua_pushlint(params.L, v);
|
||||
lua_rawset(params.L,-3);
|
||||
}
|
||||
void lua_pushi_int(lua_Integer idx, lua_Integer v)
|
||||
{
|
||||
lua_pushinteger(params.L, idx);
|
||||
lua_pushinteger(params.L, v);
|
||||
lua_pushlint(params.L, v);
|
||||
lua_rawset(params.L,-3);
|
||||
}
|
||||
void lua_pushf_lint(const char *field, int64_t v)
|
||||
{
|
||||
lua_pushstring(params.L, field);
|
||||
lua_pushlint(params.L, v);
|
||||
lua_rawset(params.L,-3);
|
||||
}
|
||||
void lua_pushi_lint(lua_Integer idx, int64_t v)
|
||||
{
|
||||
lua_pushinteger(params.L, idx);
|
||||
lua_pushlint(params.L, v);
|
||||
lua_rawset(params.L,-3);
|
||||
}
|
||||
void lua_pushf_bool(const char *field, bool b)
|
||||
@@ -771,6 +953,18 @@ void lua_pushi_str(lua_Integer idx, const char *str)
|
||||
lua_pushstring(params.L, str); // pushes nil if str==NULL
|
||||
lua_rawset(params.L,-3);
|
||||
}
|
||||
void lua_pushf_lstr(const char *field, const char *str, size_t size)
|
||||
{
|
||||
lua_pushstring(params.L, field);
|
||||
lua_pushlstring(params.L, str, size);
|
||||
lua_rawset(params.L,-3);
|
||||
}
|
||||
void lua_pushi_lstr(lua_Integer idx, const char *str, size_t size)
|
||||
{
|
||||
lua_pushinteger(params.L, idx);
|
||||
lua_pushlstring(params.L, str, size);
|
||||
lua_rawset(params.L,-3);
|
||||
}
|
||||
void lua_push_raw(const void *v, size_t l)
|
||||
{
|
||||
if (v)
|
||||
@@ -889,8 +1083,8 @@ void lua_pushf_tcphdr(const struct tcphdr *tcp, size_t len)
|
||||
lua_createtable(params.L, 0, 11);
|
||||
lua_pushf_int("th_sport",ntohs(tcp->th_sport));
|
||||
lua_pushf_int("th_dport",ntohs(tcp->th_dport));
|
||||
lua_pushf_int("th_seq",ntohl(tcp->th_seq));
|
||||
lua_pushf_int("th_ack",ntohl(tcp->th_ack));
|
||||
lua_pushf_lint("th_seq",ntohl(tcp->th_seq));
|
||||
lua_pushf_lint("th_ack",ntohl(tcp->th_ack));
|
||||
lua_pushf_int("th_x2",tcp->th_x2);
|
||||
lua_pushf_int("th_off",tcp->th_off);
|
||||
lua_pushf_int("th_flags",tcp->th_flags);
|
||||
@@ -1025,8 +1219,8 @@ void lua_pushf_ip6hdr(const struct ip6_hdr *ip6, size_t len)
|
||||
if (ip6)
|
||||
{
|
||||
lua_createtable(params.L, 0, 7);
|
||||
lua_pushf_int("ip6_flow",ntohl(ip6->ip6_ctlun.ip6_un1.ip6_un1_flow));
|
||||
lua_pushf_int("ip6_plen",ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen));
|
||||
lua_pushf_lint("ip6_flow",ntohl(ip6->ip6_ctlun.ip6_un1.ip6_un1_flow));
|
||||
lua_pushf_lint("ip6_plen",ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen));
|
||||
lua_pushf_int("ip6_nxt",ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt);
|
||||
lua_pushf_int("ip6_hlim",ip6->ip6_ctlun.ip6_un1.ip6_un1_hlim);
|
||||
lua_pushf_raw("ip6_src",&ip6->ip6_src,sizeof(struct in6_addr));
|
||||
@@ -1066,21 +1260,23 @@ void lua_pushf_dissect(const struct dissect *dis)
|
||||
lua_rawset(params.L,-3);
|
||||
}
|
||||
|
||||
void lua_pushf_ctrack(const t_ctrack *ctrack)
|
||||
void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos)
|
||||
{
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
if (!pos) pos = &ctrack->pos;
|
||||
|
||||
lua_pushliteral(params.L, "track");
|
||||
if (ctrack)
|
||||
{
|
||||
lua_createtable(params.L, 0, 13 + (ctrack->ipproto == IPPROTO_TCP));
|
||||
|
||||
lua_pushf_int("pcounter_orig", ctrack->pcounter_orig);
|
||||
lua_pushf_int("pdcounter_orig", ctrack->pdcounter_orig);
|
||||
lua_pushf_int("pbcounter_orig", ctrack->pbcounter_orig);
|
||||
lua_pushf_int("pcounter_reply", ctrack->pcounter_reply);
|
||||
lua_pushf_int("pdcounter_reply", ctrack->pdcounter_reply);
|
||||
lua_pushf_int("pbcounter_reply", ctrack->pbcounter_reply);
|
||||
lua_pushf_lint("pcounter_orig", pos->pcounter_orig);
|
||||
lua_pushf_lint("pdcounter_orig", pos->pdcounter_orig);
|
||||
lua_pushf_lint("pbcounter_orig", pos->pbcounter_orig);
|
||||
lua_pushf_lint("pcounter_reply", pos->pcounter_reply);
|
||||
lua_pushf_lint("pdcounter_reply", pos->pdcounter_reply);
|
||||
lua_pushf_lint("pbcounter_reply", pos->pbcounter_reply);
|
||||
if (ctrack->incoming_ttl)
|
||||
lua_pushf_int("incoming_ttl", ctrack->incoming_ttl);
|
||||
else
|
||||
@@ -1095,21 +1291,25 @@ void lua_pushf_ctrack(const t_ctrack *ctrack)
|
||||
if (ctrack->ipproto == IPPROTO_TCP)
|
||||
{
|
||||
lua_pushliteral(params.L, "tcp");
|
||||
lua_createtable(params.L, 0, 14);
|
||||
lua_pushf_int("seq0", ctrack->seq0);
|
||||
lua_pushf_int("seq", ctrack->seq_last);
|
||||
lua_pushf_int("ack0", ctrack->ack0);
|
||||
lua_pushf_int("ack", ctrack->ack_last);
|
||||
lua_pushf_int("pos_orig", ctrack->pos_orig - ctrack->seq0);
|
||||
lua_pushf_int("winsize_orig", ctrack->winsize_orig);
|
||||
lua_pushf_int("winsize_orig_calc", ctrack->winsize_orig_calc);
|
||||
lua_pushf_int("scale_orig", ctrack->scale_orig);
|
||||
lua_pushf_int("mss_orig", ctrack->mss_orig);
|
||||
lua_pushf_int("pos_reply", ctrack->pos_reply - ctrack->ack0);
|
||||
lua_pushf_int("winsize_reply", ctrack->winsize_reply);
|
||||
lua_pushf_int("winsize_reply_calc", ctrack->winsize_reply_calc);
|
||||
lua_pushf_int("scale_reply", ctrack->scale_reply);
|
||||
lua_pushf_int("mss_reply", ctrack->mss_reply);
|
||||
lua_createtable(params.L, 0, 18);
|
||||
lua_pushf_lint("seq0", pos->seq0);
|
||||
lua_pushf_lint("seq", pos->seq_last);
|
||||
lua_pushf_lint("ack0", pos->ack0);
|
||||
lua_pushf_lint("ack", pos->ack_last);
|
||||
lua_pushf_int("pos_orig", pos->pos_orig - pos->seq0);
|
||||
lua_pushf_int("uppos_orig", pos->uppos_orig - pos->seq0);
|
||||
lua_pushf_int("uppos_orig_prev", pos->uppos_orig_prev - pos->seq0);
|
||||
lua_pushf_int("winsize_orig", pos->winsize_orig);
|
||||
lua_pushf_int("winsize_orig_calc", pos->winsize_orig_calc);
|
||||
lua_pushf_int("scale_orig", pos->scale_orig);
|
||||
lua_pushf_int("mss_orig", pos->mss_orig);
|
||||
lua_pushf_int("pos_reply", pos->pos_reply - pos->ack0);
|
||||
lua_pushf_int("uppos_reply", pos->uppos_reply - pos->ack0);
|
||||
lua_pushf_int("uppos_reply_prev", pos->uppos_reply_prev - pos->ack0);
|
||||
lua_pushf_int("winsize_reply", pos->winsize_reply);
|
||||
lua_pushf_int("winsize_reply_calc", pos->winsize_reply_calc);
|
||||
lua_pushf_int("scale_reply", pos->scale_reply);
|
||||
lua_pushf_int("mss_reply", pos->mss_reply);
|
||||
lua_rawset(params.L,-3);
|
||||
}
|
||||
}
|
||||
@@ -1120,7 +1320,7 @@ void lua_pushf_ctrack(const t_ctrack *ctrack)
|
||||
LUA_STACK_GUARD_LEAVE(params.L, 0)
|
||||
}
|
||||
|
||||
void lua_pushf_args(const struct ptr_list_head *args, int idx_desync)
|
||||
void lua_pushf_args(const struct str2_list_head *args, int idx_desync)
|
||||
{
|
||||
// var=val - pass val string
|
||||
// var=%val - subst 'val' blob
|
||||
@@ -1130,7 +1330,7 @@ void lua_pushf_args(const struct ptr_list_head *args, int idx_desync)
|
||||
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
struct ptr_list *arg;
|
||||
struct str2_list *arg;
|
||||
const char *var, *val;
|
||||
|
||||
idx_desync = lua_absindex(params.L, idx_desync);
|
||||
@@ -1139,8 +1339,8 @@ void lua_pushf_args(const struct ptr_list_head *args, int idx_desync)
|
||||
lua_newtable(params.L);
|
||||
LIST_FOREACH(arg, args, next)
|
||||
{
|
||||
var = (char*)arg->ptr1;
|
||||
val = arg->ptr2 ? (char*)arg->ptr2 : "";
|
||||
var = arg->str1;
|
||||
val = arg->str2 ? arg->str2 : "";
|
||||
if (val[0]=='\\' && (val[1]=='%' || val[1]=='#'))
|
||||
// escape char
|
||||
lua_pushf_str(var, val+1);
|
||||
@@ -1160,7 +1360,33 @@ void lua_pushf_args(const struct ptr_list_head *args, int idx_desync)
|
||||
|
||||
LUA_STACK_GUARD_LEAVE(params.L, 0)
|
||||
}
|
||||
void lua_pushf_pos(const char *name, const struct packet_pos *pos)
|
||||
{
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
char smode[2]="?";
|
||||
lua_pushf_table(name);
|
||||
lua_getfield(params.L,-1,name);
|
||||
*smode=pos->mode;
|
||||
lua_pushf_str("mode",smode);
|
||||
lua_pushf_lint("pos",pos->pos);
|
||||
lua_pop(params.L,1);
|
||||
|
||||
LUA_STACK_GUARD_LEAVE(params.L, 0)
|
||||
}
|
||||
void lua_pushf_range(const char *name, const struct packet_range *range)
|
||||
{
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
lua_pushf_table(name);
|
||||
lua_getfield(params.L,-1,"range");
|
||||
lua_pushf_bool("upper_cutoff",range->upper_cutoff);
|
||||
lua_pushf_pos("from", &range->from);
|
||||
lua_pushf_pos("to", &range->to);
|
||||
lua_pop(params.L,1);
|
||||
|
||||
LUA_STACK_GUARD_LEAVE(params.L, 0)
|
||||
}
|
||||
|
||||
|
||||
static void lua_reconstruct_extract_options(lua_State *L, int idx, bool *badsum, bool *ip6_preserve_next, uint8_t *ip6_last_proto)
|
||||
@@ -1277,7 +1503,7 @@ bool lua_reconstruct_ip6hdr(int idx, struct ip6_hdr *ip6, size_t *len, uint8_t l
|
||||
idx = lua_absindex(params.L, idx);
|
||||
|
||||
lua_getfield(params.L,idx,"ip6_flow");
|
||||
ip6->ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(lua_type(params.L,-1)==LUA_TNUMBER ? (uint32_t)lua_tointeger(params.L,-1) : 0x60000000);
|
||||
ip6->ip6_ctlun.ip6_un1.ip6_un1_flow = htonl(lua_type(params.L,-1)==LUA_TNUMBER ? (uint32_t)lua_tolint(params.L,-1) : 0x60000000);
|
||||
lua_pop(params.L, 1);
|
||||
|
||||
lua_getfield(params.L,idx,"ip6_plen");
|
||||
@@ -1537,12 +1763,12 @@ bool lua_reconstruct_tcphdr(int idx, struct tcphdr *tcp, size_t *len)
|
||||
|
||||
lua_getfield(params.L,idx,"th_seq");
|
||||
if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err;
|
||||
tcp->th_seq = htonl((uint32_t)lua_tointeger(params.L,-1));
|
||||
tcp->th_seq = htonl((uint32_t)lua_tolint(params.L,-1));
|
||||
lua_pop(params.L, 1);
|
||||
|
||||
lua_getfield(params.L,idx,"th_ack");
|
||||
if (lua_type(params.L,-1)!=LUA_TNUMBER) goto err;
|
||||
tcp->th_ack = htonl((uint32_t)lua_tointeger(params.L,-1));
|
||||
tcp->th_ack = htonl((uint32_t)lua_tolint(params.L,-1));
|
||||
lua_pop(params.L, 1);
|
||||
|
||||
lua_getfield(params.L,idx,"th_x2");
|
||||
@@ -2017,7 +2243,7 @@ static void lua_rawsend_extract_options(lua_State *L, int idx, int *repeats, uin
|
||||
if (fwmark)
|
||||
{
|
||||
lua_getfield(L,idx,"fwmark");
|
||||
*fwmark=(uint32_t)lua_tointeger(L,-1) | params.desync_fwmark;
|
||||
*fwmark=(uint32_t)lua_tolint(L,-1) | params.desync_fwmark;
|
||||
lua_pop(L,1);
|
||||
}
|
||||
if (ifout)
|
||||
@@ -2663,6 +2889,21 @@ static void lua_init_const(void)
|
||||
{
|
||||
LUA_STACK_GUARD_ENTER(params.L)
|
||||
|
||||
const struct
|
||||
{
|
||||
const char *name, *v;
|
||||
} cstr[] = {
|
||||
{"NFQWS2_VER",params.verstr}
|
||||
};
|
||||
|
||||
DLOG("LUA STR:");
|
||||
for (int i=0;i<sizeof(cstr)/sizeof(*cstr);i++)
|
||||
{
|
||||
lua_pushstring(params.L, cstr[i].v);
|
||||
lua_setglobal(params.L, cstr[i].name);
|
||||
DLOG(" %s", cstr[i].name);
|
||||
}
|
||||
|
||||
const struct
|
||||
{
|
||||
const char *name;
|
||||
@@ -2674,6 +2915,7 @@ static void lua_init_const(void)
|
||||
{"divert_port",params.port},
|
||||
#endif
|
||||
{"desync_fwmark",params.desync_fwmark},
|
||||
{"NFQWS2_COMPAT_VER",LUA_COMPAT_VER},
|
||||
|
||||
{"VERDICT_PASS",VERDICT_PASS},
|
||||
{"VERDICT_MODIFY",VERDICT_MODIFY},
|
||||
@@ -2735,7 +2977,7 @@ static void lua_init_const(void)
|
||||
{"IPPROTO_SHIM6",IPPROTO_SHIM6},
|
||||
{"IPPROTO_NONE",IPPROTO_NONE}
|
||||
};
|
||||
DLOG("LUA NUMERIC:");
|
||||
DLOG("\nLUA NUMERIC:");
|
||||
for (int i=0;i<sizeof(cuint)/sizeof(*cuint);i++)
|
||||
{
|
||||
lua_pushinteger(params.L, (lua_Integer)cuint[i].v);
|
||||
@@ -2803,6 +3045,11 @@ static void lua_init_functions(void)
|
||||
{"u16",luacall_u16},
|
||||
{"u24",luacall_u24},
|
||||
{"u32",luacall_u32},
|
||||
// add any number of arguments as they would be unsigned int of specific size
|
||||
{"u8add",luacall_u8add},
|
||||
{"u16add",luacall_u16add},
|
||||
{"u24add",luacall_u24add},
|
||||
{"u32add",luacall_u32add},
|
||||
// convert number to blob (string) - big endian
|
||||
{"bu8",luacall_bu8},
|
||||
{"bu16",luacall_bu16},
|
||||
@@ -2836,6 +3083,12 @@ static void lua_init_functions(void)
|
||||
|
||||
// voluntarily stop receiving packets
|
||||
{"instance_cutoff",luacall_instance_cutoff},
|
||||
// voluntarily stop receiving packets of the current connection for all instances
|
||||
{"lua_cutoff",luacall_lua_cutoff},
|
||||
// get info about upcoming desync instances and their arguments
|
||||
{"execution_plan",luacall_execution_plan},
|
||||
// cancel execution of upcoming desync instances and their arguments
|
||||
{"execution_plan_cancel",luacall_execution_plan_cancel},
|
||||
// get raw packet data
|
||||
{"raw_packet",luacall_raw_packet},
|
||||
|
||||
|
||||
28
nfq2/lua.h
28
nfq2/lua.h
@@ -22,12 +22,26 @@
|
||||
#define LUA_UNSIGNED uint64_t
|
||||
#endif
|
||||
|
||||
// in old lua integer is 32 bit on 32 bit platforms and 64 bit on 64 bit platforms
|
||||
#if LUA_VERSION_NUM < 503 && __SIZEOF_POINTER__==4
|
||||
#define lua_pushlint lua_pushnumber
|
||||
#define lua_tolint lua_tonumber
|
||||
#define luaL_checklint luaL_checknumber
|
||||
#else
|
||||
#define lua_pushlint lua_pushinteger
|
||||
#define luaL_checklint luaL_checkinteger
|
||||
#define lua_tolint lua_tointeger
|
||||
#endif
|
||||
|
||||
// pushing and not popping inside luacall cause memory leak
|
||||
#define LUA_STACK_GUARD_ENTER(L) int _lsg=lua_gettop(L);
|
||||
#define LUA_STACK_GUARD_LEAVE(L,N) if ((_lsg+N)!=lua_gettop(L)) luaL_error(L,"stack guard failure");
|
||||
#define LUA_STACK_GUARD_RETURN(L,N) LUA_STACK_GUARD_LEAVE(L,N); return N;
|
||||
|
||||
|
||||
void desync_instance(const char *func, unsigned int dp_n, unsigned int func_n, char *instance, size_t inst_size);
|
||||
|
||||
|
||||
bool lua_test_init_script_files(void);
|
||||
bool lua_init(void);
|
||||
void lua_shutdown(void);
|
||||
@@ -48,8 +62,12 @@ void lua_pushf_bool(const char *field, bool b);
|
||||
void lua_pushi_bool(lua_Integer idx, bool b);
|
||||
void lua_pushf_str(const char *field, const char *str);
|
||||
void lua_pushi_str(lua_Integer idx, const char *str);
|
||||
void lua_pushf_lstr(const char *field, const char *str, size_t len);
|
||||
void lua_pushi_lstr(lua_Integer idx, const char *str, size_t len);
|
||||
void lua_pushf_int(const char *field, lua_Integer v);
|
||||
void lua_pushi_int(lua_Integer idx, lua_Integer v);
|
||||
void lua_pushf_lint(const char *field, int64_t v);
|
||||
void lua_pushi_lint(lua_Integer idx, int64_t v);
|
||||
void lua_push_raw(const void *v, size_t l);
|
||||
void lua_pushf_raw(const char *field, const void *v, size_t l);
|
||||
void lua_pushi_raw(lua_Integer idx, const void *v, size_t l);
|
||||
@@ -68,8 +86,10 @@ void lua_pushf_iphdr(const struct ip *ip, size_t len);
|
||||
void lua_pushf_ip6hdr(const struct ip6_hdr *ip6, size_t len);
|
||||
void lua_push_dissect(const struct dissect *dis);
|
||||
void lua_pushf_dissect(const struct dissect *dis);
|
||||
void lua_pushf_ctrack(const t_ctrack *ctrack);
|
||||
void lua_pushf_args(const struct ptr_list_head *args, int idx_desync);
|
||||
void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos);
|
||||
void lua_pushf_args(const struct str2_list_head *args, int idx_desync);
|
||||
void lua_pushf_pos(const char *name, const struct packet_pos *pos);
|
||||
void lua_pushf_range(const char *name, const struct packet_range *range);
|
||||
void lua_pushf_global(const char *field, const char *global);
|
||||
|
||||
bool lua_reconstruct_ip6hdr(int idx, struct ip6_hdr *ip6, size_t *len, uint8_t last_proto, bool preserve_next);
|
||||
@@ -79,10 +99,12 @@ bool lua_reconstruct_udphdr(int idx, struct udphdr *udp);
|
||||
bool lua_reconstruct_dissect(int idx, uint8_t *buf, size_t *len, bool badsum, bool ip6_preserve_next);
|
||||
|
||||
typedef struct {
|
||||
unsigned int func_n;
|
||||
const char *func, *instance;
|
||||
const struct desync_profile *dp;
|
||||
const t_ctrack *ctrack;
|
||||
const struct dissect *dis;
|
||||
t_ctrack *ctrack;
|
||||
bool incoming,cancel;
|
||||
} t_lua_desync_context;
|
||||
|
||||
bool lua_instance_cutoff_check(const t_lua_desync_context *ctx, bool bIn);
|
||||
|
||||
259
nfq2/nfqws.c
259
nfq2/nfqws.c
@@ -48,11 +48,6 @@
|
||||
#define NF_ACCEPT 1
|
||||
#endif
|
||||
|
||||
#define CTRACK_T_SYN 60
|
||||
#define CTRACK_T_FIN 60
|
||||
#define CTRACK_T_EST 300
|
||||
#define CTRACK_T_UDP 60
|
||||
|
||||
#define MAX_CONFIG_FILE_SIZE 16384
|
||||
|
||||
struct params_s params;
|
||||
@@ -99,7 +94,7 @@ static void onusr2(int sig)
|
||||
struct desync_profile_list *dpl;
|
||||
LIST_FOREACH(dpl, ¶ms.desync_profiles, next)
|
||||
{
|
||||
printf("\nDESYNC profile %u\n", dpl->dp.n);
|
||||
printf("\nDESYNC profile %u (%s)\n", dpl->dp.n, PROFILE_NAME(&dpl->dp));
|
||||
HostFailPoolDump(dpl->dp.hostlist_auto_fail_counters);
|
||||
}
|
||||
printf("\nIPCACHE\n");
|
||||
@@ -1007,27 +1002,28 @@ static bool parse_pf_list(char *opt, struct port_filters_head *pfl)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool lua_call_param_add(char *opt, struct ptr_list_head *args)
|
||||
bool lua_call_param_add(char *opt, struct str2_list_head *args)
|
||||
{
|
||||
char c,*p;
|
||||
struct ptr_list *arg;
|
||||
struct str2_list *arg;
|
||||
|
||||
if ((p = strchr(opt,'=')))
|
||||
{
|
||||
c = *p; *p = 0;
|
||||
}
|
||||
if (!is_identifier(opt) || !(arg=ptrlist_add(args)))
|
||||
if (!is_identifier(opt) || !(arg=str2list_add(args)))
|
||||
{
|
||||
if (p) *p = c;
|
||||
return false;
|
||||
}
|
||||
arg->ptr1 = strdup(opt);
|
||||
arg->str1 = strdup(opt);
|
||||
if (p)
|
||||
{
|
||||
arg->ptr2 = strdup(p+1);
|
||||
arg->str2 = strdup(p+1);
|
||||
*p = c;
|
||||
if (!arg->str2) return false;
|
||||
}
|
||||
return arg->ptr1;
|
||||
return !!arg->str1;
|
||||
}
|
||||
|
||||
struct func_list *parse_lua_call(char *opt, struct func_list_head *flist)
|
||||
@@ -1053,7 +1049,6 @@ struct func_list *parse_lua_call(char *opt, struct func_list_head *flist)
|
||||
last = !*e;
|
||||
c = *e;
|
||||
*e = 0;
|
||||
|
||||
b = lua_call_param_add(p, &f->args);
|
||||
if (!last) *e++ = c;
|
||||
if (!b) goto err;
|
||||
@@ -1156,21 +1151,21 @@ static void BlobDebug()
|
||||
}
|
||||
}
|
||||
|
||||
static void LuaDesyncDebug(struct desync_profile *dp)
|
||||
static void LuaDesyncDebug(struct desync_profile *dp, const char *entity)
|
||||
{
|
||||
if (params.debug)
|
||||
{
|
||||
struct func_list *func;
|
||||
struct ptr_list *arg;
|
||||
struct str2_list *arg;
|
||||
int n,i;
|
||||
LIST_FOREACH(func, &dp->lua_desync, next)
|
||||
{
|
||||
DLOG("profile %u lua %s(",dp->n,func->func);
|
||||
DLOG("%s %u (%s) lua %s(",entity,dp->n,PROFILE_NAME(dp),func->func);
|
||||
n=0;
|
||||
LIST_FOREACH(arg, &func->args, next)
|
||||
{
|
||||
if (n) DLOG(",");
|
||||
DLOG(arg->ptr2 ? "%s=\"%s\"" : "%s=\"\"", (char*)arg->ptr1, (char*)arg->ptr2);
|
||||
DLOG(arg->str2 ? "%s=\"%s\"" : "%s=\"\"", arg->str1, arg->str2);
|
||||
n++;
|
||||
}
|
||||
DLOG(" range_in=%c%u%c%c%u range_out=%c%u%c%c%u payload_type=",
|
||||
@@ -1288,8 +1283,10 @@ static bool wf_make_filter(
|
||||
|
||||
if (bHaveTCP)
|
||||
{
|
||||
if (dp_list_have_autohostlist(¶ms.desync_profiles))
|
||||
snprintf(wf + strlen(wf), len - strlen(wf), " or\n " DIVERT_HTTP_REDIRECT);
|
||||
// may be required by orchestrators - always redirect
|
||||
// if (dp_list_have_autohostlist(¶ms.desync_profiles))
|
||||
|
||||
snprintf(wf + strlen(wf), len - strlen(wf), " or\n " DIVERT_HTTP_REDIRECT);
|
||||
}
|
||||
|
||||
if (!LIST_EMPTY(wf_raw_part))
|
||||
@@ -1412,8 +1409,12 @@ static void exithelp(void)
|
||||
" --lua-init=@<filename>|<lua_text>\t\t\t; load LUA program from a file or string. if multiple parameters present order of execution is preserved.\n"
|
||||
" --lua-gc=<int>\t\t\t\t\t\t; forced garbage collection every N sec. default %u sec. triggers only when a packet arrives. 0 = disable.\n"
|
||||
"\nMULTI-STRATEGY:\n"
|
||||
" --new\t\t\t\t\t\t\t; begin new strategy\n"
|
||||
" --skip\t\t\t\t\t\t\t; do not use this strategy\n"
|
||||
" --new\t\t\t\t\t\t\t; begin new profile\n"
|
||||
" --skip\t\t\t\t\t\t\t; do not use this profile\n"
|
||||
" --name=<name>\t\t\t\t\t\t; set profile name\n"
|
||||
" --template[=<name>]\t\t\t\t\t; use this profile as template (must be named or will be useless)\n"
|
||||
" --cookie[=<string>]\t\t\t\t\t; pass this profile-bound string to LUA\n"
|
||||
" --import=<name>\t\t\t\t\t; populate current profile with template data\n"
|
||||
" --filter-l3=ipv4|ipv6\t\t\t\t\t; L3 protocol filter. multiple comma separated values allowed.\n"
|
||||
" --filter-tcp=[~]port1[-port2]|*\t\t\t; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list allowed.\n"
|
||||
" --filter-udp=[~]port1[-port2]|*\t\t\t; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list allowed.\n"
|
||||
@@ -1433,6 +1434,7 @@ static void exithelp(void)
|
||||
" --hostlist-auto-fail-threshold=<int>\t\t\t; how many failed attempts cause hostname to be added to auto hostlist (default : %d)\n"
|
||||
" --hostlist-auto-fail-time=<int>\t\t\t; all failed attemps must be within these seconds (default : %d)\n"
|
||||
" --hostlist-auto-retrans-threshold=<int>\t\t; how many request retransmissions cause attempt to fail (default : %d)\n"
|
||||
" --hostlist-auto-retrans-maxseq=<int>\t\t\t; count retransmissions only within this relative sequence (default : %u)\n"
|
||||
" --hostlist-auto-debug=<logfile>\t\t\t; debug auto hostlist positives (global parameter)\n"
|
||||
"\nLUA PACKET PASS MODE:\n"
|
||||
" --payload=type[,type]\t\t\t\t\t; set payload types following LUA functions should process : %s\n"
|
||||
@@ -1447,7 +1449,8 @@ static void exithelp(void)
|
||||
IPCACHE_LIFETIME,
|
||||
LUA_GC_INTERVAL,
|
||||
all_protos,
|
||||
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT, HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT,
|
||||
HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT, HOSTLIST_AUTO_FAIL_TIME_DEFAULT,
|
||||
HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT, HOSTLIST_AUTO_RETRANS_MAXSEQ,
|
||||
all_payloads
|
||||
);
|
||||
exit(1);
|
||||
@@ -1500,22 +1503,6 @@ static void ApplyDefaultBlobs(struct blob_collection_head *blobs)
|
||||
load_const_blob_to_collection("fake_default_quic",buf,620,blobs,0);
|
||||
}
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
|
||||
#ifdef __ANDROID__
|
||||
#define PRINT_VER printf("github android version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
|
||||
#else
|
||||
#define PRINT_VER printf("github version %s (%s)\n\n", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH))
|
||||
#endif
|
||||
#else
|
||||
#ifdef __ANDROID__
|
||||
#define PRINT_VER printf("self-built android version %s %s\n\n", __DATE__, __TIME__)
|
||||
#else
|
||||
#define PRINT_VER printf("self-built version %s %s\n\n", __DATE__, __TIME__)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
enum opt_indices {
|
||||
IDX_DEBUG,
|
||||
IDX_DRY_RUN,
|
||||
@@ -1560,9 +1547,14 @@ enum opt_indices {
|
||||
IDX_HOSTLIST_AUTO_FAIL_THRESHOLD,
|
||||
IDX_HOSTLIST_AUTO_FAIL_TIME,
|
||||
IDX_HOSTLIST_AUTO_RETRANS_THRESHOLD,
|
||||
IDX_HOSTLIST_AUTO_RETRANS_MAXSEQ,
|
||||
IDX_HOSTLIST_AUTO_DEBUG,
|
||||
IDX_NEW,
|
||||
IDX_SKIP,
|
||||
IDX_NAME,
|
||||
IDX_TEMPLATE,
|
||||
IDX_IMPORT,
|
||||
IDX_COOKIE,
|
||||
IDX_FILTER_L3,
|
||||
IDX_FILTER_TCP,
|
||||
IDX_FILTER_UDP,
|
||||
@@ -1640,9 +1632,14 @@ static const struct option long_options[] = {
|
||||
[IDX_HOSTLIST_AUTO_FAIL_THRESHOLD] = {"hostlist-auto-fail-threshold", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_AUTO_FAIL_TIME] = {"hostlist-auto-fail-time", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_AUTO_RETRANS_THRESHOLD] = {"hostlist-auto-retrans-threshold", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_AUTO_RETRANS_MAXSEQ] = {"hostlist-auto-retrans-maxseq", required_argument, 0, 0},
|
||||
[IDX_HOSTLIST_AUTO_DEBUG] = {"hostlist-auto-debug", required_argument, 0, 0},
|
||||
[IDX_NEW] = {"new", no_argument, 0, 0},
|
||||
[IDX_SKIP] = {"skip", no_argument, 0, 0},
|
||||
[IDX_NAME] = {"name", required_argument, 0, 0},
|
||||
[IDX_TEMPLATE] = {"template", optional_argument, 0, 0},
|
||||
[IDX_IMPORT] = {"import", required_argument, 0, 0},
|
||||
[IDX_COOKIE] = {"cookie", required_argument, 0, 0},
|
||||
[IDX_FILTER_L3] = {"filter-l3", required_argument, 0, 0},
|
||||
[IDX_FILTER_TCP] = {"filter-tcp", required_argument, 0, 0},
|
||||
[IDX_FILTER_UDP] = {"filter-udp", required_argument, 0, 0},
|
||||
@@ -1679,16 +1676,42 @@ static const struct option long_options[] = {
|
||||
[IDX_LAST] = {NULL, 0, NULL, 0},
|
||||
};
|
||||
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
#if defined(ZAPRET_GH_VER) || defined (ZAPRET_GH_HASH)
|
||||
#ifdef __ANDROID__
|
||||
#define MAKE_VER(s,size) snprintf(s,size,"github android version %s (%s) lua_compat_ver %u", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH), LUA_COMPAT_VER)
|
||||
#else
|
||||
#define MAKE_VER(s,size) snprintf(s,size,"github version %s (%s) lua_compat_ver %u", TOSTRING(ZAPRET_GH_VER), TOSTRING(ZAPRET_GH_HASH), LUA_COMPAT_VER)
|
||||
#endif
|
||||
#else
|
||||
#ifdef __ANDROID__
|
||||
#define MAKE_VER(s,size) snprintf(s,size,"self-built android version %s %s lua_compat_ver %u", __DATE__, __TIME__, LUA_COMPAT_VER)
|
||||
#else
|
||||
#define MAKE_VER(s,size) snprintf(s,size,"self-built version %s %s lua_compat_ver %u", __DATE__, __TIME__, LUA_COMPAT_VER)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
if (argc < 2) exithelp();
|
||||
|
||||
aes_init_keygen_tables(); // required for aes
|
||||
set_console_io_buffering();
|
||||
set_env_exedir(argv[0]);
|
||||
/*
|
||||
t_reassemble t;
|
||||
ReasmInit(&t,16,-10);
|
||||
memset(t.packet,0,16);
|
||||
bool b;
|
||||
b=ReasmFeed(&t,-10,"0123456789",10);
|
||||
printf("b=%u size=%zu seq=%d s=%s\n",b,t.size_present,t.seq,t.packet);
|
||||
b=ReasmFeed(&t,0,"YOREK",5);
|
||||
printf("b=%u size=%zu seq=%d s=%s\n",b,t.size_present,t.seq,t.packet);
|
||||
b=ReasmFeed(&t,-12,"XOR",3);
|
||||
printf("b=%u size=%zu seq=%d s=%s\n",b,t.size_present,t.seq,t.packet);
|
||||
b=ReasmFeed(&t,3,"abc",3);
|
||||
printf("b=%u size=%zu seq=%d s=%s\n",b,t.size_present,t.seq,t.packet);
|
||||
return 0;
|
||||
*/
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
prepare_low_appdata();
|
||||
if (service_run(argc, argv))
|
||||
{
|
||||
// we were running as service. now exit.
|
||||
@@ -1697,7 +1720,7 @@ int main(int argc, char **argv)
|
||||
#endif
|
||||
int result, v;
|
||||
int option_index = 0;
|
||||
bool bSkip = false, bDry = false;
|
||||
bool bSkip = false, bDry = false, bTemplate;
|
||||
struct hostlist_file *anon_hl = NULL, *anon_hl_exclude = NULL;
|
||||
struct ipset_file *anon_ips = NULL, *anon_ips_exclude = NULL;
|
||||
uint64_t payload_type=0;
|
||||
@@ -1709,17 +1732,29 @@ int main(int argc, char **argv)
|
||||
unsigned int hash_wf_tcp_in = 0, hash_wf_udp_in = 0, hash_wf_tcp_out = 0, hash_wf_udp_out = 0, hash_wf_raw = 0, hash_wf_raw_part = 0, hash_ssid_filter = 0, hash_nlm_filter = 0;
|
||||
#endif
|
||||
|
||||
if (argc < 2) exithelp();
|
||||
|
||||
srandom(time(NULL));
|
||||
aes_init_keygen_tables(); // required for aes
|
||||
mask_from_preflen6_prepare();
|
||||
set_env_exedir(argv[0]);
|
||||
set_console_io_buffering();
|
||||
#ifdef __CYGWIN__
|
||||
prepare_low_appdata();
|
||||
#endif
|
||||
|
||||
PRINT_VER;
|
||||
init_params(¶ms);
|
||||
|
||||
memset(¶ms, 0, sizeof(params));
|
||||
MAKE_VER(params.verstr, sizeof(params.verstr));
|
||||
printf("%s\n\n",params.verstr);
|
||||
|
||||
ApplyDefaultBlobs(¶ms.blobs);
|
||||
|
||||
struct desync_profile_list *dpl;
|
||||
struct desync_profile *dp;
|
||||
unsigned int desync_profile_count = 0;
|
||||
unsigned int desync_profile_count = 0, desync_template_count = 0;
|
||||
|
||||
bTemplate = false;
|
||||
if (!(dpl = dp_list_add(¶ms.desync_profiles)))
|
||||
{
|
||||
DLOG_ERR("desync_profile_add: out of memory\n");
|
||||
@@ -1728,39 +1763,6 @@ int main(int argc, char **argv)
|
||||
dp = &dpl->dp;
|
||||
dp->n = ++desync_profile_count;
|
||||
|
||||
#ifdef __linux__
|
||||
params.qnum = -1;
|
||||
#elif defined(BSD)
|
||||
params.port = 0;
|
||||
#endif
|
||||
params.desync_fwmark = DPI_DESYNC_FWMARK_DEFAULT;
|
||||
params.ctrack_t_syn = CTRACK_T_SYN;
|
||||
params.ctrack_t_est = CTRACK_T_EST;
|
||||
params.ctrack_t_fin = CTRACK_T_FIN;
|
||||
params.ctrack_t_udp = CTRACK_T_UDP;
|
||||
params.ipcache_lifetime = IPCACHE_LIFETIME;
|
||||
params.lua_gc = LUA_GC_INTERVAL;
|
||||
|
||||
LIST_INIT(¶ms.hostlists);
|
||||
LIST_INIT(¶ms.ipsets);
|
||||
LIST_INIT(¶ms.blobs);
|
||||
LIST_INIT(¶ms.lua_init_scripts);
|
||||
|
||||
ApplyDefaultBlobs(¶ms.blobs);
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
LIST_INIT(¶ms.ssid_filter);
|
||||
LIST_INIT(¶ms.nlm_filter);
|
||||
LIST_INIT(¶ms.wf_raw_part);
|
||||
#else
|
||||
if (can_drop_root())
|
||||
{
|
||||
params.uid = params.gid[0] = 0x7FFFFFFF; // default uid:gid
|
||||
params.gid_count = 1;
|
||||
params.droproot = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
if (argc >= 2 && (argv[1][0] == '@' || argv[1][0] == '$'))
|
||||
{
|
||||
@@ -2095,6 +2097,9 @@ int main(int argc, char **argv)
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case IDX_HOSTLIST_AUTO_RETRANS_MAXSEQ:
|
||||
dp->hostlist_auto_retrans_maxseq = (uint32_t)atoi(optarg);
|
||||
break;
|
||||
case IDX_HOSTLIST_AUTO_DEBUG:
|
||||
{
|
||||
FILE *F = fopen(optarg, "a+t");
|
||||
@@ -2120,23 +2125,83 @@ int main(int argc, char **argv)
|
||||
else
|
||||
{
|
||||
check_dp(dp);
|
||||
if (bTemplate)
|
||||
{
|
||||
if (dp->name && dp_list_search_name(¶ms.desync_templates, dp->name))
|
||||
{
|
||||
DLOG_ERR("template '%s' already present\n", dp->name);
|
||||
exit_clean(1);
|
||||
}
|
||||
dpl->dp.n = ++desync_template_count;
|
||||
dp_list_move(¶ms.desync_templates, dpl);
|
||||
}
|
||||
else
|
||||
{
|
||||
desync_profile_count++;
|
||||
}
|
||||
if (!(dpl = dp_list_add(¶ms.desync_profiles)))
|
||||
{
|
||||
DLOG_ERR("desync_profile_add: out of memory\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
dp = &dpl->dp;
|
||||
dp->n = ++desync_profile_count;
|
||||
dp->n = desync_profile_count;
|
||||
}
|
||||
anon_hl = anon_hl_exclude = NULL;
|
||||
anon_ips = anon_ips_exclude = NULL;
|
||||
payload_type = 0;
|
||||
range_in = PACKET_RANGE_NEVER;
|
||||
range_out = PACKET_RANGE_ALWAYS;
|
||||
|
||||
bTemplate = false;
|
||||
break;
|
||||
case IDX_SKIP:
|
||||
bSkip = true;
|
||||
break;
|
||||
case IDX_TEMPLATE:
|
||||
bTemplate = true;
|
||||
case IDX_NAME:
|
||||
if (optarg)
|
||||
{
|
||||
free(dp->name);
|
||||
if (!(dp->name = strdup(optarg)))
|
||||
{
|
||||
DLOG_ERR("out of memory\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case IDX_COOKIE:
|
||||
free(dp->cookie);
|
||||
if (!(dp->cookie = strdup(optarg)))
|
||||
{
|
||||
DLOG_ERR("out of memory\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
break;
|
||||
case IDX_IMPORT:
|
||||
{
|
||||
struct desync_profile_list *tpl = dp_list_search_name(¶ms.desync_templates, optarg);
|
||||
if (!tpl)
|
||||
{
|
||||
DLOG_ERR("template '%s' not found\n", optarg);
|
||||
exit_clean(1);
|
||||
}
|
||||
if (!dp_list_copy(dp, &tpl->dp))
|
||||
{
|
||||
DLOG_ERR("could not copy template\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
dp->n = desync_profile_count;
|
||||
free(dp->name_tpl);
|
||||
if (tpl->dp.name && !(dp->name_tpl = strdup(tpl->dp.name)))
|
||||
{
|
||||
DLOG_ERR("out of memory\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
dp->n_tpl = tpl->dp.n;
|
||||
}
|
||||
break;
|
||||
|
||||
case IDX_FILTER_L3:
|
||||
if (!wf_make_l3(optarg, &dp->filter_ipv4, &dp->filter_ipv6))
|
||||
@@ -2399,7 +2464,20 @@ int main(int argc, char **argv)
|
||||
desync_profile_count--;
|
||||
}
|
||||
else
|
||||
{
|
||||
check_dp(dp);
|
||||
if (bTemplate)
|
||||
{
|
||||
if (dp->name && dp_list_search_name(¶ms.desync_templates, dp->name))
|
||||
{
|
||||
DLOG_ERR("template '%s' already present\n", dp->name);
|
||||
exit_clean(1);
|
||||
}
|
||||
dpl->dp.n = ++desync_template_count;
|
||||
dp_list_move(¶ms.desync_templates, dpl);
|
||||
desync_profile_count--;
|
||||
}
|
||||
}
|
||||
|
||||
// do not need args from file anymore
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
@@ -2423,13 +2501,14 @@ int main(int argc, char **argv)
|
||||
|
||||
DLOG("adding low-priority default empty desync profile\n");
|
||||
// add default empty profile
|
||||
if (!(dpl = dp_list_add(¶ms.desync_profiles)))
|
||||
if (!(dpl = dp_list_add(¶ms.desync_profiles)) || !(dpl->dp.name=strdup("no_action")))
|
||||
{
|
||||
DLOG_ERR("desync_profile_add: out of memory\n");
|
||||
exit_clean(1);
|
||||
}
|
||||
|
||||
DLOG_CONDUP("we have %d user defined desync profile(s) and default low priority profile 0\n", desync_profile_count);
|
||||
DLOG_CONDUP("we have %u user defined desync profile(s) and default low priority profile 0\n", desync_profile_count);
|
||||
DLOG_CONDUP("we have %u user defined desync template(s)\n", desync_template_count);
|
||||
|
||||
if (params.writeable_dir_enable)
|
||||
{
|
||||
@@ -2463,11 +2542,16 @@ int main(int argc, char **argv)
|
||||
if (params.droproot)
|
||||
#endif
|
||||
{
|
||||
if (dp->hostlist_auto && ensure_file_access(dp->hostlist_auto->filename))
|
||||
if (dp->hostlist_auto && !ensure_file_access(dp->hostlist_auto->filename))
|
||||
DLOG_ERR("could not make '%s' accessible. auto hostlist file may not be writable after privilege drop\n", dp->hostlist_auto->filename);
|
||||
|
||||
}
|
||||
LuaDesyncDebug(dp);
|
||||
LuaDesyncDebug(dp,"profile");
|
||||
}
|
||||
LIST_FOREACH(dpl, ¶ms.desync_templates, next)
|
||||
{
|
||||
dp = &dpl->dp;
|
||||
LuaDesyncDebug(dp,"template");
|
||||
}
|
||||
|
||||
if (!test_list_files())
|
||||
@@ -2493,6 +2577,9 @@ int main(int argc, char **argv)
|
||||
BlobDebug();
|
||||
DLOG("\n");
|
||||
|
||||
// not required anymore. free memory
|
||||
dp_list_destroy(¶ms.desync_templates);
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
if (!*params.windivert_filter)
|
||||
{
|
||||
|
||||
@@ -10,3 +10,6 @@
|
||||
extern bool bQuit;
|
||||
#endif
|
||||
int main(int argc, char *argv[]);
|
||||
|
||||
// when something changes that can break LUA compatibility this version should be increased
|
||||
#define LUA_COMPAT_VER 2
|
||||
|
||||
@@ -26,7 +26,7 @@ void rawpacket_queue_destroy(struct rawpacket_tailhead *q)
|
||||
while((rp = rawpacket_dequeue(q))) rawpacket_free(rp);
|
||||
}
|
||||
|
||||
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload)
|
||||
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload,const t_ctrack_position *pos)
|
||||
{
|
||||
struct rawpacket *rp = malloc(sizeof(struct rawpacket));
|
||||
if (!rp) return NULL;
|
||||
@@ -52,6 +52,15 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
|
||||
memcpy(rp->packet,data,len);
|
||||
rp->len=len;
|
||||
rp->len_payload=len_payload;
|
||||
|
||||
// make a copy for replay
|
||||
if (pos)
|
||||
{
|
||||
rp->pos = *pos;
|
||||
rp->pos_present = true;
|
||||
}
|
||||
else
|
||||
rp->pos_present = false;
|
||||
|
||||
TAILQ_INSERT_TAIL(q, rp, next);
|
||||
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
#include <net/if.h>
|
||||
#include <sys/socket.h>
|
||||
|
||||
#include "conntrack_base.h"
|
||||
|
||||
struct rawpacket
|
||||
{
|
||||
struct sockaddr_storage dst;
|
||||
@@ -14,6 +16,8 @@ struct rawpacket
|
||||
uint32_t fwmark;
|
||||
size_t len, len_payload;
|
||||
uint8_t *packet;
|
||||
t_ctrack_position pos;
|
||||
bool pos_present;
|
||||
TAILQ_ENTRY(rawpacket) next;
|
||||
};
|
||||
TAILQ_HEAD(rawpacket_tailhead, rawpacket);
|
||||
@@ -22,6 +26,6 @@ void rawpacket_queue_init(struct rawpacket_tailhead *q);
|
||||
void rawpacket_queue_destroy(struct rawpacket_tailhead *q);
|
||||
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q);
|
||||
unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q);
|
||||
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload);
|
||||
struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sockaddr_storage* dst,uint32_t fwmark_orig,uint32_t fwmark,const char *ifin,const char *ifout,const void *data,size_t len,size_t len_payload,const t_ctrack_position *pos);
|
||||
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q);
|
||||
void rawpacket_free(struct rawpacket *rp);
|
||||
|
||||
132
nfq2/params.c
132
nfq2/params.c
@@ -322,7 +322,7 @@ void hexdump_limited_dlog(const uint8_t *data, size_t size, size_t limit)
|
||||
}
|
||||
}
|
||||
|
||||
void dp_init(struct desync_profile *dp)
|
||||
void dp_init_dynamic(struct desync_profile *dp)
|
||||
{
|
||||
LIST_INIT(&dp->hl_collection);
|
||||
LIST_INIT(&dp->hl_collection_exclude);
|
||||
@@ -331,33 +331,26 @@ void dp_init(struct desync_profile *dp)
|
||||
LIST_INIT(&dp->pf_tcp);
|
||||
LIST_INIT(&dp->pf_udp);
|
||||
LIST_INIT(&dp->lua_desync);
|
||||
#ifdef HAS_FILTER_SSID
|
||||
LIST_INIT(&dp->filter_ssid);
|
||||
#endif
|
||||
}
|
||||
void dp_init(struct desync_profile *dp)
|
||||
{
|
||||
dp_init_dynamic(dp);
|
||||
|
||||
dp->hostlist_auto_fail_threshold = HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT;
|
||||
dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
|
||||
dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
|
||||
dp->hostlist_auto_retrans_maxseq = HOSTLIST_AUTO_RETRANS_MAXSEQ;
|
||||
dp->filter_ipv4 = dp->filter_ipv6 = true;
|
||||
}
|
||||
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
|
||||
{
|
||||
struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
|
||||
if (!entry) return NULL;
|
||||
|
||||
dp_init(&entry->dp);
|
||||
|
||||
// add to the tail
|
||||
struct desync_profile_list *dpn,*dpl=LIST_FIRST(¶ms.desync_profiles);
|
||||
if (dpl)
|
||||
{
|
||||
while ((dpn=LIST_NEXT(dpl,next))) dpl = dpn;
|
||||
LIST_INSERT_AFTER(dpl, entry, next);
|
||||
}
|
||||
else
|
||||
LIST_INSERT_HEAD(¶ms.desync_profiles, entry, next);
|
||||
|
||||
return entry;
|
||||
}
|
||||
static void dp_clear_dynamic(struct desync_profile *dp)
|
||||
{
|
||||
free(dp->name);
|
||||
free(dp->name_tpl);
|
||||
free(dp->cookie);
|
||||
|
||||
hostlist_collection_destroy(&dp->hl_collection);
|
||||
hostlist_collection_destroy(&dp->hl_collection_exclude);
|
||||
ipset_collection_destroy(&dp->ips_collection);
|
||||
@@ -389,6 +382,67 @@ void dp_list_destroy(struct desync_profile_list_head *head)
|
||||
dp_entry_destroy(entry);
|
||||
}
|
||||
}
|
||||
|
||||
static struct desync_profile_list *desync_profile_entry_alloc()
|
||||
{
|
||||
struct desync_profile_list *entry = calloc(1,sizeof(struct desync_profile_list));
|
||||
if (entry) dp_init(&entry->dp);
|
||||
return entry;
|
||||
}
|
||||
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
|
||||
{
|
||||
struct desync_profile_list *entry = desync_profile_entry_alloc();
|
||||
if (!entry) return false;
|
||||
|
||||
struct desync_profile_list *tail, *item;
|
||||
LIST_TAIL(head, tail, item);
|
||||
LIST_INSERT_TAIL(head, tail, entry, next);
|
||||
|
||||
return entry;
|
||||
}
|
||||
bool dp_list_copy(struct desync_profile *to, const struct desync_profile *from)
|
||||
{
|
||||
// clear everything in target
|
||||
dp_clear(to);
|
||||
// first copy all simple type values
|
||||
*to = *from;
|
||||
// prepare empty dynamic structures
|
||||
dp_init_dynamic(to);
|
||||
// copy dynamic structures
|
||||
if (from->name && !(to->name = strdup(from->name))) return false;
|
||||
if (from->name_tpl && !(to->name_tpl = strdup(from->name_tpl))) return false;
|
||||
if (from->cookie && !(to->cookie = strdup(from->cookie))) return false;
|
||||
if (
|
||||
#ifdef HAS_FILTER_SSID
|
||||
!strlist_copy(&to->filter_ssid, &from->filter_ssid) ||
|
||||
#endif
|
||||
!funclist_copy(&to->lua_desync, &from->lua_desync) ||
|
||||
!ipset_collection_copy(&to->ips_collection, &from->ips_collection) ||
|
||||
!ipset_collection_copy(&to->ips_collection_exclude, &from->ips_collection_exclude) ||
|
||||
!hostlist_collection_copy(&to->hl_collection, &from->hl_collection) ||
|
||||
!hostlist_collection_copy(&to->hl_collection_exclude, &from->hl_collection_exclude))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
void dp_list_move(struct desync_profile_list_head *target, struct desync_profile_list *dpl)
|
||||
{
|
||||
struct desync_profile_list *tail, *item;
|
||||
LIST_TAIL(target, tail, item);
|
||||
LIST_REMOVE(dpl, next);
|
||||
LIST_INSERT_TAIL(target, tail, dpl, next);
|
||||
}
|
||||
struct desync_profile_list *dp_list_search_name(struct desync_profile_list_head *head, const char *name)
|
||||
{
|
||||
struct desync_profile_list *dpl;
|
||||
if (name)
|
||||
LIST_FOREACH(dpl, head, next)
|
||||
if (dpl->dp.name && !strcmp(dpl->dp.name, name))
|
||||
return dpl;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool dp_list_have_autohostlist(struct desync_profile_list_head *head)
|
||||
{
|
||||
struct desync_profile_list *dpl;
|
||||
@@ -427,6 +481,7 @@ void cleanup_params(struct params_s *params)
|
||||
|
||||
ConntrackPoolDestroy(¶ms->conntrack);
|
||||
dp_list_destroy(¶ms->desync_profiles);
|
||||
dp_list_destroy(¶ms->desync_templates);
|
||||
hostlist_files_destroy(¶ms->hostlists);
|
||||
ipset_files_destroy(¶ms->ipsets);
|
||||
ipcacheDestroy(¶ms->ipcache);
|
||||
@@ -440,3 +495,40 @@ void cleanup_params(struct params_s *params)
|
||||
free(params->user); params->user=NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
void init_params(struct params_s *params)
|
||||
{
|
||||
memset(params, 0, sizeof(*params));
|
||||
|
||||
#ifdef __linux__
|
||||
params->qnum = -1;
|
||||
#elif defined(BSD)
|
||||
params->port = 0;
|
||||
#endif
|
||||
params->desync_fwmark = DPI_DESYNC_FWMARK_DEFAULT;
|
||||
params->ctrack_t_syn = CTRACK_T_SYN;
|
||||
params->ctrack_t_est = CTRACK_T_EST;
|
||||
params->ctrack_t_fin = CTRACK_T_FIN;
|
||||
params->ctrack_t_udp = CTRACK_T_UDP;
|
||||
params->ipcache_lifetime = IPCACHE_LIFETIME;
|
||||
params->lua_gc = LUA_GC_INTERVAL;
|
||||
|
||||
LIST_INIT(¶ms->hostlists);
|
||||
LIST_INIT(¶ms->ipsets);
|
||||
LIST_INIT(¶ms->blobs);
|
||||
LIST_INIT(¶ms->lua_init_scripts);
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
LIST_INIT(¶ms->ssid_filter);
|
||||
LIST_INIT(¶ms->nlm_filter);
|
||||
LIST_INIT(¶ms->wf_raw_part);
|
||||
#else
|
||||
if (can_drop_root())
|
||||
{
|
||||
params->uid = params->gid[0] = 0x7FFFFFFF; // default uid:gid
|
||||
params->gid_count = 1;
|
||||
params->droproot = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "desync.h"
|
||||
#include "protocol.h"
|
||||
#include "helpers.h"
|
||||
#include "sec.h"
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/types.h>
|
||||
@@ -29,6 +30,7 @@
|
||||
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
|
||||
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
|
||||
#define HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT 3
|
||||
#define HOSTLIST_AUTO_RETRANS_MAXSEQ 65536
|
||||
|
||||
#define IPCACHE_LIFETIME 7200
|
||||
|
||||
@@ -53,6 +55,10 @@ enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG, LOG_
|
||||
struct desync_profile
|
||||
{
|
||||
unsigned int n; // number of the profile
|
||||
char *name; // optional malloced name string
|
||||
unsigned int n_tpl; // number of imported template
|
||||
char *name_tpl; // imported template name
|
||||
char *cookie; // optional malloced string
|
||||
|
||||
bool filter_ipv4,filter_ipv6;
|
||||
struct port_filters_head pf_tcp,pf_udp;
|
||||
@@ -73,11 +79,13 @@ struct desync_profile
|
||||
// pointer to autohostlist. NULL if no autohostlist for the profile.
|
||||
struct hostlist_file *hostlist_auto;
|
||||
int hostlist_auto_fail_threshold, hostlist_auto_fail_time, hostlist_auto_retrans_threshold;
|
||||
uint32_t hostlist_auto_retrans_maxseq;
|
||||
|
||||
hostfail_pool *hostlist_auto_fail_counters;
|
||||
|
||||
struct func_list_head lua_desync;
|
||||
};
|
||||
#define PROFILE_NAME(dp) ((dp)->name ? (dp)->name : "noname")
|
||||
|
||||
#define PROFILE_IPSETS_ABSENT(dp) (!LIST_FIRST(&(dp)->ips_collection) && !LIST_FIRST(&(dp)->ips_collection_exclude))
|
||||
#define PROFILE_IPSETS_EMPTY(dp) (ipset_collection_is_empty(&(dp)->ips_collection) && ipset_collection_is_empty(&(dp)->ips_collection_exclude))
|
||||
@@ -89,6 +97,9 @@ struct desync_profile_list {
|
||||
};
|
||||
LIST_HEAD(desync_profile_list_head, desync_profile_list);
|
||||
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head);
|
||||
void dp_list_move(struct desync_profile_list_head *target, struct desync_profile_list *dpl);
|
||||
bool dp_list_copy(struct desync_profile *to, const struct desync_profile *from);
|
||||
struct desync_profile_list *dp_list_search_name(struct desync_profile_list_head *head, const char *name);
|
||||
void dp_entry_destroy(struct desync_profile_list *entry);
|
||||
void dp_list_destroy(struct desync_profile_list_head *head);
|
||||
bool dp_list_have_autohostlist(struct desync_profile_list_head *head);
|
||||
@@ -104,6 +115,7 @@ struct params_s
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
wordexp_t wexp; // for file based config
|
||||
#endif
|
||||
char verstr[128];
|
||||
|
||||
enum log_target debug_target;
|
||||
char debug_logfile[PATH_MAX];
|
||||
@@ -119,7 +131,7 @@ struct params_s
|
||||
bool bind_fix4,bind_fix6;
|
||||
uint32_t desync_fwmark; // unused in BSD
|
||||
|
||||
struct desync_profile_list_head desync_profiles;
|
||||
struct desync_profile_list_head desync_profiles, desync_templates;
|
||||
|
||||
#ifdef __CYGWIN__
|
||||
struct str_list_head ssid_filter,nlm_filter;
|
||||
@@ -170,6 +182,8 @@ struct params_s
|
||||
|
||||
extern struct params_s params;
|
||||
extern const char *progname;
|
||||
|
||||
void init_params(struct params_s *params);
|
||||
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
|
||||
void cleanup_args(struct params_s *params);
|
||||
#endif
|
||||
|
||||
237
nfq2/pools.c
237
nfq2/pools.c
@@ -155,20 +155,33 @@ bool strlist_add(struct str_list_head *head, const char *str)
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
return true;
|
||||
}
|
||||
static struct str_list *strlist_entry_copy(const struct str_list *entry)
|
||||
{
|
||||
return strlist_entry_alloc(entry->str);
|
||||
}
|
||||
bool strlist_copy(struct str_list_head *to, const struct str_list_head *from)
|
||||
{
|
||||
struct str_list *tail, *item, *entry;
|
||||
|
||||
LIST_TAIL(to, tail, item);
|
||||
LIST_FOREACH(item, from, next)
|
||||
{
|
||||
if (!(entry = strlist_entry_copy(item))) return false;
|
||||
LIST_INSERT_TAIL(to, tail, entry, next);
|
||||
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool strlist_add_tail(struct str_list_head *head, const char *str)
|
||||
{
|
||||
struct str_list *entry = strlist_entry_alloc(str);
|
||||
if (!entry) return false;
|
||||
|
||||
// add to the tail
|
||||
struct str_list *strn,*strl=LIST_FIRST(head);
|
||||
if (strl)
|
||||
{
|
||||
while ((strn=LIST_NEXT(strl,next))) strl = strn;
|
||||
LIST_INSERT_AFTER(strl, entry, next);
|
||||
}
|
||||
else
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
struct str_list *tail, *item;
|
||||
LIST_TAIL(head, tail, item);
|
||||
LIST_INSERT_TAIL(head, tail, entry, next);
|
||||
|
||||
return true;
|
||||
}
|
||||
static void strlist_entry_destroy(struct str_list *entry)
|
||||
@@ -200,35 +213,77 @@ bool strlist_search(const struct str_list_head *head, const char *str)
|
||||
}
|
||||
|
||||
|
||||
static struct ptr_list *ptrlist_entry_alloc()
|
||||
static void str2list_entry_destroy(struct str2_list *entry)
|
||||
{
|
||||
return (struct ptr_list*)calloc(1,sizeof(struct ptr_list));
|
||||
free(entry->str1);
|
||||
free(entry->str2);
|
||||
free(entry);
|
||||
}
|
||||
void str2list_destroy(struct str2_list_head *head)
|
||||
{
|
||||
struct str2_list *entry;
|
||||
while ((entry = LIST_FIRST(head)))
|
||||
{
|
||||
LIST_REMOVE(entry, next);
|
||||
str2list_entry_destroy(entry);
|
||||
}
|
||||
}
|
||||
static struct str2_list *str2list_entry_alloc()
|
||||
{
|
||||
return (struct str2_list*)calloc(1,sizeof(struct str2_list));
|
||||
}
|
||||
|
||||
struct ptr_list *ptrlist_add(struct ptr_list_head *head)
|
||||
struct str2_list *str2list_add(struct str2_list_head *head)
|
||||
{
|
||||
struct ptr_list *entry = ptrlist_entry_alloc();
|
||||
struct str2_list *entry = str2list_entry_alloc();
|
||||
if (!entry) return NULL;
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
return entry;
|
||||
}
|
||||
static void ptrlist_entry_destroy(struct ptr_list *entry)
|
||||
static struct str2_list *str2list_entry_copy(const struct str2_list *entry)
|
||||
{
|
||||
free(entry->ptr1);
|
||||
free(entry->ptr2);
|
||||
struct str2_list *e2 = str2list_entry_alloc();
|
||||
if (!e2) return NULL;
|
||||
e2->str1 = strdup(entry->str1);
|
||||
e2->str2 = strdup(entry->str2);
|
||||
if (!e2->str1 || !e2->str2)
|
||||
{
|
||||
str2list_entry_destroy(e2);
|
||||
return false;
|
||||
}
|
||||
return e2;
|
||||
}
|
||||
bool str2list_copy(struct str2_list_head *to, const struct str2_list_head *from)
|
||||
{
|
||||
struct str2_list *tail, *item, *entry;
|
||||
|
||||
LIST_TAIL(to, tail, item);
|
||||
LIST_FOREACH(item, from, next)
|
||||
{
|
||||
if (!(entry = str2list_entry_copy(item))) return false;
|
||||
LIST_INSERT_TAIL(to, tail, entry, next);
|
||||
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void funclist_entry_destroy(struct func_list *entry)
|
||||
{
|
||||
free(entry->func);
|
||||
str2list_destroy(&entry->args);
|
||||
free(entry);
|
||||
}
|
||||
void ptrlist_destroy(struct ptr_list_head *head)
|
||||
void funclist_destroy(struct func_list_head *head)
|
||||
{
|
||||
struct ptr_list *entry;
|
||||
struct func_list *entry;
|
||||
while ((entry = LIST_FIRST(head)))
|
||||
{
|
||||
LIST_REMOVE(entry, next);
|
||||
ptrlist_entry_destroy(entry);
|
||||
funclist_entry_destroy(entry);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct func_list *funclist_entry_alloc(const char *func)
|
||||
{
|
||||
struct func_list *entry = malloc(sizeof(struct func_list));
|
||||
@@ -250,31 +305,38 @@ struct func_list *funclist_add_tail(struct func_list_head *head, const char *fun
|
||||
struct func_list *entry = funclist_entry_alloc(func);
|
||||
if (!entry) return NULL;
|
||||
|
||||
// add to the tail
|
||||
struct func_list *funcn,*funcl=LIST_FIRST(head);
|
||||
if (funcl)
|
||||
{
|
||||
while ((funcn=LIST_NEXT(funcl,next))) funcl = funcn;
|
||||
LIST_INSERT_AFTER(funcl, entry, next);
|
||||
}
|
||||
else
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
struct func_list *tail, *item;
|
||||
LIST_TAIL(head, tail, item);
|
||||
LIST_INSERT_TAIL(head, tail, entry, next);
|
||||
|
||||
return entry;
|
||||
}
|
||||
static void funclist_entry_destroy(struct func_list *entry)
|
||||
static struct func_list *funclist_entry_copy(const struct func_list *entry)
|
||||
{
|
||||
free(entry->func);
|
||||
ptrlist_destroy(&entry->args);
|
||||
free(entry);
|
||||
}
|
||||
void funclist_destroy(struct func_list_head *head)
|
||||
{
|
||||
struct func_list *entry;
|
||||
while ((entry = LIST_FIRST(head)))
|
||||
struct func_list *e2 = funclist_entry_alloc(entry->func);
|
||||
if (!e2) return NULL;
|
||||
e2->payload_type = entry->payload_type;
|
||||
e2->range_in = entry->range_in;
|
||||
e2->range_out = entry->range_out;
|
||||
if (!str2list_copy(&e2->args, &entry->args))
|
||||
{
|
||||
LIST_REMOVE(entry, next);
|
||||
funclist_entry_destroy(entry);
|
||||
funclist_entry_destroy(e2);
|
||||
return false;
|
||||
}
|
||||
return e2;
|
||||
}
|
||||
bool funclist_copy(struct func_list_head *to, const struct func_list_head *from)
|
||||
{
|
||||
struct func_list *tail, *item, *entry;
|
||||
|
||||
LIST_TAIL(to, tail, item);
|
||||
LIST_FOREACH(item, from, next)
|
||||
{
|
||||
if (!(entry = funclist_entry_copy(item))) return false;
|
||||
LIST_INSERT_TAIL(to, tail, entry, next);
|
||||
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -333,16 +395,36 @@ void hostlist_files_reset_modtime(struct hostlist_files_head *list)
|
||||
FILE_MOD_RESET(&hfile->mod_sig);
|
||||
}
|
||||
|
||||
struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile)
|
||||
static struct hostlist_item *hostlist_collection_entry_alloc(struct hostlist_file *hfile)
|
||||
{
|
||||
struct hostlist_item *entry = malloc(sizeof(struct hostlist_item));
|
||||
if (entry)
|
||||
{
|
||||
entry->hfile = hfile;
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
}
|
||||
if (entry) entry->hfile = hfile;
|
||||
return entry;
|
||||
}
|
||||
struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile)
|
||||
{
|
||||
struct hostlist_item *entry = hostlist_collection_entry_alloc(hfile);
|
||||
if (entry) LIST_INSERT_HEAD(head, entry, next);
|
||||
return entry;
|
||||
}
|
||||
static struct hostlist_item *hostlist_collection_entry_copy(const struct hostlist_item *entry)
|
||||
{
|
||||
return hostlist_collection_entry_alloc(entry->hfile);
|
||||
}
|
||||
bool hostlist_collection_copy(struct hostlist_collection_head *to, const struct hostlist_collection_head *from)
|
||||
{
|
||||
struct hostlist_item *tail, *item, *entry;
|
||||
|
||||
LIST_TAIL(to, tail, item);
|
||||
LIST_FOREACH(item, from, next)
|
||||
{
|
||||
if (!(entry = hostlist_collection_entry_copy(item))) return false;
|
||||
LIST_INSERT_TAIL(to, tail, entry, next);
|
||||
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void hostlist_collection_destroy(struct hostlist_collection_head *head)
|
||||
{
|
||||
struct hostlist_item *entry;
|
||||
@@ -579,16 +661,36 @@ void ipset_files_reset_modtime(struct ipset_files_head *list)
|
||||
FILE_MOD_RESET(&hfile->mod_sig);
|
||||
}
|
||||
|
||||
struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile)
|
||||
static struct ipset_item *ipset_collection_entry_alloc(struct ipset_file *hfile)
|
||||
{
|
||||
struct ipset_item *entry = malloc(sizeof(struct ipset_item));
|
||||
if (entry)
|
||||
{
|
||||
entry->hfile = hfile;
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
}
|
||||
if (entry) entry->hfile = hfile;
|
||||
return entry;
|
||||
}
|
||||
struct ipset_item *ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile)
|
||||
{
|
||||
struct ipset_item *entry = ipset_collection_entry_alloc(hfile);
|
||||
if (entry) LIST_INSERT_HEAD(head, entry, next);
|
||||
return entry;
|
||||
}
|
||||
static struct ipset_item *ipset_collection_entry_copy(const struct ipset_item *entry)
|
||||
{
|
||||
return ipset_collection_entry_alloc(entry->hfile);
|
||||
}
|
||||
bool ipset_collection_copy(struct ipset_collection_head *to, const struct ipset_collection_head *from)
|
||||
{
|
||||
struct ipset_item *tail, *item, *entry;
|
||||
|
||||
LIST_TAIL(to, tail, item);
|
||||
LIST_FOREACH(item, from, next)
|
||||
{
|
||||
if (!(entry = ipset_collection_entry_copy(item))) return false;
|
||||
LIST_INSERT_TAIL(to, tail, entry, next);
|
||||
tail = tail ? LIST_NEXT(tail, next) : LIST_FIRST(to);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ipset_collection_destroy(struct ipset_collection_head *head)
|
||||
{
|
||||
struct ipset_item *entry;
|
||||
@@ -645,7 +747,7 @@ bool port_filters_in_range(const struct port_filters_head *head, uint16_t port)
|
||||
{
|
||||
const struct port_filter_item *item;
|
||||
|
||||
if (!LIST_FIRST(head)) return true;
|
||||
if (LIST_EMPTY(head)) return true;
|
||||
LIST_FOREACH(item, head, next)
|
||||
{
|
||||
if (pf_in_range(port, &item->pf))
|
||||
@@ -656,7 +758,7 @@ bool port_filters_in_range(const struct port_filters_head *head, uint16_t port)
|
||||
bool port_filters_deny_if_empty(struct port_filters_head *head)
|
||||
{
|
||||
port_filter pf;
|
||||
if (LIST_FIRST(head)) return true;
|
||||
if (!LIST_EMPTY(head)) return true;
|
||||
return pf_parse("0",&pf) && port_filter_add(head,&pf);
|
||||
}
|
||||
|
||||
@@ -667,15 +769,9 @@ struct blob_item *blob_collection_add(struct blob_collection_head *head)
|
||||
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
|
||||
if (entry)
|
||||
{
|
||||
// insert to the end
|
||||
struct blob_item *itemc,*iteml=LIST_FIRST(head);
|
||||
if (iteml)
|
||||
{
|
||||
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
|
||||
LIST_INSERT_AFTER(iteml, entry, next);
|
||||
}
|
||||
else
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
struct blob_item *tail, *item;
|
||||
LIST_TAIL(head, tail, item);
|
||||
LIST_INSERT_TAIL(head, tail, entry, next);
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
@@ -693,14 +789,9 @@ struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, co
|
||||
entry->size_buf = size+size_reserve;
|
||||
|
||||
// insert to the end
|
||||
struct blob_item *itemc,*iteml=LIST_FIRST(head);
|
||||
if (iteml)
|
||||
{
|
||||
while ((itemc=LIST_NEXT(iteml,next))) iteml = itemc;
|
||||
LIST_INSERT_AFTER(iteml, entry, next);
|
||||
}
|
||||
else
|
||||
LIST_INSERT_HEAD(head, entry, next);
|
||||
struct blob_item *tail, *item;
|
||||
LIST_TAIL(head, tail, item);
|
||||
LIST_INSERT_TAIL(head, tail, entry, next);
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -725,7 +816,7 @@ void blob_collection_destroy(struct blob_collection_head *head)
|
||||
}
|
||||
bool blob_collection_empty(const struct blob_collection_head *head)
|
||||
{
|
||||
return !LIST_FIRST(head);
|
||||
return LIST_EMPTY(head);
|
||||
}
|
||||
struct blob_item *blob_collection_search_name(struct blob_collection_head *head, const char *name)
|
||||
{
|
||||
|
||||
30
nfq2/pools.h
30
nfq2/pools.h
@@ -17,6 +17,17 @@
|
||||
|
||||
#define HOSTLIST_POOL_FLAG_STRICT_MATCH 1
|
||||
|
||||
#define LIST_TAIL(head, tail, temp) {\
|
||||
tail=LIST_FIRST(head); \
|
||||
if (tail) while ((temp=LIST_NEXT(tail,next))) tail = temp; }
|
||||
|
||||
#define LIST_INSERT_TAIL(head, tail, elm, field) { \
|
||||
if (LIST_FIRST(head)) \
|
||||
LIST_INSERT_AFTER(tail, elm, field); \
|
||||
else \
|
||||
LIST_INSERT_HEAD(head, elm, field); }
|
||||
|
||||
|
||||
typedef struct hostlist_pool {
|
||||
char *str; /* key */
|
||||
uint32_t flags; /* custom data */
|
||||
@@ -38,25 +49,28 @@ bool strlist_add(struct str_list_head *head, const char *str);
|
||||
bool strlist_add_tail(struct str_list_head *head, const char *str);
|
||||
void strlist_destroy(struct str_list_head *head);
|
||||
bool strlist_search(const struct str_list_head *head, const char *str);
|
||||
bool strlist_copy(struct str_list_head *to, const struct str_list_head *from);
|
||||
|
||||
struct ptr_list {
|
||||
void *ptr1,*ptr2;
|
||||
LIST_ENTRY(ptr_list) next;
|
||||
struct str2_list {
|
||||
char *str1,*str2;
|
||||
LIST_ENTRY(str2_list) next;
|
||||
};
|
||||
LIST_HEAD(ptr_list_head, ptr_list);
|
||||
LIST_HEAD(str2_list_head, str2_list);
|
||||
|
||||
struct ptr_list *ptrlist_add(struct ptr_list_head *head);
|
||||
void ptrlist_destroy(struct ptr_list_head *head);
|
||||
struct str2_list *str2list_add(struct str2_list_head *head);
|
||||
bool str2list_copy(struct str2_list_head *to, const struct str2_list_head *from);
|
||||
void str2list_destroy(struct str2_list_head *head);
|
||||
|
||||
struct func_list {
|
||||
char *func;
|
||||
uint64_t payload_type;
|
||||
struct packet_range range_in, range_out;
|
||||
struct ptr_list_head args;
|
||||
struct str2_list_head args;
|
||||
LIST_ENTRY(func_list) next;
|
||||
};
|
||||
LIST_HEAD(func_list_head, func_list);
|
||||
struct func_list *funclist_add_tail(struct func_list_head *head, const char *func);
|
||||
bool funclist_copy(struct func_list_head *to, const struct func_list_head *from);
|
||||
void funclist_destroy(struct func_list_head *head);
|
||||
|
||||
|
||||
@@ -96,6 +110,7 @@ struct hostlist_item {
|
||||
LIST_HEAD(hostlist_collection_head, hostlist_item);
|
||||
struct hostlist_item *hostlist_collection_add(struct hostlist_collection_head *head, struct hostlist_file *hfile);
|
||||
void hostlist_collection_destroy(struct hostlist_collection_head *head);
|
||||
bool hostlist_collection_copy(struct hostlist_collection_head *to, const struct hostlist_collection_head *from);
|
||||
struct hostlist_item *hostlist_collection_search(struct hostlist_collection_head *head, const char *filename);
|
||||
bool hostlist_collection_is_empty(const struct hostlist_collection_head *head);
|
||||
|
||||
@@ -158,6 +173,7 @@ struct ipset_item {
|
||||
};
|
||||
LIST_HEAD(ipset_collection_head, ipset_item);
|
||||
struct ipset_item * ipset_collection_add(struct ipset_collection_head *head, struct ipset_file *hfile);
|
||||
bool ipset_collection_copy(struct ipset_collection_head *to, const struct ipset_collection_head *from);
|
||||
void ipset_collection_destroy(struct ipset_collection_head *head);
|
||||
struct ipset_item *ipset_collection_search(struct ipset_collection_head *head, const char *filename);
|
||||
bool ipset_collection_is_empty(const struct ipset_collection_head *head);
|
||||
|
||||
@@ -48,7 +48,7 @@ bool l7_proto_match(t_l7proto l7proto, uint64_t filter_l7)
|
||||
static const char *l7payload_name[] = {
|
||||
"all","unknown","empty","known","http_req","http_reply","tls_client_hello","tls_server_hello","quic_initial",
|
||||
"wireguard_initiation","wireguard_response","wireguard_cookie","wireguard_keepalive","wireguard_data",
|
||||
"dht","discord_ip_discovery","stun_binding_req",
|
||||
"dht","discord_ip_discovery","stun",
|
||||
"xmpp_stream", "xmpp_starttls", "xmpp_proceed", "xmpp_features",
|
||||
"dns_query", "dns_response",
|
||||
"mtproto_initial"};
|
||||
@@ -66,6 +66,35 @@ bool l7_payload_match(t_l7payload l7payload, uint64_t filter_l7p)
|
||||
{
|
||||
return filter_l7p==L7P_ALL || (filter_l7p & (1<<l7payload)) || (filter_l7p & (1<<L7P_KNOWN)) && l7payload>L7P_KNOWN && l7payload<L7P_LAST;
|
||||
}
|
||||
bool l7_payload_str_list(uint64_t l7p, char *buf, size_t size)
|
||||
{
|
||||
char *p;
|
||||
const char *pstr;
|
||||
size_t lstr;
|
||||
t_l7payload pl;
|
||||
|
||||
if (!size) return false;
|
||||
if (l7p==L7P_ALL)
|
||||
{
|
||||
if (size<4) return false;
|
||||
memcpy(buf,"all",4);
|
||||
return true;
|
||||
}
|
||||
for(pl=0, p=buf, *buf=0 ; pl<L7P_LAST ; pl++)
|
||||
{
|
||||
if (l7p & (1<<pl))
|
||||
{
|
||||
pstr = l7payload_str(pl);
|
||||
lstr = strlen(pstr);
|
||||
if (size < ((p!=buf) + lstr + 1)) return false;
|
||||
if (p!=buf) *p++=','; // not first
|
||||
memcpy(p,pstr,lstr);
|
||||
p[lstr]=0;
|
||||
p+=lstr;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
static const char *posmarker_names[] = {"abs","host","endhost","sld","midsld","endsld","method","extlen","sniext"};
|
||||
@@ -819,7 +848,7 @@ bool TLSMod(const struct fake_tls_mod *tls_mod, const uint8_t *payload, size_t p
|
||||
{
|
||||
if (tls_mod->mod & FAKE_TLS_MOD_DUP_SID)
|
||||
{
|
||||
if (IsTLSClientHello(payload, payload_len, false))
|
||||
if (IsTLSClientHelloPartial(payload, payload_len))
|
||||
{
|
||||
if (payload_len < 44)
|
||||
{
|
||||
@@ -1380,11 +1409,11 @@ bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len)
|
||||
!memcmp(data+8,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",64);
|
||||
// address is not set in request
|
||||
}
|
||||
bool IsStunBindingRequest(const uint8_t *data, size_t len)
|
||||
bool IsStunMessage(const uint8_t *data, size_t len)
|
||||
{
|
||||
return len>=20 && // header size
|
||||
data[0]==0 && data[1]==1 &&
|
||||
(data[3]&0b11)==0 && // length must be a multiple of 4
|
||||
(data[0]&0xC0)==0 && // 2 most significant bits must be zeroes
|
||||
(data[3]&3)==0 && // length must be a multiple of 4
|
||||
ntohl(*(uint32_t*)(&data[4]))==0x2112A442 && // magic cookie
|
||||
ntohs(*(uint16_t*)(&data[2]))==len-20;
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ typedef enum {
|
||||
L7P_WIREGUARD_DATA,
|
||||
L7P_DHT,
|
||||
L7P_DISCORD_IP_DISCOVERY,
|
||||
L7P_STUN_BINDING_REQ,
|
||||
L7P_STUN,
|
||||
L7P_XMPP_STREAM,
|
||||
L7P_XMPP_STARTTLS,
|
||||
L7P_XMPP_PROCEED,
|
||||
@@ -55,6 +55,7 @@ typedef enum {
|
||||
t_l7payload l7payload_from_name(const char *name);
|
||||
const char *l7payload_str(t_l7payload l7);
|
||||
bool l7_payload_match(t_l7payload l7payload, uint64_t filter_l7p);
|
||||
bool l7_payload_str_list(uint64_t l7p, char *buf, size_t size);
|
||||
|
||||
typedef enum {
|
||||
PM_ABS=0,
|
||||
@@ -126,7 +127,7 @@ bool TLSHelloExtractHostFromHandshake(const uint8_t *data, size_t len, char *hos
|
||||
|
||||
struct fake_tls_mod
|
||||
{
|
||||
char sni[128];
|
||||
char sni[256];
|
||||
uint32_t mod;
|
||||
};
|
||||
#define FAKE_TLS_MOD_RND 0x01
|
||||
@@ -152,7 +153,7 @@ bool IsWireguardKeepalive(const uint8_t *data, size_t len);
|
||||
bool IsWireguardData(const uint8_t *data, size_t len);
|
||||
bool IsDht(const uint8_t *data, size_t len);
|
||||
bool IsDiscordIpDiscoveryRequest(const uint8_t *data, size_t len);
|
||||
bool IsStunBindingRequest(const uint8_t *data, size_t len);
|
||||
bool IsStunMessage(const uint8_t *data, size_t len);
|
||||
bool IsMTProto(const uint8_t *data, size_t len);
|
||||
|
||||
#define QUIC_MAX_CID_LENGTH 20
|
||||
|
||||
Reference in New Issue
Block a user