Template
1
0
mirror of https://github.com/bol-van/zapret2.git synced 2026-03-14 22:22:29 +00:00

164 Commits
v0.4 ... v0.7.2

Author SHA1 Message Date
bol-van
de8845b89d zapret-auto: separate hostkey function 2025-12-14 18:14:42 +03:00
bol-van
f1eae764ab nfqws2: clean lua cutoff on profile change 2025-12-14 17:39:15 +03:00
bol-van
03c650b33c nfqws2: set fwmark to 0 in windows 2025-12-14 16:34:10 +03:00
bol-van
64b12c51e5 update docs 2025-12-14 16:28:43 +03:00
bol-van
2d8e031904 update docs 2025-12-14 16:26:56 +03:00
bol-van
28f0cd6e73 update docs 2025-12-14 16:19:24 +03:00
bol-van
9a9179a23b update docs 2025-12-14 16:18:36 +03:00
bol-van
48123bf1f7 update docs 2025-12-14 15:03:24 +03:00
bol-van
ece4e52676 update docs 2025-12-14 15:01:51 +03:00
bol-van
1d24d1e040 zapret-auto: update comment 2025-12-14 13:29:39 +03:00
bol-van
d0fd6b4868 update docs 2025-12-14 13:27:12 +03:00
bol-van
328408fa30 zapret-auto: deduplicate standard detector defaults 2025-12-14 13:20:28 +03:00
bol-van
0343bb248d zapret-auto: unify automate dlog prefix 2025-12-14 13:02:23 +03:00
bol-van
e4dd1574b8 zapret-auto: change function name 2025-12-14 13:00:39 +03:00
bol-van
1e3486ee14 zapret-auto: add success detector logic 2025-12-14 12:33:08 +03:00
bol-van
efe7470732 update docs 2025-12-13 23:48:26 +03:00
bol-van
8acd5690f4 update docs 2025-12-13 23:46:33 +03:00
bol-van
c2e3176a46 update docs 2025-12-13 23:44:27 +03:00
bol-van
658252d46a update docs 2025-12-13 23:43:06 +03:00
bol-van
5aaf7b3d6c update docs 2025-12-13 23:42:00 +03:00
bol-van
031ac7616d update docs 2025-12-13 23:41:16 +03:00
bol-van
098417d19f update docs 2025-12-13 23:40:43 +03:00
bol-van
2f0a74a11e update docs 2025-12-13 23:39:16 +03:00
bol-van
40c37c3448 update docs 2025-12-13 23:37:51 +03:00
bol-van
77fb530120 update docs 2025-12-13 23:36:52 +03:00
bol-van
faa0274521 update docs 2025-12-13 23:35:21 +03:00
bol-van
8a253d3d95 update docs 2025-12-13 23:34:36 +03:00
bol-van
0aac2965c1 nfqws2: minor reorder struct members 2025-12-13 22:13:04 +03:00
bol-van
d1128a8bc6 update docs 2025-12-13 20:56:17 +03:00
bol-van
e016fc0e42 update docs 2025-12-13 20:55:50 +03:00
bol-van
f48ea2f6a7 update docs 2025-12-13 20:39:03 +03:00
bol-van
2ab71ab895 update docs 2025-12-13 20:19:02 +03:00
bol-van
736e0ba3d4 update docs 2025-12-13 20:16:13 +03:00
bol-van
f2ae880c11 update docs 2025-12-13 20:15:05 +03:00
bol-van
019f3089c6 update docs 2025-12-13 20:09:12 +03:00
bol-van
30d28488c9 update docs 2025-12-13 19:53:54 +03:00
bol-van
5bcec4aada update docs 2025-12-13 19:50:16 +03:00
bol-van
886fbabcfc update docs 2025-12-13 17:00:17 +03:00
bol-van
cd8dbf2a2b update docs 2025-12-13 16:59:05 +03:00
bol-van
002742bd03 update docs 2025-12-13 16:56:45 +03:00
bol-van
dc2c707c3c update docs 2025-12-13 16:55:22 +03:00
bol-van
9630d0a9df update docs 2025-12-13 16:54:54 +03:00
bol-van
f4c4d5e558 update docs 2025-12-13 16:43:11 +03:00
bol-van
7b37880954 update docs 2025-12-13 16:39:53 +03:00
bol-van
6b7738ac16 update docs 2025-12-13 16:38:46 +03:00
bol-van
8dec014b50 update docs 2025-12-13 16:36:46 +03:00
bol-van
b0ee32f3dc update docs 2025-12-13 16:36:21 +03:00
bol-van
0e770ff46d update docs 2025-12-13 16:35:52 +03:00
bol-van
14b3aef030 update docs 2025-12-13 16:33:05 +03:00
bol-van
004c583595 update docs 2025-12-13 16:31:18 +03:00
bol-van
c4818a6a32 nfqws2: solved inability to get SSID using nl80211 on kernels 5.19+ 2025-12-13 15:33:57 +03:00
bol-van
58d57fed01 update docs 2025-12-13 11:27:16 +03:00
bol-van
d6b73fe7e0 update docs 2025-12-13 11:26:58 +03:00
bol-van
4867838fce update docs 2025-12-13 11:24:35 +03:00
bol-van
4b2551509f update docs 2025-12-13 11:22:16 +03:00
bol-van
ed6acb36a1 nfqws2: update docs 2025-12-12 23:45:32 +03:00
bol-van
26b80e80b6 nfqws2: update docs 2025-12-12 23:43:47 +03:00
bol-van
79b776b5a9 nfqws2: update docs 2025-12-12 23:42:27 +03:00
bol-van
3b251b9ee6 nfqws2: update docs 2025-12-12 23:41:43 +03:00
bol-van
8c65a966d9 nfqws2: update docs 2025-12-12 23:40:58 +03:00
bol-van
9da0b13aa3 nfqws2: update docs 2025-12-12 23:39:18 +03:00
bol-van
d7fd491121 nfqws2: update docs 2025-12-12 23:38:09 +03:00
bol-van
c60ef399ec nfqws2: update docs 2025-12-12 23:36:15 +03:00
bol-van
2abab21e4b nfqws2: update docs 2025-12-12 23:31:17 +03:00
bol-van
6190babb99 nfqws2: update docs 2025-12-12 23:29:55 +03:00
bol-van
7ce0b4a996 nfqws2: reduce default retrans maxseq to 32768, adjust config 2025-12-12 23:28:49 +03:00
bol-van
053556fe2d nfqws2: autohostlist reset fail counter if udp_in > threshold 2025-12-12 23:11:11 +03:00
bol-van
52571045fe nfqws2: add EOL at the end of truncated buffered DLOG line if it's too large. increase log line buffer 2025-12-12 20:37:58 +03:00
bol-van
db875ed1d4 nfqws2: cancel reasm if server window size is smaller than expected reasm size 2025-12-12 20:20:12 +03:00
bol-van
e828864811 nfqws2: cancel reasm if server window size is smaller than expected reasm size 2025-12-12 20:18:55 +03:00
bol-van
4404127fa3 update docs 2025-12-12 18:26:30 +03:00
bol-van
13e81e4b6f update docs 2025-12-12 18:25:45 +03:00
bol-van
a631add2d9 update docs 2025-12-12 18:24:34 +03:00
bol-van
26b9b63a20 update docs 2025-12-12 18:21:35 +03:00
bol-van
90489fad2f update docs 2025-12-12 18:21:17 +03:00
bol-van
d93c243d21 update docs 2025-12-12 18:20:46 +03:00
bol-van
65235d71d7 update docs 2025-12-12 18:19:53 +03:00
bol-van
fc01e6715f update docs 2025-12-12 18:04:18 +03:00
bol-van
1a33d68998 update docs 2025-12-12 18:00:57 +03:00
bol-van
dfaa475d2a update docs 2025-12-12 17:50:42 +03:00
bol-van
743018423a update docs 2025-12-12 17:47:15 +03:00
bol-van
762023f201 update docs 2025-12-12 16:45:16 +03:00
bol-van
a296b93b7a update docs 2025-12-12 16:44:17 +03:00
bol-van
1c9b3aa1bc update docs 2025-12-12 16:40:02 +03:00
bol-van
565fa8e337 init.d: fix non-working incoming redirect 2025-12-12 16:09:31 +03:00
bol-van
9fcecd07d1 update docs 2025-12-12 12:19:04 +03:00
bol-van
652e271877 update docs 2025-12-12 12:06:55 +03:00
bol-van
fc7ed4f4a8 update docs 2025-12-12 12:04:57 +03:00
bol-van
e9e5bdc860 update docs 2025-12-12 12:04:31 +03:00
bol-van
a2b8300219 update docs 2025-12-12 12:03:45 +03:00
bol-van
dfdcfbdf51 update docs 2025-12-12 12:02:12 +03:00
bol-van
170ec372fb update docs 2025-12-12 12:00:53 +03:00
bol-van
3f073908a6 update docs 2025-12-12 11:59:17 +03:00
bol-van
7708021587 nfqws2: rewrite autohostlist udp failure detector logic 2025-12-11 15:19:31 +03:00
bol-van
912aadf6ca zapret-auto: override host autostate key 2025-12-11 13:41:04 +03:00
bol-van
420cc0c3ef nfqws2: fix crash 2025-12-11 13:38:10 +03:00
bol-van
6ce5829d06 zapret-auto: override host autostate key 2025-12-11 12:57:32 +03:00
bol-van
a6d43af931 nfqws2: autohostlist do not react to rseq 0 2025-12-11 01:03:25 +03:00
bol-van
ca9898959e nfqws2: remove commented test code 2025-12-11 00:23:20 +03:00
bol-van
8cd2904614 nfqws2: push desync.track.pos.dt as float with nsec accuracy 2025-12-11 00:21:22 +03:00
bol-van
0de1ab1b1b init.d: AUTOHOSTLIST_INCOMING_MAXSEQ 2025-12-10 23:21:30 +03:00
bol-van
d1690aadcf nfqws2: autohostlist incoming failure triggers change 2025-12-10 23:11:28 +03:00
bol-van
2dd8533fb5 nfqws2,zapret-lib.lua,zapret-auto.lua: restructure conntrack record 2025-12-10 19:36:31 +03:00
bol-van
33ac18ea6b zapret-lib,zapret-auto: do not use desync copy to not lose VERDICT_MODIFY changes 2025-12-10 13:43:39 +03:00
bol-van
5c05c10f83 zapret-lib: return 0 if #val refers to non-string and non-table type 2025-12-10 10:49:46 +03:00
bol-van
7de0995d4a nfqws2,zapret-lib: fix non-working # and % arg subst under orchestrator 2025-12-10 10:28:48 +03:00
bol-van
a1c64e4dea update doc 2025-12-09 18:08:36 +03:00
bol-van
92b66b1535 update doc 2025-12-09 18:08:01 +03:00
bol-van
9bf4fb11e7 update doc 2025-12-09 18:05:08 +03:00
bol-van
7deeb04207 start writing manual.md 2025-12-09 18:00:24 +03:00
bol-van
776155a326 blockcheck2: fix unterminated string 2025-12-09 14:17:07 +03:00
bol-van
30423596ca zapret-lib: detect_payload_str 2025-12-09 12:18:59 +03:00
bol-van
27ef67adf9 zapret-auto: cond_payload_str 2025-12-09 11:48:23 +03:00
bol-van
bb604f111c zapret-auto: add comments 2025-12-09 11:22:09 +03:00
bol-van
e5174bc9ad zapret-auto: condition and stopif orchestrators 2025-12-09 10:50:54 +03:00
bol-van
6c29bf6702 zapret-lib,zapret-auto: allow nested orchestration 2025-12-09 09:52:24 +03:00
bol-van
976033be37 nfqws2: do not increase upseq_prev on empty packets 2025-12-09 09:52:08 +03:00
bol-van
f9b2135688 zapret-auto: add comments 2025-12-08 22:45:42 +03:00
bol-van
844fa6ab47 zapret-auto: optimize detector code 2025-12-08 20:02:26 +03:00
bol-van
dc0fe70bd6 zapret-auto: udp_in/udp_out failure detection 2025-12-08 19:46:00 +03:00
bol-van
2752c26795 blockcheck2: FOOLINGS_UDP overridable 2025-12-08 18:37:18 +03:00
bol-van
1600b41135 init.d: support --hostlist-auto-retrans-threshold 2025-12-08 16:52:49 +03:00
bol-van
2017889207 nfqws2: change retransmission detection scheme 2025-12-08 16:46:04 +03:00
bol-van
146ab847df nfqws2: allow dupsid with partial tls 2025-12-08 11:31:46 +03:00
bol-van
cf9059ed22 update changes.txt 2025-12-08 10:57:04 +03:00
bol-van
c94264c79e nfqws2: more fixes to reasm overlap support 2025-12-08 10:55:32 +03:00
bol-van
04cb71150a nfqws2: improve reasm overlap support 2025-12-08 10:35:26 +03:00
bol-van
378ee514c4 nfqws2: reasm support negative overlaps without gaps and without going beyond the starting seq 2025-12-08 09:55:44 +03:00
bol-van
1a190fcf9e nfqws2: increase tls_mod sni max size 2025-12-07 21:30:07 +03:00
bol-van
0f8a788351 zapret-auto: optimize code 2025-12-07 20:05:43 +03:00
bol-van
4c00f11c15 zapret-auto: move crec record get 2025-12-07 20:01:29 +03:00
bol-van
0f8cfd7022 zapret-lib: remove duplicate function 2025-12-07 19:59:31 +03:00
bol-van
4563b6ddcb blockcheck2: syndata tests 2025-12-07 19:44:28 +03:00
bol-van
9ae6927a0e zapret-auto: remove duplicate seq assignment 2025-12-07 17:03:45 +03:00
bol-van
8540278c9b zapret-antidpi: use tls_mod_shim 2025-12-07 17:00:55 +03:00
bol-van
76b9ab5075 zapret-lib: improve random seed 2025-12-07 16:52:37 +03:00
bol-van
3a153035e8 zapret-lib,zapret-antidpi: support sni=%var in tls_mod 2025-12-07 15:08:56 +03:00
bol-van
2b5eb3cd2d blockcheck2: remove newline print if test function absent 2025-12-07 14:31:56 +03:00
bol-van
2c35e8949a blockcheck2: fix brokern http3 test 2025-12-07 14:01:54 +03:00
bol-van
7edd428508 zapret-auto, zapret-lib: deduplicate plan instance execution code 2025-12-07 11:07:46 +03:00
bol-van
7749fce7dc zapret-auto: separate failure detection logic 2025-12-07 10:51:52 +03:00
bol-van
ea6e1e0853 blockcheck2: change qnum to allow parallel run with blockcheck1 for different domains 2025-12-07 09:46:32 +03:00
bol-van
7d2f12cbad zapret-auto: remove unused code 2025-12-06 23:50:35 +03:00
bol-van
f91c069a8b nfqws2: fix wrong enum type 2025-12-06 23:25:19 +03:00
bol-van
6961c013c5 actions: build x86 binary with classic LUA 5.4 2025-12-06 23:13:19 +03:00
bol-van
e5736b5fdd fix multiple problems with lua_Integer 32 bit type in lua < 5.3 on 32-bit platforms 2025-12-06 22:43:45 +03:00
bol-van
efa675468d nfqws2: fix wrong payload/proto type 2025-12-06 20:53:42 +03:00
bol-van
1073f03802 update changes.txt 2025-12-06 20:27:26 +03:00
bol-van
9125cb0205 zapret-auto: circular.reqhost parameter 2025-12-06 20:25:04 +03:00
bol-van
9d5435f977 nfqws2: do not export instance_cutoff, export l7proto for conntrack-less case 2025-12-06 19:43:39 +03:00
bol-van
f17ab4c91e zapret-lib,zapret-auto: unify messages 2025-12-06 17:19:28 +03:00
bol-van
97aa261e14 winws: always catch http redirect 2025-12-06 16:18:18 +03:00
bol-van
813fece07a nfqws2,zapret-auto: circular orchestrator 2025-12-06 15:58:09 +03:00
bol-van
2a7b44b1d0 zapret-lib: port support in url dissector 2025-12-06 10:46:47 +03:00
bol-van
28e719d825 zapret-lib: url and nld dissectors 2025-12-06 10:39:19 +03:00
bol-van
18725f6442 zapret-lib: remove temp debug code 2025-12-06 10:01:19 +03:00
bol-van
20b20fbb90 zapret-tests: adapt to 32bit arithmetics 2025-12-06 10:00:19 +03:00
bol-van
967b53b628 update changes.txt 2025-12-06 09:59:08 +03:00
bol-van
9cebc5cc37 nfqws2: remove any arithmetics beyond 32 bit 2025-12-06 09:57:08 +03:00
bol-van
0dc29c9c35 zapret-lib: http_reply dissector 2025-12-05 22:51:56 +03:00
bol-van
fd1eac2ef1 zapret-lib: fix seq number substraction 2025-12-05 22:31:51 +03:00
bol-van
0c2abab6a9 nfqws2: uXadd luacalls 2025-12-05 22:31:27 +03:00
bol-van
efd8acb8de zapret-lib: fix multiple problems 2025-12-05 14:42:33 +03:00
bol-van
a147ebef61 update changes.txt 2025-12-05 11:28:58 +03:00
35 changed files with 2920 additions and 560 deletions

