Compare commits

..
406 Commits
Author SHA1 Message Date
bol-van 8283f4cd76 update makefiles 2026-10-29 15:55:59 +03:00
bol-van 019bbe845f update docs 2026-10-28 10:03:42 +03:00
bol-van 9679d58499 cosmetic 2026-10-28 06:43:50 +03:00
bol-van ca7ed6a986 zapret-obfs: udp2icmp update id cache access time in both directions 2026-10-27 19:01:17 +03:00
bol-van c460884213 zapret-obfs: support cgnat in udp2icmp 2026-10-27 18:50:51 +03:00
bol-van 3570f193d5 update docs 2026-10-27 18:48:28 +03:00
bol-van 8be19e079d update docs 2026-10-27 11:23:37 +03:00
bol-van 4a33055448 nfqws2: fix UAF 2026-10-22 11:06:42 +03:00
bol-van 221d7dff24 update docs 2026-10-21 11:49:48 +03:00
bol-van f94b562482 blockcheck2: more sweeps 2026-10-21 11:49:22 +03:00
bol-van 6ec7ee67ce Merge pull request #315 from sasha-spb-ru/add-veryquick-scan-level
[blockcheck2] Add a separate very quick scan level
2026-10-21 09:08:59 +03:00
bol-van 98757082b8 blockcheck2: use guard timer in all OS 2026-10-20 18:40:30 +03:00
bol-van 5786448c93 update docs 2026-10-20 17:33:26 +03:00
bol-van a0028b9895 blockcheck2: optimize PACE 2026-10-20 17:10:25 +03:00
bol-van 486626d28f Merge pull request #329 from maxsupermanhd/blockcheck-pace
blockcheck2: request pacing
2026-10-20 17:05:53 +03:00
bol-van f8d08b8436 AI fixes 2026-10-20 15:28:52 +03:00
bol-van a4515beb32 update docs 2026-10-20 09:57:59 +03:00
bol-van 299f833f39 blockcheck2.sh: temp files sweeper fix 2026-10-20 09:56:13 +03:00
bol-van a0c928be45 Merge pull request #314 from sasha-spb-ru/clean-up-leftover-tmpfiles
[blockcheck2] Sweep leftover temp files from a killed/crashed run
2026-10-20 09:40:10 +03:00
bol-van f256fea2d8 fix inconsistances in docs and comments 2026-10-20 09:16:53 +03:00
bol-van 3a6f75cd3c update docs 2026-10-20 08:32:10 +03:00
maxsupermanhd 44fbf1b18e blockcheck2: request pacing 2026-10-19 01:49:03 +03:00
bol-van a1adf7b868 nfqws2: support rare partial root environment 2026-10-04 10:18:18 +03:00
bol-van ca950d838a zapret-lib: comments spelling 2026-09-29 08:18:27 +03:00
bol-van 873642573e update docs 2026-09-28 22:35:22 +03:00
Alexander Golovanov e41e4f18c7 [blockcheck2] Add a separate very quick scan level
quick is meant to be the fast option, but it only changes how repeated
attempts are handled - it still works through every variation of a
strategy regardless. For strategies built around a fake TLS handshake,
that means testing dozens of small tweaks (different TTLs, different
TCP tricks, extra padding, split positions) well past the point where
an early exit would have been possible.

The new veryquick level stops as soon as a strategy succeeds, instead
of continuing through the rest just to be thorough. It's a separate
option rather than a change to quick, so quick, standard, and force
behave exactly as they did.
2026-09-18 16:30:33 +03:00
Alexander Golovanov 03ce20156a [blockcheck2] Sweep leftover temp files from a killed/crashed run
The pad file, PARALLEL_OUT, and HDRTEMP are all already removed on
a normal exit - Ctrl+C, closing the terminal, a plain kill all clean
up after themselves. kill -9 and crashes skip that entirely, same as
for any script, and a later run has no way to know about a different
PID's leftovers - so all three can pile up in /tmp indefinitely.

Before each is used, the script now checks for existing files matching
its pattern and removes any whose PID is confirmed no longer running.
A file still owned by a live process - a second instance running
at the same time - is left alone.
2026-09-18 14:08:10 +03:00
bol-van 00f5aaa36d update docs 2026-09-18 11:30:00 +03:00
bol-van 1e329918dc update docs 2026-09-18 11:26:08 +03:00
bol-van 8a398236ac update docs 2026-09-18 11:25:13 +03:00
bol-van 074c981a37 update docs 2026-09-18 11:24:24 +03:00
bol-van 03c139f34a update docs 2026-09-18 11:21:19 +03:00
bol-van cdcb8d4711 update docs 2026-09-18 11:20:16 +03:00
bol-van 970adb5d55 update docs 2026-09-18 11:18:44 +03:00
bol-van 6535202a9a update docs 2026-09-18 11:15:43 +03:00
bol-van 9bff218b9a update docs 2026-09-18 11:14:28 +03:00
bol-van 3e3b902902 update docs 2026-09-18 11:12:24 +03:00
bol-van 0f65389571 blockcheck2: CURL_PAD_KB=>CURL_PAD. split padding into smaller headers 2026-09-18 10:54:36 +03:00
bol-van ec25da2277 blockcheck2: warn about eval failing strategies in custom list 2026-09-18 10:04:10 +03:00
bol-van 0d2227caf6 Merge pull request #313 from sasha-spb-ru/add-request-padding
[blockcheck2] Add a way to test the size-based block without a real download
2026-09-18 09:55:41 +03:00
bol-van eb42084b30 Merge pull request #311 from sasha-spb-ru/show-strategy-coverage
[blockcheck2] Add a coverage summary next to the results
2026-09-18 09:54:42 +03:00
bol-van 3b6f0cc345 Merge pull request #310 from sasha-spb-ru/fix-strategy-escaping
[blockcheck2] Stop requiring manual escaping in strategy lists
2026-09-18 09:51:38 +03:00
bol-van 28b6fb853e Merge pull request #297 from zaveshaa/fix-doubled-word
docs: fix doubled word in manual.en.md
2026-09-17 22:03:01 +03:00
bol-van bf3b30af9c Merge pull request #290 from 0-x-0-0/fix-static-analyzer-warnings
Fix -Wcast-qual and -Wlogical-op-parentheses warnings
2026-09-17 22:01:57 +03:00
Alexander Golovanov 34a95e8a41 [blockcheck2] Add a way to test the size-based block without a real download
The "16 KB" block triggers based on how much data passes through the
connection, not on what that data actually is. Testing for it usually
means pointing at a page you know is big enough to download - but that
only works if your target actually has one.

Adds CURL_PAD_KB: set it to a number and every request gets padded
with that many KB of junk data, so the block can be triggered against
any target, even a bare server with nothing to download. Off by
default, and doesn't change anything unless you turn it on.

The padding is written to a temp file and attached from there, not
built inline: a large inline value can hit low, easy-to-reach limits
on some platforms (Cygwin among them).
2026-09-17 12:57:31 +03:00
Alexander Golovanov bf64220ab8 [blockcheck2] Stop requiring manual escaping in strategy lists
Custom strategy lists are plain text, and each line gets run through
the shell - so a strategy containing certain characters (<, parentheses,
quotes) would fail unless you added quotes around it by hand. Some real,
valid strategies use exactly these characters.

Now, when a line fails for that reason, it's automatically retried in
a simpler way that doesn't care about those characters at all. You can
paste a strategy in exactly as blockcheck2 prints it and it'll just
work. Manual escaping still works too, and is tried first if you're
already doing it.
2026-09-17 11:31:30 +03:00
Alexander Golovanov adf7791367 [blockcheck2] Add a coverage summary next to the results
When testing several targets at once, the results only ever show
strategies that worked for every single one. If your targets are
a bunch of unrelated servers, that list can easily come up empty
even when several strategies each work for most of them.

Adds a second summary that lists every strategy that worked at all,
with how many targets it worked for, best first - so you can see
which one comes closest instead of getting an all-or-nothing answer.
2026-09-17 11:24:21 +03:00
bol-van 1ea7d10f6f update docs 2026-09-16 16:41:14 +03:00
bol-van 859c24d32b update docs 2026-09-16 16:22:20 +03:00
bol-van 5df635efdb nfqws2: HttpReplyLooksLikeDPIRedirect accept # and ? chars as domain end 2026-09-16 16:20:51 +03:00
bol-van 7119ffce54 zapret-lib: dissect_url accept # and ? chars as domain end 2026-09-16 16:14:48 +03:00
bol-van 2efdb70b1c nfqws2: make autolists nonempty even if loading failed 2026-09-15 21:51:18 +03:00
bol-van 692139aeea zapret-lib: dissect quic tvb values that can't fit into 52-bit mantissa into raw strings 2026-09-15 18:58:21 +03:00
bol-van 6b6c63e338 update docs 2026-09-15 15:21:18 +03:00
bol-van 5fab86344a nfqws2: do not make autohostlists nonempty if no lists were reloaded 2026-09-15 15:02:28 +03:00
bol-van c1e8e7c0d9 nfqws2: dp_match_data optimize struct members 2026-09-15 12:13:17 +03:00
bol-van d9fde580e6 nfqws2: dp_match_data optimize struct members 2026-09-15 12:12:34 +03:00
bol-van 5ebfa6c0dc nfqws2: move dp_match() args to struct 2026-09-15 12:09:54 +03:00
bol-van a1bca5a85e update docs 2026-09-07 21:18:32 +03:00
bol-van 3122b66190 nfqws2: optimize profile search. fast checks first 2026-09-07 21:03:48 +03:00
bol-van 0b8182d24a zapret-lib: fix length checking for keyshare extension in tls_dissect_ext 2026-09-02 10:49:58 +03:00
bol-van 8b50962e66 nfqws2: --filter-mark 2026-09-02 10:36:00 +03:00
bol-van a7ff6410d6 update docs 2026-09-02 09:35:10 +03:00
bol-van 6e186a3b38 nfqws2: pad tcp options with 0x00 in reconstruct. strip 0x00 ending options in dissect. 2026-09-02 09:18:27 +03:00
bol-van 36355d46e3 nfqws2: fix exit on HUP 2026-08-28 09:04:12 +03:00
bol-van 2f8948d0eb nfqws2:dont break on eol tcpopt in dissect 2026-08-25 08:07:53 +03:00
bol-van 68514ed871 blind patch fix 2026-08-24 21:43:31 +03:00
bol-van 204e95ad0e nfqws22: pad tcp opts with zero 2026-08-24 20:41:26 +03:00
zaveshaa 3c93f925be docs: fix doubled word in manual.en.md 2026-08-23 21:11:10 +03:00
bol-van 07c69bf132 blockcheck2: fix script crash on bad strategies from the file in custom/10-list.sh 2026-08-23 19:50:13 +03:00
bol-van 2080981cea zapret-lib: minor optimize 2026-08-23 15:58:54 +03:00
bol-van c4e4fff4a0 zapret-lib: minor optimize 2026-08-23 15:58:02 +03:00
bol-van 1c5d49699c AI and manual fixes 2026-08-23 12:07:59 +03:00
bol-van a0be7cbb40 update docs 2026-08-20 18:55:40 +03:00
bol-van e263849b1b update docs 2026-08-20 18:53:41 +03:00
bol-van 46010c4a42 nfqws2: negate ssid/nlm filters 2026-08-20 18:45:49 +03:00
bol-van b08ae78778 update docs 2026-08-19 10:06:17 +03:00
bol-van 49e2d438d8 github, builder_linux: lua 5.5.1 2026-08-19 10:03:56 +03:00
bol-van a8d24607a5 blockcheck2: --wf-dup-check not needed anymore 2026-08-15 16:54:32 +03:00
bol-van 5e84833269 blockcheck2: optimize 2026-08-15 15:42:52 +03:00
bol-van fbeb124cf8 blockcheck2: use --wf-raw-filter in Windows instead of --ipset to limit target IP addresses 2026-08-15 12:08:09 +03:00
0-x-0-0 3f87539d7c Fix compiler/static analyzer warnings 2026-08-08 14:54:40 +03:00
bol-van 032651deeb update docs 2026-08-02 07:01:51 +03:00
bol-van bdad7d7be1 update docs 2026-08-01 14:11:01 +03:00
bol-van 86bcc7db16 update docs 2026-08-01 09:58:52 +03:00
bol-van 569297c623 update docs 2026-07-31 21:54:19 +03:00
bol-van 2c21faa80e github: remove high_entropy_va patch for windivert.dll, but leave dynamic_base 2026-07-31 10:31:30 +03:00
bol-van 90097be91a Merge pull request #280 from goodrussian666/master
Fixed the double-free reports in [nfqws.c (line 1118)
2026-07-31 09:53:21 +03:00
bol-van c61706cc47 update docs 2026-07-31 09:48:37 +03:00
bol-van 5f2807e0c5 builder_linux: zlib_ng optional support 2026-07-31 09:48:12 +03:00
bol-van dd85b1f852 nfqws2: remove file_mod_time() 2026-07-31 09:03:33 +03:00
bol-van b93b84791d zapret-antidpi: remove debug output 2026-07-30 22:05:03 +03:00
bol-van 4668664ee7 update docs 2026-07-30 19:02:40 +03:00
bol-van 78bbd0ee51 update docs 2026-07-30 19:01:43 +03:00
bol-van e185d5ce60 nfqws2: check for left space during udp and icmp reconstruct 2026-07-30 17:36:04 +03:00
bol-van d55fe738eb zapret-lib: include func instance in desync_timer_name 2026-07-30 17:24:29 +03:00
bol-van a8399a59fe nfqws2: do not allow more than 2 args in conntrack_feed() 2026-07-30 17:18:52 +03:00
bol-van 37e5a8a880 nfqws2: fix hostlist and ipset load if modtime is unixtime 0 2026-07-30 17:16:16 +03:00
bol-van 3b465d9981 nfqws2: stop execution plan in C code if a blob is unavailable 2026-07-30 16:34:06 +03:00
Your Name 11bc8f4fd1 Fixed the double-free reports in [nfqws.c (line 1118)
blob_collection_add() now occurs only after name/file validation and duplicate-name checks. This prevents exit_clean() from traversing a partially registered blob while name is being freed locally.

nfq2/nfqws.c:1140:4: error: Memory pointed to by 'name' is freed twice. [doubleFree]
nfq2/nfqws.c:1148:5: error: Memory pointed to by 'name' is freed twice. [doubleFree]
nfq2/nfqws.c:1159:3: error: Memory pointed to by 'name' is freed twice. [doubleFree]
nfq2/nfqws.c:1164:3: error: Memory pointed to by 'name' is freed twice. [doubleFree]
2026-07-29 20:35:31 +02:00
bol-van 80bb86e833 blockcheck2: unify messages 2026-07-23 13:46:31 +03:00
bol-van d7e6e3fb60 blockcheck2: disable tls1.3 and quic tests in batch mode if curl does not support them 2026-07-23 13:45:17 +03:00
bol-van ea047535b9 blockcheck2: revert cygstart method as it brings more problems than profit 2026-07-23 12:50:57 +03:00
bol-van a3202599aa blockcheck2: optimize signal trap/untrap 2026-07-22 21:26:05 +03:00
bol-van b8f142253b blockcheck2: wait for cygwin pid in case of signal 2026-07-22 21:13:48 +03:00
bol-van ccb6e9b534 blockcheck2: wait up to 2 seconds for the winws2 pidfile to appear 2026-07-22 20:21:36 +03:00
bol-van 3d4828d61f blockcheck2: graceful shutdown on QUIT signal 2026-07-22 13:13:34 +03:00
bol-van 0020a8de6a blockcheck2: graceful shutdown on TERM signal 2026-07-22 13:10:27 +03:00
bol-van 6f63dbc3a8 blockcheck2: use kill -f in cygwin to speed up kill 2026-07-22 09:49:43 +03:00
bol-van bb042f734e update docs 2026-07-22 08:31:39 +03:00
bol-van e6b22f3868 blockcheck2: remove spaces in assignment 2026-07-21 20:09:41 +03:00
bol-van c73af75881 blockcheck2: use instead of in killwait 2026-07-21 20:01:27 +03:00
bol-van 889d120235 blockcheck2: fix non-working 'wait' after cygstart 2026-07-21 19:53:41 +03:00
bol-van b78b52c4cd blockcheck2: use cygstart in windows to avoid fork problems (without cygwin rebase) 2026-07-20 20:42:29 +03:00
bol-van 1d85620abd nfqws2: DLOG_ERR in timer out of memory case 2026-07-20 20:18:21 +03:00
bol-van 4b9b938db2 update changes.txt 2026-07-20 19:55:07 +03:00
bol-van 43a18c7eb7 init.d: extend discord media ports to 19294-19344 2026-07-20 19:53:18 +03:00
bol-van 49c8dfedc9 init.d: extend discord media ports to 19294-19344 2026-07-20 19:51:18 +03:00
bol-van 8a0f53f3cf nfqws2: small AI fixes 2026-07-16 18:33:23 +03:00
bol-van 8d34a4b7a2 nfqws2: limit delayed packet queue to 64 packets (anti-ddos) 2026-07-04 12:37:12 +03:00
bol-van bc6b8c64a4 nfqws2: minor fix in TLSAdvanceToHostInSNI 2026-07-04 11:27:46 +03:00
bol-van c5325fc267 blockcheck fix 2026-06-25 07:01:41 +03:00
bol-van d1b80a4254 builder-linux: curl download retries and timeouts 2026-06-24 14:29:18 +03:00
bol-van 4759d64c27 update docs 2026-06-23 20:18:56 +03:00
bol-van d9acc873fa Merge pull request #195 from goodrussian666/master
cppcheck cleanup
2026-06-23 16:40:01 +00:00
bol-van 4e5efbf2b2 update docs 2026-06-23 19:35:16 +03:00
bol-van b35db6aac5 Merge pull request #249 from loop-uh/master
орфография + фикс ошибок и ссылок
2026-06-23 16:33:22 +00:00
bol-van c54533bbb2 nfqws2: accept string or function in timer_set() 2026-06-22 19:45:43 +03:00
bol-van 8afe88dea7 update docs 2026-06-21 19:08:36 +03:00
bol-van a599b4016b update docs 2026-06-21 19:06:44 +03:00
loop-uh d2c85ec8b7 орфография + фикс ошибок и ссылок 2026-06-20 19:10:46 +03:00
bol-van 15bc21d75b update docs 2026-06-16 16:33:43 +03:00
bol-van 4df9449786 nfqws2: fix 60 msec --lua-gc default to 60 sec 2026-06-16 15:50:39 +03:00
bol-van 9474a64d27 nfqws2: do not call timer search by name if not dirty 2026-06-08 20:28:37 +03:00
bol-van 31904a564e nfqws2: compile fix for bsd and lexra 2026-06-08 13:50:42 +03:00
bol-van fd9896846a nfqws2: lua-gc arg check fix 2026-06-08 13:41:14 +03:00
bol-van 2aa5d9ee37 nfqws2: minor optimize 2026-06-08 09:54:40 +03:00
bol-van da3d28f467 nfqws2: optimize 2026-06-08 08:02:13 +03:00
bol-van 5e2b6d8bde nfqws2: AI fixes 2026-06-07 19:09:27 +03:00
bol-van 08d27bf0a2 install_easy: do not use apk in openwrt if it doesn't have db in /lib/apk/db 2026-06-07 09:06:10 +03:00
bol-van d214ebf2de update docs 2026-06-07 08:39:12 +03:00
bol-van fe8b8df2ae nfqws2,zapret-lib: fix wrong spelling : WRITEABLE -> WRITABLE 2026-06-07 08:34:40 +03:00
bol-van 441d2e3cfc update docs 2026-06-06 21:57:18 +03:00
bol-van b37f17e623 zapret-antidpi: do not VERDICT_DROP in send with delay option 2026-06-06 21:50:47 +03:00
bol-van 7b82744d4d nfqws2: fix unitialized lua_ref field access 2026-06-06 09:43:28 +03:00
bol-van 211867eca5 update docs 2026-06-02 10:47:55 +03:00
bol-van c90e0e9a7f zapret-lib: fix oob urp=0 case in rawsend_dissect_segmented 2026-05-27 16:55:51 +03:00
bol-van fd4716da54 update docs 2026-05-09 22:04:07 +03:00
bol-van 5dcb6c1163 zapret-antidpi: send delayed fooled dissect, not original 2026-05-09 22:00:18 +03:00
bol-van fe112c1f22 update docs 2026-05-07 18:14:20 +03:00
bol-van 850a9920f6 update docs 2026-05-07 18:12:53 +03:00
bol-van dc99547ff0 zapret-lib,zapret-antidpi: delay parameter in 'send' desync function 2026-05-07 17:59:40 +03:00
bol-van 8d08b4f9a4 nfqws2: nfq close ifname sock after queue deinit 2026-05-06 14:46:51 +03:00
bol-van 860b13c86e nfqws2: store bt_next instead of bt_prev 2026-05-06 14:45:49 +03:00
bol-van a154c223f4 update docs 2026-05-05 22:02:09 +03:00
bol-van 7a69d56a4b update docs 2026-04-30 17:00:44 +03:00
bol-van b3be87fd7c update docs 2026-04-30 16:58:18 +03:00
bol-van 62b86c3899 zapret-tests: show current time in timer test 2026-04-30 16:44:28 +03:00
bol-van 7db50c018a nfqws2: timer rework. remove timer-res 2026-04-30 13:12:56 +03:00
bol-van eb35bb34f5 update docs 2026-04-29 10:22:25 +03:00
bol-van d0c9fa9b76 copypaste fixes 2026-04-29 08:36:43 +03:00
bol-van 7441ed7119 update LICENSE year 2026-04-28 13:41:44 +03:00
bol-van bbaeeb73fe update docs 2026-04-28 10:34:56 +03:00
bol-van b1afa7079f nfqws2: timer_enum return only names 2026-04-28 10:29:33 +03:00
bol-van 01a4ee63d4 nfqws2: timer_info, timer_enum 2026-04-28 10:22:04 +03:00
bol-van 5aefa8610b nfqws2: fix wrong op priority 2026-04-25 18:55:36 +03:00
bol-van aa226e6e7a nfqws2: fix null ptr deref 2026-04-25 18:31:46 +03:00
bol-van 65bb7ac639 nfqws2: minor optimize 2026-04-22 18:38:16 +03:00
bol-van 62dcf80867 nfqws2: fix wlan interface name search in server mode 2026-04-22 18:30:32 +03:00
Your Name 7661f29ede cleanup based on cppcheck
nfq2/darkmagic.c:1965:6: style: Condition '!set_socket_fwmark(sock,fwmark)' is always false [knownConditionTrueFalse]
2026-04-17 07:18:15 +02:00
Your Name ce3c1600da ignore .vscode 2026-04-17 07:17:10 +02:00
bol-van 640a73d25c nfqws2: do not call timer code if there're no timers 2026-04-15 08:31:39 +03:00
bol-van 787e5244ad Merge pull request #181 from goodrussian666/master
code cleanup based on cppcheck
2026-04-14 06:03:30 +00:00
bol-van d42aea6a9f update docs 2026-04-14 08:19:40 +03:00
bol-van e0b48c54db builder-linux: update zlib 2026-04-13 17:01:56 +03:00
bol-van 0f63e09d64 update docs 2026-04-13 15:41:04 +03:00
bol-van bca26682e7 update docs 2026-04-13 15:34:57 +03:00
bol-van ee24e84b85 update docs 2026-04-13 15:30:08 +03:00
bol-van 9584e29189 update docs 2026-04-13 15:26:20 +03:00
bol-van 1ed2d1bc01 update docs 2026-04-13 10:04:42 +03:00
bol-van 8fa6f11c34 update docs 2026-04-13 09:36:55 +03:00
bol-van d83368e107 update docs 2026-04-13 09:30:40 +03:00
bol-van 33ea0afd56 nfqws2: replace timer in timer_set if it already exists 2026-04-13 09:21:16 +03:00
bol-van bdc4761c46 nfqws2: fix read after free 2026-04-12 20:50:27 +03:00
bol-van 0151ee6fc1 nfqws2: fix write after free 2026-04-12 20:28:43 +03:00
bol-van e479b0427b zapret-tests: local var 2026-04-12 18:06:04 +03:00
bol-van f062579ca7 nfqws2: fix wrong debug line 2026-04-12 17:45:40 +03:00
bol-van 3364294af6 nfqws2: timers 2026-04-12 17:41:47 +03:00
bol-van fe85c6d2db init.d: remove incompatible systemd sandboxing 2026-04-06 20:51:52 +03:00
Your Name d4aa4cc5b1 code cleanup based on cppcheck
nfq2/nfqws.c:1114:19: warning: Either the condition 'p' is redundant or there is possible null pointer dereference: p. [nullPointerRedundantCheck]
2026-04-04 14:06:26 +02:00
bol-van e78382f3ad nfqws2: fail if slen==0 2026-04-01 09:34:52 +03:00
bol-van 32951c0f6a nfqws2: do not fail tls_mod if dupsid,rndsni,padencap fail 2026-03-31 14:11:52 +03:00
bol-van b6dbec4cc6 nfqws2: improve reasm cancel logic 2026-03-30 13:46:29 +03:00
bol-van b2f4e7adc6 nfqws2: always cancel reasm of not TLS 2026-03-30 11:52:57 +03:00
bol-van 56c95c47c6 nfqws2: fix TLS payload reassemble if L7 protocol is not TLS 2026-03-29 16:57:58 +03:00
bol-van c6c01c63c3 update docs 2026-03-16 12:17:48 +03:00
bol-van 7d1baf6123 zapret-pcap: fix keep argument 2026-03-14 15:17:34 +03:00
bol-van 7cdc75d0db github: remove sdiv crash on old armv7 2026-03-12 20:51:57 +03:00
bol-van 348f907b47 winws2: remove .buildid section 2026-03-12 17:40:11 +03:00
bol-van d641b00083 winws2: update res bins 2026-03-12 17:31:02 +03:00
bol-van d3b3011000 AI fixes 2026-03-06 21:36:09 +03:00
bol-van 2ec512af17 AI fixes 2026-03-06 10:58:05 +03:00
bol-van d41151ef6f nfqws2: join fragments in quic CRYPTO reconstruction. allow intersections 2026-03-05 18:38:44 +03:00
bol-van 60ac3693fc nfqws2: optimize quic CRYPTO defrag 2026-03-05 09:41:41 +03:00
bol-van 766b60544f nfqws2: remove unused var 2026-03-04 22:50:31 +03:00
bol-van e563f60153 AI fixes 2026-03-04 22:36:31 +03:00
bol-van 6d7f8efc49 nfqws2: optimize quic CRYPTO defrag 2026-03-04 19:33:49 +03:00
bol-van e46cde8e6e nfqws2: optimize 2026-03-04 18:58:39 +03:00
bol-van 52072359f0 nfqws2: remove unneeded function 2026-03-04 18:54:38 +03:00
bol-van cafacf35bc nfqws2: quic CRYPTO frag early dedup 2026-03-04 18:52:47 +03:00
bol-van 55dc47bae4 nfqws2: remove unneeded loop 2026-03-04 14:16:19 +03:00
bol-van 14a2548bf5 nfqws2: allow quic CRYPTO fragment intersection and dups 2026-03-04 12:31:40 +03:00
bol-van f59ddbb645 github,linux-builder: revert to lj_alloc for arm64 and mips64 2026-03-03 19:25:33 +03:00
bol-van 96f58adc7a docs 2026-03-03 10:53:05 +03:00
bol-van b20ee9adbe zapret-lib: prevent double apply_arg_prefix 2026-03-03 10:49:55 +03:00
bol-van 7bfb4066cd update docs 2026-03-02 20:24:45 +03:00
bol-van a8a742f48c zapret-lib: call apply_arg_prefix right before instance execute 2026-03-02 20:21:38 +03:00
bol-van 03f1fc4788 init.d: warn if ipset/hostlist files inside zapret2 root 2026-03-02 14:18:57 +03:00
bol-van 3ae875f8aa AI fixes 2026-03-02 10:44:48 +03:00
bol-van 300084a654 github.linux-builder: move arm to armv6 2026-03-01 20:22:02 +03:00
bol-van ccef4377df github: use thumb in android armv7 build 2026-03-01 18:30:54 +03:00
bol-van 3ebb24930e -DLUAJIT_USE_SYSMALLOC 2026-03-01 10:22:19 +03:00
bol-van aff6fe3966 -DLUAJIT_USE_SYSMALLOC 2026-03-01 10:18:35 +03:00
bol-van f43030c0b8 AI fix 2026-03-01 09:53:55 +03:00
bol-van 69e8bb3c7f AI fixes 2026-03-01 09:48:18 +03:00
bol-van 038f64ddad update docs 2026-02-28 22:30:08 +03:00
bol-van abdf88574c github: build experiment 2026-02-28 22:25:47 +03:00
bol-van 318c625247 update builder-linux 2026-02-28 22:23:13 +03:00
bol-van 3e52d53df0 update builder-linux 2026-02-28 19:14:45 +03:00
bol-van 410ba5ae6e github: build experiment 2026-02-28 19:02:11 +03:00
bol-van bee761f0f7 github: build experiment 2026-02-28 18:53:51 +03:00
bol-van 863267e659 github: build experiment 2026-02-28 18:47:25 +03:00
bol-van c0299a27e3 github: build experiment 2026-02-28 18:43:24 +03:00
bol-van b9e22fd97e github: luajit host CFLAGS -O2 2026-02-28 18:41:18 +03:00
bol-van b3a6445d13 update builder-linux 2026-02-28 18:40:51 +03:00
bol-van 75e3c83d07 github: armv7 thumb 2026-02-28 18:33:56 +03:00
bol-van 1aaf73858c builder-linux armv7 thumb 2026-02-28 18:29:28 +03:00
bol-van 827b1cf065 AI fixes 2026-02-28 10:10:26 +03:00
bol-van e0f67fb203 AI fixes 2026-02-27 14:34:35 +03:00
bol-van da6f4c8536 init.d: remove KillMode=none from systemd unit 2026-02-26 22:05:29 +03:00
bol-van f83ecb64bb pie experiment 2026-02-26 21:23:53 +03:00
bol-van c634fd156c update builder-linux 2026-02-26 20:03:50 +03:00
bol-van c10cc5b83e update builder-linux 2026-02-26 18:46:19 +03:00
bol-van 60988755b7 update builder-linux 2026-02-26 18:41:36 +03:00
bol-van 7584d5e38f update makefiles 2026-02-26 16:44:58 +03:00
bol-van d019627fba nfqws2: e2k arch seccomp support 2026-02-26 16:34:47 +03:00
bol-van 1ac067ec32 nfqws2: separate strip option 2026-02-26 15:09:29 +03:00
bol-van 1b5811aa9a nfqws2: silence warning 2026-02-26 11:01:13 +03:00
bol-van 60c3f56c36 pie experiment 2026-02-26 10:53:35 +03:00
bol-van a0cfbbf958 pie experiment 2026-02-26 10:46:59 +03:00
bol-van 437c988f48 pie experiment 2026-02-26 10:43:45 +03:00
bol-van a9a64b0462 pie experiment 2026-02-26 10:37:15 +03:00
bol-van 9887e470dc update builder-linux 2026-02-26 10:35:31 +03:00
bol-van 5bacfcb65f pie experiment 2026-02-26 10:28:58 +03:00
bol-van 0f04698f07 pie experiment 2026-02-26 10:21:23 +03:00
bol-van 31d5e5598b pie experiment 2026-02-26 10:19:24 +03:00
bol-van 66e2cc2bc4 pie experiment 2026-02-26 10:10:28 +03:00
bol-van 8fcc64ad0c pie experiment 2026-02-26 09:47:25 +03:00
bol-van d2f3271542 dvtws2: build with PIE 2026-02-25 17:34:36 +03:00
bol-van 942c4956b8 github: rebase windivert.dll to >4gb to allow hi entropy aslr 2026-02-25 14:33:38 +03:00
bol-van 77a24a7ec1 github: set dynamicbase on windivert.dll 2026-02-25 12:22:28 +03:00
bol-van 43999d6077 winws2: enable ASLR 2026-02-25 10:49:07 +03:00
bol-van 697f9fc986 AI fixes 2026-02-25 08:56:35 +03:00
bol-van 8e76197dff luacheck fixes 2026-02-24 19:07:04 +03:00
bol-van 190f46b6d7 zapret-lib: minor fix 2026-02-24 18:43:49 +03:00
bol-van 41e26b3ace update docs 2026-02-24 16:32:21 +03:00
bol-van 8b6ea88a23 update docs 2026-02-24 10:19:01 +03:00
bol-van 59235827c4 nfqws2: fix broken wifi ssid update 2026-02-24 10:10:52 +03:00
bol-van 7073e1fd77 nfqws2: dns_extract_name OOB fixes 2026-02-23 22:47:14 +03:00
bol-van 340261da72 zapret-lib: harden apply_fooling checks 2026-02-23 19:33:58 +03:00
bol-van 937aa91e5d nfqws2: prevent OOB read in addpool 2026-02-23 18:45:25 +03:00
bol-van dbf673e24a AI fixes 2026-02-23 18:10:37 +03:00
bol-van 61b0a70fa7 nfqws2: support mixed compressed+uncomressed DNS answers 2026-02-23 10:25:27 +03:00
bol-van d985bb316f nfqws2: support uncompressed names in DNS answers 2026-02-23 09:32:45 +03:00
bol-van 59b3734643 nfqws2: add comment 2026-02-22 19:41:08 +03:00
bol-van 37f45a132f nfqws2: optimize 2026-02-22 18:49:44 +03:00
bol-van 4d753ecdc6 nfqws2: save some syscalls 2026-02-22 18:22:43 +03:00
bol-van 272f086639 nfqws2: optimize nfq buffers 2026-02-22 17:31:13 +03:00
bol-van d9ae16e56f nfqws2: nfq_handle_packet verbose error logging 2026-02-22 17:03:52 +03:00
bol-van 46d4208c76 zapret-pcap: use reconstruct_dissect if under orchestrator 2026-02-22 12:48:20 +03:00
bol-van 2a4195070f AI fixes 2026-02-22 09:06:53 +03:00
bol-van 8e974e78e2 delete sip.bin dup 2026-02-21 19:44:00 +03:00
bol-van 7df42bc486 init.d: --payload= in custom examples 2026-02-21 10:35:14 +03:00
bol-van 7c12f60e1e AI fixes 2026-02-21 10:23:25 +03:00
bol-van 4c7a3d08d8 github: upx 4.2.4 for all except riscv64 2026-02-20 18:43:22 +03:00
bol-van e146fc24c5 github: upx 4.2.4 for all except riscv64 2026-02-20 18:41:18 +03:00
bol-van 6165c13468 AI fix 2026-02-20 15:25:56 +03:00
bol-van f7b3946ec2 update docs 2026-02-20 13:19:17 +03:00
bol-van 9f29f2c0ae update docs 2026-02-20 13:12:08 +03:00
bol-van c13284b776 zapret-auto: per_instance_condition feed target desync to cond function, code=>cond_code 2026-02-20 07:18:31 +03:00
bol-van 6e85c9650d nfqws2: use tcp seq for reasm_offset 2026-02-19 17:38:46 +03:00
bol-van 7f3b5f659f update docs 2026-02-19 13:00:57 +03:00
bol-van 8e62b2e743 update docs 2026-02-19 12:57:50 +03:00
bol-van 94dfd5fded quic2_example_com.bin 2026-02-19 10:26:42 +03:00
bol-van 70d8e5ad15 AI fixes 2026-02-19 10:05:50 +03:00
bol-van a80aed5ccc update builder-linux 2026-02-18 17:28:03 +03:00
bol-van 2b35dc8ecd update builder-linux 2026-02-18 16:31:01 +03:00
bol-van 75fadab371 update builder-linux 2026-02-18 16:16:58 +03:00
bol-van e70f4a000a update builder-linux 2026-02-18 16:08:19 +03:00
bol-van 755c792797 github: luajit for ppc 2026-02-18 15:37:08 +03:00
bol-van b17894eec1 nfqws2: goto lua desync if reasm is cancelled 2026-02-18 15:28:30 +03:00
bol-van 9e22ec883c update builder-linux 2026-02-18 12:42:11 +03:00
bol-van f70fb89754 AI fixes, update builder-linux 2026-02-18 12:15:46 +03:00
bol-van e30f99e106 update docs 2026-02-18 10:46:10 +03:00
bol-van fce76e59aa build-linux update 2026-02-18 10:28:36 +03:00
bol-van 1b1c8ddb38 nfqws2, zapret-lib: always treat blobs, % and # as string 2026-02-17 19:22:17 +03:00
bol-van 5ced6811c8 winws: fix ensure_access for unix paths 2026-02-17 16:27:06 +03:00
bol-van 371612b000 install_bin: add mipsel64 2026-02-17 14:24:43 +03:00
bol-van 3c87be3cba update docs 2026-02-17 14:11:55 +03:00
bol-van c642fb3845 builder-linux 2026-02-17 14:07:08 +03:00
bol-van 847e689bfb AI fixes 2026-02-17 09:35:09 +03:00
bol-van 287527092a remove debug message 2026-02-17 09:15:53 +03:00
bol-van a9514f39f5 update docs 2026-02-16 20:54:18 +03:00
bol-van 4b7ff505e4 nfqws2: old kernels compat 2026-02-16 20:51:39 +03:00
bol-van 2120264e0b AI and manual fixes 2026-02-16 19:45:58 +03:00
bol-van 178bced5f3 update docs 2026-02-16 14:55:31 +03:00
bol-van ff78968807 nfqws2: ensure old toolchains do not break 2026-02-16 12:01:08 +03:00
bol-van e4535d2646 nfqws2: loongarch64 compile fix 2026-02-16 11:51:43 +03:00
bol-van 7c60ad3a7a AI fixes 2026-02-16 10:47:50 +03:00
bol-van a621edf898 AI fixes 2026-02-15 09:40:54 +03:00
bol-van 2809f8d7e4 update docs 2026-02-14 18:16:57 +03:00
bol-van 97819327cd nfqws2: remember absolute paths 2026-02-14 18:10:26 +03:00
bol-van eb9a1e9f6b nfqws2: --chdir 2026-02-14 16:08:01 +03:00
bol-van 6f6850707a zapret-lib: tls_dissect abort 2 loops if data is corrupt 2026-02-14 15:30:59 +03:00
bol-van f702865311 AI fixes 2026-02-14 13:19:48 +03:00
bol-van 6447081a01 winws2: optimize signal handling in windivert_recv 2026-02-14 11:36:00 +03:00
bol-van e4e513ec66 github: stronger gz and zip compression 2026-02-13 17:38:22 +03:00
bol-van 47630450bd AI fixes 2026-02-13 16:49:42 +03:00
bol-van e4129fec63 github: upx 5.1.0 2026-02-13 13:35:55 +03:00
bol-van f71ba91e7c remove no-unwind from makefiles 2026-02-13 10:59:24 +03:00
bol-van 59e6603b83 dont use no-unwind to prevent crashes 2026-02-13 10:34:16 +03:00
bol-van 14a061859f change toolchain, riscv64 2026-02-13 09:11:51 +03:00
bol-van 9aaa419f68 nfqws2: fix fread inf loop 2026-02-12 11:54:12 +03:00
bol-van d5231bc4fc nfqws2: allow any size iv_len in aes_gcm 2026-02-11 15:42:23 +03:00
bol-van 35cebfba73 winws2: use -msse only for luajit 2026-02-11 14:09:55 +03:00
bol-van 811d16054b update docs 2026-02-11 14:05:29 +03:00
bol-van a9ee072a14 github: cygwin lto 2026-02-11 14:01:24 +03:00
bol-van 1dbf5ecfe6 optimize exe size 2026-02-11 13:18:14 +03:00
bol-van b210db168f nfqws2: bsd compile fixes 2026-02-11 13:05:45 +03:00
bol-van 5306a043d0 AI fixes 2026-02-11 11:26:20 +03:00
bol-van b375a94036 update docs 2026-02-11 11:22:53 +03:00
bol-van 8b2bff4187 AI fixes 2026-02-11 11:03:27 +03:00
bol-van 827ab7cdcc nfqws2: optimize quit logic 2026-02-10 19:05:14 +03:00
bol-van bfa1d8c5dd nfqws2: compile mask_from_bitcount only for windows 2026-02-10 15:59:56 +03:00
bol-van 52ea6270f4 nfqws2: update kavl 2026-02-10 15:51:50 +03:00
bol-van 0fb21856c6 nfqws2: update uthash 2026-02-10 15:47:28 +03:00
bol-van 48e4d3a6e7 init.d: optimize ipt dports 2026-02-10 12:34:47 +03:00
bol-van 6204c74993 update docs 2026-02-10 12:07:24 +03:00
bol-van d981391120 update docs 2026-02-10 12:06:26 +03:00
bol-van 7db676e02c init.d: use bitmap:port ipset for standard dports 2026-02-10 11:33:50 +03:00
bol-van c91cae0903 nfqws2: quit handling optimize 2026-02-09 21:06:36 +03:00
bol-van c06712a0d5 nfqws2: optimize 2026-02-09 19:49:47 +03:00
bol-van 2e2f118e10 nfqws2: EINTR safety 2026-02-09 19:44:06 +03:00
bol-van 6638140880 zapret-auto: instances arg in condition, cond_lua 2026-02-09 17:24:11 +03:00
bol-van 41bac1833e nfqws2: remove bind to address in rawsend 2026-02-09 15:59:53 +03:00
bol-van c3b1cc3eb9 update docs 2026-02-09 13:45:23 +03:00
bol-van 6f52fb08f9 update docs 2026-02-09 13:44:41 +03:00
bol-van 08549b570b update docs 2026-02-09 13:43:46 +03:00
bol-van 13daef5167 update docs 2026-02-09 13:39:26 +03:00
bol-van 1fd6063cd7 update docs 2026-02-09 13:38:25 +03:00
bol-van 5e4f78228e zapret-auto: per_instance_condition not execute if cond arg absent 2026-02-09 13:28:51 +03:00
bol-van 2e255ca59f zapret-auto: per_instance_condition 2026-02-09 13:19:01 +03:00
bol-van 565a8abffc AI fixes 2026-02-09 10:04:13 +03:00
bol-van 69f1576f7e AI fixes 2026-02-08 17:22:39 +03:00
bol-van 0917cb21bb AI fixes 2026-02-08 17:12:36 +03:00
bol-van 8f316ae1a2 nfqws2: AI fixes 2026-02-07 20:07:49 +03:00
bol-van caaf5e7a2e nfqws2: DLOG_ERR payload too large 2026-02-07 14:50:54 +03:00
bol-van dbfbd6e6d3 nfqws2: DLOG_ERR if payload does not fit into the buffer 2026-02-07 14:47:31 +03:00
bol-van 397fe60b5f update docs 2026-02-07 13:55:23 +03:00
bol-van e096ed64bc update docs 2026-02-07 13:54:01 +03:00
bol-van 0f2def9bd5 update docs 2026-02-07 13:52:11 +03:00
bol-van 85721e4b82 update docs 2026-02-07 13:50:55 +03:00
bol-van 0fd9314df9 update docs 2026-02-07 13:49:54 +03:00
bol-van a9e2bfe49c update docs 2026-02-07 13:48:27 +03:00
bol-van bd7a40f5a9 nfqws2: handling of incoming frag, AI fixes 2026-02-07 13:36:31 +03:00
bol-van bcd50f5215 zapret-tests: 64-bit time support checks 2026-02-06 17:16:40 +03:00
bol-van 927cca3d44 AI fixes 2026-02-06 16:42:18 +03:00
bol-van 162e8906a6 nfqws2: use mktime instead of timelocal 2026-02-06 15:53:50 +03:00
bol-van 3f7180379b update docs 2026-02-06 15:47:34 +03:00
bol-van 5d0af6b058 nfqws2: load wlanapi.dll dynamically only if required 2026-02-06 15:42:36 +03:00
bol-van 392e1cc1ef nfqws2: fix sz=0 case in fill_random_bytes 2026-02-06 14:58:24 +03:00
bol-van 8a5643851d zapret-tests: fix ip_len in csum tests 2026-02-06 12:01:31 +03:00
bol-van 6299a46ab7 nfqws2: 1ULL in proto/payload 2026-02-06 11:31:47 +03:00
bol-van c5ecc0493d nfqws2: check malloc result 2026-02-06 11:05:54 +03:00
bol-van 7bb8b1d7b3 nfqws2: clear partially allocated windivert filters 2026-02-06 11:04:27 +03:00
bol-van 401bd83f82 nfqws2: use malloc in fuzz for packet data 2026-02-06 11:03:51 +03:00
bol-van c117c30849 nfqws2: AI fixes 2026-02-06 10:47:29 +03:00
bol-van 6828e7352c antivirus issue ban warning 2026-02-06 10:10:09 +03:00
bol-van 943e548f93 mdig: minor change 2026-02-05 18:51:36 +03:00
bol-van 539c329da3 update docs 2026-02-05 14:35:14 +03:00
bol-van 4c6902c17c update docs 2026-02-05 14:34:41 +03:00
bol-van 9121d949f6 update docs 2026-02-05 14:34:17 +03:00
bol-van 64c1f96f80 nfqws2: time convert functions 2026-02-05 14:33:15 +03:00
bol-van 3334786fe3 AI fixes 2026-02-05 12:54:59 +03:00
bol-van 20a0fa671d AI fixes 2026-02-05 12:36:27 +03:00
bol-van 747de07c85 update docs 2026-02-05 12:22:50 +03:00
bol-van 6384af6607 update docs 2026-02-05 12:22:18 +03:00
bol-van 3046dd8013 nfqws2: bt and utp_bt protocol detectors 2026-02-05 12:19:31 +03:00
bol-van c80ae95a09 nfqws2: hidden packet data fuzz option 2026-02-05 11:06:32 +03:00
bol-van d7e5fc1a7c nfqws2: AI fixes 2026-02-05 09:37:34 +03:00
bol-van 97a6b9dd5b nfqws2: AI inspired fixes 2026-02-04 22:06:23 +03:00
bol-van cfd2df41c4 nfqws2: tls debug ssl 3.0 2026-02-04 17:54:07 +03:00
bol-van f47f4a0cae blockcheck2: small fixes 2026-02-04 17:35:07 +03:00
bol-van 823a2e2e5d update docs 2026-02-04 15:18:57 +03:00
bol-van 0cdbedde74 update docs 2026-02-04 15:17:27 +03:00
bol-van 36e243863b update docs 2026-02-04 15:15:47 +03:00
97 changed files with 5460 additions and 1998 deletions

No files matched your search

+2
View File
@@ -18,5 +18,7 @@ Discussions - место для обсуждения вопросов между
Если вы игнорируете данное требование, вы не достигните своих целей , а только добавите желания удалить ваш issue или при настойчивости забанить.
Идите в дискуссии, не захламляйте issues.
Так же будут немедленно удаляться любые issue, связанные с реакцией антивирусов. При агрессии или настойчивости - бан. (подсказка : вирусов нет, удаляйте если не верите)
Here is the place for bugs only. All questions, especially user-like questions (non-technical) go to Discussions.
There're also no viruses here. All virus claims and everyting non-technical and non-bugs will be instantly deleted, closed or moved to Discussions.
+86 -42
View File
@@ -25,33 +25,21 @@ jobs:
- arch: arm64
tool: aarch64-unknown-linux-musl
- arch: arm
tool: arm-unknown-linux-musleabi
# - arch: armhf
# tool: arm-unknown-linux-musleabihf
# - arch: armv7
# tool: armv7-unknown-linux-musleabi
# - arch: armv7hf
# tool: armv7-unknown-linux-musleabihf
# - arch: mips64el
# tool: mips64el-unknown-linux-musl
tool: armv6-unknown-linux-musleabi
- arch: mips64
tool: mips64-unknown-linux-musl
# - arch: mipsel
# tool: mipsel-unknown-linux-musl
- arch: mipselsf
tool: mipsel-unknown-linux-muslsf
# - arch: mips
# tool: mips-unknown-linux-musl
- arch: mipssf
tool: mips-unknown-linux-muslsf
# - arch: ppc64
# tool: powerpc64-unknown-linux-musl
- arch: ppc
tool: powerpc-unknown-linux-musl
- arch: x86
tool: i586-unknown-linux-musl
- arch: x86_64
tool: x86_64-unknown-linux-musl
- arch: riscv64
tool: riscv64-unknown-linux-musl
- arch: lexra
tool: mips-linux
dir: rsdk-4.6.4-5281-EB-3.10-0.9.33-m32ub-20141001
@@ -69,7 +57,7 @@ jobs:
env:
ARCH: ${{ matrix.arch }}
TOOL: ${{ matrix.tool }}
REPO: ${{ matrix.arch == 'lexra' && matrix.repo || 'spvkgn/musl-cross' }}
REPO: ${{ matrix.arch == 'lexra' && matrix.repo || 'bol-van/musl-cross' }}
DIR: ${{ matrix.arch == 'lexra' && matrix.dir || matrix.tool }}
run: |
sudo dpkg --add-architecture i386
@@ -94,10 +82,14 @@ jobs:
LDFLAGS: ${{ matrix.env.LDFLAGS != '' && matrix.env.LDFLAGS || null }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
LUA_VER: 5.5
LUA_RELEASE: 5.5.0
LUA_RELEASE: 5.5.1
LUAJIT_VER: 2.1
LUAJIT_RELEASE: 2.1-20250826
LUAJIT_LUAVER: 5.1
MINSIZE: -flto=auto -ffunction-sections -fdata-sections
LDMINSIZE: -Wl,--gc-sections -flto=auto
#current toolchain's musl is not PIC. will be broken by upx
#PIC: -fpic
run: |
DEPS_DIR=$GITHUB_WORKSPACE/deps
export CC="$TARGET-gcc"
@@ -107,13 +99,28 @@ jobs:
export STRIP=$TARGET-strip
export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig
export STAGING_DIR=$RUNNER_TEMP
OPTIMIZE=-Oz
SYSMALLOC=-DLUAJIT_USE_SYSMALLOC
case "$ARCH" in
lexra)
OPTIMIZE=-Os
;;
arm)
CPU="-mcpu=arm1176jzf-s -mthumb"
;;
arm64|mips64)
# not safe without GC64
SYSMALLOC=
;;
esac
MINSIZE="$OPTIMIZE $MINSIZE"
if [[ "$ARCH" == lexra ]] || [[ "$ARCH" == ppc ]] || [[ "$ARCH" == x86 ]] ; then
if [[ "$ARCH" == lexra ]] || [[ "$ARCH" == riscv64 ]] || [[ "$ARCH" == x86 ]] ; then
# use classic lua
wget -qO- https://www.lua.org/ftp/lua-${LUA_RELEASE}.tar.gz | tar -xz
(
cd lua-${LUA_RELEASE}
make CC=$CC CFLAGS="-Os -flto=auto $CFLAGS" linux -j$(nproc)
make CC=$CC AR="$AR rc" CFLAGS="$CPU $MINSIZE $CFLAGS" LDFLAGS="$LDMINSIZE $LDFLAGS" linux -j$(nproc)
make install INSTALL_TOP=$DEPS_DIR INSTALL_BIN=$DEPS_DIR/bin INSTALL_INC=$DEPS_DIR/include/lua${LUA_VER} INSTALL_LIB=$DEPS_DIR/lib
)
LJIT=0
@@ -129,9 +136,10 @@ jobs:
*)
HOSTCC="cc -m32"
esac
echo ARCH=$ARCH SYSMALLOC=$SYSMALLOC
(
cd luajit2-*
make BUILDMODE=static XCFLAGS=-DLUAJIT_DISABLE_FFI HOST_CC="$HOSTCC" CROSS= CC="$CC" TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP CFLAGS="-Os -s -flto=auto $CFLAGS" -j$(nproc)
make BUILDMODE=static XCFLAGS="$SYSMALLOC -DLUAJIT_DISABLE_FFI" HOST_CC="$HOSTCC" CROSS= CC="$CC" TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP TARGET_CFLAGS="$CPU $MINSIZE $CFLAGS" TARGET_LDFLAGS="$CPU $LDMINSIZE $LDFLAGS" -j$(nproc)
make install PREFIX= DESTDIR=$DEPS_DIR
)
LJIT=1
@@ -147,7 +155,8 @@ jobs:
for i in libmnl libnfnetlink libnetfilter_queue ; do
(
cd $i-*
CFLAGS="-Os -flto=auto $CFLAGS" \
CFLAGS="$CPU $MINSIZE $CFLAGS" \
LDFLAGS="$LDMINSIZE $LDFLAGS" \
./configure --prefix= --host=$TARGET --enable-static --disable-shared --disable-dependency-tracking
make install -j$(nproc) DESTDIR=$DEPS_DIR
)
@@ -159,7 +168,7 @@ jobs:
xargs -I{} wget -qO- https://github.com/madler/zlib/archive/refs/tags/{}.tar.gz | tar -xz
(
cd zlib-*
CFLAGS="-Os -flto=auto $CFLAGS" \
CFLAGS="$CPU $MINSIZE $CFLAGS" \
./configure --prefix= --static
make install -j$(nproc) DESTDIR=$DEPS_DIR
)
@@ -170,9 +179,10 @@ jobs:
install -Dm644 -t $DEPS_DIR/include/sys /usr/include/x86_64-linux-gnu/sys/queue.h /usr/include/sys/capability.h
# zapret2
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -static-libgcc -static -I$DEPS_DIR/include $CFLAGS" \
OPTIMIZE=$OPTIMIZE \
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -static-libgcc -I$DEPS_DIR/include $CPU $CFLAGS" \
LDFLAGS="-L$DEPS_DIR/lib $LDFLAGS" \
make -C zapret2 LUA_JIT=$LJIT LUA_CFLAGS="$LCFLAGS" LUA_LIB="$LLIB" -j$(nproc)
make -C zapret2 CFLAGS_PIC= LDFLAGS_PIE=-static LUA_JIT=$LJIT LUA_CFLAGS="$LCFLAGS" LUA_LIB="$LLIB" -j$(nproc)
tar -C zapret2/binaries/my -cJf zapret2-linux-$ARCH.tar.xz .
@@ -220,6 +230,8 @@ jobs:
LUAJIT_VER: 2.1
LUAJIT_RELEASE: 2.1-20250826
LUAJIT_LUAVER: 5.1
MINSIZE: -Oz -flto=auto -ffunction-sections -fdata-sections
LDMINSIZE: -Wl,--gc-sections -flto=auto
run: |
DEPS_DIR=$GITHUB_WORKSPACE/deps
export TOOLCHAIN=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64
@@ -230,6 +242,17 @@ jobs:
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
export STRIP=$TOOLCHAIN/bin/llvm-strip
export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig
SYSMALLOC=-DLUAJIT_USE_SYSMALLOC
case "$ABI" in
armeabi-v7a)
CPU="-mthumb"
;;
arm64-v8a)
# not safe without GC64
SYSMALLOC=
PAGESIZE="-Wl,-z,max-page-size=16384"
;;
esac
# luajit
wget -qO- https://github.com/openresty/luajit2/archive/refs/tags/v${LUAJIT_RELEASE}.tar.gz | tar -xz
@@ -242,7 +265,7 @@ jobs:
esac
(
cd luajit2-*
make BUILDMODE=static XCFLAGS=-DLUAJIT_DISABLE_FFI HOST_CC="$HOSTCC" CROSS= CC="$CC" TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP CFLAGS="-Os -flto=auto $CFLAGS" -j$(nproc)
make BUILDMODE=static XCFLAGS="$SYSMALLOC -DLUAJIT_DISABLE_FFI" HOST_CC="$HOSTCC" CROSS= CC="$CC" TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP TARGET_CFLAGS="$CPU $MINSIZE $CFLAGS" TARGET_LDFLAGS="$LDMINSIZE $LDFLAGS" -j$(nproc)
make install PREFIX= DESTDIR=$DEPS_DIR
)
LJIT=1
@@ -258,7 +281,8 @@ jobs:
for i in libmnl libnfnetlink libnetfilter_queue ; do
(
cd $i-*
CFLAGS="-Os -flto=auto -Wno-implicit-function-declaration" \
CFLAGS="$CPU $MINSIZE -Wno-implicit-function-declaration $CFLAGS" \
LDFLAGS="$LDMINSIZE $LDFLAGS" \
./configure --prefix= --host=$TARGET --enable-static --disable-shared --disable-dependency-tracking
make install -j$(nproc) DESTDIR=$DEPS_DIR
)
@@ -266,8 +290,8 @@ jobs:
done
# zapret2
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -I$DEPS_DIR/include" \
LDFLAGS="-L$DEPS_DIR/lib" \
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -I$DEPS_DIR/include $CPU" \
LDFLAGS="-L$DEPS_DIR/lib $PAGESIZE" \
make -C zapret2 LUA_JIT=$LJIT LUA_CFLAGS="$LCFLAGS" LUA_LIB="$LLIB" -j$(nproc) android
# strip unwanted ELF sections to prevent warnings on old Android versions
@@ -313,13 +337,16 @@ jobs:
env:
TARGET: ${{ matrix.target }}
ARCH: ${{ matrix.arch }}
PIC: -fpic
CC: ${{ matrix.target }}-freebsd11-clang
MINSIZE: -Os -flto=auto -ffunction-sections -fdata-sections
LDMINSIZE: -Wl,--gc-sections -flto=auto
run: |
wget -qO- https://github.com/openresty/luajit2/archive/refs/tags/v${LUAJIT_RELEASE}.tar.gz | tar -xz
(
cd luajit2-*
make BUILDMODE=static XCFLAGS=-DLUAJIT_DISABLE_FFI HOST_CC=gcc CC=$CC CFLAGS="-Os -flto=auto $CFLAGS"
make BUILDMODE=static XCFLAGS="$PIC -DLUAJIT_USE_SYSMALLOC -DLUAJIT_DISABLE_FFI" HOST_CC=gcc CC=$CC TARGET_CFLAGS="$MINSIZE $CFLAGS $PIC" TARGET_LDFLAGS="$LDMINSIZE $LDFLAGS"
make install PREFIX= DESTDIR=$DEPS_DIR
)
@@ -390,7 +417,7 @@ jobs:
uses: cygwin/cygwin-install-action@v4
with:
platform: ${{ matrix.arch }}
site: ${{ matrix.arch == 'x86_64' && 'http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215' || null }}
site: ${{ matrix.arch == 'x86_64' && 'http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/64bit/2024/01/30/231215' || 'http://ctm.crouchingtigerhiddenfruitbat.org/pub/cygwin/circa/2022/11/23/063457' }}
check-sig: 'false'
packages: >-
gcc-core
@@ -424,13 +451,15 @@ jobs:
- name: Build luajit
env:
LUAJIT_RELEASE: 2.1-20250826
MINSIZE: -Os -flto=auto -ffunction-sections -fdata-sections
LDMINSIZE: -Wl,--gc-sections -flto=auto
shell: C:\cygwin\bin\bash.exe -eo pipefail '{0}'
run: >-
export MAKEFLAGS=-j$(nproc) &&
wget -q https://github.com/openresty/luajit2/archive/refs/tags/v${LUAJIT_RELEASE}.tar.gz &&
tar -xzf v${LUAJIT_RELEASE}.tar.gz &&
rm -f v${LUAJIT_RELEASE}.tar.gz &&
make -C luajit2-${LUAJIT_RELEASE} BUILDMODE=static XCFLAGS=-DLUAJIT_DISABLE_FFI CFLAGS="-Os -s" &&
make -C luajit2-${LUAJIT_RELEASE} BUILDMODE=static XCFLAGS="-DLUAJIT_USE_SYSMALLOC -DLUAJIT_DISABLE_FFI -ffat-lto-objects" TARGET_CFLAGS="$MINSIZE $CFLAGS" TARGET_LDFLAGS="$LDMINSIZE $LDFLAGS" &&
make -C luajit2-${LUAJIT_RELEASE} install
- name: Build winws
@@ -453,6 +482,7 @@ jobs:
cp -a -t output psmisc/psmisc-*.src/psmisc-*/inst/usr/bin/killall.exe /usr/bin/cygwin1.dll &&
wget -O WinDivert.zip https://github.com/basil00/WinDivert/releases/download/v2.2.2/WinDivert-2.2.2-A.zip &&
unzip -j WinDivert.zip "*/${DIR}/WinDivert.dll" "*/${DIR}/WinDivert${BITS}.sys" -d output &&
peflags --dynamicbase=true output/WinDivert.dll &&
zip zapret2-win-${{ matrix.arch }}.zip -j output/*
- name: Upload artifacts
@@ -485,17 +515,28 @@ jobs:
pattern: zapret2-*
- name: Install upx
uses: crazy-max/ghaction-upx@v3
with:
install-only: true
version: v4.2.4
shell: bash
env:
VER_OLD: 4.2.4
VER_NEW: 5.1.0
run: |
# old upx works for old kernels like 2.6.26
# new upx crashes on ~<3.10 but required for riscv64
curl -Lo - https://github.com/upx/upx/releases/download/v$VER_OLD/upx-$VER_OLD-amd64_linux.tar.xz | tar -Jx upx-$VER_OLD-amd64_linux/upx
sudo cp upx-$VER_OLD-amd64_linux/upx /usr/local/bin/upx_old
curl -Lo - https://github.com/upx/upx/releases/download/v$VER_NEW/upx-$VER_NEW-amd64_linux.tar.xz | tar -Jx upx-$VER_NEW-amd64_linux/upx
sudo cp upx-$VER_NEW-amd64_linux/upx /usr/local/bin/upx_new
rm -r upx-$VER_OLD-amd64_linux/upx upx-$VER_NEW-amd64_linux/upx
- name: Prepare binaries
shell: bash
run: |
cd ${{ steps.bins.outputs.download-path }}
run_upx() {
upx --best --lzma $@ || true
run_upx_old() {
upx_old --best --lzma $@ || true
}
run_upx_new() {
upx_new --best --lzma $@ || true
}
run_dir() {
for f in $dir/* ; do
@@ -503,8 +544,10 @@ jobs:
case $f in
*.tar.xz )
tar -C $dir -xvf $f && rm $f
if [[ $dir =~ linux ]] && [[ $dir != *-linux-mips64 ]] && [[ $dir != *-linux-lexra ]]; then
run_upx $dir/*
if [[ $dir = *-linux-riscv64 ]]; then
run_upx_new $dir/*
elif [[ $dir =~ linux ]] && [[ $dir != *-linux-mips64 ]] && [[ $dir != *-linux-lexra ]]; then
run_upx_old $dir/*
fi
;;
*.zip )
@@ -532,6 +575,7 @@ jobs:
*-linux-mipselsf ) run_dir linux-mipsel ;;
*-linux-mipssf ) run_dir linux-mips ;;
*-linux-ppc ) run_dir linux-ppc ;;
*-linux-riscv64 ) run_dir linux-riscv64 ;;
*-linux-x86 ) run_dir linux-x86 ;;
*-linux-x86_64 ) run_dir linux-x86_64 ;;
*-linux-lexra ) run_dir linux-lexra ;;
@@ -546,8 +590,8 @@ jobs:
run: |
rm -rf ${{ env.repo_dir }}/.git*
find ${{ env.repo_dir }}/binaries -type f -exec sha256sum {} \; >sha256sum.txt
tar --owner=0 --group=0 -czf ${{ env.repo_dir }}.tar.gz ${{ env.repo_dir }}
zip -qr ${{ env.repo_dir }}.zip ${{ env.repo_dir }}
tar --owner=0 --group=0 -c ${{ env.repo_dir }} | pigz -11 >${{ env.repo_dir }}.tar.gz
zip -9qr ${{ env.repo_dir }}.zip ${{ env.repo_dir }}
(
cd ${{ env.repo_dir }}
rm -rf binaries/{android*,freebsd*,win*} \
@@ -555,7 +599,7 @@ jobs:
nfq2 ip2net mdig docs Makefile
pigz -11 lua/*.lua
)
tar --owner=0 --group=0 -czf ${{ env.repo_dir }}-openwrt-embedded.tar.gz ${{ env.repo_dir }}
tar --owner=0 --group=0 -c ${{ env.repo_dir }} | pigz -11 >${{ env.repo_dir }}-openwrt-embedded.tar.gz
- name: Upload release assets
uses: softprops/action-gh-release@v2
+1
View File
@@ -11,3 +11,4 @@ ipset/zapret-ip*.txt
ipset/zapret-ip*.gz
ipset/zapret-hosts*.txt
ipset/zapret-hosts*.gz
.vscode/
+22 -1
View File
@@ -3,6 +3,11 @@ LIST_HTTPS_TLS12="${LIST_HTTPS_TLS12:-$TESTDIR/list_https_tls12.txt}"
LIST_HTTPS_TLS13="${LIST_HTTPS_TLS13:-$TESTDIR/list_https_tls13.txt}"
LIST_QUIC="${LIST_QUIC:-$TESTDIR/list_quic.txt}"
emptyf()
{
:
}
check_list()
{
# $1 - test function
@@ -19,7 +24,23 @@ check_list()
""|\#*) continue ;;
esac
line=$(echo "$line" | tr -d "\r\n")
eval pktws_curl_test_update "$1" "$2" $line && ok=1
# dry run eval in subshell. can fail because of unescaped chars or something else
if (eval emptyf $line) 2>/dev/null; then
# real run in the current shell. can modify vars
eval pktws_curl_test_update "$1" "$2" $line && ok=1
else
# $line contains characters that are meaningful to nfqws2/lua-desync
# syntax (e.g. "<" in --out-range=s1<d1, or "(" and "'" in a
# --lua-init=...=tls_mod(...,'rnd') expression) but aren't valid
# shell syntax on their own, so the dry run above rejected it.
# Fall back to a plain (non-eval) split: $line is only word-split
# on whitespace here, nothing in it is re-parsed as shell syntax,
# so these can be used exactly as blockcheck2 itself prints them,
# with no manual escaping needed.
pktws_curl_test_update "$1" "$2" $line && ok=1
echo >&2 'WARNING: this strategy fails eval (may be unescaped special characters). using fallback space separated method'
echo >&2 "WARNING: exact line : $line"
fi
done < "$3"
[ "$ok" = 1 ]
+2 -2
View File
@@ -2,11 +2,11 @@
Скопируйте эту директорию под другим именем в blockcheck2.d, отредактируйте list файлы, впишите туда свои стратегии.
В диалоге blockcheck2.sh выберите тест с названием вашей директории.
Можно комментировать строки символом '#' в начале строки.
Параметры со спец символами типа "<" должны быть эскейпнуты по правилам shell.
Параметры со спец символами типа "<" больше не обязательно эскейпить - если строка не разбирается как shell, она пробуется заново буквально. Эскейпинг по правилам shell по-прежнему работает и пробуется первым.
Альтернативный путь до файлов стратегий можно задать переменными LIST_HTTP, LIST_HTTPS_TLS12, LIST_HTTPS_TLS13, LIST_QUIC.
This is simple strategy tester from a file.
Copy this folder, write your strategies into list files and select your test in blockcheck2 dialog.
Lines can be commented using the '#' symbol at the line start.
Parameters with special symbols like "<" must be escaped.
Parameters with special symbols like "<" no longer need escaping - a line that doesn't parse as shell is retried literally instead of failing. Escaping by shell rules still works too and is tried first.
Strategy list files paths can be overriden in env variables : LIST_HTTP, LIST_HTTPS_TLS12, LIST_HTTPS_TLS13, LIST_QUIC.
+2 -2
View File
@@ -5,9 +5,9 @@ pktws_oob()
# $1 - test function
# $2 - domain
local dropacks urp
local urp
for urp in b 0 2 midsld; do
pktws_curl_test_update "$1" "$2" --in-range=-s1 --lua-desync=oob:urp=$urp$dropack
pktws_curl_test_update "$1" "$2" --in-range=-s1 --lua-desync=oob:urp=$urp
done
}
+1 -1
View File
@@ -63,7 +63,7 @@ pktws_seqovl_tests_tls()
for split in '1 2' 'sniext sniext+1' 'sniext+3 sniext+4' 'midsld-1 midsld' '1 2,midsld'; do
f="$(extract_arg 1 $split)"
f2="$(extract_arg 2 $split)"
pktws_curl_test_update $1 $2 $PAYLOAD --lua-desync=$MULTIDISORDER:pos=$f2:seqovl=$f && ok=1
pktws_curl_test_update $1 $2 $pre $PAYLOAD --lua-desync=$MULTIDISORDER:pos=$f2:seqovl=$f && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=$MULTIDISORDER:pos=$f2:seqovl=$f:seqovl_pattern=$pat && ok=1
done
[ "$ok" = 1 ] && ok_any=1
+1 -1
View File
@@ -11,7 +11,7 @@ pktws_check_http()
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}
pktws_curl_test_update "$1" "$2" --lua-desync=syndata:blob=fake_default_http ${split:+$PAYLOAD --lua-desync=$split}
done
}
+9
View File
@@ -41,7 +41,9 @@ pktws_check_http()
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=fake_http:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS && ok=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --payload=empty "--out-range=<s1" --lua-desync=send:$TCP_MD5 && ok=1
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
for ttl in $attls; do
for ff in $fake 0x00000000; do
@@ -52,6 +54,7 @@ pktws_check_http()
}
done
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_fake=1
@@ -64,9 +67,13 @@ pktws_fake_https_vary_()
local ok_any=0 testf=$1 domain="$2" fooling="$3" pre="$4" post="$5"
shift; shift; shift
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=multisplit:blob=$fake:$fooling:pos=2:nodrop:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid,padencap:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 ] && ok=1
}
@@ -115,11 +122,13 @@ pktws_check_https_tls()
done
for fooling in $FOOLINGS_TCP; do
pktws_fake_https_vary $testf $domain "$fooling" "$pre"
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
for ttl in $attls; do
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
pktws_fake_https_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_fake=1
+6
View File
@@ -35,6 +35,7 @@ pktws_check_faked()
[ "$SCANLEVEL" = force ] || break
}
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$ok" = 1 ] && break
done
@@ -43,7 +44,9 @@ pktws_check_faked()
pktws_curl_test_update $testf $domain ${FAKED_PATTERN:+--blob=faked_pat:@"$FAKED_PATTERN" }$pre $PAYLOAD --lua-desync=$splitf:${FAKED_PATTERN:+pattern=faked_pat:}pos=$split:$fooling && ok=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKED_PATTERN:+--blob=faked_pat:@"$FAKED_PATTERN" }$pre $PAYLOAD --lua-desync=$splitf:${FAKED_PATTERN:+pattern=faked_pat:}pos=$split:$fooling:repeats=$FAKE_REPEATS --payload=empty --out-range="<s1" --lua-desync=send:$TCP_MD5 && ok=1
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
for ttl in $attls; do
for split in $splits; do
@@ -53,10 +56,13 @@ pktws_check_faked()
[ "$SCANLEVEL" = force ] || break
}
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ $ok = 0 -a "$SCANLEVEL" != force ] && eval need_$splitf=1
[ $ok = 1 ] && ok_any=1
[ "$SCANLEVEL" = veryquick -a "$ok_any" = 1 ] && break
done
[ "$ok_any" = 1 ]
}
+8
View File
@@ -7,11 +7,17 @@ pktws_hostfake_vary_()
for disorder in '' 'disorder_after:'; do
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake1:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake2:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake1:midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake2:midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
done
[ "$ok_any" = 1 ] && ok=1
}
@@ -51,11 +57,13 @@ pktws_check_hostfake()
done
for fooling in $FOOLINGS_TCP; do
pktws_hostfake_vary $testf $domain "$fooling" "$pre"
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
for ttl in $attls; do
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
pktws_hostfake_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_hostfakesplit=1
[ $ok = 1 ]
+10
View File
@@ -70,9 +70,13 @@ pktws_fake_https_vary_()
local ok_any=0 testf=$1 domain="$2" fooling="$3" pre="$4" post="$5"
shift; shift; shift
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=multisplit:blob=$fake:$fooling:pos=2:nodrop:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid,padencap:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split $post && ok_any=1
[ "$ok_any" = 1 ] && ok=1
}
@@ -122,22 +126,28 @@ pktws_check_https_tls()
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
pktws_fake_https_vary $testf $domain "ip${IPVV}_ttl=$ttl" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$ok" = 1 ] && break
done
for fooling in $FOOLINGS_TCP; do
for split in $splits; do
pktws_fake_https_vary $testf $domain "$fooling" "$pre"
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
for ttl in $attls; do
for split in $splits; do
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
pktws_fake_https_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$ok" = 1 ] && ok_any=1
[ "$SCANLEVEL" = veryquick -a "$ok_any" = 1 ] && break
done
[ "$ok_any" = 1 ]
}
+21 -5
View File
@@ -38,6 +38,7 @@ pktws_check_http()
}
done
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$ok" = 1 ] && break
done
@@ -48,7 +49,9 @@ pktws_check_http()
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }${FAKED_PATTERN_HTTP:+--blob=faked_pat:@"$FAKED_PATTERN_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTP:+pattern=faked_pat:}pos=$split:$fooling:repeats=$FAKE_REPEATS --payload=empty "--out-range=<s1" --lua-desync=send:$TCP_MD5 && ok=1
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
for ttl in $attls; do
for split in $splits; do
@@ -60,8 +63,11 @@ pktws_check_http()
}
done
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
}
@@ -69,11 +75,15 @@ pktws_fake_https_vary_()
{
local ok_any=0 testf=$1 domain="$2" fooling="$3" pre="$4" post="$5"
shift; shift; shift
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
pktws_curl_test_update $testf $domain ${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=multisplit:blob=$fake:$fooling:pos=2:nodrop:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid,padencap:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS:+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain ${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS:+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=0x00000000:$fooling:repeats=$FAKE_REPEATS --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS:+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=multisplit:blob=$fake:$fooling:pos=2:nodrop:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS:+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
[ "$ok_any" = 1 -a "$SCANLEVEL" = veryquick ] && { ok=1; return 0; }
pktws_curl_test_update $testf $domain ${FAKE_HTTPS:+--blob=$fake:@"$FAKE_HTTPS" }${FAKED_PATTERN_HTTPS:+--blob=faked_pat:@"$FAKED_PATTERN_HTTPS" }$pre $PAYLOAD --lua-desync=fake:blob=$fake:$fooling:tls_mod=rnd,dupsid,padencap:repeats=$FAKE_REPEATS --lua-desync=$splitf:${FAKED_PATTERN_HTTPS:+pattern=faked_pat:}pos=$split:$fooling $post && ok_any=1
[ "$ok_any" = 1 ] && ok=1
}
@@ -123,22 +133,28 @@ pktws_check_https_tls()
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
pktws_fake_https_vary $testf $domain "ip${IPVV}_ttl=$ttl" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$ok" = 1 ] && break
done
for fooling in $FOOLINGS_TCP; do
for split in $splits; do
pktws_fake_https_vary $testf $domain "$fooling" "$pre"
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
for ttl in $attls; do
for split in $splits; do
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
pktws_fake_https_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$ok" = 1 ] && ok_any=1
[ "$SCANLEVEL" = veryquick -a "$ok_any" = 1 ] && break
done
[ "$ok_any" = 1 ]
}
@@ -7,11 +7,17 @@ pktws_hostfake_vary_()
for disorder in '' 'disorder_after:'; do
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}$fooling:repeats=$FAKE_REPEATS $post && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake1:$fooling:repeats=$FAKE_REPEATS $post && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake2:$fooling:repeats=$FAKE_REPEATS $post && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake1:midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
pktws_curl_test_update $testf $domain $pre ${FAKE:+--blob=$fake:@"$FAKE" }$PAYLOAD --lua-desync=fake:blob=$fake:$fooling:repeats=$FAKE_REPEATS --lua-desync=hostfakesplit:${HOSTFAKE:+host=${HOSTFAKE}:}${disorder}nofake2:midhost=midsld:$fooling:repeats=$FAKE_REPEATS $post && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" = veryquick ] && return 0
done
}
pktws_hostfake_vary()
@@ -48,6 +54,7 @@ pktws_check_hostfake()
done
for fooling in $FOOLINGS_TCP; do
pktws_hostfake_vary $testf $domain "$fooling" "$pre" && ok=1
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
for ttl in $attls; do
for f in '' "--payload=empty --out-range=s1<d1 --lua-desync=pktmod:ip${IPVV}_ttl=1"; do
@@ -56,6 +63,7 @@ pktws_check_hostfake()
[ "$SCANLEVEL" = force ] || break
}
done
[ "$SCANLEVEL" = veryquick -a "$ok" = 1 ] && break
done
[ "$ok" = 1 ]
}
+225 -40
View File
@@ -34,9 +34,12 @@ DVTWS2=${DVTWS2:-${ZAPRET_BASE}/nfq2/dvtws2}
WINWS2=${WINWS2:-${ZAPRET_BASE}/nfq2/winws2}
MDIG=${MDIG:-${ZAPRET_BASE}/mdig/mdig}
DESYNC_MARK=0x10000000
PACE=${PACE:-0}
CURL_MAX_TIME=${CURL_MAX_TIME:-2}
CURL_MAX_TIME_QUIC=${CURL_MAX_TIME_QUIC:-$CURL_MAX_TIME}
CURL_MAX_TIME_DOH=${CURL_MAX_TIME_DOH:-2}
CURL_PAD=${CURL_PAD:-0}
PAD_MAX_HEADER=${PAD_MAX_HEADER:-4000}
USER_AGENT=${USER_AGENT:-Mozilla}
HTTP_PORT=${HTTP_PORT:-80}
HTTPS_PORT=${HTTPS_PORT:-443}
@@ -49,13 +52,19 @@ IPFW_RULE_NUM=${IPFW_RULE_NUM:-$(($$ % $IPFW_RULE_MAX + 1))}
IPFW_DIVERT_PORT=${IPFW_DIVERT_PORT:-$(($$ % 64536 + 1000))}
QNUM=${QNUM:-$(($$ % 64536 + 1000))}
IPSET_FILE=/tmp/blockcheck_ipset_$$.txt
PARALLEL_OUT=/tmp/zapret_parallel_$$
HDRTEMP=/tmp/zapret-hdr-$$
NFT_TABLE=blockcheck$$
IPT_OUT_CHAIN=blockcheck_output_$$
IPT_IN_CHAIN=blockcheck_input_$$
IPT_COMMENT="-m comment --comment blockcheck_$$"
PARALLEL_OUT_TEMPLATE=/tmp/zapret2_parallel_
PARALLEL_OUT=$PARALLEL_OUT_TEMPLATE$$
HDRTEMP_TEMPLATE=/tmp/zapret2-hdr-
HDRTEMP=$HDRTEMP_TEMPLATE$$
CURL_PAD_FILE_TEMPLATE=/tmp/zapret2-curlpad-
NFT_TABLE_TEMPLATE=blockcheck2-
NFT_TABLE=$NFT_TABLE_TEMPLATE$$
IPT_OUT_CHAIN_TEMPLATE=blockcheck2_output_
IPT_OUT_CHAIN=$IPT_OUT_CHAIN_TEMPLATE$$
IPT_IN_CHAIN_TEMPLATE=blockcheck2_input_
IPT_IN_CHAIN=$IPT_IN_CHAIN_TEMPLATE$$
IPT_COMMENT="-m comment --comment blockcheck2_$$"
DNSCHECK_DNS=${DNSCHECK_DNS:-8.8.8.8 1.1.1.1 77.88.8.1}
DNSCHECK_DOM=${DNSCHECK_DOM:-pornhub.com ej.ru rutracker.org www.torproject.org bbc.com}
@@ -64,17 +73,67 @@ DNSCHECK_DIG1=/tmp/dig1.txt
DNSCHECK_DIG2=/tmp/dig2.txt
DNSCHECK_DIGS=/tmp/digs.txt
GUARD_TIMER="timer_set('exit_guard',function(name,data) io.stderr:write('exit_guard\n'); os.exit(3000); end,20000,true)"
unset PF_STATUS
PF_RULES_SAVE=/tmp/pf-zapret-save.conf
PF_RULES_SAVE=/tmp/pf-zapret2-save.conf
unset ALL_PROXY
apply_header_padfile()
{
local n=1 left size f pid
# A normal exit already removes this run's own pad file (see
# cleanup() below), which covers Ctrl+C, a closed terminal, and
# a plain kill. kill -9 and crashes bypass that, as they would
# for any script's cleanup, so sweep any such leftover from
# a previous run before making this run's own - only once its PID
# is confirmed no longer running, so a genuinely still-running
# concurrent instance (different PID, its own file) is never
# touched
for f in $CURL_PAD_FILE_TEMPLATE*; do
[ -e "$f" ] || continue
pid=${f##*-}
case "$pid" in ''|*[!0-9]*) continue ;; esac
kill -0 "$pid" 2>/dev/null || rm -f "$f"
done
if [ "$CURL_PAD" -gt 0 ] 2>/dev/null; then
left=$CURL_PAD
CURL_PAD_FILE=$CURL_PAD_FILE_TEMPLATE$$
rm -f "$CURL_PAD_FILE"
touch "$CURL_PAD_FILE"
while [ "$left" -ge 14 ]; do
left=$(($left-14))
if [ "$left" -gt "$PAD_MAX_HEADER" ]; then
size="$PAD_MAX_HEADER"
else
size=$left
fi
left=$(($left-$size))
# if the next header would be too small add the remainder to the current header
[ "$left" -lt 14 ] && size=$(($size+$left))
printf 'X-Pad-%04d: ' $n >> "$CURL_PAD_FILE"
printf "%${size}s" | tr ' ' 'A' >> "$CURL_PAD_FILE"
# curl internally adds 0D0A line ending even if it's 0A in the file
echo >> "$CURL_PAD_FILE"
n=$(($n+1))
done
CURL_OPT="${CURL_OPT}${CURL_OPT:+ }-H @$CURL_PAD_FILE"
fi
}
killwait()
{
# $1 - signal (-9, -2, ...)
# $2 - pid
kill $1 $2
local KILL=kill
# avoid internal bash kill in cygwin to support -f
[ "$UNAME" = "CYGWIN" ] && KILL=/bin/kill
$KILL $1 $2
# suppress job kill message
wait $2 2>/dev/null
}
@@ -161,6 +220,7 @@ cleanup()
pf_clean
;;
esac
[ -n "$CURL_PAD_FILE" ] && rm -f "$CURL_PAD_FILE"
}
IPT()
@@ -634,8 +694,13 @@ curl_with_subst_ip()
local connect_to="--connect-to $1::$ip${2:+:$2}" arg
shift ; shift ; shift;
[ "$CURL_VERBOSE" = 1 ] && arg="-v"
[ "$CURL_CMD" = 1 ] && echo $CURL ${arg:+$arg }$connect_to "$@"
ALL_PROXY="$ALL_PROXY" "$CURL" ${arg:+$arg }$connect_to "$@"
[ "$CURL_CMD" = 1 ] && echo $CURL -w "%{time_total}" ${arg:+$arg }$connect_to "$@"
local tooks
tooks=$(ALL_PROXY="$ALL_PROXY" "$CURL" -w "%{time_total}" ${arg:+$arg }$connect_to "$@")
local ret=$?
local tookms=$(awk "BEGIN {print int($tooks * 1000)}")
[ "$PACE" -gt "$tookms" ] && msleep $(($PACE - $tookms))
return "$ret"
}
curl_with_dig()
{
@@ -819,7 +884,7 @@ pktws_ipt_prepare()
# $2 - port
# $3 - ip list
local ip
local ip v=
case "$FWTYPE" in
iptables)
@@ -839,10 +904,12 @@ pktws_ipt_prepare()
opf_prepare_dvtws $1 $2 "$3"
;;
windivert)
[ "$IPV" = 6 ] && v="v6"
WF="--wf-l3=ipv${IPV} --wf-${1}-out=$2"
rm -f "$IPSET_FILE"
WFRAWF=
for ip in $3; do
echo $ip >>"$IPSET_FILE"
[ -n "$WFRAWF" ] && WFRAWF="$WFRAWF or "
WFRAWF="${WFRAWF}ip${v}.DstAddr=$ip or ip${v}.SrcAddr=$ip"
done
;;
@@ -871,8 +938,7 @@ pktws_ipt_unprepare()
pf_restore
;;
windivert)
unset WF
rm -f "$IPSET_FILE"
unset WF WFRAWF
;;
esac
}
@@ -940,29 +1006,70 @@ pktws_ipt_unprepare_udp()
pktws_ipt_unprepare udp $1
}
pktws_ipt_sweep()
{
# remove leftovers after hard kill/crash
local f pid IPTABLES
case "$FWTYPE" in
nftables)
nft list tables | grep '^table inet blockcheck2-' | while IFS= read -r f; do
pid=${f##*-}
case "$pid" in ''|*[!0-9]*) continue ;; esac
kill -0 "$pid" 2>/dev/null || nft delete $f
done
;;
iptables)
for IPTABLES in iptables ip6tables; do
$IPTABLES -t mangle -S | grep -o -e "INPUT -j $IPT_IN_CHAIN_TEMPLATE[0-9]\+" -e "OUTPUT -j $IPT_OUT_CHAIN_TEMPLATE[0-9]\+" | while IFD= read -r f; do
pid=${f##*_}
case "$pid" in ''|*[!0-9]*) continue ;; esac
kill -0 "$pid" 2>/dev/null || $IPTABLES -t mangle -D $f
done
$IPTABLES -t mangle -S | grep -o -e "$IPT_IN_CHAIN_TEMPLATE[0-9]\+" -e "$IPT_OUT_CHAIN_TEMPLATE[0-9]\+" | sort -u | while IFD= read -r f; do
pid=${f##*_}
case "$pid" in ''|*[!0-9]*) continue ;; esac
kill -0 "$pid" 2>/dev/null || {
$IPTABLES -t mangle -F $f
$IPTABLES -t mangle -X $f
}
done
done
;;
esac
}
pktws_start()
{
case "$UNAME" in
Linux)
"$NFQWS2" --uid $WS_UID:$WS_GID --fwmark=$DESYNC_MARK --qnum=$QNUM --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
"$NFQWS2" --uid $WS_UID:$WS_GID --fwmark=$DESYNC_MARK --qnum=$QNUM --lua-init="$GUARD_TIMER" --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
;;
FreeBSD|OpenBSD)
"$DVTWS2" --port=$IPFW_DIVERT_PORT --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
"$DVTWS2" --port=$IPFW_DIVERT_PORT --lua-init="$GUARD_TIMER" --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
;;
CYGWIN)
# allow multiple PKTWS instances with the same wf filter but different ipset
# some methods require empty acks
"$WINWS2" --wf-dup-check=0 --wf-tcp-empty=1 $WF --ipset="$IPSET_FILE" --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
# use raw filter to filter target ip addresses in-kernel to allow multiple blockchecks running at the same time
# use guard timer to kill unmanaged pktws instances
"$WINWS2" --wf-tcp-empty=1 $WF --wf-raw-filter="$WFRAWF" \
--lua-init="$GUARD_TIMER" \
--lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
;;
esac
PID=$!
# give some time to initialize
minsleep
}
ws_kill()
{
local sig
[ -z "$PID" ] || {
killwait -9 $PID 2>/dev/null
sig=-9
# use fast kill using TerminateProcess() in cygwin
[ "$UNAME" = "CYGWIN" ] && sig=-f
killwait $sig $PID 2>/dev/null
PID=
}
}
@@ -1026,7 +1133,7 @@ curl_test()
[ $REPEATS -gt 1 ] && echo 'AVAILABLE'
else
code=$?
[ "$SCANLEVEL" = quick ] && break
[ "$SCANLEVEL" = quick -o "$SCANLEVEL" = veryquick ] && break
fi
done
fi
@@ -1089,7 +1196,7 @@ pktws_curl_test()
}
strategy_append_extra_pktws()
{
strategy="${strategy:+${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }$strategy${PKTWS_EXTRA_POST:+ $PKTWS_EXTRA_POST}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_POST_1"}${PKTWS_EXTRA_POST_2:+ "$PKTWS_EXTRA_POST_2"}${PKTWS_EXTRA_POST_3:+ "$PKTWS_EXTRA_POST_3"}${PKTWS_EXTRA_POST_4:+ "$PKTWS_EXTRA_POST_4"}${PKTWS_EXTRA_POST_5:+ "$PKTWS_EXTRA_POST_5"}${PKTWS_EXTRA_POST_6:+ "$PKTWS_EXTRA_POST_6"}${PKTWS_EXTRA_POST_7:+ "$PKTWS_EXTRA_POST_7"}${PKTWS_EXTRA_POST_8:+ "$PKTWS_EXTRA_POST_8"}${PKTWS_EXTRA_POST_9:+ "$PKTWS_EXTRA_POST_9"}}"
strategy="${strategy:+${PKTWS_EXTRA_PRE:+$PKTWS_EXTRA_PRE }${PKTWS_EXTRA_PRE_1:+"$PKTWS_EXTRA_PRE_1" }${PKTWS_EXTRA_PRE_2:+"$PKTWS_EXTRA_PRE_2" }${PKTWS_EXTRA_PRE_3:+"$PKTWS_EXTRA_PRE_3" }${PKTWS_EXTRA_PRE_4:+"$PKTWS_EXTRA_PRE_4" }${PKTWS_EXTRA_PRE_5:+"$PKTWS_EXTRA_PRE_5" }${PKTWS_EXTRA_PRE_6:+"$PKTWS_EXTRA_PRE_6" }${PKTWS_EXTRA_PRE_7:+"$PKTWS_EXTRA_PRE_7" }${PKTWS_EXTRA_PRE_8:+"$PKTWS_EXTRA_PRE_8" }${PKTWS_EXTRA_PRE_9:+"$PKTWS_EXTRA_PRE_9" }$strategy${PKTWS_EXTRA_POST:+ $PKTWS_EXTRA_POST}${PKTWS_EXTRA_POST_1:+ "$PKTWS_EXTRA_POST_1"}${PKTWS_EXTRA_POST_2:+ "$PKTWS_EXTRA_POST_2"}${PKTWS_EXTRA_POST_3:+ "$PKTWS_EXTRA_POST_3"}${PKTWS_EXTRA_POST_4:+ "$PKTWS_EXTRA_POST_4"}${PKTWS_EXTRA_POST_5:+ "$PKTWS_EXTRA_POST_5"}${PKTWS_EXTRA_POST_6:+ "$PKTWS_EXTRA_POST_6"}${PKTWS_EXTRA_POST_7:+ "$PKTWS_EXTRA_POST_7"}${PKTWS_EXTRA_POST_8:+ "$PKTWS_EXTRA_POST_8"}${PKTWS_EXTRA_POST_9:+ "$PKTWS_EXTRA_POST_9"}}"
}
@@ -1172,6 +1279,29 @@ result_intersection_print()
n=$(($n + 1))
done
}
result_coverage_print()
{
# Lists every distinct successful strategy together with how many of the
# DOMAINS_COUNT domains/targets it worked for, most-covered first.
# Unlike result_intersection_print, a strategy doesn't need 100% coverage
# to be listed here - useful when DOMAINS is a set of largely independent
# targets (e.g. one IP per ASN/provider) where no single strategy is
# expected to satisfy every one of them, and the question is which
# strategy gets closest.
local n=0 hash hashvar hashcountvar ct val
while : ; do
eval hash=\"\$RES_$n\"
[ -n "$hash" ] || break
hashvar=RESHASH_${hash}
hashcountvar=${hashvar}_COUNTER
eval ct=\"\$$hashcountvar\"
eval val=\"\$$hashvar\"
printf '%s %s\n' "$ct" "$val"
n=$(($n + 1))
done | sort -rn | while IFS=' ' read -r ct rest; do
echo "$ct/$DOMAINS_COUNT : $rest"
done
}
report_strategy()
{
# $1 - test function
@@ -1576,11 +1706,13 @@ ask_params()
echo "TLS 1.3 only strategy is better than nothing."
ask_yes_no_var ENABLE_HTTPS_TLS13 "check https tls 1.3"
}
else
echo
echo "installed curl version does not support TLS 1.3 . tests disabled."
fi
}
[ "$ENABLE_HTTPS_TLS13" = 1 -a -z "$TLS13" ] && {
echo
echo "WARNING ! installed curl version does not support TLS 1.3 . tests disabled."
ENABLE_HTTPS_TLS13=0
}
[ -n "$ENABLE_HTTP3" ] || {
ENABLE_HTTP3=0
@@ -1591,11 +1723,13 @@ ask_params()
echo "make sure target domain(s) support QUIC or result will be negative in any case"
ask_yes_no_var ENABLE_HTTP3 "check http3 QUIC"
}
else
echo
echo "installed curl version does not support http3 QUIC. tests disabled."
fi
}
[ "$ENABLE_HTTP3" = 1 -a -z "$HTTP3" ] && {
echo
echo "WARNING ! installed curl version does not support http3 QUIC. tests disabled."
ENABLE_HTTP3=0
}
[ -n "$REPEATS" ] || {
[ "$BATCH" = 1 ] || {
@@ -1624,10 +1758,11 @@ ask_params()
SCANLEVEL=standard
[ "$BATCH" = 1 ] || {
echo
echo quick - in multi-attempt mode skip further attempts after first failure
echo standard - do investigation what works on your DPI
echo force - scan maximum despite of result
ask_list SCANLEVEL "quick standard force" "$SCANLEVEL"
echo veryquick - same as quick, and also stop testing more variations of a strategy family once one already succeeds
echo quick - in multi-attempt mode skip further attempts after first failure
echo standard - do investigation what works on your DPI
echo force - scan maximum despite of result
ask_list SCANLEVEL "veryquick quick standard force" "$SCANLEVEL"
}
}
@@ -1826,6 +1961,49 @@ check_dns()
return $r
}
sweep_stale_pidfiles()
{
# $1 - fixed filename prefix immediately preceding the pid
#
# A normal exit already removes this run's own PARALLEL_OUT/HDRTEMP
# files (unprepare_all(), further down), which covers Ctrl+C,
# a closed terminal, and a plain kill. kill -9 and crashes bypass
# that, as they would for any script's cleanup, and can leave
# stale files behind indefinitely, since nothing about a later run
# gives it any reason to know about a different PID's leftovers.
# Removes a matching file only once its PID (the run that created
# it) is confirmed no longer running, so a genuinely still-running
# concurrent instance - a different PID, its own files - is never
# touched.
local f pid prefix="$1"
for f in "$prefix"*; do
[ -e "$f" ] || continue
pid=${f#"$prefix"}
pid=${pid%%[!0-9]*}
[ -n "$pid" ] || continue
kill -0 "$pid" 2>/dev/null || rm -f "$f"
done
}
sweep_leftovers()
{
sweep_stale_pidfiles $PARALLEL_OUT_TEMPLATE
sweep_stale_pidfiles $HDRTEMP_TEMPLATE
pktws_ipt_sweep
}
block_signals()
{
# prevent signal function reenter
trap '' QUIT TERM HUP PIPE INT
}
untrap()
{
trap - QUIT TERM HUP PIPE INT
}
unprepare_all()
{
# make sure we are not in a middle state that impacts connectivity
@@ -1841,18 +2019,23 @@ unprepare_all()
}
sigint()
{
block_signals
echo
echo terminating...
unprepare_all
# exitp can wait for the user input. restore default signal behavior without trap
untrap
exitp 1
}
sigint_cleanup()
{
block_signals
cleanup
exit 1
}
sigsilent()
{
block_signals
# must not write anything here to stdout
unprepare_all
exit 1
@@ -1863,19 +2046,20 @@ fix_sbin_path
check_system
check_already
[ "$UNAME" != CYGWIN -a "$SKIP_PKTWS" != 1 ] && require_root
sweep_leftovers
check_prerequisites
trap sigint_cleanup INT
check_dns
check_virt
ask_params
apply_header_padfile
trap - INT
PID=
NREPORT=
unset WF
trap sigint INT
trap sigsilent PIPE
trap sigsilent HUP
trap sigsilent PIPE HUP TERM QUIT
for dom in $DOMAINS; do
for IPV in $IPVS; do
configure_ip_version
@@ -1889,9 +2073,7 @@ for dom in $DOMAINS; do
[ "$ENABLE_HTTP3" = 1 ] && check_domain_http3 $dom
done
done
trap - HUP
trap - PIPE
trap - INT
untrap
cleanup
@@ -1903,10 +2085,13 @@ report_print
echo \* COMMON
result_intersection_print
echo
echo \* COVERAGE
result_coverage_print
echo
[ "$SCANLEVEL" = force ] || {
echo "blockcheck optimizes test sequence. To save time some strategies can be skipped if their test is considered useless."
echo "That's why COMMON intersection can miss strategies that would work for all domains."
echo "Use \"force\" scan level to test all strategies and generate trustable intersection."
echo "That's why COMMON intersection can miss strategies that would work for all domains, and COVERAGE counts can undercount."
echo "Use \"force\" scan level to test all strategies and generate trustable results."
echo "Current scan level was \"$SCANLEVEL\"".
}
}
+7 -8
View File
@@ -426,14 +426,6 @@ alloc_num()
eval $1="$v"
}
std_ports()
{
NFQWS2_PORTS_TCP_IPT=$(replace_char - : $NFQWS2_PORTS_TCP)
NFQWS2_PORTS_TCP_KEEPALIVE_IPT=$(replace_char - : $NFQWS2_PORTS_TCP_KEEPALIVE)
NFQWS2_PORTS_UDP_IPT=$(replace_char - : $NFQWS2_PORTS_UDP)
NFQWS2_PORTS_UDP_KEEPALIVE_IPT=$(replace_char - : $NFQWS2_PORTS_UDP_KEEPALIVE)
}
has_bad_ws_options()
{
# $1 - nfqws2 opts
@@ -446,6 +438,13 @@ has_bad_ws_options()
echo "Kernel ipsets should be used instead. Write custom scripts and filter IPs in kernel."
echo
}
contains "$1" "--ipset=$ZAPRET_BASE" || contains "$1" "--ipset-exclude=$ZAPRET_BASE" ||
contains "$1" "--hostlist=$ZAPRET_BASE" || contains "$1" "--hostlist-exclude=$ZAPRET_BASE" && {
echo
echo "WARNING !!! you store ipset or hostlist files inside '$ZAPRET_BASE'"
echo "It's not recommended. install_easy.sh will delete them during update."
echo
}
return 1
}
+2 -1
View File
@@ -212,7 +212,8 @@ check_system()
OPENWRT_PACKAGER=opkg
OPENWRT_PACKAGER_INSTALL="opkg install"
OPENWRT_PACKAGER_UPDATE="opkg update"
exists apk && {
# do not use apk if it does not have database
[ -d /lib/apk/db ] && exists apk && {
OPENWRT_PACKAGER=apk
OPENWRT_PACKAGER_INSTALL="apk add"
OPENWRT_PACKAGER_UPDATE=
+35 -18
View File
@@ -1,7 +1,7 @@
std_ports
ipt_connbytes="-m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes"
IPSET_EXCLUDE="-m set ! --match-set nozapret"
IPSET_EXCLUDE6="-m set ! --match-set nozapret6"
IPSET_PORTS_NAME=zport
ipt()
{
@@ -227,6 +227,16 @@ fw_reverse_nfqws_rule()
fw_reverse_nfqws_rule6 $1 "$3" $4
}
ipt_port_ipset()
{
# $1 - ipset name
# $2 - ports
ipset -q flush $1 || {
ipset create $1 bitmap:port range 0-65535 || return
}
echo "$2" | tr ',' '\n' | sed -nEe "s/^.+$/add $1 &/p" | ipset -! restore
}
ipt_first_packets()
{
# $1 - packet count
@@ -237,26 +247,31 @@ ipt_do_nfqws_in_out()
# $1 - 1 - add, 0 - del
# $2 - tcp,udp
# $3 - ports
# $4 - PKT_OUT. special value : 'keepalive'
# $5 - PKT_IN
local f4 f6 first_packets_only
# $4 - PKT. special value : 'keepalive'
# $5 - 1 - out, 0 - in
# $6 - ipset base name
local f f4 f6 first_packets_only ipset
[ -n "$3" ] || return
ipset="${6}_$2"
[ "$4" = keepalive ] && ipset="${ipset}_k"
[ "$1" = 1 ] && ipt_port_ipset $ipset "$3"
[ -n "$4" -a "$4" != 0 ] &&
{
first_packets_only="$(ipt_first_packets $4)"
f4="-p $2 -m multiport --dports $3 $first_packets_only"
f4="-p $2 -m set --match-set $ipset"
if [ "$5" = 1 ]; then
f4="$f4 dst"
f=fw_nfqws_post
else
f4="$f4 src"
f=fw_reverse_nfqws_rule
fi
f4="$f4 $first_packets_only"
f6=$f4
filter_apply_ipset_target f4 f6
fw_nfqws_post $1 "$f4" "$f6" $QNUM
}
[ -n "$5" -a "$5" != 0 ] &&
{
first_packets_only="$(ipt_first_packets $5)"
f4="-p $2 -m multiport --dports $3 $first_packets_only"
f6=$f4
filter_apply_ipset_target f4 f6
fw_reverse_nfqws_rule $1 "$f4" "$f6" $QNUM
$f $1 "$f4" "$f6" $QNUM
}
[ "$1" = 1 ] || ipset -q destroy $ipset
}
zapret_do_firewall_standard_nfqws_rules_ipt()
@@ -264,10 +279,12 @@ zapret_do_firewall_standard_nfqws_rules_ipt()
# $1 - 1 - add, 0 - del
[ "$NFQWS2_ENABLE" = 1 ] && {
ipt_do_nfqws_in_out $1 tcp "$NFQWS2_PORTS_TCP_IPT" "$NFQWS2_TCP_PKT_OUT" "$NFQWS2_TCP_PKT_IN"
ipt_do_nfqws_in_out $1 tcp "$NFQWS2_PORTS_TCP_KEEPALIVE_IPT" keepalive "$NFQWS2_TCP_PKT_IN"
ipt_do_nfqws_in_out $1 udp "$NFQWS2_PORTS_UDP_IPT" "$NFQWS2_UDP_PKT_OUT" "$NFQWS2_UDP_PKT_IN"
ipt_do_nfqws_in_out $1 udp "$NFQWS2_PORTS_UDP_KEEPALIVE_IPT" keepalive "$NFQWS2_UDP_PKT_IN"
ipt_do_nfqws_in_out $1 tcp "$NFQWS2_PORTS_TCP" "$NFQWS2_TCP_PKT_OUT" 1 $IPSET_PORTS_NAME
ipt_do_nfqws_in_out $1 tcp "$NFQWS2_PORTS_TCP" "$NFQWS2_TCP_PKT_IN" 0 $IPSET_PORTS_NAME
ipt_do_nfqws_in_out $1 tcp "$NFQWS2_PORTS_TCP_KEEPALIVE" keepalive 1 $IPSET_PORTS_NAME
ipt_do_nfqws_in_out $1 udp "$NFQWS2_PORTS_UDP" "$NFQWS2_UDP_PKT_OUT" 1 $IPSET_PORTS_NAME
ipt_do_nfqws_in_out $1 udp "$NFQWS2_PORTS_UDP" "$NFQWS2_UDP_PKT_IN" 0 $IPSET_PORTS_NAME
ipt_do_nfqws_in_out $1 udp "$NFQWS2_PORTS_UDP_KEEPALIVE" keepalive 1 $IPSET_PORTS_NAME
}
}
zapret_do_firewall_standard_rules_ipt()
-1
View File
@@ -3,7 +3,6 @@ nft_connbytes="ct original packets"
# required for : nft -f -
create_dev_stdin
std_ports
nft_create_table()
{
+1 -1
View File
@@ -1,6 +1,6 @@
MIT License
Copyright (c) 2016-2025 bol-van
Copyright (c) 2016-2026 bol-van
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
+139 -7
View File
@@ -152,7 +152,7 @@ v0.8.1
* zapret-antidpi: http_unixeol
* blockcheck2: http_unixeol test
0.8.2
v0.8.2
* nfqws2: do not start if NFQWS2_COMPAT_VER unexpected
* nfqws2: cache dns response IP addresses if --ipcache-hostname enabled
@@ -163,14 +163,14 @@ v0.8.1
* winws2: --wf-filter-loopback
* blockcheck2: NOTEST_MISC_HTTP[S], NOTEST_SYNDATA_HTTP[S]
0.8.3
v0.8.3
* nfqws2, zapret-lib: gzip compression and decompression
* nfqws2: ignore trailing spaces and tabs in hostlists and ipsets. "host.com " or "1.2.3.4 " are ok now
* init.d: 99-lan-filter custom script
* mdig: --eagain, --eagain-delay
0.8.4
v0.8.4
* winws2: fix loopback large packets processing (up to 64K)
* zapret-lib, zapret-antidpi: use numeric indexes in http dissects
@@ -180,7 +180,7 @@ v0.8.1
* nfqws2: gracefully shutdown on SIGINT and SIGTERM
* nfqws2: harden wireguard detection. do not detect if reserved bytes 1..3 != 0
0.8.5
v0.8.5
* nfqws2: do not require / in the beginning of URI in http
* zapret-lib: rawsend_dissect_segmented support URG
@@ -190,13 +190,13 @@ v0.8.1
* zapret-lib: tcp_nop_del
* blockcheck2: tcp_nop_del in SYN packets with md5 in openbsd
0.8.6
v0.8.6
* winws2, blockcheck2: allow multiple instances in windows, linux, freebsd (not openbsd)
* nfqws2: fix critical bug - wrong ipv6 dissection
* zapret-auto: fix standard_failure_detector http redirect regression
0.9.0
v0.9.0
* nfqws2: removed hard check for host: presence in http_req
* nfqws2: file open test before destroying in-memory content of ipset/hostlist
@@ -215,9 +215,141 @@ v0.8.1
* winws2: use windivert bulk mode
* nfqws2: template free import
0.9.1
v0.9.1
* nfqws2: 'stat', 'clock_getfloattime' luacalls
* nfqws2: bcryptorandom normalize behavior when system entropy is low. prevent blocks
* nfqws2: --new[=name]
* winws2: fix not setting signal handlers
v0.9.2
* nfqws2: bt and utp_bt protocol detectors
* nfqws2: localtime,gmtime,timelocal,timegm luacalls
* winws2: load wlanapi.dll dynamically only if needed
* winws2: fixed lost windivert deinit on logical network disappear
v0.9.3
* nfqws2: handling of incoming fragmented packets (no reconstruct, raw ip payload)
* zapret-auto: per_instance_condition orchestrator
* zapret-auto: "instances" argument in condition orchestrator
* zapret-auto: cond_tcp_has_ts, cond_lua iff functions
* zapret-lib: replay_execution_plan and plan_clear max parameter
* init.d: use bitmap:port ipset for standard dports
* github: reduce executables files size
* install_bin: added linux-riscv64 scan dir
* github actions: added linux-riscv64 arch
v0.9.4
* github actions: update upx to 5.1.0. use upx for linux-riscv5
* github actions: stronger zip and gz compression
* nfqws2: --chdir
* nfqws2: fixed wrong scale factor application to winsize
* nfqws2: very old kernels compat
v0.9.4.2
* builder_linux: simple scripts to build static linux bins for any supported architecture
* zapret-auto: incompatible change. cond_lua "code" parameter => "cond_code". to avoid collision with luaexec
v0.9.4.3
* nfqws2: fix broken wifi ssid update
* github: revert to upx 4.2.4 for all archs except riscv64
* zapret-lib: apply_fooling throws error if tcp_ts,tcp_seq,tcp_ack,ip_ttl,ip6_ttl,ip_autottl,ip6_autottl are empty or invalid
0.9.4.4
* winws2, dvtws2: ASLR
* github, linux-builder: reduce arm executable size by 20% - move to armv7+thumb
* init.d: warn if hostlist/ipset files are inside zapret2 root
* zapret-lib: do not call apply_arg_prefix in apply_execution_plan - call it right before instance execute
0.9.4.5
* github: rollback to lj_alloc in luajit for arm64 and mips64
* github: use 16K page size for android arm64 build
* nfqws2: join fragments in quic CRYPTO reconstruction. allow intersections.
0.9.4.6
* nfqws2: fix TLS payload reassemble if L7 protocol is not TLS
0.9.4.7
* nfqws2: do not fail tls_mod if dupsid,rndsni,padencap fail
0.9.5
* nfqws2: timers
0.9.5.1
* nfqws2: timer_info, timer_enum
0.9.5.2
* nfqws2: rewrite time counting algorithm, remove --timer-res
1.0
* zapret-lib,zapret-antidpi: delay parameter in "send" desync function
* zapret-lib: fix oob urp=b case in rawsend_dissect_segmented
* nfqws2, zapret-lib: (LUA_COMPAT_VER=6) fix wrong spelling : WRITEABLE -> WRITABLE
1.0.1
* install_easy: do not use apk in openwrt if it doesn't have db in /lib/apk/db
* nfqws2: fix UAF if a timer is deleted in timer function
1.0.2
* nfqws2: fix 60 msec lua-gc default to 60 sec
1.0.3
* nfqws2: accept string or function in timer_set(). remember function as a function, not as a string.
* nfqws2: limit delayed packet queue to 64 packets (anti-ddos)
* init.d: add udp ports range 19294-19344 to discord media
* blockcheck2: use cygstart in windows to avoid fork problems (without cygwin rebase)
1.0.4
* blockcheck2: revert cygstart method as it brings more problems than profit
* nfqws2: stop execution plan in C code if a blob is unavailable
* nfqws2: desync_timer_name includes now instance name
* builder_linux: optional build with zlib-ng : set ZLIB_NG=1 variable
* github: remove high_entropy_va patch for windivert.dll, but leave dynamic_base
1.0.5
* blockcheck2: use --wf-raw-filter in Windows instead of --ipset to limit target IP addresses
* github, builder_linux: lua 5.5.1
* nfqws2: negate SSID/NLM filters
* nfqws2: desync function can explicitly return nil as a synonym of VERDICT_PASS
* nfqws2: pad tcp options with 0x00 in reconstruct. strip 0x00 ending options in dissect.
* nfqws2: --filter-mark
* zapret-lib: luaexec now passes returned verdict code
* blockcheck2: fix script crash on bad strategies from the file in custom/10-list.sh
1.0.5.1
* nfqws2: optimize profile search. fast checks first
1.0.5.2
* nfqws2: more profile search optimizations
1.0.6
* zapret-lib: dissect quic tvb values that can't fit into 52-bit mantissa into raw strings
* zapret-lib, nfqws2: treat ? and # characters as domain end in URL
* blockcheck2: in 10-list.sh try space separated logic as fallback if eval fails (useful for copy-paste from blockcheck2)
* blockcheck2: CURL_PAD - add junk headers to increase request size and trigger 16-kb block without large downloaded data
* blockcheck2: in addition to COMMON print COVERAGE section with how many domains worked for each strategy
* blockcheck2: sweep old temp files after hard kill or crash. sweep ip/nf tables in linux
* blockcheck2: pktws guard timer in all OS
* blockcheck2: request PACE-ing
* blockcheck2: veryquick scan level
-11
View File
@@ -1,11 +0,0 @@
Here listed all api breaking changes.
When something changes capable of breaking things NFQWS2_COMPAT_VER increases.
v2
* removed "stun_binding_req" specialized payload. replaced with common "stun" - any stun packets, not only binding request.
every LUA relying on desync.l7payload should be revised.
nfqws2 --payload option and init.d custom scripts must be updated.
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
+31 -4
View File
@@ -1,9 +1,36 @@
debian,ubuntu :
* debian,ubuntu :
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libmnl-dev libsystemd-dev libluajit2-5.1-dev
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libmnl-dev libsystemd-dev libluajit-5.1-dev
make -C /opt/zapret2 systemd
FreeBSD :
* fedora, rhel, centos, alma
dnf install make gcc zlib-ng-compat-devel libcap-devel libnetfilter_queue-devel libmnl-devel systemd-devel luajit-devel
make -C /opt/zapret2 systemd
* linux static :
need any x86_64 classic linux distribution
tested on debian/ubuntu/fedora 2020+
if your distro is very exotic, old or not glibc based you can debootstrap a modern debian/ubuntu system and chroot to it
NOTE: it's not possible to build luajit in chroot under standard openwrt kernel. build process requires 32-bit x86 support, kernel is compiled without it.
NOTE: toolchains are pre-compiled for x86_64 glibc. they can't run on arm or anything that is not x86_64.
optionally review "common.inc" for Lua and LuaJIT versions
debian/ubuntu: apt install curl xz-utils bzip2 unzip make gcc gcc-multilib libc6-dev libcap-dev pkg-config
fedora: dnf install curl xz bzip2 unzip make gcc glibc-devel glibc-devel.i686 libcap-devel pkg-config
copy directory "builder-linux" somethere with enough free disk space (up to 2G for all toolchains)
run "get_toolchains.sh"
select architectures you need or "ALL"
run "build_deps.sh", select "ALL"
run "build_zapret2.sh", select "ALL"
get static musl bins from "binaries" folder
"zapret2" is downloaded from github master branch. if you need specific version - download manually to "zapret2" dir
i586 and riscv64 targets are built with classic PUC Lua
* FreeBSD :
pkg install pkgconf
pkg search luajit-2
@@ -11,7 +38,7 @@ pkg search luajit-2
pkg install luajit-2.1.0.20250728
make -C /opt/zapret2
OpenBSD :
* OpenBSD :
pkg_add luajit gmake
gmake -C /opt/zapret2 bsd
+4 -4
View File
@@ -11,9 +11,9 @@ setup-x86_64.exe --allow-unsupported-windows --no-verify --site http://ctm.crouc
4) install and compile luajit from here : https://github.com/openresty/luajit2
download latest releast, unpack, cd to it's directory
download latest release, unpack, cd to it's directory
make BUILDMODE=static CFLAGS="-Os"
make BUILDMODE=static CFLAGS="-Os -DLUAJIT_DISABLE_FFI -ffat-lto-objects -flto=auto -ffunction-sections -fdata-sections -fvisibility=hidden"
make install
5) cd to %ZAPRET_BASE%/nfq2
@@ -32,5 +32,5 @@ Choose version 2.2.2 for Windows 10 and 2.2.0 for Windows 7.
8) Copy cygwin1.dll, winws2.exe, windivert.dll and windivert64.sys to one folder.
9) Run winws2.exe from cmd.exe running as administrator.
winws will not run from cygwin shell with cygwin1.dll copy in it's folder.
winws will not run without cygwin1.dll outside of cygwin shell.
winws2 will not run from cygwin shell with cygwin1.dll copy in it's folder.
winws2 will not run without cygwin1.dll outside of cygwin shell.
+122
View File
@@ -0,0 +1,122 @@
#!/bin/bash
EXEDIR="$(dirname "$0")"
EXEDIR="$(cd "$EXEDIR"; pwd)"
. "$EXEDIR/common.inc"
dl_deps()
{
[ -d "$DEPS" ] || mkdir -p "$DEPS"
(
cd "$DEPS"
exists_dir libnfnetlink-* ||
curl $CURL_OPT -Lo - https://www.netfilter.org/pub/libnfnetlink/libnfnetlink-1.0.2.tar.bz2 | tar -xj || exit 5
exists_dir libmnl-* ||
curl $CURL_OPT -Lo - https://www.netfilter.org/pub/libmnl/libmnl-1.0.5.tar.bz2 | tar -xj || exit 5
exists_dir libnetfilter_queue-* ||
curl $CURL_OPT -Lo - https://www.netfilter.org/pub/libnetfilter_queue/libnetfilter_queue-1.0.5.tar.bz2 | tar -xj || exit 5
exists_dir zlib-ng-${ZLIB_NG_VER} ||
curl $CURL_OPT -Lo - https://github.com/zlib-ng/zlib-ng/archive/refs/tags/${ZLIB_NG_VER}.tar.gz | tar -xz || exit 5
exists_dir zlib-${ZLIB_VER} ||
curl $CURL_OPT -Lo - https://zlib.net/fossils/zlib-${ZLIB_VER}.tar.gz | tar -xz || exit 5
exists_dir luajit2-* ||
curl $CURL_OPT -Lo - https://github.com/openresty/luajit2/archive/refs/tags/v${LUAJIT_RELEASE}.tar.gz | tar -xz || exit 5
exists_dir lua-* ||
curl $CURL_OPT -Lo - https://www.lua.org/ftp/lua-${LUA_RELEASE}.tar.gz | tar -xz || exit 5
)
}
build_netlink()
{
for i in libmnl libnfnetlink libnetfilter_queue ; do
(
cd $i-*
[ -f "Makefile" ] && make clean
CFLAGS="$OPTIMIZE $MINSIZE $CFLAGS" \
LDFLAGS="$LDMINSIZE $LDFLAGS" \
./configure --prefix= --host=$TARGET CC=$CC LD=$LD --enable-static --disable-shared --disable-dependency-tracking
make install -j$nproc DESTDIR=$STAGING_DIR
)
sed -i "s|^prefix=.*|prefix=$STAGING_DIR|g" $STAGING_DIR/lib/pkgconfig/$i.pc
done
}
build_zlib()
{
(
if [ "$ZLIB_NG" = 1 ]; then
cd zlib-ng-${ZLIB_NG_VER}
else
cd zlib-${ZLIB_VER}
fi
[ -f "Makefile" ] && make clean
CFLAGS="$OPTIMIZE $MINSIZE $CFLAGS" \
LDFLAGS="$LDMINSIZE $LDFLAGS" \
./configure --prefix= --static --zlib-compat
make install -j$nproc DESTDIR=$STAGING_DIR
)
}
build_lua()
{
(
cd lua-${LUA_RELEASE}
make clean
make CC="$CC" AR="$AR rc" CFLAGS="$OPTIMIZE $MINSIZE $CFLAGS" LDFLAGS="$LDMINSIZE $LDFLAGS" linux -j$nproc
make install INSTALL_TOP="$STAGING_DIR" INSTALL_BIN="$STAGING_DIR/bin" INSTALL_INC="$STAGING_DIR/include/lua${LUA_VER}" INSTALL_LIB="$STAGING_DIR/lib"
)
}
build_luajit()
{
local CFL="$CFLAGS"
local SYSMALLOC=
(
cd luajit2-*
CFLAGS="-Os"
make clean
case $TARGET in
aarch64*|mips64*)
# sysmalloc can cause troubles without GC64. GC64 slows down by 10-15%. better not to use sysmalloc and leave lj_alloc.
;;
*)
# save some exe size
SYSMALLOC=-DLUAJIT_USE_SYSMALLOC
esac
make BUILDMODE=static XCFLAGS="$SYSMALLOC -DLUAJIT_DISABLE_FFI $CFLAGS_PIC" HOST_CC="$HOST_CC" CROSS= CC="$CC" TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP TARGET_CFLAGS="$OPTIMIZE $MINSIZE $CFL" TARGET_LDFLAGS="$CPU $LDMINSIZE $LDFLAGS"
make install PREFIX= DESTDIR="$STAGING_DIR"
)
}
build_luajit_for_target()
{
target_has_luajit $1 && {
case "$1" in
*64*)
HOST_CC="$HOSTCC"
;;
*)
HOST_CC="$HOSTCC -m32"
;;
esac
build_luajit
}
}
check_prog curl tar gzip bzip2 sed make cc pkg-config
check_h_files
dl_deps
check_toolchains
ask_target
CFLAGS_BASE="$CFLAGS"
for t in $TGT; do
CFLAGS="$CFLAGS_BASE"
buildenv $t
CFLAGS="$CFLAGS $CFLAGS_PIC"
pushd "$DEPS"
install_h_files
build_zlib
build_netlink
build_lua
build_luajit_for_target $t
popd
buildenv_clear
done
+64
View File
@@ -0,0 +1,64 @@
#!/bin/bash
EXEDIR="$(dirname "$0")"
EXEDIR="$(cd "$EXEDIR"; pwd)"
. "$EXEDIR/common.inc"
ZDIR="zapret"
ZBASE="$EXEDIR"
BRANCH=master
ZURL=https://github.com/bol-van/zapret/archive/refs/heads/${BRANCH}.zip
ZBIN="$EXEDIR/binaries"
dl_zapret1()
{
if [ -d "$ZBASE/$ZDIR" ]; then
dir_is_not_empty "$ZBASE/$ZDIR" && {
echo "zapret dir is not empty. if you want to redownload - delete it."
return
}
rmdir "$ZBASE/$ZDIR"
fi
(
cd "$ZBASE"
curl $CURL_OPT -Lo /tmp/zapret.zip "$ZURL"
unzip /tmp/zapret.zip
rm /tmp/zapret.zip
mv zapret-${BRANCH} $ZDIR
)
}
check_prog curl unzip make
dl_zapret1
check_toolchains
ask_target
[ -d "$ZBIN" ] || mkdir -p "$ZBIN"
CFLAGS_BASE="$CFLAGS"
for t in $TGT; do
CFLAGS="$CFLAGS_BASE $MINSIZE"
buildenv $t
translate_target $t || {
echo COULD NOT TRANSLATE TARGET $t TO BIN DIR
continue
}
pushd $ZBASE/$ZDIR
make clean
OPTIMIZE=$OPTIMIZE \
CFLAGS="-static-libgcc -I$STAGING_DIR/include $CFLAGS $CFLAGS_PIC" \
LDFLAGS="-L$STAGING_DIR/lib $LDMINSIZE $LDFLAGS_PIE $LDFLAGS" \
make
[ -d "$ZBIN/$ZBINTARGET" ] || mkdir "$ZBIN/$ZBINTARGET"
cp -f binaries/my/* "$ZBIN/$ZBINTARGET"
popd
buildenv_clear
done
+75
View File
@@ -0,0 +1,75 @@
#!/bin/bash
EXEDIR="$(dirname "$0")"
EXEDIR="$(cd "$EXEDIR"; pwd)"
. "$EXEDIR/common.inc"
ZDIR="zapret2"
ZBASE="$EXEDIR"
BRANCH=master
ZURL=https://github.com/bol-van/zapret2/archive/refs/heads/${BRANCH}.zip
ZBIN="$EXEDIR/binaries"
dl_zapret2()
{
if [ -d "$ZBASE/$ZDIR" ]; then
dir_is_not_empty "$ZBASE/$ZDIR" && {
echo "zapret2 dir is not empty. if you want to redownload - delete it."
return
}
rmdir "$ZBASE/$ZDIR"
fi
(
cd "$ZBASE"
curl $CURL_OPT -Lo /tmp/zapret2.zip "$ZURL"
unzip /tmp/zapret2.zip
rm /tmp/zapret2.zip
mv zapret2-${BRANCH} $ZDIR
)
}
check_prog curl unzip make
dl_zapret2
check_toolchains
ask_target
[ -d "$ZBIN" ] || mkdir -p "$ZBIN"
CFLAGS_BASE="$CFLAGS"
for t in $TGT; do
CFLAGS="$CFLAGS_BASE"
buildenv $t
translate_target $t || {
echo COULD NOT TRANSLATE TARGET $t TO BIN DIR
continue
}
pushd $ZBASE/$ZDIR
LUA_JIT=0
LCFLAGS="-I${STAGING_DIR}/include/lua${LUA_VER}"
LLIB="-L${STAGING_DIR}/lib -llua"
target_has_luajit $t && {
LUA_JIT=1
LCFLAGS="-I${STAGING_DIR}/include/luajit-${LUAJIT_VER}"
LLIB="-L${STAGING_DIR}/lib -lluajit-${LUAJIT_LUA_VER}"
}
make clean
LUA_JIT=$LUA_JIT LUA_VER=$LUA_VER LUAJIT_LUA_VER=$LUAJIT_LUA_VER \
OPTIMIZE=$OPTIMIZE \
MINSIZE=$MINSIZE \
CFLAGS="-static-libgcc -I$STAGING_DIR/include $CFLAGS" \
LDFLAGS="-L$STAGING_DIR/lib $LDFLAGS" \
make CFLAGS_PIC="$CFLAGS_PIC" LDFLAGS_PIE="$LDFLAGS_PIE" LUA_JIT=$LJIT LUA_CFLAGS="$LCFLAGS" LUA_LIB="$LLIB"
[ -d "$ZBIN/$ZBINTARGET" ] || mkdir "$ZBIN/$ZBINTARGET"
cp -f binaries/my/* "$ZBIN/$ZBINTARGET"
popd
buildenv_clear
done
+311
View File
@@ -0,0 +1,311 @@
EXEDIR="$(dirname "$0")"
EXEDIR="$(cd "$EXEDIR"; pwd)"
CURL_OPT="--connect-timeout 5 --max-time 120 --retry 5 --retry-delay 30"
TOOLCHAINS="$EXEDIR/toolchain"
DEPS="$EXEDIR/deps"
STAGE="$EXEDIR/staging"
OPTIMIZE=${OPTIMIZE:--Oz}
#MINSIZE="${MINSIZE:--flto=auto -ffunction-sections -fdata-sections}"
MINSIZE="${MINSIZE:--ffunction-sections -fdata-sections}"
LDMINSIZE="${LDMINSIZE:--Wl,--gc-sections -flto=auto}"
#CFLAGS=""
LDFLAGS="-lgcc_eh $LDFLAGS"
# PIE makes ASLR working but adds 5% to size
# PIE does not work for arm32 and all mips
PIE=${PIE:-0}
HOSTCC=${HOSTCC:-cc}
ZLIB_VER=${ZLIB_VER:-1.3.2}
ZLIB_NG_VER=${ZLIB_NG_VER:-2.3.3}
LUA_VER=${LUA_VER:-5.5}
LUA_RELEASE=${LUA_RELEASE:-5.5.1}
LUAJIT_VER=${LUAJIT_VER:-2.1}
LUAJIT_RELEASE=${LUAJIT_RELEASE:-2.1-20250826}
LUAJIT_LUA_VER=${LUAJIT_LUA_VER:-5.1}
nproc=$(nproc)
TARGETS="\
aarch64-unknown-linux-musl \
armv6-unknown-linux-musleabi \
i586-unknown-linux-musl \
x86_64-unknown-linux-musl \
mips-unknown-linux-muslsf \
mips64-unknown-linux-musl \
mips64el-unknown-linux-musl \
mipsel-unknown-linux-muslsf \
powerpc-unknown-linux-musl \
riscv64-unknown-linux-musl \
"
target_has_luajit()
{
case "$1" in
aarch64-unknown-linux-musl| \
armv6-unknown-linux-musleabi| \
x86_64-unknown-linux-musl| \
mips-unknown-linux-muslsf| \
mips64-unknown-linux-musl| \
mips64el-unknown-linux-musl| \
mipsel-unknown-linux-muslsf| \
powerpc-unknown-linux-musl) \
return 0
;;
esac
return 1
}
REQD_H_FILES="/usr/include/sys/capability.h /usr/include/bits/libc-header-start.h"
REQD_QUEUE_1="/usr/include/sys/queue.h"
REQD_QUEUE_2="/usr/include/x86_64-linux-gnu/sys/queue.h"
check_h_files()
{
[ ! -f "$REQD_QUEUE_1" -a ! -f "$REQD_QUEUE_2" ] && {
echo "could not find $REQD_QUEUE_1 or $REQD_QUEUE_2"
help_pkg
exit 10
}
check_file $REQD_H_FILES
}
install_h_files()
{
if [ -f "$REQD_QUEUE_1" ]; then
install -Dm644 -t $STAGING_DIR/include/sys $REQD_QUEUE_1
elif [ -f "$REQD_QUEUE_2" ]; then
install -Dm644 -t $STAGING_DIR/include/sys $REQD_QUEUE_2
fi
install -Dm644 -t $STAGING_DIR/include/sys $REQD_H_FILES
}
buildenv()
{
# $1 = arch
export TARGET=$1
export CC=$TARGET-gcc
export LD=$TARGET-ld
export AR=$TARGET-ar
export NM=$TARGET-nm
export STRIP=$TARGET-strip
export STAGING_DIR="$EXEDIR/staging/$TARGET"
[ -d "$STAGING_DIR" ] || {
mkdir -p "$STAGING_DIR"
mkdir -p "$STAGING_DIR/lib/pkgconfig"
mkdir -p "$STAGING_DIR/bin"
mkdir -p "$STAGING_DIR/include"
}
export PKG_CONFIG_PATH=$STAGING_DIR/lib/pkgconfig
OLDPATH="$PATH"
export PATH="$PATH:$TOOLCHAINS/$TARGET/bin"
CPU=
CFLAGS_PIC=
LDFLAGS_PIE=-static
# not all archs support -static-pie. if does not support - it produces dynamic executable
# "-static -static-pie" causes segfaults
case $1 in
armv6-*)
CPU="-mthumb -msoft-float"
CFLAGS="$CPU $CFLAGS"
;;
mips*)
;;
*)
[ "$PIE" = 1 ] && {
CFLAGS_PIC=-fPIC
LDFLAGS_PIE="-static-pie"
}
esac
}
buildenv_clear()
{
export PATH="$OLDPATH" TARGET= CC= LD= AR= NM= STRIP= STAGING_DIR= PKG_CONFIG_PATH=
OLDPATH=
}
which()
{
# on some systems 'which' command is considered deprecated and not installed by default
# 'command -v' replacement does not work exactly the same way. it outputs shell aliases if present
# $1 - executable name
local IFS=:
[ "$1" != "${1#/}" ] && [ -x "$1" ] && {
echo "$1"
return 0
}
for p in $PATH; do
[ -x "$p/$1" ] && {
echo "$p/$1"
return 0
}
done
return 1
}
exists()
{
which "$1" >/dev/null 2>/dev/null
}
exists_dir()
{
# use $1, ignore other args
[ -d "$1" ]
}
dir_is_not_empty()
{
# $1 - directory
local n
[ -d "$1" ] || return 1
n=$(ls -A "$1" | wc -c | xargs)
[ "$n" != 0 ]
}
find_str_in_list()
{
# $1 - string
# $2 - space separated values
local v
[ -n "$1" ] && {
for v in $2; do
[ "$v" = "$1" ] && return 0
done
}
return 1
}
ask_list()
{
# $1 - mode var
# $2 - space separated value list
# $3 - (optional) default value
local M_DEFAULT
eval M_DEFAULT="\$$1"
local M_DEFAULT_VAR="$M_DEFAULT"
local M="" m
[ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3" ;}
n=1
for m in $2; do
echo $n : $m
n=$(($n+1))
done
printf "your choice (default : $M_DEFAULT) : "
read m
[ -n "$m" ] && M=$(echo $2 | cut -d ' ' -f$m 2>/dev/null)
[ -z "$M" ] && M="$M_DEFAULT"
echo selected : $M
eval $1="\"$M\""
[ "$M" != "$M_DEFAULT_VAR" ]
}
ask_target()
{
# $1 = 1 = ask all, otherwise ask only present toolchains
# already set ?
[ -n "$TGT" ] && return
local d ALL_TARGETS
[ "$1" = 1 ] || {
if dir_is_not_empty "$TOOLCHAINS"; then
for d in "$TOOLCHAINS"/*; do
[ -d "$d" ] && {
d="$(basename "$d")"
ALL_TARGETS="$ALL_TARGETS $d"
}
done
fi
}
[ -n "$ALL_TARGETS" ] || ALL_TARGETS="$TARGETS"
echo "select target :"
ask_list TARGET "ALL $ALL_TARGETS" "ALL"
echo
echo selected TARGET : $TARGET
echo
if [ $TARGET = ALL ]; then
TGT="$ALL_TARGETS"
else
TGT="$TARGET"
fi
}
check_toolchains()
{
dir_is_not_empty "$TOOLCHAINS" || {
echo DOWNLOAD TOOLCHAINS FIRST
exit 1
}
}
help_pkg()
{
echo "debian/ubuntu: apt install curl xz-utils bzip2 unzip make gcc gcc-multilib libc6-dev libcap-dev pkg-config"
echo "fedora: dnf install curl xz bzip2 unzip make gcc glibc-devel glibc-devel.i686 libcap-devel pkg-config"
}
check_prog()
{
while [ -n "$1" ]; do
exists $1 || {
echo $1 is not available
help_pkg
exit 10
}
shift
done
}
check_file()
{
while [ -n "$1" ]; do
[ -f "$1" ] || {
echo $1 is not available
help_pkg
exit 10
}
shift
done
}
translate_target()
{
case $1 in
aarch64-unknown-linux-musl)
ZBINTARGET=linux-arm64
;;
armv6-unknown-linux-musleabi)
ZBINTARGET=linux-arm
;;
x86_64-unknown-linux-musl)
ZBINTARGET=linux-x86_64
;;
i586-unknown-linux-musl)
ZBINTARGET=linux-x86
;;
mips-unknown-linux-muslsf)
ZBINTARGET=linux-mips
;;
mipsel-unknown-linux-muslsf)
ZBINTARGET=linux-mipsel
;;
mips64-unknown-linux-musl)
ZBINTARGET=linux-mips64
;;
mips64el-unknown-linux-musl)
ZBINTARGET=linux-mipsel64
;;
powerpc-unknown-linux-musl)
ZBINTARGET=linux-ppc
;;
riscv64-unknown-linux-musl)
ZBINTARGET=linux-riscv64
;;
*)
return 1
esac
return 0
}
+22
View File
@@ -0,0 +1,22 @@
#!/bin/bash
EXEDIR="$(dirname "$0")"
EXEDIR="$(cd "$EXEDIR"; pwd)"
. "$EXEDIR/common.inc"
BASEURL=https://github.com/bol-van/musl-cross/releases/download/latest
check_prog curl tar xz
[ -d "$TOOLCHAINS" ] || mkdir -p "$TOOLCHAINS"
ask_target 1
(
cd "$TOOLCHAINS"
for t in $TGT; do
[ -d "$t" ] && rm -r "$t"
curl $CURL_OPT -Lo - "${BASEURL}/${t}.tar.xz" | tar -Jx
done
)
+394 -143
View File
@@ -34,13 +34,15 @@
- [Passing blobs](#passing-blobs)
- [In-profile filters](#in-profile-filters)
- [Typical instance invocation scheme within a profile](#typical-instance-invocation-scheme-within-a-profile)
- [Lua function prototype](#lua-function-prototype)
- [Lua desync function prototype](#lua-desync-function-prototype)
- [Structure of the desync table](#structure-of-the-desync-table)
- [Dissect structure](#dissect-structure)
- [Handling multi-packet payloads](#handling-multi-packet-payloads)
- [The track table structure](#the-track-table-structure)
- [ICMP processing](#icmp-processing)
- [raw IP processing](#raw-ip-processing)
- [Timers](#timers)
- [Timer function prototype](#timer-function-prototype)
- [nfqws2 C interface](#nfqws2-c-interface)
- [Base constants](#base-constants)
- [Standard blobs](#standard-blobs)
@@ -59,45 +61,52 @@
- [Random Data Generation](#random-data-generation)
- [brandom](#brandom)
- [Parsing](#parsing)
- [parse\_hex](#parse_hex)
- [parse_hex](#parse_hex)
- [Cryptography](#cryptography)
- [bcryptorandom](#bcryptorandom)
- [bxor,bor,band](#bxorborband)
- [hash](#hash)
- [aes](#aes)
- [aes\_gcm](#aes_gcm)
- [aes\_ctr](#aes_ctr)
- [aes_gcm](#aes_gcm)
- [aes_ctr](#aes_ctr)
- [hkdf](#hkdf)
- [Compression](#compression)
- [gunzip](#gunzip)
- [gzip](#gzip)
- [System functions](#system-functions)
- [uname](#uname)
- [clock\_gettime](#clock_gettime)
- [clock_gettime](#clock_gettime)
- [getpid](#getpid)
- [stat](#stat)
- [time](#time)
- [Packet handling options](#packet-handling-options)
- [standard reconstruct](#standard-reconstruct)
- [standard rawsend](#standard-rawsend)
- [Dissection and reconstruction](#dissection-and-reconstruction)
- [dissect](#dissect)
- [reconstruct\_dissect](#reconstruct_dissect)
- [reconstruct\_hdr](#reconstruct_hdr)
- [csum\_fix](#csum_fix)
- [dissect_hdr](#dissect_hdr)
- [reconstruct_dissect](#reconstruct_dissect)
- [reconstruct_hdr](#reconstruct_hdr)
- [csum_fix](#csum_fix)
- [conntrack](#conntrack)
- [Obtaining IP addresses](#obtaining-ip-addresses)
- [Receiving and sending Packets](#receiving-and-sending-packets)
- [rawsend](#rawsend)
- [raw\_packet](#raw_packet)
- [raw_packet](#raw_packet)
- [Working with payloads](#working-with-payloads)
- [Markers](#markers)
- [resolve\_pos](#resolve_pos)
- [tls\_mod](#tls_mod)
- [resolve_pos](#resolve_pos)
- [tls_mod](#tls_mod)
- [Instance execution management](#instance-execution-management)
- [instance\_cutoff](#instance_cutoff)
- [lua\_cutoff](#lua_cutoff)
- [execution\_plan](#execution_plan)
- [execution\_plan\_cancel](#execution_plan_cancel)
- [instance_cutoff](#instance_cutoff)
- [lua_cutoff](#lua_cutoff)
- [execution_plan](#execution_plan)
- [execution_plan_cancel](#execution_plan_cancel)
- [Timer control](#timer-control)
- [timer_set](#timer_set)
- [timer_del](#timer_del)
- [timer_info](#timer_info)
- [timer_enum](#timer_enum)
- [zapret-lib.lua base function library](#zapret-liblua-base-function-library)
- [Base desync functions](#base-desync-functions)
- [luaexec](#luaexec)
@@ -105,16 +114,16 @@
- [pktdebug](#pktdebug)
- [argdebug](#argdebug)
- [posdebug](#posdebug)
- [detect\_payload\_str](#detect_payload_str)
- [desync\_orchestrator\_example](#desync_orchestrator_example)
- [detect_payload_str](#detect_payload_str)
- [desync_orchestrator_example](#desync_orchestrator_example)
- [Utility functions](#utility-functions)
- [var\_debug](#var_debug)
- [var_debug](#var_debug)
- [deepcopy](#deepcopy)
- [logical\_xor](#logical_xor)
- [array\_search](#array_search)
- [logical_xor](#logical_xor)
- [array_search](#array_search)
- [String operations](#string-operations)
- [in\_list](#in_list)
- [find\_next\_line](#find_next_line)
- [in_list](#in_list)
- [find_next_line](#find_next_line)
- [Raw string handling](#raw-string-handling)
- [hex](#hex)
- [pattern](#pattern)
@@ -122,18 +131,18 @@
- [TCP sequence number handling](#tcp-sequence-number-handling)
- [Position handling](#position-handling)
- [Dissection](#dissection)
- [dissect\_url](#dissect_url)
- [dissect\_nld](#dissect_nld)
- [dissect\_http](#dissect_http)
- [dissect\_tls](#dissect_tls)
- [dissect_url](#dissect_url)
- [dissect_nld](#dissect_nld)
- [dissect_http](#dissect_http)
- [dissect_tls](#dissect_tls)
- [Working with L3 and L4 protocol elements](#working-with-l3-and-l4-protocol-elements)
- [find\_tcp\_options](#find_tcp_options)
- [find_tcp_options](#find_tcp_options)
- [ip6hdr](#ip6hdr)
- [ip protocol](#ip-protocol)
- [packet\_len](#packet_len)
- [packet_len](#packet_len)
- [Working with hostnames](#working-with-hostnames)
- [genhost](#genhost)
- [host\_ip](#host_ip)
- [host_ip](#host_ip)
- [File name and path operations](#file-name-and-path-operations)
- [Reading and writing Files](#reading-and-writing-files)
- [Data compression](#data-compression)
@@ -142,29 +151,30 @@
- [standard ipid](#standard-ipid)
- [standard fooling](#standard-fooling)
- [standard ipfrag](#standard-ipfrag)
- [apply\_ip\_id](#apply_ip_id)
- [apply\_fooling](#apply_fooling)
- [apply_ip_id](#apply_ip_id)
- [apply_fooling](#apply_fooling)
- [ipfrag2](#ipfrag2)
- [wssize\_rewrite](#wssize_rewrite)
- [dis\_reverse](#dis_reverse)
- [wssize_rewrite](#wssize_rewrite)
- [dis_reverse](#dis_reverse)
- [IP addresses and interfaces](#ip-addresses-and-interfaces)
- [Sending](#sending)
- [rawsend\_dissect\_ipfrag](#rawsend_dissect_ipfrag)
- [rawsend\_dissect\_segmented](#rawsend_dissect_segmented)
- [rawsend\_payload\_segmented](#rawsend_payload_segmented)
- [rawsend_dissect_ipfrag](#rawsend_dissect_ipfrag)
- [rawsend_dissect_segmented](#rawsend_dissect_segmented)
- [rawsend_payload_segmented](#rawsend_payload_segmented)
- [Standard direction and payload filters](#standard-direction-and-payload-filters)
- [Working with multi-packet payloads](#working-with-multi-packet-payloads)
- [Timer helpers](#timer-helpers)
- [Orchestration](#orchestration)
- [instance\_cutoff\_shim](#instance_cutoff_shim)
- [cutoff\_shim\_check](#cutoff_shim_check)
- [apply\_arg\_prefix](#apply_arg_prefix)
- [apply\_execution\_plan](#apply_execution_plan)
- [verdict\_aggregate](#verdict_aggregate)
- [plan\_instance\_execute](#plan_instance_execute)
- [plan\_instance\_pop](#plan_instance_pop)
- [plan\_clear](#plan_clear)
- [instance_cutoff_shim](#instance_cutoff_shim)
- [cutoff_shim_check](#cutoff_shim_check)
- [apply_arg_prefix](#apply_arg_prefix)
- [apply_execution_plan](#apply_execution_plan)
- [verdict_aggregate](#verdict_aggregate)
- [plan_instance_execute](#plan_instance_execute)
- [plan_instance_pop](#plan_instance_pop)
- [plan_clear](#plan_clear)
- [orchestrate](#orchestrate)
- [replay\_execution\_plan](#replay_execution_plan)
- [replay_execution_plan](#replay_execution_plan)
- [zapret-antidpi.lua DPI attack program library](#zapret-antidpilua-dpi-attack-program-library)
- [Standard parameter sets](#standard-parameter-sets)
- [standard direction](#standard-direction)
@@ -174,22 +184,22 @@
- [send](#send)
- [pktmod](#pktmod)
- [HTTP fooling](#http-fooling)
- [http\_hostcase](#http_hostcase)
- [http\_domcase](#http_domcase)
- [http\_methodeol](#http_methodeol)
- [http\_unixeol](#http_unixeol)
- [http_hostcase](#http_hostcase)
- [http_domcase](#http_domcase)
- [http_methodeol](#http_methodeol)
- [http_unixeol](#http_unixeol)
- [Window size replacement](#window-size-replacement)
- [wsize](#wsize)
- [wssize](#wssize)
- [Fakes](#fakes)
- [syndata](#syndata)
- [tls\_client\_hello\_clone](#tls_client_hello_clone)
- [tls_client_hello_clone](#tls_client_hello_clone)
- [fake](#fake)
- [rst](#rst)
- [TCP segmentation](#tcp-segmentation)
- [multisplit](#multisplit)
- [multidisorder](#multidisorder)
- [multidisorder\_legacy](#multidisorder_legacy)
- [multidisorder_legacy](#multidisorder_legacy)
- [fakedsplit](#fakedsplit)
- [fakeddisorder](#fakeddisorder)
- [hostfakesplit](#hostfakesplit)
@@ -197,32 +207,35 @@
- [oob](#oob)
- [UDP Fooling](#udp-fooling)
- [udplen](#udplen)
- [dht\_dn](#dht_dn)
- [dht_dn](#dht_dn)
- [Other Functions](#other-functions)
- [synack](#synack)
- [synack\_split](#synack_split)
- [synack_split](#synack_split)
- [zapret-auto.lua automation and orchestration library](#zapret-autolua-automation-and-orchestration-library)
- [State storage](#state-storage)
- [automate\_conn\_record](#automate_conn_record)
- [standard\_hostkey](#standard_hostkey)
- [automate\_host\_record](#automate_host_record)
- [automate_conn_record](#automate_conn_record)
- [standard_hostkey](#standard_hostkey)
- [automate_host_record](#automate_host_record)
- [Handling successes and failures](#handling-successes-and-failures)
- [automate\_failure\_counter](#automate_failure_counter)
- [automate\_failure\_counter\_reset](#automate_failure_counter_reset)
- [automate_failure_counter](#automate_failure_counter)
- [automate_failure_counter_reset](#automate_failure_counter_reset)
- [Success and failure detection](#success-and-failure-detection)
- [automate\_failure\_check](#automate_failure_check)
- [standard\_success\_detector](#standard_success_detector)
- [standard\_failure\_detector](#standard_failure_detector)
- [automate_failure_check](#automate_failure_check)
- [standard_success_detector](#standard_success_detector)
- [standard_failure_detector](#standard_failure_detector)
- [Orchestrators](#orchestrators)
- [circular](#circular)
- [repeater](#repeater)
- [condition](#condition)
- [per_instance_condition](#per_instance_condition)
- [stopif](#stopif)
- [iff functions](#iff-functions)
- [cond\_true](#cond_true)
- [cond\_false](#cond_false)
- [cond\_random](#cond_random)
- [cond\_payload\_str](#cond_payload_str)
- [cond_true](#cond_true)
- [cond_false](#cond_false)
- [cond_random](#cond_random)
- [cond_payload_str](#cond_payload_str)
- [cond_tcp_has_ts](#cond_tcp_has_ts)
- [cond_lua](#cond_lua)
- [Auxiliary programs](#auxiliary-programs)
- [ip2net](#ip2net)
- [mdig](#mdig)
@@ -246,16 +259,16 @@
- [List management system](#list-management-system)
- [Standard list files](#standard-list-files)
- [ipset scripts](#ipset-scripts)
- [clear\_lists.sh](#clear_listssh)
- [create\_ipset.sh](#create_ipsetsh)
- [get\_config.sh](#get_configsh)
- [get\_user.sh](#get_usersh)
- [get\_ipban.sh](#get_ipbansh)
- [get\_exclude.sh](#get_excludesh)
- [get\_antifilter\_\*.sh](#get_antifilter_sh)
- [get\_antizapret\_domains.sh](#get_antizapret_domainssh)
- [get\_refilter\_\*.sh](#get_refilter_sh)
- [get\_reestr\_\*.sh](#get_reestr_sh)
- [clear_lists.sh](#clear_listssh)
- [create_ipset.sh](#create_ipsetsh)
- [get_config.sh](#get_configsh)
- [get_user.sh](#get_usersh)
- [get_ipban.sh](#get_ipbansh)
- [get_exclude.sh](#get_excludesh)
- [get_antifilter_*.sh](#get_antifilter_sh)
- [get_antizapret_domains.sh](#get_antizapret_domainssh)
- [get_refilter_*.sh](#get_refilter_sh)
- [get_reestr_*.sh](#get_reestr_sh)
- [ipban system](#ipban-system)
- [Init scripts](#init-scripts)
- [Firewall integration](#firewall-integration)
@@ -339,7 +352,7 @@ Once a profile is selected, what constitutes its action-oriented logic? Actions
[in-profile filters](#in-profile-filters) are also available. There are three types: the `--payload` filter (a list of payloads accepted by the instance) and two range filters, `--in-range` and `--out-range`, which define the specific byte range within the stream that the instance should process. Once defined, in-profile filters apply to all subsequent instances until they are redefined. The primary purpose of these filters is to minimize relatively slow Lua calls by offloading as much decision-making as possible to the C-side code.
When a packet reaches a Lua instance, the function receives two [parameters](#lua-function-prototype): `ctx` and `desync`. `ctx` provides a context for interacting with specific C-side functions. The [`desync`](#structure-of-the-desync-table) parameter is a table containing various attributes of the packet being processed. Most notably, it includes the [dissect](#dissect-structure) (the `dis` subtable) and information from the conntrack entry (the [track subtable](#the-track-table-structure)). Numerous other parameters can be inspected by executing [`var_debug(desync)`](#var_debug) or by using the pre-built [`pktdebug`](#pktdebug) instance.
When a packet reaches a Lua instance, the function receives two [parameters](#lua-desync-function-prototype): `ctx` and `desync`. `ctx` provides a context for interacting with specific C-side functions. The [`desync`](#structure-of-the-desync-table) parameter is a table containing various attributes of the packet being processed. Most notably, it includes the [dissect](#dissect-structure) (the `dis` subtable) and information from the conntrack entry (the [track subtable](#the-track-table-structure)). Numerous other parameters can be inspected by executing [`var_debug(desync)`](#var_debug) or by using the pre-built [`pktdebug`](#pktdebug) instance.
During the [replay](#handling-multi-packet-payloads) of delayed packets, the Lua instance receives details such as the part number, the total number of parts in the original message, the current part's position, and [reasm](#handling-multi-packet-payloads) or [decrypt](#handling-multi-packet-payloads) data if available.
@@ -633,6 +646,7 @@ General parameters for all versions - nfqws2, dvtws2, winws2.
--comment=any_text ; any text. ignored
--intercept=0|1 ; allow interception. 0 - no, 1 - yes. If 0 lua-init scripts are executed then process exits. NFQUEUE is not initialized.
--daemon ; detach from the console (daemonize)
--chdir[=path] ; change current directory. if no path specified use the executable file directory - EXEDIR
--pidfile=<filename> ; write PID to a file
--ctrack-timeouts=S:E:F[:U] ; conntrack timeouts for tcp stages (SYN, ESTABLISHED, FIN) and for udp
--ctrack-disable=[0|1] ; 1 disables conntrack
@@ -643,7 +657,7 @@ General parameters for all versions - nfqws2, dvtws2, winws2.
--reasm-disable=[type[,type]] ; disable fragment reassembly for a list of payloads: tls_client_hello quic_initial. without arguments - disable reasm for everything.
DESYNC ENGINE INIT:
--writeable[=<dir_name>] ; create a directory for Lua with write permissions and store its path in the "WRITEABLE" env variable (only one directory)
--writable[=<dir_name>] ; create a directory for Lua with write permissions and store its path in the "WRITABLE" env variable (only one directory)
--blob=<item_name>:[+ofs]@<filename>|0xHEX ; load a binary file or hex string into the Lua variable <item_name>. +ofs specifies the offset from the start of the file
--lua-init=@<filename>|<lua_text> ; execute Lua code from a string or file once at startup. supports gzipped files. automatically checks for "<filename>.gz"
--lua-gc=<int> ; Lua garbage collector invocation interval in seconds. 0 disables periodic calls.
@@ -682,8 +696,8 @@ MULTI-STRATEGY:
LUA PACKET PASS MODE:
--payload=type[,type] ; in-profile filter: payload filter for subsequent instances within the profile
--out-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; in-profile filter: conntrack counter range for subsequent instances within the profile - outgoing direction
--in-range=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>] ; in-profile filter: conntrack counter range for subsequent instances within the profile - incoming direction
--out-range=<mode>[<int>][(-|<)<mode>[<int>]] ; in-profile filter: conntrack counter range for subsequent instances within the profile - outgoing direction
--in-range=<mode>[<int>][(-|<)<mode>[<int>]] ; in-profile filter: conntrack counter range for subsequent instances within the profile - incoming direction
LUA DESYNC ACTION:
--lua-desync=<function>[:param1=val1[:param2=val2]] ; call a LUA instance with the specified parameters during profile processing if in-profile filter conditions are met
@@ -698,7 +712,9 @@ Specific parameters for nfqws2:
--bind-fix4 ; fix for the issue where generated packets on Linux exit from the wrong interface when using PBR (IPv4)
--bind-fix6 ; same as above for IPv6
--fwmark=<int|0xHEX> ; mark bit to prevent looping. default = 0x40000000
--filter-mark=mark[/mask] ; profile filter: filter by packet mark. mark and mask can be decimal or 0xHEX
--filter-ssid=ssid1[,ssid2,ssid3,...] ; profile filter: WiFi network name (SSID)
--filter-ssid-neg=[0|1] ; profile filter: negate SSID filter
```
Specific parameters for dvtws2:
@@ -731,7 +747,9 @@ Specific parameters for winws2:
--wf-save=<filename> ; save the final complete WinDivert filter to a file
LOGICAL NETWORK FILTER:
--ssid-filter=ssid1[,ssid2,ssid3,...] ; list of WiFi networks; interception is enabled only when connected to these, otherwise it is disabled.
--ssid-filter-neg=[0|1] ; negate WiFi network filter
--nlm-filter=net1[,net2,net3,...] ; list of Network List Manager networks; interception is enabled only when connected to these, otherwise it is disabled.
--nlm-filter-neg=[0|1] ; negate NLM filter
--nlm-list[=all] ; display a list of connected NLM networks. "all" shows all NLM networks.
```
@@ -751,9 +769,11 @@ Table of recognizable payload types and flow protocols
| tls | tcp | tls_client_hello<br>tls_server_hello |
| xmpp | tcp | xmpp_stream<br>xmpp_starttls<br>xmpp_proceed<br>xmpp_features |
| mtproto | tcp | mtproto_initial |
| bt | tcp | bt_handshake |
| quic | udp | quic_initial |
| wireguard | udp | wireguard_initiation<br>wireguard_response<br>wireguard_cookie<br>wireguard_keepalive |
| dht | udp | dht |
| utp_bt | udp | utp_bt_handshake |
| discord | udp | discord_ip_discovery |
| stun | udp | stun |
| dns | udp | dns_query dns_response |
@@ -900,6 +920,8 @@ Another way to address this-and not just for Wi-Fi-is by using the Network List
An NLM network is the result of the system detecting a connection to a specific network. You might connect to a router via Wi-Fi or Ethernet, but it will be recognized as the same network. To distinguish between networks, the system typically looks at the gateway's MAC address. NLM technology is interesting and useful, but unfortunately, adequate management tools were only available in Windows 7. In newer systems, you have to dig into PowerShell or the Registry to manually assign connections to the correct GUIDs if the system categorizes them incorrectly. Alternatively, you can simply use the list of GUIDs automatically assigned by the system.
SSID/NLM filters can be negated in both systems.
## Server mode
Certain types of manipulations can be performed not only from the client side but also from the server side. `nfqws2` was designed to fully support both inbound and outbound traffic, on both the client and server sides.
@@ -1003,13 +1025,13 @@ Windows:
- All `Se*` privileges are irrevocably removed from the token, except for `SeChangeNotifyPrivilege`.
- A Job object is used to prohibit the creation of child processes and restrict desktop interaction - clipboard access, changing desktop settings, changing display settings, etc.
There is a simple way to pass a writable directory to the Lua code using the `--writeable[=<dirname>]` parameter. `nfqws2` creates the directory and assigns permissions so that the Lua code can write files there, then passes the directory name in the `WRITEABLE` environment variable. If `dirname` is not specified, a directory is created within `%USERPROFILE%/AppData/LocalLow` on Windows.
There is a simple way to pass a writable directory to the Lua code using the `--writable[=<dirname>]` parameter. `nfqws2` creates the directory and assigns permissions so that the Lua code can write files there, then passes the directory name in the `WRITABLE` environment variable. If `dirname` is not specified, a directory is created within `%USERPROFILE%/AppData/LocalLow` on Windows.
On the Lua side, dangerous functions are removed: `os.execute`, `io.popen`, `package.loadlib`, and the `debug` module. On GitHub, `nfqws2` executables are built with a version of LuaJIT that excludes FFI.
## Calling Lua code
Lua code is invoked in two stages:
Lua code is invoked in 3 stages:
1. Once at program startup via `--lua-init=code|@file`. If the parameter value starts with `@`, a file is executed; otherwise, the value is treated as Lua code. Gzip file compression is supported. The program first checks for "file", then "file.gz".
2. During profile processing via `--lua-desync=function_name:arg1[=val1]:arg2[=val2]:argN[=valN]`.
@@ -1018,6 +1040,7 @@ Two types of automatic substitutions are implemented on the C side:
`%var` substitutes the value of the variable `desync.var` or `var` if the former is missing.
`#var` substitutes the length of the variable `desync.var` or `var` if the former is missing.
Colons and the `%`, `#` symbols at the beginning can be escaped with a backslash `\`.
3. During [timer](#timers) processing.
Both `--lua-init` and `--lua-desync` can be used multiple times. Execution follows the exact order in which they are specified.
@@ -1033,12 +1056,16 @@ A blob is a binary data block of any size that can be loaded into a Lua variable
Direct file operations from Lua code are not recommended unless absolutely necessary. Lua code runs with restricted privileges; intended operations might fail or behave inconsistently across different operating systems and environments. Blob loading occurs before entering the sandbox, providing a higher chance of success.
Since a blob's name is a Lua variable name, you cannot name it arbitrarily. You must follow Lua naming conventions.
For example, a variable name cannot start with a digit, contain non-alphanumeric characters (other than `_`), or use reserved words.
Names are case-sensitive.
### In-profile filters
These come in three types: `--payload`, `--in-range`, and `--out-range`. Filter values remain active from the moment they are specified until the next override.
- `--payload=type1[,type2][,type3]...` accepts a comma-separated list of known [payloads](#protocol-detection), "all", or "known". The default is `--payload=all`.
- `--(in-range|out-range)=[(n|a|d|s|p)<int>](-|<)[(n|a|d|s|p)<int>]` sets conntrack counter ranges for inbound and outbound directions. The default is `--in-range=x`, `--out-range=a`.
- `--(in-range|out-range)=<mode>[<int>][(-|<)<mode>[<int>]]` sets conntrack counter ranges for inbound and outbound directions. The default is `--in-range=x`, `--out-range=a`.
Ranges are specified in the following formats: `mX-mY`, `mX<mY`, `-mY`, `<mY`, `mX-`, where `m` is the counter mode, `X` is the lower bound, and `Y` is the upper bound. Modes `x` and `a` are specified as a single letter without a range or counter value. The `-` sign indicates an inclusive upper bound, while `<` indicates an exclusive one.
@@ -1084,7 +1111,7 @@ The specific mechanics of these functions are less important here; the focus is
- The `--payload` directive applies to the two instances following it.
- The line `--lua-desync=fake:blob=fake_default_tls:badsum:strategy=1` calls the `fake` function with three arguments: `blob`, `badsum`, and `strategy`. The value for the `badsum` argument is an empty string.
## Lua function prototype
## Lua desync function prototype
A standard Lua function uses the following prototype:
@@ -1387,6 +1414,7 @@ All multi-byte numeric values are automatically converted from network byte orde
| :------------ | :----- | :--------------------------------------------------------------- |
| ip | table | IPv4 header |
| ip6 | table | IPv6 header |
| frag_off | number | IP fragment offset. present only in IP fragments. |
| tcp | table | TCP header |
| udp | table | UDP header |
| icmp | table | ICMP header |
@@ -1580,6 +1608,45 @@ If the ip protocol is not recognized as tcp, udp, icmp, icmpv6, it is considered
Dissect has ip/ip6 field and payload. Payload contains all data after L3 headers.
desync.track is always missing.
## Timers
Lua code can be called independently of received network data.
The event source is time.
A timer is an nfqws2 object, identified by a unique name, that allows you to call a specified Lua function at a specified frequency or once after a certain period of time.
The timer is set by the [timer_set](#timer_set) function, and deleted by the [timer_del](#timer_del) function.
nfqws2 is a single-threaded program, like the Lua engine. Timers are called in the same thread that processes network data.
In Linux and Windows, packets are received in blocks, not one at a time. A block is processed until all remaining packets are exhausted.
Timers are called between block processing. If processing takes a significant amount of time, the timer call may not be perfectly timed.
Timers can be useful for handling unreplied packets.
For example, you need to send something somewhere and read the response. But the other party might not respond or the response might not arrive.
To prevent your system from hanging in an undefined state and leaving garbage in memory, a timer can help.
Using timers, desync functions, and send functions, you can build a full-fledged state machine - even your own implementation of TCP or another guaranteed delivery system.
The system should be designed asynchronously, using a state machine. Direct sleep delays is not the option, as they break the queue-based traffic processing scheme.
While you're waiting, everything else will hang.
In the `--intercept=0` mode, if there are timers, nfqws2 doesn't exit immediately, but calls the timers until there are none left.
After this, the process terminates.
### Timer function prototype
```
function timer(name, data)
```
The timer function can be passed any Lua variable of any type.
A table can be used to store state associated with the timer.
Simple type variables can be used to pass read-only values ​​one-way.
data is set when the timer is started via [timer_set](#timer_set).
When the timer is deleted, the variable is automatically deallocated if there are no other references to it.
If a timer function fails with an error, the timer is forcibly deleted.
Therefore, when developing timer functions, it is especially important to avoid error conditions.
A one-shot timer is automatically deleted after the timer function is called. Manual deletion is not required, although it is permitted.
# nfqws2 C interface
@@ -1642,8 +1709,8 @@ Before executing `--lua-init`, the C code sets up base constants, blobs, and C f
| env | Purpose |
| :-------- |:---------- |
| WRITEABLE | A directory writable by Lua. Corresponds to the `--writeable` option. |
| APPDATALOW | (Windows only) The AppData location for the low mandatory level. This is also writable, but using `--writeable` is preferred for cross-platform compatibility. |
| WRITABLE | A directory writable by Lua. Corresponds to the `--writable` option. |
| APPDATALOW | (Windows only) The AppData location for the low mandatory level. This is also writable, but using `--writable` is preferred for cross-platform compatibility. |
## C functions
@@ -1991,6 +2058,34 @@ If successful returns the following table :
In case of error returns 3 values : nil, error string, error number (errno).
#### time
```
function localtime(unixtime)
function gmtime(unixtime)
function timelocal(tm)
function timegm(tm)
```
localtime and gmtime return dissected unixtime similar to C "struct tm". timelocal and timegm are reverse functions.
| Field | Type | Description |
| :------- | :----- | :---------- |
| sec* | number | second |
| min* | number | minute |
| hour* | number | hour |
| mon* | number | month starting from 0 |
| mday* | number | day of month starting from 1 |
| year* | number | full year, not from 1900 |
| wday | number | day of week. 0 = sunday |
| yday | number | day of year starting from 0 |
| isdst* | number | not zero if summer time in effect |
| zone | string | time zone |
| str | string | formatted string: "dd.mm.yyyy hh:mi:ss" |
Fields marked with `*` are required for reverse translation.
### Packet handling options
The following functions use standard sets of options: `rawsend` and `reconstruct`.
@@ -2061,16 +2156,32 @@ Returns a table representing the dissection of the `raw_ip` packet.
This is the same operation that occurs automatically before desync functions are called based on the profile.
Those functions receive an already prepared dissect.
#### dissect_hdr
```
function dissect_tcphdr(tcp)
function dissect_udphdr(udp)
function dissect_icmphdr(icmp)
function dissect_iphdr(ip)
function dissect_ip6hdr(ip6)
```
Dissection of individual raw headers.
Returns a table representing the dissected header.
For TCP options, all 0x00 options (padding) at the end are trimmed.
#### reconstruct_dissect
```
function reconstruct_dissect(dissect[, reconstruct_opts])
```
Returns `raw_ip`. All checksums are calculated automatically. L4 checksums are intentionally corrupted if `badsum` is specified in `reconstruct_opts`.
Returns `raw_ip`. All checksums are calculated automatically. L4 checksums are intentionally corrupted if `badsum` is specified in [reconstruct_opts](#standard-reconstruct).
Reconstructing dissects with IP fragmentation involves a specific interaction between Lua and C code.
The Lua code must prepare a dissect of the full packet intended for fragmentation, but fill certain fields as they should appear in the fragment:
Reconstruction of fragmented IP packets involves special magic.
1. if the "frag_off" field is present, tcp/udp/icmp headers are ignored, payload contains raw ip payload. Incoming fragmented packets come in this form. nfqws2 does not defragment at the IP layer. But this is very persistently done by Linux systems - in order for a fragment to come to nfqws2, you need to try hard by inserting "notrack" into prerouting or output. Dissects in this form can be reconstructed as is. But preparing them in Lua is extremely inconvenient, since you will have to go through the black magic of working with a binary representation.
2. If the "frag_off" field is absent, fragment reconstruction is performed on the entire packet's dissect involving both Lua and C code. Lua code must prepare a dissect of the full packet intended for fragmentation, but fill certain fields as they should appear in the fragment:
- **ipv4**: `ip.ip_len` must be calculated as it should appear in the fragment.
The C code uses `ip.ip_len` to determine the size of the fragmented portion.
@@ -2096,6 +2207,7 @@ Reconstructs the corresponding raw headers from the dissect tables. Returns the
- IPv6 reconstruction utilizes `reconstruct_opts`, specifically `ip6_preserve_next` and `ip6_last_proto`.
- The IP header checksum is calculated automatically since it does not depend on any other components.
- TCP, UDP and ICMP checksums are not calculated automatically because they depend on other components.
- TCP options are padded with 0x00 to a multiple of 4 bytes.
#### csum_fix
@@ -2138,7 +2250,7 @@ If conntrack is disabled or the packet is not valid tcp or udp, nil is returned.
function get_source_ip(target)
```
Get source IP (raw string) that would be used for connection the the target IP.
Get source IP (raw string) that would be used for connection to the target IP.
Returns nil if destination is unreachable.
```
@@ -2296,6 +2408,7 @@ Returns an array of information about all subsequent, pending instances in the c
| range | table | effective range of [counters](#in-profile-filters) `--in-range` or `--out-range` depending on the current direction |
| payload | table | effective payload filter : payload name indexed table. |
| payload_filter | string | effective payload filter : a comma-separated list of payload names. |
| arg | table | instance arguments |
**range**
@@ -2321,6 +2434,66 @@ function execution_plan_cancel(ctx)
A one-time cancellation of all subsequent instances within a profile.
The instance performing the cancellation takes over the coordination of further actions and is called the orchestrator.
### Timer control
Timer creation and deletion functions can be called from any Lua code.
This could be lua-init, lua-desync, or a timer function. A timer function can also act on itself, such as changing the period or terminating its own calls.
Timers are identified by a name. Multiple timers with different names can call the same timer function.
It will be passed the timer name and arbitrary data as parameters (#timer-function-prototype)
#### timer_set
Create or replace the timer.
```
function timer_set(name, func, period, oneshot, data)
```
* name - a unique timer name. If a timer with this name already exists, it is deleted and replaced with a new one. When replaced, the countdown restarts.
* func - the timer function. string or function. if it's a string function is resolved during timer_set call and remembered as a function, not as a string.
* period - the timer call frequency in milliseconds
* oneshot - a bool indicating whether the timer is single-shot (true) or periodic (false)
* data - an arbitrary variable passed to the [timer-function](#timer-function-prototype)
#### timer_del
Delete the timer.
```
function timer_del(name)
```
#### timer_info
Get information about the timer identified by name.
```
function timer_info(name)
```
Returns table in case of success, nil otherwise.
| Field | Type | Description |
| :------ | :----- | :------------------ |
| name | string | unique timer name |
| func | function | timer function |
| oneshot | bool | true = single shot timer, false = periodic timer |
| period | number | timer period in msec |
| fires | number | number of timer calls made |
#### timer_enum
Get an array of unique names of all existing timers.
```
function timer_enum()
```
# zapret-lib.lua base function library
Nearly every function includes detailed comments regarding its purpose and parameters.
@@ -2341,6 +2514,8 @@ The code can address the `desync` table-it is temporarily assigned to a global v
Example: `--lua-desync=luaexec:code="desync.rnd=brandom(math.random(5,10))"`
Verdict can be returned using "return" statement.
### pass
```
@@ -2444,10 +2619,10 @@ Performs a linear search in table `a` for value `v`. `array_field_search` assume
function in_list(s, v)
```
### find_next_line
Checks whether string `v` is included in a comma-separated list of strings `s`. For example, `abc` is included in the list `xyz,abc,12345`.
### find_next_line
```
function find_next_line(s, pos)
```
@@ -3149,12 +3324,12 @@ function host_or_ip(desync)
```
function is_absolute_path(path)
function append_path(path, file)
function writeable_file_name(filename)
function writeble_file_name(filename)
```
- `is_absolute_path` returns true if the path starts from the root. It accounts for CYGWIN path specifics.
- `append_path` appends a file or directory name `file` to `path`, using '/' as a separator.
- `writeable_file_name` returns `filename` if it contains an absolute path or if the `WRITEABLE` environment variable is not set. Otherwise, it retrieves the path from the `WRITEABLE` environment variable and appends the `filename` using `append_path`.
- `writeble_file_name` returns `filename` if it contains an absolute path or if the `WRITABLE` environment variable is not set. Otherwise, it retrieves the path from the `WRITABLE` environment variable and appends the `filename` using `append_path`.
## Reading and writing Files
@@ -3289,7 +3464,7 @@ The `ipfrag_options` contain only two standard parameters. The rest are handled
| Field | Description |
| :-------------- | :------------------------------------------------------------------------------------------------------------------ |
| ipfrag | Name of the fragmenter function. If not specified, `ipfrag2` is used. The fragmenter returns an array of dissects (fragments). |
| ipfrag | Name of the fragmenter function. If specified with no value, `ipfrag2` is used. The fragmenter returns an array of dissects (fragments). |
| ipfrag_disorder | Send fragments in reverse order. |
| ipfrag_pos_udp | (ipfrag2 fragmenter) UDP fragmentation position. Must be a multiple of 8; defaults to 8. |
| ipfrag_pos_tcp | (ipfrag2 fragmenter) TCP fragmentation position. Must be a multiple of 8; defaults to 32. |
@@ -3458,6 +3633,23 @@ function replay_drop(desync)
These functions work correctly with both [replays](#handling-multi-packet-payloads) and regular dissects. For regular dissects, `replay_first` is always true, `replay_drop_set` does not change the flag, and `replay_drop` is always false.
## Timer helpers
```
function dis_timer_name(dis)
```
Construct timer name based on ip src and dst addresses, l4 protocol name, port numbers or icmp codes.
May not be unique.
```
function desync_timer_name(desync)
```
Construct timer name that includes instance name, dis_timer_name result, conntrack packet number.
If track is absent random characters are added to the end.
This name can be considered unique per desync+instance and can be used as an oneshot timer name.
## Orchestration
This group includes functions that support the orchestration and shimming processes.
@@ -3492,7 +3684,8 @@ Checks the [instance cutoff](#instance_cutoff) state for `desync.func_instance`
function apply_arg_prefix(desync)
```
Performs substitution of argument values from `desync.arg` that start with `%` and `#`.
Performs substitution of argument values from `desync.arg` that start with `%`, `#`, `\`.
Multiple calls are safe but do not update desync.arg if blobs were changed.
### apply_execution_plan
@@ -3501,6 +3694,8 @@ function apply_execution_plan(desync, instance)
```
Copies the instance identification and its arguments from an [execution plan](#execution_plan) `instance` into the desync object, thereby recreating the desync state as if the `instance` were called directly by C code.
With one exception : apply_arg_prefix is not applied because args can refer a blob created by previous conditionally executed instances.
The [execution plan](#execution_plan) is provided by the C function `execution_plan()` as an array of `instance` elements.
### verdict_aggregate
@@ -3515,11 +3710,17 @@ Aggregates verdicts v1 and v2. VERDICT_MODIFY overrides VERDICT_PASS, while VERD
```
function plan_instance_execute(desync, verdict, instance)
function plan_instance_execute_preapplied(desync, verdict, instance)
```
Executes an [execution plan](#execution_plan) `instance`, taking into account the [instance cutoff](#instance_cutoff) and standard [payload](#in-profile-filters) and [range](#in-profile-filters) filters.
Calls apply_arg_prefix right before calling the instance.
Returns the aggregation of the current verdict and the `instance` verdict.
The "preapplied" version does not apply execution plan, allowing the calling code to do so.
Sometimes, to decide whether to call an instance, you need a desync table configured for the called instance.
"preapplied" version allows to avoid double copying.
### plan_instance_pop
```
@@ -3531,10 +3732,10 @@ Retrieves, removes, and returns the first element of the [execution plan](#execu
### plan_clear
```
function plan_clear(desync)
function plan_clear(desync, max)
```
Clears the [execution plan](#execution_plan) in `desync.plan` by removing all `instance` elements.
Clears up to the "max" instances if "max" is defined or the whole [execution plan](#execution_plan) in `desync.plan`.
### orchestrate
@@ -3548,10 +3749,10 @@ If `ctx=nil`, it does nothing, assuming the plan is already in `desync.plan`.
### replay_execution_plan
```
function replay_execution_plan(desync)
function replay_execution_plan(desync, max)
```
Executes the entire [execution plan](#execution_plan) from `desync.plan`, respecting the [instance cutoff](#instance_cutoff) and standard [payload](#in-profile-filters) and [range](#in-profile-filters) filters.
Executes up to the "max" instances if "max" is defined, or the entire [execution plan](#execution_plan) from `desync.plan`, respecting the [instance cutoff](#instance_cutoff) and standard [payload](#in-profile-filters) and [range](#in-profile-filters) filters.
# zapret-antidpi.lua DPI attack program library
@@ -3613,9 +3814,14 @@ function send(ctx, desync)
- arg: [standard ipfrag](#standard-ipfrag)
- arg: [standard reconstruct](#standard-reconstruct)
- arg: [standard rawsend](#standard-rawsend)
- arg: delay - packet send delay in msec
- Default `ip_id` mode is `none`.
Sends the current dissect with optional modifications applied.
If delay is specified packet data and send options are remembered. After specified time packet is sent out.
The function returns VERDICT_PASS - the sending of the current dissect is not canceled. If you want to cancel, use the [drop](#drop) instance.
### pktmod
@@ -4000,7 +4206,7 @@ function hostfakesplit(ctx, desync)
- arg: host - template for [fake host generation](#genhost) - random.template
- arg: midhost - [marker](#markers) for an additional split of the segment containing the real host.
- arg: disorder_after - [marker](#markers) for an additional split of the final real part and sending segments in reverse order.
- arg: nofake, nofake2 - skip sending specific fake packets.
- arg: nofake1, nofake2 - skip sending specific fake packets.
- arg: blob - replace the current payload with the specified [blob](#passing-blobs).
- arg: optional - abort the operation if the blob is specified but missing.
- arg: nodrop - skip issuing a VERDICT_DROP.
@@ -4215,7 +4421,7 @@ function automate_failure_counter(hrec, crec, fails, maxtime)
- hrec - [host storage](#automate_host_record)
- crec - [stream storage](#automate_conn_record)
- fails - the target number of failures.
- maxtime - the time in seconds after which, since the last failure, the next failure restarts the count from scratch.
- time - the time in seconds after which, since the last failure, the next failure restarts the count from scratch.
Returns `true` if the counter reaches the `fails` value. The counter is reset upon returning `true`.
@@ -4349,13 +4555,26 @@ function condition(ctx, desync)
- arg: `iff` - name of the [iff function](#iff-functions)
- arg: `neg` - invert the `iff` value; defaults to `false`
- arg: `instances` - how many following instances to execute conditionally. all if not defined.
`condition` calls `iff`. If `iff xor neg = true`, all instances in the `plan` are executed; otherwise, the plan is cleared.
### per_instance_condition
```
function per_instance_condition(ctx, desync)
```
- arg: `instances` - how many following instances to execute conditionally. all if not defined.
All following instanced are called only if they have "cond" argument with the "iff" function name and it returns true. The "cond_neg" argument inverts "cond" result.
Names are not iff/neg to avoid conflict with other orchestrators.
### stopif
```
function condition(ctx, desync)
function stopif(ctx, desync)
```
- arg: `iff` - name of the [iff function](#iff-functions)
@@ -4407,6 +4626,23 @@ function cond_payload_str(desync)
Returns `true` if the substring `pattern` is present in `desync.dis.payload`.
This is a basic signature detector. If the C code does not recognize the protocol you need, you can write your own signature detector and run subsequent instances under a `condition` orchestrator using your detector as the `iff` function.
#### cond_tcp_has_ts
```
function cond_tcp_has_ts(desync)
```
Returns `true` if the dissect is tcp and has tcp timestamp option.
#### cond_lua
```
function cond_lua(desync)
```
Executes a Lua code from the "cond_code" argument. The code returns condition value. Direct addressing of the desync table is possible within the code.
desync.arg is passed without called "apply_arg_prefix" : `%`, `#`, `\` remain as is without substitution because can refer blobs created by previous conditionally executed instances.
# Auxiliary programs
@@ -4559,6 +4795,7 @@ Parallel mode is [supported](#shell-variables). In this mode, each attempt is ex
- **standard** - uses a test algorithm that excludes strategies deemed irrelevant based on previous successes or other criteria. In the case of multiple attempts, testing does not stop upon failure. The success rate and curl errors can also provide useful information for situational analysis.
- **quick** - same as standard, but when using multiple attempts, testing stops after the first failure.
- **veryquick** - same as quick, and also stops testing further variations of a strategy family (extra TCP foolings, autottl deltas, TTL values, and, where applicable, multisplit/fakedsplit positions and split-mechanisms) as soon as any combination has already succeeded for the current target, instead of continuing through the rest for completeness. Only affects the fake-based strategy families (25-fake.sh, 30-faked.sh, 35-hostfake.sh, 50-fake-multi.sh, 55-fake-faked.sh, 60-fake-hostfake.sh); can make those noticeably faster to test when an early candidate already succeeds, at the cost of not necessarily finding every strategy that would also have succeeded (success here means curl got through - it says nothing about how that strategy will actually do in a real browser).
- **force** - tests as extensively as possible, regardless of previous test results.
### Supported protocols
@@ -4692,6 +4929,8 @@ MULTIDISORDER=multidisorder_legacy - replace multidisorder with the version from
NOTEST_BASIC_HTTP=1 - disable 10-http-basic.sh tests
NOTEST_MISC_HTTP=1 - disable http 15-misc.sh tests
NOTEST_MISC_HTTPS=1 - disable https 15-misc.sh tests
NOTEST_OOB_HTTP=1 - disable http 17-oob.sh tests
NOTEST_OOB_HTTPS=1 - disable https 17-oob.sh tests
NOTEST_MULTI_HTTP=1 - disable http 20-multi.sh tests
NOTEST_MULTI_HTTPS=1 - disable https 20-multi.sh tests
NOTEST_SEQOVL_HTTP=1 - disable http 23-seqovl.sh tests
@@ -4704,6 +4943,7 @@ NOTEST_FAKED_HTTP=1 - disable http 25-faked.sh tests
NOTEST_FAKED_HTTPS=1 - disable https 25-faked.sh tests
NOTEST_HOSTFAKE_HTTP=1 - disable http 35-hostfake.sh tests
NOTEST_HOSTFAKE_HTTPS=1 - disable https 35-hostfake.sh tests
HOSTFAKE=host - specify hostname for hostfakesplit
NOTEST_FAKE_MULTI_HTTP=1 - disable http 50-fake-multi.sh tests
NOTEST_FAKE_MULTI_HTTPS=1 - disable https 50-fake-multi.sh tests
NOTEST_FAKE_FAKED_HTTP=1 - disable http 55-fake-faked.sh tests
@@ -4717,53 +4957,55 @@ NOTEST_QUIC=1 - disable 90-quic.sh tests
A simple tester that uses strategy lists from files. Strategies must be on separate lines; line breaks within a single strategy are not allowed. Separate lists are used for different protocols: `list_http.txt`, `list_https_tls12.txt`, `list_https_tls13.txt`, and `list_quic.sh`. These files support comments starting with `#`.
When defining parameters, keep in mind that they will be interpreted as shell arguments. Special characters must be escaped according to shell rules.
For example, leaving `<` unquoted across the entire parameter or incorrectly quoting the `--luaexec=code=print("abc")` parameter will result in an error. If your Lua code uses strings, it is best to enclose them in single quotes and wrap the entire parameter in double quotes.
When defining parameters, keep in mind that they will first be tried as shell arguments. Special characters (`<`, `(`, `'`, and similar) are shell syntax and would normally need escaping - for example, leaving `<` unquoted across the entire parameter, or incorrectly quoting the `--luaexec=code=print("abc")` parameter, would previously result in an error. If a line fails this way now, it's automatically retried as a plain, unparsed argument list instead (split only on whitespace, nothing re-interpreted), so strategies containing these characters work whether or not you escape them yourself - copy one straight from `blockcheck2`'s own output and it will just work. Escaping by hand (single quotes around Lua strings, the whole parameter wrapped in double quotes) is still supported and still takes priority when it succeeds, for anyone who wants shell-side expansion inside a list line.
Note that `blockcheck2` will output strategy parameters without escaping.
The recommended way to use this is to copy it into its own subdirectory within `blockcheck2.d` and populate the `.txt` files with your tests. Then, select your custom test name from the dialog.
## Summary
At the end of the test, all successful strategies are displayed for each domain and each IP protocol version. If more than one domain was tested, the intersection of successful strategies (those that worked for all) is also provided. However, this intersection can only be fully relied upon when using `SCANLEVEL=force`. Otherwise, strategies that might have worked for subsequent domains might not have been tested for the first one.
At the end of the test, all successful strategies are displayed for each domain and each IP protocol version. If more than one domain was tested, the intersection of successful strategies (those that worked for all, labeled COMMON) is also provided, together with a COVERAGE listing of every successful strategy and how many of the domains it worked for, most-covered first - useful when testing a set of largely independent targets where no single strategy is expected to satisfy all of them. However, COMMON and the COVERAGE counts can only be fully relied upon when using `SCANLEVEL=force`. Otherwise, strategies that might have worked for subsequent domains might not have been tested for the first one.
## Shell variables
```
CURL - path to the curl executable
CURL_MAX_TIME - curl timeout in seconds
CURL_MAX_TIME_QUIC - curl timeout for QUIC. If not set, CURL_MAX_TIME is used
CURL_MAX_TIME_DOH - curl timeout for DoH servers
CURL_CMD=1 - display curl commands
CURL_OPT - additional curl options. `-k` to ignore certificates, `-v` for verbose protocol output
CURL_HTTPS_GET=1 - use the GET method instead of HEAD for HTTPS
DOMAINS - space-separated list of domains or domains with URIs to test
TEST - name of the test
IPVS=4|6|46 - IP protocol versions to test
ENABLE_HTTP=0|1 - enable plain HTTP test
ENABLE_HTTPS_TLS12=0|1 - enable HTTPS TLS 1.2 test
ENABLE_HTTPS_TLS13=0|1 - enable HTTPS TLS 1.3 test
ENABLE_HTTP3=0|1 - enable QUIC test
REPEATS - number of test attempts
PARALLEL=0|1 - enable parallel attempts. May overwhelm the site due to aggressive requests and lead to incorrect results
SCANLEVEL=quick|standard|force - scanning level
BATCH=1 - batch mode (no prompts or waiting for console input)
HTTP_PORT, HTTPS_PORT, QUIC_PORT - port numbers for the respective protocols
SKIP_DNSCHECK=1 - skip DNS check
SKIP_IPBLOCK=1 - skip port or IP blocking tests
PKTWS_EXTRA_POST - additional nfqws/dvtws/winws parameters added after the main strategy
PKTWS_EXTRA_POST_1 .. PKTWS_EXTRA_POST_9 - separate additional parameters that contain spaces
PKTWS_EXTRA_PRE - additional nfqws/dvtws/winws parameters added before the main strategy
PKTWS_EXTRA_PRE_1 .. PKTWS_EXTRA_PRE_9 - separate additional parameters that contain spaces
DNSCHECK_DNS - space-separated list of third-party DNS servers for DNS spoofing tests
DNSCHECK_DOM - space-separated list of domains for DNS spoofing tests
SECURE_DNS=0|1 - force enable or disable DoH
DOH_SERVERS - space-separated list of DoH URLs for automatic selection of a working server
DOH_SERVER - specific DoH URL (disables auto-selection)
UNBLOCKED_DOM - an unblocked domain used for IP block tests
SIMULATE=1 - enable simulation mode for debugging script logic. Disables real curl requests and replaces them with random results.
SIM_SUCCESS_RATE=<percent> - simulation success probability as a percentage
```
| Variable | Description |
| :------- | :---------- |
| CURL | path to the curl executable |
| CURL_MAX_TIME | curl timeout in seconds |
| CURL_MAX_TIME_QUIC | curl timeout for QUIC. If not set, CURL_MAX_TIME is used |
| CURL_MAX_TIME_DOH | curl timeout for DoH servers |
| CURL_CMD=1 | display curl commands |
| CURL_OPT | additional curl options. `-k` to ignore certificates, `-v` for verbose protocol output |
| CURL_HTTPS_GET=1 | use the GET method instead of HEAD for HTTPS |
| CURL_PAD | pad every curl request with a junk headers of this many bytes. Full length taken into account along with header name, data field and EOL. Useful for testing a "16 KB"-style whitelist block against a target with no large page of its own to download, since that block triggers on total bytes transferred rather than on how much of it was a real response. Independent of CURL_HTTPS_GET; use whichever fits the target |
| PAD_MAX_HEADER | maximum length in bytes of the data field of one header for CURL_PAD padding. the length can be exceeded by no more than 14 characters for the last header, if the last header together with the name and EOL could be less than 14 characters |
| PACE | minimum time in msec for a single curl query. allows to slow down hammering to avoid server side ban |
| DOMAINS | space-separated list of domains or domains with URIs to test |
| TEST | name of the test |
| IPVS=4\|6\|46 | IP protocol versions to test |
| ENABLE_HTTP=0\|1 | enable plain HTTP test |
| ENABLE_HTTPS_TLS12=0\|1 | enable HTTPS TLS 1.2 test |
| ENABLE_HTTPS_TLS13=0\|1 | enable HTTPS TLS 1.3 test |
| ENABLE_HTTP3=0\|1 | enable QUIC test |
| REPEATS | number of test attempts |
| PARALLEL=0|1 | enable\ parallel\ attempts. May overwhelm the site due to aggressive requests and lead to incorrect results |
| SCANLEVEL=quick\|standard\|force | scanning level |
| BATCH=1 | batch mode (no prompts or waiting for console input) |
| HTTP_PORT, HTTPS_PORT, QUIC_PORT | port numbers for the respective protocols |
| SKIP_DNSCHECK=1 | skip DNS check |
| SKIP_IPBLOCK=1 | skip port or IP blocking tests |
| PKTWS_EXTRA_POST | additional nfqws/dvtws/winws parameters added after the main strategy |
| PKTWS_EXTRA_POST_1 .. PKTWS_EXTRA_POST_9 | separate additional parameters that contain spaces |
| PKTWS_EXTRA_PRE | additional nfqws/dvtws/winws parameters added before the main strategy |
| PKTWS_EXTRA_PRE_1 .. PKTWS_EXTRA_PRE_9 | separate additional parameters that contain spaces |
| DNSCHECK_DNS | space-separated list of third-party DNS servers for DNS spoofing tests |
| DNSCHECK_DOM | space-separated list of domains for DNS spoofing tests |
| SECURE_DNS=0\|1 | force enable or disable DoH |
| DOH_SERVERS | space-separated list of DoH URLs for automatic selection of a working server |
| DOH_SERVER | specific DoH URL (disables auto-selection) |
| UNBLOCKED_DOM | an unblocked domain used for IP block tests |
| SIMULATE=1 | enable simulation mode for debugging script logic. Disables real curl requests and replaces them with random results. |
| SIM_SUCCESS_RATE=\<percent\> | simulation success probability as a percentage |
## Why it won't open
@@ -5044,7 +5286,7 @@ filter_apply_hostlist_target()
# $1 - name of the variable containing nfqws2 options
```
Replaces the `<HOSTLIST>` and `<HOSTLIST_AUTO>` markers in $1 depending on the [MODE_FILTER](#config-file) and the presence of list files in ipset.
Replaces the `<HOSTLIST>` and `<HOSTLIST_NOAUTO>` markers in $1 depending on the [MODE_FILTER](#config-file) and the presence of list files in ipset.
```
standard_mode_daemons()
@@ -5136,6 +5378,15 @@ ipt_first_packets()
Outputs to stdout: `-m connbytes --connbytes-dir=original --connbytes-mode=packets --connbytes $RANGE`. `RANGE` is defined as "1:$1". If `$1` is "keepalive", nothing is output (no connbytes filter).
```
ipt_port_ipset()
# $1 - ipset name
# $2 - comma separated port or port range list. ranges are port1-port2
```
Creates "bitmap:port" ipset filled with the supplied port list. If the set already exists it's elements are replaced.
##### Working with nftables
```
@@ -5424,8 +5675,8 @@ There are several options :
## Windows Server
winws2 is linked against wlanapi.dll which is absent by default.
To solve this problem run power shell as administrator and execute command `Install-WindowsFeature -Name Wireless-Networking`.
To use `--ssid-filter` install wireless networking feature.
Run power shell as administrator and execute command `Install-WindowsFeature -Name Wireless-Networking`.
Then reboot the system.
## Windows ARM64
+450 -192
View File
File diff suppressed because it is too large. Load diff
+27 -16
View File
@@ -9,8 +9,8 @@
VPN. Может использоваться для частичной прозрачной обфускации протоколов.
Проект нацелен прежде всего на маломощные embedded устройства - роутеры, работающие под OpenWrt. Поддерживаются
традиционные Linux-системы, FreeBSD, OpenBSD, Windows. В некоторых случаях возможна самостоятельная прикрутка
решения к различным прошивкам.
традиционные Linux-системы, FreeBSD, OpenBSD, Windows. MacOS не поддерживается и вряд ли будет по техническим причинам.
В некоторых случаях возможна самостоятельная прикрутка решения к различным прошивкам.
[Полный мануал](manual.md)
@@ -48,15 +48,20 @@ zapret2 является дальнейшим развитием проекта
Lua код получает от C кода структурированное представление приходящих пакетов в виде дерева (диссекты), подобного тем, что вы видите в wireshark.
Туда же приходят результаты сборки или дешифровки частей некоторых протоколов (tls, quic).
С код предоставляет функции-хелперы, позволяющие отсылать пакеты, работать с двоичными данными, разбирать TLS, искать маркер-позции и т.д.
С код предоставляет функции-хелперы, позволяющие отсылать пакеты, работать с двоичными данными, разбирать TLS, искать маркер-позиции и т.д.
Имеется библиотека хелперов, написанных на Lua, а так же готовая библиотека программ атаки на DPI (стратегий), реализующая функции *nfqws1* в расширенном варианте
и с большей гибкостью.
Вы всегда сможете взять и дописать что-то свое. В этом и есть смысл, чтобы борьбой с DPI смог заняться любой, кто разбирается в пакетах.
Вы всегда сможете взять и дописать что-то свое. От мелкой частной кустомизации, которую бессмысленно зашивать намертво в C код, до полноценной desync функции.
В этом и есть смысл, чтобы борьбой с DPI смог заняться любой, кто разбирается в пакетах.
Мог "потыкать" его, проверить свои идеи. А потом поделиться с друзьями своим решением "одного клика".
zapret2 - инструмент для таких энтузиастов. Но это не готовое решение для чайников. Проект не ставит себе целью сделать все простым для всех.
Автор считает, что это невозможно в принципе по обьективным причинам.
Борьбой с DPI возможности zapret2 не ограничиваются. По сути это мультиплатформенный пакетный программируемый манипулятор.
Вы можете использовать его для генерации произвольного IPv4/IPv6 трафика, обфускации или шифрования имеющегося, построения нестандартных протоколов обмена через IP сети,
реализации собственных firewall или DPI систем.
## С чего начать
@@ -102,7 +107,7 @@ windivert вообще не отслеживает соединения. Поэ
Дальше под рутом нужно запустить *nfqws2* с параметрами командной строки. Они строятся примерно следующим образом :
```
nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua \
nfqws2 --qnum=200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua \
--filter-tcp=80,443 --filter-l7=tls,http \
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,rndsni,dupsid \
--payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_md5 \
@@ -117,7 +122,7 @@ nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.
После двоеточия и через двоеточия следуют параметры для данной функции в формате `param[=value]`. В примере реализована стратегия
```
nfqws --qnum 200 --debug \
nfqws --qnum=200 --debug \
--filter-tcp=80,443 --filter-l7=tls,http \
--dpi-desync=fake,multisplit --dpi-desync-fooling=md5sig --dpi-desync-split-pos=1,midsld \
--dpi-desync-split-seqovl=5 --dpi-desync-split-seqovl-pattern=0x1603030000 \
@@ -150,7 +155,7 @@ nfqws --qnum 200 --debug \
В *nfqws1* они падали на профиль с автолистом.
```
nfqws2 --qnum 200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua \
nfqws2 --qnum=200 --debug --lua-init=@zapret-lib.lua --lua-init=@zapret-antidpi.lua \
--filter-tcp=80 --filter-l7=http --hostlist=mylist1.txt --lua-desync=multisplit --new \
--filter-tcp=80 --filter-l7=http --hostlist-exclude=mylist2.txt --lua-desync=fake:blob=0x00000000:ip_ttl=5:ip6_ttl=3 --lua-desync=multidisorder:pos=5,endhost-1 --new \
--filter-tcp=443 --filter-l7=tls --hostlist=mylist1.txt --lua-desync=multidisorder
@@ -167,7 +172,7 @@ range задается как `mX-mY`, `mX<mY`, `-mY`, `<mY`, `mX-`.
Есть и режимы, не требущие числа - `a` - всегда, `x` - никогда.
Если разделителем указан знак '-' - конечная позиция включительна, а если '<' - не включительна.
Установка по умолчанию `--in-range=x --out-range=a --payload all`. То есть отсекаются все входящие пакеты и берутся все исходящие.
Установка по умолчанию `--in-range=x --out-range=a --payload=all`. То есть отсекаются все входящие пакеты и берутся все исходящие.
`--in-range`, `--out-range` и `--payload` фильтры могут присутствовать множественно в одном профиле.
Их действие распространяется на все последующие `--lua-desync` функции до следующего фильтра того же типа или до конца профиля.
@@ -248,7 +253,7 @@ nfqws \
nfqws2 \
--blob=tls_google:@tls_clienthello_google_com.bin \
--filter-l7=tls \
--payload tls_client_hello,http_req \
--payload=tls_client_hello,http_req \
--lua-desync=fakedsplit:pattern=tls_google:pos=method+2:nofake1:ip_ttl=1:ip6_ttl=1:ip_autottl=-1,3-20:ip6_autottl=-1,3-20
```
@@ -269,19 +274,19 @@ nfqws2 --lua-desync=wssize:wsize=1:scale=6 --lua-desync=syndata --lua-desync=mul
```
nfqws1 \
--filter-l7 tls \
--filter-l7=tls \
--dpi-desync=fake --dpi-desync-fooling=datanoack --dpi-desync-fake-tls=! \
--dpi-desync-fake-tls-mod=rnd,rndsni,dupsid
nfqws2
--filter-l7 tls \
--filter-l7=tls \
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_flags_unset=ack:tls_mod=rnd,rndsni,dupsid,padencap \
--payload=empty --out-range="s1<d1" --lua-desync=pktmod:ip_ttl=1:ip6_ttl=1
nfqws2 \
--lua-init="fake_default_tls=tls_mod(fake_default_tls,'rnd,rndsni')" \
--filter-l7 tls \
--filter-l7=tls \
--payload=tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_flags_unset=ack:tls_mod=dupsid,padencap \
--payload=empty --out-range="s1<d1" --lua-desync=pktmod:ip_ttl=1:ip6_ttl=1
```
@@ -414,8 +419,8 @@ nfqws2 \
### Какие есть еще параметры
Как узнать какие есть еще функции и какие у них бывают параметры ? Смотрите `zapret-antidpi.lua`. Перед каждой функцией подробно описано какие параметры она берет.
Описание стандартных блоков параметров есть в начале. Позже - по мере сил и возможностей - будет писаться талмуд - справочник с руководством по программированию
*nfqws2* и описание стандартных библиотек.
Описание стандартных блоков параметров есть в начале.
Или сразу читайте [талмуд](manual.md) . Там все документировано.
### Очень важный совет
@@ -425,7 +430,13 @@ nfqws2 \
### Не только лишь автономный обман DPI
Рабочий тестовый пример icmp обфускатора udp от винды к серверу на vps.
Для теста используем wireguard. Ничего в конфигах менять не надо - wireguard будет думать, что он работает по udp, но на самом деле он преобразуется в пинги icmp, которые могут проходить NAT. Размер пакетов не изменяется, потому проблемы MTU нет.
Для теста используем wireguard. Ничего в конфигах менять не надо - wireguard будет думать, что он работает по udp, но на самом деле он преобразуется в пинги icmp, которые могут проходить NAT.
Если NAT не меняет поле Identifier в icmp (типично для Linux NAT), можно использовать легкий stateless вариант, когда размер пакета не меняется, и он с гарантией влезает в MTU.
Провайдерский CGNAT меняет Identifier. Для его поддержки существует параметр udp2icmp `cgnat`. Клиент увеличит размеры исходящих пакетов на 2 байта, поэтому нужно предварительно
уменьшить MTU интерфейса wireguard на 2, если он выбран "под завязку". В режиме cgnat серверный конец будет вести базу измененных идентификаторов и сохранять их при ответе.
Обычно на CGNAT время жизни icmp identifier небольшое - 30 секунд, но может быть еще меньше, и освежаться может только исходящими пакетами. Поэтому нужен частый keepalive со стороны клиента.
Если этого не сделать, будет обрыв до момента, когда wireguard клиент что-либо пошлет. Некоторые операторы троттлят icmp, поэтому могут быть проблемы со скоростью.
Будем загонять исходящие с клиента в icmp type 8 (echo request) code 199 , исходящие с сервера в icmp type 0 (echo reply) code 199.
Код у обоих концов делаем одинаковый, иначе NAT не соотнесет. Без NAT можно коды делать разными для клиента и сервера.
@@ -468,7 +479,7 @@ table ip ztest {
```
```
nfqws2 --qnum 200 --server
nfqws2 --qnum=200 --server
--lua-init=@/opt/zapret2/lua/zapret-lib.lua
--lua-init=@/opt/zapret2/lua/zapret-obfs.lua
--in-range=a
Binary file not shown.
-13
View File
@@ -1,13 +0,0 @@
REGISTER sip:192.168.1.1 SIP/2.0
Via: SIP/2.0/UDP 192.168.1.2:42931;rport;branch=z9hG4bKPj3fd2e8713ffcd90c43f6ce69f6c98461
Max-Forwards: 50
From: <sip:703@192.168.1.1>;tag=ca565d7bd4e24a6d80c631d395ee117e
To: <sip:703@192.168.1.1>
Call-ID: dfec38302b8cea3d83c1452527c895c1
CSeq: 26139 REGISTER
User-Agent: MicroSIP/3.21.5
Contact: <sip:703@192.168.1.2:42931;ob>
Expires: 300
Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, INFO, SUBSCRIBE, NOTIFY, REFER, MESSAGE, OPTIONS
Content-Length: 0
+2 -2
View File
@@ -2,8 +2,8 @@
WEBSERVER_DEFAULT_STRATEGY="
--server
--payload http_reply,tls_server_hello --lua-desync=fake:blob=0x00000000000000000000000000000000:badsum:repeats=2 --lua-desync=multisplit
--payload empty --lua-desync=synack_split"
--payload=http_reply,tls_server_hello --lua-desync=fake:blob=0x00000000000000000000000000000000:badsum:repeats=2 --lua-desync=multisplit
--payload=empty --lua-desync=synack_split"
# can override in config :
NFQWS_OPT_DESYNC_WEBSERVER="${NFQWS_OPT_DESYNC_WEBSERVER:-$WEBSERVER_DEFAULT_STRATEGY}"
+1 -1
View File
@@ -2,7 +2,7 @@
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config :
NFQWS_OPT_DESYNC_DHT="${NFQWS_OPT_DESYNC_DHT:---payload dht --lua-desync=dht_dn}"
NFQWS_OPT_DESYNC_DHT="${NFQWS_OPT_DESYNC_DHT:---payload=dht --lua-desync=dht_dn}"
# set it to "keepalive" to fool all packets, not just the first. or set number of packets to be fooled.
NFQWS_OPT_DHT_PKT_OUT=${NFQWS_OPT_DHT_PKT_OUT:-20}
@@ -2,8 +2,8 @@
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config :
NFQWS_OPT_DESYNC_DISCORD_MEDIA="${NFQWS_OPT_DESYNC_DISCORD_MEDIA:---payload discord_ip_discovery --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
DISCORD_MEDIA_PORT_RANGE="${DISCORD_MEDIA_PORT_RANGE:-50000-50099}"
NFQWS_OPT_DESYNC_DISCORD_MEDIA="${NFQWS_OPT_DESYNC_DISCORD_MEDIA:---payload=discord_ip_discovery --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
DISCORD_MEDIA_PORT_RANGE="${DISCORD_MEDIA_PORT_RANGE:-50000-50099,19294-19344}"
alloc_dnum DNUM_DISCORD_MEDIA
alloc_qnum QNUM_DISCORD_MEDIA
@@ -21,7 +21,7 @@ zapret_custom_firewall()
local DISABLE_IPV6=1
local port_range=$(replace_char - : $DISCORD_MEDIA_PORT_RANGE)
local f="-p udp --dport $port_range -m u32 --u32"
local f="-p udp -m multiport --dports $port_range -m u32 --u32"
# this is simplified test to skip writing monstrous rule. instead of checking 64 bytes for zeroes only check 2 dwords for zero
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=0x52&&0>>22&0x3C@8=0x00010046&&0>>22&0x3C@16=0&&0>>22&0x3C@76=0" '' $QNUM_DISCORD_MEDIA
}
@@ -30,6 +30,6 @@ zapret_custom_firewall_nft()
# stop logic is not required
local DISABLE_IPV6=1
local f="udp dport $DISCORD_MEDIA_PORT_RANGE udp length == 82 @ih,0,32 0x00010046 @ih,64,128 0x00000000000000000000000000000000 @ih,192,128 0x00000000000000000000000000000000 @ih,320,128 0x00000000000000000000000000000000 @ih,448,128 0x00000000000000000000000000000000"
local f="udp dport {$DISCORD_MEDIA_PORT_RANGE} udp length == 82 @ih,0,32 0x00010046 @ih,64,128 0x00000000000000000000000000000000 @ih,192,128 0x00000000000000000000000000000000 @ih,320,128 0x00000000000000000000000000000000 @ih,448,128 0x00000000000000000000000000000000"
nft_fw_nfqws_post "$f" '' $QNUM_DISCORD_MEDIA
}
@@ -1,7 +1,7 @@
# this custom script demonstrates how to launch extra nfqws instance limited by ipset
# can override in config :
NFQWS2_MY1_OPT="${NFQWS2_MY1_OPT:---filter-udp=* --payload known,unknown --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2:payload=all --new --filter-tcp=* --payload=known,unknown --lua-desync=multisplit}"
NFQWS2_MY1_OPT="${NFQWS2_MY1_OPT:---filter-udp=* --payload=known,unknown --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2:payload=all --new --filter-tcp=* --payload=known,unknown --lua-desync=multisplit}"
NFQWS2_MY1_SUBNETS4="${NFQWS2_MY1_SUBNETS4:-173.194.0.0/16 108.177.0.0/17 74.125.0.0/16 64.233.160.0/19 172.217.0.0/16}"
NFQWS2_MY1_SUBNETS6="${NFQWS2_MY1_SUBNETS6:-2a00:1450::/29}"
NFQWS2_MY1_PORTS_TCP=${NFQWS2_MY1_PORTS_TCP:-$NFQWS2_PORTS_TCP}
+1 -1
View File
@@ -2,7 +2,7 @@
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config :
NFQWS_OPT_DESYNC_QUIC="${NFQWS_OPT_DESYNC_QUIC:---payload quic_initial --lua-desync=fake:blob=fake_default_quic:repeats=2}"
NFQWS_OPT_DESYNC_QUIC="${NFQWS_OPT_DESYNC_QUIC:---payload=quic_initial --lua-desync=fake:blob=fake_default_quic:repeats=2}"
alloc_dnum DNUM_QUIC4ALL
alloc_qnum QNUM_QUIC4ALL
+1 -1
View File
@@ -2,7 +2,7 @@
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config :
NFQWS_OPT_DESYNC_STUN="${NFQWS_OPT_DESYNC_STUN:---payload stun --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
NFQWS_OPT_DESYNC_STUN="${NFQWS_OPT_DESYNC_STUN:---payload=stun --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
alloc_dnum DNUM_STUN4ALL
alloc_qnum QNUM_STUN4ALL
+1 -1
View File
@@ -3,7 +3,7 @@
# NOTE: @ih requires nft 1.0.1+ and updated kernel version. it's confirmed to work on 5.15 (openwrt 23) and not work on 5.10 (openwrt 22)
# can override in config :
NFQWS_OPT_DESYNC_WG="${NFQWS_OPT_DESYNC_WG:---payload wireguard_initiation,wireguard_response,wireguard_cookie --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
NFQWS_OPT_DESYNC_WG="${NFQWS_OPT_DESYNC_WG:---payload=wireguard_initiation,wireguard_response,wireguard_cookie --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
alloc_dnum DNUM_WG4ALL
alloc_qnum QNUM_WG4ALL
-1
View File
@@ -38,7 +38,6 @@ Environment=INSTANCE=%i
RestrictAddressFamilies=AF_NETLINK AF_UNIX AF_INET6 AF_INET
LockPersonality=true
MemoryDenyWriteExecute=true
PrivateDevices=true
PrivateMounts=true
PrivateTmp=true
-1
View File
@@ -7,7 +7,6 @@ Type=forking
Restart=no
TimeoutSec=30sec
IgnoreSIGPIPE=no
KillMode=none
GuessMainPID=no
RemainAfterExit=no
ExecStart=/opt/zapret2/init.d/sysv/zapret2 start
@@ -1,5 +1,5 @@
outbound and ip and
udp.DstPort>=50000 and udp.DstPort<=50099 and
(udp.DstPort>=50000 and udp.DstPort<=50099 or udp.DstPort>=19294 and udp.DstPort<=19344) and
udp.PayloadLength=74 and
udp.Payload32[0]=0x00010046 and
udp.Payload32[2]=0 and
+1 -1
View File
@@ -157,7 +157,7 @@ fi
unset PKTWS
case $UNAME in
Linux)
ARCHLIST="my linux-x86_64 linux-x86 linux-arm64 linux-arm linux-mips64 linux-mipsel linux-mips linux-lexra linux-ppc"
ARCHLIST="my linux-x86_64 linux-x86 linux-arm64 linux-arm linux-mips64 linux-mipsel64 linux-mipsel linux-mips linux-lexra linux-ppc linux-riscv64"
PKTWS=nfqws2
;;
FreeBSD)
+12 -6
View File
@@ -1,8 +1,11 @@
CC ?= cc
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
CFLAGS_PIC = -fPIC
CFLAGS += -std=gnu99 $(OPTIMIZE)
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_WIN = -static
LDFLAGS_PIE = -pie
LIBS =
LIBS_WIN = -lws2_32
SRC_FILES = ip2net.c qsort.c
@@ -10,24 +13,27 @@ SRC_FILES = ip2net.c qsort.c
all: ip2net
ip2net: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o ip2net $(SRC_FILES) $(LIBS) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_PIC) -o ip2net $(SRC_FILES) $(LIBS) $(LDFLAGS) $(LDFLAGS_PIE)
systemd: ip2net
android: ip2net
bsd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_BSD) -o ip2net $(SRC_FILES) $(LIBS) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_PIC) $(CFLAGS_BSD) -o ip2net $(SRC_FILES) $(LIBS) $(LDFLAGS) $(LDFLAGS_PIE)
mac: $(SRC_FILES)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -o ip2neta $(SRC_FILES) -target arm64-apple-macos10.8 $(LIBS) $(LDFLAGS)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -o ip2netx $(SRC_FILES) -target x86_64-apple-macos10.8 $(LIBS) $(LDFLAGS)
$(CC) $(CFLAGS) $(CFLAGS_PIC) $(CFLAGS_BSD) -o ip2neta $(SRC_FILES) -target arm64-apple-macos10.8 $(LIBS) $(LDFLAGS) $(LDFLAGS_PIE)
$(CC) $(CFLAGS) $(CFLAGS_PIC) $(CFLAGS_BSD) -o ip2netx $(SRC_FILES) -target x86_64-apple-macos10.8 $(LIBS) $(LDFLAGS) $(LDFLAGS_PIE)
strip ip2neta ip2netx
lipo -create -output ip2net ip2netx ip2neta
rm -f ip2netx ip2neta
win: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_WIN) -o ip2net $(SRC_FILES) $(LIBS_WIN) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_WIN) -o ip2net.exe $(SRC_FILES) $(LIBS_WIN) $(LDFLAGS)
win-arm64-cross:
clang -s $(CFLAGS) $(CFLAGS_WIN) --sysroot=/clangarm64 --target=aarch64-w64-mingw32 -B/clang64/bin -rtlib=compiler-rt -o mdig.exe $(SRC_FILES) $(LIBS_WIN) $(LDFLAGS)
clean:
rm -f ip2net *.o
+33 -20
View File
@@ -54,7 +54,7 @@ standard rawsend :
standard payload :
* payload - comma separarated list of allowed payload types. if not present - allow non-empty known payloads.
* payload - comma separated list of allowed payload types. if not present - allow non-empty known payloads.
standard ip_id :
@@ -86,6 +86,7 @@ end
-- nfqws1 : "--dup"
-- standard args : direction, fooling, ip_id, ipfrag, rawsend, reconstruct
-- arg : delay=<msec> - drop and send delayed
function send(ctx, desync)
direction_cutoff_opposite(ctx, desync, "any")
if direction_check(desync, "any") then
@@ -93,10 +94,19 @@ function send(ctx, desync)
local dis = deepcopy(desync.dis)
apply_fooling(desync, dis)
apply_ip_id(desync, dis, nil, "none")
-- it uses rawsend, reconstruct and ipfrag options
rawsend_dissect_ipfrag(dis, desync_opts(desync))
if desync.arg.delay then
local tname = desync_timer_name(desync)
timer_set(tname, "send_timer_delayed", tonumber(desync.arg.delay), true, {dis = dis, opts = desync_opts(desync)})
else
-- it uses rawsend, reconstruct and ipfrag options
rawsend_dissect_ipfrag(dis, desync_opts(desync))
end
end
end
function send_timer_delayed(name, data)
-- oneshot timer, auto deletes
rawsend_dissect_ipfrag(data.dis, data.opts)
end
-- nfqws1 : "--orig"
-- apply modification to current packet
@@ -125,7 +135,7 @@ function http_domcase(ctx, desync)
local host_range = resolve_multi_pos(desync.dis.payload,desync.l7payload,"host,endhost")
if #host_range == 2 then
local host = string.sub(desync.dis.payload,host_range[1],host_range[2]-1)
local newhost="", i
local newhost=""
for i = 1, #host do
newhost=newhost..((i%2)==0 and string.lower(string.sub(host,i,i)) or string.upper(string.sub(host,i,i)))
end
@@ -221,7 +231,7 @@ function http_unixeol(ctx, desync)
if #http < #desync.dis.payload then
hdis.headers[idx_ua].value = hdis.headers[idx_ua].value .. string.rep(" ", #desync.dis.payload - #http)
end
local http = http_reconstruct_req(hdis, true)
http = http_reconstruct_req(hdis, true)
if #http==#desync.dis.payload then
desync.dis.payload = http
DLOG("http_unixeol: applied")
@@ -389,7 +399,8 @@ 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_shim(desync, dis.payload, desync.arg.tls_mod, nil)
local pl = tls_mod_shim(desync, dis.payload, desync.arg.tls_mod, nil)
if pl then dis.payload = pl end
end
if b_debug then DLOG("syndata: "..hexdump_dlog(dis.payload)) end
if rawsend_dissect_ipfrag(dis, desync_opts(desync)) then
@@ -449,7 +460,8 @@ 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_shim(desync, fake_payload, desync.arg.tls_mod, desync.reasm_data)
local pl = tls_mod_shim(desync, fake_payload, desync.arg.tls_mod, desync.reasm_data)
if pl then fake_payload = pl end
end
-- check debug to save CPU
if b_debug then DLOG("fake: "..hexdump_dlog(fake_payload)) end
@@ -577,7 +589,7 @@ end
-- algorithm is not 100% the same as in nfqws1. multi-segment queries can produce different segment ordering.
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
-- 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=<posmarker> . decrease seq number of the second segment in the original order by N and fill N bytes with pattern (default - all zero). N is resolved marker position and must be less than the first split pos.
-- arg : seqovl_pattern=<blob> . override pattern
-- arg : blob=<blob> - use this data instead of reasm_data
-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent
@@ -631,7 +643,7 @@ end
-- nfqws1 : "--dpi-desync=multidisorder". segment ordering is the same as in nfqws1
-- standard args : direction, payload, fooling, ip_id, rawsend, reconstruct, ipfrag
-- 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=<posmarker> . decrease seq number of the second segment in the original order by N and fill N bytes with pattern (default - all zero). N is resolved marker position and must be less than the first split pos.
-- arg : seqovl_pattern=<blob> . override pattern
-- arg : optional - use zero pattern if seqovl_pattern blob is absent
function multidisorder_legacy(ctx, desync)
@@ -729,14 +741,15 @@ function hostfakesplit(ctx, desync)
local midhost
if desync.arg.midhost then
midhost = resolve_pos(data,desync.l7payload,desync.arg.midhost)
if not midhost then
if midhost then
DLOG("hosfakesplit: midhost marker resolved to "..midhost)
if midhost<=pos[1] or midhost>pos[2] then
DLOG("hostfakesplit: midhost is not inside the host range")
midhost = nil
end
else
DLOG("hostfakesplit: cannot resolve midhost marker '"..desync.arg.midhost.."'")
end
DLOG("hosfakesplit: midhost marker resolved to "..midhost)
if midhost<=pos[1] or midhost>pos[2] then
DLOG("hostfakesplit: midhost is not inside the host range")
midhost = nil
end
end
-- if present apply ipfrag only to real host parts. fakes and parts outside of the host must be visible to DPI.
if midhost then
@@ -893,7 +906,7 @@ function fakedsplit(ctx, desync)
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
end
else
DLOG("fakedsplit: cannot resolve pos '"..desync.arg.pos.."'")
DLOG("fakedsplit: cannot resolve pos '"..spos.."'")
end
else
DLOG("fakedsplit: not acting on further replay pieces")
@@ -938,11 +951,11 @@ function fakeddisorder(ctx, desync)
if b_debug then DLOG("fakeddisorder: resolved split pos: "..tostring(pos-1)) end
-- do not apply fooling to original parts except tcp_ts_up but apply ip_id
local fake, part, pat
local fake, part
local opts_orig = {rawsend = rawsend_opts_base(desync), reconstruct = {}, ipfrag = {}, ipid = desync.arg, fooling = {tcp_ts_up = desync.arg.tcp_ts_up}}
local opts_fake = {rawsend = rawsend_opts(desync), reconstruct = reconstruct_opts(desync), ipfrag = {}, ipid = desync.arg, fooling = desync.arg}
fakepat = desync.arg.pattern and blob(desync,desync.arg.pattern) or "\x00"
local fakepat = desync.arg.pattern and blob(desync,desync.arg.pattern) or "\x00"
-- second fake
fake = pattern(fakepat,pos,#data-pos+1)
@@ -1008,7 +1021,7 @@ function fakeddisorder(ctx, desync)
return desync.arg.nodrop and VERDICT_PASS or VERDICT_DROP
end
else
DLOG("fakeddisorder: cannot resolve pos '"..desync.arg.pos.."'")
DLOG("fakeddisorder: cannot resolve pos '"..spos.."'")
end
else
DLOG("fakeddisorder: not acting on further replay pieces")
@@ -1209,8 +1222,8 @@ function udplen(ctx, desync)
else
desync.dis.payload = string.sub(desync.dis.payload,1,len+inc)
DLOG("udplen: "..len.." => "..#desync.dis.payload)
return VERDICT_MODIFY
end
return VERDICT_MODIFY
end
end
end
+73 -6
View File
@@ -107,10 +107,10 @@ end
-- hostname is original hostname
function is_dpi_redirect(hostname, location)
local ds = dissect_url(location)
if ds.domain then
if ds and ds.domain then
local sld1 = dissect_nld(hostname,2)
local sld2 = dissect_nld(ds.domain,2)
return sld2 and sld1~=sld2
return sld2 and sld1~=sld2 and true or false
end
return false
end
@@ -301,9 +301,10 @@ end
-- 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: time=<sec> - if last failure happened earlier than `time` seconds ago - reset failure counter. default is 60.
-- arg: success_detector - success detector function name
-- arg: failure_detector - failure detector function name
-- 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
-- args for failure detector - see standard_failure_detector or your own detector
-- args for success detector - see standard_success_detector or your own detector
@@ -313,7 +314,7 @@ function circular(ctx, desync)
local function count_strategies(hrec)
if not hrec.ctstrategy then
local uniq={}
local n=0
local n
for i,instance in pairs(desync.plan) do
if instance.arg.strategy then
n = tonumber(instance.arg.strategy)
@@ -405,6 +406,33 @@ function cond_payload_str(desync)
end
return desync.dis.payload and string.find(desync.dis.payload,desync.arg.pattern,1,true)
end
-- true if dissect is tcp and timestamp tcp option is present
function cond_tcp_has_ts(desync)
return desync.dis.tcp and find_tcp_option(desync.dis.tcp.options, TCP_KIND_TS)
end
-- exec lua code in "cond_code" arg and return it's result
function cond_lua(desync)
if not desync.arg.cond_code then
error("cond_lua: no 'cond_code' parameter")
end
local fname = desync.func_instance.."_cond_cond_code"
if not _G[fname] then
local err
_G[fname], err = load(desync.arg.cond_code, fname)
if not _G[fname] then
error(err)
end
end
-- allow dynamic cond_code to access desync
_G.desync = desync
local res, v = pcall(_G[fname])
_G.desync = nil
if not res then
error(v);
end
return v
end
-- check iff function available. error if not
function require_iff(desync, name)
if not desync.arg.iff then
@@ -418,18 +446,57 @@ end
-- 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
-- arg: instances - how many instances execute conditionally. all if not defined
-- test case : --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)
plan_clear(desync, tonumber(desync.arg.instances))
if #desync.plan>0 then
DLOG("condition: executing remaining "..#desync.plan.." instance(s)")
end
end
return replay_execution_plan(desync)
end
-- execute further desync instances.
-- each instance must have "cond" arg and may optionally have "cond_neg" arg.
-- "cond" - condition function. "cond_neg" - invert condition function result
-- arg: instances - how many instances execute conditionally. all if not defined
function per_instance_condition(ctx, desync)
orchestrate(ctx, desync)
local verdict = VERDICT_PASS
local n = 0
local max = tonumber(desync.arg.instances)
while not max or n<max do
local instance = plan_instance_pop(desync)
if not instance then break end
if instance.arg.cond then
if type(_G[instance.arg.cond])~="function" then
error("per_instance_condition: invalid 'iff' function '"..instance.arg.cond.."'")
end
-- preapply exec plan to feed cond function correct args
apply_execution_plan(desync, instance)
if logical_xor(_G[instance.arg.cond](desync), instance.arg.cond_neg) then
verdict = plan_instance_execute_preapplied(desync, verdict, instance)
else
DLOG("per_instance_condition: condition not satisfied. skipping '"..instance.func_instance.."'")
end
else
DLOG("per_instance_condition: no 'cond' arg in '"..instance.func_instance.."'. skipping")
end
n = n + 1
end
if #desync.plan>0 then
DLOG("per_instance_condition: executing remaining "..#desync.plan.." instance(s) unconditionally")
end
return verdict_aggregate(verdict, replay_execution_plan(desync))
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)
+303 -168
View File
@@ -1,4 +1,4 @@
NFQWS2_COMPAT_VER_REQUIRED=5
NFQWS2_COMPAT_VER_REQUIRED=6
if NFQWS2_COMPAT_VER~=NFQWS2_COMPAT_VER_REQUIRED then
error("Incompatible NFQWS2_COMPAT_VER. Use pktws and lua scripts from the same release !")
@@ -24,13 +24,17 @@ function luaexec(ctx, desync)
_G[fname], err = load(desync.arg.code, fname)
if not _G[fname] then
error(err)
return
end
end
-- allow dynamic code to access desync
_G.desync = desync
_G[fname]()
local res, ret = pcall(_G[fname])
_G.desync = nil
if not res then
error(ret)
else
return ret or VERDICT_PASS -- older nfqws2 failed if desync function returned explicit nil
end
end
-- basic desync function
@@ -93,12 +97,12 @@ function detect_payload_str(ctx, desync)
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)
local b = data and string.find(data,desync.arg.pattern,1,true)
if b then
DLOG("detect_payload_str: detected '"..desync.arg.payload.."'")
DLOG("detect_payload_str: detected '"..(desync.arg.payload or '?').."'")
if desync.arg.payload then desync.l7payload = desync.arg.payload end
else
DLOG("detect_payload_str: not detected '"..desync.arg.payload.."'")
DLOG("detect_payload_str: not detected '"..(desync.arg.payload or '?').."'")
if desync.arg.undetected then desync.l7payload = desync.arg.undetected end
end
end
@@ -146,11 +150,13 @@ end
-- applies # and $ prefixes. #var means var length, %var means var value
function apply_arg_prefix(desync)
-- prevent double apply
if desync.arg.__prefix_applied then return end
for a,v in pairs(desync.arg) do
local c = string.sub(v,1,1)
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
desync.arg[a] = tostring(type(blb)=='string' and #blb or 0)
elseif c=='%' then
desync.arg[a] = blob(desync,string.sub(v,2))
elseif c=='\\' then
@@ -160,6 +166,7 @@ function apply_arg_prefix(desync)
end
end
end
desync.arg.__prefix_applied = true
end
-- copy instance identification and args from execution plan to desync table
-- NOTE : to not lose VERDICT_MODIFY dissect changes pass original desync table
@@ -170,7 +177,7 @@ function apply_execution_plan(desync, instance)
desync.func_n = instance.func_n
desync.func_instance = instance.func_instance
desync.arg = deepcopy(instance.arg)
apply_arg_prefix(desync)
-- no apply_arg_prefix here because it may refer non-existing blobs
end
-- produce resulting verdict from 2 verdicts
function verdict_aggregate(v1, v2)
@@ -189,8 +196,7 @@ function verdict_aggregate(v1, v2)
end
return bitor(v,vn)
end
function plan_instance_execute(desync, verdict, instance)
apply_execution_plan(desync, instance)
function plan_instance_execute_preapplied(desync, verdict, 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
@@ -198,16 +204,28 @@ function plan_instance_execute(desync, verdict, instance)
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
-- condition is satisfied. here blobs must be referenced
apply_arg_prefix(desync)
desync.arg.__prefix_applied = nil
DLOG("plan_instance_execute: calling '"..desync.func_instance.."'")
verdict = verdict_aggregate(verdict,_G[instance.func](nil, desync))
end
return verdict
end
function plan_instance_execute(desync, verdict, instance)
apply_execution_plan(desync, instance)
return plan_instance_execute_preapplied(desync,verdict,instance)
end
function plan_instance_pop(desync)
return (desync.plan and #desync.plan>0) and table.remove(desync.plan, 1) or nil
end
function plan_clear(desync)
while table.remove(desync.plan) do end
function plan_clear(desync, max)
if max then
local n=0
while n<max and table.remove(desync.plan,1) do n=n+1 end
else
while table.remove(desync.plan) do end
end
end
-- this approach allows nested orchestrators
function orchestrate(ctx, desync)
@@ -230,12 +248,17 @@ function desync_copy(desync)
return dcopy
end
-- redo what whould be done without orchestration
function replay_execution_plan(desync)
function replay_execution_plan(desync, max)
local verdict = VERDICT_PASS
while true do
local n=0
while not max or n<max do
local instance = plan_instance_pop(desync)
if not instance then break end
verdict = plan_instance_execute(desync, verdict, instance)
n = n + 1
end
if max and n>=max then
DLOG("replay_execution_plan: reached max instances limit "..max)
end
return verdict
end
@@ -322,24 +345,25 @@ end
-- convert array a to packed string using 'packer' function. only numeric indexes starting from 1, order preserved
function barray(a, packer)
if a then
local s=""
local sa={}
for i=1,#a do
s = s .. packer(a[i])
sa[i] = packer(a[i])
end
return s
return table.concat(sa)
end
end
-- convert table a to packed string using 'packer' function. any indexes, any order
function btable(a, packer)
if a then
local s=""
local sa={}
local i=1
for k,v in pairs(a) do
s = s .. packer(v)
sa[i] = packer(v)
i=i+1
end
return s
return table.concat(sa)
end
end
-- sequence comparision functions. they work only within 2G interval
-- seq1>=seq2
function seq_ge(seq1, seq2)
@@ -419,7 +443,7 @@ function string2hex(s)
return ss
end
function has_nonprintable(s)
return s:match("[^ -\\r\\n\\t]")
return s:match("[^ -\r\n\t]")
end
function make_readable(v)
if type(v)=="string" then
@@ -527,9 +551,10 @@ function blob(desync, name, def)
-- use global var if no field in dissect table
blob = _G[name]
if not blob then
error("blob '"..name.."' unavailable")
error("blob '"..name.."' unavailable")
end
end
blob = tostring(blob)
end
return blob
end
@@ -614,7 +639,7 @@ function tls_mod_shim(desync, blob, modlist, payload)
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)
modlist = string.sub(modlist,1,p1+3)..tostring(val)..string.sub(modlist,p2+1)
end
return tls_mod(blob,modlist,payload)
end
@@ -626,7 +651,7 @@ function parse_tcp_flags(s)
local s_upper = string.upper(s)
for flag in string.gmatch(s_upper, "[^,]+") do
if flags[flag] then
f = bitor(f,flags[flag])
f = bitor(f,flags[flag])
else
error("tcp flag '"..flag.."' is invalid")
end
@@ -737,6 +762,63 @@ function fix_ip6_next(ip6, last_proto)
end
end
function dis_ipsrc(dis)
if dis.ip then
return dis.ip.ip_src
elseif dis.ip6 then
return dis.ip6.ip6_src
end
end
function dis_ipdst(dis)
if dis.ip then
return dis.ip.ip_dst
elseif dis.ip6 then
return dis.ip6.ip6_dst
end
end
function dis_l4_name(dis)
local l4
if dis.tcp then
l4="tcp"
elseif dis.udp then
l4="udp"
elseif dis.icmp then
l4="icmp"
else
l4="raw"..ip_proto_l3(dis)
end
return l4
end
function dis_l4_ports(dis)
local p1,p2
if dis.tcp then
p1=dis.tcp.th_sport
p2=dis.tcp.th_dport
elseif dis.udp then
p1=dis.udp.uh_sport
p2=dis.udp.uh_dport
elseif dis.icmp then
p1=dis.icmp.icmp_type
p2=dis.icmp.icmp_code
end
return p1 and (p1..":"..p2) or "?"
end
function dis_timer_name(dis)
return table.concat({ntop(dis_ipsrc(dis)),"->",ntop(dis_ipdst(dis)),"_",dis_l4_name(dis),"_",dis_l4_ports(dis)})
end
function desync_timer_name(desync)
local name = desync.func_instance.."_"..dis_timer_name(desync.dis)
if desync.track then
name = name.."_n"..desync.track.pos.direct.pcounter
else
name = name.."_"..brandom_az09(10)
end
return name
end
-- reverses ip addresses, ports and seq/ack
function dis_reverse(dis)
if dis.ip then
@@ -790,9 +872,9 @@ function autottl(incoming_ttl, attl)
if incoming_ttl>223 then
orig=255
elseif incoming_ttl<128 and incoming_ttl>96 then
elseif incoming_ttl<=128 and incoming_ttl>96 then
orig=128
elseif incoming_ttl<64 and incoming_ttl>32 then
elseif incoming_ttl<=64 and incoming_ttl>32 then
orig=64
else
return nil
@@ -836,7 +918,7 @@ end
-- tcp_seq=N - add N to tcp.th_seq
-- tcp_ack=N - add N to tcp.th_ack
-- tcp_ts=N - add N to timestamp value
-- tcp_md5[=hex] - add MD5 header with optional 16-byte data. all zero by default.
-- tcp_md5[=hex] - add MD5 header with optional 16-byte data. random by default.
-- tcp_flags_set=<list> - set tcp flags in comma separated list
-- tcp_flags_unset=<list> - unset tcp flags in comma separated list
-- tcp_ts_up - move timestamp tcp option to the top if it's present. this allows linux not to accept badack segments without badseq. this is very strange discovery but it works.
@@ -857,7 +939,11 @@ function apply_fooling(desync, dis, fooling_options)
if type(desync.track.lua_state.autottl_cache)~="table" then desync.track.lua_state.autottl_cache={} end
if type(desync.track.lua_state.autottl_cache[desync.func_instance])~="table" then desync.track.lua_state.autottl_cache[desync.func_instance]={} end
if not desync.track.lua_state.autottl_cache[desync.func_instance].autottl_found then
desync.track.lua_state.autottl_cache[desync.func_instance].autottl = autottl(desync.track.incoming_ttl,parse_autottl(arg_autottl))
local attl = parse_autottl(arg_autottl)
if not attl then
error("apply_fooling: invalid autottl value '"..arg_autottl.."'")
end
desync.track.lua_state.autottl_cache[desync.func_instance].autottl = autottl(desync.track.incoming_ttl,attl)
if desync.track.lua_state.autottl_cache[desync.func_instance].autottl then
desync.track.lua_state.autottl_cache[desync.func_instance].autottl_found = true
DLOG("apply_fooling: discovered autottl "..desync.track.lua_state.autottl_cache[desync.func_instance].autottl)
@@ -872,8 +958,11 @@ function apply_fooling(desync, dis, fooling_options)
DLOG("apply_fooling: cannot apply autottl because incoming ttl unknown")
end
end
if not ttl and tonumber(arg_ttl) then
if not ttl and arg_ttl then
ttl = tonumber(arg_ttl)
if not ttl or ttl<0 or ttl>255 then
error("apply_fooling: ip_ttl and ip6_ttl require valid value")
end
end
--io.stderr:write("TTL "..tostring(ttl).."\n")
return ttl
@@ -890,11 +979,19 @@ function apply_fooling(desync, dis, fooling_options)
-- use current packet if dissect not given
if not dis then dis = desync.dis end
if dis.tcp then
if tonumber(fooling_options.tcp_seq) then
dis.tcp.th_seq = u32add(dis.tcp.th_seq, fooling_options.tcp_seq)
if fooling_options.tcp_seq then
if tonumber(fooling_options.tcp_seq) then
dis.tcp.th_seq = u32add(dis.tcp.th_seq, fooling_options.tcp_seq)
else
error("apply_fooling: tcp_seq requires increment parameter. there's no default value.")
end
end
if tonumber(fooling_options.tcp_ack) then
dis.tcp.th_ack = u32add(dis.tcp.th_ack, fooling_options.tcp_ack)
if fooling_options.tcp_ack then
if tonumber(fooling_options.tcp_ack) then
dis.tcp.th_ack = u32add(dis.tcp.th_ack, fooling_options.tcp_ack)
else
error("apply_fooling: tcp_ack requires increment parameter. there's no default value.")
end
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)))
@@ -909,12 +1006,16 @@ function apply_fooling(desync, dis, fooling_options)
end
end
end
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(u32add(u32(dis.tcp.options[idx].data),fooling_options.tcp_ts))..string.sub(dis.tcp.options[idx].data,5)
if fooling_options.tcp_ts then
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(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
else
DLOG("apply_fooling: timestamp tcp option not present or invalid")
error("apply_fooling: tcp_ts requires increment parameter. there's no default value.")
end
end
if fooling_options.tcp_md5 then
@@ -925,18 +1026,18 @@ function apply_fooling(desync, dis, fooling_options)
end
end
if fooling_options.tcp_ts_up then
move_ts_top(dis.tcp.options)
move_ts_top()
end
end
if dis.ip6 then
local bin
if fooling_options.ip6_hopbyhop then
bin = prepare_bin(fooling_options.ip6_hopbyhop,"\x00\x00\x00\x00\x00\x00")
insert_ip6_exthdr(dis.ip6,nil,IPPROTO_HOPOPTS,bin)
insert_ip6_exthdr(dis.ip6,1,IPPROTO_HOPOPTS,bin)
end
if fooling_options.ip6_hopbyhop2 then
bin = prepare_bin(fooling_options.ip6_hopbyhop2,"\x00\x00\x00\x00\x00\x00")
insert_ip6_exthdr(dis.ip6,nil,IPPROTO_HOPOPTS,bin)
insert_ip6_exthdr(dis.ip6,1,IPPROTO_HOPOPTS,bin)
end
-- for possible unfragmentable part
if fooling_options.ip6_destopt then
@@ -1094,7 +1195,7 @@ end
-- option : ipfrag.ipfrag_disorder - send fragments from last to first
function rawsend_dissect_ipfrag(dis, options)
if options and options.ipfrag and options.ipfrag.ipfrag then
if options and options.ipfrag and options.ipfrag.ipfrag and not dis.frag then
local frag_func = options.ipfrag.ipfrag=="" and "ipfrag2" or options.ipfrag.ipfrag
if type(_G[frag_func]) ~= "function" then
error("rawsend_dissect_ipfrag: ipfrag function '"..tostring(frag_func).."' does not exist")
@@ -1146,16 +1247,17 @@ function rawsend_dissect_segmented(desync, dis, mss, options)
local pos=1
local len
local payload=discopy.payload
while pos <= #payload do
len = #payload - pos + 1
if len > max_data then len = max_data end
if oob then
if urp>=pos and urp<(pos+len)then
discopy.tcp.th_flags = bitor(dis.tcp.th_flags, TH_URG)
if urp==0 and pos==1 then
discopy.tcp.th_flags = bitor(discopy.tcp.th_flags, TH_URG)
elseif urp>=pos and urp<(pos+len) then
discopy.tcp.th_flags = bitor(discopy.tcp.th_flags, TH_URG)
discopy.tcp.th_urp = urp-pos+1
else
discopy.tcp.th_flags = bitand(dis.tcp.th_flags, bitnot(TH_URG))
discopy.tcp.th_flags = bitand(discopy.tcp.th_flags, bitnot(TH_URG))
discopy.tcp.th_urp = 0
end
end
@@ -1165,7 +1267,7 @@ function rawsend_dissect_segmented(desync, dis, mss, options)
-- stop if failed
return false
end
discopy.tcp.th_seq = discopy.tcp.th_seq + len
discopy.tcp.th_seq = u32add(discopy.tcp.th_seq, len)
pos = pos + len
end
return true
@@ -1188,7 +1290,7 @@ function rawsend_payload_segmented(desync, payload, seq, options)
end
-- check if desync.outgoing comply with arg.dir or def if it's not present or "out" of they are not present both. dir can be "in","out","any"
-- check if desync.outgoing complies with arg.dir or def if it's not present or "out" if they are not present both. dir can be "in","out","any"
function direction_check(desync, def)
local dir = desync.arg.dir or def or "out"
return desync.outgoing and dir~="in" or not desync.outgoing and dir~="out"
@@ -1212,7 +1314,7 @@ function payload_match_filter(l7payload, l7payload_filter, def)
local pl = neg and string.sub(argpl,2) or argpl
return neg ~= (in_list(pl, "all") or in_list(pl, l7payload) or in_list(pl, "known") and l7payload~="unknown" and l7payload~="empty")
end
-- check if desync payload type comply with payload type list in arg.payload
-- check if desync payload type complies with payload type list in arg.payload
-- if arg.payload is not present - check for known payload - not empty and not unknown (nfqws1 behavior without "--desync-any-protocol" option)
-- if arg.payload is prefixed with '~' - it means negation
function payload_check(desync, def)
@@ -1334,9 +1436,9 @@ end
function append_path(path,file)
return string.sub(path,#path,#path)=='/' and path..file or path.."/"..file
end
function writeable_file_name(filename)
function writable_file_name(filename)
if is_absolute_path(filename) then return filename end
local writedir = os.getenv("WRITEABLE")
local writedir = os.getenv("WRITABLE")
if not writedir then return filename end
return append_path(writedir, filename)
end
@@ -1374,7 +1476,7 @@ end
-- option : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8
-- option : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32
-- option : ipfrag_pos_icmp - icmp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8
-- option : ipfrag_pos - icmp frag position for other L4. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32
-- option : ipfrag_pos - frag position for other L4. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32
-- option : ipfrag_next - next protocol field in ipv6 fragment extenstion header of the second fragment. same as first by default.
function ipfrag2(dis, ipfrag_options)
local function frag_idx(exthdr)
@@ -1500,13 +1602,17 @@ function tls_client_hello_mod(tls, options)
DLOG("tls_client_hello_mod: could not dissect tls")
return
end
if not tdis.handshake or not tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT] then
if not tdis.handshake or not tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT] or not tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis then
DLOG("tls_client_hello_mod: handshake not dissected")
return
end
local idx_sni
if options.sni_snt or options.sni_del_ext or options.sni_del or options.sni_first or options.sni_last then
idx_sni = array_field_search(tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext, "type", TLS_EXT_SERVER_NAME)
if tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext then
idx_sni = array_field_search(tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext, "type", TLS_EXT_SERVER_NAME)
else
tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext={}
end
if not idx_sni then
DLOG("tls_client_hello_mod: no SNI extension. adding")
table.insert(tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext, 1, { type = TLS_EXT_SERVER_NAME, dis = { list = {} } } )
@@ -1530,11 +1636,11 @@ function tls_client_hello_mod(tls, options)
table.insert(tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.ext[idx_sni].dis.list, { name = options.sni_last, type = options.sni_snt_new } )
end
end
local tls = tls_reconstruct(tdis)
if not tls then
local rtls = tls_reconstruct(tdis)
if not rtls then
DLOG_ERR("tls_client_hello_mod: reconstruct error")
end
return tls
return rtls
end
-- checks if filename is gzip compressed
@@ -1601,9 +1707,9 @@ function gzip_file(filename, data, expected_ratio, level, memlevel, compress_blo
if not gz then
error("gzip_file: stream init error")
end
local off=1, block_size
local off=1
repeat
block_size = #data-off+1
local block_size = #data-off+1
if block_size>compress_block_size then block_size=compress_block_size end
local comp, eof = gzip_deflate(gz, string.sub(data,off,off+block_size-1), block_size / expected_ratio)
if not comp then
@@ -1623,7 +1729,7 @@ function readfile(filename)
if not f then
error("readfile: "..err)
end
local s,err = f:read("*a")
local s, err = f:read("*a")
f:close()
if err then
error("readfile: "..err)
@@ -1641,13 +1747,14 @@ function writefile(filename, data)
if not f then
error("writefile: "..err)
end
local s,err = f:write(data)
local s, err = f:write(data)
f:close()
if not s then
error("writefile: "..err)
end
end
-- DISSECTORS
function http_dissect_header(header)
@@ -1661,7 +1768,7 @@ function http_dissect_header(header)
end
-- make table with structured http header representation
function http_dissect_headers(http, pos)
local eol,pnext,header,value,idx,headers,pos_endheader,pos_startvalue,pos_headers_end
local eol,pnext,header,value,headers,pos_endheader,pos_startvalue,pos_headers_end
headers={}
while pos do
eol,pnext = find_next_line(http,pos)
@@ -1756,7 +1863,7 @@ function dissect_url(url)
creds = string.sub(url,p1,pend-1)
p1 = pend+1
end
pstart,pend = string.find(url,"/",p1,true)
pstart,pend = string.find(url,"[/?#]",p1)
if pend then
if pend==pb then
uri = string.sub(url,pb)
@@ -2110,7 +2217,7 @@ function is_tls_record(tls, offset, ctype, partialOK)
if not tls then return false end
if not offset then offset=1 end
if (#tls-offset+1)<6 or (ctype and ctype~=tls_record_type(tls, offset)) then return false end
if (#tls-offset+1)<5 or (ctype and ctype~=tls_record_type(tls, offset)) then return false end
local f2 = u16(tls, offset+1)
return f2>=TLS_VER_SSL30 and f2<=TLS_VER_TLS12 and (partialOK or tls_record_full(tls, offset))
@@ -2149,12 +2256,12 @@ function is_tls_handshake(tls, offset, htype, partialOK)
if not TLS_HANDSHAKE_TYPE_NAMES[typ] then return false end
if typ==TLS_HANDSHAKE_TYPE_CLIENT or typ==TLS_HANDSHAKE_TYPE_SERVER then
-- valid tls versions
if (#tls-offset+1)<6 then return false end
local f2 = u16(tls,offset+4)
if f2<TLS_VER_SSL30 or f2>TLS_VER_TLS12 then return false end
end
-- length fits to data buffer
return partialOK or tls_handshake_full(tls, offset)
end
function is_tls_hello(tls, offset, partialOK)
return is_tls_handshake(tls, offset, TLS_HANDSHAKE_TYPE_CLIENT, partialOK) or is_tls_handshake(tls, offset, TLS_HANDSHAKE_TYPE_SERVER, partialOK)
@@ -2174,21 +2281,32 @@ function quic_tvb(data, offset)
return bitand(u32(data,offset),0x3FFFFFFF), 4
elseif size==3 then
if (offset+7)>#data then return end
-- only lua 5.3+ can handle this. others can't store 64-bit integers
return bitand(u32(data,offset),0x3FFFFFFF) * 0x100000000 + u32(data,offset+4), 8
-- only lua 5.3+ has 64-bit integer type. others can't store 64-bit integers. return raw string if the value cannot fit.
local msb = bitand(u32(data,offset),0x3FFFFFFF)
-- lua 5.3+ has math.type function, older lua and luajit - don't
if math.type==nil and msb>0x1FFFFF then
return string.sub(data,offset,offset+7), 8
else
return msb * 0x100000000 + u32(data,offset+4), 8
end
end
end
-- quic-style tvb reconstruct
function bquic_tvb(v)
if v<0x40 then
return bu8(v)
elseif v<0x4000 then
return bu16(v + 0x4000)
elseif v<0x40000000 then
return bu32(v + 0x80000000)
elseif v<0x4000000000000000 then
-- only lua 5.3+ can handle 64-bit int !
return bu32(divint(v, 0x100000000) + 0xC0000000) .. bu32(v % 0x100000000)
if type(v)=="string" then
-- raw string. do not do anything, just return it
return v
else
if v<0x40 then
return bu8(v)
elseif v<0x4000 then
return bu16(v + 0x4000)
elseif v<0x40000000 then
return bu32(v + 0x80000000)
elseif v<0x4000000000000000 then
-- only lua 5.3+ can handle 64-bit int !
return bu32(divint(v, 0x100000000) + 0xC0000000) .. bu32(v % 0x100000000)
end
end
end
@@ -2225,7 +2343,8 @@ function tls_dissect_ext(ext)
return left, off
end
local dis={}, off, len, left
local dis={}
local off, len, left
ext.dis = nil
@@ -2282,7 +2401,7 @@ function tls_dissect_ext(ext)
left, off = len16_header()
if not left then return end
dis.list = {}
while left>=1 do
while left>=4 do
len = u16(ext.data, off + 2)
if (len+4)>left then return end
dis.list[#dis.list+1] = { group = u16(ext.data, off) , kex = string.sub(ext.data, off+4, off+4+len-1) }
@@ -2311,7 +2430,7 @@ function tls_dissect_ext(ext)
off = off + size
left = left - size
len, size = quic_tvb(ext.data, off)
if not len then return end
if type(len)~="number" then return end
off = off + size
left = left - size
if len > left then return end
@@ -2328,93 +2447,102 @@ end
-- dissect client/server hello. leave 'data' as is for others
function tls_dissect_handshake(handshake, partialOK)
if is_tls_hello(handshake.data, 1, partialOK) then
local hlen = tls_handshake_len(handshake.data, 1)
if hlen > #handshake.data then
if not partialOK then return false end
hlen = #handshake.data
end
local typ = tls_handshake_type(handshake.data, 1)
handshake.dis = { type = typ , ver = u16(handshake.data, 5), name = tostring(TLS_HANDSHAKE_TYPE_NAMES[typ]) }
-- random
if hlen<36 then return partialOK end
handshake.dis.random = string.sub(handshake.data, 7, 38)
-- session_id
if hlen<39 then return partialOK end
local len = u8(handshake.data, 39)
local left = hlen-39-len
if left<0 then return partialOK end
handshake.dis.session_id = string.sub(handshake.data, 40, 40+len-1)
local off = 40+len
-- cipher suite(s)
if left<2 then return partialOK end
if handshake.dis.type==TLS_HANDSHAKE_TYPE_CLIENT then
-- client hello - array
len = u16(handshake.data, off)
if left<(2+len) then return partialOK end
handshake.dis.cipher_suites={}
for i=1,(len/2) do
handshake.dis.cipher_suites[i] = u16(handshake.data, off + i*2)
local function tls_dissect_handshake_(handshake, partialOK)
handshake.dis = nil
if is_tls_hello(handshake.data, 1, partialOK) then
local hlen = tls_handshake_len(handshake.data, 1)
if hlen > #handshake.data then
if not partialOK then return false end
hlen = #handshake.data
end
off = off + 2 + len
left = left - 2 - len
else
-- server hello - single
handshake.dis.cipher_suite = u16(handshake.data, off)
local typ = tls_handshake_type(handshake.data, 1)
handshake.dis = { type = typ , ver = u16(handshake.data, 5), name = tostring(TLS_HANDSHAKE_TYPE_NAMES[typ]) }
-- random
if hlen<38 then return partialOK end
handshake.dis.random = string.sub(handshake.data, 7, 38)
-- session_id
if hlen<39 then return partialOK end
local len = u8(handshake.data, 39)
local left = hlen-39-len
if left<0 then return partialOK end
handshake.dis.session_id = string.sub(handshake.data, 40, 40+len-1)
local off = 40+len
-- cipher suite(s)
if left<2 then return partialOK end
if handshake.dis.type==TLS_HANDSHAKE_TYPE_CLIENT then
-- client hello - array
len = u16(handshake.data, off)
if left<(2+len) then return partialOK end
handshake.dis.cipher_suites={}
for i=1,(len/2) do
handshake.dis.cipher_suites[i] = u16(handshake.data, off + i*2)
end
off = off + 2 + len
left = left - 2 - len
else
-- server hello - single
handshake.dis.cipher_suite = u16(handshake.data, off)
off = off + 2
left = left - 2
end
-- compression method(s)
if left<1 then return partialOK end
if handshake.dis.type==1 then
-- client hello - array
len = u8(handshake.data, off)
if left<(1+len) then return partialOK end
handshake.dis.compression_methods={}
for i=1,len do
handshake.dis.compression_methods[i] = u8(handshake.data, off + i)
end
off = off + 1 + len
left = left - 1 - len
else
-- server hello - single
handshake.dis.compression_method = u8(handshake.data, off)
off = off + 1
left = left - 1
end
-- tls extensions
if left<2 then return partialOK end
local extlen = u16(handshake.data, off)
if left<(2+extlen) and not partialOK then return false end
off = off + 2
left = left - 2
end
if left>extlen then left=extlen end
-- compression method(s)
if left<1 then return partialOK end
if handshake.dis.type==1 then
-- client hello - array
len = u8(handshake.data, off)
if left<(1+len) then return partialOK end
handshake.dis.compression_methods={}
for i=1,len do
handshake.dis.compression_methods[i] = u8(handshake.data, off + i)
end
off = off + 1 + len
left = left - 1 - len
else
-- server hello - single
handshake.dis.compression_method = u8(handshake.data, off)
off = off + 1
left = left - 1
end
-- tls extensions
if left<2 then return partialOK end
local extlen = u16(handshake.data, off)
if left<(2+extlen) and not partialOK then return end
off = off + 2
left = left - 2
if left>extlen then left=extlen end
handshake.dis.ext = {}
while left>=4 do
len = u16(handshake.data, off + 2)
if len>(left-4) then
if partialOK then
break
else
return
handshake.dis.ext = {}
while left>=4 do
len = u16(handshake.data, off + 2)
if len>(left-4) then
if partialOK then
break
else
return false
end
end
local typ = u16(handshake.data, off)
handshake.dis.ext[#handshake.dis.ext+1] = { type = typ, name = tostring(TLS_HELLO_EXT_NAMES[typ]), data = string.sub(handshake.data, off+4, off+4+len-1) }
tls_dissect_ext(handshake.dis.ext[#handshake.dis.ext])
left = left - 4 - len
off = off + 4 + len
end
local typ = u16(handshake.data, off)
handshake.dis.ext[#handshake.dis.ext+1] = { type = typ, name = tostring(TLS_HELLO_EXT_NAMES[typ]), data = string.sub(handshake.data, off+4, off+4+len-1) }
tls_dissect_ext(handshake.dis.ext[#handshake.dis.ext])
left = left - 4 - len
off = off + 4 + len
end
return true
return true
end
return false
end
return false
local b = tls_dissect_handshake_(handshake,partialOK)
if not b then
-- clear partially filled dissect if failed
handshake.dis = nil
end
return b
end
-- convert tls blob tls dissect
@@ -2433,6 +2561,11 @@ function tls_dissect(tls, offset, partialOK)
if typ==TLS_RECORD_TYPE_CHANGE_CIPHER_SPEC then
encrypted = true
elseif typ==TLS_RECORD_TYPE_HANDSHAKE and not encrypted then
-- need 4 bytes for handshake type and 24-bit length
if (#tls-off+1)<9 then
if not partialOK then return end
break
end
local htyp = tls_handshake_type(tls, off + 5)
tdis.rec[#tdis.rec].htype = htyp
if not tdis.handshake then tdis.handshake = {} end
@@ -2448,7 +2581,7 @@ function tls_dissect(tls, offset, partialOK)
-- next record
if not is_tls_record(tls, off + 5 + len, nil, partialOK) or tls_record_type(tls, off + 5 + len) ~= typ then
if not partialOK then return end
break
goto endrec
end
off = off + 5 + len
len = tls_record_data_len(tls, off)
@@ -2458,14 +2591,15 @@ function tls_dissect(tls, offset, partialOK)
-- next record
off = off + 5 + len
end
::endrec::
if tdis.handshake then
for htyp, handshake in pairs(tdis.handshake) do
if (handshake.type == TLS_HANDSHAKE_TYPE_CLIENT or handshake.type == TLS_HANDSHAKE_TYPE_SERVER) then
tls_dissect_handshake(handshake, 1, partialOK)
tls_dissect_handshake(handshake, partialOK)
end
end
elseif is_tls_handshake(tls, offset, nil, partialOK) then
elseif not tdis.rec and is_tls_handshake(tls, offset, nil, partialOK) then
local htyp = tls_handshake_type(tls, offset)
tdis.handshake = { [htyp] = { type = htyp, name = TLS_HANDSHAKE_TYPE_NAMES[htyp], data = string.sub(tls, offset, #tls) } }
tls_dissect_handshake(tdis.handshake[htyp], partialOK)
@@ -2540,8 +2674,10 @@ function tls_reconstruct_handshake(handshake)
end
exts = exts .. bu16(handshake.dis.ext[i].type) .. bu16(#handshake.dis.ext[i].data) .. handshake.dis.ext[i].data
end
handshake.data = bu8(handshake.type) .. bu24(#header + 2 + #exts) .. header .. bu16(#exts) .. exts
else
handshake.data = bu8(handshake.type) .. bu24(#header) .. header
end
handshake.data = bu8(handshake.type) .. bu24(#header + 2 + #exts) .. header .. bu16(#exts) .. exts
end
end
@@ -2592,11 +2728,10 @@ function tls_reconstruct(tdis)
if not rec.data then return nil end
end
tls = barray(tdis.rec, function(a) return (#a.data > 0) and (bu8(a.type) .. bu16(a.ver) .. bu16(#a.data) .. a.data) or "" end)
elseif tdis.handshake and #tdis.handshake==1 then
-- without record layer
for k,handshake in pairs(tdis.handshake) do
tls = handshake.data
break
elseif tdis.handshake then
local i = next(tdis.handshake)
if i~=nil then
tls = tdis.handshake[i].data
end
end
+78 -8
View File
@@ -82,13 +82,13 @@ end
-- test case :
-- endpoint1:
-- --filter-icmp=0,8,128,129 --filter-ipp=193,198,209,250 --filter-tcp=* --filter-udp=* --in-range=a --lua-desync=ippxor:xor=192:dataxor=0xABCD
-- --filter-icmp=0,8,128,129 --filter-ipp=193,198,209,250 --filter-tcp=* --filter-udp=* --in-range=a --lua-desync=ippxor:ippxor=192:dataxor=0xABCD
-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto {193, 198, 209, 250} queue num 200 bypass
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp dport "{5001}" queue num 200 bypass
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport "{5001}" queue num 200 bypass
-- iperf -i 1 -c endpoint2
-- endpoint2:
-- --filter-icmp=0,8,128,129 --filter-ipp=193,198,209,250 --filter-tcp=* --filter-udp=* --in-range=a --lua-desync=ippxor:xor=192:dataxor=0xABCD --server
-- --filter-icmp=0,8,128,129 --filter-ipp=193,198,209,250 --filter-tcp=* --filter-udp=* --in-range=a --lua-desync=ippxor:ippxor=192:dataxor=0xABCD --server
-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto {193, 198, 209, 250} queue num 200 bypass
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 tcp sport "{5001}" queue num 200 bypass
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp sport "{5001}" queue num 200 bypass
@@ -173,9 +173,16 @@ end
-- arg : scode - server icmp code
-- arg : dataxor - blob to xor udp payload
-- arg : server=[0|1] - override server mode. by default use "--server" nfqws2 parameter
-- arg : cgnat - do not rely on identifier - cgnat in most cases changes it. expand udp packet size by 2 (may exceed MTU !)
-- arg : id_lifetime - mapped identifiers lifetime in seconds
function udp2icmp(ctx, desync)
local dataxor
local bserver = desync.arg.server and (desync.arg.server~="0") or b_server
local bserver
if desync.arg.server then
bserver = desync.arg.server~="0"
else
bserver = b_server
end
local function one_byte_arg(name)
if desync.arg[name] then
@@ -216,6 +223,25 @@ function udp2icmp(ctx, desync)
desync.dis.payload = bxor(desync.dis.payload, pattern(dataxor,1,#desync.dis.payload))
end
end
local function map_purge()
if udp2icmp_map then
local last = udp2icmp_map.purge or 0
local now = os.time()
local timeout = desync.arg.id_lifetime and tonumber(desync.arg.id_lifetime) or 60
if last~=now then
for k,v in pairs(udp2icmp_map) do
if type(v)=='table' and v.t then
if now>=(v.t + timeout) then
udp2icmp_map[k] = nil
end
end
end
udp2icmp_map.purge=now
end
end
end
map_purge()
if desync.arg.dataxor then
dataxor = blob(desync,desync.arg.dataxor)
@@ -229,19 +255,63 @@ function udp2icmp(ctx, desync)
if b_debug then -- save some cpu
DLOG("udp2icmp: udp => icmp sport="..desync.dis.udp.uh_sport.." dport="..desync.dis.udp.uh_dport.." size="..#desync.dis.payload)
end
local id = bitxor(desync.dis.udp.uh_sport,desync.dis.udp.uh_dport)
if desync.arg.cgnat then
if bserver then
-- extract original icmp identifier from the map. it must match original or NAT will not deliver
local map_id = (desync.dis.ip6 and desync.dis.ip6.ip6_dst or desync.dis.ip.ip_dst)..
(desync.dis.ip6 and desync.dis.ip6.ip6_src or desync.dis.ip.ip_src)..
bu16(desync.dis.udp.uh_dport)..bu16(desync.dis.udp.uh_sport)
if udp2icmp_map then
local id_ = udp2icmp_map[map_id]
if id_ then
id=id_.id
if b_debug then DLOG(string.format("udp2icmp: found mapped icmp identifier %04X",id)) end
id_.t=os.time() -- update time
else
DLOG("udp2icmp: mapped icmp identifier NOT found !")
end
end
else
-- cgnat changes identifier. save it in the end of the packet, expand packet size by 2
desync.dis.payload = desync.dis.payload .. bu16(id)
DLOG("udp2icmp: expanding udp size to "..#desync.dis.payload)
end
end
desync.dis.icmp = {
icmp_type = ictype(true),
icmp_code = iccode(true),
icmp_data = u32(
bu16(bitxor(desync.dis.udp.uh_sport,desync.dis.udp.uh_dport))..
(bserver and bu16(desync.dis.udp.uh_sport) or bu16(desync.dis.udp.uh_dport)))
icmp_data = u32(bu16(id)..(bserver and bu16(desync.dis.udp.uh_sport) or bu16(desync.dis.udp.uh_dport)))
}
desync.dis.udp = nil
fix_ip_proto(desync.dis)
return VERDICT_MODIFY
elseif desync.dis.icmp and desync.dis.icmp.icmp_type==ictype(false) and desync.dis.icmp.icmp_code==iccode(false) then
local pl = bitand(desync.dis.icmp.icmp_data,0xFFFF)
local pm = bitxor(bitrshift(desync.dis.icmp.icmp_data,16),pl)
local pm
local id = bitrshift(desync.dis.icmp.icmp_data,16)
if bserver and desync.arg.cgnat then
if #desync.dis.payload<2 then
DLOG("udp2icmp: udp is less than 2 bytes and cgnat is on ! doing nothing")
return VERDICT_PASS
end
if not udp2icmp_map then udp2icmp_map={} end
pm = bitxor(u16(desync.dis.payload,#desync.dis.payload-1),pl) -- use right 2 bytes
desync.dis.payload = string.sub(desync.dis.payload,1,-3) -- shrink right 2 bytes
DLOG("udp2icmp: shrinking udp size to "..#desync.dis.payload)
-- keep original icmp identifier indexed by ip/port tuple
local map_id = (desync.dis.ip6 and desync.dis.ip6.ip6_src or desync.dis.ip.ip_src)..
(desync.dis.ip6 and desync.dis.ip6.ip6_dst or desync.dis.ip.ip_dst)..
bu16(pm)..bu16(pl)
udp2icmp_map[map_id] = { id=id, t=os.time() }
if b_debug then DLOG(string.format("udp2icmp: stored mapped icmp identifier %04X",id)) end
else
pm = bitxor(id,pl)
end
desync.dis.udp = {
uh_sport = bserver and pm or pl,
uh_dport = bserver and pl or pm,
@@ -424,7 +494,7 @@ function synhide(ctx, desync)
if fl==TH_SYN then
-- client sent
local ttl = tonumber(desync.dis.ip and desync.arg.ghost or desync.arg.ghost6)
local ttl = tonumber(desync.dis.ip and desync.arg.ghost or (desync.dis.ip6 and desync.arg.ghost6))
if ttl then
DLOG("synhide: punch NAT hole with ttl="..ttl)
local dis = deepcopy(desync.dis)
+8 -7
View File
@@ -1,6 +1,6 @@
function pcap_write_header(file)
-- big endian, nanoseconds in timestamps, ver 2.4, max packet size - 0x4000 (16384), 0x65 - l3 packets without l2
file:write("\xA1\xB2\x3C\x4D\x00\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x40\x00\x00\x00\x00\x65")
-- big endian, nanoseconds in timestamps, ver 2.4, max packet size - 0xFFFF (65535), 0x65 - l3 packets without l2
file:write("\xA1\xB2\x3C\x4D\x00\x02\x00\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xFF\xFF\x00\x00\x00\x65")
end
function pcap_write_packet(file, raw)
local sec, nsec = clock_gettime();
@@ -8,15 +8,15 @@ function pcap_write_packet(file, raw)
file:write(raw)
end
function pcap_write(file, raw)
local pos = file:seek()
local pos = file:seek('end')
if (pos==0) then
pcap_write_header(file)
end
pcap_write_packet(file, raw)
end
-- test case : --writeable=zdir --in-range=a --lua-desync=pcap:file=test.pcap
-- arg : file=<filename> - file for storing pcap data. if --writeable is specified and filename is relative - append filename to writeable path
-- test case : --writable=zdir --in-range=a --lua-desync=pcap:file=test.pcap
-- arg : file=<filename> - file for storing pcap data. if --writable is specified and filename is relative - append filename to writable path
-- arg : keep - do not overwrite file, append packets to existing
function pcap(ctx, desync)
if not desync.arg.file or #desync.arg.file==0 then
@@ -24,7 +24,7 @@ function pcap(ctx, desync)
end
local fn_cache_name = desync.func_instance.."_fn"
if not _G[fn_cache_name] then
_G[fn_cache_name] = writeable_file_name(desync.arg.file)
_G[fn_cache_name] = writable_file_name(desync.arg.file)
if not desync.arg.keep then
-- overwrite file
os.remove(_G[fn_cache_name])
@@ -34,6 +34,7 @@ function pcap(ctx, desync)
if not f then
error("pcap: could not write to '".._G[fn_cache_name].."'")
end
pcap_write(f, raw_packet(ctx))
local raw = ctx and raw_packet(ctx) or reconstruct_dissect(desync.dis)
pcap_write(f, raw)
f:close()
end
+110 -23
View File
@@ -14,8 +14,8 @@ end
function test_all(...)
test_run({
test_crypto, test_bin, test_gzip, test_ipstr, test_dissect, test_csum, test_resolve,
test_get_source_ip, test_ifaddrs, test_rawsend},...)
test_crypto, test_bin, test_time, test_gzip, test_ipstr, test_dissect, test_csum, test_resolve,
test_get_source_ip, test_ifaddrs, test_rawsend, test_timer},...)
end
@@ -90,10 +90,9 @@ function test_hkdf()
local ikm = brandom(math.random(5,10))
for ninfo=1,nblob do
local info = brandom(math.random(5,10))
local okm_prev
for k,sha in pairs({"sha256","sha224"}) do
for k,okml in pairs({8, 16, 50}) do
local okm_prev
for k,okml in pairs({8, 16, 50}) do
local okm
print("* hkdf "..sha)
print("salt: "..string2hex(salt))
@@ -107,7 +106,6 @@ function test_hkdf()
print("duplicate okm !")
end
okms[okm] = true
test_assert(not okm_prev or okm_prev==string.sub(okm, 1, #okm_prev))
okm_prev = okm
end
@@ -121,7 +119,7 @@ function test_aes()
print("* aes")
local clear_text="test "..brandom_az09(11)
local iv, key, encrypted, decrypted
local encrypted, decrypted
for key_size=16,32,8 do
local key = brandom(key_size)
@@ -415,6 +413,42 @@ function test_bin(...)
test_run({test_ub, test_bit, test_swap, test_ux},...)
end
function test_time(...)
print("* time")
local unixtime=os.time()
local tm = localtime(unixtime);
local t
print()
print("now: "..tm.str.." "..tm.zone.." = "..unixtime)
local tm = gmtime(unixtime);
print("gmt: "..tm.str.." "..tm.zone.." = "..unixtime)
print()
for i=1,20 do
unixtime = math.random(0,0x7FFFFFFF);
tm = localtime(unixtime);
t = timelocal(tm)
print("timelocal: "..tm.str.." "..tm.zone.." = "..t)
print( t==unixtime and "LOCALTIME OK" or "LOCALTIME FAILED" )
test_assert(t==unixtime)
unixtime = math.random(0,0x7FFFFFFF);
tm = gmtime(unixtime);
t = timegm(tm)
print("timegm: "..tm.str.." "..tm.zone.." = "..t)
print( t==unixtime and "GMTIME OK" or "GMTIME FAILED" )
test_assert(t==unixtime)
end
unixtime = math.random(0x80000000,0xFFFFFFFF);
tm = gmtime(unixtime)
t = timegm(tm)
print( t==unixtime and "TIME 0x80000000..0xFFFFFFFF OK" or "TIME 0x80000000..0xFFFFFFFF FAILED : "..unixtime.." != "..t.." ("..tm.str..")" )
unixtime = math.random(0x100000000,0x200000000);
tm = gmtime(unixtime)
t = timegm(tm)
print( t==unixtime and "TIME 64 OK" or "TIME 64 FAILED : "..unixtime.." != "..t.." ("..tm.str..")" )
end
function test_gzip()
print("* gzip")
@@ -473,7 +507,7 @@ end
function test_dissect()
print("* dissect")
local dis, raw1, raw2
local raw1, raw2
for i=1,20 do
print("* dissect test "..tostring(i))
@@ -502,8 +536,7 @@ function test_dissect()
{ kind = 1 },
{ kind = 0xE0, data = brandom(math.random(1,10)) },
{ kind = 1 },
{ kind = 0xE1, data = brandom(math.random(1,10)) },
{ kind = 0 }
{ kind = 0xE1, data = brandom(math.random(1,10)) }
}
},
payload = brandom(math.random(0, 20))
@@ -577,7 +610,7 @@ function test_dissect()
},
payload = brandom(math.random(0, 20))
}
raw1 = reconstruct_dissect(ip6_udp)
print("IP6+UDP : "..string2hex(raw1))
dis1 = dissect(raw1)
@@ -670,8 +703,7 @@ function test_csum()
{ kind = 1 },
{ kind = 0xE0, data = brandom(math.random(1,10)) },
{ kind = 1 },
{ kind = 0xE1, data = brandom(math.random(1,10)) },
{ kind = 0 }
{ kind = 0xE1, data = brandom(math.random(1,10)) }
}
}
tcpb = reconstruct_tcphdr(tcp)
@@ -687,14 +719,15 @@ function test_csum()
bu8(tcp.options[1].kind)..
bu8(tcp.options[2].kind)..bu8(2 + #tcp.options[2].data)..tcp.options[2].data ..
bu8(tcp.options[3].kind)..
bu8(tcp.options[4].kind)..bu8(2 + #tcp.options[4].data)..tcp.options[4].data ..
bu8(tcp.options[5].kind)
raw = raw .. string.rep(bu8(TCP_KIND_NOOP), bitand(4-bitand(#raw,3),3))
bu8(tcp.options[4].kind)..bu8(2 + #tcp.options[4].data)..tcp.options[4].data
raw = raw .. string.rep(bu8(0), bitand(4-bitand(#raw,3),3))
print( raw==tcpb and "TCP RECONSTRUCT OK" or "TCP RECONSTRUCT FAILED" )
test_assert(raw==tcpb)
raw = reconstruct_dissect({ip=ip, tcp=tcp, payload=payload})
dis1 = dissect(raw)
ip.ip_len = IP_BASE_LEN + #ip.options + #tcpb + #payload
ip4b = reconstruct_iphdr(ip)
tcpb = csum_tcp_fix(ip4b,tcpb,payload)
dis2 = dissect(ip4b..tcpb..payload)
print( dis1.tcp.th_sum==dis2.tcp.th_sum and "TCP+IP4 CSUM OK" or "TCP+IP4 CSUM FAILED" )
@@ -736,11 +769,6 @@ function test_csum()
uh_ulen = UDP_BASE_LEN + #payload
}
ip.ip_p = IPPROTO_UDP
ip4b = reconstruct_iphdr(ip)
ip6.ip6_plen = packet_len({ip6=ip6,udp=udp,payload=payload}) - IP6_BASE_LEN
ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_UDP})
udpb = reconstruct_udphdr(udp)
raw = bu16(udp.uh_sport) ..
bu16(udp.uh_dport) ..
@@ -749,13 +777,19 @@ function test_csum()
print( raw==udpb and "UDP RECONSTRUCT OK" or "UDP RECONSTRUCT FAILED" )
test_assert(raw==udpb)
ip.ip_p = IPPROTO_UDP
raw = reconstruct_dissect({ip=ip, udp=udp, payload=payload})
dis1 = dissect(raw)
ip.ip_p = IPPROTO_UDP
ip.ip_len = IP_BASE_LEN + #ip.options + #udpb + #payload
ip4b = reconstruct_iphdr(ip)
udpb = csum_udp_fix(ip4b,udpb,payload)
dis2 = dissect(ip4b..udpb..payload)
print( dis1.udp.uh_sum==dis2.udp.uh_sum and "UDP+IP4 CSUM OK" or "UDP+IP4 CSUM FAILED" )
test_assert(dis1.udp.uh_sum==dis2.udp.uh_sum)
ip6.ip6_plen = packet_len({ip6=ip6,udp=udp,payload=payload}) - IP6_BASE_LEN
ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_UDP})
raw = reconstruct_dissect({ip6=ip6, udp=udp, payload=payload})
dis1 = dissect(raw)
udpb = csum_udp_fix(ip6b,udpb,payload)
@@ -870,6 +904,61 @@ function test_ifaddrs(opts)
end
end
function print_current_time()
local sec,nsec = clock_gettime()
local t = sec + nsec/1000000000;
print("time: "..t)
end
function timer_info_print(tinfo)
print(" timer_info.name="..tinfo.name)
print(" timer_info.period="..tinfo.period)
print(" timer_info.oneshot="..tostring(tinfo.oneshot))
print(" timer_info.fires="..tinfo.fires)
end
function timer_info_print_by_name(name)
local tinfo = timer_info(name)
timer_info_print(tinfo)
end
function timer1(name, data)
print("timer "..name.." fired. data="..tostring(data))
print_current_time()
timer_info_print_by_name(name)
end
function timer2(name, data)
data.n = data.n+1
print("timer "..name.." fired. data.n="..tostring(data.n))
print_current_time()
timer_info_print_by_name(name)
if data.n>=4 then
timer_del(name)
end
end
function test_timer(opts)
-- anonymous function
timer_set("t0",function(name,data)
print("timer "..name.." fired. anonymous timer function")
print_current_time()
end,
100,true)
-- pass function as function
timer_set("t1",timer1,500,true,"sample_data");
local tbl = {n=0}
-- pass function through string name
timer_set("t2","timer2",700,false,tbl);
print("* timers\n")
local timers=timer_enum()
for i,name in ipairs(timers) do
print("TIMER "..i.." :")
timer_info_print_by_name(name)
end
print_current_time()
print()
end
function test_rawsend(opts)
print("* rawsend")
@@ -911,7 +1000,6 @@ function test_rawsend(opts)
end
local ip, ip6, udp, dis, ddis, raw_ip, raw_udp, raw
local payload = brandom(math.random(100,1200))
local b
local target
for ifname,ifinfo in pairs(get_ifaddrs()) do
@@ -959,7 +1047,6 @@ function test_rawsend(opts)
print("send ipv4 udp using pure rawsend without dissect")
test_assert(rawsend_print(raw, {repeats=5}))
local target
for ifname,ifinfo in pairs(get_ifaddrs()) do
for k,v in pairs(ifinfo.addr) do
if #v.addr==16 and (string.sub(v.addr,1,1)=="\xFC" or string.sub(v.addr,1,1)=="\xFD") then
@@ -1045,7 +1132,7 @@ function test_rawsend(opts)
print("send ipv6 icmp")
test_assert(rawsend_dissect_print(dis, {fwmark = 0x8E10, repeats=3}))
local ip2 = {
ip2 = {
ip_tos = 0,
ip_id = math.random(0,0xFFFF),
ip_off = 0,
+12 -7
View File
@@ -1,35 +1,40 @@
CC ?= cc
OPTIMIZE ?= -Os
CFLAGS_PIC = -fPIC
CFLAGS += -std=gnu99 $(OPTIMIZE)
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_WIN = -static
LDFLAGS_PIE = -pie
LIBS = -lpthread
LIBS_ANDROID =
LIBS_WIN = -lws2_32
LIBS_WIN = -lws2_32 -lpthread
SRC_FILES = *.c
all: mdig
mdig: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o mdig $(SRC_FILES) $(LIBS) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_PIC) -o mdig $(SRC_FILES) $(LIBS) $(LDFLAGS) $(LDFLAGS_PIE)
systemd: mdig
android: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o mdig $(SRC_FILES) $(LIBS_ANDROID) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_PIC) -o mdig $(SRC_FILES) $(LIBS_ANDROID) $(LDFLAGS) $(LDFLAGS_PIE)
bsd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_BSD) -o mdig $(SRC_FILES) $(LIBS) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_PIC) $(CFLAGS_BSD) -o mdig $(SRC_FILES) $(LIBS) $(LDFLAGS) $(LDFLAGS_PIE)
mac: $(SRC_FILES)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -o mdiga $(SRC_FILES) -target arm64-apple-macos10.8 $(LIBS_BSD) $(LDFLAGS)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -o mdigx $(SRC_FILES) -target x86_64-apple-macos10.8 $(LIBS_BSD) $(LDFLAGS)
$(CC) $(CFLAGS) $(CFLAGS_PIC) $(CFLAGS_BSD) -o mdiga $(SRC_FILES) -target arm64-apple-macos10.8 $(LIBS_BSD) $(LDFLAGS) $(LDFLAGS_PIE)
$(CC) $(CFLAGS) $(CFLAGS_PIC) $(CFLAGS_BSD) -o mdigx $(SRC_FILES) -target x86_64-apple-macos10.8 $(LIBS_BSD) $(LDFLAGS) $(LDFLAGS_PIE)
strip mdiga mdigx
lipo -create -output mdig mdigx mdiga
rm -f mdigx mdiga
win: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_WIN) -o mdig $(SRC_FILES) $(LIBS_WIN) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_WIN) -o mdig.exe $(SRC_FILES) $(LIBS_WIN) $(LDFLAGS)
win-arm64-cross:
clang -s $(CFLAGS) $(CFLAGS_WIN) --sysroot=/clangarm64 --target=aarch64-w64-mingw32 -B/clang64/bin -rtlib=compiler-rt -o mdig.exe $(SRC_FILES) $(LIBS_WIN) $(LDFLAGS)
clean:
rm -f mdig *.o
+1 -1
View File
@@ -220,7 +220,7 @@ static void *t_resolver(void *arg)
{
if ((family == AF_INET && (glob.family & FAMILY4)) || (family == AF_INET6 && (glob.family & FAMILY6)))
{
unsigned int mask;
unsigned int mask=0;
bool mask_needed = false;
if (s_mask)
{
+8 -3
View File
@@ -1,7 +1,12 @@
CC ?= cc
PKG_CONFIG ?= pkg-config
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 -s $(OPTIMIZE) -flto=auto -Wno-address-of-packed-member
OPTIMIZE ?= -Oz
MINSIZE ?= -flto=auto -ffunction-sections -fdata-sections
STRIPP = -s
CFLAGS_PIC = -fPIC
CFLAGS += -std=gnu99 $(OPTIMIZE) $(MINSIZE) $(CFLAGS_PIC) -Wno-address-of-packed-member
LDFLAGS_PIE = -pie
LDFLAGS += -flto=auto -Wl,--gc-sections $(LDFLAGS_PIE)
LIBS = -lz -lm
SRC_FILES = *.c crypto/*.c
@@ -37,7 +42,7 @@ LUA_CFLAGS+=-DLUAJIT
all: dvtws2
dvtws2: $(SRC_FILES)
$(CC) $(CFLAGS) $(LUA_CFLAGS) -o dvtws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LDFLAGS)
$(CC) $(STRIPP) $(CFLAGS) $(LUA_CFLAGS) -o dvtws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LDFLAGS)
clean:
rm -f dvtws2
+24 -11
View File
@@ -1,17 +1,26 @@
CC ?= cc
PKG_CONFIG ?= pkg-config
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
CFLAGS_LINUX = -Wno-alloc-size-larger-than
MINSIZE ?= -flto=auto -ffunction-sections -fdata-sections
CFLAGS += -std=gnu99 $(OPTIMIZE) $(MINSIZE)
CFLAGS_PIC = -fPIC
CFLAGS_LINUX = -Wno-alloc-size-larger-than $(CFLAGS_PIC)
CFLAGS_SYSTEMD = -DUSE_SYSTEMD
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
CFLAGS_BSD = -Wno-address-of-packed-member $(CFLAGS_PIC)
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static -Wl,--nxcompat
CFLAGS_CYGWIN32 =
CFLAGS_CYGWIN64 = -Wl,--dynamicbase -Wl,--high-entropy-va
CFLAGS_UBSAN = -fsanitize=undefined,alignment -fno-sanitize-recover=undefined,alignment
LDFLAGS_PIE = -pie
LDFLAGS += -flto=auto -Wl,--gc-sections $(LDFLAGS_PIE)
LDFLAGS_ANDROID = -llog
LDFLAGS_CYGWIN = -Wl,--build-id=none
STRIPP=-s
LIBS =
LIBS_LINUX = -lz -lnetfilter_queue -lnfnetlink -lmnl -lm
LIBS_SYSTEMD = -lsystemd
LIBS_BSD = -lz -lm
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32 -liphlpapi -lntdll
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lole32 -loleaut32 -liphlpapi -lntdll
LIBS_CYGWIN32 = -lwindivert32
LIBS_CYGWIN64 = -lwindivert64
RES_CYGWIN32 = windows/res/winws_res32.o
@@ -26,6 +35,7 @@ ifeq ($(LUA_JIT),1)
LUAJIT_VER?=2.1
LUAJIT_LUA_VER?=5.1
LUA_PKG:=luajit
CFLAGS_CYGWIN32 = -msse2 -mfpmath=sse
$(info trying luajit $(LUAJIT_VER) lua $(LUAJIT_LUA_VER))
@@ -133,21 +143,24 @@ LUA_CFL += $(LUA_CFLAGS)
all: nfqws2
nfqws2: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(LUA_CFL) $(CFLAGS_LINUX) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LDFLAGS)
$(CC) $(STRIPP) $(CFLAGS) $(LUA_CFL) $(CFLAGS_LINUX) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LDFLAGS)
ubsan: $(SRC_FILES)
$(CC) $(CFLAGS_UBSAN) $(CFLAGS) $(LUA_CFL) $(CFLAGS_LINUX) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LDFLAGS)
systemd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(LUA_CFL) $(CFLAGS_LINUX) $(CFLAGS_SYSTEMD) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LIBS_SYSTEMD) $(LDFLAGS)
$(CC) $(STRIPP) $(CFLAGS) $(LUA_CFL) $(CFLAGS_LINUX) $(CFLAGS_SYSTEMD) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LIBS_SYSTEMD) $(LDFLAGS)
android: $(SRC_FILES_ANDROID)
$(CC) -s $(CFLAGS) $(LUA_CFL) -o nfqws2 $(SRC_FILES_ANDROID) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LDFLAGS) $(LDFLAGS_ANDROID)
$(CC) $(STRIPP) $(CFLAGS) $(LUA_CFL) -o nfqws2 $(SRC_FILES_ANDROID) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LDFLAGS) $(LDFLAGS_ANDROID)
bsd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(LUA_CFL) $(CFLAGS_BSD) -o dvtws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_BSD) $(LDFLAGS)
$(CC) $(STRIPP) $(CFLAGS) $(LUA_CFL) $(CFLAGS_BSD) -o dvtws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_BSD) $(LDFLAGS)
cygwin64:
$(CC) -s $(CFLAGS) $(LUA_CFL) $(CFLAGS_CYGWIN) -o winws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_CYGWIN) $(LIBS_CYGWIN64) $(RES_CYGWIN64) $(LDFLAGS)
$(CC) $(STRIPP) $(CFLAGS) $(LUA_CFL) $(CFLAGS_CYGWIN) $(CFLAGS_CYGWIN64) -o winws2 $(SRC_FILES) $(RES_CYGWIN64) $(LIBS) $(LUA_LIB) $(LIBS_CYGWIN) $(LIBS_CYGWIN64) $(LDFLAGS) $(LDFLAGS_CYGWIN)
cygwin32:
$(CC) -s $(CFLAGS) $(LUA_CFL) $(CFLAGS_CYGWIN) -o winws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_CYGWIN) $(LIBS_CYGWIN32) $(RES_CYGWIN32) $(LDFLAGS)
$(CC) $(STRIPP) $(CFLAGS) $(LUA_CFL) $(CFLAGS_CYGWIN) $(CFLAGS_CYGWIN32) -o winws2 $(SRC_FILES) $(RES_CYGWIN32) $(LIBS) $(LUA_LIB) $(LIBS_CYGWIN) $(LIBS_CYGWIN32) $(LDFLAGS) $(LDFLAGS_CYGWIN)
cygwin: cygwin64
clean:
+4 -4
View File
@@ -72,13 +72,13 @@ static uint16_t do_csum(const uint8_t *buff, size_t len)
}
if (len & 4)
{
result += *(uint32_t *)buff;
result += *(const uint32_t *)buff;
buff += 4;
}
}
if (len & 2)
{
result += *(uint16_t *)buff;
result += *(const uint16_t *)buff;
buff += 2;
}
}
@@ -115,8 +115,8 @@ void ip4_fix_checksum(struct ip *ip)
uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum)
{
uint64_t a = (uint64_t)sum + htonl(len + proto) +
*(uint32_t *)saddr + *((uint32_t *)saddr + 1) + *((uint32_t *)saddr + 2) + *((uint32_t *)saddr + 3) +
*(uint32_t *)daddr + *((uint32_t *)daddr + 1) + *((uint32_t *)daddr + 2) + *((uint32_t *)daddr + 3);
*(const uint32_t *)saddr + *((const uint32_t *)saddr + 1) + *((const uint32_t *)saddr + 2) + *((const uint32_t *)saddr + 3) +
*(const uint32_t *)daddr + *((const uint32_t *)daddr + 1) + *((const uint32_t *)daddr + 2) + *((const uint32_t *)daddr + 3);
return ~from64to16(a);
}
+4 -4
View File
@@ -19,10 +19,10 @@ struct icmp46
uint16_t icmp_cksum;
union
{
uint32_t icmp_data32;
uint16_t icmp_data16[2];
uint8_t icmp_data8[4];
};
uint32_t data32;
uint16_t data16[2];
uint8_t data8[4];
} data;
};
uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum);
+18 -24
View File
@@ -104,8 +104,9 @@ static void ConntrackInitTrack(t_ctrack *t)
{
memset(t, 0, sizeof(*t));
t->l7proto = L7_UNKNOWN;
t->reasm_client_payload = L7P_UNKNOWN;
t->pos.client.scale = t->pos.server.scale = 0;
rawpacket_queue_init(&t->delayed);
rawpacket_queue_init(&t->delayed, RAW_PACKET_QUEUE_DELAYED_MAX);
lua_newtable(params.L);
t->lua_state = luaL_ref(params.L, LUA_REGISTRYINDEX);
lua_newtable(params.L);
@@ -140,8 +141,17 @@ static void ConntrackApplyPos(t_ctrack *t, bool bReverse, const struct dissect *
if (dis->ip6) direct->ip6flow = ntohl(dis->ip6->ip6_ctlun.ip6_un1.ip6_un1_flow);
scale = tcp_find_scale_factor(dis->tcp);
mss = tcp_find_mss(dis->tcp);
direct->winsize_calc = direct->winsize = ntohs(dis->tcp->th_win);
if (t->pos.state == SYN)
{
// scale and mss only valid in syn packets
scale = tcp_find_scale_factor(dis->tcp);
if (scale != SCALE_NONE) direct->scale = scale<14 ? scale : 14; // RFC7323 hard limit
direct->mss = tcp_find_mss(dis->tcp);
}
else
// apply scale only outside of the SYN stage
direct->winsize_calc <<= direct->scale;
direct->seq_last = ntohl(dis->tcp->th_seq);
direct->pos = direct->seq_last + dis->len_payload;
@@ -154,10 +164,6 @@ static void ConntrackApplyPos(t_ctrack *t, bool bReverse, const struct dissect *
if (!((direct->pos - direct->uppos) & 0x80000000))
direct->uppos = direct->pos;
}
direct->winsize_calc = direct->winsize = ntohs(dis->tcp->th_win);
if (scale != SCALE_NONE) direct->scale = scale;
if (direct->scale != SCALE_NONE) direct->winsize_calc <<= direct->scale;
if (mss && !direct->mss) direct->mss = mss;
if (!direct->rseq_over_2G && ((direct->seq_last - direct->seq0) & 0x80000000))
direct->rseq_over_2G = true;
@@ -167,9 +173,6 @@ static void ConntrackApplyPos(t_ctrack *t, bool bReverse, const struct dissect *
static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct dissect *dis)
{
uint8_t scale;
uint16_t mss;
if (bReverse)
{
t->pos.server.pcounter++;
@@ -283,7 +286,7 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct dissect *d
}
return false;
ok:
ctr->track.ipproto = proto;
ctr->track.pos.ipproto = proto;
if (ctrack) *ctrack = &ctr->track;
if (bReverse) *bReverse = b_rev;
return true;
@@ -347,13 +350,13 @@ void ConntrackPoolDump(const t_conntrack *p)
{
t_conntrack_pool *t, *tmp;
time_t tnow;
char sa1[40], sa2[40];
char sa1[INET6_ADDRSTRLEN], sa2[INET6_ADDRSTRLEN];
if (!(tnow=boottime())) 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 client=d%llu/n%llu/b%llu server=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%llu ",
proto_name(t->conn.l4proto),
sa1, t->conn.sport, sa2, t->conn.dport,
t->conn.l4proto == IPPROTO_TCP ? connstate_s[t->track.pos.state] : "-",
@@ -365,8 +368,8 @@ void ConntrackPoolDump(const t_conntrack *p)
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);
t->track.pos.client.winsize, t->track.pos.client.scale,
t->track.pos.server.winsize, t->track.pos.server.scale);
else
printf("rseq=%u client.pos=%u rack=%u server.pos=%u",
t->track.pos.client.seq_last, t->track.pos.client.pos,
@@ -392,15 +395,6 @@ bool ReasmInit(t_reassemble *reasm, size_t size_requested, uint32_t seq_start)
reasm->seq = seq_start;
return true;
}
bool ReasmResize(t_reassemble *reasm, size_t new_size)
{
uint8_t *p = realloc(reasm->packet, new_size);
if (!p) return false;
reasm->packet = p;
reasm->size = 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)
{
+4 -2
View File
@@ -29,6 +29,8 @@
#define RETRANS_COUNTER_STOP ((uint8_t)-1)
#define RAW_PACKET_QUEUE_DELAYED_MAX 64
typedef union {
struct in_addr ip;
struct in6_addr ip6;
@@ -53,7 +55,6 @@ typedef struct {
typedef struct
{
bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache
uint8_t ipproto;
struct timespec t_start;
@@ -81,8 +82,9 @@ 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_l7payload reasm_client_payload; // payload type being reassembled
t_reassemble reasm_client;
struct rawpacket_tailhead delayed;
struct rawpacket_queue delayed;
} t_ctrack;
typedef struct
+4 -3
View File
@@ -21,15 +21,15 @@ typedef struct
uint32_t ip6flow;
// tcp only state, not used in udp
uint32_t pos; // TCP: seq_last+payload, ack_last+payload UDP: sum of all seen payload lenghts including current
uint32_t pos; // seq_last+payload, ack_last+payload
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
uint32_t seq_last; // last seen seq and ack
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
uint8_t scale; // last seen window scale factor
bool rseq_over_2G;
} t_ctrack_position;
@@ -38,5 +38,6 @@ typedef struct
struct timespec t_last;
t_connstate state;
t_ctrack_position client, server;
uint8_t ipproto;
}
t_ctrack_positions;
+18 -9
View File
@@ -391,7 +391,9 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
uint64_t orig_add_len = ctx->add_len * 8;
size_t i;
if (tag_len != 0) memcpy(tag, ctx->base_ectr, tag_len);
if (tag_len>16) return -1;
if (tag_len) memcpy(tag, ctx->base_ectr, tag_len);
if (orig_len || orig_add_len) {
memset(work_buf, 0x00, 16);
@@ -443,10 +445,12 @@ int gcm_crypt_and_tag(
prepare the gcm context with the keying material, we simply
invoke each of the three GCM sub-functions in turn...
*/
gcm_start(ctx, mode, iv, iv_len, add, add_len);
gcm_update(ctx, length, input, output);
gcm_finish(ctx, tag, tag_len);
return(0);
if (tag_len>16) return -1;
int ret;
if ((ret=gcm_start(ctx, mode, iv, iv_len, add, add_len))) return ret;
if ((ret=gcm_update(ctx, length, input, output))) return ret;
return gcm_finish(ctx, tag, tag_len);
}
@@ -477,23 +481,28 @@ int gcm_auth_decrypt(
uchar check_tag[16]; // the tag generated and returned by decryption
int diff; // an ORed flag to detect authentication errors
size_t i; // our local iterator
int ret;
if (tag_len>16) return -1;
/*
we use GCM_DECRYPT_AND_TAG (above) to perform our decryption
(which is an identical XORing to reverse the previous one)
and also to re-generate the matching authentication tag
*/
gcm_crypt_and_tag(ctx, AES_DECRYPT, iv, iv_len, add, add_len,
input, output, length, check_tag, tag_len);
if ((ret = gcm_crypt_and_tag(ctx, AES_DECRYPT, iv, iv_len, add, add_len, input, output, length, check_tag, tag_len))) return ret;
// now we verify the authentication tag in 'constant time'
for (diff = 0, i = 0; i < tag_len; i++)
diff |= tag[i] ^ check_tag[i];
if (diff != 0) { // see whether any bits differed?
if (diff)
{
// see whether any bits differed?
memset(output, 0, length); // if so... wipe the output data
return(GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
}
return(0);
return 0;
}
/******************************************************************************
-1
View File
@@ -29,7 +29,6 @@
#if defined(_MSC_VER)
#include <basetsd.h>
typedef unsigned int size_t;// use the right type for length declarations
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;
#else
+11 -12
View File
@@ -60,9 +60,9 @@ int hkdf(SHAversion whichSha,
uint8_t okm[], size_t okm_len)
{
uint8_t prk[USHAMaxHashSize];
return hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk) ||
hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info,
info_len, okm, okm_len);
int ret;
if ((ret=hkdfExtract(whichSha, salt, salt_len, ikm, ikm_len, prk))) return ret;
return hkdfExpand(whichSha, prk, USHAHashSize(whichSha), info, info_len, okm, okm_len);
}
/*
@@ -146,6 +146,7 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
size_t hash_len, N;
unsigned char T[USHAMaxHashSize];
size_t Tlen, where, i;
int ret;
if (info == 0) {
info = (const unsigned char *)"";
@@ -164,12 +165,11 @@ int hkdfExpand(SHAversion whichSha, const uint8_t prk[], size_t prk_len,
for (i = 1; i <= N; i++) {
HMACContext context;
unsigned char c = i;
int ret = hmacReset(&context, whichSha, prk, prk_len) ||
hmacInput(&context, T, Tlen) ||
hmacInput(&context, info, info_len) ||
hmacInput(&context, &c, 1) ||
hmacResult(&context, T);
if (ret != shaSuccess) return ret;
if ((ret=hmacReset(&context, whichSha, prk, prk_len))) return ret;
if ((ret=hmacInput(&context, T, Tlen))) return ret;
if ((ret=hmacInput(&context, info, info_len))) return ret;
if ((ret=hmacInput(&context, &c, 1))) return ret;
if ((ret=hmacResult(&context, T))) return ret;
memcpy(okm + where, T,
(i != N) ? hash_len : (okm_len - where));
where += hash_len;
@@ -321,9 +321,8 @@ int hkdfResult(HKDFContext *context,
if (!okm) return context->Corrupted = shaBadParam;
if (!prk) prk = prkbuf;
ret = hmacResult(&context->hmacContext, prk) ||
hkdfExpand(context->whichSha, prk, context->hashSize, info,
info_len, okm, okm_len);
if (!(ret = hmacResult(&context->hmacContext, prk)))
ret = hkdfExpand(context->whichSha, prk, context->hashSize, info, info_len, okm, okm_len);
context->Computed = 1;
return context->Corrupted = ret;
}
+14 -21
View File
@@ -49,9 +49,10 @@ int hmac(SHAversion whichSha,
uint8_t digest[USHAMaxHashSize])
{
HMACContext context;
return hmacReset(&context, whichSha, key, key_len) ||
hmacInput(&context, message_array, length) ||
hmacResult(&context, digest);
int ret;
if ((ret=hmacReset(&context, whichSha, key, key_len))) return ret;
if ((ret=hmacInput(&context, message_array, length))) return ret;
return hmacResult(&context, digest);
}
/*
@@ -101,10 +102,8 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
*/
if (key_len > blocksize) {
USHAContext tcontext;
int err = USHAReset(&tcontext, whichSha) ||
USHAInput(&tcontext, key, key_len) ||
USHAResult(&tcontext, tempkey);
if (err != shaSuccess) return err;
if ((ret=USHAReset(&tcontext, whichSha)) || (ret=USHAInput(&tcontext, key, key_len)) || (ret=USHAResult(&tcontext, tempkey)))
return ret;
key = tempkey;
key_len = hashsize;
@@ -134,9 +133,9 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
/* perform inner hash */
/* init context for 1st pass */
ret = USHAReset(&context->shaContext, whichSha) ||
if (!(ret = USHAReset(&context->shaContext, whichSha)))
/* and start with inner pad */
USHAInput(&context->shaContext, k_ipad, blocksize);
ret = USHAInput(&context->shaContext, k_ipad, blocksize);
return context->Corrupted = ret;
}
@@ -197,8 +196,7 @@ int hmacFinalBits(HMACContext *context,
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
/* then final bits of datagram */
return context->Corrupted =
USHAFinalBits(&context->shaContext, bits, bit_count);
return context->Corrupted = USHAFinalBits(&context->shaContext, bits, bit_count);
}
/*
@@ -229,21 +227,16 @@ int hmacResult(HMACContext *context, uint8_t *digest)
/* finish up 1st pass */
/* (Use digest here as a temporary buffer.) */
ret =
USHAResult(&context->shaContext, digest) ||
if (!(ret=USHAResult(&context->shaContext, digest)) &&
/* perform outer SHA */
/* init context for 2nd pass */
USHAReset(&context->shaContext, context->whichSha) ||
!(ret=USHAReset(&context->shaContext, context->whichSha)) &&
/* start with outer pad */
USHAInput(&context->shaContext, context->k_opad,
context->blockSize) ||
!(ret=USHAInput(&context->shaContext, context->k_opad, context->blockSize)) &&
/* then results of 1st hash */
USHAInput(&context->shaContext, digest, context->hashSize) ||
!(ret=USHAInput(&context->shaContext, digest, context->hashSize)))
/* finish up 2nd pass */
USHAResult(&context->shaContext, digest);
ret=USHAResult(&context->shaContext, digest);
context->Computed = 1;
return context->Corrupted = ret;
+6 -6
View File
@@ -64,12 +64,12 @@
* Add "length" to the length.
* Set Corrupted when overflow has occurred.
*/
static uint32_t addTemp;
#define SHA224_256AddLength(context, length) \
(addTemp = (context)->Length_Low, (context)->Corrupted = \
(((context)->Length_Low += (length)) < addTemp) && \
(++(context)->Length_High == 0) ? shaInputTooLong : \
(context)->Corrupted )
static int SHA224_256AddLength(SHA256Context *context, uint32_t length)
{
uint32_t addTemp = context->Length_Low;
if (((context->Length_Low += length) < addTemp) && (++(context)->Length_High == 0)) context->Corrupted = shaInputTooLong;
return context->Corrupted;
}
/* Local Function Prototypes */
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0);
+315 -162
View File
@@ -20,6 +20,8 @@
#include "nfqws.h"
#ifdef __CYGWIN__
#include "timer.h"
#include <sys/cygwin.h>
#include <wlanapi.h>
@@ -48,7 +50,7 @@ uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment)
{
return htonl(ntohl(netorder_value)+cpuorder_increment);
}
uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment)
uint16_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment)
{
return htons(ntohs(netorder_value)+cpuorder_increment);
}
@@ -102,8 +104,8 @@ bool tcp_syn_segment(const struct tcphdr *tcphdr)
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr,uint8_t *proto, uint16_t *sport, uint16_t *dport)
{
if (sport) *sport = htons(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0);
if (dport) *dport = htons(tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0);
if (sport) *sport = ntohs(tcphdr ? tcphdr->th_sport : udphdr ? udphdr->uh_sport : 0);
if (dport) *dport = ntohs(tcphdr ? tcphdr->th_dport : udphdr ? udphdr->uh_dport : 0);
if (proto) *proto = tcphdr ? IPPROTO_TCP : udphdr ? IPPROTO_UDP : IPPROTO_NONE;
}
@@ -178,8 +180,8 @@ void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const st
}
else
{
memset(src,0,sizeof(*src));
memset(dst,0,sizeof(*dst));
if (src) memset(src,0,sizeof(*src));
if (dst) memset(dst,0,sizeof(*dst));
}
}
@@ -229,7 +231,7 @@ uint16_t family_from_proto(uint8_t l3proto)
{
case IPPROTO_IP: return AF_INET;
case IPPROTO_IPV6: return AF_INET6;
default: return -1;
default: return AF_UNSPEC;
}
}
@@ -285,7 +287,7 @@ void str_icmp_type_name(char *s, size_t s_len, bool v6, uint8_t type)
static void str_srcdst_ip(char *s, size_t s_len, const void *saddr,const void *daddr)
{
char s_ip[16],d_ip[16];
char s_ip[INET_ADDRSTRLEN],d_ip[INET_ADDRSTRLEN];
*s_ip=*d_ip=0;
inet_ntop(AF_INET, saddr, s_ip, sizeof(s_ip));
inet_ntop(AF_INET, daddr, d_ip, sizeof(d_ip));
@@ -306,7 +308,7 @@ void print_ip(const struct ip *ip)
}
void str_srcdst_ip6(char *s, size_t s_len, const void *saddr,const void *daddr)
{
char s_ip[40],d_ip[40];
char s_ip[INET6_ADDRSTRLEN],d_ip[INET6_ADDRSTRLEN];
*s_ip=*d_ip=0;
inet_ntop(AF_INET6, saddr, s_ip, sizeof(s_ip));
inet_ntop(AF_INET6, daddr, d_ip, sizeof(d_ip));
@@ -314,14 +316,14 @@ void str_srcdst_ip6(char *s, size_t s_len, const void *saddr,const void *daddr)
}
void str_ip6hdr(char *s, size_t s_len, const struct ip6_hdr *ip6hdr, uint8_t proto)
{
char ss[83],s_proto[16];
char ss[100],s_proto[16];
str_srcdst_ip6(ss,sizeof(ss),&ip6hdr->ip6_src,&ip6hdr->ip6_dst);
str_proto_name(s_proto,sizeof(s_proto),proto);
snprintf(s,s_len,"%s proto=%s ttl=%u",ss,s_proto,ip6hdr->ip6_hlim);
}
void print_ip6hdr(const struct ip6_hdr *ip6hdr, uint8_t proto)
{
char s[128];
char s[132];
str_ip6hdr(s,sizeof(s),ip6hdr,proto);
printf("%s",s);
}
@@ -335,7 +337,7 @@ void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr)
if (tcphdr->th_flags & TH_PUSH) *f++='P';
if (tcphdr->th_flags & TH_URG) *f++='U';
*f=0;
snprintf(s,s_len,"sport=%u dport=%u flags=%s seq=%u ack_seq=%u",htons(tcphdr->th_sport),htons(tcphdr->th_dport),flags,htonl(tcphdr->th_seq),htonl(tcphdr->th_ack));
snprintf(s,s_len,"sport=%u dport=%u flags=%s seq=%u ack_seq=%u",ntohs(tcphdr->th_sport),ntohs(tcphdr->th_dport),flags,ntohl(tcphdr->th_seq),ntohl(tcphdr->th_ack));
}
void print_tcphdr(const struct tcphdr *tcphdr)
{
@@ -345,7 +347,7 @@ void print_tcphdr(const struct tcphdr *tcphdr)
}
void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr)
{
snprintf(s,s_len,"sport=%u dport=%u",htons(udphdr->uh_sport),htons(udphdr->uh_dport));
snprintf(s,s_len,"sport=%u dport=%u",ntohs(udphdr->uh_sport),ntohs(udphdr->uh_dport));
}
void print_udphdr(const struct udphdr *udphdr)
{
@@ -358,9 +360,9 @@ void str_icmphdr(char *s, size_t s_len, bool v6, const struct icmp46 *icmp)
char stype[32];
str_icmp_type_name(stype,sizeof(stype),v6,icmp->icmp_type);
if (icmp->icmp_type==ICMP_ECHO || icmp->icmp_type==ICMP_ECHOREPLY || icmp->icmp_type==ICMP6_ECHO_REQUEST || icmp->icmp_type==ICMP6_ECHO_REPLY)
snprintf(s,s_len,"icmp_type=%s icmp_code=%u id=0x%04X seq=%u",stype,icmp->icmp_code,ntohs(icmp->icmp_data16[0]),ntohs(icmp->icmp_data16[1]));
snprintf(s,s_len,"icmp_type=%s icmp_code=%u id=0x%04X seq=%u",stype,icmp->icmp_code,ntohs(icmp->data.data16[0]),ntohs(icmp->data.data16[1]));
else
snprintf(s,s_len,"icmp_type=%s icmp_code=%u data=0x%08X",stype,icmp->icmp_code,ntohl(icmp->icmp_data32));
snprintf(s,s_len,"icmp_type=%s icmp_code=%u data=0x%08X",stype,icmp->icmp_code,ntohl(icmp->data.data32));
}
void print_icmphdr(const struct icmp46 *icmp, bool v6)
{
@@ -375,13 +377,20 @@ bool proto_check_ipv4(const uint8_t *data, size_t len)
{
if (len < sizeof(struct ip)) return false;
if (((struct ip*)data)->ip_v!=4) return false;
uint16_t iplen = ntohs(((struct ip*)data)->ip_len);
uint8_t off = ((struct ip*)data)->ip_hl << 2;
return off>=sizeof(struct ip) && len>=off;
return off>=sizeof(struct ip) && iplen>=off && len>=off;
}
bool proto_check_ipv4_payload(const uint8_t *data, size_t len)
{
return len >= ntohs(((struct ip*)data)->ip_len);
}
// move to transport protocol
void proto_skip_ipv4(const uint8_t **data, size_t *len)
void proto_skip_ipv4(const uint8_t **data, size_t *len, bool *frag, uint16_t *frag_off)
{
uint8_t off = ((struct ip*)*data)->ip_hl << 2;
if (frag_off) *frag_off = (ntohs(((struct ip*)*data)->ip_off) & IP_OFFMASK) << 3;
if (frag) *frag = ntohs(((struct ip*)*data)->ip_off) & (IP_OFFMASK|IP_MF);
*data += off;
*len -= off;
}
@@ -430,21 +439,25 @@ bool proto_check_ipv6_payload(const uint8_t *data, size_t len)
}
// move to transport protocol
// proto_type = 0 => error
void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type)
void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type, bool *frag, uint16_t *frag_off)
{
size_t hdrlen;
uint8_t HeaderType;
uint16_t plen;
struct ip6_hdr *ip6 = (struct ip6_hdr*)*data;
uint16_t plen;
uint16_t fr_off=0;
bool fr=false;
uint8_t HeaderType;
if (proto_type) *proto_type = 0; // put error in advance
if (frag) *frag = false;
if (frag_off) *frag_off = 0;
HeaderType = ip6->ip6_nxt;
if (proto_type) *proto_type = HeaderType;
plen = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
*data += sizeof(struct ip6_hdr); *len -= sizeof(struct ip6_hdr); // skip ipv6 base header
if (plen < *len) *len = plen;
while (*len) // need at least one byte for NextHeader field
while (*len && !(fr && fr_off)) // need at least one byte for NextHeader field. stop after fragment header if not first fragment
{
switch (HeaderType)
{
@@ -459,6 +472,11 @@ void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type)
break;
case IPPROTO_FRAGMENT: // fragment. length fixed to 8, hdrlen field defined as reserved
hdrlen = 8;
if (*len < hdrlen) return; // error
fr_off = ntohs(((struct ip6_frag*)*data)->ip6f_offlg & IP6F_OFF_MASK);
fr = ((struct ip6_frag*)*data)->ip6f_offlg & (IP6F_OFF_MASK|IP6F_MORE_FRAG);
if (frag_off) *frag_off = fr_off;
if (frag) *frag = fr;
break;
case IPPROTO_AH:
// special case. length in ah header is in 32-bit words minus 2
@@ -484,16 +502,18 @@ void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type)
uint8_t *proto_find_ip6_exthdr(struct ip6_hdr *ip6, size_t len, uint8_t proto)
{
size_t hdrlen;
uint8_t HeaderType, last_proto, *data;
uint16_t plen;
uint8_t HeaderType, last_proto, *data;
bool fr=false;
uint16_t fr_off=0;
if (len<sizeof(struct ip6_hdr)) return false;
if (len<sizeof(struct ip6_hdr)) return NULL;
plen = ntohs(ip6->ip6_ctlun.ip6_un1.ip6_un1_plen);
last_proto = ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt;
data = (uint8_t*)(ip6+1);
len -= sizeof(struct ip6_hdr);
if (plen < len) len = plen;
while (len) // need at least one byte for NextHeader field
while (len && !(fr && fr_off)) // need at least one byte for NextHeader field. stop after fragment header if not first fragment
{
if (last_proto==proto) return data; // found
switch (last_proto)
@@ -504,15 +524,18 @@ uint8_t *proto_find_ip6_exthdr(struct ip6_hdr *ip6, size_t len, uint8_t proto)
case IPPROTO_MH: // mobility header
case IPPROTO_HIP: // Host Identity Protocol Version v2
case IPPROTO_SHIM6:
if (len < 2) return false; // error
if (len < 2) return NULL; // error
hdrlen = 8 + (data[1] << 3);
break;
case IPPROTO_FRAGMENT: // fragment. length fixed to 8, hdrlen field defined as reserved
hdrlen = 8;
if (len < hdrlen) return NULL; // error
fr_off = ntohs(((struct ip6_frag*)data)->ip6f_offlg & IP6F_OFF_MASK);
fr = ((struct ip6_frag*)data)->ip6f_offlg & (IP6F_OFF_MASK|IP6F_MORE_FRAG);
break;
case IPPROTO_AH:
// special case. length in ah header is in 32-bit words minus 2
if (len < 2) return false; // error
if (len < 2) return NULL; // error
hdrlen = 8 + (data[1] << 2);
break;
default:
@@ -520,7 +543,7 @@ uint8_t *proto_find_ip6_exthdr(struct ip6_hdr *ip6, size_t len, uint8_t proto)
// exthdr was not found
return NULL;
}
if (len < hdrlen) return false; // error
if (len < hdrlen) return NULL; // error
last_proto = *data;
len -= hdrlen; data += hdrlen;
}
@@ -537,19 +560,25 @@ void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis, bo
dis->data_pkt = data;
dis->len_pkt = len;
if (proto_check_ipv4(data, len))
size_t iplen;
if (proto_check_ipv4(data, len) && (no_payload_check || proto_check_ipv4_payload(data, len)))
{
dis->ip = (const struct ip *) data;
dis->proto = dis->ip->ip_p;
p = data;
proto_skip_ipv4(&data, &len);
iplen = ntohs(((struct ip*)data)->ip_len);
if (iplen<len) dis->len_pkt = len = iplen;
proto_skip_ipv4(&data, &len, &dis->frag, &dis->frag_off);
dis->len_l3 = data-p;
}
else if (proto_check_ipv6(data, len) && (no_payload_check || proto_check_ipv6_payload(data, len)))
{
dis->ip6 = (const struct ip6_hdr *) data;
p = data;
proto_skip_ipv6(&data, &len, &dis->proto);
iplen = ntohs(((struct ip6_hdr*)data)->ip6_ctlun.ip6_un1.ip6_un1_plen) + sizeof(struct ip6_hdr);
if (iplen<len) dis->len_pkt = len = iplen;
proto_skip_ipv6(&data, &len, &dis->proto, &dis->frag, &dis->frag_off);
dis->len_l3 = data-p;
}
else
@@ -558,31 +587,31 @@ void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis, bo
}
dis->transport_len = len;
dis->len_l4 = 0;
if (dis->proto==IPPROTO_TCP && proto_check_tcp(data, len))
if (!dis->frag)
{
dis->tcp = (const struct tcphdr *) data;
p = data;
proto_skip_tcp(&data, &len);
dis->len_l4 = data-p;
}
else if (dis->proto==IPPROTO_UDP && proto_check_udp(data, len) && (no_payload_check || proto_check_udp_payload(data, len)))
{
dis->udp = (const struct udphdr *) data;
p = data;
proto_skip_udp(&data, &len);
dis->len_l4 = data-p;
}
else if ((dis->proto==IPPROTO_ICMP || dis->proto==IPPROTO_ICMPV6) && proto_check_icmp(data, len))
{
dis->icmp = (const struct icmp46 *) data;
p = data;
proto_skip_icmp(&data, &len);
dis->len_l4 = data-p;
}
else
{
dis->len_l4 = 0;
if (dis->proto==IPPROTO_TCP && proto_check_tcp(data, len))
{
dis->tcp = (const struct tcphdr *) data;
p = data;
proto_skip_tcp(&data, &len);
dis->len_l4 = data-p;
}
else if (dis->proto==IPPROTO_UDP && proto_check_udp(data, len) && (no_payload_check || proto_check_udp_payload(data, len)))
{
dis->udp = (const struct udphdr *) data;
p = data;
proto_skip_udp(&data, &len);
dis->len_l4 = data-p;
}
else if ((dis->proto==IPPROTO_ICMP || dis->proto==IPPROTO_ICMPV6) && proto_check_icmp(data, len))
{
dis->icmp = (const struct icmp46 *) data;
p = data;
proto_skip_icmp(&data, &len);
dis->len_l4 = data-p;
}
}
dis->data_payload = data;
@@ -777,8 +806,8 @@ static BOOL RemoveTokenPrivs(void)
if (memcmp(&privs->Privileges[k].Luid, &luid_SeChangeNotifyPrivilege, sizeof(LUID)))
privs->Privileges[k].Attributes = SE_PRIVILEGE_REMOVED;
}
bRes = AdjustTokenPrivileges(hToken, FALSE, privs, dwSize, NULL, NULL);
}
bRes = AdjustTokenPrivileges(hToken, FALSE, privs, dwSize, NULL, NULL);
free(privs);
}
}
@@ -902,11 +931,29 @@ BOOL SetMandatoryLabelObject(HANDLE h, SE_OBJECT_TYPE ObjType, DWORD dwMandatory
bool ensure_file_access(const char *filename)
{
return SetMandatoryLabelFile(filename, SECURITY_MANDATORY_LOW_RID, 0);
bool b=false;
size_t l = cygwin_conv_path(CCP_POSIX_TO_WIN_W | CCP_ABSOLUTE, filename, NULL, 0);
WCHAR *wfilename = (WCHAR*)malloc(l);
if (wfilename)
{
if (!cygwin_conv_path(CCP_POSIX_TO_WIN_W | CCP_ABSOLUTE, filename, wfilename, l))
b = SetMandatoryLabelFileW(wfilename, SECURITY_MANDATORY_LOW_RID, 0);
free(wfilename);
}
return b;
}
bool ensure_dir_access(const char *dir)
{
return SetMandatoryLabelFile(dir, SECURITY_MANDATORY_LOW_RID, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
bool b=false;
size_t l = cygwin_conv_path(CCP_POSIX_TO_WIN_W | CCP_ABSOLUTE, dir, NULL, 0);
WCHAR *wdir = (WCHAR*)malloc(l);
if (wdir)
{
if (!cygwin_conv_path(CCP_POSIX_TO_WIN_W | CCP_ABSOLUTE, dir, wdir, l))
b=SetMandatoryLabelFileW(wdir, SECURITY_MANDATORY_LOW_RID, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
free(wdir);
}
return b;
}
bool prepare_low_appdata()
@@ -1065,6 +1112,7 @@ bool win_sandbox(void)
static HANDLE w_filter = NULL;
static OVERLAPPED ovl = { .hEvent = NULL };
static const struct str_list_head *wlan_filter_ssid = NULL, *nlm_filter_net = NULL;
static bool wlan_filter_ssid_neg = false, nlm_filter_net_neg = false;
static DWORD logical_net_filter_tick=0;
INetworkListManager* pNetworkListManager=NULL;
@@ -1148,12 +1196,51 @@ static bool AdapterID2Name(const GUID *guid,char *name,DWORD name_len)
return bRet;
}
bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_list_head *nlm_filter)
typedef DWORD (WINAPI *t_WlanOpenHandle)(
DWORD dwClientVersion,
PVOID pReserved,
PDWORD pdwNegotiatedVersion,
PHANDLE phClientHandle
);
typedef DWORD (WINAPI *t_WlanCloseHandle)(
HANDLE hClientHandle,
PVOID pReserved
);
typedef DWORD (WINAPI *t_WlanEnumInterfaces)(
HANDLE hClientHandle,
PVOID pReserved,
PWLAN_INTERFACE_INFO_LIST *ppInterfaceList
);
typedef DWORD (WINAPI *t_WlanQueryInterface)(
HANDLE hClientHandle,
const GUID *pInterfaceGuid,
WLAN_INTF_OPCODE OpCode,
PVOID pReserved,
PDWORD pdwDataSize,
PVOID *ppData,
PWLAN_OPCODE_VALUE_TYPE pWlanOpcodeValueType
);
typedef DWORD (WINAPI *t_WlanFreeMemory)(
PVOID pMemory
);
t_WlanOpenHandle f_WlanOpenHandle = NULL;
t_WlanCloseHandle f_WlanCloseHandle = NULL;
t_WlanEnumInterfaces f_WlanEnumInterfaces = NULL;
t_WlanQueryInterface f_WlanQueryInterface = NULL;
t_WlanFreeMemory f_WlanFreeMemory = NULL;
HMODULE hdll_wlanapi = NULL;
bool win_dark_init(const struct str_list_head *ssid_filter, bool ssid_filter_neg, const struct str_list_head *nlm_filter, bool nlm_filter_neg)
{
win_dark_deinit();
if (LIST_EMPTY(ssid_filter)) ssid_filter=NULL;
if (LIST_EMPTY(nlm_filter)) nlm_filter=NULL;
wlan_filter_ssid_neg = ssid_filter_neg;
nlm_filter_net_neg = nlm_filter_neg;
if (nlm_filter)
{
if (SUCCEEDED(w_win32_error = CoInitialize(NULL)))
@@ -1161,12 +1248,38 @@ bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_lis
if (FAILED(w_win32_error = CoCreateInstance(&CLSID_NetworkListManager, NULL, CLSCTX_ALL, &IID_INetworkListManager, (LPVOID*)&pNetworkListManager)))
{
CoUninitialize();
DLOG_ERR("could not create CLSID_NetworkListManager. win32 error %u\n", w_win32_error);
return false;
}
}
else
return false;
}
if (ssid_filter)
{
// dont load any crap from current dir
hdll_wlanapi = LoadLibraryExW(L"wlanapi.dll",NULL,LOAD_LIBRARY_SEARCH_SYSTEM32);
if (!hdll_wlanapi)
{
w_win32_error = GetLastError();
DLOG_ERR("could not load wlanapi.dll. win32 error %u\n", w_win32_error);
win_dark_deinit();
return false;
}
f_WlanOpenHandle = (t_WlanOpenHandle)GetProcAddress(hdll_wlanapi,"WlanOpenHandle");
f_WlanCloseHandle = (t_WlanCloseHandle)GetProcAddress(hdll_wlanapi,"WlanCloseHandle");
f_WlanEnumInterfaces = (t_WlanEnumInterfaces)GetProcAddress(hdll_wlanapi,"WlanEnumInterfaces");
f_WlanQueryInterface = (t_WlanQueryInterface)GetProcAddress(hdll_wlanapi,"WlanQueryInterface");
f_WlanFreeMemory = (t_WlanFreeMemory)GetProcAddress(hdll_wlanapi,"WlanFreeMemory");
if (!f_WlanOpenHandle || !f_WlanCloseHandle || !f_WlanEnumInterfaces || !f_WlanQueryInterface || !f_WlanFreeMemory)
{
w_win32_error = GetLastError();
DLOG_ERR("could not import all required functions from wlanapi.dll\n");
win_dark_deinit();
return false;
}
}
nlm_filter_net = nlm_filter;
wlan_filter_ssid = ssid_filter;
return true;
@@ -1180,6 +1293,17 @@ void win_dark_deinit(void)
}
if (nlm_filter_net) CoUninitialize();
wlan_filter_ssid = nlm_filter_net = NULL;
wlan_filter_ssid_neg = nlm_filter_net_neg = false;
if (hdll_wlanapi)
{
FreeLibrary(hdll_wlanapi);
hdll_wlanapi = NULL;
f_WlanOpenHandle = NULL;
f_WlanCloseHandle = NULL;
f_WlanEnumInterfaces = NULL;
f_WlanQueryInterface = NULL;
f_WlanFreeMemory = NULL;
}
}
@@ -1361,16 +1485,16 @@ static bool wlan_filter_match(const struct str_list_head *ssid_list)
return true;
}
w_win32_error = WlanOpenHandle(2, NULL, &dwCurVersion, &hClient);
w_win32_error = f_WlanOpenHandle(2, NULL, &dwCurVersion, &hClient);
if (w_win32_error != ERROR_SUCCESS) goto fail;
w_win32_error = WlanEnumInterfaces(hClient, NULL, &pIfList);
w_win32_error = f_WlanEnumInterfaces(hClient, NULL, &pIfList);
if (w_win32_error != ERROR_SUCCESS) goto fail;
for (k = 0; k < pIfList->dwNumberOfItems; k++)
{
pIfInfo = pIfList->InterfaceInfo + k;
if (pIfInfo->isState == wlan_interface_state_connected)
{
w_win32_error = WlanQueryInterface(hClient,
w_win32_error = f_WlanQueryInterface(hClient,
&pIfInfo->InterfaceGuid,
wlan_intf_opcode_current_connection,
NULL,
@@ -1386,20 +1510,20 @@ static bool wlan_filter_match(const struct str_list_head *ssid_list)
len = strlen(ssid->str);
if (len==pConnectInfo->wlanAssociationAttributes.dot11Ssid.uSSIDLength && !memcmp(ssid->str,pConnectInfo->wlanAssociationAttributes.dot11Ssid.ucSSID,len))
{
WlanFreeMemory(pConnectInfo);
f_WlanFreeMemory(pConnectInfo);
goto found;
}
}
WlanFreeMemory(pConnectInfo);
f_WlanFreeMemory(pConnectInfo);
}
}
w_win32_error = 0;
fail:
bRes = false;
ex:
if (pIfList) WlanFreeMemory(pIfList);
if (hClient) WlanCloseHandle(hClient, 0);
if (pIfList) f_WlanFreeMemory(pIfList);
if (hClient) f_WlanCloseHandle(hClient, 0);
return bRes;
found:
w_win32_error = 0;
@@ -1407,16 +1531,18 @@ found:
goto ex;
}
bool logical_net_filter_match(void)
{
return wlan_filter_match(wlan_filter_ssid) && nlm_filter_match(nlm_filter_net);
}
bool logical_net_filter_present(void)
{
return (wlan_filter_ssid && !LIST_EMPTY(wlan_filter_ssid)) || (nlm_filter_net && !LIST_EMPTY(nlm_filter_net));
}
bool logical_net_filter_match(void)
{
return (wlan_filter_match(wlan_filter_ssid) ^ wlan_filter_ssid_neg) &&
(nlm_filter_match(nlm_filter_net) ^ nlm_filter_net_neg);
}
static bool logical_net_filter_match_rate_limited(void)
@@ -1465,7 +1591,6 @@ void rawsend_cleanup(void)
{
if (w_filter)
{
CancelIoEx(w_filter,&ovl);
WinDivertClose(w_filter);
w_filter=NULL;
}
@@ -1493,76 +1618,115 @@ bool windivert_init(const char *filter)
return false;
}
static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count)
static bool windivert_recv_exit(void)
{
UINT recv_len;
DWORD err;
DWORD rd;
char c;
sigset_t pending;
// make signals working
usleep(0);
if (bQuit)
{
errno=EINTR;
return false;
return true;
}
if (!logical_net_filter_match_rate_limited())
{
errno=ENODEV;
return false;
return true;
}
usleep(0);
return false;
}
*wa_count *= sizeof(WINDIVERT_ADDRESS);
if (WinDivertRecvEx(hFilter, packet, *len, &recv_len, 0, wa, wa_count, &ovl))
static bool windivert_recv_filter(HANDLE hFilter, uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count, uint64_t *bt_next)
{
UINT recv_len;
DWORD rd,twait;
uint64_t tmax;
unsigned int wac;
uint64_t bt;
if (windivert_recv_exit())
return false;
if (params.timers)
{
*wa_count /= sizeof(WINDIVERT_ADDRESS);
if (!*bt_next || params.timers_dirty) *bt_next = TimerPoolNext(params.timers, &params.timers_dirty);
bt = boottime_ms();
tmax = *bt_next>bt ? *bt_next-bt : 0;
if (!tmax)
{
*bt_next = TimerPoolRun(&params.timers, &params.timers_dirty, bt);
bt = boottime_ms();
tmax = *bt_next>bt ? *bt_next-bt : 0;
}
}
else
{
*bt_next = 0;
tmax = 0;
}
wac = *wa_count * sizeof(WINDIVERT_ADDRESS);
if (WinDivertRecvEx(hFilter, packet, *len, &recv_len, 0, wa, &wac, &ovl))
{
*wa_count = wac/sizeof(WINDIVERT_ADDRESS);
*len = recv_len;
return true;
}
for(;;)
w_win32_error = GetLastError();
switch(w_win32_error)
{
w_win32_error = GetLastError();
switch(w_win32_error)
{
case ERROR_IO_PENDING:
// make signals working
while (WaitForSingleObject(ovl.hEvent,50)==WAIT_TIMEOUT)
case ERROR_IO_PENDING:
// need to check for signals periodically
for(;;)
{
if (params.timers)
{
if (bQuit)
{
errno=EINTR;
return false;
}
if (!logical_net_filter_match_rate_limited())
{
errno=ENODEV;
return false;
}
usleep(0);
twait = tmax>50 ? 50 : (DWORD)tmax;
tmax -= twait;
}
if (!GetOverlappedResult(hFilter,&ovl,&rd,TRUE))
continue;
*wa_count /= sizeof(WINDIVERT_ADDRESS);
*len = rd;
return true;
case ERROR_INSUFFICIENT_BUFFER:
errno = ENOBUFS;
break;
case ERROR_NO_DATA:
errno = ESHUTDOWN;
break;
default:
errno = EIO;
}
break;
else
twait = 50;
// make signals working
if (WaitForSingleObject(ovl.hEvent,twait)!=WAIT_TIMEOUT) break;
if (windivert_recv_exit())
return false;
if (params.timers && !tmax)
{
bt = boottime_ms();
*bt_next = TimerPoolRun(&params.timers, &params.timers_dirty, bt);
bt = boottime_ms();
tmax = *bt_next>bt ? *bt_next-bt : 0;
}
}
if (!GetOverlappedResult(hFilter,&ovl,&rd,FALSE))
{
errno=EIO;
goto cancel;
}
*wa_count = wac/sizeof(WINDIVERT_ADDRESS);
*len = rd;
return true;
case ERROR_INSUFFICIENT_BUFFER:
errno = ENOBUFS;
break;
case ERROR_NO_DATA:
errno = ESHUTDOWN;
break;
default:
errno = EIO;
}
cancel:
// make sure no pending operations
CancelIoEx(w_filter,&ovl);
GetOverlappedResult(hFilter, &ovl, &rd, TRUE);
return false;
}
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count)
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count, uint64_t *bt_next)
{
return windivert_recv_filter(w_filter,packet,len,wa,wa_count);
return windivert_recv_filter(w_filter,packet,len,wa,wa_count,bt_next);
}
static bool windivert_send_filter(HANDLE hFilter, const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa)
@@ -1677,6 +1841,7 @@ static int rawsend_sendto_divert(sa_family_t family, int sock, const void *buf,
{
struct sockaddr_storage sa;
socklen_t slen;
ssize_t wr;
#ifdef __FreeBSD__
// since FreeBSD 14 it requires hardcoded ipv4 values, although can also send ipv6 frames
@@ -1698,7 +1863,16 @@ static int rawsend_sendto_divert(sa_family_t family, int sock, const void *buf,
#endif
memset(&sa,0,slen);
sa.ss_family = family;
return sendto(sock, buf, len, 0, (struct sockaddr*)&sa, slen);
while ((wr=sendto(sock, buf, len, 0, (struct sockaddr*)&sa, slen))<0 && errno==EINTR);
if (wr<0)
{
char s[64];
snprintf(s,sizeof(s),"rawsend_sendto_divert: sendto (%zu)",len);
DLOG_PERROR(s);
return -1;
}
return wr;
}
#endif
@@ -1779,8 +1953,9 @@ static int rawsend_socket(sa_family_t family)
}
if (family==AF_INET && setsockopt(*sock, IPPROTO_IP, IP_NODEFRAG, &yes, sizeof(yes)) == -1)
{
// since 2.6.36
DLOG_PERROR("rawsend: setsockopt(IP_NODEFRAG)");
goto exiterr;
//goto exiterr;
}
if (family==AF_INET && setsockopt(*sock, IPPROTO_IP, IP_FREEBIND, &yes, sizeof(yes)) == -1)
{
@@ -1811,7 +1986,9 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const
ssize_t bytes;
int sock=rawsend_socket(dst->sa_family);
if (sock==-1) return false;
#if defined(BSD) || defined(__linux__)
if (!set_socket_fwmark(sock,fwmark)) return false;
#endif
int salen = dst->sa_family == AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
struct sockaddr_storage dst2;
memcpy(&dst2,dst,salen);
@@ -1830,47 +2007,32 @@ bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const
#else
#ifdef __linux__
struct sockaddr_storage sa_src;
switch(dst->sa_family)
{
case AF_INET:
if (!b_bind_fix4) goto nofix;
extract_endpoints(data,NULL,NULL,NULL, &sa_src, NULL);
break;
case AF_INET6:
if (!b_bind_fix6) goto nofix;
extract_endpoints(NULL,data,NULL,NULL, &sa_src, NULL);
break;
default:
return false; // should not happen
}
//printf("family %u dev %s bind : ", dst->sa_family, ifout); print_sockaddr((struct sockaddr *)&sa_src); printf("\n");
// force outgoing interface for raw packets. linux may choose it wrong if ip rules exist
if (setsockopt(sock, SOL_SOCKET, SO_BINDTODEVICE, ifout, ifout ? strlen(ifout)+1 : 0) == -1)
{
DLOG_PERROR("rawsend: setsockopt(SO_BINDTODEVICE)");
return false;
}
if (bind(sock, (const struct sockaddr*)&sa_src, dst->sa_family==AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)))
{
DLOG_PERROR("rawsend: bind (ignoring)");
// do not fail. this can happen regardless of IP_FREEBIND
// rebind to any address
memset(&sa_src,0,sizeof(sa_src));
sa_src.ss_family = dst->sa_family;
if (bind(sock, (const struct sockaddr*)&sa_src, dst->sa_family==AF_INET ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6)))
{
DLOG_PERROR("rawsend: bind to any");
return false;
}
}
nofix:
#endif
// normal raw socket sendto
bytes = sendto(sock, data, len, 0, (struct sockaddr*)&dst2, salen);
if (bytes==-1)
while ((bytes = sendto(sock, data, len, 0, (struct sockaddr*)&dst2, salen))<0 && errno==EINTR);
if (bytes<0)
{
char s[40];
char s[64];
snprintf(s,sizeof(s),"rawsend: sendto (%zu)",len);
DLOG_PERROR(s);
return false;
@@ -1894,7 +2056,7 @@ bool rawsend_rp(const struct rawpacket *rp)
{
return rawsend((struct sockaddr*)&rp->dst,rp->fwmark,rp->ifout,rp->packet,rp->len);
}
bool rawsend_queue(struct rawpacket_tailhead *q)
bool rawsend_queue(struct rawpacket_queue *q)
{
struct rawpacket *rp;
bool b;
@@ -1988,6 +2150,7 @@ static uint16_t wlan_get_family_id(struct mnl_socket* nl)
static int wlan_info_attr_cb(const struct nlattr *attr, void *data)
{
struct wlan_interface *wlan = (struct wlan_interface *)data;
size_t len;
switch(mnl_attr_get_type(attr))
{
case NL80211_ATTR_IFINDEX:
@@ -1999,12 +2162,10 @@ static int wlan_info_attr_cb(const struct nlattr *attr, void *data)
wlan->ifindex = mnl_attr_get_u32(attr);
break;
case NL80211_ATTR_SSID:
if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
{
DLOG_PERROR("mnl_attr_validate(ssid)");
return MNL_CB_ERROR;
}
snprintf(wlan->ssid,sizeof(wlan->ssid),"%s",mnl_attr_get_str(attr));
len = mnl_attr_get_payload_len(attr);
if (len>=sizeof(wlan->ssid)) len=sizeof(wlan->ssid)-1;
memcpy(wlan->ssid, mnl_attr_get_payload(attr), len);
wlan->ssid[len]=0;
break;
case NL80211_ATTR_IFNAME:
if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
@@ -2050,8 +2211,8 @@ static uint8_t *find_ie(uint8_t *buf, size_t len, uint8_t ie)
{
if (len<(2+buf[1])) break;
if (buf[0]==ie) return buf;
buf+=buf[1]+2;
len-=buf[1]+2;
buf+=buf[1]+2;
}
return NULL;
}
@@ -2134,6 +2295,7 @@ static bool scan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wla
// 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;
w->count=0;
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;
@@ -2327,11 +2489,11 @@ bool set_socket_buffers(int fd, int rcvbuf, int sndbuf)
return true;
}
bool make_writeable_dir()
bool make_writable_dir()
{
char wdir[PATH_MAX], *wrdir;
if (*params.writeable_dir)
wrdir = params.writeable_dir;
if (*params.writable_dir)
wrdir = params.writable_dir;
else
{
#ifdef __CYGWIN__
@@ -2347,20 +2509,11 @@ bool make_writeable_dir()
if (mkdir(wrdir,0755) && errno!=EEXIST)
return false;
bool b = false;
bool b;
#ifdef __CYGWIN__
size_t l = cygwin_conv_path(CCP_POSIX_TO_WIN_W | CCP_ABSOLUTE, wrdir, NULL, 0);
WCHAR *wwrdir = (WCHAR*)malloc(l);
if (wwrdir)
{
if (!cygwin_conv_path(CCP_POSIX_TO_WIN_W | CCP_ABSOLUTE, wrdir, wwrdir, l))
b = SetMandatoryLabelFileW(wwrdir, SECURITY_MANDATORY_LOW_RID, OBJECT_INHERIT_ACE | CONTAINER_INHERIT_ACE);
free(wwrdir);
}
b = ensure_dir_access(wrdir);
#else
if (ensure_dir_access(wrdir))
b = true;
else
if (!(b=ensure_dir_access(wrdir)))
{
// could not chown. may be still accessible ?
char testfile[PATH_MAX];
@@ -2374,6 +2527,6 @@ bool make_writeable_dir()
}
}
#endif
if (b) setenv("WRITEABLE",wrdir,1);
if (b) setenv("WRITABLE",wrdir,1);
return b;
}
+10 -7
View File
@@ -94,7 +94,7 @@
// returns netorder value
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment);
uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
uint16_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
#define SCALE_NONE ((uint8_t)-1)
@@ -121,7 +121,7 @@ bool tcp_synack_segment(const struct tcphdr *tcphdr);
bool tcp_syn_segment(const struct tcphdr *tcphdr);
bool make_writeable_dir();
bool make_writable_dir();
bool ensure_file_access(const char *filename);
#ifdef __CYGWIN__
extern uint32_t w_win32_error;
@@ -129,13 +129,13 @@ extern uint32_t w_win32_error;
bool ensure_dir_access(const char *filename);
bool prepare_low_appdata();
bool win_sandbox(void);
bool win_dark_init(const struct str_list_head *ssid_filter, const struct str_list_head *nlm_filter);
bool win_dark_init(const struct str_list_head *ssid_filter, bool ssid_filter_neg, const struct str_list_head *nlm_filter, bool nlm_filter_neg);
void win_dark_deinit(void);
bool logical_net_filter_present(void);
bool logical_net_filter_match(void);
bool nlm_list(bool bAll);
bool windivert_init(const char *filter);
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count);
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count, uint64_t *bt_next);
bool windivert_send(const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa);
#else
#define ensure_dir_access(dir) ensure_file_access(dir)
@@ -147,7 +147,7 @@ bool rawsend_preinit(bool bind_fix4, bool bind_fix6);
bool rawsend(const struct sockaddr* dst,uint32_t fwmark,const char *ifout,const void *data,size_t len);
bool rawsend_rp(const struct rawpacket *rp);
// return trues if all packets were send successfully
bool rawsend_queue(struct rawpacket_tailhead *q);
bool rawsend_queue(struct rawpacket_queue *q);
// cleans up socket autocreated by rawsend
void rawsend_cleanup(void);
bool rawsend_rep(int repeats, const struct sockaddr* dst, uint32_t fwmark, const char *ifout, const void *data, size_t len);
@@ -174,10 +174,11 @@ void str_udphdr(char *s, size_t s_len, const struct udphdr *udphdr);
void str_icmphdr(char *s, size_t s_len, bool v6, const struct icmp46 *icmp);
bool proto_check_ipv4(const uint8_t *data, size_t len);
void proto_skip_ipv4(const uint8_t **data, size_t *len);
bool proto_check_ipv4_payload(const uint8_t *data, size_t len);
void proto_skip_ipv4(const uint8_t **data, size_t *len, bool *frag, uint16_t *frag_off);
bool proto_check_ipv6(const uint8_t *data, size_t len);
bool proto_check_ipv6_payload(const uint8_t *data, size_t len);
void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type);
void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type, bool *frag, uint16_t *frag_off);
uint8_t *proto_find_ip6_exthdr(struct ip6_hdr *ip6, size_t len, uint8_t proto);
bool proto_check_tcp(const uint8_t *data, size_t len);
void proto_skip_tcp(const uint8_t **data, size_t *len);
@@ -202,6 +203,8 @@ struct dissect
size_t transport_len;
const uint8_t *data_payload;
size_t len_payload;
bool frag;
uint16_t frag_off;
};
void proto_dissect_l3l4(const uint8_t *data, size_t len, struct dissect *dis, bool no_payload_check);
void reverse_ip(struct ip *ip, struct ip6_hdr *ip6);
+314 -195
View File
@@ -188,7 +188,10 @@ static void packet_debug(bool replay, const struct dissect *dis)
{
char s_proto[16];
str_proto_name(s_proto,sizeof(s_proto),dis->proto);
DLOG("\nIP PROTO %s: len=%zu : ", s_proto, dis->len_payload);
if (dis->frag)
DLOG("\nIP FRAG off=%u PROTO %s: len=%zu : ", dis->frag_off, s_proto, dis->len_payload);
else
DLOG("\nIP PROTO %s: len=%zu : ", s_proto, dis->len_payload);
hexdump_limited_dlog(dis->data_payload, dis->len_payload, PKTDATA_MAXDUMP);
DLOG("\n");
}
@@ -198,60 +201,80 @@ static void packet_debug(bool replay, const struct dissect *dis)
}
}
// ipr,ipr6 - reverse ip - ip of the other side of communication
struct dp_match_data
{
const struct in_addr *ip;
const struct in6_addr *ip6;
const struct in_addr *ipr;
const struct in6_addr *ipr6;
const char *hostname;
const char *ssid;
bool *bCheckDone, *bCheckResult, *bExcluded;
t_l7proto l7proto;
uint32_t fwmark;
uint16_t port;
uint8_t icmp_type, icmp_code;
bool bNoSubdom;
uint8_t l3proto;
};
static bool dp_match(
struct desync_profile *dp,
uint8_t l3proto,
const struct in_addr *ip, const struct in6_addr *ip6,
const struct in_addr *ipr, const struct in6_addr *ipr6,
uint16_t port, uint8_t icmp_type, uint8_t icmp_code,
const char *hostname, bool bNoSubdom, t_l7proto l7proto, const char *ssid,
bool *bCheckDone, bool *bCheckResult, bool *bExcluded)
const struct dp_match_data *match)
{
bool bHostlistsEmpty;
if (bCheckDone) *bCheckDone = false;
if (match->bCheckDone) *match->bCheckDone = false;
if (!HostlistsReloadCheckForProfile(dp)) return false;
// fast checks first
if ((ip && !dp->filter_ipv4) || (ip6 && !dp->filter_ipv6))
// L3 filter does not match
return false;
switch(l3proto)
{
case IPPROTO_TCP:
if (!port_filters_match(&dp->pf_tcp, port)) return false;
break;
case IPPROTO_UDP:
if (!port_filters_match(&dp->pf_udp, port)) return false;
break;
case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
if (!icmp_filters_match(&dp->icf, icmp_type, icmp_code)) return false;
break;
default:
if (!ipp_filters_match(&dp->ipf, l3proto)) return false;
}
if (!l7_proto_match(l7proto, dp->filter_l7))
// L7 filter does not match
return false;
#ifdef HAS_FILTER_SSID
if (!LIST_EMPTY(&dp->filter_ssid) && !strlist_search(&dp->filter_ssid, ssid))
#ifdef __linux__
if ((match->fwmark & dp->filter_mark_mask)!=dp->filter_mark)
return false;
#endif
if ((match->ip && !dp->filter_ipv4) || (match->ip6 && !dp->filter_ipv6))
// L3 filter does not match
return false;
if (!l7_proto_match(match->l7proto, dp->filter_l7))
// L7 filter does not match
return false;
switch(match->l3proto)
{
case IPPROTO_TCP:
if (!port_filters_match(&dp->pf_tcp, match->port)) return false;
break;
case IPPROTO_UDP:
if (!port_filters_match(&dp->pf_udp, match->port)) return false;
break;
case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
if (!icmp_filters_match(&dp->icf, match->icmp_type, match->icmp_code)) return false;
break;
default:
if (!ipp_filters_match(&dp->ipf, match->l3proto)) return false;
}
#ifdef HAS_FILTER_SSID
if (!LIST_EMPTY(&dp->filter_ssid) && (!strlist_search(&dp->filter_ssid, match->ssid) ^ dp->filter_ssid_neg))
return false;
#endif
if (!HostlistsReloadCheckForProfile(dp)) return false;
bHostlistsEmpty = PROFILE_HOSTLISTS_EMPTY(dp);
if (!dp->hostlist_auto && !hostname && !bHostlistsEmpty)
if (!dp->hostlist_auto && !match->hostname && !bHostlistsEmpty)
// avoid cpu consuming ipset check. profile cannot win if regular hostlists are present without auto hostlist and hostname is unknown.
return false;
if (!IpsetCheck(dp, ip, ip6, ipr, ipr6))
if (!IpsetCheck(dp, match->ip, match->ip6, match->ipr, match->ipr6))
// target ip does not match
return false;
// autohostlist profile matching l3/l4/l7 filter always win if we have a hostname. no matter it matches or not.
if (dp->hostlist_auto && hostname)
if (dp->hostlist_auto && match->hostname)
{
DLOG("autohostlist profile %u (%s) wins because hostname is known\n",dp->n,dp->name);
return true;
@@ -263,12 +286,12 @@ static bool dp_match(
else
{
// if hostlists are present profile matches only if hostname is known and satisfy profile hostlists
if (hostname)
if (match->hostname)
{
if (bCheckDone) *bCheckDone = true;
if (match->bCheckDone) *match->bCheckDone = true;
bool b;
b = HostlistCheck(dp, hostname, bNoSubdom, bExcluded, true);
if (bCheckResult) *bCheckResult = b;
b = HostlistCheck(dp, match->hostname, match->bNoSubdom, match->bExcluded, true);
if (match->bCheckResult) *match->bCheckResult = b;
return b;
}
}
@@ -280,29 +303,38 @@ static struct desync_profile *dp_find(
const struct in_addr *ip, const struct in6_addr *ip6,
const struct in_addr *ipr, const struct in6_addr *ipr6,
uint16_t port, uint8_t icmp_type, uint8_t icmp_code,
const char *hostname, bool bNoSubdom, t_l7proto l7proto, const char *ssid,
const char *hostname, bool bNoSubdom, t_l7proto l7proto,
const char *ssid, uint32_t fwmark,
bool *bCheckDone, bool *bCheckResult, bool *bExcluded)
{
struct desync_profile_list *dpl;
struct dp_match_data match = {
.l3proto=l3proto,
.ip=ip, .ip6=ip6, .ipr=ipr, .ipr6=ipr6,
.port=port, .icmp_type=icmp_type, .icmp_code=icmp_code,
.hostname=hostname, .bNoSubdom=bNoSubdom, .l7proto=l7proto,
.ssid=ssid, .fwmark=fwmark,
.bCheckDone=bCheckDone, .bCheckResult=bCheckResult, .bExcluded=bExcluded
};
if (params.debug)
{
char s[40];
char s[INET6_ADDRSTRLEN];
ntopa46(ip, ip6, s, sizeof(s));
if (ipr || ipr6)
{
char sr[40];
char sr[INET6_ADDRSTRLEN];
ntopa46(ipr, ipr6, sr, sizeof(sr));
DLOG("desync profile search for %s ip1=%s ip2=%s port=%u icmp=%u:%u l7proto=%s ssid='%s' hostname='%s'\n",
proto_name(l3proto), s, sr, port, icmp_type, icmp_code, l7proto_str(l7proto), ssid ? ssid : "", hostname ? hostname : "");
DLOG("desync profile search for %s ip1=%s ip2=%s port=%u icmp=%u:%u l7proto=%s ssid='%s' mark=0x%08X hostname='%s'\n",
proto_name(l3proto), s, sr, port, icmp_type, icmp_code, l7proto_str(l7proto), ssid ? ssid : "", fwmark, hostname ? hostname : "");
}
else
DLOG("desync profile search for %s ip=%s port=%u icmp=%u:%u l7proto=%s ssid='%s' hostname='%s'\n",
proto_name(l3proto), s, port, icmp_type, icmp_code, l7proto_str(l7proto), ssid ? ssid : "", hostname ? hostname : "");
DLOG("desync profile search for %s ip=%s port=%u icmp=%u:%u l7proto=%s ssid='%s' mark=0x%08X hostname='%s'\n",
proto_name(l3proto), s, port, icmp_type, icmp_code, l7proto_str(l7proto), ssid ? ssid : "", fwmark, hostname ? hostname : "");
}
if (bCheckDone) *bCheckDone = false;
LIST_FOREACH(dpl, head, next)
{
if (dp_match(&dpl->dp, l3proto, ip, ip6, ipr, ipr6, port, icmp_type, icmp_code, hostname, bNoSubdom, l7proto, ssid, bCheckDone, bCheckResult, bExcluded))
if (dp_match(&dpl->dp, &match))
{
DLOG("desync profile %u (%s) matches\n", dpl->dp.n, PROFILE_NAME(&dpl->dp));
return &dpl->dp;
@@ -525,7 +557,7 @@ static bool send_delayed(t_ctrack *ctrack)
return true;
}
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)
static bool reasm_start(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)
@@ -543,7 +575,7 @@ static bool reasm_start(t_ctrack *ctrack, t_reassemble *reasm, uint8_t proto, ui
DLOG("unexpected large payload for reassemble: size=%zu\n", sz);
return false;
}
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)
static bool reasm_client_start(t_ctrack *ctrack, uint8_t proto, t_l7payload pl, size_t sz, size_t szMax, const uint8_t *data_payload, size_t len_payload)
{
if (!ctrack) return false;
// if pcounter==0 it means we dont know server window size - no incoming packets redirected ?
@@ -553,10 +585,11 @@ static bool reasm_client_start(t_ctrack *ctrack, uint8_t proto, size_t sz, size_
// 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);
DLOG("reasm cancelled because server window size %u is smaller than expected reasm size %zu\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);
ctrack->reasm_client_payload = pl;
return reasm_start(&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, uint32_t seq, const uint8_t *data_payload, size_t len_payload)
{
@@ -589,6 +622,7 @@ static void reasm_client_stop(t_ctrack *ctrack, const char *dlog_msg)
{
DLOG("%s", dlog_msg);
ReasmClear(&ctrack->reasm_client);
ctrack->reasm_client_payload = L7P_UNKNOWN;
}
send_delayed(ctrack);
}
@@ -609,7 +643,8 @@ 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.server.pcounter : ctrack->pos.client.pcounter) == 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) ||
(!ctrack && 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");
@@ -681,7 +716,7 @@ static bool check_pos_to(const t_ctrack_position *pos, const struct packet_range
if (pos)
{
ps = pos_get(pos, range->to.mode);
return (ps < range->to.pos) || !range->upper_cutoff && (ps == range->to.pos);
return (ps < range->to.pos) || (!range->upper_cutoff && (ps == range->to.pos));
}
else
return false;
@@ -699,7 +734,7 @@ static bool check_pos_range(const t_ctrack_position *pos, const struct packet_ra
}
static bool replay_queue(struct rawpacket_tailhead *q);
static bool replay_queue(struct rawpacket_queue *q);
static bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname, bool hostname_is_ip)
{
@@ -729,25 +764,20 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr
if (!params.cache_hostname)
{
*hostname = 0;
return true;
return false;
}
if (params.debug)
{
char s[40];
char s[INET6_ADDRSTRLEN];
ntopa46(a4, a6, s, sizeof(s));
DLOG("ipcache hostname search for %s\n", s);
}
ip_cache_item *ipc = ipcacheTouch(&params.ipcache, a4, a6, NULL);
if (!ipc)
{
DLOG_ERR("ipcache_get_hostname: out of memory\n");
return false;
}
if (ipc->hostname)
ip_cache_item *ipc = ipcacheFind(&params.ipcache, a4, a6, NULL);
if (ipc && ipc->hostname)
{
if (params.debug)
{
char s[40];
char s[INET6_ADDRSTRLEN];
ntopa46(a4, a6, s, sizeof(s));
DLOG("got cached hostname for %s : %s (is_ip=%u)\n", s, ipc->hostname, ipc->hostname_is_ip);
}
@@ -756,31 +786,36 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr
}
else
*hostname = 0;
return true;
return *hostname;
}
static void ipcache_update_ttl(t_ctrack *ctrack, const struct in_addr *a4, const struct in6_addr *a6, const char *iface)
{
// no need to cache ttl in server mode because first packet is incoming
if (ctrack && !params.server)
{
ip_cache_item *ipc = ipcacheTouch(&params.ipcache, a4, a6, iface);
if (!ipc)
{
DLOG_ERR("ipcache: out of memory\n");
return;
}
ip_cache_item *ipc;
if (ctrack->incoming_ttl)
{
ipc = ipcacheTouch(&params.ipcache, a4, a6, iface);
if (!ipc)
{
DLOG_ERR("ipcache: out of memory\n");
return;
}
if (ipc->ttl != ctrack->incoming_ttl)
{
DLOG("updated ttl cache\n");
ipc->ttl = ctrack->incoming_ttl;
}
}
else if (ipc->ttl)
else
{
DLOG("got cached ttl %u\n", ipc->ttl);
ctrack->incoming_ttl = ipc->ttl;
ipc = ipcacheFind(&params.ipcache, a4, a6, iface);
if (ipc && ipc->ttl)
{
DLOG("got cached ttl %u\n", ipc->ttl);
ctrack->incoming_ttl = ipc->ttl;
}
}
}
}
@@ -789,10 +824,8 @@ static void ipcache_get_ttl(t_ctrack *ctrack, const struct in_addr *a4, const st
// no need to cache ttl in server mode because first packet is incoming
if (ctrack && !ctrack->incoming_ttl && !params.server)
{
ip_cache_item *ipc = ipcacheTouch(&params.ipcache, a4, a6, iface);
if (!ipc)
DLOG_ERR("ipcache: out of memory\n");
else if (ipc->ttl)
ip_cache_item *ipc = ipcacheFind(&params.ipcache, a4, a6, iface);
if (ipc && ipc->ttl)
{
DLOG("got cached ttl %u\n", ipc->ttl);
ctrack->incoming_ttl = ipc->ttl;
@@ -810,20 +843,26 @@ static bool desync_get_result(uint8_t *verdict)
DLOG_ERR("desync function returned more than one result : %d\n", rescount);
goto err;
}
// absence of the return value or nil mean VERDICT_PASS
if (rescount)
{
if (!lua_isinteger(params.L, -1))
if (lua_isnil(params.L, -1))
*verdict = VERDICT_PASS;
else
{
DLOG_ERR("desync function returned non-int result\n");
goto err;
if (!lua_isinteger(params.L, -1))
{
DLOG_ERR("desync function returned non-int result\n");
goto err;
}
lua_Integer lv = lua_tointeger(params.L, -1);
if (lv & ~VERDICT_MASK_VALID_LUA)
{
DLOG_ERR("desync function returned bad int result\n");
goto err;
}
*verdict = (uint8_t)lv;
}
lua_Integer lv = lua_tointeger(params.L, -1);
if (lv & ~VERDICT_MASK_VALID_LUA)
{
DLOG_ERR("desync function returned bad int result\n");
goto err;
}
*verdict = (uint8_t)lv;
}
else
*verdict = VERDICT_PASS; // default result if function returns nothing
@@ -896,7 +935,7 @@ static uint8_t desync(
if (LIST_FIRST(&dp->lua_desync))
{
lua_rawgeti(params.L, LUA_REGISTRYINDEX, params.ref_desync_ctx);
t_lua_desync_context *ctx = (t_lua_desync_context *)luaL_checkudata(params.L, 1, "desync_ctx");
t_lua_desync_context *ctx = (t_lua_desync_context *)luaL_checkudata(params.L, -1, "desync_ctx");
// this is singleton stored in the registry. safe to pop
lua_pop(params.L,1);
@@ -990,7 +1029,6 @@ static uint8_t desync(
lua_pushf_global(params.L, "tcp_mss", "DEFAULT_MSS");
}
ref_arg = luaL_ref(params.L, LUA_REGISTRYINDEX);
ctx->func_n = 1;
LIST_FOREACH(func, &dp->lua_desync, next)
{
@@ -1023,7 +1061,12 @@ static uint8_t desync(
}
lua_rawgeti(params.L, LUA_REGISTRYINDEX, params.ref_desync_ctx);
lua_rawgeti(params.L, LUA_REGISTRYINDEX, ref_arg);
lua_pushf_args(params.L, &func->args, -1, true);
if (!lua_pushf_args(params.L, &func->args, -1, true))
{
// some % or # blobs cannot be resolved
lua_pop(params.L, 3);
goto err;
}
lua_pushf_str(params.L, "func", func->func);
lua_pushf_int(params.L, "func_n", ctx->func_n);
lua_pushf_str(params.L, "func_instance", instance);
@@ -1135,7 +1178,7 @@ static void setup_direction(
if (params.debug)
{
char ip[40];
char ip[INET6_ADDRSTRLEN];
ntopa46(*sdip4, *sdip6, ip, sizeof(ip));
DLOG("%s mode desync profile/ipcache search target ip=%s port=%u\n", params.server ? "server" : "client", ip, *sdport);
}
@@ -1174,6 +1217,7 @@ struct play_state
t_l7proto l7proto;
t_l7payload l7payload;
const char *ssid;
uint32_t fwmark;
bool bReverse, bReverseFixed, bHaveHost;
};
static bool play_prolog(
@@ -1181,7 +1225,8 @@ static bool play_prolog(
const struct dissect *dis,
const t_ctrack_positions *tpos,
bool bReplay,
const char *ifin, const char *ifout)
const char *ifin, const char *ifout,
uint32_t fwmark)
{
ps->verdict = VERDICT_PASS;
@@ -1196,6 +1241,7 @@ static bool play_prolog(
ps->l7proto = L7_UNKNOWN;
ps->l7payload = dis->len_payload ? L7P_UNKNOWN : L7P_EMPTY;
ps->ssid = NULL;
ps->fwmark = fwmark;
const char *ifname;
@@ -1208,8 +1254,7 @@ static bool play_prolog(
return false;
ps->bReverseFixed = ps->bReverse ^ params.server;
setup_direction(dis, ps->bReverseFixed, &ps->src, &ps->dst, &ps->sdip4, &ps->sdip6, &ps->sdport);
ifname = ps->bReverse ? ifin : ifout;
ifname = ps->bReverseFixed ? ifin : ifout;
#ifdef HAS_FILTER_SSID
ps->ssid = wlan_ssid_search_ifname(ifname);
if (ps->ssid) DLOG("found ssid for %s : %s\n", ifname, ps->ssid);
@@ -1220,7 +1265,7 @@ static bool play_prolog(
DLOG("using cached desync profile %u (%s)\n", ps->dp->n, PROFILE_NAME(ps->dp));
else if (!ps->ctrack_replay->dp_search_complete)
{
ps->dp = ps->ctrack_replay->dp = dp_find(&params.desync_profiles, dis->proto, ps->sdip4, ps->sdip6, NULL, NULL, ps->sdport, 0xFF, 0xFF, ps->ctrack_replay->hostname, ps->ctrack_replay->hostname_is_ip, ps->l7proto, ps->ssid, NULL, NULL, NULL);
ps->dp = ps->ctrack_replay->dp = dp_find(&params.desync_profiles, dis->proto, ps->sdip4, ps->sdip6, NULL, NULL, ps->sdport, 0xFF, 0xFF, ps->ctrack_replay->hostname, ps->ctrack_replay->hostname_is_ip, ps->l7proto, ps->ssid, ps->fwmark, NULL, NULL, NULL);
ps->ctrack_replay->dp_search_complete = true;
}
if (!ps->dp)
@@ -1245,7 +1290,7 @@ static bool play_prolog(
// in absence of conntrack guess direction by presence of interface names. won't work on BSD
ps->bReverseFixed = ps->ctrack ? (ps->bReverse ^ params.server) : (ps->bReverse = ifin && *ifin && (!ifout || !*ifout));
setup_direction(dis, ps->bReverseFixed, &ps->src, &ps->dst, &ps->sdip4, &ps->sdip6, &ps->sdport);
ifname = ps->bReverse ? ifin : ifout;
ifname = ps->bReverseFixed ? ifin : ifout;
#ifdef HAS_FILTER_SSID
ps->ssid = wlan_ssid_search_ifname(ifname);
if (ps->ssid) DLOG("found ssid for %s : %s\n", ifname, ps->ssid);
@@ -1263,12 +1308,12 @@ static bool play_prolog(
hostname_is_ip = ps->ctrack->hostname_is_ip;
if (!hostname && !ps->bReverse)
{
if (ipcache_get_hostname(ps->sdip4, ps->sdip6, ps->host, sizeof(ps->host), &hostname_is_ip) && *ps->host)
if (ipcache_get_hostname(ps->sdip4, ps->sdip6, ps->host, sizeof(ps->host), &hostname_is_ip))
if (!(hostname = ps->ctrack->hostname = strdup(ps->host)))
DLOG_ERR("strdup(host): out of memory\n");
}
}
ps->dp = dp_find(&params.desync_profiles, dis->proto, ps->sdip4, ps->sdip6, NULL, NULL, ps->sdport, 0xFF, 0xFF, hostname, hostname_is_ip, ps->l7proto, ps->ssid, NULL, NULL, NULL);
ps->dp = dp_find(&params.desync_profiles, dis->proto, ps->sdip4, ps->sdip6, NULL, NULL, ps->sdport, 0xFF, 0xFF, hostname, hostname_is_ip, ps->l7proto, ps->ssid, ps->fwmark, NULL, NULL, NULL);
if (ps->ctrack)
{
ps->ctrack->dp = ps->dp;
@@ -1356,7 +1401,7 @@ static bool dp_rediscovery(struct play_state *ps)
ps->dp = dp_find(&params.desync_profiles, ps->dis->proto, ps->sdip4, ps->sdip6, NULL, NULL, ps->sdport, 0xFF, 0xFF,
ps->ctrack_replay ? ps->ctrack_replay->hostname : ps->bHaveHost ? ps->host : NULL,
ps->ctrack_replay ? ps->ctrack_replay->hostname_is_ip : bHostIsIp,
ps->l7proto, ps->ssid,
ps->l7proto, ps->ssid, ps->fwmark,
&bCheckDone, &bCheckResult, &bCheckExcluded);
if (ps->ctrack_replay)
{
@@ -1434,7 +1479,7 @@ static uint8_t dpi_desync_tcp_packet_play(
{
struct play_state ps;
if (!play_prolog(&ps, dis, tpos, !!replay_piece_count, ifin, ifout))
if (!play_prolog(&ps, dis, tpos, !!replay_piece_count, ifin, ifout, fwmark))
return ps.verdict;
uint32_t desync_fwmark = fwmark | params.desync_fwmark;
@@ -1451,7 +1496,8 @@ static uint8_t dpi_desync_tcp_packet_play(
{L7P_HTTP_REPLY,L7_HTTP,IsHttpReply,false},
{L7P_XMPP_STREAM,L7_XMPP,IsXMPPStream,false},
{L7P_XMPP_PROCEED,L7_XMPP,IsXMPPProceedTLS,false},
{L7P_XMPP_FEATURES,L7_XMPP,IsXMPPFeatures,false}
{L7P_XMPP_FEATURES,L7_XMPP,IsXMPPFeatures,false},
{L7P_BT_HANDSHAKE,L7_BT,IsBTHandshake,false}
};
protocol_probe(testers, sizeof(testers) / sizeof(*testers), dis->data_payload, dis->len_payload, ps.ctrack, &ps.l7proto, &ps.l7payload);
@@ -1531,10 +1577,11 @@ static uint8_t dpi_desync_tcp_packet_play(
if (!ps.ctrack_replay || ReasmIsEmpty(&ps.ctrack_replay->reasm_client))
{
t_protocol_probe testers[] = {
{L7P_TLS_CLIENT_HELLO,L7_TLS,IsTLSClientHelloPartial},
{L7P_TLS_CLIENT_HELLO,L7_TLS,IsTLSClientHelloPartial,false},
{L7P_HTTP_REQ,L7_HTTP,IsHttp,false},
{L7P_XMPP_STREAM,L7_XMPP,IsXMPPStream,false},
{L7P_XMPP_STARTTLS,L7_XMPP,IsXMPPStartTLS,false}
{L7P_XMPP_STARTTLS,L7_XMPP,IsXMPPStartTLS,false},
{L7P_BT_HANDSHAKE,L7_BT,IsBTHandshake,false}
};
protocol_probe(testers, sizeof(testers) / sizeof(*testers), rdata_payload, rlen_payload, ps.ctrack_replay, &ps.l7proto, &ps.l7payload);
@@ -1544,18 +1591,13 @@ static uint8_t dpi_desync_tcp_packet_play(
if (ps.tpos && (ps.tpos->client.seq_last - ps.tpos->client.seq0)==1)
{
t_protocol_probe testers[] = {
{L7P_MTPROTO_INITIAL,L7_MTPROTO,IsMTProto}
{L7P_MTPROTO_INITIAL,L7_MTPROTO,IsMTProto,false}
};
protocol_probe(testers, sizeof(testers) / sizeof(*testers), rdata_payload, rlen_payload, ps.ctrack_replay, &ps.l7proto, &ps.l7payload);
}
}
}
if (ps.l7payload==L7P_HTTP_REQ)
{
ps.bHaveHost = HttpExtractHost(rdata_payload, rlen_payload, ps.host, sizeof(ps.host));
}
else if (ps.l7payload==L7P_TLS_CLIENT_HELLO || ps.l7proto==L7_TLS && ps.l7payload==L7P_UNKNOWN && ps.ctrack_replay && !ReasmIsEmpty(&ps.ctrack_replay->reasm_client))
if (ps.l7payload==L7P_TLS_CLIENT_HELLO || ps.ctrack_replay && ps.ctrack_replay->reasm_client_payload==L7P_TLS_CLIENT_HELLO && !ReasmIsEmpty(&ps.ctrack_replay->reasm_client))
{
ps.l7payload = L7P_TLS_CLIENT_HELLO;
@@ -1570,20 +1612,22 @@ static uint8_t dpi_desync_tcp_packet_play(
if (!bReqFull && ReasmIsEmpty(&ps.ctrack->reasm_client) && !is_retransmission(&ps.ctrack->pos.client))
{
// do not reconstruct unexpected large payload (they are feeding garbage ?)
if (!reasm_client_start(ps.ctrack, IPPROTO_TCP, TLSRecordLen(dis->data_payload), TCP_MAX_REASM, dis->data_payload, dis->len_payload))
goto pass_reasm_cancel;
// also do not reconstruct if server window size is low
if (!reasm_client_start(ps.ctrack, IPPROTO_TCP, L7P_TLS_CLIENT_HELLO, TLSRecordLen(dis->data_payload), TCP_MAX_REASM, dis->data_payload, dis->len_payload))
goto rediscover;
}
if (!ReasmIsEmpty(&ps.ctrack->reasm_client))
{
if (rawpacket_queue(&ps.ctrack->delayed, &ps.dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, &ps.ctrack->pos))
if (rawpacket_queue(&ps.ctrack->delayed, &ps.dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, &ps.ctrack->pos, false))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ps.ctrack->delayed));
}
else
{
// likely exceeded packet limit or unlikely out of memory
DLOG_ERR("rawpacket_queue failed !\n");
goto pass_reasm_cancel;
goto reasm_cancel_rediscover;
}
if (ReasmIsFull(&ps.ctrack->reasm_client))
{
@@ -1595,8 +1639,16 @@ static uint8_t dpi_desync_tcp_packet_play(
}
ps.bHaveHost = TLSHelloExtractHost(rdata_payload, rlen_payload, ps.host, sizeof(ps.host), true);
}
else
{
reasm_client_cancel(ps.ctrack);
if (ps.l7payload==L7P_HTTP_REQ)
ps.bHaveHost = HttpExtractHost(rdata_payload, rlen_payload, ps.host, sizeof(ps.host));
}
}
// UNSOLVED: if reasm is cancelled all packets except the last are passed as is without lua desync
rediscover:
if (!dp_rediscovery(&ps))
goto pass_reasm_cancel;
@@ -1607,6 +1659,13 @@ pass:
pass_reasm_cancel:
reasm_client_cancel(ps.ctrack);
goto pass;
reasm_cancel_rediscover:
reasm_client_cancel(ps.ctrack);
rdata_payload = dis->data_payload;
rlen_payload = dis->len_payload;
ps.l7payload = L7P_UNKNOWN; // could be middle packet
goto rediscover;
}
// return : true - should continue, false - should stop with verdict
@@ -1627,6 +1686,7 @@ static void udp_standard_protocol_probe(const uint8_t *data_payload, size_t len_
{L7P_DHT,L7_DHT,IsDht,false},
{L7P_DTLS_CLIENT_HELLO,L7_DTLS,IsDTLSClientHello,false},
{L7P_DTLS_SERVER_HELLO,L7_DTLS,IsDTLSServerHello,false},
{L7P_UTP_BT_HANDSHAKE,L7_UTP_BT,IsUTP_BTHandshake,false},
{L7P_WIREGUARD_INITIATION,L7_WIREGUARD,IsWireguardHandshakeInitiation,false},
{L7P_WIREGUARD_RESPONSE,L7_WIREGUARD,IsWireguardHandshakeResponse,false},
{L7P_WIREGUARD_COOKIE,L7_WIREGUARD,IsWireguardHandshakeCookie,false},
@@ -1640,11 +1700,15 @@ static const uint8_t *dns_extract_name(const uint8_t *a, const uint8_t *b, const
{
size_t nl, off;
const uint8_t *p;
bool bptr = (*a & 0xC0)==0xC0;
bool bptr;
uint8_t x,y;
if (!name_size) return NULL;
bptr = (*a & 0xC0)==0xC0;
if (bptr)
{
if (a>=e) return NULL;
if (a+1>=e) return NULL;
// name pointer
off = (*a & 0x3F)<<8 | a[1];
p = b + off;
@@ -1656,66 +1720,115 @@ static const uint8_t *dns_extract_name(const uint8_t *a, const uint8_t *b, const
if (p>=e) return NULL;
for (nl=0; *p ;)
{
if ((p+*p+1)>=e || (*p+1)>=(name_size-nl)) return NULL;
if (nl) name[nl++] = '.';
memcpy(name + nl, p + 1, *p);
nl += *p;
p += *p + 1;
if (nl)
{
if (nl>=name_size) return NULL;
name[nl++] = '.';
}
// do not support mixed ptr+real
if ((*p & 0xC0) || (p+*p+1)>=e || (*p+1)>=(name_size-nl)) return NULL;
for(y=*p++,x=0 ; x<y ; x++,p++) name[nl+x] = tolower(*p);
nl += y;
}
if (nl>=name_size) return NULL;
name[nl] = 0;
return bptr ? a+2 : p+1;
}
static bool dns_skip_name(const uint8_t **a, size_t *len)
{
// 11 higher bits indicate pointer
// lazy skip name. mixed compressed/uncompressed names are supported
for(;;)
{
if (*len<2) return false;
if ((**a & 0xC0)==0xC0)
{
// pointer is the end
(*a)+=2; (*len)-=2;
break;
}
if (!**a)
{
// zero length is the end
(*a)++; (*len)--;
break;
}
if (*len<(**a+1)) return false;
*len-=**a+1;
*a+=**a+1;
}
return true;
}
static bool feed_dns_response(const uint8_t *a, size_t len)
{
if (!params.cache_hostname) return true;
// check of minimum header length and response flag
uint16_t k, off, dlen, qcount = a[4]<<8 | a[5], acount = a[6]<<8 | a[7];
char s_ip[40];
uint16_t k, typ, off, dlen, qcount = a[4]<<8 | a[5], acount = a[6]<<8 | a[7];
char s_ip[INET6_ADDRSTRLEN];
const uint8_t *b = a, *p;
const uint8_t *e = b + len;
size_t nl;
char name[256] = "";
if (len<12 || !(a[2]&0x80)) return false;
a+=12; len-=12;
for(k=0;k<qcount;k++)
if (!qcount || len<12 || !(a[2]&0x80)) return false;
if (!acount)
{
DLOG("skipping DNS response without answer\n");
return false;
}
a+=12; len-=12;
for(k=0,*name = 0 ; k<qcount ; k++)
{
if (*name) return false; // we do not support multiple queries with names
// remember original query name
if (!(p = dns_extract_name(a, b, e, name, sizeof(name)))) return false;
len -= p-a;
if ((len<4) || p[2] || p[3]!=1) return false;
typ = pntoh16(p);
// must be A or AAAA query. others are not interesting
if ((len<4) || p[0] || p[1]!=1 && p[1]!=28 || p[2] || p[3]!=1) return false;
if (typ!=1 && typ!=28)
{
DLOG("skipping DNS query type %u for '%s'\n", typ, name);
return false;
}
else
{
DLOG("DNS query type %u for '%s'\n", typ, name);
}
// skip type, class
a=p+4; len-=4;
}
if (!*name) return false;
for(k=0;k<acount;k++)
{
// 11 higher bits indicate pointer
if (len<12 || (*a & 0xC0)!=0xC0) return false;
dlen = a[10]<<8 | a[11];
if (len<(dlen+12)) return false;
if (a[4]==0 && a[5]==1 && a[2]==0) // IN class and higher byte of type = 0
if (!dns_skip_name(&a,&len)) return false;
if (len<10) return false;
dlen = a[8]<<8 | a[9];
if (len<(dlen+10)) return false;
if (a[2]==0 && a[3]==1) // IN class
{
switch(a[3])
typ = pntoh16(a);
switch(typ)
{
case 1: // A
if (dlen!=4) break;
if (params.debug && inet_ntop(AF_INET, a+12, s_ip, sizeof(s_ip)))
DLOG("DNS response : %s\n", s_ip);
ipcache_put_hostname((struct in_addr *)(a+12), NULL, name, false);
if (params.debug && inet_ntop(AF_INET, a+10, s_ip, sizeof(s_ip)))
DLOG("DNS response type %u : %s\n", typ, s_ip);
ipcache_put_hostname((struct in_addr *)(a+10), NULL, name, false);
break;
case 28: // AAAA
if (dlen!=16) break;
if (params.debug && inet_ntop(AF_INET6, a+12, s_ip, sizeof(s_ip)))
DLOG("DNS response : %s\n", s_ip);
ipcache_put_hostname(NULL, (struct in6_addr *)(a+12), name, false);
if (params.debug && inet_ntop(AF_INET6, a+10, s_ip, sizeof(s_ip)))
DLOG("DNS response type %u : %s\n", typ, s_ip);
ipcache_put_hostname(NULL, (struct in6_addr *)(a+10), name, false);
break;
default:
DLOG("skipping DNS response type %u\n", typ);
}
}
len -= 12+dlen; a += 12+dlen;
len -= 10+dlen; a += 10+dlen;
}
return true;
}
@@ -1730,7 +1843,7 @@ static uint8_t dpi_desync_udp_packet_play(
{
struct play_state ps;
if (!play_prolog(&ps, dis, tpos, !!replay_piece_count, ifin, ifout))
if (!play_prolog(&ps, dis, tpos, !!replay_piece_count, ifin, ifout, fwmark))
return ps.verdict;
uint32_t desync_fwmark = fwmark | params.desync_fwmark;
@@ -1773,7 +1886,7 @@ static uint8_t dpi_desync_udp_packet_play(
else
{
DLOG("QUIC reasm is too long. cancelling.\n");
goto pass_reasm_cancel;
goto rediscover_cancel;
}
}
size_t hello_offset, hello_len, defrag_len = sizeof(defrag);
@@ -1796,19 +1909,19 @@ static uint8_t dpi_desync_udp_packet_play(
if (bIsHello && !bReqFull && ReasmIsEmpty(&ps.ctrack->reasm_client))
{
// preallocate max buffer to avoid reallocs that cause memory copy
if (!reasm_client_start(ps.ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len))
goto pass_reasm_cancel;
if (!reasm_client_start(ps.ctrack, IPPROTO_UDP, L7P_QUIC_INITIAL, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len))
goto rediscover_cancel;
}
if (!ReasmIsEmpty(&ps.ctrack->reasm_client))
{
if (rawpacket_queue(&ps.ctrack->delayed, &ps.dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, &ps.ctrack->pos))
if (rawpacket_queue(&ps.ctrack->delayed, &ps.dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, &ps.ctrack->pos, false))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ps.ctrack->delayed));
}
else
{
DLOG_ERR("rawpacket_queue failed !\n");
goto pass_reasm_cancel;
goto rediscover_cancel;
}
if (bReqFull)
{
@@ -1838,17 +1951,17 @@ static uint8_t dpi_desync_udp_packet_play(
if (ReasmIsEmpty(&ps.ctrack->reasm_client))
{
// preallocate max buffer to avoid reallocs that cause memory copy
if (!reasm_client_start(ps.ctrack, IPPROTO_UDP, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len))
goto pass_reasm_cancel;
if (!reasm_client_start(ps.ctrack, IPPROTO_UDP, L7P_QUIC_INITIAL, UDP_MAX_REASM, UDP_MAX_REASM, clean, clean_len))
goto rediscover_cancel;
}
if (rawpacket_queue(&ps.ctrack->delayed, &ps.dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, &ps.ctrack->pos))
if (rawpacket_queue(&ps.ctrack->delayed, &ps.dst, fwmark, desync_fwmark, ifin, ifout, dis->data_pkt, dis->len_pkt, dis->len_payload, &ps.ctrack->pos, false))
{
DLOG("DELAY desync until reasm is complete (#%u)\n", rawpacket_queue_count(&ps.ctrack->delayed));
}
else
{
DLOG_ERR("rawpacket_queue failed !\n");
goto pass_reasm_cancel;
goto rediscover_cancel;
}
return ct_new_postnat_fix(ps.ctrack, dis, mod_pkt, len_mod_pkt);
}
@@ -1873,18 +1986,16 @@ static uint8_t dpi_desync_udp_packet_play(
feed_dns_response(dis->data_payload, dis->len_payload);
} // len_payload
// UNSOLVED: if reasm is cancelled all packets except the last are passed as is without lua desync
rediscover_cancel:
reasm_client_cancel(ps.ctrack);
if (!dp_rediscovery(&ps))
goto pass;
ps.verdict = desync(ps.dp, fwmark, ifin, ifout, ps.bReverseFixed, ps.ctrack_replay, tpos, ps.l7payload, ps.l7proto, dis, ps.sdip4, ps.sdip6, ps.sdport, mod_pkt, len_mod_pkt, replay_piece, replay_piece_count, reasm_offset, NULL, 0, data_decrypt, len_decrypt);
pass:
return (!ps.bReverse && (ps.verdict & VERDICT_MASK) == VERDICT_DROP) ? ct_new_postnat_fix(ps.ctrack, dis, mod_pkt, len_mod_pkt) : ps.verdict;
pass_reasm_cancel:
reasm_client_cancel(ps.ctrack);
goto pass;
return (!ps.bReverseFixed && (ps.verdict & VERDICT_MASK) == VERDICT_DROP) ? ct_new_postnat_fix(ps.ctrack, dis, mod_pkt, len_mod_pkt) : ps.verdict;
}
// conntrack is supported only for RELATED icmp
@@ -1944,7 +2055,7 @@ static uint8_t dpi_desync_icmp_packet(
// invert direction. they are answering to this packet
bReverse = !bReverse;
DLOG("found conntrack entry. inverted reverse=%u\n",bReverse);
if (ctrack->dp_search_complete)
if (ctrack->dp_search_complete && ctrack->dp)
{
// RELATED icmp processed within base connection profile
dp = ctrack->dp;
@@ -1981,8 +2092,8 @@ static uint8_t dpi_desync_icmp_packet(
hostname = ctrack->hostname;
hostname_is_ip = ctrack->hostname_is_ip;
}
else if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL, dis->ip6 ? &dis->ip6->ip6_dst : NULL, host, sizeof(host), &hostname_is_ip) && *host ||
ipcache_get_hostname(dis->ip ? &dis->ip->ip_src : NULL, dis->ip6 ? &dis->ip6->ip6_src : NULL, host, sizeof(host), &hostname_is_ip) && *host)
else if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL, dis->ip6 ? &dis->ip6->ip6_dst : NULL, host, sizeof(host), &hostname_is_ip) ||
ipcache_get_hostname(dis->ip ? &dis->ip->ip_src : NULL, dis->ip6 ? &dis->ip6->ip6_src : NULL, host, sizeof(host), &hostname_is_ip))
{
hostname = host;
}
@@ -1994,7 +2105,7 @@ static uint8_t dpi_desync_icmp_packet(
dis->ip ? &dis->ip->ip_src : NULL, dis->ip6 ? &dis->ip6->ip6_src : NULL,
0, dis->icmp->icmp_type, dis->icmp->icmp_code,
hostname, hostname_is_ip,
L7_UNKNOWN, ssid, NULL, NULL, NULL);
L7_UNKNOWN, ssid, fwmark, NULL, NULL, NULL);
if (!dp)
{
DLOG("matching desync profile not found\n");
@@ -2029,7 +2140,7 @@ static uint8_t dpi_desync_ip_packet(
if (!!dis->ip == !!dis->ip6) return verdict;
struct sockaddr_storage src, dst;
const char *ssid;
const char *ssid = NULL;
struct desync_profile *dp;
extract_endpoints(dis->ip, dis->ip6, NULL, NULL, &src, &dst);
@@ -2048,8 +2159,8 @@ static uint8_t dpi_desync_ip_packet(
bool hostname_is_ip = false;
const char *hostname = NULL;
char host[256];
if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL, dis->ip6 ? &dis->ip6->ip6_dst : NULL, host, sizeof(host), &hostname_is_ip) && *host ||
ipcache_get_hostname(dis->ip ? &dis->ip->ip_src : NULL, dis->ip6 ? &dis->ip6->ip6_src : NULL, host, sizeof(host), &hostname_is_ip) && *host)
if (ipcache_get_hostname(dis->ip ? &dis->ip->ip_dst : NULL, dis->ip6 ? &dis->ip6->ip6_dst : NULL, host, sizeof(host), &hostname_is_ip) ||
ipcache_get_hostname(dis->ip ? &dis->ip->ip_src : NULL, dis->ip6 ? &dis->ip6->ip6_src : NULL, host, sizeof(host), &hostname_is_ip))
{
hostname = host;
}
@@ -2060,7 +2171,7 @@ static uint8_t dpi_desync_ip_packet(
dis->ip ? &dis->ip->ip_src : NULL, dis->ip6 ? &dis->ip6->ip6_src : NULL,
0, 0xFF, 0xFF,
hostname, hostname_is_ip,
L7_UNKNOWN, ssid, NULL, NULL, NULL);
L7_UNKNOWN, ssid, fwmark, NULL, NULL, NULL);
if (!dp)
{
DLOG("matching desync profile not found\n");
@@ -2097,37 +2208,30 @@ static uint8_t dpi_desync_packet_play(
if (!!dis.ip != !!dis.ip6)
{
packet_debug(!!replay_piece_count, &dis);
// fix csum if unmodified and if OS can pass wrong csum to queue (depends on OS)
// modified means we have already fixed the checksum or made it invalid intentionally
// this is the only point we VIOLATE const to fix the checksum in the original buffer to avoid copying to mod_pkt
switch (dis.proto)
if (dis.tcp)
{
case IPPROTO_TCP:
if (dis.tcp)
{
verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &dis, mod_pkt, len_mod_pkt);
verdict_tcp_csum_fix(verdict, (struct tcphdr *)dis.tcp, dis.transport_len, dis.ip, dis.ip6);
}
break;
case IPPROTO_UDP:
if (dis.udp)
{
verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &dis, mod_pkt, len_mod_pkt);
verdict_udp_csum_fix(verdict, (struct udphdr *)dis.udp, dis.transport_len, dis.ip, dis.ip6);
}
break;
case IPPROTO_ICMP:
case IPPROTO_ICMPV6:
if (dis.icmp)
{
verdict = dpi_desync_icmp_packet(fwmark, ifin, ifout, &dis, mod_pkt, len_mod_pkt);
verdict_icmp_csum_fix(verdict, (struct icmp46 *)dis.icmp, dis.transport_len, dis.ip6);
}
break;
default:
verdict = dpi_desync_ip_packet(fwmark, ifin, ifout, &dis, mod_pkt, len_mod_pkt);
verdict = dpi_desync_tcp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &dis, mod_pkt, len_mod_pkt);
verdict_tcp_csum_fix(verdict, (struct tcphdr *)dis.tcp, dis.transport_len, dis.ip, dis.ip6);
}
else if (dis.udp)
{
verdict = dpi_desync_udp_packet_play(replay_piece, replay_piece_count, reasm_offset, fwmark, ifin, ifout, tpos, &dis, mod_pkt, len_mod_pkt);
verdict_udp_csum_fix(verdict, (struct udphdr *)dis.udp, dis.transport_len, dis.ip, dis.ip6);
}
else if (dis.icmp)
{
verdict = dpi_desync_icmp_packet(fwmark, ifin, ifout, &dis, mod_pkt, len_mod_pkt);
verdict_icmp_csum_fix(verdict, (struct icmp46 *)dis.icmp, dis.transport_len, dis.ip6);
}
else
verdict = dpi_desync_ip_packet(fwmark, ifin, ifout, &dis, mod_pkt, len_mod_pkt);
}
else
DLOG("invalid packet - neither ipv4 or ipv6\n");
return verdict;
}
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)
@@ -2140,17 +2244,29 @@ uint8_t dpi_desync_packet(uint32_t fwmark, const char *ifin, const char *ifout,
static bool replay_queue(struct rawpacket_tailhead *q)
static bool replay_queue(struct rawpacket_queue *q)
{
struct rawpacket *rp;
size_t offset;
unsigned int i, count;
bool b = true;
uint8_t mod[RECONSTRUCT_MAX_SIZE];
size_t modlen;
uint32_t seq0;
t_ctrack_position *pos;
bool b = true, bseq;
for (i = 0, offset = 0, count = rawpacket_queue_count(q); (rp = rawpacket_dequeue(q)); offset += rp->len_payload, rawpacket_free(rp), i++)
for (i = 0, offset = 0, count = rawpacket_queue_count(q); (rp = rawpacket_dequeue(q)); rawpacket_free(rp), i++)
{
// TCP: track reasm_offset using sequence numbers
if ((bseq = rp->tpos_present && rp->tpos.ipproto==IPPROTO_TCP))
{
pos = rp->server_side ? &rp->tpos.server : &rp->tpos.client;
if (i)
offset = pos->seq_last - seq0;
else
seq0 = pos->seq_last;
}
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->tpos_present ? &rp->tpos : NULL, rp->packet, rp->len, mod, &modlen);
@@ -2168,6 +2284,9 @@ static bool replay_queue(struct rawpacket_tailhead *q)
DLOG("DROPPING delayed packet #%u\n", i+1);
break;
}
if (!bseq)
offset += rp->len_payload;
}
return b;
}
+5 -4
View File
@@ -18,6 +18,7 @@ bool pf_parse(const char *s, port_filter *pf)
if (*s=='*' && s[1]==0)
{
pf->from=1; pf->to=0xFFFF;
pf->neg=false;
return true;
}
if (*s=='~')
@@ -172,27 +173,27 @@ bool packet_range_parse(const char *s, struct packet_range *range)
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr)
{
char s_ip[16];
char s_ip[INET_ADDRSTRLEN];
*s_ip=0;
inet_ntop(AF_INET, &cidr->addr, s_ip, sizeof(s_ip));
snprintf(s,s_len,cidr->preflen<32 ? "%s/%u" : "%s", s_ip, cidr->preflen);
}
void print_cidr4(const struct cidr4 *cidr)
{
char s[19];
char s[INET_ADDRSTRLEN+4];
str_cidr4(s,sizeof(s),cidr);
printf("%s",s);
}
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr)
{
char s_ip[40];
char s_ip[INET6_ADDRSTRLEN];
*s_ip=0;
inet_ntop(AF_INET6, &cidr->addr, s_ip, sizeof(s_ip));
snprintf(s,s_len,cidr->preflen<128 ? "%s/%u" : "%s", s_ip, cidr->preflen);
}
void print_cidr6(const struct cidr6 *cidr)
{
char s[44];
char s[INET6_ADDRSTRLEN+4];
str_cidr6(s,sizeof(s),cidr);
printf("%s",s);
}
+33 -9
View File
@@ -2,6 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "helpers.h"
#define ZCHUNK 16384
#define BUFMIN 128
@@ -14,6 +15,7 @@ int z_readfile(FILE *F, char **buf, size_t *size, size_t extra_alloc)
unsigned char in[ZCHUNK];
size_t bufsize;
void *newbuf;
size_t rd;
memset(&zs, 0, sizeof(zs));
@@ -25,20 +27,21 @@ int z_readfile(FILE *F, char **buf, size_t *size, size_t extra_alloc)
do
{
zs.avail_in = fread(in, 1, sizeof(in), F);
if (ferror(F))
if (!fread_safe(in, 1, sizeof(in), F, &rd))
{
r = Z_ERRNO;
goto zerr;
}
if (!zs.avail_in)
if (!rd)
{
// file is not full
r = Z_DATA_ERROR;
goto zerr;
}
zs.avail_in = rd;
zs.next_in = in;
do
for(;;)
{
if ((bufsize - *size) < BUFMIN)
{
@@ -53,20 +56,41 @@ int z_readfile(FILE *F, char **buf, size_t *size, size_t extra_alloc)
}
zs.avail_out = bufsize - *size;
zs.next_out = (unsigned char*)(*buf + *size);
r = inflate(&zs, Z_NO_FLUSH);
if (r != Z_OK && r != Z_STREAM_END) goto zerr;
*size = bufsize - zs.avail_out;
} while (r == Z_OK && zs.avail_in);
if (r==Z_STREAM_END) break;
if (r==Z_BUF_ERROR)
{
if (zs.avail_in)
goto zerr;
else
{
r = Z_OK;
break;
}
}
if (r!=Z_OK) goto zerr;
}
} while (r == Z_OK);
if (*size < bufsize)
{
// free extra space
if ((newbuf = realloc(*buf, *size + extra_alloc))) *buf = newbuf;
if (*size + extra_alloc)
{
// free extra space
if ((newbuf = realloc(*buf, *size + extra_alloc))) *buf = newbuf;
}
else
{
free(*buf);
*buf = NULL;
}
}
inflateEnd(&zs);
return Z_OK;
return r;
zerr:
inflateEnd(&zs);
+298 -174
View File
@@ -9,9 +9,15 @@
#include <stdlib.h>
#include <ctype.h>
#include <libgen.h>
#include <limits.h>
#include <errno.h>
#include <sys/param.h>
#ifdef __CYGWIN__
#include <sys/cygwin.h>
#endif
#define UNIQ_SORT \
{ \
size_t i, j, u; \
@@ -29,26 +35,25 @@ int unique_ssize_t(ssize_t *pu, int ct) UNIQ_SORT
static int cmp_size_t(const void * a, const void * b)
{
return *(size_t*)a < *(size_t*)b ? -1 : *(size_t*)a > *(size_t*)b;
return *(const size_t*)a < *(const size_t*)b ? -1 : *(const size_t*)a > *(const size_t*)b;
}
void qsort_size_t(size_t *array, int ct)
{
qsort(array,ct,sizeof(*array),cmp_size_t);
qsort(array, ct, sizeof(*array), cmp_size_t);
}
static int cmp_ssize_t(const void * a, const void * b)
{
return *(ssize_t*)a < *(ssize_t*)b ? -1 : *(ssize_t*)a > *(ssize_t*)b;
return *(const ssize_t*)a < *(const ssize_t*)b ? -1 : *(const ssize_t*)a > *(const ssize_t*)b;
}
void qsort_ssize_t(ssize_t *array, int ct)
{
qsort(array,ct,sizeof(*array),cmp_ssize_t);
qsort(array, ct, sizeof(*array), cmp_ssize_t);
}
int str_index(const char **strs, int count, const char *str)
{
for(int i=0;i<count;i++)
if (!strcmp(strs[i],str)) return i;
for (int i = 0; i < count; i++)
if (!strcmp(strs[i], str)) return i;
return -1;
}
@@ -60,7 +65,7 @@ void rtrim(char *s)
void replace_char(char *s, char from, char to)
{
for(;*s;s++) if (*s==from) *s=to;
for (; *s; s++) if (*s == from) *s = to;
}
const char *strncasestr(const char *s, const char *find, size_t slen)
@@ -88,18 +93,18 @@ const char *strncasestr(const char *s, const char *find, size_t slen)
static inline bool is_letter(char c)
{
return (c>='a' && c<='z') || (c>='A' && c<='Z');
return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
}
static inline bool is_digit(char c)
{
return c>='0' && c<='9';
return c >= '0' && c <= '9';
}
bool is_identifier(const char *p)
{
if (*p!='_' && !is_letter(*p))
if (*p != '_' && !is_letter(*p))
return false;
for(++p;*p;p++)
if (!is_letter(*p) && !is_digit(*p) && *p!='_')
for (++p; *p; p++)
if (!is_letter(*p) && !is_digit(*p) && *p != '_')
return false;
return true;
}
@@ -120,8 +125,7 @@ bool load_file(const char *filename, off_t offset, void *buffer, size_t *buffer_
}
}
*buffer_size = fread(buffer, 1, *buffer_size, F);
if (ferror(F))
if (!fread_safe(buffer, 1, *buffer_size, F, buffer_size))
{
fclose(F);
return false;
@@ -143,7 +147,7 @@ bool save_file(const char *filename, const void *buffer, size_t buffer_size)
return false;
}
fclose(F);
if (wr!=buffer_size)
if (wr != buffer_size)
{
errno = EIO;
return false;
@@ -152,22 +156,22 @@ bool save_file(const char *filename, const void *buffer, size_t buffer_size)
}
bool append_to_list_file(const char *filename, const char *s)
{
FILE *F = fopen(filename,"at");
FILE *F = fopen(filename, "at");
if (!F) return false;
bool bOK = fprintf(F,"%s\n",s)>0;
bool bOK = fprintf(F, "%s\n", s) > 0;
fclose(F);
return bOK;
}
void expand_bits(void *target, const void *source, unsigned int source_bitlen, unsigned int target_bytelen)
{
unsigned int target_bitlen = target_bytelen<<3;
unsigned int bitlen = target_bitlen<source_bitlen ? target_bitlen : source_bitlen;
unsigned int bytelen = bitlen>>3;
unsigned int target_bitlen = target_bytelen << 3;
unsigned int bitlen = target_bitlen < source_bitlen ? target_bitlen : source_bitlen;
unsigned int bytelen = bitlen >> 3;
if ((target_bytelen-bytelen)>=1) memset(target+bytelen,0,target_bytelen-bytelen);
memcpy(target,source,bytelen);
if ((bitlen &= 7)) ((uint8_t*)target)[bytelen] = ((uint8_t*)source)[bytelen] & (~((1 << (8-bitlen)) - 1));
if ((target_bytelen - bytelen) >= 1) memset((uint8_t*)target + bytelen, 0, target_bytelen - bytelen);
memcpy(target, source, bytelen);
if ((bitlen &= 7)) ((uint8_t*)target)[bytelen] = ((uint8_t*)source)[bytelen] & (~((1 << (8 - bitlen)) - 1));
}
// " [fd00::1]" => "fd00::1"
@@ -179,53 +183,53 @@ void expand_bits(void *target, const void *source, unsigned int source_bitlen, u
bool strip_host_to_ip(char *host)
{
size_t l;
char *h,*p;
char *h, *p;
uint8_t addr[16];
for (h = host ; *h==' ' || *h=='\t' ; h++);
for (h = host; *h == ' ' || *h == '\t'; h++);
l = strlen(h);
if (l>=2)
if (l >= 2)
{
if (*h=='[')
if (*h == '[')
{
// ipv6 ?
for (p=++h ; *p && *p!=']' ; p++);
if (*p==']')
for (p = ++h; *p && *p != ']'; p++);
if (*p == ']')
{
l = p-h;
memmove(host,h,l);
host[l]=0;
return inet_pton(AF_INET6, host, addr)>0;
l = p - h;
memmove(host, h, l);
host[l] = 0;
return inet_pton(AF_INET6, host, addr) > 0;
}
}
else
{
if (inet_pton(AF_INET6, h, addr)>0)
if (inet_pton(AF_INET6, h, addr) > 0)
{
// ipv6 ?
if (host!=h)
if (host != h)
{
l = strlen(h);
memmove(host,h,l);
host[l]=0;
memmove(host, h, l);
host[l] = 0;
}
return true;
}
else
{
// ipv4 ?
for (p=h ; *p && *p!=':' ; p++);
l = p-h;
if (host!=h) memmove(host,h,l);
host[l]=0;
return inet_pton(AF_INET, host, addr)>0;
for (p = h; *p && *p != ':'; p++);
l = p - h;
if (host != h) memmove(host, h, l);
host[l] = 0;
return inet_pton(AF_INET, host, addr) > 0;
}
}
}
return false;
}
void ntopa46(const struct in_addr *ip, const struct in6_addr *ip6,char *str, size_t len)
void ntopa46(const struct in_addr *ip, const struct in6_addr *ip6, char *str, size_t len)
{
if (!len) return;
*str = 0;
@@ -235,13 +239,13 @@ void ntopa46(const struct in_addr *ip, const struct in6_addr *ip6,char *str, siz
}
void ntop46(const struct sockaddr *sa, char *str, size_t len)
{
ntopa46(sa->sa_family==AF_INET ? &((struct sockaddr_in*)sa)->sin_addr : NULL,
sa->sa_family==AF_INET6 ? &((struct sockaddr_in6*)sa)->sin6_addr : NULL,
ntopa46(sa->sa_family == AF_INET ? &((struct sockaddr_in*)sa)->sin_addr : NULL,
sa->sa_family == AF_INET6 ? &((struct sockaddr_in6*)sa)->sin6_addr : NULL,
str, len);
}
void ntop46_port(const struct sockaddr *sa, char *str, size_t len)
{
char ip[40];
char ip[INET6_ADDRSTRLEN];
ntop46(sa, ip, sizeof(ip));
switch (sa->sa_family)
{
@@ -265,32 +269,32 @@ void print_sockaddr(const struct sockaddr *sa)
uint16_t saport(const struct sockaddr *sa)
{
return ntohs(sa->sa_family==AF_INET ? ((struct sockaddr_in*)sa)->sin_port :
sa->sa_family==AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0);
return ntohs(sa->sa_family == AF_INET ? ((struct sockaddr_in*)sa)->sin_port :
sa->sa_family == AF_INET6 ? ((struct sockaddr_in6*)sa)->sin6_port : 0);
}
bool sa_has_addr(const struct sockaddr *sa)
{
switch(sa->sa_family)
switch (sa->sa_family)
{
case AF_INET:
return ((struct sockaddr_in*)sa)->sin_addr.s_addr!=INADDR_ANY;
case AF_INET6:
return memcmp(((struct sockaddr_in6*)sa)->sin6_addr.s6_addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
default:
return false;
case AF_INET:
return ((struct sockaddr_in*)sa)->sin_addr.s_addr != INADDR_ANY;
case AF_INET6:
return memcmp(((struct sockaddr_in6*)sa)->sin6_addr.s6_addr, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
default:
return false;
}
}
bool seq_within(uint32_t s, uint32_t s1, uint32_t s2)
{
return (s2>=s1 && s>=s1 && s<=s2) || (s2<s1 && (s<=s2 || s>=s1));
return (s2 >= s1 && s >= s1 && s <= s2) || (s2 < s1 && (s <= s2 || s >= s1));
}
bool ipv6_addr_is_zero(const struct in6_addr *a)
{
return !memcmp(a,"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",16);
return !memcmp(a, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", 16);
}
@@ -309,8 +313,8 @@ uint32_t pntoh24(const uint8_t *p)
}
void phton24(uint8_t *p, uint32_t v)
{
p[0] = (uint8_t)(v>>16);
p[1] = (uint8_t)(v>>8);
p[0] = (uint8_t)(v >> 16);
p[1] = (uint8_t)(v >> 8);
p[2] = (uint8_t)v;
}
uint32_t pntoh32(const uint8_t *p)
@@ -319,9 +323,9 @@ uint32_t pntoh32(const uint8_t *p)
}
void phton32(uint8_t *p, uint32_t v)
{
p[0] = (uint8_t)(v>>24);
p[1] = (uint8_t)(v>>16);
p[2] = (uint8_t)(v>>8);
p[0] = (uint8_t)(v >> 24);
p[1] = (uint8_t)(v >> 16);
p[2] = (uint8_t)(v >> 8);
p[3] = (uint8_t)v;
}
uint64_t pntoh48(const uint8_t *p)
@@ -330,11 +334,11 @@ uint64_t pntoh48(const uint8_t *p)
}
void phton48(uint8_t *p, uint64_t v)
{
p[0] = (uint8_t)(v>>40);
p[1] = (uint8_t)(v>>32);
p[2] = (uint8_t)(v>>24);
p[3] = (uint8_t)(v>>16);
p[4] = (uint8_t)(v>>8);
p[0] = (uint8_t)(v >> 40);
p[1] = (uint8_t)(v >> 32);
p[2] = (uint8_t)(v >> 24);
p[3] = (uint8_t)(v >> 16);
p[4] = (uint8_t)(v >> 8);
p[5] = (uint8_t)v;
}
uint64_t pntoh64(const uint8_t *p)
@@ -343,24 +347,24 @@ uint64_t pntoh64(const uint8_t *p)
}
void phton64(uint8_t *p, uint64_t v)
{
p[0] = (uint8_t)(v>>56);
p[1] = (uint8_t)(v>>48);
p[2] = (uint8_t)(v>>40);
p[3] = (uint8_t)(v>>32);
p[4] = (uint8_t)(v>>24);
p[5] = (uint8_t)(v>>16);
p[6] = (uint8_t)(v>>8);
p[0] = (uint8_t)(v >> 56);
p[1] = (uint8_t)(v >> 48);
p[2] = (uint8_t)(v >> 40);
p[3] = (uint8_t)(v >> 32);
p[4] = (uint8_t)(v >> 24);
p[5] = (uint8_t)(v >> 16);
p[6] = (uint8_t)(v >> 8);
p[7] = (uint8_t)v;
}
uint16_t bswap16(uint16_t u)
{
// __builtin_bswap16 is absent in ancient lexra gcc 4.6
return (u>>8) | ((u&0xFF)<<8);
return (u >> 8) | ((u & 0xFF) << 8);
}
uint32_t bswap24(uint32_t u)
{
return (u>>16) & 0xFF | u & 0xFF00 | (u<<16) & 0xFF0000;
return (u >> 16) & 0xFF | u & 0xFF00 | (u << 16) & 0xFF0000;
}
uint64_t bswap48(uint64_t u)
{
@@ -371,39 +375,39 @@ uint64_t bswap48(uint64_t u)
#define INVALID_HEX_DIGIT ((uint8_t)-1)
static inline uint8_t parse_hex_digit(char c)
{
return (c>='0' && c<='9') ? c-'0' : (c>='a' && c<='f') ? c-'a'+0xA : (c>='A' && c<='F') ? c-'A'+0xA : INVALID_HEX_DIGIT;
return (c >= '0' && c <= '9') ? c - '0' : (c >= 'a' && c <= 'f') ? c - 'a' + 0xA : (c >= 'A' && c <= 'F') ? c - 'A' + 0xA : INVALID_HEX_DIGIT;
}
static inline bool parse_hex_byte(const char *s, uint8_t *pbyte)
{
uint8_t u,l;
uint8_t u, l;
u = parse_hex_digit(s[0]);
l = parse_hex_digit(s[1]);
if (u==INVALID_HEX_DIGIT || l==INVALID_HEX_DIGIT)
if (u == INVALID_HEX_DIGIT || l == INVALID_HEX_DIGIT)
{
*pbyte=0;
*pbyte = 0;
return false;
}
else
{
*pbyte=(u<<4) | l;
*pbyte = (u << 4) | l;
return true;
}
}
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size)
{
uint8_t *pe = pbuf+*size;
*size=0;
while(pbuf<pe && *s)
uint8_t *pe = pbuf + *size;
*size = 0;
while (pbuf < pe && *s)
{
if (!parse_hex_byte(s,pbuf))
if (!parse_hex_byte(s, pbuf))
return false;
pbuf++; s+=2; (*size)++;
pbuf++; s += 2; (*size)++;
}
return true;
}
char hex_digit(uint8_t v)
{
return v<=9 ? '0'+v : (v<=0xF) ? v+'A'-0xA : '?';
return v <= 9 ? '0' + v : (v <= 0xF) ? v + 'A' - 0xA : '?';
}
int fprint_localtime(FILE *F)
@@ -412,39 +416,34 @@ int fprint_localtime(FILE *F)
time_t now;
time(&now);
localtime_r(&now,&t);
localtime_r(&now, &t);
return fprintf(F, "%02d.%02d.%04d %02d:%02d:%02d", t.tm_mday, t.tm_mon + 1, t.tm_year + 1900, t.tm_hour, t.tm_min, t.tm_sec);
}
bool file_size(const char *filename, off_t *size)
{
struct stat st;
if (stat(filename,&st)==-1) return false;
*size = st.st_size;
if (stat(filename, &st) == -1) return false;
if (size) *size = st.st_size;
return true;
}
time_t file_mod_time(const char *filename)
{
struct stat st;
return stat(filename,&st)==-1 ? 0 : st.st_mtime;
}
bool file_mod_signature(const char *filename, file_mod_sig *ms)
{
struct stat st;
if (stat(filename,&st)==-1)
if (stat(filename, &st) == -1)
{
FILE_MOD_RESET(ms);
return false;
}
ms->mod_time=st.st_mtime;
ms->size=st.st_size;
ms->mod_time = st.st_mtim;
ms->size = st.st_size;
return true;
}
bool file_open_test(const char *filename, int flags)
{
int fd = open(filename,flags);
if (fd>=0)
int fd = open(filename, flags);
if (fd >= 0)
{
close(fd);
return true;
@@ -453,89 +452,150 @@ bool file_open_test(const char *filename, int flags)
}
void fill_random_bytes(uint8_t *p,size_t sz)
void fill_random_bytes(uint8_t *p, size_t sz)
{
size_t k;
for (k=0 ; (k+1)<sz ; k+=2) phton16(p+k, (uint16_t)random());
if (sz & 1) p[sz-1]=(uint8_t)random();
if (sz)
{
// alignment
if ((size_t)p & 1) { *p = (uint8_t)random(); sz--; p++; }
// random has only 31 bits of entropy. not 32 bits
for (k = 0; (k + 1) < sz; k += 2) *(uint16_t*)(p + k) = (uint16_t)random();
if (sz & 1) p[sz - 1] = (uint8_t)random();
}
}
void fill_random_az(uint8_t *p,size_t sz)
void fill_random_az(uint8_t *p, size_t sz)
{
size_t k;
for(k=0;k<sz;k++) p[k] = 'a'+(random() % ('z'-'a'+1));
for (k = 0; k < sz; k++) p[k] = 'a' + (random() % ('z' - 'a' + 1));
}
void fill_random_az09(uint8_t *p,size_t sz)
void fill_random_az09(uint8_t *p, size_t sz)
{
size_t k;
uint8_t rnd;
for(k=0;k<sz;k++)
for (k = 0; k < sz; k++)
{
rnd = random() % (10 + 'z'-'a'+1);
p[k] = rnd<10 ? rnd+'0' : 'a'+rnd-10;
rnd = random() % (10 + 'z' - 'a' + 1);
p[k] = rnd < 10 ? rnd + '0' : 'a' + rnd - 10;
}
}
#if defined(__FreeBSD__) && __FreeBSD_version <= 1200000
#include <sys/sysctl.h>
int getentropy(void *buf, size_t len)
{
int mib[2];
size_t size = len;
int mib[2];
size_t size = len;
// Check for reasonable length (getentropy limits to 256)
if (len > 256) {
errno = EIO;
return -1;
}
// Check for reasonable length (getentropy limits to 256)
if (len > 256) {
errno = EIO;
return -1;
}
mib[0] = CTL_KERN;
mib[1] = KERN_ARND;
mib[0] = CTL_KERN;
mib[1] = KERN_ARND;
if (sysctl(mib, 2, buf, &size, NULL, 0) == -1) {
return -1;
}
if (sysctl(mib, 2, buf, &size, NULL, 0) == -1) {
return -1;
}
return (size == len) ? 0 : -1;
return (size == len) ? 0 : -1;
}
#endif
bool fill_crypto_random_bytes(uint8_t *p,size_t sz)
ssize_t read_intr(int fd, void *buf, size_t count)
{
ssize_t rd;
while ((rd = read(fd, buf, count)) < 0 && errno == EINTR);
return rd;
}
bool fread_safe(void *ptr, size_t size, size_t nmemb, FILE *F, size_t *rd)
{
size_t result, to_read, total_read = 0;
while (total_read < nmemb)
{
to_read = nmemb - total_read;
errno = 0;
total_read += (result = fread((uint8_t*)ptr + (total_read * size), size, to_read, F));
if (result < to_read)
{
if (ferror(F))
{
if (errno == EINTR)
{
clearerr(F);
continue;
}
*rd = total_read;
return false;
}
break;
}
}
*rd = total_read;
return true;
}
char* fgets_safe(char *s, int size, FILE *stream)
{
char *result;
while (true)
{
errno = 0;
if ((result = fgets(s, size, stream))) return result;
if (ferror(stream))
{
if (errno == EINTR)
{
clearerr(stream);
continue;
}
return NULL;
}
if (feof(stream)) return NULL;
}
}
bool fill_crypto_random_bytes(uint8_t *p, size_t sz)
{
ssize_t rd;
int fd;
#if defined(__linux__) || defined(__CYGWIN__)
for(; sz && (rd=getrandom(p,sz,GRND_NONBLOCK))>0 ; p+=rd, sz-=rd);
for (; sz && (rd = getrandom(p, sz, GRND_NONBLOCK)) > 0; p += rd, sz -= rd);
if (sz)
#elif defined(BSD)
while(sz)
while (sz)
{
rd = sz<256 ? sz : 256; // BSD limitation
if (getentropy(p,rd)) break;
p+=rd; sz-=rd;
rd = sz < 256 ? sz : 256; // BSD limitation
if (getentropy(p, rd)) break;
p += rd; sz -= rd;
}
if (sz)
#endif
{
if ((fd = open("/dev/random",O_NONBLOCK))>=0)
if ((fd = open("/dev/random", O_NONBLOCK)) >= 0)
{
do
{
if ((rd=read(fd,p,sz))>0)
if ((rd = read_intr(fd, p, sz)) > 0)
{
p+=rd; sz-=rd;
p += rd; sz -= rd;
}
} while(sz && rd>0);
} while (sz && rd > 0);
close(fd);
}
if (sz && (fd = open("/dev/urandom",0))>=0)
if (sz && (fd = open("/dev/urandom", 0)) >= 0)
{
do
{
if ((rd=read(fd,p,sz))>0)
if ((rd = read_intr(fd, p, sz)) > 0)
{
p+=rd; sz-=rd;
p += rd; sz -= rd;
}
} while(sz && rd>0);
} while (sz && rd > 0);
close(fd);
}
}
@@ -543,33 +603,33 @@ bool fill_crypto_random_bytes(uint8_t *p,size_t sz)
}
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing")))
__attribute__((optimize("no-strict-aliasing")))
#endif
void bxor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz)
{
for (; sz>=8 ; x1+=8, x2+=8, result+=8, sz-=8)
for (; sz >= 8; x1 += 8, x2 += 8, result += 8, sz -= 8)
*(uint64_t*)result = *(uint64_t*)x1 ^ *(uint64_t*)x2;
for (; sz ; x1++, x2++, result++, sz--)
for (; sz; x1++, x2++, result++, sz--)
*result = *x1 ^ *x2;
}
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing")))
__attribute__((optimize("no-strict-aliasing")))
#endif
void bor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz)
{
for (; sz>=8 ; x1+=8, x2+=8, result+=8, sz-=8)
for (; sz >= 8; x1 += 8, x2 += 8, result += 8, sz -= 8)
*(uint64_t*)result = *(uint64_t*)x1 | *(uint64_t*)x2;
for (; sz ; x1++, x2++, result++, sz--)
for (; sz; x1++, x2++, result++, sz--)
*result = *x1 | *x2;
}
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing")))
__attribute__((optimize("no-strict-aliasing")))
#endif
void band(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz)
{
for (; sz>=8 ; x1+=8, x2+=8, result+=8, sz-=8)
for (; sz >= 8; x1 += 8, x2 += 8, result += 8, sz -= 8)
*(uint64_t*)result = *(uint64_t*)x1 & *(uint64_t*)x2;
for (; sz ; x1++, x2++, result++, sz--)
for (; sz; x1++, x2++, result++, sz--)
*result = *x1 & *x2;
}
@@ -594,17 +654,69 @@ void close_std_and_exit(int code)
bool set_env_exedir(const char *argv0)
{
char *s,*d;
bool bOK=false;
char *s, *d;
bool bOK = false;
if ((s = strdup(argv0)))
{
if ((d = dirname(s)))
bOK = !setenv("EXEDIR",d,1);
{
char d_abs[PATH_MAX];
if (realpath(d, d_abs))
d=d_abs;
bOK = !setenv("EXEDIR", d, 1);
}
free(s);
}
return bOK;
}
// works for existing and new files
bool realpath_any(const char *file, char *pabs)
{
bool b = true;
char *s1=NULL, *s2=NULL;
int res;
size_t l;
#ifdef __CYGWIN__
l = cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, file, NULL, 0);
char *rp_file = (char*)malloc(l);
if (cygwin_conv_path(CCP_WIN_A_TO_POSIX | CCP_ABSOLUTE, file, rp_file, l))
goto err;
#else
#define rp_file file
#endif
if (!realpath(rp_file,pabs))
{
char pa[PATH_MAX], *dir, *base;
if (!(s1 = strdup(rp_file))) goto err;
dir = dirname(s1);
if (!realpath(dir,pa))
goto err;
if (!(s2 = strdup(rp_file))) goto err;
base = basename(s2);
l = strlen(pa);
if (l && pa[l-1]=='/')
res=snprintf(pabs,PATH_MAX,"%s%s",pa, base);
else
res=snprintf(pabs,PATH_MAX,"%s/%s",pa,base);
b = res>0 && res<PATH_MAX;
}
ex:
#ifdef __CYGWIN__
free(rp_file);
#else
#undef rp_file
#endif
free(s1);
free(s2);
return b;
err:
b = false;
goto ex;
}
bool parse_int16(const char *p, int16_t *v)
{
if (*p == '+' || *p == '-' || *p >= '0' && *p <= '9')
@@ -616,34 +728,46 @@ bool parse_int16(const char *p, int16_t *v)
return false;
}
uint32_t mask_from_bitcount(uint32_t zct)
{
return zct<32 ? ~((1u << zct) - 1) : 0;
}
static void mask_from_bitcount6_make(uint32_t zct, struct in6_addr *a)
{
if (zct >= 128)
memset(a->s6_addr,0x00,16);
else
{
int32_t n = (127 - zct) >> 3;
memset(a->s6_addr,0xFF,n);
memset(a->s6_addr+n,0x00,16-n);
a->s6_addr[n] = ~((1u << (zct & 7)) - 1);
}
}
static struct in6_addr ip6_mask[129];
void mask_from_bitcount6_prepare(void)
{
for (int zct=0;zct<=128;zct++) mask_from_bitcount6_make(zct, ip6_mask+zct);
}
const struct in6_addr *mask_from_bitcount6(uint32_t zct)
{
return ip6_mask+zct;
}
time_t boottime(void)
{
struct timespec ts;
return clock_gettime(CLOCK_BOOT_OR_UPTIME, &ts) ? 0 : ts.tv_sec;
}
uint64_t boottime_ms(void)
{
struct timespec ts;
if (clock_gettime(CLOCK_BOOT_OR_UPTIME, &ts))
return 0;
else
return ts.tv_sec*1000ULL + ts.tv_nsec/1000000;
}
#ifdef __CYGWIN__
uint32_t mask_from_bitcount(uint32_t zct)
{
return zct < 32 ? ~((1u << zct) - 1) : 0;
}
static void mask_from_bitcount6_make(uint32_t zct, struct in6_addr *a)
{
if (zct >= 128)
memset(a->s6_addr, 0x00, 16);
else
{
int32_t n = (127 - zct) >> 3;
memset(a->s6_addr, 0xFF, n);
memset(a->s6_addr + n, 0x00, 16 - n);
a->s6_addr[n] = ~((1u << (zct & 7)) - 1);
}
}
static struct in6_addr ip6_mask[129];
void mask_from_bitcount6_prepare(void)
{
for (int zct = 0; zct <= 128; zct++) mask_from_bitcount6_make(zct, ip6_mask + zct);
}
const struct in6_addr *mask_from_bitcount6(uint32_t zct)
{
return ip6_mask + zct;
}
#endif
+18 -8
View File
@@ -12,6 +12,9 @@
#include <fcntl.h>
#define UNARY_PLUS(v) (v>0 ? "+" : "")
//#define MIN(v1,v2) ((v1)<(v2) ? (v1) : (v2))
//#define MAX(v1,v2) ((v1)<(v2) ? (v2) : (v1))
// this saves memory. sockaddr_storage is larger than required. it can be 128 bytes. sockaddr_in6 is 28 bytes.
typedef union
@@ -33,6 +36,10 @@ const char *strncasestr(const char *s,const char *find, size_t slen);
// [a-zA-z][a-zA-Z0-9]*
bool is_identifier(const char *p);
ssize_t read_intr(int fd, void *buf, size_t count);
bool fread_safe(void *ptr, size_t size, size_t nmemb, FILE *F, size_t *rd);
char* fgets_safe(char *s, int size, FILE *stream);
bool load_file(const char *filename, off_t offset, void *buffer, size_t *buffer_size);
bool save_file(const char *filename, const void *buffer, size_t buffer_size);
bool append_to_list_file(const char *filename, const char *s);
@@ -75,13 +82,12 @@ int fprint_localtime(FILE *F);
typedef struct
{
time_t mod_time;
struct timespec mod_time;
off_t size;
} file_mod_sig;
#define FILE_MOD_COMPARE(ms1,ms2) (((ms1)->mod_time==(ms2)->mod_time) && ((ms1)->size==(ms2)->size))
#define FILE_MOD_COMPARE(ms1,ms2) (((ms1)->mod_time.tv_sec==(ms2)->mod_time.tv_sec) && ((ms1)->mod_time.tv_nsec==(ms2)->mod_time.tv_nsec) && ((ms1)->size==(ms2)->size))
#define FILE_MOD_RESET(ms) memset(ms,0,sizeof(file_mod_sig))
bool file_mod_signature(const char *filename, file_mod_sig *ms);
time_t file_mod_time(const char *filename);
bool file_size(const char *filename, off_t *size);
bool file_open_test(const char *filename, int flags);
@@ -102,19 +108,23 @@ void set_console_io_buffering(void);
void close_std(void);
void close_std_and_exit(int code);
bool set_env_exedir(const char *argv0);
bool realpath_any(const char *file, char *pabs);
bool parse_int16(const char *p, int16_t *v);
uint32_t mask_from_bitcount(uint32_t zct);
void mask_from_bitcount6_prepare(void);
const struct in6_addr *mask_from_bitcount6(uint32_t zct);
#ifdef CLOCK_BOOTTIME
#define CLOCK_BOOT_OR_UPTIME CLOCK_BOOTTIME
#elif defined(CLOCK_UPTIME)
#define CLOCK_BOOT_OR_UPTIME CLOCK_UPTIME
#else
#define CLOCK_BOOT_OR_UPTIME CLOCK_MONOTINIC
#define CLOCK_BOOT_OR_UPTIME CLOCK_MONOTONIC
#endif
time_t boottime(void);
uint64_t boottime_ms(void);
#ifdef __CYGWIN__
uint32_t mask_from_bitcount(uint32_t zct);
void mask_from_bitcount6_prepare(void);
const struct in6_addr *mask_from_bitcount6(uint32_t zct);
#endif
+41 -24
View File
@@ -8,8 +8,10 @@ static bool addpool(hostlist_pool **hostlist, char **s, const char *end, int *ct
{
char *p=*s;
for (; p<end && (*p==' ' || *p=='\t') ; p++);
*s = p;
// comment line ?
if ( *p != '#' && *p != ';' && *p != '/' && *p != '\r' && *p != '\n')
if (p<end && *p != '#' && *p != ';' && *p != '/' && *p != '\r' && *p != '\n')
{
// advance until eol lowering all chars
uint32_t flags = 0;
@@ -60,22 +62,25 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename)
{
r = z_readfile(F,&zbuf,&zsize,0);
fclose(F);
if (r==Z_OK)
if (r==Z_STREAM_END)
{
DLOG_CONDUP("zlib compression detected. uncompressed size : %zu\n", zsize);
p = zbuf;
e = zbuf + zsize;
while(p<e)
if (zbuf)
{
if (!addpool(hostlist,&p,e,&ct))
p = zbuf;
e = zbuf + zsize;
while(p<e)
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
free(zbuf);
return false;
if (!addpool(hostlist,&p,e,&ct))
{
DLOG_ERR("Not enough memory to store host list : %s\n", filename);
free(zbuf);
return false;
}
}
free(zbuf);
}
free(zbuf);
}
else
{
@@ -87,7 +92,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename)
{
DLOG_CONDUP("loading plain text list\n");
while (fgets(s, sizeof(s), F))
while (fgets_safe(s, sizeof(s), F))
{
p = s;
if (!addpool(hostlist,&p,p+strlen(p),&ct))
@@ -97,6 +102,12 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename)
return false;
}
}
if (ferror(F))
{
DLOG_PERROR("AppendHostList");
fclose(F);
return false;
}
fclose(F);
}
@@ -104,7 +115,8 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename)
return true;
}
static bool LoadHostList(struct hostlist_file *hfile)
// bChanged is set to true if the list was changed and not set otherwise
static bool LoadHostList(struct hostlist_file *hfile, bool *bChanged)
{
if (hfile->filename)
{
@@ -122,6 +134,7 @@ static bool LoadHostList(struct hostlist_file *hfile)
DLOG_PERROR("file_open_test");
goto unchanged;
}
if (bChanged) *bChanged=true;
// don't want to keep backup copy in memory - it will require *2 RAM. Problem on low-ram devices. It's better to fail hostlist read than have OOM.
// if a file can be opened there're few chances it can't be read. fs corruption, disk error, deleted or made inaccessible between 2 syscals ?
// it's all hypotetically possible but very unlikely. but OOM is much more real problem on an embedded device if list is large enough
@@ -138,14 +151,14 @@ unchanged:
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
}
static bool LoadHostLists(struct hostlist_files_head *list)
static bool LoadHostLists(struct hostlist_files_head *list, bool *bChanged)
{
bool bres=true;
struct hostlist_file *hfile;
LIST_FOREACH(hfile, list, next)
{
if (!LoadHostList(hfile))
if (!LoadHostList(hfile, bChanged))
// at least one failed
bres=false;
}
@@ -170,9 +183,10 @@ static void MakeAutolistsNonEmpty()
bool LoadAllHostLists()
{
if (!LoadHostLists(&params.hostlists))
bool bChanged=false;
if (!LoadHostLists(&params.hostlists, &bChanged))
return false;
MakeAutolistsNonEmpty();
if (bChanged) MakeAutolistsNonEmpty();
return true;
}
@@ -216,12 +230,15 @@ static bool SearchHostList(hostlist_pool *hostlist, const char *host, bool no_ma
static bool HostlistsReloadCheck(const struct hostlist_collection_head *hostlists)
{
struct hostlist_item *item;
bool bChanged=false;
LIST_FOREACH(item, hostlists, next)
{
if (!LoadHostList(item->hfile))
if (!LoadHostList(item->hfile, &bChanged))
return false;
}
MakeAutolistsNonEmpty();
// this is relatively heavy function. walks through all the profiles. do not walk if no hostlists were releaded
if (bChanged) MakeAutolistsNonEmpty();
return true;
}
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp)
@@ -274,13 +291,15 @@ bool HostlistCheck(const struct desync_profile *dp, const char *host, bool no_ma
static struct hostlist_file *RegisterHostlist_(struct hostlist_files_head *hostlists, struct hostlist_collection_head *hl_collection, const char *filename)
{
struct hostlist_file *hfile;
char pabs[PATH_MAX];
if (filename)
{
if (!(hfile=hostlist_files_search(hostlists, filename)))
if (!(hfile=hostlist_files_add(hostlists, filename)))
if (!realpath(filename,pabs)) return NULL;
if (!(hfile=hostlist_files_search(hostlists, pabs)))
if (!(hfile=hostlist_files_add(hostlists, pabs)))
return NULL;
if (!hostlist_collection_search(hl_collection, filename))
if (!hostlist_collection_search(hl_collection, pabs))
if (!hostlist_collection_add(hl_collection, hfile))
return NULL;
}
@@ -296,13 +315,11 @@ static struct hostlist_file *RegisterHostlist_(struct hostlist_files_head *hostl
}
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename)
{
/*
if (filename && !file_mod_time(filename))
if (filename && !file_size(filename,NULL))
{
DLOG_ERR("cannot access hostlist file '%s'\n",filename);
return NULL;
}
*/
return RegisterHostlist_(
&params.hostlists,
bExclude ? &dp->hl_collection_exclude : &dp->hl_collection,
+56 -38
View File
@@ -11,36 +11,42 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
struct cidr4 c4;
struct cidr6 c6;
for (p=*s; p<end && *p && *p!=' ' && *p!='\t' && *p!='\r' && *p != '\n'; p++);
// comment line
if (!(**s == '#' || **s == ';' || **s == '/' || **s == '\r' || **s == '\n' ))
for (p=*s; p<end && (*p==' ' || *p=='\t') ; p++);
if (p<end)
{
l = p-*s;
if (l>=sizeof(cidr)) l=sizeof(cidr)-1;
memcpy(cidr,*s,l);
cidr[l]=0;
// comment line
if (!(*p == '#' || *p == ';' || *p == '/' || *p == '\r' || *p == '\n' ))
{
*s=p;
// advance to the token's end
for (; p<end && *p && *p!=' ' && *p!='\t' && *p!='\r' && *p != '\n'; p++);
if (parse_cidr4(cidr,&c4))
{
if (!ipset4AddCidr(&ips->ips4, &c4))
l = p-*s;
if (l>=sizeof(cidr)) l=sizeof(cidr)-1;
memcpy(cidr,*s,l);
cidr[l]=0;
if (parse_cidr4(cidr,&c4))
{
ipsetDestroy(ips);
return false;
if (!ipset4AddCidr(&ips->ips4, &c4))
{
ipsetDestroy(ips);
return false;
}
if (ct) (*ct)++;
}
if (ct) (*ct)++;
}
else if (parse_cidr6(cidr,&c6))
{
if (!ipset6AddCidr(&ips->ips6, &c6))
else if (parse_cidr6(cidr,&c6))
{
ipsetDestroy(ips);
return false;
if (!ipset6AddCidr(&ips->ips6, &c6))
{
ipsetDestroy(ips);
return false;
}
if (ct) (*ct)++;
}
if (ct) (*ct)++;
else
DLOG_ERR("bad ip or subnet : %s\n",cidr);
}
else
DLOG_ERR("bad ip or subnet : %s\n",cidr);
}
// skip remaining non-eol chars
@@ -77,22 +83,25 @@ static bool AppendIpset(ipset *ips, const char *filename)
{
r = z_readfile(F,&zbuf,&zsize,0);
fclose(F);
if (r==Z_OK)
if (r==Z_STREAM_END)
{
DLOG_CONDUP("zlib compression detected. uncompressed size : %zu\n", zsize);
p = zbuf;
e = zbuf + zsize;
while(p<e)
if (zbuf)
{
if (!addpool(ips,&p,e,&ct))
p = zbuf;
e = zbuf + zsize;
while(p<e)
{
DLOG_ERR("Not enough memory to store ipset : %s\n", filename);
free(zbuf);
return false;
if (!addpool(ips,&p,e,&ct))
{
DLOG_ERR("Not enough memory to store ipset : %s\n", filename);
free(zbuf);
return false;
}
}
free(zbuf);
}
free(zbuf);
}
else
{
@@ -104,7 +113,7 @@ static bool AppendIpset(ipset *ips, const char *filename)
{
DLOG_CONDUP("loading plain text list\n");
while (fgets(s, sizeof(s)-1, F))
while (fgets_safe(s, sizeof(s)-1, F))
{
p = s;
if (!addpool(ips,&p,p+strlen(p),&ct))
@@ -114,6 +123,12 @@ static bool AppendIpset(ipset *ips, const char *filename)
return false;
}
}
if (ferror(F))
{
DLOG_PERROR("AppendIpset");
fclose(F);
return false;
}
fclose(F);
}
@@ -176,7 +191,7 @@ bool LoadAllIpsets()
static bool SearchIpset(const ipset *ips, const struct in_addr *ipv4, const struct in6_addr *ipv6)
{
char s_ip[40];
char s_ip[INET6_ADDRSTRLEN];
bool bInSet=false;
if (!!ipv4 != !!ipv6)
@@ -272,12 +287,15 @@ bool IpsetCheck(
static struct ipset_file *RegisterIpset_(struct ipset_files_head *ipsets, struct ipset_collection_head *ips_collection, const char *filename)
{
struct ipset_file *hfile;
char pabs[PATH_MAX];
if (filename)
{
if (!(hfile=ipset_files_search(ipsets, filename)))
if (!(hfile=ipset_files_add(ipsets, filename)))
if (!realpath(filename,pabs)) return NULL;
if (!(hfile=ipset_files_search(ipsets, pabs)))
if (!(hfile=ipset_files_add(ipsets, pabs)))
return NULL;
if (!ipset_collection_search(ips_collection, filename))
if (!ipset_collection_search(ips_collection, pabs))
if (!ipset_collection_add(ips_collection, hfile))
return NULL;
}
@@ -292,7 +310,7 @@ static struct ipset_file *RegisterIpset_(struct ipset_files_head *ipsets, struct
}
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename)
{
if (filename && !file_mod_time(filename))
if (filename && !file_size(filename,NULL))
{
DLOG_ERR("cannot access ipset file '%s'\n",filename);
return NULL;
+33 -19
View File
@@ -92,6 +92,19 @@ int main(void) {
} \
if (cnt_) *cnt_ = cnt; \
return (__type*)p; \
} \
__scope __type *kavl_interval_##suf(const __type *root, const __type *x, __type **lower, __type **upper) { \
const __type *p = root, *l = 0, *u = 0; \
while (p != 0) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp < 0) u = p, p = p->__head.p[0]; \
else if (cmp > 0) l = p, p = p->__head.p[1]; \
else { l = u = p; break; } \
} \
if (lower) *lower = (__type*)l; \
if (upper) *upper = (__type*)u; \
return (__type*)p; \
}
#define __KAVL_ROTATE(suf, __type, __head) \
@@ -271,43 +284,42 @@ int main(void) {
#define __KAVL_ITR(suf, __scope, __type, __head, __cmp) \
struct kavl_itr_##suf { \
const __type *stack[KAVL_MAX_DEPTH], **top, *right; /* _right_ points to the right child of *top */ \
const __type *stack[KAVL_MAX_DEPTH], **top; \
}; \
__scope void kavl_itr_first_##suf(const __type *root, struct kavl_itr_##suf *itr) { \
const __type *p; \
for (itr->top = itr->stack - 1, p = root; p; p = p->__head.p[0]) \
*++itr->top = p; \
itr->right = (*itr->top)->__head.p[1]; \
} \
__scope int kavl_itr_find_##suf(const __type *root, const __type *x, struct kavl_itr_##suf *itr) { \
const __type *p = root; \
itr->top = itr->stack - 1; \
while (p != 0) { \
int cmp; \
*++itr->top = p; \
cmp = __cmp(x, p); \
if (cmp < 0) *++itr->top = p, p = p->__head.p[0]; \
if (cmp < 0) p = p->__head.p[0]; \
else if (cmp > 0) p = p->__head.p[1]; \
else break; \
} \
if (p) { \
*++itr->top = p; \
itr->right = p->__head.p[1]; \
return 1; \
} else if (itr->top >= itr->stack) { \
itr->right = (*itr->top)->__head.p[1]; \
return 0; \
} else return 0; \
return p? 1 : 0; \
} \
__scope int kavl_itr_next_##suf(struct kavl_itr_##suf *itr) { \
for (;;) { \
const __type *p; \
for (p = itr->right, --itr->top; p; p = p->__head.p[0]) \
__scope int kavl_itr_next_bidir_##suf(struct kavl_itr_##suf *itr, int dir) { \
const __type *p; \
if (itr->top < itr->stack) return 0; \
dir = !!dir; \
p = (*itr->top)->__head.p[dir]; \
if (p) { /* go down */ \
for (; p; p = p->__head.p[!dir]) \
*++itr->top = p; \
if (itr->top < itr->stack) return 0; \
itr->right = (*itr->top)->__head.p[1]; \
return 1; \
} else { /* go up */ \
do { \
p = *itr->top--; \
} while (itr->top >= itr->stack && p == (*itr->top)->__head.p[dir]); \
return itr->top < itr->stack? 0 : 1; \
} \
}
} \
/**
* Insert a node to the tree
@@ -332,6 +344,7 @@ int main(void) {
* @return node equal to _x_ if present, or NULL if absent
*/
#define kavl_find(suf, root, x, cnt) kavl_find_##suf(root, x, cnt)
#define kavl_interval(suf, root, x, lower, upper) kavl_interval_##suf(root, x, lower, upper)
/**
* Delete a node from the tree
@@ -376,7 +389,8 @@ int main(void) {
*
* @return 1 if there is a next object; 0 otherwise
*/
#define kavl_itr_next(suf, itr) kavl_itr_next_##suf(itr)
#define kavl_itr_next(suf, itr) kavl_itr_next_bidir_##suf(itr, 1)
#define kavl_itr_prev(suf, itr) kavl_itr_next_bidir_##suf(itr, 0)
/**
* Return the pointer at the iterator
+556 -181
View File
File diff suppressed because it is too large. Load diff
+4 -4
View File
@@ -4,7 +4,7 @@
#include <stdint.h>
#ifdef LUAJIT
#include "luajit.h"
#include <luajit.h>
#else
#include <lua.h>
#endif
@@ -82,8 +82,8 @@ void lua_pushf_lud(lua_State *L, const char *field, void *p);
void lua_pushf_table(lua_State *L, const char *field);
void lua_pushi_table(lua_State *L, lua_Integer idx);
void lua_push_blob(lua_State *L, int idx_desync, const char *blob);
void lua_pushf_blob(lua_State *L, int idx_desync, const char *field, const char *blob);
bool lua_push_blob(lua_State *L, int idx_desync, const char *blob);
bool lua_pushf_blob(lua_State *L, int idx_desync, const char *field, const char *blob);
void lua_push_ipaddr(lua_State *L, const struct sockaddr *sa);
void lua_pushf_ipaddr(lua_State *L, const char *field, const struct sockaddr *sa);
@@ -103,7 +103,7 @@ void lua_push_dissect(lua_State *L, const struct dissect *dis);
void lua_pushf_dissect(lua_State *L, const struct dissect *dis);
void lua_push_ctrack(lua_State *L, const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming);
void lua_pushf_ctrack(lua_State *L, const t_ctrack *ctrack, const t_ctrack_positions *tpos, bool bIncoming);
void lua_pushf_args(lua_State *L, const struct str2_list_head *args, int idx_desync, bool subst_prefix);
bool lua_pushf_args(lua_State *L, const struct str2_list_head *args, int idx_desync, bool subst_prefix);
void lua_pushf_pos(lua_State *L, const char *name, const struct packet_pos *pos);
void lua_pushf_range(lua_State *L, const char *name, const struct packet_range *range);
void lua_pushf_global(lua_State *L, const char *field, const char *global);
+402 -111
View File
File diff suppressed because it is too large. Load diff
+1 -3
View File
@@ -6,10 +6,8 @@
#define HAS_FILTER_SSID 1
#endif
#ifdef __CYGWIN__
extern volatile sig_atomic_t bQuit;
#endif
int main(int argc, char *argv[]);
// when something changes that can break LUA compatibility this version should be increased
#define LUA_COMPAT_VER 5
#define LUA_COMPAT_VER 6
+24 -13
View File
@@ -4,30 +4,40 @@
#include "packet_queue.h"
void rawpacket_queue_init(struct rawpacket_tailhead *q)
void rawpacket_queue_init(struct rawpacket_queue *q, unsigned int max_packets)
{
TAILQ_INIT(q);
TAILQ_INIT(&q->q);
q->max_packets = max_packets;
}
void rawpacket_free(struct rawpacket *rp)
{
if (rp) free(rp->packet);
free(rp);
}
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q)
struct rawpacket *rawpacket_dequeue(struct rawpacket_queue *q)
{
struct rawpacket *rp;
rp = TAILQ_FIRST(q);
if (rp) TAILQ_REMOVE(q, rp, next);
rp = TAILQ_FIRST(&q->q);
if (rp) TAILQ_REMOVE(&q->q, rp, next);
return rp;
}
void rawpacket_queue_destroy(struct rawpacket_tailhead *q)
void rawpacket_queue_destroy(struct rawpacket_queue *q)
{
struct rawpacket *rp;
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_positions *tpos)
struct rawpacket *rawpacket_queue(
struct rawpacket_queue *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,
bool server_side)
{
if (q->max_packets && rawpacket_queue_count(q)>=q->max_packets) return NULL;
struct rawpacket *rp = malloc(sizeof(struct rawpacket));
if (!rp) return NULL;
@@ -37,7 +47,7 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
free(rp);
return NULL;
}
rp->dst = *dst;
rp->fwmark_orig = fwmark_orig;
rp->fwmark = fwmark;
@@ -61,20 +71,21 @@ struct rawpacket *rawpacket_queue(struct rawpacket_tailhead *q,const struct sock
}
else
rp->tpos_present = false;
rp->server_side = server_side;
TAILQ_INSERT_TAIL(q, rp, next);
TAILQ_INSERT_TAIL(&q->q, rp, next);
return rp;
}
unsigned int rawpacket_queue_count(const struct rawpacket_tailhead *q)
unsigned int rawpacket_queue_count(const struct rawpacket_queue *q)
{
const struct rawpacket *rp;
unsigned int ct=0;
TAILQ_FOREACH(rp, q, next) ct++;
TAILQ_FOREACH(rp, &q->q, next) ct++;
return ct;
}
bool rawpacket_queue_empty(const struct rawpacket_tailhead *q)
bool rawpacket_queue_empty(const struct rawpacket_queue *q)
{
return !TAILQ_FIRST(q);
return !TAILQ_FIRST(&q->q);
}
+13 -6
View File
@@ -18,14 +18,21 @@ struct rawpacket
uint8_t *packet;
t_ctrack_positions tpos;
bool tpos_present;
bool server_side; // true = reasm of packets from the server side
TAILQ_ENTRY(rawpacket) next;
};
TAILQ_HEAD(rawpacket_tailhead, rawpacket);
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_positions *tpos);
struct rawpacket *rawpacket_dequeue(struct rawpacket_tailhead *q);
struct rawpacket_queue
{
struct rawpacket_tailhead q;
unsigned int max_packets;
};
void rawpacket_queue_init(struct rawpacket_queue *q, unsigned int max_packets);
void rawpacket_queue_destroy(struct rawpacket_queue *q);
bool rawpacket_queue_empty(const struct rawpacket_queue *q);
unsigned int rawpacket_queue_count(const struct rawpacket_queue *q);
struct rawpacket *rawpacket_queue(struct rawpacket_queue *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,bool server_side);
struct rawpacket *rawpacket_dequeue(struct rawpacket_queue *q);
void rawpacket_free(struct rawpacket *rp);
+11 -10
View File
@@ -116,7 +116,7 @@ static char log_buf[4096];
static size_t log_buf_sz=0;
static void syslog_log_function(int priority, const char *line)
{
syslog(priority,"%s",log_buf);
syslog(priority,"%s",line);
}
static int DLOG_FILENAME(const char *filename, const char *format, ...)
@@ -130,7 +130,7 @@ static int DLOG_FILENAME(const char *filename, const char *format, ...)
}
static void file_log_function(int priority, const char *line)
{
DLOG_FILENAME(params.debug_logfile,"%s",log_buf);
DLOG_FILENAME(params.debug_logfile,"%s",line);
}
#ifdef __ANDROID__
@@ -405,7 +405,7 @@ static struct desync_profile_list *desync_profile_entry_alloc()
struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
{
struct desync_profile_list *entry = desync_profile_entry_alloc();
if (!entry) return false;
if (!entry) return NULL;
struct desync_profile_list *tail, *item;
LIST_TAIL(head, tail, item);
@@ -532,14 +532,15 @@ bool alloc_windivert_portfilters(struct params_s *params)
&params->wf_ipf_in, &params->wf_ipf_out};
for (int i=0 ; i<(sizeof(wdbufs)/sizeof(*wdbufs)) ; i++)
{
if (!(*wdbufs[i] = malloc(WINDIVERT_PORTFILTER_MAX)))
return false;
if (!(*wdbufs[i] = malloc(WINDIVERT_PORTFILTER_MAX))) goto err;
**wdbufs[i] = 0;
}
if (!(params->wf_raw_filter = malloc(WINDIVERT_MAX)))
return false;
if (!(params->wf_raw_filter = malloc(WINDIVERT_MAX))) goto err;
*params->wf_raw_filter = 0;
return true;
err:
cleanup_windivert_portfilters(params);
return false;
}
#endif
void cleanup_params(struct params_s *params)
@@ -558,6 +559,7 @@ void cleanup_params(struct params_s *params)
ipcacheDestroy(&params->ipcache);
blob_collection_destroy(&params->blobs);
strlist_destroy(&params->lua_init_scripts);
TimerPoolDestroy(&params->timers);
#ifdef __CYGWIN__
strlist_destroy(&params->ssid_filter);
@@ -586,14 +588,14 @@ void init_params(struct params_s *params)
params->ctrack_t_fin = CTRACK_T_FIN;
params->ctrack_t_udp = CTRACK_T_UDP;
params->ipcache_lifetime = IPCACHE_LIFETIME;
params->lua_gc = LUA_GC_INTERVAL;
params->lua_gc = LUA_GC_INTERVAL*1000;
LIST_INIT(&params->hostlists);
LIST_INIT(&params->ipsets);
LIST_INIT(&params->blobs);
LIST_INIT(&params->lua_init_scripts);
params->reasm_payload_disable = params->payload_disable = 1<<L7P_NONE;
params->reasm_payload_disable = params->payload_disable = 1ULL<<L7P_NONE;
#ifdef __CYGWIN__
LIST_INIT(&params->ssid_filter);
@@ -607,5 +609,4 @@ void init_params(struct params_s *params)
params->droproot = true;
}
#endif
}
+15 -5
View File
@@ -7,6 +7,7 @@
#include "protocol.h"
#include "helpers.h"
#include "sec.h"
#include "timer.h"
#include <sys/param.h>
#include <sys/types.h>
@@ -23,7 +24,8 @@
#define RAW_SNDBUF (64*1024) // in bytes
#define Q_MAXLEN 1024 // in packets
#define Q_MAXLEN 4096 // in packets
#define Q_RCVBUF (1024*1024) // in bytes
#define HOSTLIST_AUTO_FAIL_THRESHOLD_DEFAULT 3
#define HOSTLIST_AUTO_FAIL_TIME_DEFAULT 60
@@ -70,6 +72,10 @@ struct desync_profile
// annot use global filter because it's not possible to bind multiple instances to a single queue
// it's possible to run multiple winws2 instances on the same windivert filter, but it's not the case for linux
struct str_list_head filter_ssid;
bool filter_ssid_neg;
#endif
#ifdef __linux__
uint32_t filter_mark,filter_mark_mask;
#endif
// list of pointers to ipsets
@@ -94,7 +100,6 @@ struct desync_profile
bool b_hostlist_auto_retrans_maxseq, b_hostlist_auto_incoming_maxseq, b_hostlist_auto_retrans_reset;
bool b_hostlist_auto_udp_out, b_hostlist_auto_udp_in;
bool b_filter_l3, b_filter_l7;
};
#define PROFILE_NAME(dp) ((dp)->name ? (dp)->name : "noname")
@@ -133,6 +138,7 @@ struct params_s
bool debug;
bool daemon, intercept;
unsigned int fuzz;
#ifdef __linux__
int qnum;
@@ -146,6 +152,7 @@ struct params_s
#ifdef __CYGWIN__
struct str_list_head ssid_filter,nlm_filter;
bool ssid_filter_neg, nlm_filter_neg;
struct str_list_head wf_raw_part;
char *windivert_filter;
@@ -187,10 +194,13 @@ struct params_s
uint64_t payload_disable;
struct str_list_head lua_init_scripts;
bool writeable_dir_enable;
char writeable_dir[PATH_MAX];
bool writable_dir_enable;
char writable_dir[PATH_MAX];
int lua_gc;
timer_pool *timers;
bool timers_dirty; // changed something in timers
uint64_t lua_gc;
int ref_desync_ctx; // desync ctx userdata registry ref
lua_State *L;
};
+34 -38
View File
@@ -5,33 +5,6 @@
#include <stdio.h>
#include <arpa/inet.h>
#define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) { \
free(elem->str); \
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return false; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, keystr_len, elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return false; \
}
#define ADD_HOSTLIST_POOL(etype, ppool, keystr, keystr_len, flg) \
etype *elem_find; \
HASH_FIND(hh, *ppool, keystr, keystr_len, elem_find); \
@@ -493,7 +466,6 @@ void kavl_bit_destroy(struct kavl_bit_elem **hdr)
if (!e) break;
kavl_bit_destroy_elem(e);
}
free(*hdr);
}
struct kavl_bit_elem *kavl_bit_add(struct kavl_bit_elem **hdr, void *data, unsigned int bitlen, size_t struct_size)
{
@@ -524,10 +496,15 @@ struct kavl_bit_elem *kavl_bit_get(const struct kavl_bit_elem *hdr, const void *
static bool ipset_kavl_add(struct kavl_bit_elem **ipset, const void *a, uint8_t preflen)
{
uint8_t bytelen = (preflen+7)>>3;
uint8_t *abuf = malloc(bytelen);
if (!abuf) return false;
memcpy(abuf,a,bytelen);
uint8_t *abuf, bytelen = (preflen+7)>>3;
if (bytelen)
{
abuf = malloc(bytelen);
if (!abuf) return false;
memcpy(abuf,a,bytelen);
}
else
abuf = NULL;
if (!kavl_bit_add(ipset,abuf,preflen,0))
{
free(abuf);
@@ -912,12 +889,15 @@ struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, co
{
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
if (!entry) return NULL;
if (!(entry->data = malloc(size+size_reserve)))
if (size+size_reserve)
{
free(entry);
return NULL;
if (!(entry->data = malloc(size+size_reserve)))
{
free(entry);
return NULL;
}
if (data) memcpy(entry->data,data,size);
}
if (data) memcpy(entry->data,data,size);
entry->size = size;
entry->size_buf = size+size_reserve;
@@ -1025,7 +1005,7 @@ static ip_cache4 *ipcache4Add(ip_cache4 **ipcache, const struct in_addr *a, cons
}
static void ipcache4Print(ip_cache4 *ipcache)
{
char s_ip[16];
char s_ip[INET_ADDRSTRLEN];
time_t now;
ip_cache4 *ipc, *tmp;
@@ -1083,7 +1063,7 @@ static ip_cache6 *ipcache6Add(ip_cache6 **ipcache, const struct in6_addr *a, con
}
static void ipcache6Print(ip_cache6 *ipcache)
{
char s_ip[40];
char s_ip[INET6_ADDRSTRLEN];
time_t now;
ip_cache6 *ipc, *tmp;
@@ -1107,6 +1087,22 @@ void ipcachePrint(ip_cache *ipcache)
ipcache6Print(ipcache->ipcache6);
}
ip_cache_item *ipcacheFind(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6, const char *iface)
{
ip_cache4 *ipcache4;
ip_cache6 *ipcache6;
if (a4)
{
if ((ipcache4 = ipcache4Find(ipcache->ipcache4,a4,iface)))
return &ipcache4->data;
}
else if (a6)
{
if ((ipcache6 = ipcache6Find(ipcache->ipcache6,a6,iface)))
return &ipcache6->data;
}
return NULL;
}
ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6, const char *iface)
{
ip_cache4 *ipcache4;
+29
View File
@@ -27,6 +27,34 @@
else \
LIST_INSERT_HEAD(head, elm, field); }
#define DESTROY_STR_POOL(etype, ppool) \
etype *elem, *tmp; \
HASH_ITER(hh, *ppool, elem, tmp) { \
free(elem->str); \
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \
return false; \
if (!(elem->str = malloc(keystr_len + 1))) \
{ \
free(elem); \
return NULL; \
} \
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, keystr_len, elem); \
if (oom) \
{ \
free(elem->str); \
free(elem); \
return NULL; \
}
typedef struct hostlist_pool {
char *str; /* key */
@@ -265,6 +293,7 @@ typedef struct ip_cache
} ip_cache;
ip_cache_item *ipcacheTouch(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6, const char *iface);
ip_cache_item *ipcacheFind(ip_cache *ipcache, const struct in_addr *a4, const struct in6_addr *a6, const char *iface);
void ipcachePurgeRateLimited(ip_cache *ipcache, time_t lifetime);
void ipcacheDestroy(ip_cache *ipcache);
void ipcachePrint(ip_cache *ipcache);
+106 -70
View File
@@ -17,12 +17,15 @@ static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t **
{
int i;
const uint8_t *p1,*p2;
if (level<1) return false;
for (i=1,p2=dom+dlen;i<level;i++)
{
for (p2--; p2>dom && *p2!='.'; p2--);
if (p2<=dom) return false;
}
for (p1=p2-1 ; p1>dom && *p1!='.'; p1--);
if (p1<dom) return false;
if (*p1=='.') p1++;
if (p) *p = p1;
if (len) *len = p2-p1;
@@ -30,7 +33,7 @@ static bool FindNLD(const uint8_t *dom, size_t dlen, int level, const uint8_t **
}
static const char *l7proto_name[] = {
"all","unknown","known","http","tls","dtls","quic","wireguard","dht","discord","stun","xmpp","dns","mtproto"
"all","unknown","known","http","tls","dtls","quic","wireguard","dht","discord","stun","xmpp","dns","mtproto","bt","utp_bt"
};
const char *l7proto_str(t_l7proto l7)
{
@@ -44,7 +47,7 @@ t_l7proto l7proto_from_name(const char *name)
}
bool l7_proto_match(t_l7proto l7proto, uint64_t filter_l7)
{
return filter_l7==L7_ALL || (filter_l7 & (1<<l7proto)) || (filter_l7 & (1<<L7_KNOWN)) && l7proto>L7_KNOWN && l7proto<L7_LAST;
return (filter_l7==L7_ALL) || (filter_l7 & (1ULL<<l7proto)) || (filter_l7 & (1ULL<<L7_KNOWN)) && (l7proto>L7_KNOWN) && (l7proto<L7_LAST);
}
static const char *l7payload_name[] = {
@@ -58,7 +61,9 @@ static const char *l7payload_name[] = {
"dht","discord_ip_discovery","stun",
"xmpp_stream", "xmpp_starttls", "xmpp_proceed", "xmpp_features",
"dns_query", "dns_response",
"mtproto_initial"};
"mtproto_initial",
"bt_handshake", "utp_bt_handshake"
};
t_l7payload l7payload_from_name(const char *name)
{
int idx = str_index(l7payload_name,sizeof(l7payload_name)/sizeof(*l7payload_name),name);
@@ -71,7 +76,7 @@ const char *l7payload_str(t_l7payload l7)
}
bool l7_payload_match(t_l7payload l7payload, uint64_t filter_l7p)
{
return filter_l7p==L7P_ALL || (filter_l7p & (1<<l7payload)) || (filter_l7p & (1<<L7P_KNOWN)) && l7payload>L7P_KNOWN && l7payload<L7P_LAST;
return (filter_l7p==L7P_ALL) || (filter_l7p & (1ULL<<l7payload)) || (filter_l7p & (1ULL<<L7P_KNOWN)) && (l7payload>L7P_KNOWN) && (l7payload<L7P_LAST);
}
bool l7_payload_str_list(uint64_t l7p, char *buf, size_t size)
{
@@ -89,7 +94,7 @@ bool l7_payload_str_list(uint64_t l7p, char *buf, size_t size)
}
for(pl=0, p=buf, e=p+size, *buf=0 ; pl<L7P_LAST ; pl++)
{
if (l7p & (1<<pl))
if (l7p & (1ULL<<pl))
{
pstr = l7payload_str(pl);
lstr = strlen(pstr);
@@ -140,7 +145,6 @@ bool posmarker_parse(const char *s, struct proto_pos *m)
m->pos = 0;
}
return true;
}
bool posmarker_list_parse(const char *s, struct proto_pos *m, int *mct)
{
@@ -244,7 +248,7 @@ void ResolveMultiPos(const uint8_t *data, size_t sz, t_l7payload l7payload, cons
}
static const char *http_methods[] = { "GET ","POST ","HEAD ","OPTIONS ","PUT ","DELETE ","CONNECT ","TRACE ",NULL };
static const char *http_methods[] = { "GET ","POST ","HEAD ","OPTIONS ","PUT ","DELETE ","CONNECT ","TRACE ", "PATCH ", NULL };
static const char *HttpMethod(const uint8_t *data, size_t len)
{
const char **method;
@@ -327,7 +331,7 @@ bool IsHttpReply(const uint8_t *data, size_t len)
data[10]>='0' && data[10]<='9' &&
data[11]>='0' && data[11]<='9';
}
int HttpReplyCode(const uint8_t *data, size_t len)
int HttpReplyCode(const uint8_t *data)
{
return (data[9]-'0')*100 + (data[10]-'0')*10 + (data[11]-'0');
}
@@ -366,7 +370,7 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
if (!host || !*host || !IsHttpReply(data, len)) return false;
code = HttpReplyCode(data,len);
code = HttpReplyCode(data);
if ((code!=302 && code!=307) || !HttpExtractHeader(data,len,"\nLocation:",loc,sizeof(loc))) return false;
@@ -381,7 +385,7 @@ bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *
// somethinkg like : censor.net/badpage.php?reason=denied&source=RKN
for(p=redirect_host; *p && *p!='/' ; p++);
for(p=redirect_host; *p && *p!='/' && *p!='?' && *p!='#' ; p++);
*p=0;
if (!*redirect_host) return false;
@@ -413,7 +417,7 @@ ssize_t HttpPos(t_marker posmarker, int16_t pos, const uint8_t *data, size_t sz)
if (*method=='\n' || *method=='\r') method++;
if (*method=='\n' || *method=='\r') method++;
// max length is PROPPATCH
for (p=method,i=0;i<9;i++) if (*p>='A' && *p<='Z') p++;
for (p=method,i=0; i<9 && *p>='A' && *p<='Z'; i++,p++);
if (i<3 || *p!=' ') break;
return CheckPos(sz,method-data+pos);
case PM_HOST:
@@ -444,6 +448,7 @@ const char *TLSVersionStr(uint16_t tlsver)
{
switch(tlsver)
{
case 0x0300: return "SSL 3.0";
case 0x0301: return "TLS 1.0";
case 0x0302: return "TLS 1.1";
case 0x0303: return "TLS 1.2";
@@ -545,10 +550,14 @@ bool TLSFindExtLenOffsetInHandshake(const uint8_t *data, size_t len, size_t *off
l += data[l] + 1;
// CipherSuitesLength
if (len < (l + 2)) return false;
l += (data[0]==0x02 ? 0 : pntoh16(data + l)) + 2;
if (data[0]==0x01) // client hello ?
l += pntoh16(data + l);
l+=2;
// CompressionMethodsLength
if (len < (l + 1)) return false;
l += data[l] + 1;
if (data[0]==0x01) // client hello ?
l += data[l];
l++;
// ExtensionsLength
if (len < (l + 2)) return false;
*off = l;
@@ -556,7 +565,7 @@ bool TLSFindExtLenOffsetInHandshake(const uint8_t *data, size_t len, size_t *off
}
bool TLSFindExtLen(const uint8_t *data, size_t len, size_t *off)
{
if (!TLSFindExtLenOffsetInHandshake(data+5,len-5,off))
if (len<5 || !TLSFindExtLenOffsetInHandshake(data+5,len-5,off))
return false;
*off+=5;
return true;
@@ -640,9 +649,11 @@ bool TLSAdvanceToHostInSNI(const uint8_t **ext, size_t *elen, size_t *slen)
// u8 data+2 - server name type. 0=host_name
// u16 data+3 - server name length
if (*elen < 5 || (*ext)[2] != 0) return false;
uint16_t nll = pntoh16(*ext);
*slen = pntoh16(*ext + 3);
if (nll<(*slen+3) || nll>(*elen-2)) return false;
*ext += 5; *elen -= 5;
return *slen <= *elen;
return true;
}
static bool TLSExtractHostFromExt(const uint8_t *ext, size_t elen, char *host, size_t len_host)
{
@@ -761,9 +772,10 @@ bool TLSMod_parse_list(const char *modlist, struct fake_tls_mod *tls_mod)
}
// payload is related to received tls client hello
// if options cannot be applied because of the base fake - it's fatal. you should provide valid fake tls with required extensions.
// if options cannot be applied because of the payload - it's non-fatal. some options may not be applied with warning.
bool TLSMod(const struct fake_tls_mod *tls_mod, const uint8_t *payload, size_t payload_len, uint8_t *fake_tls, size_t *fake_tls_size, size_t fake_tls_buf_size)
{
bool bRes = true;
const uint8_t *ext;
size_t extlen,slen,extlen_offset=0,padlen_offset=0;
@@ -776,7 +788,7 @@ bool TLSMod(const struct fake_tls_mod *tls_mod, const uint8_t *payload, size_t p
{
if (!TLSFindExtLen(fake_tls, *fake_tls_size, &extlen_offset))
{
DLOG_ERR("cannot apply tls mod.tls structure invalid\n");
DLOG_ERR("cannot apply tls mod. tls structure invalid\n");
return false;
}
DLOG("tls extensions length offset : %zu\n", extlen_offset);
@@ -830,7 +842,7 @@ bool TLSMod(const struct fake_tls_mod *tls_mod, const uint8_t *payload, size_t p
if (!slen)
{
DLOG_ERR("cannot apply rndsni tls mod. tls has zero sized SNI\n");
bRes = false;
return false;
}
else
{
@@ -876,20 +888,11 @@ bool TLSMod(const struct fake_tls_mod *tls_mod, const uint8_t *payload, size_t p
if (IsTLSClientHelloPartial(payload, payload_len))
{
if (payload_len < 44)
{
DLOG("cannot apply dupsid tls mod. data payload is too short.\n");
bRes = false;
}
DLOG("(nonfatal) cannot apply dupsid tls mod. data payload is too short.\n");
else if (fake_tls[43] != payload[43])
{
DLOG("cannot apply dupsid tls mod. fake and orig session id length mismatch : %u!=%u.\n", fake_tls[43], payload[43]);
bRes = false;
}
DLOG("(nonfatal) cannot apply dupsid tls mod. fake and orig session id length mismatch : %u!=%u.\n", fake_tls[43], payload[43]);
else if (payload_len < (44 + payload[43]))
{
DLOG("cannot apply dupsid tls mod. data payload is not valid.\n");
bRes = false;
}
DLOG("(nonfatal) cannot apply dupsid tls mod. data payload is not valid.\n");
else
{
memcpy(fake_tls + 44, payload + 44, fake_tls[43]); // session id
@@ -898,8 +901,7 @@ bool TLSMod(const struct fake_tls_mod *tls_mod, const uint8_t *payload, size_t p
}
else
{
DLOG_ERR("cannot apply dupsid tls mod. payload is not valid tls.\n");
bRes = false;
DLOG_ERR("(nonfatal) cannot apply dupsid tls mod. payload is not valid tls.\n");
}
}
if (tls_mod->mod & FAKE_TLS_MOD_PADENCAP)
@@ -937,8 +939,7 @@ bool TLSMod(const struct fake_tls_mod *tls_mod, const uint8_t *payload, size_t p
size_t sz_pad = pntoh16(fake_tls + padlen_offset) + payload_len;
if ((sz_rec & ~0xFFFF) || (sz_handshake & ~0xFFFFFF) || (sz_ext & ~0xFFFF) || (sz_pad & ~0xFFFF))
{
DLOG("cannot apply padencap tls mod. length overflow.\n");
bRes = false;
DLOG("(nonfatal) cannot apply padencap tls mod. length overflow.\n");
}
else
{
@@ -951,7 +952,7 @@ bool TLSMod(const struct fake_tls_mod *tls_mod, const uint8_t *payload, size_t p
}
}
return bRes;
return true;
}
@@ -1185,16 +1186,16 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
return false;
}
uint64_t payload_len,token_len;
size_t pn_offset;
uint64_t payload_len,token_len,pn_offset;
pn_offset = 1 + 4 + 1 + data[5];
if (pn_offset >= data_len) return false;
// SCID length
pn_offset += 1 + data[pn_offset];
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
if (pn_offset >= data_len || (pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
// token length
pn_offset += tvb_get_varint(data + pn_offset, &token_len);
pn_offset += token_len;
if (pn_offset >= data_len) return false;
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
if (pn_offset >= data_len || (pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
pn_offset += tvb_get_varint(data + pn_offset, &payload_len);
if (payload_len<20 || (pn_offset + payload_len)>data_len) return false;
@@ -1215,17 +1216,17 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
phton64(aesiv + sizeof(aesiv) - 8, pntoh64(aesiv + sizeof(aesiv) - 8) ^ pkn);
size_t cryptlen = payload_len - pkn_len - 16;
uint64_t cryptlen = payload_len - pkn_len - 16;
if (cryptlen > *clean_len) return false;
*clean_len = cryptlen;
*clean_len = (size_t)cryptlen;
const uint8_t *decrypt_begin = data + pn_offset + pkn_len;
uint8_t atag[16],header[2048];
size_t header_len = pn_offset + pkn_len;
uint64_t header_len = pn_offset + pkn_len;
if (header_len > sizeof(header)) return false; // not likely header will be so large
memcpy(header, data, header_len);
header[0] = packet0;
for(size_t i = 0; i < pkn_len; i++) header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i));
for(uint8_t i = 0; i < pkn_len; i++) header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i));
if (aes_gcm_crypt(AES_DECRYPT, clean, decrypt_begin, cryptlen, aeskey, sizeof(aeskey), aesiv, sizeof(aesiv), header, header_len, atag, sizeof(atag)))
return false;
@@ -1243,6 +1244,13 @@ static int cmp_range64(const void * a, const void * b)
{
return (((struct range64*)a)->offset < ((struct range64*)b)->offset) ? -1 : (((struct range64*)a)->offset > ((struct range64*)b)->offset) ? 1 : 0;
}
/*
static bool intersected_u64(uint64_t l1, uint64_t r1, uint64_t l2, uint64_t r2)
{
return l1 <= r2 && l2 <= r1;
}
*/
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len, bool *bFull)
{
// Crypto frame can be split into multiple chunks
@@ -1256,7 +1264,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
uint64_t offset,sz,szmax=0,zeropos=0,pos=0;
bool found=false;
struct range64 ranges[MAX_DEFRAG_PIECES];
int i,range=0;
int i,j,range=0;
while(pos<clean_len)
{
@@ -1278,24 +1286,54 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
if ((pos+sz)>clean_len) return false;
if ((offset+sz)>defrag_data_len) return false; // defrag buf overflow
// remove exact duplicates early to save cpu
for(i=0;i<range;i++)
if (ranges[i].offset==offset && ranges[i].len==sz)
goto skip_range;
if (zeropos < offset)
// make sure no uninitialized gaps exist in case of not full fragment coverage
memset(defrag_data+zeropos,0,offset-zeropos);
if ((offset+sz) > zeropos)
zeropos=offset+sz;
memcpy(defrag_data+offset,clean+pos,sz);
if ((offset+sz) > szmax) szmax = offset+sz;
found=true;
pos+=sz;
if ((offset+sz) > szmax) szmax = offset+sz;
memcpy(defrag_data+offset,clean+pos,sz);
ranges[range].offset = offset;
ranges[range].len = sz;
range++;
skip_range:
pos+=sz;
}
}
if (found)
{
qsort(ranges, range, sizeof(*ranges), cmp_range64);
// for(i=0 ; i<range ; i++)
// printf("range1 %llu-%llu\n",ranges[i].offset,ranges[i].offset+ranges[i].len);
if (range>0)
{
for (j=0,i=1; i < range; i++)
{
uint64_t current_end = ranges[j].offset + ranges[j].len;
uint64_t next_start = ranges[i].offset;
uint64_t next_end = ranges[i].offset + ranges[i].len;
if (next_start <= current_end)
ranges[j].len = MAX(next_end,current_end) - ranges[j].offset;
else
ranges[++j] = ranges[i];
}
range = j+1;
}
// for(i=0 ; i<range ; i++)
// printf("range2 %llu-%llu\n",ranges[i].offset,ranges[i].offset+ranges[i].len);
defrag[0] = 6;
defrag[1] = 0; // offset
// 2..9 - length 64 bit
@@ -1304,21 +1342,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
defrag[2] |= 0xC0; // 64 bit value
*defrag_len = (size_t)(szmax+10);
qsort(ranges, range, sizeof(*ranges), cmp_range64);
//for(i=0 ; i<range ; i++)
// printf("RANGE %zu len %zu\n",ranges[i].offset,ranges[i].len);
for(i=0,offset=0,*bFull=true ; i<range ; i++)
{
if (ranges[i].offset!=offset)
{
*bFull = false;
break;
}
offset += ranges[i].len;
}
*bFull = range==1 && !ranges[0].offset;
//printf("bFull=%u\n",*bFull);
}
return found;
@@ -1328,14 +1352,12 @@ bool IsQUICInitial(const uint8_t *data, size_t len)
{
// too small packets are not likely to be initials
// long header, fixed bit
if (len < 128 || (data[0] & 0xF0)!=0xC0) return false;
if (len < 128) return false;
uint32_t ver = QUICExtractVersion(data,len);
if (QUICDraftVersion(ver) < 11) return false;
// quic v1 : initial packets are 00b
// quic v2 : initial packets are 01b
if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00)) return false;
if ((data[0] & 0xF0) != (is_quic_v2(ver) ? 0xD0 : 0xC0)) return false;
uint64_t offset=5, sz, sz2;
@@ -1343,11 +1365,14 @@ bool IsQUICInitial(const uint8_t *data, size_t len)
if (data[offset] > QUIC_MAX_CID_LENGTH) return false;
offset += 1 + data[offset];
if (offset>=len) return false;
// SCID
if (data[offset] > QUIC_MAX_CID_LENGTH) return false;
offset += 1 + data[offset];
// token length
if (offset>=len || (offset + tvb_get_size(data[offset])) > len) return false;
offset += tvb_get_varint(data + offset, &sz);
offset += sz;
if (offset >= len) return false;
@@ -1437,7 +1462,7 @@ bool IsStunMessage(const uint8_t *data, size_t len)
(data[0]&0xC0)==0 && // 2 most significant bits must be zeroes
(data[3]&3)==0 && // length must be a multiple of 4
pntoh32(data+4)==0x2112A442 && // magic cookie
pntoh16(data+2)==(len-20);
pntoh16(data+2)<=(len-20);
}
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing")))
@@ -1452,7 +1477,7 @@ bool IsMTProto(const uint8_t *data, size_t len)
return !memcmp(decrypt+56,"\xEF\xEF\xEF\xEF",4);
*/
// this way requires only one AES instead of 4
uint8_t decrypt[16] __attribute__((aligned)), iv[16];
uint8_t decrypt[16] __attribute__((aligned(16))), iv[16] __attribute__((aligned(16)));
aes_context ctx;
memcpy(iv, data+40, 16);
@@ -1484,3 +1509,14 @@ bool IsDTLSServerHello(const uint8_t *data, size_t len)
{
return IsDTLS(data,len) && data[0]==0x16 && data[13]==2;
}
bool IsBTHandshake(const uint8_t *data, size_t len)
{
// len, pstrlen, reserved, sha1, peer id
return len>=(1+19+8+20+20) && !memcmp(data,"\x13" "BitTorrent protocol",20);
}
bool IsUTP_BTHandshake(const uint8_t *data, size_t len)
{
// len, pstrlen, reserved, sha1, peer id
return len>=(20+1+19+8+20+20) && data[0]==0x01 && !memcmp(data+20,"\x13" "BitTorrent protocol",20);;
}
+7 -2
View File
@@ -20,6 +20,8 @@ typedef enum {
L7_XMPP,
L7_DNS,
L7_MTPROTO,
L7_BT,
L7_UTP_BT,
L7_LAST, L7_INVALID=L7_LAST, L7_NONE=L7_LAST
} t_l7proto;
const char *l7proto_str(t_l7proto l7);
@@ -56,6 +58,8 @@ typedef enum {
L7P_DNS_QUERY,
L7P_DNS_RESPONSE,
L7P_MTPROTO_INITIAL,
L7P_BT_HANDSHAKE,
L7P_UTP_BT_HANDSHAKE,
L7P_LAST, L7P_INVALID=L7P_LAST, L7P_NONE=L7P_LAST
} t_l7payload;
t_l7payload l7payload_from_name(const char *name);
@@ -100,7 +104,7 @@ bool HttpExtractHeader(const uint8_t *data, size_t len, const char *header, char
bool HttpExtractHost(const uint8_t *data, size_t len, char *host, size_t len_host);
bool IsHttpReply(const uint8_t *data, size_t len);
// must be pre-checked by IsHttpReply
int HttpReplyCode(const uint8_t *data, size_t len);
int HttpReplyCode(const uint8_t *data);
// must be pre-checked by IsHttpReply
bool HttpReplyLooksLikeDPIRedirect(const uint8_t *data, size_t len, const char *host);
@@ -160,7 +164,8 @@ bool IsMTProto(const uint8_t *data, size_t len);
bool IsDTLS(const uint8_t *data, size_t len);
bool IsDTLSClientHello(const uint8_t *data, size_t len);
bool IsDTLSServerHello(const uint8_t *data, size_t len);
bool IsBTHandshake(const uint8_t *data, size_t len);
bool IsUTP_BTHandshake(const uint8_t *data, size_t len);
#define QUIC_MAX_CID_LENGTH 20
typedef struct quic_cid {
+59 -22
View File
@@ -6,6 +6,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <grp.h>
#include <errno.h>
#include "params.h"
@@ -13,12 +14,12 @@
#include <sys/prctl.h>
#include <sys/syscall.h>
#include <linux/securebits.h>
#include <linux/seccomp.h>
#include <linux/filter.h>
// __X32_SYSCALL_BIT defined in linux/unistd.h
#include <linux/unistd.h>
#include <syscall.h>
#include <errno.h>
/************ SECCOMP ************/
@@ -210,10 +211,10 @@ int getmaxcap(void)
}
bool dropcaps(void)
{
uint64_t caps = (1<<CAP_NET_ADMIN)|(1<<CAP_NET_RAW);
uint64_t caps = (1ULL<<CAP_NET_ADMIN)|(1ULL<<CAP_NET_RAW);
int maxcap = getmaxcap();
if (setpcap(caps|(1<<CAP_SETPCAP)))
if (setpcap(caps|(1ULL<<CAP_SETPCAP)))
{
for (int cap = 0; cap <= maxcap; cap++)
{
@@ -249,7 +250,7 @@ bool can_drop_root(void)
{
#ifdef __linux__
// has some caps
return checkpcap((1<<CAP_SETUID)|(1<<CAP_SETGID));
return checkpcap((1ULL<<CAP_SETUID)|(1ULL<<CAP_SETGID));
#else
// effective root
return !geteuid();
@@ -266,8 +267,15 @@ bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count)
#ifdef __linux__
if (prctl(PR_SET_KEEPCAPS, 1L))
{
DLOG_PERROR("prctl(PR_SET_KEEPCAPS)");
return false;
int e=errno;
// if SECBIT_NO_SETUID_FIXUP is set PR_SET_KEEPCAPS is not necessary
int bits = prctl(PR_GET_SECUREBITS);
if (bits<0 || !(bits & SECBIT_NO_SETUID_FIXUP))
{
errno=e;
DLOG_PERROR("prctl(PR_SET_KEEPCAPS)");
return false;
}
}
#endif
if (user)
@@ -327,37 +335,66 @@ void daemonize(void)
int pid;
char cwd[PATH_MAX];
if (!getcwd(cwd, sizeof(cwd))) *cwd=0;
if (!getcwd(cwd, sizeof(cwd)))
{
DLOG_PERROR("getcwd");
*cwd=0;
}
pid = fork();
if (pid == -1)
{
DLOG_PERROR("fork");
exit(2);
exit(20);
}
else if (pid != 0)
exit(0);
if (*cwd)
{
int res = chdir(cwd);
}
if (*cwd && chdir(cwd)<0)
DLOG_PERROR("chdir");
if (setsid() == -1)
exit(2);
if (chdir("/") == -1)
exit(2);
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
{
DLOG_PERROR("setsid");
exit(21);
}
if (close(STDIN_FILENO)<0 && errno!=EBADF)
{
DLOG_PERROR("close(stdin)");
exit(22);
}
if (close(STDOUT_FILENO)<0 && errno!=EBADF)
{
DLOG_PERROR("close(stdout)");
exit(22);
}
if (close(STDERR_FILENO)<0 && errno!=EBADF)
{
DLOG_PERROR("close(stderr)");
exit(22);
}
/* redirect fd's 0,1,2 to /dev/null */
open("/dev/null", O_RDWR);
int fd;
/* stdin */
fd = dup(0);
if (open("/dev/null", O_RDWR)<0)
{
// will work only if debug not to console
DLOG_PERROR("open(stdin)");
exit(23);
}
/* stdout */
fd = dup(0);
if (dup(0)<0)
{
// will work only if debug not to console
DLOG_PERROR("dup(stdout)");
exit(24);
}
/* stderror */
if (dup(0)<0)
{
// will work only if debug not to console
DLOG_PERROR("dup(stderr)");
exit(25);
}
}
bool writepid(const char *filename)
+27
View File
@@ -18,6 +18,25 @@ bool dropcaps(void);
#define arch_nr (offsetof(struct seccomp_data, arch))
#define syscall_arg(x) (offsetof(struct seccomp_data, args[x]))
#ifndef __AUDIT_ARCH_64BIT
#define __AUDIT_ARCH_64BIT 0x80000000
#endif
#ifndef __AUDIT_ARCH_LE
#define __AUDIT_ARCH_LE 0x40000000
#endif
#ifndef EM_RISCV
#define EM_RISCV 243
#endif
#ifndef AUDIT_ARCH_RISCV64
#define AUDIT_ARCH_RISCV64 (EM_RISCV | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE)
#endif
#ifndef EM_LOONGARCH
#define EM_LOONGARCH 258
#endif
#ifndef AUDIT_ARCH_LOONGARCH64
#define AUDIT_ARCH_LOONGARCH64 (EM_LOONGARCH | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE)
#endif
#if defined(__aarch64__)
# define ARCH_NR AUDIT_ARCH_AARCH64
@@ -72,6 +91,14 @@ bool dropcaps(void);
# define ARCH_NR AUDIT_ARCH_RISCV64
#elif defined(__loongarch__) && __loongarch_grlen == 64
# define ARCH_NR AUDIT_ARCH_LOONGARCH64
#elif defined(__e2k__)
# define ARCH_NR AUDIT_ARCH_E2K
#else
# error "Platform does not support seccomp filter yet"
+164
View File
@@ -0,0 +1,164 @@
#include "timer.h"
#include "params.h"
#include "helpers.h"
#include "lua.h"
#undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
static bool oom = false;
static void ut_oom_recover(void *elem)
{
oom = true;
}
static unsigned int timer_n=0;
static void TimerPoolDestroyItem(timer_pool *elem)
{
free(elem->str);
luaL_unref(params.L, LUA_REGISTRYINDEX, elem->lua_ref);
luaL_unref(params.L, LUA_REGISTRYINDEX, elem->func_ref);
}
void TimerPoolDel(timer_pool **pp, timer_pool *p)
{
TimerPoolDestroyItem(p);
HASH_DEL(*pp,p);
free(p);
}
void TimerPoolDestroy(timer_pool **pp)
{
timer_pool *elem, *tmp;
HASH_ITER(hh, *pp, elem, tmp) TimerPoolDel(pp,elem);
}
struct timer_pool *TimerPoolSearch(timer_pool *p, const char *str)
{
timer_pool *elem_find;
HASH_FIND_STR(p, str, elem_find);
return elem_find;
}
struct timer_pool *TimerPoolAdd(timer_pool **pp, const char *str, uint64_t period, bool oneshot)
{
ADD_STR_POOL(timer_pool, pp, str, strlen(str))
elem->lua_ref = LUA_NOREF;
elem->func_ref = LUA_NOREF;
elem->period = period;
elem->oneshot = oneshot;
elem->bt_next = boottime_ms() + elem->period;
elem->n = ++timer_n;
elem->fires = 0;
return elem;
}
static bool TimerPoolRunTimer(timer_pool *p)
{
lua_rawgeti(params.L, LUA_REGISTRYINDEX, p->func_ref);
lua_pushstring(params.L, p->str);
lua_rawgeti(params.L, LUA_REGISTRYINDEX, p->lua_ref);
p->fires++;
DLOG("\ntimer: '%s' period %llu oneshot %u fires=%u\n",p->str,p->period,p->oneshot,p->fires);
int status = lua_pcall(params.L, 2, 0, 0);
if (status)
{
lua_dlog_error();
return false;
}
return true;
}
uint64_t TimerPoolNext(const timer_pool *p, bool *dirty)
{
*dirty = false;
if (!p) return 0;
const timer_pool *elem, *tmp;
uint64_t mintime=0x7FFFFFFFFFFFFFFF;
HASH_ITER(hh, p, elem, tmp)
{
if (elem->bt_next < mintime) mintime = elem->bt_next;
}
return mintime;
}
uint64_t TimerPoolRun(timer_pool **pp, bool *dirty, uint64_t bt)
{
if (!*pp)
{
*dirty = false;
return 0; // no timers
}
timer_pool *elem, *tmp, *p;
char *name;
const char *del;
unsigned int n;
uint64_t mintime;
if (!bt) bt = boottime_ms();
again:
mintime=0x7FFFFFFFFFFFFFFF;
*dirty = false;
HASH_ITER(hh, *pp, elem, tmp)
{
if (bt >= elem->bt_next)
{
if ((name = strdup(elem->str)))
{
n = elem->n;
del = NULL;
if (!TimerPoolRunTimer(elem))
del = "timer: '%s' deleted because of error\n";
if (*dirty)
{
// timer function could delete the timer or recreate with the same name
p = TimerPoolSearch(*pp, name);
if (p!=elem || p->n!=n) elem = NULL; // timer deleted or recreated with the same name (but another 'n')
}
if (elem)
{
if (!del && elem->oneshot)
del = "timer: '%s' deleted because of oneshot\n";
// elem is valid, not deleted and not recreated
if (del)
{
DLOG(del,name);
TimerPoolDel(pp, elem);
elem = NULL;
}
else
{
// in case process was freezed (--ssid-filter/nlm-filter stop in winws for example)
// do not use previous activation time or timer can hit multiple times
// use current time instead to prevent bulk activation
elem->bt_next = bt + elem->period;
}
}
free(name);
if (*dirty)
goto again; // they may have deleted or created any number of timers, HASH_ITER may fail or access invalid pointers - restart
}
else // unlikely
{
if (elem->oneshot)
{
DLOG_ERR("timer: '%s' deleted because of out of memory\n", elem->str);
TimerPoolDel(pp, elem);
elem = NULL;
}
else
{
DLOG_ERR("timer: '%s' skipped because of out of memory\n", elem->str);
elem->bt_next = bt + elem->period;
}
}
}
if (elem && (elem->bt_next < mintime)) mintime = elem->bt_next;
}
if (!*pp) return 0; // no timers
return mintime;
}
+25
View File
@@ -0,0 +1,25 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include "pools.h"
typedef struct timer_pool {
char *str; /* key */
int func_ref;
uint64_t period;
bool oneshot;
int lua_ref;
uint64_t bt_next; /* next activation time */
unsigned int n, fires;
UT_hash_handle hh; /* makes this structure hashable */
} timer_pool;
void TimerPoolDestroy(timer_pool **pp);
struct timer_pool *TimerPoolSearch(timer_pool *p, const char *str);
struct timer_pool *TimerPoolAdd(timer_pool **pp, const char *str, uint64_t period, bool oneshot);
void TimerPoolDel(timer_pool **pp, timer_pool *p);
// return next timer fire time
uint64_t TimerPoolRun(timer_pool **pp, bool *dirty, uint64_t bt);
uint64_t TimerPoolNext(const timer_pool *p, bool *dirty);
+13 -12
View File
@@ -1,5 +1,5 @@
/*
Copyright (c) 2003-2021, Troy D. Hanson http://troydhanson.github.io/uthash/
Copyright (c) 2003-2025, Troy D. Hanson https://troydhanson.github.io/uthash/
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -30,12 +30,9 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <stddef.h> /* ptrdiff_t */
#include <stdlib.h> /* exit */
#if defined(HASH_DEFINE_OWN_STDINT) && HASH_DEFINE_OWN_STDINT
/* This codepath is provided for backward compatibility, but I plan to remove it. */
#warning "HASH_DEFINE_OWN_STDINT is deprecated; please use HASH_NO_STDINT instead"
typedef unsigned int uint32_t;
typedef unsigned char uint8_t;
#elif defined(HASH_NO_STDINT) && HASH_NO_STDINT
#if defined(HASH_NO_STDINT) && HASH_NO_STDINT
/* The user doesn't have <stdint.h>, and must figure out their own way
to provide definitions for uint8_t and uint32_t. */
#else
#include <stdint.h> /* uint8_t, uint32_t */
#endif
@@ -51,6 +48,8 @@ typedef unsigned char uint8_t;
#else /* VS2008 or older (or VS2010 in C mode) */
#define NO_DECLTYPE
#endif
#elif defined(__MCST__) /* Elbrus C Compiler */
#define DECLTYPE(x) (__typeof(x))
#elif defined(__BORLANDC__) || defined(__ICCARM__) || defined(__LCC__) || defined(__WATCOMC__)
#define NO_DECLTYPE
#else /* GNU, Sun and other compilers */
@@ -157,7 +156,7 @@ do {
if (head) { \
unsigned _hf_bkt; \
HASH_TO_BKT(hashval, (head)->hh.tbl->num_buckets, _hf_bkt); \
if (HASH_BLOOM_TEST((head)->hh.tbl, hashval) != 0) { \
if (HASH_BLOOM_TEST((head)->hh.tbl, hashval)) { \
HASH_FIND_IN_BKT((head)->hh.tbl, hh, (head)->hh.tbl->buckets[ _hf_bkt ], keyptr, keylen, hashval, out); \
} \
} \
@@ -194,7 +193,7 @@ do {
} while (0)
#define HASH_BLOOM_BITSET(bv,idx) (bv[(idx)/8U] |= (1U << ((idx)%8U)))
#define HASH_BLOOM_BITTEST(bv,idx) (bv[(idx)/8U] & (1U << ((idx)%8U)))
#define HASH_BLOOM_BITTEST(bv,idx) ((bv[(idx)/8U] & (1U << ((idx)%8U))) != 0)
#define HASH_BLOOM_ADD(tbl,hashv) \
HASH_BLOOM_BITSET((tbl)->bloom_bv, ((hashv) & (uint32_t)((1UL << (tbl)->bloom_nbits) - 1U)))
@@ -206,7 +205,7 @@ do {
#define HASH_BLOOM_MAKE(tbl,oomed)
#define HASH_BLOOM_FREE(tbl)
#define HASH_BLOOM_ADD(tbl,hashv)
#define HASH_BLOOM_TEST(tbl,hashv) (1)
#define HASH_BLOOM_TEST(tbl,hashv) 1
#define HASH_BLOOM_BYTELEN 0U
#endif
@@ -450,7 +449,7 @@ do {
#define HASH_DELETE_HH(hh,head,delptrhh) \
do { \
struct UT_hash_handle *_hd_hh_del = (delptrhh); \
const struct UT_hash_handle *_hd_hh_del = (delptrhh); \
if ((_hd_hh_del->prev == NULL) && (_hd_hh_del->next == NULL)) { \
HASH_BLOOM_FREE((head)->hh.tbl); \
uthash_free((head)->hh.tbl->buckets, \
@@ -593,7 +592,9 @@ do {
/* SAX/FNV/OAT/JEN hash functions are macro variants of those listed at
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx */
* http://eternallyconfuzzled.com/tuts/algorithms/jsw_tut_hashing.aspx
* (archive link: https://archive.is/Ivcan )
*/
#define HASH_SAX(key,keylen,hashv) \
do { \
unsigned _sx_i; \
-6
View File
@@ -28,12 +28,6 @@ bool service_run(int argc, char *argv[])
return StartServiceCtrlDispatcherA(ServiceTable);
}
static void service_set_status(DWORD state)
{
ServiceStatus.dwCurrentState = state;
SetServiceStatus(hStatus, &ServiceStatus);
}
// Control handler function
void service_controlhandler(DWORD request)
{
+1 -1
View File
@@ -4,6 +4,6 @@
#include <stdbool.h>
bool service_run();
bool service_run(int argc, char *argv[]);
#endif
Binary file not shown.
Binary file not shown.