View File

@@ -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
(

View 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"
}

View File

@@ -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}

View File

@@ -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}
@@ -1199,8 +1199,8 @@ test_runner()
[ -f "$script" ] || continue
unset -f $FUNC
. "$script"
echo
existf $FUNC && {
echo
echo "* script : $TEST/$(basename "$script")"
$FUNC "$@"
}
@@ -1354,7 +1354,7 @@ check_domain_http_udp()
[ "$SKIP_PKTWS" = 1 ] || {
echo
echo preparing $PKTWSD redirection
mdig_resolve_all $IPV ips $4
mdig_resolve_all $IPV ips $3
pktws_ipt_prepare_udp $2 "$ips"
pktws_check_domain_http3_bypass $1 $3

View File

@@ -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 parm10 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,14 @@ 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="${AUTOHOSTLIST_INCOMING_MAXSEQ:+--hostlist-auto-incoming-maxseq=$AUTOHOSTLIST_INCOMING_MAXSEQ}"
parm10="${AUTOHOSTLIST_UDP_IN:+--hostlist-auto-udp-in=$AUTOHOSTLIST_UDP_IN}"
parm11="${AUTOHOSTLIST_UDP_OUT:+--hostlist-auto-udp-out=$AUTOHOSTLIST_UDP_OUT}"
parm12="--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}${parm9:+ $parm9}${parm10:+ $parm10}${parm11:+ $parm11}"
parmNA="$parm1${parm2:+ $parm2}${parm3:+ $parm3}${parm10:+ $parm12}"
}
v="$(replace_str $HOSTLIST_NOAUTO_MARKER "$parmNA" "$v")"
v="$(replace_str $HOSTLIST_MARKER "$parm" "$v")"

View File

@@ -97,17 +97,19 @@ nft_activate_chain4()
{
# $1 - chain name
# $2 - saddr/daddr
local b rule markf= act
local b rule markf= act flt_ifname
[ "$DISABLE_IPV4" = "1" ] || {
eval act="\$${1}_act4"
[ -n "$act" ] && return
b=0
nft_wanif_filter_present && b=1
flt_ifname="oifname"
starts_with "$1" pre && flt_ifname="iifname"
[ "$2" = daddr ] && markf=$(nft_mark_filter)
rule="meta mark and $DESYNC_MARK == 0 $markf"
[ $b = 1 ] && rule="$rule oifname @wanif"
[ $b = 1 ] && rule="$rule $flt_ifname @wanif"
rule="$rule ip $2 != @nozapret jump $1"
nft_rule_exists ${1}_hook "$rule" || nft_add_rule ${1}_hook $rule
@@ -118,17 +120,19 @@ nft_activate_chain6()
{
# $1 - chain name
# $2 - saddr/daddr
local b rule markf=
local b rule markf= act flt_ifname
[ "$DISABLE_IPV6" = "1" ] || {
eval act="\$${1}_act6"
[ -n "$act" ] && return
b=0
nft_wanif6_filter_present && b=1
flt_ifname="oifname"
starts_with "$1" pre && flt_ifname="iifname"
[ "$2" = daddr ] && markf=$(nft_mark_filter)
rule="meta mark and $DESYNC_MARK == 0 $markf"
[ $b = 1 ] && rule="$rule oifname @wanif6"
[ $b = 1 ] && rule="$rule $flt_ifname @wanif6"
rule="$rule ip6 $2 != @nozapret6 jump $1"
nft_rule_exists ${1}_hook "$rule" || nft_add_rule ${1}_hook $rule

View File

@@ -26,9 +26,15 @@ 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
# NOTE : in order for these adjustment to work it's required to redirect enough starting packets
# NOTE : set PKT_IN, PKT_OUT variables appropriately
AUTOHOSTLIST_INCOMING_MAXSEQ=4096
AUTOHOSTLIST_RETRANS_MAXSEQ=32768
AUTOHOSTLIST_RETRANS_THRESHOLD=3
AUTOHOSTLIST_FAIL_THRESHOLD=3
AUTOHOSTLIST_FAIL_TIME=60
AUTOHOSTLIST_UDP_IN=1
AUTOHOSTLIST_UDP_OUT=4
# 1 = debug autohostlist positives to ipset/zapret-hosts-auto-debug.log
AUTOHOSTLIST_DEBUGLOG=0
@@ -60,11 +66,10 @@ NFQWS2_PORTS_TCP=80,443
NFQWS2_PORTS_UDP=443
# PKT_OUT means connbytes dir original
# PKT_IN means connbytes dir reply
# this is --dpi-desync-cutoff=nX kernel mode implementation for linux. it saves a lot of CPU.
NFQWS2_TCP_PKT_OUT=$((6+$AUTOHOSTLIST_RETRANS_THRESHOLD))
NFQWS2_TCP_PKT_IN=3
NFQWS2_UDP_PKT_OUT=$((6+$AUTOHOSTLIST_RETRANS_THRESHOLD))
NFQWS2_UDP_PKT_IN=0
NFQWS2_TCP_PKT_OUT=20
NFQWS2_TCP_PKT_IN=10
NFQWS2_UDP_PKT_OUT=5
NFQWS2_UDP_PKT_IN=3
# redirect outgoing traffic without connbytes limiter and incoming with connbytes limiter
# normally it's needed only for stateless DPI that matches every packet in a single TCP session
# typical example are plain HTTP keep alives

View File

@@ -47,5 +47,61 @@ v0.4
* 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
v0.7
* nfqws2, zapret-lib : fix non-working % and # arg substitution under orchestrator
* nfqws2, zapret-lib : structure conntrack in/out positions. pass in desync.track.pos.{client,server,direct,reverse} position tables
* nfqws2: autohostlist: trigger RST and http redirect failures only within specified relative sequence
* nfqws2: autohostlist: trigger http redirect failure if payload is http_req without connection proto check
* nfqws2: push desync.track.pos.dt as float with nsec accuracy
* zapret-auto: override host autostate key in automate_host_record
* nfqws2: rewrite udp autohostlist failure detector logic
v0.7.1
* init.d: nft fix non-working incoming redirect
* nfqws2: cancel reasm if server window size is smaller than expected reasm size
* nfqws2: add EOL at the end of truncated buffered DLOG line if it's too large. increase log line buffer
* nfqws2: autohostlist reset fail counter if udp_in > threshold
* nfqws2: reduced default retrans maxseq to 32768
* nfqws2: solved inability to get SSID using nl80211 on kernels 5.19+
v0.7.2
* zapret-lib: fix broken is_retransmission()
* zapret-auto: add success detector logic
* nfqws2: clean lua cutoff on profile change

View File

@@ -5,3 +5,7 @@ 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.
v3
* restructured desync.track. pass positions in desync.track.pos.{client,server,direct,reverse}
code relying on conntrack counters and sequence numbers must be rewritten

1183
docs/manual.md Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,3 @@
# zapret2 v0.2
## Зачем это нужно
Автономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь

View File

@@ -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()

View File

@@ -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"

View File

@@ -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)

429
lua/zapret-auto.lua Normal file
View File

@@ -0,0 +1,429 @@
-- 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 and success detectors test potential block conditions for orchestrators
-- standard host key generator for per-host storage
-- arg: reqhost - require hostname, do not work with ip
-- arg: nld=N - cut hostname to N level domain. NLD=2 static.intranet.microsoft.com => microsoft.com
function standard_hostkey(desync)
local hostkey = desync.track and desync.track.hostname
if hostkey then
if desync.arg.nld and tonumber(desync.arg.nld)>0 then
-- dissect_nld returns nil if domain is invalid or does not have this NLD
-- fall back to original hostkey if it fails
local hktemp = dissect_nld(hostkey, tonumber(desync.arg.nld))
if hktemp then
hostkey = hktemp
end
end
elseif not desync.arg.reqhost then
hostkey = host_ip(desync)
end
-- prevent nld for ip addresses
return hostkey
end
-- per-host storage
-- arg: key - a string - table name inside autostate table. to allow multiple orchestrator instances to use single host storage
-- arg: hostkey - hostkey generator function name
function automate_host_record(desync)
local hostkey, hkf, askey
if desync.arg.hostkey then
if type(_G[desync.arg.hostkey])~="function" then
error("automate: invalid hostkey function '"..desync.arg.hostkey.."'")
end
hkf = _G[desync.arg.hostkey]
else
hkf = standard_hostkey
end
hostkey = hkf(desync)
if not hostkey then
DLOG("automate: host record key unavailable")
return nil
end
askey = (desync.arg.key and #desync.arg.key>0) and desync.arg.key or desync.func_instance
DLOG("automate: host record key 'autostate."..askey.."."..hostkey.."'")
if not autostate then
autostate = {}
end
if not autostate[askey] then
autostate[askey] = {}
end
if not autostate[askey][hostkey] then
autostate[askey][hostkey] = {}
end
return autostate[askey][hostkey]
end
-- per-connection storage
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
-- resets failure counter if it has started counting
function automate_failure_counter_reset(hrec)
if hrec.failure_counter then
DLOG("automate: failure counter reset")
hrec.failure_counter = nil
end
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
function standard_detector_defaults(arg)
return {
inseq = tonumber(arg.inseq) or 4096,
retrans = tonumber(arg.retrans) or 3,
maxseq = tonumber(arg.maxseq) or 32768,
udp_in = tonumber(arg.udp_in) or 1,
udp_out = tonumber(arg.udp_out) or 4,
no_http_redirect = arg.no_http_redirect,
no_rst = arg.no_rst
}
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: maxseq=<rseq> - tcp: test retransmissions only within this relative sequence. default is 32K
-- arg: retrans=N - tcp: retrans count threshold. default is 3
-- arg: inseq=<rseq> - tcp: maximum relative sequence number to treat incoming RST as DPI reset. default is 4K
-- arg: no_http_redirect - tcp: disable http_reply dpi redirect trigger
-- arg: no_rst - tcp: disable incoming RST trigger
-- arg: udp_out - udp: >= outgoing udp packets. default is 4
-- arg: udp_in - udp: with <= incoming udp packets. default is 1
function standard_failure_detector(desync, crec)
local arg = standard_detector_defaults(desync.arg)
local trigger = false
if desync.dis.tcp then
local seq = pos_get(desync,'s')
if desync.outgoing then
if #desync.dis.payload>0 and arg.retrans and arg.maxseq>0 and seq<=arg.maxseq and (crec.retrans or 0)<arg.retrans then
if is_retransmission(desync) then
crec.retrans = crec.retrans and (crec.retrans+1) or 1
DLOG("standard_failure_detector: retransmission "..crec.retrans.."/"..arg.retrans)
trigger = crec.retrans>=arg.retrans
end
end
else
if not arg.no_rst and arg.inseq>0 and bitand(desync.dis.tcp.th_flags, TH_RST)~=0 and seq>=1 then
trigger = seq<=arg.inseq
if b_debug then
if trigger then
DLOG("standard_failure_detector: incoming RST s"..seq.." in range s"..arg.inseq)
else
DLOG("standard_failure_detector: not counting incoming RST s"..seq.." beyond s"..arg.inseq)
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 arg.udp_out>0 then
local pos_out = pos_get(desync,'n',false)
local pos_in = pos_get(desync,'n',true)
trigger = pos_out>=arg.udp_out and pos_in<=arg.udp_in
if trigger then
if b_debug then
DLOG("standard_failure_detector: arg.udp_out "..pos_out..">="..arg.udp_out.." arg.udp_in "..pos_in.."<="..arg.udp_in)
end
end
end
end
end
return trigger
end
-- standard success detector
-- success means previous failures were temporary and counter should be reset
-- detected successes:
-- tcp: outgoing seq is beyond 'maxseq' and maxseq>0
-- tcp: incoming seq is beyond 'inseq' and inseq>0
-- udp: incoming packets count > `udp_in` and `udp_out`>0
-- arg: maxseq=<rseq> - tcp: success if outgoing relative sequence is beyond this value. default is 32K
-- arg: inseq=<rseq> - tcp: success if incoming relative sequence is beyond this value. default is 4K
-- arg: udp_out - udp : must be nil or >0 to test udp_in
-- arg: udp_in - udp: if number if incoming packets > udp_in it means success
function standard_success_detector(desync, crec)
local arg = standard_detector_defaults(desync.arg)
if desync.dis.tcp then
local seq = pos_get(desync,'s')
if desync.outgoing then
if arg.maxseq>0 and seq>arg.maxseq then
DLOG("standard_success_detector: outgoing s"..seq.." is beyond s"..arg.maxseq..". treating connection as successful")
return true
end
else
if arg.inseq>0 and seq>arg.inseq then
DLOG("standard_success_detector: incoming s"..seq.." is beyond s"..arg.inseq..". treating connection as successful")
return true
end
end
elseif desync.dis.udp then
if not desync.outgoing then
local pos = pos_get(desync,'n')
if arg.udp_out>0 and pos>arg.udp_in then
if b_debug then
DLOG("standard_success_detector: arg.udp_in "..pos..">"..arg.udp_in)
end
return true
end
end
end
return false
end
-- calls success and failure detectors
-- resets counter if success is detected
-- increases counter if failure is detected
-- returns true if failure counter exceeds threshold
function automate_failure_check(desync, hrec, crec)
if crec.nocheck then return false end
local failure_detector, success_detector
if desync.arg.failure_detector then
if type(_G[desync.arg.failure_detector])~="function" then
error("automate: invalid failure detector function '"..desync.arg.failure_detector.."'")
end
failure_detector = _G[desync.arg.failure_detector]
else
failure_detector = standard_failure_detector
end
if desync.arg.success_detector then
if type(_G[desync.arg.success_detector])~="function" then
error("automate: invalid success detector function '"..desync.arg.success_detector.."'")
end
success_detector = _G[desync.arg.success_detector]
else
success_detector = standard_success_detector
end
if success_detector(desync, crec) then
crec.nocheck = true
DLOG("automate: success detected")
automate_failure_counter_reset(hrec)
return false
end
if failure_detector(desync, crec) then
crec.nocheck = true
DLOG("automate: failure detected")
local fails = tonumber(desync.arg.fails) or 3
local maxtime = tonumber(desync.arg.time) or 60
return automate_failure_counter(hrec, crec, fails, maxtime)
end
return false
end
-- circularily change strategy numbers when failure count reaches threshold ('fails')
-- 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: success_detector - success detector function name
-- arg: failure_detector - failure detector function name
-- args for failure detector - see standard_failure_detector or your own detector
-- args for success detector - see standard_success_detector or your own detector
-- test case: nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-auto.lua --in-range=-s34228 --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)
if automate_failure_check(desync, hrec, crec) then
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
DLOG("circular: current strategy "..hrec.nstrategy)
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(desync, 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

View File

@@ -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
@@ -37,16 +37,24 @@ function pktdebug(ctx, desync)
end
-- basic desync function
-- prints function args
function argdebug(ctx,desync)
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)
function posdebug(ctx, desync)
if not desync.track then
DLOG("posdebug: no track")
return
end
local s="posdebug: "..(desync.outgoing and "out" or "in").." time +"..desync.track.pos.dt.."s direct"
for i,pos in pairs({'n','d','b','s','p'}) do
s=s.." "..pos..pos_get(desync, pos, false)
end
s=s.." reverse"
for i,pos in pairs({'n','d','b','s','p'}) do
s=s.." "..pos..pos_get(desync, pos, true)
end
s=s.." payload "..#desync.dis.payload
if desync.reasm_data then
@@ -61,76 +69,201 @@ function posdebug(ctx,desync)
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
function apply_arg_prefix(desync)
for a,v in pairs(desync.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
if c=='#' then
local blb = blob(desync,string.sub(v,2))
desync.arg[a] = (type(blb)=='string' or type(blb)=='table') and #blb or 0
elseif c=='%' then
desync.arg[a] = blob(desync,string.sub(v,2))
elseif c=='\\' then
c = string.sub(v,2,2);
if c=='#' or c=='%' then
arg[a] = string.sub(v,2)
desync.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, plan)
desync.func = plan.func
desync.func_n = plan.func_n
desync.func_instance = plan.func_instance
desync.arg = deepcopy(plan.arg)
apply_arg_prefix(desync.arg)
-- NOTE : to not lose VERDICT_MODIFY dissect changes pass original desync table
-- NOTE : if a copy was passed and VERDICT_MODIFY returned you must copy modified dissect back to desync table or resend it and return VERDICT_DROP
-- NOTE : args and some fields are substituted. if you need them - make a copy before calling this.
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)
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, plan)
for i=1,#plan do
if not payload_match_filter(desync.l7payload, plan[i].payload_filter) then
DLOG("orchestrator: not calling '"..desync.func_instance.."' because payload '"..desync.l7payload.."' does not match filter '"..plan[i].payload_filter.."'")
elseif not pos_check_range(desync, plan[i].range) then
DLOG("orchestrator: not calling '"..desync.func_instance.."' because pos "..pos_str(desync,plan[i].range.from).." "..pos_str(desync,plan[i].range.to).." is out of range '"..pos_range_str(plan[i].range).."'")
else
apply_execution_plan(desync, plan[i])
DLOG("orchestrator: executing '"..desync.func_instance.."'")
_G[plan[i].func](ctx, desync)
end
function replay_execution_plan(desync)
local verdict = VERDICT_PASS
while true do
local instance = plan_instance_pop(desync)
if not instance then break end
verdict = plan_instance_execute(desync, 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)
local plan = execution_plan(ctx)
if #plan>0 then
DLOG("orchestrator: taking over upcoming desync instances")
local desync_copy = deepcopy(desync)
execution_plan_cancel(ctx)
replay_execution_plan(desync_copy, plan)
end
DLOG("orchestrator: taking over upcoming desync instances")
orchestrate(ctx, desync)
return replay_execution_plan(desync)
end
-- these function duplicate range check logic from C code
-- 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
function pos_get_pos(track_pos, mode)
if track_pos then
if mode=='n' then
return desync.outgoing and desync.track.pcounter_orig or desync.track.pcounter_reply
return track_pos.pcounter
elseif mode=='d' then
return desync.outgoing and desync.track.pdcounter_orig or desync.track.pdcounter_reply
return track_pos.pdcounter
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 (desync.track.tcp.seq - desync.track.tcp.seq0) or (desync.track.tcp.ack - desync.track.tcp.ack0)
return track_pos.pbcounter
elseif track_pos.tcp then
if mode=='s' then
return track_pos.tcp.rseq
elseif mode=='p' then
return track_pos.tcp.pos
end
end
end
return 0
end
function pos_get(desync, mode, reverse)
if desync.track then
local track_pos = reverse and desync.track.pos.reverse or desync.track.pos.direct
return pos_get_pos(track_pos,mode)
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
@@ -164,7 +297,9 @@ 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.pos.direct.tcp and 0==bitand(u32add(desync.track.pos.direct.tcp.uppos_prev, -desync.track.pos.direct.tcp.pos), 0x80000000)
end
-- prepare standard rawsend options from desync
-- repeats - how many time send the packet
@@ -236,12 +371,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
@@ -429,6 +567,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)
@@ -641,10 +861,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)))
@@ -655,7 +875,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
@@ -872,7 +1092,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
@@ -888,6 +1107,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
@@ -898,6 +1118,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
@@ -924,10 +1145,10 @@ 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
@@ -1015,6 +1236,18 @@ function genhost(len, template)
end
end
-- return ip addr of target host in text form
function host_ip(desync)
return desync.target.ip and ntop(desync.target.ip) or desync.target.ip6 and ntop(desync.target.ip6)
end
-- return hostname of target host 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 host_ip(desync)
end
function is_absolute_path(path)
if string.sub(path,1,1)=='/' then return true end
local un = uname()

View File

@@ -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

View File

@@ -37,7 +37,7 @@ void ConntrackClearHostname(t_ctrack *track)
static void ConntrackClearTrack(t_ctrack *track)
{
ConntrackClearHostname(track);
ReasmClear(&track->reasm_orig);
ReasmClear(&track->reasm_client);
rawpacket_queue_destroy(&track->delayed);
luaL_unref(params.L, LUA_REGISTRYINDEX, track->lua_state);
luaL_unref(params.L, LUA_REGISTRYINDEX, track->lua_instance_cutoff);
@@ -102,8 +102,7 @@ static void ConntrackInitTrack(t_ctrack *t)
{
memset(t, 0, sizeof(*t));
t->l7proto = L7_UNKNOWN;
t->pos.scale_orig = t->pos.scale_reply = SCALE_NONE;
time(&t->pos.t_start);
t->pos.client.scale = t->pos.server.scale = SCALE_NONE;
rawpacket_queue_init(&t->delayed);
lua_newtable(params.L);
t->lua_state = luaL_ref(params.L, LUA_REGISTRYINDEX);
@@ -128,6 +127,36 @@ static t_conntrack_pool *ConntrackNew(t_conntrack_pool **pp, const t_conn *c)
return ctnew;
}
static void ConntrackApplyPos(const struct tcphdr *tcp, t_ctrack *t, bool bReverse, uint32_t len_payload)
{
uint8_t scale;
uint16_t mss;
t_ctrack_position *direct, *reverse;
direct = bReverse ? &t->pos.server : &t->pos.client;
reverse = bReverse ? &t->pos.client : &t->pos.server;
scale = tcp_find_scale_factor(tcp);
mss = ntohs(tcp_find_mss(tcp));
direct->seq_last = ntohl(tcp->th_seq);
direct->pos = direct->seq_last + len_payload;
reverse->pos = reverse->seq_last = ntohl(tcp->th_ack);
if (t->pos.state == SYN)
direct->uppos_prev = direct->uppos = direct->pos;
else if (len_payload)
{
direct->uppos_prev = direct->uppos;
if (!((direct->pos - direct->uppos) & 0x80000000))
direct->uppos = direct->pos;
}
direct->winsize = ntohs(tcp->th_win);
direct->winsize_calc = direct->winsize;
if (direct->scale != SCALE_NONE) direct->winsize_calc <<= direct->scale;
if (mss && !direct->mss) direct->mss = mss;
if (scale != SCALE_NONE) direct->scale = scale;
}
// non-tcp packets are passed with tcphdr=NULL but len_payload filled
static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr *tcphdr, uint32_t len_payload)
{
@@ -136,16 +165,16 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (bReverse)
{
t->pos.pcounter_reply++;
t->pos.pdcounter_reply += !!len_payload;
t->pos.pbcounter_reply += len_payload;
t->pos.server.pcounter++;
t->pos.server.pdcounter += !!len_payload;
t->pos.server.pbcounter += len_payload;
}
else
{
t->pos.pcounter_orig++;
t->pos.pdcounter_orig += !!len_payload;
t->pos.pbcounter_orig += len_payload;
t->pos.client.pcounter++;
t->pos.client.pdcounter += !!len_payload;
t->pos.client.pbcounter += len_payload;
}
if (tcphdr)
@@ -153,16 +182,16 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (tcp_syn_segment(tcphdr))
{
if (t->pos.state != SYN) ConntrackReInitTrack(t); // erase current entry
t->pos.seq0 = ntohl(tcphdr->th_seq);
t->pos.client.seq0 = ntohl(tcphdr->th_seq);
}
else if (tcp_synack_segment(tcphdr))
{
// ignore SA dups
uint32_t seq0 = ntohl(tcphdr->th_ack) - 1;
if (t->pos.state != SYN && t->pos.seq0 != seq0)
if (t->pos.state != SYN && t->pos.client.seq0 != seq0)
ConntrackReInitTrack(t); // erase current entry
if (!t->pos.seq0) t->pos.seq0 = seq0;
t->pos.ack0 = ntohl(tcphdr->th_seq);
if (!t->pos.client.seq0) t->pos.client.seq0 = seq0;
t->pos.server.seq0 = ntohl(tcphdr->th_seq);
}
else if (tcphdr->th_flags & (TH_FIN | TH_RST))
{
@@ -173,49 +202,28 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct tcphdr
if (t->pos.state == SYN)
{
t->pos.state = ESTABLISHED;
if (!bReverse && !t->pos.ack0) t->pos.ack0 = ntohl(tcphdr->th_ack) - 1;
if (!bReverse && !t->pos.server.seq0) t->pos.server.seq0 = ntohl(tcphdr->th_ack) - 1;
}
}
scale = tcp_find_scale_factor(tcphdr);
mss = ntohs(tcp_find_mss(tcphdr));
if (bReverse)
{
t->pos.pos_orig = t->pos.seq_last = ntohl(tcphdr->th_ack);
t->pos.ack_last = ntohl(tcphdr->th_seq);
t->pos.pos_reply = t->pos.ack_last + len_payload;
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->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);
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;
}
ConntrackApplyPos(tcphdr, t, bReverse, len_payload);
}
else
{
if (bReverse)
{
t->pos.ack_last = t->pos.pos_reply;
t->pos.pos_reply += len_payload;
t->pos.server.seq_last = t->pos.server.pos;
t->pos.server.pos += len_payload;
}
else
{
t->pos.seq_last = t->pos.pos_orig;
t->pos.pos_orig += len_payload;
t->pos.client.seq_last = t->pos.client.pos;
t->pos.client.pos += len_payload;
}
}
time(&t->pos.t_last);
clock_gettime(CLOCK_REALTIME, &t->pos.t_last);
// make sure t_start gets exactly the same value as first t_last
if (!t->t_start.tv_sec) t->t_start = 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)
@@ -311,13 +319,15 @@ bool ConntrackPoolDrop(t_conntrack *p, const struct ip *ip, const struct ip6_hdr
void ConntrackPoolPurge(t_conntrack *p)
{
time_t tidle, tnow = time(NULL);
time_t tidle;
struct timespec tnow;
t_conntrack_pool *t, *tmp;
if ((tnow - p->t_last_purge) >= p->t_purge_interval)
if (clock_gettime(CLOCK_REALTIME, &tnow)) return;
if ((tnow.tv_sec - p->t_last_purge) >= p->t_purge_interval)
{
HASH_ITER(hh, p->pool, t, tmp) {
tidle = tnow - t->track.pos.t_last;
tidle = tnow.tv_sec - t->track.pos.t_last.tv_sec;
if (t->track.b_cutoff ||
(t->conn.l4proto == IPPROTO_TCP && (
(t->track.pos.state == SYN && tidle >= p->timeout_syn) ||
@@ -329,7 +339,7 @@ void ConntrackPoolPurge(t_conntrack *p)
HASH_DEL(p->pool, t); ConntrackFreeElem(t);
}
}
p->t_last_purge = tnow;
p->t_last_purge = tnow.tv_sec;
}
}
@@ -341,29 +351,31 @@ static void taddr2str(uint8_t l3proto, const t_addr *a, char *buf, size_t bufsiz
void ConntrackPoolDump(const t_conntrack *p)
{
t_conntrack_pool *t, *tmp;
struct timespec tnow;
char sa1[40], sa2[40];
time_t tnow = time(NULL);
if (clock_gettime(CLOCK_REALTIME, &tnow)) return;
HASH_ITER(hh, p->pool, t, tmp) {
taddr2str(t->conn.l3proto, &t->conn.src, sa1, sizeof(sa1));
taddr2str(t->conn.l3proto, &t->conn.dst, sa2, sizeof(sa2));
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 ",
printf("%s [%s]:%u => [%s]:%u : %s : t0=%llu last=t0+%llu now=last+%llu client=d%llu/n%llu/b%llu server=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.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);
(unsigned long long)t->track.t_start.tv_sec, (unsigned long long)(t->track.pos.t_last.tv_sec - t->track.t_start.tv_sec), (unsigned long long)(tnow.tv_sec - t->track.pos.t_last.tv_sec),
(unsigned long long)t->track.pos.client.pdcounter, (unsigned long long)t->track.pos.client.pcounter, (unsigned long long)t->track.pos.client.pbcounter,
(unsigned long long)t->track.pos.server.pdcounter, (unsigned long long)t->track.pos.server.pcounter, (unsigned long long)t->track.pos.server.pbcounter);
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.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);
printf("seq0=%u rseq=%u client.pos=%u ack0=%u rack=%u server.pos=%u client.mss=%u server.mss=%u client.wsize=%u:%d server.wsize=%u:%d",
t->track.pos.client.seq0, t->track.pos.client.seq_last - t->track.pos.client.seq0, t->track.pos.client.pos - t->track.pos.client.seq0,
t->track.pos.server.seq0, t->track.pos.server.seq_last - t->track.pos.server.seq0, t->track.pos.server.pos - t->track.pos.server.seq0,
t->track.pos.client.mss, t->track.pos.server.mss,
t->track.pos.client.winsize, t->track.pos.client.scale == SCALE_NONE ? -1 : t->track.pos.client.scale,
t->track.pos.server.winsize, t->track.pos.server.scale == SCALE_NONE ? -1 : t->track.pos.server.scale);
else
printf("rseq=%u pos_orig=%u rack=%u pos_reply=%u",
t->track.pos.seq_last, t->track.pos.pos_orig,
t->track.pos.ack_last, t->track.pos.pos_reply);
printf("rseq=%u client.pos=%u rack=%u server.pos=%u",
t->track.pos.client.seq_last, t->track.pos.client.pos,
t->track.pos.server.seq_last, t->track.pos.server.pos);
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 +406,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)

View File

@@ -43,7 +43,7 @@ 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;
@@ -54,15 +54,16 @@ typedef struct
bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache
uint8_t ipproto;
struct timespec t_start;
// 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;
t_ctrack_positions pos;
struct desync_profile *dp; // desync profile cache
bool dp_search_complete;
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 failure_detect_finalized;
uint8_t incoming_ttl;
@@ -79,7 +80,7 @@ typedef struct
int lua_state; // registry index of associated LUA object
int lua_instance_cutoff; // registry index of per connection function instance cutoff table
t_reassemble reasm_orig;
t_reassemble reasm_client;
struct rawpacket_tailhead delayed;
} t_ctrack;

View File

@@ -14,19 +14,26 @@ 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 seq_last, ack_last; // TCP: last seen seq and ack UDP: sum of all seen payload lenghts NOT including current
uint64_t pcounter; // packet counter
uint64_t pdcounter; // data packet counter (with payload)
uint64_t pbcounter; // transferred byte counter. includes retransmissions. it's not the same as relative seq.
uint32_t pos; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
uint32_t uppos; // max seen position. useful to detect retransmissions
uint32_t uppos_prev; // previous max seen position. useful to detect retransmissions
uint32_t seq_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;
uint32_t seq0; // starting seq and ack
uint16_t winsize; // last seen window size
uint16_t mss;
uint32_t winsize_calc; // calculated window size
uint8_t scale; // last seen window scale factor. SCALE_NONE if none
} t_ctrack_position;
typedef struct
{
struct timespec t_last;
t_connstate state;
t_ctrack_position client, server;
}
t_ctrack_positions;

View File

@@ -40,9 +40,6 @@
#include <linux/genetlink.h>
#include <libmnl/libmnl.h>
#include <net/if.h>
#define _LINUX_IF_H // prevent conflict between linux/if.h and net/if.h in old gcc 4.x
#include <linux/wireless.h>
#include <sys/ioctl.h>
#endif
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment)
@@ -1578,9 +1575,9 @@ bool rawsend_queue(struct rawpacket_tailhead *q)
// linux-specific wlan retrieval implementation
typedef void netlink_prepare_nlh_cb_t(struct nlmsghdr *nlh);
typedef void netlink_prepare_nlh_cb_t(struct nlmsghdr *nlh, void *param);
static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, uint16_t flags, uint8_t cmd, uint8_t version, netlink_prepare_nlh_cb_t cb_prepare_nlh, mnl_cb_t cb_data, void *data)
static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, uint16_t flags, uint8_t cmd, uint8_t version, netlink_prepare_nlh_cb_t cb_prepare_nlh, void *prepare_data, mnl_cb_t cb_data, void *data)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
@@ -1595,7 +1592,7 @@ static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, u
genl->cmd = cmd;
genl->version = version;
if (cb_prepare_nlh) cb_prepare_nlh(nlh);
if (cb_prepare_nlh) cb_prepare_nlh(nlh, prepare_data);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
{
@@ -1619,7 +1616,7 @@ static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, u
return false;
}
static void wlan_id_prepare(struct nlmsghdr *nlh)
static void wlan_id_prepare(struct nlmsghdr *nlh, void *param)
{
mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, "nl80211");
}
@@ -1651,7 +1648,7 @@ static int wlan_id_cb(const struct nlmsghdr *nlh, void *data)
static uint16_t wlan_get_family_id(struct mnl_socket* nl)
{
uint16_t id;
return netlink_genl_simple_transact(nl, GENL_ID_CTRL, NLM_F_REQUEST | NLM_F_ACK, CTRL_CMD_GETFAMILY, 1, wlan_id_prepare, wlan_id_cb, &id) ? id : 0;
return netlink_genl_simple_transact(nl, GENL_ID_CTRL, NLM_F_REQUEST | NLM_F_ACK, CTRL_CMD_GETFAMILY, 1, wlan_id_prepare, NULL, wlan_id_cb, &id) ? id : 0;
}
static int wlan_info_attr_cb(const struct nlattr *attr, void *data)
@@ -1686,42 +1683,130 @@ static int wlan_info_attr_cb(const struct nlattr *attr, void *data)
}
return MNL_CB_OK;
}
struct wlan_info_req
{
struct wlan_interface_collection *wc;
bool bReqSSID;
};
static int wlan_info_cb(const struct nlmsghdr *nlh, void *data)
{
int ret;
struct wlan_info_req *wr = (struct wlan_info_req*)data;
if (wr->wc->count>=WLAN_INTERFACE_MAX) return MNL_CB_OK;
memset(wr->wc->wlan + wr->wc->count,0,sizeof(struct wlan_interface));
ret = mnl_attr_parse(nlh, sizeof(struct genlmsghdr), wlan_info_attr_cb, wr->wc->wlan + wr->wc->count);
if (ret>=0 && (!wr->bReqSSID || *wr->wc->wlan[wr->wc->count].ssid) && *wr->wc->wlan[wr->wc->count].ifname && wr->wc->wlan[wr->wc->count].ifindex)
wr->wc->count++;
return ret;
}
static bool wlan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w, bool bReqSSID)
{
struct wlan_info_req req = { .bReqSSID = bReqSSID, .wc = w };
return netlink_genl_simple_transact(nl, wlan_family_id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0, NULL, NULL, wlan_info_cb, &req);
}
static void scan_prepare(struct nlmsghdr *nlh, void *param)
{
mnl_attr_put_u32(nlh, NL80211_ATTR_IFINDEX, *(int*)param);
}
static uint8_t *find_ie(uint8_t *buf, size_t len, uint8_t ie)
{
while (len>=2)
{
if (len<(2+buf[1])) break;
if (buf[0]==ie) return buf;
buf+=buf[1]+2;
len-=buf[1]+2;
}
return NULL;
}
static int scan_info_attr_cb(const struct nlattr *attr, void *data)
{
struct wlan_interface *wlan = (struct wlan_interface *)data;
const struct nlattr *nested;
uint8_t *payload, *ie;
uint16_t payload_len;
bool ok;
switch(mnl_attr_get_type(attr))
{
case NL80211_ATTR_IFINDEX:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
{
DLOG_PERROR("mnl_attr_validate");
return MNL_CB_ERROR;
}
wlan->ifindex = mnl_attr_get_u32(attr);
if (!if_indextoname(wlan->ifindex, wlan->ifname))
DLOG_PERROR("if_indextoname");
break;
case NL80211_ATTR_BSS:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
{
DLOG_PERROR("mnl_attr_validate");
return MNL_CB_ERROR;
}
ok = false;
mnl_attr_for_each_nested(nested, attr)
{
if (mnl_attr_get_type(nested)==NL80211_BSS_STATUS)
{
uint32_t status = mnl_attr_get_u32(nested);
if (status==NL80211_BSS_STATUS_ASSOCIATED || status==NL80211_BSS_STATUS_AUTHENTICATED || status==NL80211_BSS_STATUS_IBSS_JOINED)
{
ok=1;
break;
}
}
}
if (!ok) break;
mnl_attr_for_each_nested(nested, attr)
{
switch(mnl_attr_get_type(nested))
{
case NL80211_BSS_INFORMATION_ELEMENTS:
payload_len = mnl_attr_get_payload_len(nested);
payload = mnl_attr_get_payload(nested);
ie = find_ie(payload,payload_len,0);
if (ie)
{
uint8_t l = ie[1];
if (l>=(sizeof(wlan->ssid))) l=sizeof(wlan->ssid)-1;
memcpy(wlan->ssid,ie+2,l);
wlan->ssid[l]=0;
}
break;
}
}
break;
}
return MNL_CB_OK;
}
static int scan_info_cb(const struct nlmsghdr *nlh, void *data)
{
int ret;
struct wlan_interface_collection *wc = (struct wlan_interface_collection*)data;
if (wc->count>=WLAN_INTERFACE_MAX) return MNL_CB_OK;
memset(wc->wlan+wc->count,0,sizeof(wc->wlan[0]));
ret = mnl_attr_parse(nlh, sizeof(struct genlmsghdr), wlan_info_attr_cb, wc->wlan+wc->count);
if (ret>=0 && *wc->wlan[wc->count].ifname && wc->wlan[wc->count].ifindex)
{
if (*wc->wlan[wc->count].ssid)
wc->count++;
else
{
// sometimes nl80211 does not return SSID but wireless ext does
int wext_fd = socket(AF_INET, SOCK_DGRAM, 0);
if (wext_fd!=-1)
{
struct iwreq req;
snprintf(req.ifr_ifrn.ifrn_name,sizeof(req.ifr_ifrn.ifrn_name),"%s",wc->wlan[wc->count].ifname);
req.u.essid.pointer = wc->wlan[wc->count].ssid;
req.u.essid.length = sizeof(wc->wlan[wc->count].ssid);
req.u.essid.flags = 0;
if (ioctl(wext_fd, SIOCGIWESSID, &req)!=-1)
if (*wc->wlan[wc->count].ssid)
wc->count++;
close(wext_fd);
}
}
}
ret = mnl_attr_parse(nlh, sizeof(struct genlmsghdr), scan_info_attr_cb, wc->wlan+wc->count);
if (ret>=0 && *wc->wlan[wc->count].ssid && *wc->wlan[wc->count].ifname && wc->wlan[wc->count].ifindex)
wc->count++;
return ret;
}
static bool wlan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w)
static bool scan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w)
{
return netlink_genl_simple_transact(nl, wlan_family_id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0, NULL, wlan_info_cb, w);
struct wlan_interface_collection wc_all = { .count = 0 };
// wlan_info does not return ssid since kernel 5.19
// it's used to enumerate all wifi interfaces then call scan_info on each
if (!wlan_info(nl, wlan_family_id, &wc_all, false)) return false;
for(int i=0;i<wc_all.count;i++)
if (!netlink_genl_simple_transact(nl, wlan_family_id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0, scan_prepare, (void*)&wc_all.wlan[i].ifindex, scan_info_cb, w))
return false;
return true;
}
static bool wlan_init80211(struct mnl_socket** nl)
{
if (!(*nl = mnl_socket_open(NETLINK_GENERIC)))
@@ -1755,7 +1840,7 @@ static bool wlan_info_rate_limited(struct mnl_socket* nl, uint16_t wlan_family_i
// do not purge too often to save resources
if (wlan_info_last != now)
{
bres = wlan_info(nl,wlan_family_id,w);
bres = scan_info(nl,wlan_family_id,w);
wlan_info_last = now;
}
return bres;
@@ -1781,10 +1866,6 @@ bool wlan_info_init(void)
}
return true;
}
bool wlan_info_get(void)
{
return wlan_info(nl_wifi, id_nl80211, &wlans);
}
bool wlan_info_get_rate_limited(void)
{
return wlan_info_rate_limited(nl_wifi, id_nl80211, &wlans);

View File

@@ -190,7 +190,6 @@ extern struct wlan_interface_collection wlans;
void wlan_info_deinit(void);
bool wlan_info_init(void);
bool wlan_info_get(void);
bool wlan_info_get_rate_limited(void);
const char *wlan_ssid_search_ifname(const char *ifname);
const char *wlan_ssid_search_ifidx(int ifidx);

View File

@@ -240,31 +240,38 @@ static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const ch
}
}
static bool is_retransmission(const t_ctrack_position *pos)
{
return !((pos->uppos_prev - pos->pos) & 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)
{
if (ctrack && ctrack->dp && ctrack->hostname_ah_check && ctrack->req_retrans_counter != RETRANS_COUNTER_STOP)
if (ctrack && ctrack->dp && ctrack->hostname_ah_check && !ctrack->failure_detect_finalized && ctrack->req_retrans_counter != RETRANS_COUNTER_STOP)
{
if (l4proto == IPPROTO_TCP)
if (l4proto == IPPROTO_TCP && ctrack->pos.state!=SYN)
{
if (!ctrack->req_seq_finalized || ctrack->req_seq_abandoned)
return false;
if (!seq_within(ctrack->pos.seq_last, ctrack->req_seq_start, ctrack->req_seq_end))
if (!seq_within(ctrack->pos.client.seq_last, ctrack->pos.client.seq0, ctrack->pos.client.seq0 + ctrack->dp->hostlist_auto_retrans_maxseq))
{
DLOG("req retrans : tcp seq %u not within the req range %u-%u. stop tracking.\n", ctrack->pos.seq_last, ctrack->req_seq_start, ctrack->req_seq_end);
ctrack->failure_detect_finalized = true;
DLOG("retrans : tcp seq %u not within range %u-%u. stop tracking.\n", ctrack->pos.client.seq_last, ctrack->pos.client.seq0, ctrack->pos.client.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->pos.client))
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->failure_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;
}
@@ -316,23 +323,55 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
}
}
}
static void fill_client_ip_port(const struct sockaddr *client, char *client_ip_port, size_t client_ip_port_size)
{
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)client, client_ip_port, client_ip_port_size);
else
*client_ip_port = 0;
}
static void process_retrans_fail(t_ctrack *ctrack, uint8_t proto, const struct sockaddr *client)
{
if (params.server) return; // no autohostlists in server mode
char client_ip_port[48];
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)client, client_ip_port, sizeof(client_ip_port));
else
*client_ip_port = 0;
fill_client_ip_port(client, client_ip_port, sizeof(client_ip_port));
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 (%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);
}
}
static void process_udp_fail(t_ctrack *ctrack, const t_ctrack_positions *tpos, const struct sockaddr *client)
{
// no autohostlists in server mode
if (!params.server && ctrack && ctrack->dp && ctrack->hostname && ctrack->hostname_ah_check &&
!ctrack->failure_detect_finalized && ctrack->dp->hostlist_auto_udp_out)
{
char client_ip_port[48];
if (!tpos) tpos = &ctrack->pos;
//printf("UDP_POS %u %u\n",tpos->client.pcounter, tpos->server.pcounter);
if (tpos->server.pcounter > ctrack->dp->hostlist_auto_udp_in)
{
// success
ctrack->failure_detect_finalized = true;
fill_client_ip_port(client, client_ip_port, sizeof(client_ip_port));
auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
}
else if (tpos->client.pcounter >= ctrack->dp->hostlist_auto_udp_out)
{
// failure
ctrack->failure_detect_finalized = true;
fill_client_ip_port(client, client_ip_port, sizeof(client_ip_port));
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : udp_in %u<=%u udp_out %u>=%u",
ctrack->hostname, ctrack->dp->n, PROFILE_NAME(ctrack->dp), client_ip_port, l7proto_str(ctrack->l7proto),
tpos->server.pcounter, ctrack->dp->hostlist_auto_udp_in,
tpos->client.pcounter, ctrack->dp->hostlist_auto_udp_out);
auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
}
}
}
static bool send_delayed(t_ctrack *ctrack)
{
@@ -344,23 +383,22 @@ static bool send_delayed(t_ctrack *ctrack)
return true;
}
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)
static bool rawpacket_queue_csum_fix(struct rawpacket_tailhead *q, const struct dissect *dis, const t_ctrack_positions *tpos, 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, pos);
return rawpacket_queue(q, dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, tpos);
}
static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload)
static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, uint32_t seq, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload)
{
ReasmClear(reasm);
if (sz <= szMax)
{
uint32_t seq = (proto == IPPROTO_TCP) ? ctrack->pos.seq_last : 0;
if (ReasmInit(reasm, sz, seq))
{
ReasmFeed(reasm, seq, data_payload, len_payload);
@@ -374,15 +412,24 @@ static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, si
DLOG("unexpected large payload for reassemble: size=%zu\n", sz);
return false;
}
static bool reasm_orig_start(t_ctrack *ctrack, uint8_t proto, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload)
static bool reasm_client_start(t_ctrack *ctrack, uint8_t proto, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload)
{
return reasm_start(ctrack, &ctrack->reasm_orig, proto, sz, szMax, data_payload, len_payload);
if (!ctrack) return false;
if (proto==IPPROTO_TCP && ctrack->pos.server.winsize_calc < sz)
{
// this is rare but possible situation
// server gave us too small tcp window
// client will not send all pieces of reasm
// if we drop packets and wait for next pieces we will see nothing but retransmissions
DLOG("reasm cancelled because server window size %u is smaller than expected reasm size %u\n", ctrack->pos.server.winsize_calc, sz);
return false;
}
return reasm_start(ctrack, &ctrack->reasm_client, proto, (proto == IPPROTO_TCP) ? ctrack->pos.client.seq_last : 0, sz, szMax, data_payload, len_payload);
}
static bool reasm_feed(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, const uint8_t *data_payload, size_t len_payload)
static bool reasm_feed(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, uint32_t seq, const uint8_t *data_payload, size_t len_payload)
{
if (ctrack && !ReasmIsEmpty(reasm))
{
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);
@@ -397,29 +444,30 @@ static bool reasm_feed(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, con
}
return false;
}
static bool reasm_orig_feed(t_ctrack *ctrack, uint8_t proto, const uint8_t *data_payload, size_t len_payload)
static bool reasm_client_feed(t_ctrack *ctrack, uint8_t proto, const uint8_t *data_payload, size_t len_payload)
{
return reasm_feed(ctrack, &ctrack->reasm_orig, proto, data_payload, len_payload);
if (!ctrack) return false;
return reasm_feed(ctrack, &ctrack->reasm_client, proto, (proto == IPPROTO_TCP) ? ctrack->pos.client.seq_last : (uint32_t)ctrack->reasm_client.size_present, data_payload, len_payload);
}
static void reasm_orig_stop(t_ctrack *ctrack, const char *dlog_msg)
static void reasm_client_stop(t_ctrack *ctrack, const char *dlog_msg)
{
if (ctrack)
{
if (!ReasmIsEmpty(&ctrack->reasm_orig))
if (!ReasmIsEmpty(&ctrack->reasm_client))
{
DLOG("%s", dlog_msg);
ReasmClear(&ctrack->reasm_orig);
ReasmClear(&ctrack->reasm_client);
}
send_delayed(ctrack);
}
}
static void reasm_orig_cancel(t_ctrack *ctrack)
static void reasm_client_cancel(t_ctrack *ctrack)
{
reasm_orig_stop(ctrack, "reassemble session cancelled\n");
reasm_client_stop(ctrack, "reassemble session cancelled\n");
}
static void reasm_orig_fin(t_ctrack *ctrack)
static void reasm_client_fin(t_ctrack *ctrack)
{
reasm_orig_stop(ctrack, "reassemble session finished\n");
reasm_client_stop(ctrack, "reassemble session finished\n");
}
@@ -429,7 +477,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->pos.pcounter_reply : ctrack->pos.pcounter_orig) == 1 || dis->tcp && (tcp_syn_segment(dis->tcp) || tcp_synack_segment(dis->tcp)))
if (ctrack && (params.server ? ctrack->pos.server.pcounter : ctrack->pos.client.pcounter) == 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,21 +506,22 @@ static uint8_t ct_new_postnat_fix(const t_ctrack *ctrack, const struct dissect *
}
static uint64_t pos_get(const t_ctrack_position *pos, char mode, bool bReply)
static uint64_t pos_get(const t_ctrack_position *pos, char mode)
{
if (pos)
{
switch (mode)
{
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;
case 'n': return pos->pcounter;
case 'd': return pos->pdcounter;
case 's': return pos->seq_last - pos->seq0;
case 'p': return pos->pos - pos->seq0;
case 'b': return pos->pbcounter;
}
}
return 0;
}
static bool check_pos_from(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
static bool check_pos_from(const t_ctrack_position *pos, const struct packet_range *range)
{
uint64_t ps;
if (range->from.mode == 'x') return false;
@@ -480,7 +529,7 @@ static bool check_pos_from(const t_ctrack_position *pos, bool bReply, const stru
{
if (pos)
{
ps = pos_get(pos, range->from.mode, bReply);
ps = pos_get(pos, range->from.mode);
return ps >= range->from.pos;
}
else
@@ -488,7 +537,7 @@ static bool check_pos_from(const t_ctrack_position *pos, bool bReply, const stru
}
return true;
}
static bool check_pos_to(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
static bool check_pos_to(const t_ctrack_position *pos, const struct packet_range *range)
{
uint64_t ps;
if (range->to.mode == 'x') return false;
@@ -496,7 +545,7 @@ static bool check_pos_to(const t_ctrack_position *pos, bool bReply, const struct
{
if (pos)
{
ps = pos_get(pos, range->to.mode, bReply);
ps = pos_get(pos, range->to.mode);
return (ps < range->to.pos) || !range->upper_cutoff && (ps == range->to.pos);
}
else
@@ -504,14 +553,14 @@ static bool check_pos_to(const t_ctrack_position *pos, bool bReply, const struct
}
return true;
}
static bool check_pos_cutoff(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
static bool check_pos_cutoff(const t_ctrack_position *pos, const struct packet_range *range)
{
bool bto = check_pos_to(pos, bReply, range);
return pos ? !bto : (!bto || !check_pos_from(pos, bReply, range));
bool bto = check_pos_to(pos, range);
return pos ? !bto : (!bto || !check_pos_from(pos, range));
}
static bool check_pos_range(const t_ctrack_position *pos, bool bReply, const struct packet_range *range)
static bool check_pos_range(const t_ctrack_position *pos, const struct packet_range *range)
{
return check_pos_from(pos, bReply, range) && check_pos_to(pos, bReply, range);
return check_pos_from(pos, range) && check_pos_to(pos, range);
}
@@ -645,9 +694,11 @@ static uint8_t desync(
const char *ifout,
bool bIncoming,
t_ctrack *ctrack,
const t_ctrack_position *pos,
const t_ctrack_positions *tpos,
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)
@@ -661,6 +712,7 @@ static uint8_t desync(
struct packet_range *range;
size_t l;
char instance[256];
const t_ctrack_position *pos, *rpos;
if (ctrack)
{
@@ -675,8 +727,13 @@ static uint8_t desync(
DLOG("lua out cutoff\n");
return verdict;
}
if (!pos) pos = &ctrack->pos;
if (!tpos) tpos = &ctrack->pos;
}
pos = tpos ? (bIncoming ^ params.server) ? &tpos->server : &tpos->client : NULL;
rpos = tpos ? (bIncoming ^ params.server) ? &tpos->client : &tpos->server : NULL;
LUA_STACK_GUARD_ENTER(params.L)
if (LIST_FIRST(&dp->lua_desync))
{
b_cutoff_all = b_unwanted_payload = true;
@@ -695,12 +752,12 @@ static uint8_t desync(
{
if (lua_instance_cutoff_check(&ctx, bIncoming))
DLOG("* lua '%s' : voluntary cutoff\n", instance);
else if (check_pos_cutoff(pos, bIncoming, range))
else if (check_pos_cutoff(pos, 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(pos, range->from.mode, bIncoming),
range->to.mode, pos_get(pos, range->to.mode, bIncoming),
range->from.mode, pos_get(pos, range->from.mode),
range->to.mode, pos_get(pos, range->to.mode),
range->from.mode, range->from.pos,
range->upper_cutoff ? '<' : '-',
range->to.mode, range->to.pos,
@@ -723,7 +780,7 @@ static uint8_t desync(
// create arg table that persists across multiple desync function calls
lua_newtable(params.L);
lua_pushf_dissect(dis);
lua_pushf_ctrack(ctrack, pos);
lua_pushf_ctrack(ctrack, tpos, bIncoming);
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);
@@ -732,7 +789,13 @@ static uint8_t desync(
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,15 +804,16 @@ 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 (pos && pos->mss_orig)
lua_pushf_int("tcp_mss", pos->mss_orig);
if (rpos && rpos->mss)
lua_pushf_int("tcp_mss", rpos->mss);
else
lua_pushf_global("tcp_mss", "DEFAULT_MSS");
}
@@ -765,12 +829,12 @@ static uint8_t desync(
if (!lua_instance_cutoff_check(&ctx, bIncoming))
{
range = bIncoming ? &func->range_in : &func->range_out;
if (check_pos_range(pos, bIncoming, range))
if (check_pos_range(pos, 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(pos, range->from.mode, bIncoming),
range->to.mode, pos_get(pos, range->to.mode, bIncoming),
range->from.mode, pos_get(pos, range->from.mode),
range->to.mode, pos_get(pos, range->to.mode),
range->from.mode, range->from.pos,
range->upper_cutoff ? '<' : '-',
range->to.mode, range->to.pos);
@@ -787,7 +851,7 @@ static uint8_t desync(
}
lua_pushlightuserdata(params.L, &ctx);
lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg);
lua_pushf_args(&func->args, -1);
lua_pushf_args(&func->args, -1, true);
lua_pushf_str("func", func->func);
lua_pushf_int("func_n", ctx.func_n);
lua_pushf_str("func_instance", instance);
@@ -815,8 +879,8 @@ 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(pos, range->from.mode, bIncoming),
range->to.mode, pos_get(pos, range->to.mode, bIncoming),
range->from.mode, pos_get(pos, range->from.mode),
range->to.mode, pos_get(pos, range->to.mode),
range->from.mode, range->from.pos,
range->upper_cutoff ? '<' : '-',
range->to.mode, range->to.pos);
@@ -864,6 +928,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");
@@ -910,11 +975,28 @@ static void setup_direction(
}
}
static void dp_changed(t_ctrack *ctrack)
{
if (ctrack)
{
if (ctrack->b_lua_in_cutoff)
{
DLOG("clearing lua in cutoff because of profile change\n");
ctrack->b_lua_in_cutoff = false;
}
if (ctrack->b_lua_out_cutoff)
{
DLOG("clearing lua out cutoff because of profile change\n");
ctrack->b_lua_out_cutoff = false;
}
}
}
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 t_ctrack_positions *tpos,
const struct dissect *dis,
uint8_t *mod_pkt, size_t *len_mod_pkt)
{
@@ -1071,49 +1153,48 @@ static uint8_t dpi_desync_tcp_packet_play(
// 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->pos.ack_last - ctrack->pos.ack0) == 1)
if (!params.server && ctrack && ctrack->hostname_ah_check && !ctrack->failure_detect_finalized && dp->hostlist_auto_incoming_maxseq)
{
bool bFail = false;
char client_ip_port[48];
if (*params.hostlist_auto_debuglog)
ntop46_port((struct sockaddr*)&dst, client_ip_port, sizeof(client_ip_port));
else
*client_ip_port = 0;
if (dis->tcp->th_flags & TH_RST)
uint32_t rseq = ctrack->pos.server.seq_last - ctrack->pos.server.seq0;
if (rseq)
{
DLOG("incoming RST detected for hostname %s\n", ctrack->hostname);
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)
{
if (l7payload == L7P_HTTP_REPLY)
char client_ip_port[48];
fill_client_ip_port((struct sockaddr*)&dst, client_ip_port, sizeof(client_ip_port));
if (seq_within(ctrack->pos.server.seq_last, ctrack->pos.server.seq0 + 1, ctrack->pos.server.seq0 + dp->hostlist_auto_incoming_maxseq))
{
DLOG("incoming HTTP reply detected for hostname %s\n", ctrack->hostname);
bFail = HttpReplyLooksLikeDPIRedirect(dis->data_payload, dis->len_payload, ctrack->hostname);
bool bFail = false;
if (dis->tcp->th_flags & TH_RST)
{
DLOG("incoming RST detected for hostname %s rseq %u\n", ctrack->hostname, rseq);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : rseq %u : incoming RST", ctrack->hostname, ctrack->dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto), rseq);
bFail = true;
}
else if (dis->len_payload && l7payload == L7P_HTTP_REPLY)
{
DLOG("incoming HTTP reply detected for hostname %s rseq %u\n", ctrack->hostname, rseq);
bFail = HttpReplyLooksLikeDPIRedirect(dis->data_payload, dis->len_payload, ctrack->hostname);
if (bFail)
{
DLOG("redirect to another domain detected. possibly DPI redirect.\n");
HOSTLIST_DEBUGLOG_APPEND("%s : profile %u (%s) : client %s : proto %s : rseq %u : redirect to another domain", ctrack->hostname, ctrack->dp->n, PROFILE_NAME(dp), client_ip_port, l7proto_str(l7proto), rseq);
}
else
DLOG("local or in-domain redirect detected. it's not a DPI redirect.\n");
}
if (bFail)
{
DLOG("redirect to another domain detected. possibly DPI redirect.\n");
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));
auto_hostlist_failed(dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, l7proto);
ctrack->failure_detect_finalized = true;
}
else
DLOG("local or in-domain redirect detected. it's not a DPI redirect.\n");
}
else
{
// received not http reply. do not monitor this connection anymore
DLOG("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname);
// incoming_maxseq exceeded. treat connection as successful
auto_hostlist_reset_fail_counter(dp, ctrack->hostname, client_ip_port, l7proto);
ctrack->failure_detect_finalized = true;
}
}
if (bFail)
auto_hostlist_failed(dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, l7proto);
else
if (dis->len_payload)
auto_hostlist_reset_fail_counter(dp, ctrack->hostname, client_ip_port, l7proto);
if (dis->tcp->th_flags & TH_RST)
ctrack->hostname_ah_check = false; // do not react to further dup RSTs
}
}
// not reverse
@@ -1122,18 +1203,17 @@ static uint8_t dpi_desync_tcp_packet_play(
struct blob_collection_head *fake;
uint8_t *p, *phost = NULL;
int i;
bool bHaveHost = false, bHostIsIp = false;
if (replay_piece_count)
{
rdata_payload = ctrack_replay->reasm_orig.packet;
rlen_payload = ctrack_replay->reasm_orig.size_present;
rdata_payload = ctrack_replay->reasm_client.packet;
rlen_payload = ctrack_replay->reasm_client.size_present;
}
else if (reasm_orig_feed(ctrack, IPPROTO_TCP, dis->data_payload, dis->len_payload))
else if (reasm_client_feed(ctrack, IPPROTO_TCP, dis->data_payload, dis->len_payload))
{
rdata_payload = ctrack->reasm_orig.packet;
rlen_payload = ctrack->reasm_orig.size_present;
rdata_payload = ctrack->reasm_client.packet;
rlen_payload = ctrack->reasm_client.size_present;
}
process_retrans_fail(ctrack, IPPROTO_TCP, (struct sockaddr*)&src);
@@ -1148,7 +1228,7 @@ static uint8_t dpi_desync_tcp_packet_play(
}
// we do not reassemble http
reasm_orig_cancel(ctrack);
reasm_client_cancel(ctrack);
bHaveHost = HttpExtractHost(rdata_payload, rlen_payload, host, sizeof(host));
if (!bHaveHost)
@@ -1156,17 +1236,6 @@ static uint8_t dpi_desync_tcp_packet_play(
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->pos.seq_last;
ctrack->req_seq_end = ctrack->pos.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))
{
@@ -1185,29 +1254,14 @@ static uint8_t dpi_desync_tcp_packet_play(
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->pos.seq_last, ctrack->req_seq_start, ctrack->req_seq_end)))
if (!bReqFull && ReasmIsEmpty(&ctrack->reasm_client) && !is_retransmission(&ctrack->pos.client))
{
// 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))
if (!reasm_client_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->pos.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.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 (!ReasmIsEmpty(&ctrack->reasm_client))
{
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
{
@@ -1218,16 +1272,16 @@ static uint8_t dpi_desync_tcp_packet_play(
DLOG_ERR("rawpacket_queue failed !\n");
goto pass_reasm_cancel;
}
if (ReasmIsFull(&ctrack->reasm_orig))
if (ReasmIsFull(&ctrack->reasm_client))
{
replay_queue(&ctrack->delayed);
reasm_orig_fin(ctrack);
reasm_client_fin(ctrack);
}
return VERDICT_DROP;
}
}
}
else if (ctrack && (ctrack->pos.seq_last - ctrack->pos.seq0)==1 && IsMTProto(dis->data_payload, dis->len_payload))
else if (ctrack && (ctrack->pos.client.seq_last - ctrack->pos.client.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.
@@ -1246,12 +1300,6 @@ static uint8_t dpi_desync_tcp_packet_play(
};
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->pos.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)
{
@@ -1311,10 +1359,10 @@ static uint8_t dpi_desync_tcp_packet_play(
if (!dp) goto pass_reasm_cancel;
if (dp != dp_prev)
{
dp_changed(ctrack_replay);
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
}
}
if (bHaveHost && !PROFILE_HOSTLISTS_EMPTY(dp))
{
if (!bCheckDone)
@@ -1354,19 +1402,19 @@ static uint8_t dpi_desync_tcp_packet_play(
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, pos, 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, tpos, 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;
pass_reasm_cancel:
reasm_orig_cancel(ctrack);
reasm_client_cancel(ctrack);
goto pass;
}
// return : true - should continue, false - should stop with verdict
static void quic_reasm_cancel(t_ctrack *ctrack, const char *reason)
{
reasm_orig_cancel(ctrack);
reasm_client_cancel(ctrack);
DLOG("%s\n", reason);
}
@@ -1375,7 +1423,7 @@ 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 t_ctrack_positions *tpos,
const struct dissect *dis,
uint8_t *mod_pkt, size_t *len_mod_pkt)
{
@@ -1561,8 +1609,8 @@ static uint8_t dpi_desync_udp_packet_play(
if (replay_piece_count)
{
clean_len = ctrack_replay->reasm_orig.size_present;
pclean = ctrack_replay->reasm_orig.packet;
clean_len = ctrack_replay->reasm_client.size_present;
pclean = ctrack_replay->reasm_client.packet;
}
else
{
@@ -1572,13 +1620,13 @@ static uint8_t dpi_desync_udp_packet_play(
if (pclean)
{
bool reasm_disable = params.reasm_payload_disable && l7_payload_match(l7payload, params.reasm_payload_disable);
if (ctrack && !reasm_disable && !ReasmIsEmpty(&ctrack->reasm_orig))
if (ctrack && !reasm_disable && !ReasmIsEmpty(&ctrack->reasm_client))
{
if (ReasmHasSpace(&ctrack->reasm_orig, clean_len))
if (ReasmHasSpace(&ctrack->reasm_client, clean_len))
{
reasm_orig_feed(ctrack, IPPROTO_UDP, clean, clean_len);
pclean = ctrack->reasm_orig.packet;
clean_len = ctrack->reasm_orig.size_present;
reasm_client_feed(ctrack, IPPROTO_UDP, clean, clean_len);
pclean = ctrack->reasm_client.packet;
clean_len = ctrack->reasm_client.size_present;
}
else
{
@@ -1603,13 +1651,13 @@ static uint8_t dpi_desync_udp_packet_play(
if (ctrack && !reasm_disable)
{
if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_orig))
if (bIsHello && !bReqFull && ReasmIsEmpty(&ctrack->reasm_client))
{
// preallocate max buffer to avoid reallocs that cause memory copy
if (!reasm_orig_start(ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len))
if (!reasm_client_start(ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len))
goto pass_reasm_cancel;
}
if (!ReasmIsEmpty(&ctrack->reasm_orig))
if (!ReasmIsEmpty(&ctrack->reasm_client))
{
if (rawpacket_queue_csum_fix(&ctrack->delayed, dis, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
{
@@ -1623,7 +1671,7 @@ static uint8_t dpi_desync_udp_packet_play(
if (bReqFull)
{
replay_queue(&ctrack->delayed);
reasm_orig_fin(ctrack);
reasm_client_fin(ctrack);
}
return ct_new_postnat_fix(ctrack, dis, mod_pkt, len_mod_pkt);
}
@@ -1645,10 +1693,10 @@ static uint8_t dpi_desync_udp_packet_play(
DLOG("QUIC initial contains CRYPTO with partial fragment coverage\n");
if (ctrack && !reasm_disable)
{
if (ReasmIsEmpty(&ctrack->reasm_orig))
if (ReasmIsEmpty(&ctrack->reasm_client))
{
// preallocate max buffer to avoid reallocs that cause memory copy
if (!reasm_orig_start(ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len))
if (!reasm_client_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, &ctrack->pos, &dst, fwmark, desync_fwmark, ifin, ifout))
@@ -1682,7 +1730,7 @@ static uint8_t dpi_desync_udp_packet_play(
// received payload without host. it means we are out of the request retransmission phase. stop counter
ctrack_stop_retrans_counter(ctrack);
reasm_orig_cancel(ctrack);
reasm_client_cancel(ctrack);
t_protocol_probe testers[] = {
{L7P_DISCORD_IP_DISCOVERY,L7_DISCORD,IsDiscordIpDiscoveryRequest,false},
@@ -1756,6 +1804,7 @@ static uint8_t dpi_desync_udp_packet_play(
goto pass_reasm_cancel;
if (dp != dp_prev)
{
dp_changed(ctrack_replay);
DLOG("desync profile changed by revealed l7 protocol or hostname !\n");
}
}
@@ -1784,20 +1833,14 @@ static uint8_t dpi_desync_udp_packet_play(
else
{
if (ctrack_replay)
{
ctrack_replay->hostname_ah_check = dp->hostlist_auto && !bCheckExcluded;
if (ctrack_replay->hostname_ah_check)
{
// first request is not retrans
if (!bDiscoveredHostname && !reasm_offset)
process_retrans_fail(ctrack_replay, IPPROTO_UDP, (struct sockaddr*)&src);
}
}
}
}
}
}
process_udp_fail(ctrack_replay, tpos, (struct sockaddr*)&src);
} // len_payload
if (bCheckDone && !bCheckResult)
{
DLOG("not applying tampering because of negative hostlist check\n");
@@ -1810,12 +1853,12 @@ static uint8_t dpi_desync_udp_packet_play(
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, pos, 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, tpos, 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;
pass_reasm_cancel:
reasm_orig_cancel(ctrack);
reasm_client_cancel(ctrack);
goto pass;
}
@@ -1859,7 +1902,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 t_ctrack_positions *tpos,
const uint8_t *data_pkt, size_t len_pkt,
uint8_t *mod_pkt, size_t *len_mod_pkt)
{
@@ -1875,7 +1918,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, pos, &dis, mod_pkt, len_mod_pkt);
verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &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);
}
@@ -1883,7 +1926,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, pos, &dis, mod_pkt, len_mod_pkt);
verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &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);
}
@@ -1913,7 +1956,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->pos_present ? &rp->pos : NULL, rp->packet, rp->len, mod, &modlen);
uint8_t verdict = dpi_desync_packet_play(i, count, offset, rp->fwmark_orig, rp->ifin, rp->ifout, rp->tpos_present ? &rp->tpos : NULL, rp->packet, rp->len, mod, &modlen);
switch (verdict & VERDICT_MASK)
{
case VERDICT_MODIFY:

View File

@@ -13,8 +13,10 @@
#ifdef __linux__
#define DPI_DESYNC_FWMARK_DEFAULT 0x40000000
#else
#elif defined(SO_USER_COOKIE)
#define DPI_DESYNC_FWMARK_DEFAULT 512
#else
#define DPI_DESYNC_FWMARK_DEFAULT 0
#endif
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);

View File

@@ -514,7 +514,7 @@ bool pf_is_empty(const port_filter *pf)
bool packet_pos_parse(const char *s, struct packet_pos *pos)
{
if (*s!='n' && *s!='d' && *s!='s' && *s!='b' && *s!='x' && *s!='a') return false;
if (*s!='n' && *s!='d' && *s!='s' && *s!='p' && *s!='b' && *s!='x' && *s!='a') return false;
pos->mode=*s;
if (pos->mode=='x' || pos->mode=='a')
{

View File

@@ -68,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));
@@ -141,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;
}
@@ -198,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));
@@ -216,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);
@@ -236,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);
@@ -247,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);
@@ -258,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);
@@ -269,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;
@@ -622,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);
@@ -638,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 && lua_type(L,2)!=LUA_TNIL)
{
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)
}
@@ -772,7 +841,7 @@ static int luacall_execution_plan(lua_State *L)
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_args(&func->args, -1, false);
lua_pushf_str("func", func->func);
lua_pushf_int("func_n", ctx->func_n);
lua_pushf_str("func_instance", instance);
@@ -839,13 +908,37 @@ 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_number(const char *field, lua_Number v)
{
lua_pushstring(params.L, field);
lua_pushnumber(params.L, v);
lua_rawset(params.L,-3);
}
void lua_pushi_number(lua_Integer idx, lua_Number v)
{
lua_pushinteger(params.L, idx);
lua_pushnumber(params.L, v);
lua_rawset(params.L,-3);
}
void lua_pushf_bool(const char *field, bool b)
@@ -872,6 +965,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)
@@ -990,8 +1095,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);
@@ -1126,8 +1231,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));
@@ -1167,23 +1272,44 @@ void lua_pushf_dissect(const struct dissect *dis)
lua_rawset(params.L,-3);
}
void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos)
void lua_pushf_ctrack_pos(const t_ctrack *ctrack, const t_ctrack_position *pos)
{
LUA_STACK_GUARD_ENTER(params.L)
if (!pos) pos = &ctrack->pos;
lua_pushf_lint("pcounter", pos->pcounter);
lua_pushf_lint("pdcounter", pos->pdcounter);
lua_pushf_lint("pbcounter", pos->pbcounter);
if (ctrack->ipproto == IPPROTO_TCP)
{
lua_pushliteral(params.L, "tcp");
lua_createtable(params.L, 0, 10);
lua_pushf_lint("seq0", pos->seq0);
lua_pushf_lint("seq", pos->seq_last);
lua_pushf_lint("rseq", pos->seq_last - pos->seq0);
lua_pushf_int("pos", pos->pos - pos->seq0);
lua_pushf_int("uppos", pos->uppos - pos->seq0);
lua_pushf_int("uppos_prev", pos->uppos_prev - pos->seq0);
lua_pushf_int("winsize", pos->winsize);
lua_pushf_int("winsize_calc", pos->winsize_calc);
lua_pushf_int("scale", pos->scale);
lua_pushf_int("mss", pos->mss);
lua_rawset(params.L,-3);
}
LUA_STACK_GUARD_LEAVE(params.L, 0)
}
void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming)
{
LUA_STACK_GUARD_ENTER(params.L)
if (!tpos) tpos = &ctrack->pos;
lua_pushliteral(params.L, "track");
if (ctrack)
{
lua_createtable(params.L, 0, 13 + (ctrack->ipproto == IPPROTO_TCP));
lua_createtable(params.L, 0, 9);
lua_pushf_int("pcounter_orig", pos->pcounter_orig);
lua_pushf_int("pdcounter_orig", pos->pdcounter_orig);
lua_pushf_int("pbcounter_orig", pos->pbcounter_orig);
lua_pushf_int("pcounter_reply", pos->pcounter_reply);
lua_pushf_int("pdcounter_reply", pos->pdcounter_reply);
lua_pushf_int("pbcounter_reply", pos->pbcounter_reply);
if (ctrack->incoming_ttl)
lua_pushf_int("incoming_ttl", ctrack->incoming_ttl);
else
@@ -1194,27 +1320,38 @@ void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos)
lua_pushf_reg("lua_state", ctrack->lua_state);
lua_pushf_bool("lua_in_cutoff", ctrack->b_lua_in_cutoff);
lua_pushf_bool("lua_out_cutoff", ctrack->b_lua_out_cutoff);
lua_pushf_lint("t_start", (lua_Number)ctrack->t_start.tv_sec + ctrack->t_start.tv_nsec/1000000000.);
if (ctrack->ipproto == IPPROTO_TCP)
{
lua_pushliteral(params.L, "tcp");
lua_createtable(params.L, 0, 14);
lua_pushf_int("seq0", pos->seq0);
lua_pushf_int("seq", pos->seq_last);
lua_pushf_int("ack0", pos->ack0);
lua_pushf_int("ack", pos->ack_last);
lua_pushf_int("pos_orig", pos->pos_orig - 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("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);
}
lua_pushliteral(params.L, "pos");
lua_createtable(params.L, 0, 5);
// orig, reply related to connection logical direction
// for tcp orig is client (who connects), reply is server (who listens).
// for orig is the first seen party, reply is another party
lua_pushf_number("dt",
(lua_Number)tpos->t_last.tv_sec - (lua_Number)ctrack->t_start.tv_sec +
(tpos->t_last.tv_nsec - ctrack->t_start.tv_nsec)/1000000000.);
lua_pushliteral(params.L, "client");
lua_newtable(params.L);
lua_pushf_ctrack_pos(ctrack, &tpos->client);
lua_rawset(params.L,-3);
lua_pushliteral(params.L, "server");
lua_newtable(params.L);
lua_pushf_ctrack_pos(ctrack, &tpos->server);
lua_rawset(params.L,-3);
// direct and reverse are adjusted for server mode. in server mode orig and reply are exchanged.
lua_pushliteral(params.L, "direct");
lua_getfield(params.L, -2, (params.server ^ bIncoming) ? "server" : "client");
lua_rawset(params.L,-3);
lua_pushliteral(params.L, "reverse");
lua_getfield(params.L, -2, (params.server ^ bIncoming) ? "client" : "server");
lua_rawset(params.L,-3);
lua_rawset(params.L,-3);
}
else
lua_pushnil(params.L);
@@ -1223,7 +1360,7 @@ void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_position *pos)
LUA_STACK_GUARD_LEAVE(params.L, 0)
}
void lua_pushf_args(const struct str2_list_head *args, int idx_desync)
void lua_pushf_args(const struct str2_list_head *args, int idx_desync, bool subst_prefix)
{
// var=val - pass val string
// var=%val - subst 'val' blob
@@ -1244,17 +1381,22 @@ void lua_pushf_args(const struct str2_list_head *args, int idx_desync)
{
var = arg->str1;
val = arg->str2 ? arg->str2 : "";
if (val[0]=='\\' && (val[1]=='%' || val[1]=='#'))
// escape char
lua_pushf_str(var, val+1);
else if (val[0]=='%')
lua_pushf_blob(idx_desync, var, val+1);
else if (val[0]=='#')
if (subst_prefix)
{
lua_push_blob(idx_desync, val+1);
lua_Integer len = lua_rawlen(params.L, -1);
lua_pop(params.L,1);
lua_pushf_int(var, len);
if (val[0]=='\\' && (val[1]=='%' || val[1]=='#'))
// escape char
lua_pushf_str(var, val+1);
else if (val[0]=='%')
lua_pushf_blob(idx_desync, var, val+1);
else if (val[0]=='#')
{
lua_push_blob(idx_desync, val+1);
lua_Integer len = lua_rawlen(params.L, -1);
lua_pop(params.L,1);
lua_pushf_int(var, len);
}
else
lua_pushf_str(var, val);
}
else
lua_pushf_str(var, val);
@@ -1272,7 +1414,7 @@ void lua_pushf_pos(const char *name, const struct packet_pos *pos)
lua_getfield(params.L,-1,name);
*smode=pos->mode;
lua_pushf_str("mode",smode);
lua_pushf_int("pos",pos->pos);
lua_pushf_lint("pos",pos->pos);
lua_pop(params.L,1);
LUA_STACK_GUARD_LEAVE(params.L, 0)
@@ -1406,7 +1548,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");
@@ -1666,12 +1808,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");
@@ -2146,7 +2288,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)
@@ -2948,6 +3090,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},

View File

@@ -22,7 +22,19 @@
#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
// these macros ensure correct stack position or throw error if not
#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;
@@ -51,8 +63,14 @@ 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_pushf_number(const char *field, lua_Number v);
void lua_pushi_number(lua_Integer idx, lua_Number 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);
@@ -71,8 +89,8 @@ 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, const t_ctrack_position *pos);
void lua_pushf_args(const struct str2_list_head *args, int idx_desync);
void lua_pushf_ctrack(const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming);
void lua_pushf_args(const struct str2_list_head *args, int idx_desync, bool subst_prefix);
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);

View File

@@ -1283,8 +1283,10 @@ static bool wf_make_filter(
if (bHaveTCP)
{
if (dp_list_have_autohostlist(&params.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(&params.desync_profiles))
snprintf(wf + strlen(wf), len - strlen(wf), " or\n " DIVERT_HTTP_REDIRECT);
}
if (!LIST_EMPTY(wf_raw_part))
@@ -1432,11 +1434,15 @@ 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-incoming-maxseq=<int>\t\t\t; treat tcp connection as successful if incoming relative sequence exceedes this threshold (default : %u)\n"
" --hostlist-auto-udp-out=<int>\t\t\t\t; udp failure condition : sent at least `udp_out` packets (default : %u)\n"
" --hostlist-auto-udp-in=<int>\t\t\t\t; udp failure condition : received not more than `udp_in` packets (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"
" --out-range=[(n|a|d|s)<int>](-|<)[(n|a|d|s)<int>]\t; set outgoing packet range for following LUA functions. '-' - include end pos, '<' - not include. prefix meaning : n - packet number, d - data packet number, s - relative sequence, b - byte count, x - never, a - always\n"
" --in-range=[(n|a|d|s)<int>](-|<)[(n|a|d|s)<int>]\t; set incoming packet range for following LUA functions. '-' - include end pos, '<' - not include. prefix meaning : n - packet number, d - data packet number, s - relative sequence, b - byte count, x - never, a - always\n"
" --out-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>]\t; set outgoing packet range for following LUA functions. '-' - include end pos, '<' - not include. prefix meaning : n - packet number, d - data packet number, s - relative sequence, p - data position relative sequence, b - byte count, x - never, a - always\n"
" --in-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>]\t; set incoming packet range for following LUA functions. '-' - include end pos, '<' - not include. prefix meaning : n - packet number, d - data packet number, s - relative sequence, p - data position relative sequence, b - byte count, x - never, a - always\n"
"\nLUA DESYNC ACTION:\n"
" --lua-desync=<functon>[:param1=val1[:param2=val2]]\t; call LUA function when packet received\n",
#if defined(__linux__) || defined(SO_USER_COOKIE)
@@ -1446,7 +1452,10 @@ 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, HOSTLIST_AUTO_INCOMING_MAXSEQ,
HOSTLIST_AUTO_UDP_OUT, HOSTLIST_AUTO_UDP_IN,
all_payloads
);
exit(1);
@@ -1543,6 +1552,10 @@ 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_INCOMING_MAXSEQ,
IDX_HOSTLIST_AUTO_UDP_IN,
IDX_HOSTLIST_AUTO_UDP_OUT,
IDX_HOSTLIST_AUTO_DEBUG,
IDX_NEW,
IDX_SKIP,
@@ -1627,6 +1640,10 @@ 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_INCOMING_MAXSEQ] = {"hostlist-auto-incoming-maxseq", required_argument, 0, 0},
[IDX_HOSTLIST_AUTO_UDP_IN] = {"hostlist-auto-udp-in", required_argument, 0, 0},
[IDX_HOSTLIST_AUTO_UDP_OUT] = {"hostlist-auto-udp-out", 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},
@@ -2075,6 +2092,18 @@ 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_INCOMING_MAXSEQ:
dp->hostlist_auto_incoming_maxseq = (uint32_t)atoi(optarg);
break;
case IDX_HOSTLIST_AUTO_UDP_OUT:
dp->hostlist_auto_udp_out = atoi(optarg);
break;
case IDX_HOSTLIST_AUTO_UDP_IN:
dp->hostlist_auto_udp_in = atoi(optarg);
break;
case IDX_HOSTLIST_AUTO_DEBUG:
{
FILE *F = fopen(optarg, "a+t");

View File

@@ -12,4 +12,4 @@ extern bool bQuit;
int main(int argc, char *argv[]);
// when something changes that can break LUA compatibility this version should be increased
#define LUA_COMPAT_VER 2
#define LUA_COMPAT_VER 3

View File

@@ -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,const t_ctrack_position *pos)
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_positions *tpos)
{
struct rawpacket *rp = malloc(sizeof(struct rawpacket));
if (!rp) return NULL;
@@ -54,13 +54,13 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
rp->len_payload=len_payload;
// make a copy for replay
if (pos)
if (tpos)
{
rp->pos = *pos;
rp->pos_present = true;
rp->tpos = *tpos;
rp->tpos_present = true;
}
else
rp->pos_present = false;
rp->tpos_present = false;
TAILQ_INSERT_TAIL(q, rp, next);

View File

@@ -16,8 +16,8 @@ struct rawpacket
uint32_t fwmark;
size_t len, len_payload;
uint8_t *packet;
t_ctrack_position pos;
bool pos_present;
t_ctrack_positions tpos;
bool tpos_present;
TAILQ_ENTRY(rawpacket) next;
};
TAILQ_HEAD(rawpacket_tailhead, rawpacket);
@@ -26,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,const t_ctrack_position *pos);
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_positions *tpos);
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q);
void rawpacket_free(struct rawpacket *rp);

View File

@@ -112,7 +112,7 @@ int DLOG_FILENAME_VA(const char *filename, const char *format, va_list args)
typedef void (*f_log_function)(int priority, const char *line);
static char log_buf[1024];
static char log_buf[4096];
static size_t log_buf_sz=0;
static void syslog_log_function(int priority, const char *line)
{
@@ -158,11 +158,18 @@ static void android_log_function(int priority, const char *line)
#endif
static void log_buffered(f_log_function log_function, int syslog_priority, const char *format, va_list args)
{
if (vsnprintf(log_buf+log_buf_sz,sizeof(log_buf)-log_buf_sz,format,args)>0)
if (vsnprintf(log_buf+log_buf_sz,sizeof(log_buf)-log_buf_sz-1,format,args)>0)
{
log_buf_sz=strlen(log_buf);
// log when buffer is full or buffer ends with \n
if (log_buf_sz>=(sizeof(log_buf)-1) || (log_buf_sz && log_buf[log_buf_sz-1]=='\n'))
if (log_buf_sz==(sizeof(log_buf)-2))
{
log_buf[log_buf_sz++] = '\n';
log_buf[log_buf_sz] = 0;
log_function(syslog_priority,log_buf);
log_buf_sz = 0;
}
else if (log_buf_sz && log_buf[log_buf_sz-1]=='\n')
{
log_function(syslog_priority,log_buf);
log_buf_sz = 0;
@@ -342,6 +349,10 @@ void dp_init(struct desync_profile *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->hostlist_auto_incoming_maxseq = HOSTLIST_AUTO_INCOMING_MAXSEQ;
dp->hostlist_auto_udp_out = HOSTLIST_AUTO_UDP_OUT;
dp->hostlist_auto_udp_in = HOSTLIST_AUTO_UDP_IN;
dp->filter_ipv4 = dp->filter_ipv6 = true;
}
static void dp_clear_dynamic(struct desync_profile *dp)

View File

@@ -30,6 +30,10 @@
#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 32768
#define HOSTLIST_AUTO_INCOMING_MAXSEQ 4096
#define HOSTLIST_AUTO_UDP_OUT 4
#define HOSTLIST_AUTO_UDP_IN 1
#define IPCACHE_LIFETIME 7200
@@ -39,7 +43,7 @@
#define BLOB_EXTRA_BYTES 128
// this MSS is used for ipv6 in windows and linux
#define DEFAULT_MSS 1360
#define DEFAULT_MSS 1220
#define RECONSTRUCT_MAX_SIZE 16384
@@ -78,6 +82,8 @@ 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;
int hostlist_auto_udp_in, hostlist_auto_udp_out;
uint32_t hostlist_auto_retrans_maxseq, hostlist_auto_incoming_maxseq;
hostfail_pool *hostlist_auto_fail_counters;

View File

@@ -368,8 +368,10 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
// extract 2nd level domains
const char *dhost, *drhost;
if (!FindNLD((uint8_t*)host,strlen(host),2,(const uint8_t**)&dhost,NULL) || !FindNLD((uint8_t*)redirect_host,strlen(redirect_host),2,(const uint8_t**)&drhost,NULL))
if (!FindNLD((uint8_t*)redirect_host,strlen(redirect_host),2,(const uint8_t**)&drhost,NULL))
return false;
if (!FindNLD((uint8_t*)host,strlen(host),2,(const uint8_t**)&dhost,NULL))
return true; // no SLD redirects to SLD
// compare 2nd level domains
return strcasecmp(dhost, drhost)!=0;
@@ -848,7 +850,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)
{

View File

@@ -127,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