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

569 Commits

Author SHA1 Message Date
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
bol-van
181395be87 nfqws2: compile compat 2026-02-04 15:14:49 +03:00
bol-van
fb71a41ea5 nfqws2: compile compat 2026-02-04 15:12:23 +03:00
bol-van
7f8f64a355 nfqws2: compile compat 2026-02-04 15:04:59 +03:00
bol-van
7e31dc9d89 update docs 2026-02-04 14:24:34 +03:00
bol-van
4a9072a949 nfqws2: unblocked bcryptorandom, --new=name, AI fixes 2026-02-04 14:24:10 +03:00
bol-van
4b0e3af020 update docs 2026-02-03 22:42:03 +03:00
bol-van
d442a38774 update docs 2026-02-03 22:40:48 +03:00
bol-van
ede3515fa3 update docs 2026-02-03 22:37:59 +03:00
bol-van
831cf02ad5 update docs 2026-02-03 22:33:10 +03:00
bol-van
c436470b18 nfqws2: type field in stat table 2026-02-03 22:32:57 +03:00
bol-van
56b4ce0b2a nfqws2: clock_getfloattime() 2026-02-03 22:03:56 +03:00
bol-van
18b33008af nfqws2: stat luacall 2026-02-03 21:58:14 +03:00
bol-van
c72c48432e nfqws2: fix icmp data32 2026-02-03 17:08:45 +03:00
bol-van
c5894b0708 nfqws2: fix icmp_data reconstruct in 32-bit luajit 2026-02-03 16:40:14 +03:00
bol-van
79b018dd74 nfqws2: check ip version=4 2026-02-03 15:58:08 +03:00
bol-van
56cce72dac github: disable check sig for cygwin 2026-02-03 12:23:43 +03:00
bol-van
a8b4007386 github: disable check sig for cygwin 2026-02-03 11:15:40 +03:00
bol-van
2977c20044 AI inspired fixes 2026-02-03 10:45:15 +03:00
bol-van
d432e770a6 zapret-lib: fix broken verdict_aggregate 2026-02-02 19:29:11 +03:00
bol-van
0574d609de update docs 2026-02-02 19:02:15 +03:00
bol-van
043b85dfb4 update docs 2026-02-02 18:14:37 +03:00
bol-van
22b7861603 update docs 2026-02-02 18:10:41 +03:00
bol-van
8b24076c20 update docs 2026-02-02 18:07:22 +03:00
bol-van
3abc22baf5 AI inspired fix 2026-02-02 18:02:31 +03:00
bol-van
739c24cdf3 nfqws2: process --filter-l3 as a list in templates 2026-02-02 13:57:40 +03:00
bol-van
5c97563698 AI inspired fixes 2026-02-02 11:02:33 +03:00
bol-van
2ddfe55d9a AI inspired fixes 2026-02-02 10:58:48 +03:00
bol-van
a781f3d1ce update docs 2026-02-01 16:01:30 +03:00
bol-van
080655c4c2 nfqws2: copy b_filter_l3 2026-02-01 15:57:09 +03:00
bol-van
3434739144 update docs 2026-02-01 14:50:57 +03:00
bol-van
740cbfbc34 nfqws2: copy param set bool 2026-02-01 14:32:18 +03:00
bol-van
37f0f4589f nfqws2: template free import 2026-02-01 14:28:24 +03:00
bol-van
9d7fed4c67 update docs 2026-02-01 11:32:01 +03:00
bol-van
2533a3debc update docs 2026-02-01 10:15:54 +03:00
bol-van
6e90adad5b update docs 2026-02-01 09:56:24 +03:00
bol-van
aa359128bb update docs 2026-02-01 09:53:22 +03:00
bol-van
fed07a0249 nfqws2: fix initial -1 scale, allow raw packets in conntrack_feed 2026-02-01 09:49:16 +03:00
bol-van
055ae067f9 AI inspired fixes 2026-01-31 18:06:44 +03:00
bol-van
2490ef6951 AI inspired fixes 2026-01-31 17:47:18 +03:00
bol-van
a531da39fd winws2: optimize bulk buffer size 2026-01-31 17:14:00 +03:00
bol-van
b920964ab3 winws2: optimize bulk buffer size 2026-01-31 17:13:37 +03:00
bol-van
7d9f5a4b83 winws2: use windivert bulk mode 2026-01-31 16:54:17 +03:00
bol-van
b157613b1a nfqws2: minor beautify 2026-01-31 13:24:48 +03:00
bol-van
4081878b36 update docs 2026-01-31 13:19:37 +03:00
bol-van
b1fbf5c81a update docs 2026-01-31 13:17:33 +03:00
bol-van
04d940e619 nfqws2: fix comments 2026-01-31 13:00:52 +03:00
bol-van
bd9aec8374 zapret-obfs: synhide: conntrack_feed for both server and client 2026-01-31 11:44:11 +03:00
bol-van
e9bffca658 zapret-obfs: synhide: use conntrack_feed, use x2 magic by default 2026-01-31 11:28:16 +03:00
bol-van
001942fe74 nfqws2: conntrack_feed() 2026-01-31 11:26:20 +03:00
bol-van
f5d1108cce winws2: remove vista from manifest 2026-01-31 09:41:30 +03:00
bol-van
27d387c76d zapret-obfs: fix comment 2026-01-30 21:59:11 +03:00
bol-van
d5306fb97a nfqws2: android 5 compat 2026-01-30 21:47:19 +03:00
bol-van
5f87b7670a AI inspired fixes 2026-01-30 19:18:17 +03:00
bol-van
2a2a3e4f73 AI inspired fixes 2026-01-30 19:06:13 +03:00
bol-van
1f99fb49af zapret-obfs: remove wrong comment 2026-01-30 18:58:59 +03:00
bol-van
b99b59bbdb zapret-obfs: synhide xorseq 2026-01-30 18:55:56 +03:00
bol-van
9128601820 AI inspired fixes 2026-01-30 17:23:47 +03:00
bol-van
584d3b5925 zapret-obfs: synhide more magics 2026-01-30 16:37:19 +03:00
bol-van
eff7e6488a fix openwrt makefile 2026-01-30 13:16:01 +03:00
bol-van
27c49bcfe4 zapret-obfs: add comment 2026-01-30 11:54:21 +03:00
bol-van
48fbd39ada zapret-obfs: synhide 2026-01-30 11:52:59 +03:00
bol-van
6eb4970c9b update docs 2026-01-29 18:03:23 +03:00
bol-van
ba5cff29f1 update docs 2026-01-29 18:01:47 +03:00
bol-van
bd155daa91 update docs 2026-01-29 17:57:55 +03:00
bol-van
5de6595ccd update docs 2026-01-29 17:53:41 +03:00
bol-van
4253b7b408 update docs 2026-01-29 17:52:31 +03:00
bol-van
389a331d83 update docs 2026-01-29 17:51:37 +03:00
bol-van
540094baac update docs 2026-01-29 16:07:36 +03:00
bol-van
a3c4724542 update docs 2026-01-29 16:06:59 +03:00
bol-van
79f33ef75a update docs 2026-01-29 16:06:20 +03:00
bol-van
d4c1126961 makefile: -Wno-alloc-size-larger-than 2026-01-29 14:25:12 +03:00
bol-van
9e378f629d update docs 2026-01-29 13:52:16 +03:00
bol-van
227c2e76e3 update docs 2026-01-29 13:48:07 +03:00
bol-van
2f74d21923 update docs 2026-01-29 13:46:06 +03:00
bol-van
4376aa0cdf update docs 2026-01-29 13:45:29 +03:00
bol-van
331e0dcbab update docs 2026-01-29 13:31:03 +03:00
bol-van
f1af8cbde9 update docs 2026-01-29 13:30:15 +03:00
bol-van
b865591f2a update docs 2026-01-29 13:29:27 +03:00
bol-van
384d219597 update docs 2026-01-29 12:37:25 +03:00
bol-van
7880782a95 update docs 2026-01-29 12:36:13 +03:00
bol-van
d914472542 update docs 2026-01-29 12:32:56 +03:00
bol-van
6a32bc46e2 update docs 2026-01-29 12:31:12 +03:00
bol-van
8cf0d68d58 update docs 2026-01-29 10:53:24 +03:00
bol-van
04134d78ee update docs 2026-01-29 10:51:38 +03:00
bol-van
47f6410946 winws2: --wf-raw-filter 2026-01-29 10:16:12 +03:00
bol-van
a29e159895 rm bad files 2026-01-29 10:15:24 +03:00
bol-van
e5fd657a8a zapret-obfs: change comments 2026-01-29 09:42:02 +03:00
bol-van
faea98da74 zapret-obfs: use shim in wgobfs 2026-01-29 09:40:45 +03:00
bol-van
c8722d1ed9 update docs 2026-01-28 18:41:38 +03:00
bol-van
77e405e24d update docs 2026-01-28 18:38:15 +03:00
bol-van
7c5dfad8e2 update docs 2026-01-28 18:27:11 +03:00
bol-van
b25f16126b update docs 2026-01-28 18:25:53 +03:00
bol-van
4970c01344 update docs 2026-01-28 18:23:29 +03:00
bol-van
4e412ab2d6 update docs 2026-01-28 18:22:55 +03:00
bol-van
a2374f0fcf update docs 2026-01-28 18:17:33 +03:00
bol-van
65337446d4 update docs 2026-01-28 18:09:27 +03:00
bol-van
be88140bb0 nfqws2: icmpv6 codes lua constants 2026-01-28 17:19:02 +03:00
bol-van
27fff3f5c3 nfqws2: use conntrack l7 proto for related icmp 2026-01-28 16:54:21 +03:00
bol-van
8ba5739ef2 zapret-obfs: minor changes 2026-01-28 15:45:18 +03:00
bol-van
a788975268 zapret-obfs: udp2icmp server parameter without value means 1 2026-01-28 14:41:31 +03:00
bol-van
e441711b05 zapret-obfs.lua: udp2icmp 2026-01-28 14:10:09 +03:00
bol-van
314627d851 zapret-obfs: fix ippxor=0 case 2026-01-27 19:59:36 +03:00
bol-van
4560ef6d5b zapret-obfs: optimize 2026-01-27 18:53:26 +03:00
bol-van
431e794356 zapret-obfs: optimize 2026-01-27 18:51:29 +03:00
bol-van
f50bd701f7 zapret-obfs: optimize 2026-01-27 18:21:23 +03:00
bol-van
15f29169d5 blockcheck2: more ttl=0 fixes 2026-01-27 17:37:24 +03:00
bol-van
a106519f1e zapret-tests update 2026-01-27 15:43:06 +03:00
bol-van
5b016f62e4 zapret-obfs: ippxor 2026-01-27 14:08:10 +03:00
bol-van
68c15864a4 nfqws2: print ver on all os 2026-01-27 10:25:04 +03:00
bol-van
752cafad7c fix stupid AI suggestion 2026-01-26 20:12:25 +03:00
bol-van
12853b8052 zapret-tests: send raw ip protocol 2026-01-26 18:39:33 +03:00
bol-van
1d869650b1 nfqws2: dissect of partial packets 2026-01-26 16:04:06 +03:00
bol-van
12a9bf8b19 nfqws2: icmp payload type for unrelated icmps 2026-01-26 15:34:19 +03:00
bol-van
4ade6f7e82 del old files 2026-01-26 15:02:57 +03:00
bol-van
6adb789314 icmp and ipp support 2026-01-26 14:55:24 +03:00
bol-van
78b3baa03f icmp and ipp support 2026-01-26 14:22:38 +03:00
bol-van
90fa71d6d6 openbsd build info fix 2026-01-26 09:07:30 +03:00
bol-van
e33e1a9b89 openbsd build info fix 2026-01-26 09:06:34 +03:00
bol-van
e7f0e79f78 binaries with readme 2026-01-26 09:04:12 +03:00
bol-van
8b11d6c279 update docs 2026-01-24 20:25:35 +03:00
bol-van
30044e8c61 zapret-auto: check track 2026-01-22 23:02:54 +03:00
bol-van
1cffa0f5ec blockcheck2: --wf-tcp-empty=1 required for some methods 2026-01-22 14:58:33 +03:00
bol-van
8bee9efcf0 update docs 2026-01-20 11:13:38 +03:00
bol-van
848221b096 nfqws2: use __close in lua 5.5 2026-01-20 11:03:59 +03:00
bol-van
fb3bdd9b70 zapret-lib: gzip use local gz 2026-01-20 11:03:03 +03:00
bol-van
ca6d145312 lua 5.5 2026-01-20 10:31:55 +03:00
bol-van
01d78e8dc4 lua 5.5 2026-01-20 10:29:08 +03:00
bol-van
db050b9ba1 blockcheck2: fix broken iptables rule 2026-01-19 16:42:17 +03:00
bol-van
b65da8d8db nfqws2: remove unused var 2026-01-19 16:30:37 +03:00
bol-van
1359986d29 nfqws2: deduplicate code 2026-01-19 16:28:12 +03:00
bol-van
36ee42bc8c nfqws2: remove unneeded code 2026-01-19 12:02:30 +03:00
bol-van
a8373a8400 update docs 2026-01-19 11:54:40 +03:00
bol-van
33b1e81041 nfqws2: check hostlist/ipset file is readable before destroying in-memory copy 2026-01-19 11:46:21 +03:00
bol-van
577d9e6aba AI inspired fixes 2026-01-19 11:25:49 +03:00
bol-van
3caf1ce10a zapret-auto: circular DLOG instead of DLOG_ERR if no track 2026-01-18 18:17:43 +03:00
bol-van
8e67260a23 nfqws2: minor optimize 2026-01-18 13:16:01 +03:00
bol-van
378b1c727d nfqws2: removed hard check for host: presence in http_req 2026-01-18 11:47:06 +03:00
bol-van
14bd4832a4 update docs 2026-01-18 11:33:12 +03:00
bol-van
6d8b405bf0 update docs 2026-01-18 11:29:17 +03:00
bol-van
00b6d70efc nfqws2: tcp protocol_probe reasm data 2026-01-18 10:59:03 +03:00
bol-van
ca14fbe9c8 AI inspired fixes 2026-01-17 23:09:08 +03:00
bol-van
c81968b94b nfqws2: fix wrong ipv6 dissection 2026-01-17 22:40:08 +03:00
bol-van
a2d567c7a0 nfqws2: fix wrong ipv6 dissection 2026-01-17 22:31:21 +03:00
bol-van
5026199f24 zapret-antidpi: oob instance cutoff if called not from the very beginning of tcp 2026-01-17 19:45:54 +03:00
bol-van
68435f64ea update docs 2026-01-17 18:11:01 +03:00
bol-van
d84dfaf61d blockcheck2, winws: multiple instances compat 2026-01-17 18:03:06 +03:00
bol-van
4c13c63d27 AI inspired fixes 2026-01-17 13:31:48 +03:00
bol-van
5dde1264ce update docs 2026-01-17 10:26:36 +03:00
bol-van
cc989c52ed update docs 2026-01-17 10:01:38 +03:00
bol-van
0446b1493b AI inspired fixes 2026-01-17 10:01:26 +03:00
bol-van
97cd8cebca update docs 2026-01-17 09:53:37 +03:00
bol-van
2d02eeb578 blockcheck2: tcp_nop_del for openbsd 2026-01-17 09:50:39 +03:00
bol-van
fe318a42e8 zapret-lib: tcp_nop_del 2026-01-16 21:34:18 +03:00
bol-van
73c10e3f15 update docs 2026-01-16 18:37:58 +03:00
bol-van
17cf260fd0 update docs 2026-01-16 18:33:19 +03:00
bol-van
fa15c635bb update docs 2026-01-16 18:24:13 +03:00
bol-van
74690047b5 update docs 2026-01-16 18:18:56 +03:00
bol-van
d24453da69 update docs 2026-01-16 18:16:56 +03:00
bol-van
af200628cd update docs 2026-01-16 18:15:19 +03:00
bol-van
76fe7bff82 update docs 2026-01-16 18:14:16 +03:00
bol-van
1d1eedbb3b update docs 2026-01-16 18:06:56 +03:00
bol-van
274b331825 blockcheck2: remove drop_ack from oob 2026-01-16 17:12:53 +03:00
bol-van
69f900b3da udpate docs 2026-01-16 17:06:10 +03:00
bol-van
da9faabf97 udpate docs 2026-01-16 17:00:16 +03:00
bol-van
60934f5ab8 udpate docs 2026-01-16 16:53:17 +03:00
bol-van
eb7043fc12 zapret-antidpi: oob remove drop_ack 2026-01-16 16:37:56 +03:00
bol-van
681c53c3b4 AI inspired fixes 2026-01-16 16:17:34 +03:00
bol-van
65f6923383 update docs 2026-01-16 15:30:00 +03:00
bol-van
f0f59261bb update docs 2026-01-16 15:29:37 +03:00
bol-van
06cf59d050 update docs 2026-01-16 15:24:48 +03:00
bol-van
f0bff44219 update docs 2026-01-16 15:24:15 +03:00
bol-van
da0016ed0e update docs 2026-01-16 15:23:12 +03:00
bol-van
704c73f821 zapret-antidpi: oob error if char != 1 symbol 2026-01-16 15:05:23 +03:00
bol-van
201dd40b46 zapret-antidpi: oob error if char > 1 symbol 2026-01-16 15:04:16 +03:00
bol-van
aa13a1f5d2 blockcheck2: oob --wf-tcp-empty=1 in windows 2026-01-16 14:57:59 +03:00
bol-van
2a3b6f2a8b zapret-antidpi: oob dlog drop_ack event 2026-01-16 14:56:39 +03:00
bol-van
801dec81c8 ask_list default value fix 2026-01-16 14:18:26 +03:00
bol-van
14359afb93 AI inspired fixes 2026-01-16 13:52:46 +03:00
bol-van
372c6748ca zapret-lib,antidpi: optimizations 2026-01-15 23:30:55 +03:00
bol-van
87d2fcd5a1 blockcheck2: AI fixes and oob 2026-01-15 22:34:15 +03:00
bol-van
74ddd4f9d2 AI inspired fixes 2026-01-15 21:29:37 +03:00
bol-van
6b7507deb5 nfqws2: set desync.tcp_mss to minimum of both ends or default if at least one is unknown 2026-01-15 20:51:57 +03:00
bol-van
f8156a3d38 blockcheck2: ttl/autottl disable fix for BSD 2026-01-15 20:29:40 +03:00
bol-van
67a8ee47e3 zapret-antidpi: oob 2026-01-15 20:05:22 +03:00
bol-van
93d81ca4b2 blockcheck: multiple NOTEST fixes 2026-01-15 15:08:30 +03:00
bol-van
3d9a36600b blockcheck: NOTEST_SEQOVL fix 2026-01-15 15:04:01 +03:00
bol-van
c3adb3f045 nfqws2: simplify complex unwinds in lua code 2026-01-15 11:46:36 +03:00
bol-van
f919533873 nfqws2: simplify complex unwinds in lua code 2026-01-15 11:40:39 +03:00
bol-van
17bdfe16b1 blockcheck2: custom test special chars escape warning 2026-01-15 10:22:00 +03:00
bol-van
bc0102fbdc nfqws2: do not require / in the beginning of URI in http 2026-01-15 10:13:08 +03:00
bol-van
10d72b3242 AI inspired fixes 2026-01-15 09:41:55 +03:00
bol-van
9dd14dfc7c nfqws2: check ipv6 plen 2026-01-14 19:13:46 +03:00
bol-van
10201f1abf nfqws2: bitset/bitget check negative from-to 2026-01-14 17:39:15 +03:00
bol-van
236550918b update docs 2026-01-14 17:22:27 +03:00
bol-van
72a269e88d makefile fixes 2026-01-14 17:08:35 +03:00
bol-van
d3199eebd3 zapret-tests: fixes and ipv6 rawsend 2026-01-14 16:40:44 +03:00
bol-van
ffcb14726d AI and manual fixes 2026-01-14 16:39:16 +03:00
bol-van
aa5a1f4183 zapret-wgobfs: add comment 2026-01-14 09:49:28 +03:00
bol-van
ca186a6566 AI inspired fixes 2026-01-14 09:47:12 +03:00
bol-van
dced388652 update docs 2026-01-13 13:48:20 +03:00
bol-van
1f7d10bf5b update docs 2026-01-13 13:47:48 +03:00
bol-van
6b1b4adddb update docs 2026-01-13 13:46:49 +03:00
bol-van
cfe7b76352 update docs 2026-01-13 13:43:52 +03:00
bol-van
62fd0dc432 update docs 2026-01-13 13:42:11 +03:00
bol-van
050a01bda2 update docs 2026-01-13 13:40:57 +03:00
bol-van
4c5d84c19e update docs 2026-01-13 13:40:23 +03:00
bol-van
d430b4775d update docs 2026-01-13 13:38:49 +03:00
bol-van
807565968e update docs 2026-01-13 13:38:16 +03:00
bol-van
e062b1795e update docs 2026-01-13 13:37:28 +03:00
bol-van
3417e50438 update docs 2026-01-13 13:35:56 +03:00
bol-van
70f5a88ec0 update docs 2026-01-13 13:22:34 +03:00
bol-van
4b3fba3fb2 nfqws2: add comments 2026-01-13 10:39:15 +03:00
bol-van
9cded5448a nfqws2: add comments 2026-01-13 10:38:00 +03:00
bol-van
2302ac6949 nfqws2: optimize unmodified csum fix logic 2026-01-13 10:33:59 +03:00
bol-van
0be76b902e nfqws2: minor optimize 2026-01-12 20:23:54 +03:00
bol-van
fa89e011fb nfqws2: align packet buffers 2026-01-12 18:32:52 +03:00
bol-van
622a81001d AI inspired fixes 2026-01-12 16:51:40 +03:00
bol-van
4d793b73a4 nfqws2: do nothing on signals if quit requested 2026-01-12 11:32:38 +03:00
bol-van
a47b6a529b update docs 2026-01-12 10:51:29 +03:00
bol-van
7c320c8d57 update docs 2026-01-12 10:13:26 +03:00
bol-van
b18f0770c8 update docs 2026-01-12 10:12:35 +03:00
bol-van
f7fc845014 update docs 2026-01-12 10:11:10 +03:00
bol-van
2c1a885a07 update docs 2026-01-12 10:10:01 +03:00
bol-van
9eb308d84c update docs 2026-01-12 10:09:02 +03:00
bol-van
3e724c3810 update docs 2026-01-12 10:03:35 +03:00
bol-van
c179d55d88 nfqws2: harden wireguard detector 2026-01-12 09:34:56 +03:00
bol-van
3f1af1441e nfqws2: check quit flag outside of EINTR context 2026-01-12 09:08:19 +03:00
bol-van
4c1b2b65f3 nfqws2: gracefully shutdown on SIGINT and SIGTERM 2026-01-11 21:01:18 +03:00
bol-van
918258413f nfqws2: fix tls reasm logic 2026-01-11 19:41:13 +03:00
bol-van
e6206c5a5f nfqws2: fix tls reasm 2026-01-11 18:20:29 +03:00
bol-van
f93c6de772 nfqws2: --payload-disable 2026-01-11 17:25:53 +03:00
bol-van
5a7e2b1ca2 nfqws2: alternative representation of payload filter in execution_plan item 2026-01-11 16:20:45 +03:00
bol-van
ca8104c72a zapret-lib: remove bitable, use barray 2026-01-11 15:36:10 +03:00
bol-van
3aad1f9ed9 nfqws2: optimize ctx userdata 2026-01-11 14:10:42 +03:00
bol-van
fd288d5e7d nfqws2: move ctx from lightuserdata to userdata. prevents crashes on specific ARM cpus 2026-01-11 13:58:31 +03:00
bol-van
349fe3f7d7 update docs 2026-01-11 12:32:44 +03:00
bol-van
4554b7c15b zapret-lib, zapret-antidpi: use numeric indexes in http dissects 2026-01-11 12:29:53 +03:00
bol-van
0b595ae3a8 AI inspired fixes 2026-01-11 11:39:37 +03:00
bol-van
3e69e1b8c1 zapret-lib: bitable 2026-01-11 11:21:12 +03:00
bol-van
02b895910b dvtws2: openbsd compile fix 2026-01-11 11:04:09 +03:00
bol-van
b2a53e9c64 nfqws2: AI inspired fixes 2026-01-11 10:56:24 +03:00
bol-van
a626cfce8a update docs 2026-01-11 09:36:47 +03:00
bol-van
ebcbfc37ba update docs 2026-01-10 20:14:44 +03:00
bol-van
33d3c94b68 update docs 2026-01-10 20:12:45 +03:00
bol-van
d55dbb7717 update docs 2026-01-10 20:05:21 +03:00
bol-van
cb82be9eab update docs 2026-01-10 20:04:01 +03:00
bol-van
024d36acc4 update docs 2026-01-10 20:02:06 +03:00
bol-van
08c6151a4c update docs 2026-01-10 19:56:22 +03:00
bol-van
520317dc3c update docs 2026-01-10 19:24:02 +03:00
bol-van
6bc0bf1b97 AI inspired fixes 2026-01-10 18:54:26 +03:00
bol-van
d18fec9053 update docs 2026-01-10 16:47:40 +03:00
bol-van
e60e5a0578 update docs 2026-01-10 16:46:44 +03:00
bol-van
84576a7039 update docs 2026-01-10 16:44:07 +03:00
bol-van
7957a0a425 update docs 2026-01-10 16:42:58 +03:00
bol-van
7ba4110416 update docs 2026-01-10 16:35:54 +03:00
bol-van
4babaef6a8 update docs 2026-01-10 16:32:54 +03:00
bol-van
872e37d160 update docs 2026-01-10 16:28:48 +03:00
bol-van
a8219f4897 update docs 2026-01-10 16:25:24 +03:00
bol-van
36267b7e9b update docs 2026-01-10 16:22:35 +03:00
bol-van
99a7f06976 eng manual 2026-01-10 15:42:42 +03:00
bol-van
3617b8934f blockcheck2: 23-seqovl fix 2026-01-10 14:58:38 +03:00
bol-van
8e6387a6df config.default add MDIG comments 2026-01-09 13:14:36 +03:00
bol-van
3bc0e8e350 mdig: EAGAIN->EAI_AGAIN help text 2026-01-09 12:38:06 +03:00
bol-van
7f12334872 update docs 2026-01-09 12:04:48 +03:00
bol-van
0f42ff1731 ipset: mdig eagain support 2026-01-09 12:00:56 +03:00
bol-van
801328dc02 mdig: --eagain, --eagain-delay 2026-01-09 11:42:33 +03:00
bol-van
fdb9c9be60 mdig: increase EAGAIN attempts 2026-01-09 10:17:13 +03:00
bol-van
5e89db0c7b replace spaces with tabs 2026-01-08 20:43:55 +03:00
bol-van
0e95de6083 replace spaces with tabs 2026-01-08 20:43:20 +03:00
bol-van
3ec585c97e init.d: 99-lan-filter custom script 2026-01-08 20:20:52 +03:00
bol-van
577959f442 init.d: nft_detele_chain => nft_del_chain 2026-01-08 19:14:47 +03:00
bol-van
36731cd9b5 zapret1 unfixed parts 2026-01-08 19:13:34 +03:00
bol-van
b3b8133c39 nfqws2: minor safety fix 2026-01-08 12:19:41 +03:00
bol-van
5f96ce1099 nfqws2: minor safety fix 2026-01-08 12:18:54 +03:00
bol-van
2088f593d4 nfqws2: remove unused code 2026-01-08 11:55:51 +03:00
bol-van
03152ba76f nfqws2: move rawsend_cleanup 2026-01-08 11:46:45 +03:00
bol-van
f94d1b1d16 nfqws2: ignore trailing spaces and tabs in hostlists and ipsets 2026-01-08 11:38:13 +03:00
bol-van
790a2ca355 nfqws2: params leaks fix 2026-01-07 14:45:09 +03:00
bol-van
f318397726 AI inspired fixes 2026-01-07 13:44:56 +03:00
bol-van
5a116cf9be nfqws2: memleak fix 2026-01-07 13:18:30 +03:00
bol-van
d40f05865b zapret-tests: improve resolve tests 2026-01-07 12:35:19 +03:00
bol-van
e47603281c zapret-tests: improve resolve tests 2026-01-07 12:27:27 +03:00
bol-van
8ba58c8f16 update docs 2026-01-07 08:32:44 +03:00
bol-van
2def9397a0 zapret-lib: add expected_ratio to z_readfile 2026-01-07 08:31:23 +03:00
bol-van
a61895778b update docs 2026-01-07 08:26:51 +03:00
bol-van
a622061b45 nfqws2: optimize realloc increment 2026-01-07 08:24:04 +03:00
bol-van
1bbd342ff2 update docs 2026-01-07 08:15:43 +03:00
bol-van
84f978cee4 update docs 2026-01-07 08:14:24 +03:00
bol-van
dd3cffca5f update docs 2026-01-07 08:13:02 +03:00
bol-van
b699e5d9ec nfqws2, zapret-lib: more gzip optimizations 2026-01-07 08:09:41 +03:00
bol-van
e6591575fe ipset: -9 gzip ratio 2026-01-07 07:03:12 +03:00
bol-van
ca7569f68a update docs 2026-01-07 06:52:51 +03:00
bol-van
3a16523399 update docs 2026-01-07 06:51:58 +03:00
bol-van
2fd172118c nfqws2: change default expected gzip ratio 2026-01-07 06:50:15 +03:00
bol-van
c43574d056 nfqws2: gzip optimize memory alloc 2026-01-07 06:45:27 +03:00
bol-van
22d4df73f6 update docs 2026-01-07 06:36:14 +03:00
bol-van
23d6cddb30 nfqws2: coroutine compat 2026-01-06 23:12:28 +03:00
bol-van
c3b5d5e9ed update docs 2026-01-06 22:17:53 +03:00
bol-van
20856321c3 update docs 2026-01-06 22:15:31 +03:00
bol-van
75f3c7eac3 nfqws2: free zlib stream in __gc 2026-01-06 22:14:53 +03:00
bol-van
129461dc45 zapret-tests: gzip test 2026-01-06 21:06:14 +03:00
bol-van
91a3badc67 AI inspired fixes 2026-01-06 20:35:42 +03:00
bol-van
ff15bcceae nfqws2: fix clang warning 2026-01-06 17:18:46 +03:00
bol-van
61b20f86a7 update docs 2026-01-06 17:07:16 +03:00
bol-van
2de8809ead zapret-lib: writefile 2026-01-06 17:07:08 +03:00
bol-van
c77e8f799f update docs 2026-01-06 16:49:46 +03:00
bol-van
4cdf498a14 update docs 2026-01-06 16:48:33 +03:00
bol-van
4bbfc3081d update docs 2026-01-06 16:47:25 +03:00
bol-van
1099cf013d update docs 2026-01-06 16:46:42 +03:00
bol-van
cb85f6e672 zapret-lib: fix error message 2026-01-06 16:42:00 +03:00
bol-van
823f4a6fb6 zapret-lib: fix error message 2026-01-06 16:41:35 +03:00
bol-van
05647e84ef zapret-lib: do not error on premature file end 2026-01-06 16:40:58 +03:00
bol-van
8bc74d0c4f nfqws2, zapret-lib: gzip 2026-01-06 16:23:18 +03:00
bol-van
0eb6cc9722 nfqws2: remove unused lua code 2026-01-06 12:08:35 +03:00
bol-van
13594401c6 init.d: 80-dns-intercept fix wrong comments 2026-01-05 10:43:35 +03:00
bol-van
2983c681d7 update docs 2026-01-04 14:28:02 +03:00
bol-van
68eefd9dd7 update docs 2026-01-04 14:21:14 +03:00
bol-van
73f6f7c522 update docs 2026-01-04 14:18:54 +03:00
bol-van
df83a29b98 update docs 2026-01-04 14:17:07 +03:00
bol-van
9881cc4da2 update docs 2026-01-04 13:00:37 +03:00
bol-van
44f8ad6747 update docs 2026-01-04 12:38:33 +03:00
bol-van
c651367d6a update docs 2026-01-04 12:35:08 +03:00
bol-van
90f88271c5 update docs 2026-01-04 12:34:07 +03:00
bol-van
9ba8d6cbdf update docs 2026-01-04 12:18:17 +03:00
bol-van
27efbb37d7 update docs 2026-01-04 12:16:57 +03:00
bol-van
d725bd8fd7 update docs 2026-01-04 12:13:58 +03:00
bol-van
0ef50d04dc update docs 2026-01-04 12:13:33 +03:00
bol-van
fdae4b1812 update docs 2026-01-04 12:08:36 +03:00
bol-van
d0644f6160 update docs 2026-01-04 12:06:01 +03:00
bol-van
b4f1765574 update docs 2026-01-04 12:04:58 +03:00
bol-van
8454d48fcd update docs 2026-01-04 12:01:30 +03:00
bol-van
70d7a77d06 update docs 2026-01-04 11:56:51 +03:00
bol-van
2a48f82feb update docs 2026-01-04 11:54:34 +03:00
bol-van
c5d997ce48 update docs 2026-01-04 11:52:55 +03:00
bol-van
c950edb380 update docs 2026-01-04 11:39:23 +03:00
bol-van
0d96b03f49 blockcheck2: additional NOTEST 2026-01-04 11:38:47 +03:00
bol-van
9772641813 init.d: 80-dns-intercept use mangle iptable 2026-01-03 20:19:28 +03:00
bol-van
7307a03ff7 init.d: 80-dns-intercept print_op 2026-01-03 20:16:49 +03:00
bol-van
b529198f24 80-dns-intercept: remove DISABLE_IPVx filters 2026-01-03 19:59:51 +03:00
bol-van
5f5cfb434c update docs 2026-01-03 19:48:42 +03:00
bol-van
2f1aa5734e winws2: --wf-filter-loopback 2026-01-03 19:44:29 +03:00
bol-van
062360f3f3 update docs 2026-01-03 19:24:12 +03:00
bol-van
7122808425 init.d: dns intercept scheme 2026-01-03 19:14:35 +03:00
bol-van
515921522e init.d: ressurect lanif 2026-01-03 17:50:11 +03:00
bol-van
c0ce825a95 update lame issue warning 2026-01-03 15:04:39 +03:00
bol-van
c4b23d21ce init.d: sysv functions fix wrong interface order 2026-01-03 14:55:39 +03:00
bol-van
0847d9f140 nfqws2: replace printf with write in sighup 2026-01-03 13:24:18 +03:00
bol-van
b239690e33 AI inspired fixes 2026-01-03 13:15:01 +03:00
bol-van
4f6510daf1 base.sh: detect hard links to busybox 2026-01-03 00:39:29 +03:00
bol-van
0cad2329a1 install_bin: fix and 2026-01-03 00:39:03 +03:00
bol-van
24d9eb1fe2 nfqws2: use query name in dns response extraction 2026-01-03 00:12:43 +03:00
bol-van
f98445d36b update docs 2026-01-02 22:45:02 +03:00
bol-van
7278bb1b87 nfqws2: fix non-working dns ipcache if --debug=0 2026-01-02 20:01:23 +03:00
bol-van
5b58997e3e update docs 2026-01-02 19:53:22 +03:00
bol-van
93a6487eb5 update docs 2026-01-02 19:39:31 +03:00
bol-van
fdca797671 nfqws2: cache dns response IP addresses if --ipcache-hostname enabled 2026-01-02 19:29:33 +03:00
bol-van
bb9e78e8fb nfqws2: optimize udp protocol detect code 2026-01-02 17:44:52 +03:00
bol-van
2a15a1a778 Merge pull request #61 from Pavel4e5/typos
Typos
2026-01-02 17:26:44 +03:00
Pavel4e5
bf89b415bb Merge branch 'bol-van:master' into typos 2026-01-02 18:42:40 +05:00
bol-van
735936efc5 zapret-tests: test_swap 2026-01-01 14:26:23 +03:00
bol-van
9d09d8adcc nfqws2: fix comment 2025-12-31 18:07:30 +03:00
bol-van
3874e16075 nfqws2: print luajit status at startup 2025-12-31 16:10:22 +03:00
bol-van
cbb05967ba update docs 2025-12-31 10:49:19 +03:00
bol-van
665bd5f318 zapret-lib: check NFQWS2_COMPAT_VER 2025-12-31 10:48:42 +03:00
bol-van
fa1d7c30c3 blockcheck2: --payload= 2025-12-31 10:42:54 +03:00
Pavel4e5
940f94162d update docs 2025-12-31 02:47:05 +05:00
Pavel4e5
60108bf378 zapret-antidpi: correct error message 2025-12-31 02:40:33 +05:00
bol-van
5a68245e32 update docs 2025-12-30 15:33:28 +03:00
bol-van
b2dbdd4dd7 update docs 2025-12-30 15:32:55 +03:00
bol-van
5bc65c3b91 update docs 2025-12-30 15:20:49 +03:00
bol-van
6bf7f2c7c0 nfqws2: use luaL_loadbuffer 2025-12-30 15:11:15 +03:00
bol-van
44a80abb3f nfqws2: use luaL_loadbuffer 2025-12-30 15:05:42 +03:00
bol-van
89f0f39b83 update docs 2025-12-30 13:27:07 +03:00
bol-van
ad6f1db149 blockcheck2: http_unixeol test 2025-12-30 13:26:51 +03:00
bol-van
9154fe1677 zapret-lib, zapret-antidpi: http_reconstruct_req, http_unixeol 2025-12-30 13:26:15 +03:00
bol-van
5e63a0f5c5 update docs 2025-12-30 11:24:08 +03:00
bol-van
0521053991 github actions: use pigz -11 instead of gzip 2025-12-30 11:10:10 +03:00
bol-van
7b7ed1ad60 update docs 2025-12-30 10:51:07 +03:00
bol-van
2915647c63 update docs 2025-12-30 10:50:19 +03:00
bol-van
958a4e918b update docs 2025-12-30 10:48:11 +03:00
bol-van
cb332dad74 update docs 2025-12-30 10:44:05 +03:00
bol-van
17e9e0a8e6 update docs 2025-12-29 20:40:50 +03:00
bol-van
78b348a193 nfqws2: bu48 crash fix 2025-12-29 19:25:28 +03:00
bol-van
8103a02689 nfqws2: fix wrong bitset on 32-bit platforms 2025-12-29 19:14:25 +03:00
131 changed files with 17268 additions and 4190 deletions

2
.gitattributes vendored
View File

@@ -1,5 +1,7 @@
* text=auto eol=lf
*.cmd eol=crlf
*.bat eol=crlf
*.manifest eol=crlf
*.rc eol=crlf
init.d/windivert.filter.examples/** eol=crlf
files/** binary

View File

@@ -11,8 +11,14 @@ Issues - это место для обращений к разработчику
Discussions - место для обсуждения вопросов между пользователями.
Все, что выходит за рамки багов и технически грамотных предложений, идей,
вопросы типа "как мне это запустить", "что нажать", "что вписать" - будет безжалостно удаляться.
вопросы типа "как мне это запустить", "что нажать", "что вписать", "перестало открываться" - будет безжалостно удаляться.
Если вы не знаете как пользоваться, для вас что-то сложно, здесь - не место обучению программе или linux и не место для вопросов подобного рода.
Поймите, пожалуйста, что zapret - это инструмент, а не готовое решение для пользователя. В его функциях нет кнопки "открыть сайты", поэтому
если они перестали открываться - это не issue. Функцию "открыть сайты" дают только сборки - ищите их и все вопросы адресуйте туда.
Если вы игнорируете данное требование, вы не достигните своих целей , а только добавите желания удалить ваш 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.

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: armv7-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,17 +57,17 @@ 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
sudo apt update -qq
if [[ "$ARCH" == lexra ]]; then
sudo apt install -y libcap-dev libc6:i386 zlib1g:i386
sudo apt install -y pigz libcap-dev libc6:i386 zlib1g:i386
URL=https://github.com/$REPO/raw/refs/heads/master/$DIR.txz
else
# luajit buildvm requires 32 bit executable on host platform for 32 bit cross targets
sudo apt install -y libcap-dev libc6-dev gcc-multilib
sudo apt install -y pigz libcap-dev libc6-dev gcc-multilib
URL=https://github.com/$REPO/releases/download/latest/$TOOL.tar.xz
fi
mkdir -p $HOME/tools
@@ -93,11 +81,15 @@ jobs:
CFLAGS: ${{ matrix.env.CFLAGS != '' && matrix.env.CFLAGS || null }}
LDFLAGS: ${{ matrix.env.LDFLAGS != '' && matrix.env.LDFLAGS || null }}
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
LUA_VER: 5.4
LUA_RELEASE: 5.4.8
LUA_VER: 5.5
LUA_RELEASE: 5.5.0
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,23 @@ jobs:
export STRIP=$TARGET-strip
export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig
export STAGING_DIR=$RUNNER_TEMP
OPTIMIZE=-Oz
case "$ARCH" in
lexra)
OPTIMIZE=-Os
;;
arm)
CPU="-mcpu=cortex-a7 -mthumb"
;;
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
@@ -131,7 +133,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 -s -flto=auto $CFLAGS" -j$(nproc)
make BUILDMODE=static XCFLAGS="-DLUAJIT_USE_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 +149,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 +162,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 +173,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 +224,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
@@ -242,7 +248,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="-DLUAJIT_USE_SYSMALLOC -DLUAJIT_DISABLE_FFI" HOST_CC="$HOSTCC" CROSS= CC="$CC" TARGET_AR="$AR rcus" TARGET_STRIP=$STRIP TARGET_CFLAGS="$MINSIZE $CFLAGS" TARGET_LDFLAGS="$LDMINSIZE $LDFLAGS" -j$(nproc)
make install PREFIX= DESTDIR=$DEPS_DIR
)
LJIT=1
@@ -258,7 +264,8 @@ jobs:
for i in libmnl libnfnetlink libnetfilter_queue ; do
(
cd $i-*
CFLAGS="-Os -flto=auto -Wno-implicit-function-declaration" \
CFLAGS="$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
)
@@ -313,13 +320,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,8 +400,8 @@ 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 }}
check-sig: ${{ matrix.arch == 'x86_64' && 'false' || 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
make
@@ -424,13 +434,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 +465,8 @@ 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 &&
( [ "$BITS" = 64 ] && rebase -b 0x205c00000 output/WinDivert.dll || true ) &&
peflags --dynamicbase=true --high-entropy-va=true output/WinDivert.dll &&
zip zapret2-win-${{ matrix.arch }}.zip -j output/*
- name: Upload artifacts
@@ -485,17 +499,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 +528,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 +559,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,16 +574,16 @@ 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*} \
init.d/{openrc,pfsense,runit,s6,systemd,windivert.filter.examples} \
nfq2 ip2net mdig docs Makefile
gzip lua/*.lua
pigz -11 lua/*.lua
)
tar --owner=0 --group=0 -czf ${{ env.repo_dir }}-openwrt-embedded.tar.gz ${{ env.repo_dir }}
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

2
binaries/readme.txt Normal file
View File

@@ -0,0 +1,2 @@
Бинари только в релизах. Собираем с исходников или качаем релиз с гитхаба ! Инфа по сборке в docs/compile.
Binaries are only in releases. Build from source or download release from github ! See docs/compile.

View File

@@ -2,9 +2,11 @@
Скопируйте эту директорию под другим именем в blockcheck2.d, отредактируйте list файлы, впишите туда свои стратегии.
В диалоге blockcheck2.sh выберите тест с названием вашей директории.
Можно комментировать строки символом '#' в начале строки.
Параметры со спец символами типа "<" должны быть эскейпнуты по правилам 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.
Strategy list files paths can be overriden in env variables : LIST_HTTP, LIST_HTTPS_TLS12, LIST_HTTPS_TLS13, LIST_QUIC.

View File

@@ -1,4 +1,5 @@
# write nfqws2 parameters here
# WARNING : parameters with special symbols like "<" must be escaped or will cause error
--payload=http_req --lua-desync=http_hostcase
--payload=http_req --lua-desync=http_methodeol
--payload=http_req --lua-desync=fake:blob=fake_default_http:tcp_ts=-1000

View File

@@ -1,3 +1,4 @@
# write nfqws2 parameters here
# WARNING : parameters with special symbols like "<" must be escaped or will cause error
--payload tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_ts=-1000
--payload=tls_client_hello --lua-desync=fake:blob=0x00000000:tcp_md5:repeats=1 --lua-desync=fake:blob=fake_default_tls:tcp_md5:tls_mod=rnd,dupsid:repeats=1 --lua-desync=multisplit:pos=2

View File

@@ -1,4 +1,5 @@
# write nfqws2 parameters here
# WARNING : parameters with special symbols like "<" must be escaped or will cause error
--payload tls_client_hello --lua-desync=fake:blob=fake_default_tls:tcp_ts=-1000
--payload tls_client_hello --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop
--payload tls_client_hello --lua-desync=luaexec:code="desync.pat=tls_mod(fake_default_tls,'rnd,rndsni,dupsid,padencap',desync.reasm_data)" --lua-desync=tcpseg:pos=0,-1:seqovl=#pat:seqovl_pattern=pat --lua-desync=drop

View File

@@ -1,3 +1,4 @@
# write nfqws2 parameters here
# WARNING : parameters with special symbols like "<" must be escaped or will cause error
--payload quic_initial --lua-desync=fake:blob=fake_default_quic:repeats=11
--payload quic_initial --lua-desync=send:ipfrag --lua-desync=drop

View File

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

View File

@@ -5,7 +5,9 @@ pktws_check_http()
# $1 - test function
# $2 - domain
local PAYLOAD="--payload http_req" repeats ok
local PAYLOAD="--payload=http_req" repeats ok
[ "$NOTEST_MISC_HTTP" = 1 ] && { echo "SKIPPED"; return; }
for repeats in 1 20 100 260; do
# send starting bytes of original payload
@@ -20,7 +22,9 @@ pktws_check_https_tls12()
# $1 - test function
# $2 - domain
local PAYLOAD="--payload tls_client_hello" repeats ok
local PAYLOAD="--payload=tls_client_hello" repeats ok
[ "$NOTEST_MISC_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
for repeats in 1 20 100 260; do
# send starting bytes of original payload

View File

@@ -0,0 +1,39 @@
. "$TESTDIR/def.inc"
pktws_oob()
{
# $1 - test function
# $2 - domain
local urp
for urp in b 0 2 midsld; do
pktws_curl_test_update "$1" "$2" --in-range=-s1 --lua-desync=oob:urp=$urp
done
}
pktws_check_http()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_OOB_HTTP" = 1 ] && { echo "SKIPPED"; return; }
pktws_oob "$@"
}
pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_OOB_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_oob "$@"
}
pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
pktws_check_https_tls12 "$1" "$2"
}

View File

@@ -1,18 +1,22 @@
. "$TESTDIR/def.inc"
pktws_simple_split_tests()
{
# $1 - test function
# $2 - domain/uri
# $3 - splits
# $4 - PRE args for nfqws2
local pos ok ok_any pre="$4"
local splitf splitfs="multisplit $MULTIDISORDER"
local pos ok ok_any pre="$4" func
local splitf splitfs="multisplit multidisorder"
ok_any=0
for splitf in $splitfs; do
func=$splitf
[ "$func" = multidisorder ] && func=$MULTIDISORDER
eval need_$splitf=0
ok=0
for pos in $3; do
pktws_curl_test_update $1 $2 $pre $PAYLOAD --lua-desync=$splitf:pos=$pos && ok=1
pktws_curl_test_update $1 $2 $pre $PAYLOAD --lua-desync=$func:pos=$pos && ok=1
done
[ "$ok" = 1 -a "$SCANLEVEL" != force ] || eval need_$splitf=1
[ "$ok" = 1 ] && ok_any=1
@@ -26,7 +30,7 @@ pktws_check_http()
# $1 - test function
# $2 - domain
local splits_http='method+2 midsld method+2,midsld'
local PAYLOAD="--payload http_req"
local PAYLOAD="--payload=http_req"
[ "$NOTEST_MULTI_HTTP" = 1 ] && { echo "SKIPPED"; return; }
@@ -39,9 +43,7 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,midsld,1220 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
local PAYLOAD="--payload tls_client_hello"
[ "$NOTEST_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
local PAYLOAD="--payload=tls_client_hello"
pktws_simple_split_tests "$1" "$2" "$splits_tls" "$3"
}
@@ -50,6 +52,9 @@ pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
# do not use 'need' values obtained with wssize
@@ -62,5 +67,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -1,3 +1,5 @@
. "$TESTDIR/def.inc"
pktws_check_http()
{
# $1 - test function
@@ -5,7 +7,7 @@ pktws_check_http()
[ "$NOTEST_SEQOVL_HTTP" = 1 ] && { echo "SKIPPED"; return; }
local PAYLOAD="--payload http_req"
local PAYLOAD="--payload=http_req"
local ok pat= split f f2
@@ -34,54 +36,47 @@ pktws_seqovl_tests_tls()
# $1 - test function
# $2 - domain/uri
# $3 - PRE args for nfqws2
local ok ok_any
local testf=$1 domain="$2" pre="$3"
local pat rnd_mod padencap_mod split f f2
local PAYLOAD="--payload tls_client_hello"
local PAYLOAD="--payload=tls_client_hello"
pat=${SEQOVL_PATTERN_HTTPS:+seqovl_pat}
pat=${pat:-fake_default_tls}
rnd_mod="--lua-init=$pat=tls_mod($pat,'rnd')"
padencap_mod="--lua-desync=luaexec:code=desync.pat=tls_mod($pat,'rnd,dupsid,padencap',desync.reasm_data)"
padencap_mod="--lua-desync=luaexec:code=desync.patmod=tls_mod($pat,'rnd,dupsid,padencap',desync.reasm_data)"
ok=0
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=1 --lua-desync=drop && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=tcpseg:pos=0,-1:seqovl=#$pat:seqovl_pattern=$pat --lua-desync=drop && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=tcpseg:pos=0,-1:seqovl=#pat:seqovl_pattern=pat --lua-desync=drop && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=tcpseg:pos=0,-1:seqovl=#patmod:seqovl_pattern=patmod --lua-desync=drop && ok=1
ok_any=$ok
ok=0
for split in 10 10,sniext+1 10,sniext+4 10,midsld; do
pktws_curl_test_update $testf $domain $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=1 && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$rnd_mod $pre $PAYLOAD --lua-desync=multisplit:pos=$split:seqovl=#$pat:seqovl_pattern=$pat && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=multisplit:pos=$split:seqovl=#pat:seqovl_pattern=pat && ok=1
pktws_curl_test_update $testf $domain ${SEQOVL_PATTERN_HTTPS:+--blob=$pat:@"$SEQOVL_PATTERN_HTTPS" }$pre $PAYLOAD $padencap_mod --lua-desync=multisplit:pos=$split:seqovl=#patmod:seqovl_pattern=patmod && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
done
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
[ "$ok_any" = 1 ]
}
pktws_check_https_tls()
{
# $1 - test function
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_SEQOVL_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_seqovl_tests_tls "$1" "$2" "$3"
}
pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_SEQOVL_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_seqovl_tests_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
pktws_seqovl_tests_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
}
@@ -90,5 +85,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_SEQOVL_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_seqovl_tests_tls "$1" "$2"
}

View File

@@ -5,11 +5,13 @@ pktws_check_http()
# $1 - test function
# $2 - domain
local PAYLOAD="--payload http_req" split
local PAYLOAD="--payload=http_req" split
[ "$NOTEST_SYNDATA_HTTP" = 1 ] && { echo "SKIPPED"; return; }
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
}
@@ -19,7 +21,7 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
local PAYLOAD="--payload tls_client_hello" ok=0 pre="$3" split
local PAYLOAD="--payload=tls_client_hello" ok=0 pre="$3" split
for split in '' multisplit $MULTIDISORDER; do
pktws_curl_test_update "$1" "$2" $pre --lua-desync=syndata ${split:+$PAYLOAD --lua-desync=$split} && ok=1
@@ -36,6 +38,8 @@ pktws_check_https_tls12()
# $1 - test function
# $2 - domain
[ "$NOTEST_SYNDATA_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
}
@@ -45,5 +49,7 @@ pktws_check_https_tls13()
# $1 - test function
# $2 - domain
[ "$NOTEST_SYNDATA_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -18,8 +18,8 @@ pktws_check_http()
need_fake=0
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
ok_any=0
ok=0
@@ -40,7 +40,7 @@ pktws_check_http()
for ff in $fake 0x00000000; do
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
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
done
done
for ttl in $attls; do
@@ -55,8 +55,8 @@ pktws_check_http()
done
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_fake=1
[ $ok = 1 ] && okany=1
[ $okany = 1 ]
[ $ok = 1 ] && ok_any=1
[ $ok_any = 1 ]
}
pktws_fake_https_vary_()
@@ -76,7 +76,7 @@ pktws_fake_https_vary()
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && \
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:$TCP_MD5" && ok_any=1
[ "$ok_any" = 1 ]
}
@@ -86,8 +86,6 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_FAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
local testf=$1 domain="$2" pre="$3"
local ok ok_any ttls attls f fake fooling
local PAYLOAD="--payload=tls_client_hello"
@@ -102,8 +100,8 @@ pktws_check_https_tls()
need_fake=0
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
ok_any=0
ok=0
@@ -125,14 +123,17 @@ pktws_check_https_tls()
done
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_fake=1
[ $ok = 1 ] && okany=1
[ $okany = 1 ]
[ $ok = 1 ] && ok_any=1
[ $ok_any = 1 ]
}
pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
# do not use 'need' values obtained with wssize
@@ -145,5 +146,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -14,8 +14,8 @@ pktws_check_faked()
local PAYLOAD="--payload=$3"
local FAKED_PATTERN="$5"
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
# do not test fakedsplit if multisplit works
[ "$need_multisplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=fakedsplit
@@ -42,7 +42,7 @@ pktws_check_faked()
for split in $splits; do
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
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
done
done
for ttl in $attls; do
@@ -77,7 +77,6 @@ pktws_check_https_tls()
# $1 - test function
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
local splits='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
pktws_check_faked $1 "$2" tls_client_hello "$splits" "$FAKED_PATTERN_HTTPS" "$3"
@@ -87,6 +86,9 @@ pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
# do not use 'need' values obtained with wssize
@@ -99,5 +101,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -1,6 +1,5 @@
. "$TESTDIR/def.inc"
pktws_hostfake_vary_()
{
local ok_any=0 testf=$1 domain="$2" fooling="$3" pre="$4" post="$5" disorder
@@ -22,7 +21,7 @@ pktws_hostfake_vary()
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && \
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:$TCP_MD5" && ok_any=1
[ "$ok_any" = 1 ]
}
@@ -37,8 +36,8 @@ pktws_check_hostfake()
local ok ttls attls f fooling
local PAYLOAD="--payload=$3"
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
need_hostfakesplit=0
ok=0
@@ -58,7 +57,7 @@ pktws_check_hostfake()
pktws_hostfake_vary $testf $domain "ip${IPVV}_autottl=-$ttl,3-20" "$pre" "$f" && [ "$SCANLEVEL" != force ] && break
done
done
[ $ok = 0 -a "$SCANLEVEL" != force ] && eval need_hostfake=1
[ $ok = 0 -a "$SCANLEVEL" != force ] && need_hostfakesplit=1
[ $ok = 1 ]
}
@@ -77,14 +76,15 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_hostfake $1 "$2" tls_client_hello "$3"
}
pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
# do not use 'need' values obtained with wssize
@@ -97,5 +97,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -16,8 +16,8 @@ pktws_check_http()
fake=fake_default_http
fi
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
# do not test fake + multisplit if multisplit works
[ "$need_multisplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=multisplit
@@ -46,7 +46,7 @@ pktws_check_http()
for ff in $fake 0x00000000; do
pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=$fake:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split && ok=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=fake_http:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split --payload empty "--out-range=<s1" --lua-desync=send:tcp_md5 && ok=1
contains "$fooling" tcp_md5 && pktws_curl_test_update $testf $domain ${FAKE_HTTP:+--blob=fake_http:@"$FAKE_HTTP" }$PAYLOAD --lua-desync=fake:blob=$ff:$fooling:repeats=$FAKE_REPEATS --lua-desync=$splitf:pos=$split --payload=empty "--out-range=<s1" --lua-desync=send:$TCP_MD5 && ok=1
done
done
done
@@ -82,7 +82,7 @@ pktws_fake_https_vary()
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && \
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:$TCP_MD5" && ok_any=1
[ "$ok_any" = 1 ]
}
@@ -92,8 +92,6 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_FAKE_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
local testf=$1 domain="$2" pre="$3"
local ok ok_any ttls attls f fake fooling splitf splitfs= split splits='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,midsld,1220 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
local PAYLOAD="--payload=tls_client_hello"
@@ -106,8 +104,8 @@ pktws_check_https_tls()
fake=fake_default_tls
fi
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
# do not test fake + multisplit if multisplit works
[ "$need_multisplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=multisplit
@@ -148,6 +146,9 @@ pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
}
@@ -156,5 +157,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_MULTI_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -16,8 +16,8 @@ pktws_check_http()
fake=fake_default_http
fi
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
# do not test fake + multisplit if multisplit works
[ "$need_fakedsplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=fakedsplit
@@ -46,7 +46,7 @@ pktws_check_http()
for ff in $fake 0x00000000; do
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 && ok=1
# 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
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
done
done
@@ -69,11 +69,11 @@ 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
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
[ "$ok_any" = 1 ] && ok=1
}
@@ -83,7 +83,7 @@ pktws_fake_https_vary()
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "$5" && ok_any=1
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && \
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5" && ok_any=1
pktws_fake_https_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:$TCP_MD5" && ok_any=1
[ "$ok_any" = 1 ]
}
@@ -93,8 +93,6 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_FAKE_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
local testf=$1 domain="$2" pre="$3"
local ok ok_any ttls attls f fake fooling splitf splitfs= split splits='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
local PAYLOAD="--payload=tls_client_hello"
@@ -107,8 +105,8 @@ pktws_check_https_tls()
fake=fake_default_tls
fi
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
# do not test fake + fakedsplit if fakedsplit works
[ "$need_fakedsplit" = 0 -a "$SCANLEVEL" != force ] || splitfs=fakedsplit
@@ -149,6 +147,9 @@ pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
}
@@ -157,5 +158,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_FAKED_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -20,7 +20,7 @@ pktws_hostfake_vary()
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "$5"
# duplicate SYN with MD5
contains "$fooling" tcp_md5 && \
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:tcp_md5"
pktws_hostfake_vary_ "$1" "$2" "$3" "$4" "${5:+$5 }--payload=empty --out-range=<s1 --lua-desync=send:$TCP_MD5"
}
pktws_check_hostfake()
@@ -33,8 +33,8 @@ pktws_check_hostfake()
[ "$need_hostfakesplit" = 0 ] && return 0
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
[ "$MAX_TTL" = 0 ] || ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
[ "$MAX_AUTOTTL_DELTA" = 0 ] || attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
ok=0
for ttl in $ttls; do
@@ -69,7 +69,7 @@ pktws_check_http()
local FAKE="$FAKE_HTTP"
if [ -n "$FAKE_HTTP" ]; then
fake=bfake
fake=fake_http
else
fake=fake_default_http
fi
@@ -83,13 +83,11 @@ pktws_check_https_tls()
# $2 - domain
# $3 - PRE args for nfqws2
[ "$NOTEST_FAKE_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
local PAYLOAD="--payload=tls_client_hello"
local FAKE="$FAKE_HTTPS"
if [ -n "$FAKE_HTTPS" ]; then
fake=bfake
fake=fake_tls
else
fake=fake_default_tls
fi
@@ -101,6 +99,9 @@ pktws_check_https_tls12()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2" && [ "$SCANLEVEL" != force ] && return
pktws_check_https_tls "$1" "$2" --lua-desync=wssize:wsize=1:scale=6
}
@@ -109,5 +110,8 @@ pktws_check_https_tls13()
{
# $1 - test function
# $2 - domain
[ "$NOTEST_FAKE_HOSTFAKE_HTTPS" = 1 ] && { echo "SKIPPED"; return 0; }
pktws_check_https_tls "$1" "$2"
}

View File

@@ -8,7 +8,7 @@ pktws_check_http3()
[ "$NOTEST_QUIC" = 1 ] && { echo "SKIPPED"; return; }
local repeats fake pos fool
local PAYLOAD="--payload quic_initial"
local PAYLOAD="--payload=quic_initial"
if [ -n "$FAKE_QUIC" ]; then
fake=fake_quic

View File

@@ -15,3 +15,7 @@ MAX_AUTOTTL_DELTA=${MAX_AUTOTTL_DELTA:-5}
# can use MULTIDISORER=multidisorder_legacy
MULTIDISORDER=${MULTIDISORDER:-multidisorder}
TCP_MD5=tcp_md5
# OpenBSD can occupy 24 bytes in tcp options in SYN packet leaving no space for the md5 header
[ "$UNAME" = OpenBSD ] && TCP_MD5=$TCP_MD5:tcp_nop_del

View File

@@ -26,7 +26,6 @@ CURL=${CURL:-curl}
TEST_DEFAULT=${TEST_DEFAULT:-standard}
DOMAINS_DEFAULT=${DOMAINS_DEFAULT:-rutracker.org}
QNUM=${QNUM:-59781}
SOCKS_PORT=${SOCKS_PORT:-1993}
WS_UID=${WS_UID:-1}
WS_GID=${WS_GID:-3003}
@@ -35,8 +34,6 @@ DVTWS2=${DVTWS2:-${ZAPRET_BASE}/nfq2/dvtws2}
WINWS2=${WINWS2:-${ZAPRET_BASE}/nfq2/winws2}
MDIG=${MDIG:-${ZAPRET_BASE}/mdig/mdig}
DESYNC_MARK=0x10000000
IPFW_RULE_NUM=${IPFW_RULE_NUM:-1}
IPFW_DIVERT_PORT=${IPFW_DIVERT_PORT:-59780}
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}
@@ -45,12 +42,20 @@ HTTP_PORT=${HTTP_PORT:-80}
HTTPS_PORT=${HTTPS_PORT:-443}
QUIC_PORT=${QUIC_PORT:-443}
UNBLOCKED_DOM=${UNBLOCKED_DOM:-iana.org}
PARALLEL_OUT=/tmp/zapret_parallel
SIM_SUCCESS_RATE=${SIM_SUCCESS_RATE:-10}
HDRTEMP=/tmp/zapret-hdr
IPFW_RULE_MAX=${IPFW_RULE_MAX:-999}
IPFW_RULE_NUM=${IPFW_RULE_NUM:-$(($$ % $IPFW_RULE_MAX + 1))}
IPFW_DIVERT_PORT=${IPFW_DIVERT_PORT:-$(($$ % 64536 + 1000))}
QNUM=${QNUM:-$(($$ % 64536 + 1000))}
NFT_TABLE=blockcheck
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_$$"
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}
@@ -59,7 +64,6 @@ DNSCHECK_DIG1=/tmp/dig1.txt
DNSCHECK_DIG2=/tmp/dig2.txt
DNSCHECK_DIGS=/tmp/digs.txt
IPSET_FILE=/tmp/blockcheck_ipset.txt
unset PF_STATUS
PF_RULES_SAVE=/tmp/pf-zapret-save.conf
@@ -240,7 +244,7 @@ mdig_vars()
# $1 - ip version 4/6
# $2 - hostname
hostvar=$(echo $2 | sed -e 's/[\./?&#@%*$^:~=!()+-]/_/g')
hostvar=$(echo $2 | sed -e 's/[\./?&#@%*$^:~=!()+-]/_/g' | tr 'A-Z' 'a-z')
cachevar=DNSCACHE_${hostvar}_$1
countvar=${cachevar}_COUNT
eval count=\$${countvar}
@@ -297,7 +301,7 @@ mdig_resolve_all()
mdig_vars "$1" "$sdom"
if [ -n "$count" ]; then
n=0
while [ "$n" -le $count ]; do
while [ "$n" -lt $count ]; do
eval ip__=\$${cachevar}_$n
if [ -n "$ips__" ]; then
ips__="$ips__ $ip__"
@@ -408,8 +412,14 @@ zp_already_running()
CYGWIN)
win_process_exists $PKTWSD || win_process_exists winws || win_process_exists goodbyedpi
;;
*)
FreeBSD|OpenBSD)
process_exists $PKTWSD || process_exists tpws || process_exists dvtws
;;
Linux)
process_exists $PKTWSD || process_exists tpws || process_exists nfqws
;;
*)
return 1
esac
}
check_already()
@@ -633,11 +643,11 @@ curl_with_dig()
# $2 - domain name
# $3 - port
# $4+ - curl params
local dom=$2 port=$3
local dom="$2" port=$3
local sdom suri ip
split_by_separator "$dom" / sdom suri
mdig_resolve $1 ip $sdom
mdig_resolve $1 ip "$sdom"
shift ; shift ; shift
if [ -n "$ip" ]; then
curl_with_subst_ip "$sdom" "$port" "$ip" "$@"
@@ -652,12 +662,12 @@ curl_probe()
# $3 - port
# $4 - subst ip
# $5+ - curl params
local ipv=$1 dom=$2 port=$3 subst=$4
local ipv=$1 dom="$2" port=$3 subst=$4
shift; shift; shift; shift
if [ -n "$subst" ]; then
curl_with_subst_ip $dom $port $subst "$@"
curl_with_subst_ip "$dom" $port $subst "$@"
else
curl_with_dig $ipv $dom $port "$@"
curl_with_dig $ipv "$dom" $port "$@"
fi
}
curl_test_http()
@@ -668,7 +678,7 @@ curl_test_http()
# $4 - "detail" - detail info
local code loc hdrt="${HDRTEMP}_${!:-$$}.txt" dom="$(tolower "$2")"
curl_probe $1 $2 $HTTP_PORT "$3" -SsD "$hdrt" -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT "http://$2" -o /dev/null 2>&1 || {
curl_probe $1 "$2" $HTTP_PORT "$3" -SsD "$hdrt" -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT "http://$2" -o /dev/null 2>&1 || {
code=$?
rm -f "$hdrt"
return $code
@@ -680,6 +690,7 @@ curl_test_http()
code=$(hdrfile_http_code "$hdrt")
[ "$code" = 301 -o "$code" = 302 -o "$code" = 307 -o "$code" = 308 ] && {
loc=$(hdrfile_location "$hdrt")
split_by_separator "$dom" / dom
tolower "$loc" | grep -qE "^https?://.*$dom(/|$)" ||
tolower "$loc" | grep -vqE '^https?://' || {
echo suspicious redirection $code to : $loc
@@ -703,7 +714,7 @@ curl_test_https_tls12()
# $3 - subst ip
# do not use tls 1.3 to make sure server certificate is not encrypted
curl_probe $1 $2 $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.2 $TLSMAX12 "https://$2" -o /dev/null 2>&1
curl_probe $1 "$2" $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.2 $TLSMAX12 "https://$2" -o /dev/null 2>&1
}
curl_test_https_tls13()
{
@@ -712,7 +723,7 @@ curl_test_https_tls13()
# $3 - subst ip
# force TLS1.3 mode
curl_probe $1 $2 $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.3 $TLSMAX13 "https://$2" -o /dev/null 2>&1
curl_probe $1 "$2" $HTTPS_PORT "$3" $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME $CURL_OPT --tlsv1.3 $TLSMAX13 "https://$2" -o /dev/null 2>&1
}
curl_test_http3()
@@ -721,7 +732,7 @@ curl_test_http3()
# $2 - domain name
# force QUIC only mode without tcp
curl_with_dig $1 $2 $QUIC_PORT $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME_QUIC --http3-only $CURL_OPT "https://$2" -o /dev/null 2>&1
curl_with_dig $1 "$2" $QUIC_PORT $HTTPS_HEAD -Ss -A "$USER_AGENT" --max-time $CURL_MAX_TIME_QUIC --http3-only $CURL_OPT "https://$2" -o /dev/null 2>&1
}
ipt_aux_scheme()
@@ -731,24 +742,24 @@ ipt_aux_scheme()
# $3 - port
# to avoid possible INVALID state drop
[ "$2" = tcp ] && IPT_ADD_DEL $1 INPUT -p $2 --sport $3 ! --syn -j ACCEPT
[ "$2" = tcp ] && IPT_ADD_DEL $1 INPUT -p $2 --sport $3 ! --syn $IPT_COMMENT -j ACCEPT
local icmp_filter="-p icmp -m icmp --icmp-type"
[ "$IPV" = 6 ] && icmp_filter="-p icmpv6 -m icmp6 --icmpv6-type"
IPT_ADD_DEL $1 INPUT $icmp_filter time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK -j DROP
IPT_ADD_DEL $1 INPUT $icmp_filter time-exceeded -m connmark --mark $DESYNC_MARK/$DESYNC_MARK $IPT_COMMENT -j DROP
# for strategies with incoming packets involved (autottl)
IPT_ADD_DEL $1 OUTPUT -p $2 --dport $3 -m conntrack --ctstate INVALID -j ACCEPT
IPT_ADD_DEL $1 OUTPUT -p $2 --dport $3 -m conntrack --ctstate INVALID $IPT_COMMENT -j ACCEPT
if [ "$IPV" = 6 -a -n "$IP6_DEFRAG_DISABLE" ]; then
# the only way to reliable disable ipv6 defrag. works only in 4.16+ kernels
IPT_ADD_DEL $1 OUTPUT -t raw -p $2 -m frag -j CT --notrack
IPT_ADD_DEL $1 OUTPUT -t raw -p $2 -m frag $IPT_COMMENT -j CT --notrack
elif [ "$IPV" = 4 ]; then
# enable fragments
IPT_ADD_DEL $1 OUTPUT -f -j ACCEPT
IPT_ADD_DEL $1 OUTPUT -f $IPT_COMMENT -j ACCEPT
fi
# enable everything generated by nfqws (works only in OUTPUT, not in FORWARD)
# raw table may not be present
IPT_ADD_DEL $1 OUTPUT -t raw -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j CT --notrack
IPT_ADD_DEL $1 OUTPUT -t raw -m mark --mark $DESYNC_MARK/$DESYNC_MARK $IPT_COMMENT -j CT --notrack
}
ipt_scheme()
{
@@ -758,18 +769,18 @@ ipt_scheme()
local ip
$IPTABLES -t mangle -N blockcheck_output 2>/dev/null
$IPTABLES -t mangle -F blockcheck_output
IPT OUTPUT -t mangle -j blockcheck_output
$IPTABLES -t mangle -N $IPT_OUT_CHAIN 2>/dev/null
$IPTABLES -t mangle -F $IPT_OUT_CHAIN
IPT OUTPUT -t mangle -j $IPT_OUT_CHAIN
# prevent loop
$IPTABLES -t mangle -A blockcheck_output -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j RETURN
$IPTABLES -t mangle -A blockcheck_output ! -p $1 -j RETURN
$IPTABLES -t mangle -A blockcheck_output -p $1 ! --dport $2 -j RETURN
$IPTABLES -t mangle -A $IPT_OUT_CHAIN -m mark --mark $DESYNC_MARK/$DESYNC_MARK -j RETURN
$IPTABLES -t mangle -A $IPT_OUT_CHAIN ! -p $1 -j RETURN
$IPTABLES -t mangle -A $IPT_OUT_CHAIN -p $1 ! --dport $2 -j RETURN
for ip in $3; do
$IPTABLES -t mangle -A blockcheck_output -d $ip -j CONNMARK --or-mark $DESYNC_MARK
$IPTABLES -t mangle -A blockcheck_output -d $ip -j NFQUEUE --queue-num $QNUM
$IPTABLES -t mangle -A $IPT_OUT_CHAIN -d $ip -j CONNMARK --or-mark $DESYNC_MARK
$IPTABLES -t mangle -A $IPT_OUT_CHAIN -d $ip -j NFQUEUE --queue-num $QNUM
done
ipt_aux_scheme 1 $1 $2
@@ -845,9 +856,9 @@ pktws_ipt_unprepare()
case "$FWTYPE" in
iptables)
ipt_aux_scheme 0 $1 $2
IPT_DEL OUTPUT -t mangle -j blockcheck_output
$IPTABLES -t mangle -F blockcheck_output 2>/dev/null
$IPTABLES -t mangle -X blockcheck_output 2>/dev/null
IPT_DEL OUTPUT -t mangle -j $IPT_OUT_CHAIN
$IPTABLES -t mangle -F $IPT_OUT_CHAIN 2>/dev/null
$IPTABLES -t mangle -X $IPT_OUT_CHAIN 2>/dev/null
;;
nftables)
nft delete table inet $NFT_TABLE 2>/dev/null
@@ -875,17 +886,17 @@ pktws_ipt_prepare_tcp()
pktws_ipt_prepare tcp $1 "$2"
# for autottl mode
# for autottl mode and tcp_mss detection
case "$FWTYPE" in
iptables)
$IPTABLES -N blockcheck_input -t mangle 2>/dev/null
$IPTABLES -F blockcheck_input -t mangle 2>/dev/null
IPT INPUT -t mangle -j blockcheck_input
$IPTABLES -t mangle -A blockcheck_input ! -p tcp -j RETURN
$IPTABLES -t mangle -A blockcheck_input -p tcp ! --sport $1 -j RETURN
$IPTABLES -t mangle -A blockcheck_input -p tcp ! --tcp-flags SYN,ACK SYN,ACK -j RETURN
$IPTABLES -N $IPT_IN_CHAIN -t mangle 2>/dev/null
$IPTABLES -F $IPT_IN_CHAIN -t mangle 2>/dev/null
IPT INPUT -t mangle -j $IPT_IN_CHAIN
$IPTABLES -t mangle -A $IPT_IN_CHAIN ! -p tcp -j RETURN
$IPTABLES -t mangle -A $IPT_IN_CHAIN -p tcp ! --sport $1 -j RETURN
$IPTABLES -t mangle -A $IPT_IN_CHAIN -p tcp ! --tcp-flags SYN,ACK SYN,ACK -j RETURN
for ip in $2; do
$IPTABLES -A blockcheck_input -t mangle -s $ip -j NFQUEUE --queue-num $QNUM
$IPTABLES -A $IPT_IN_CHAIN -t mangle -s $ip -j NFQUEUE --queue-num $QNUM
done
;;
nftables)
@@ -909,9 +920,9 @@ pktws_ipt_unprepare_tcp()
case "$FWTYPE" in
iptables)
IPT_DEL INPUT -t mangle -j blockcheck_input
$IPTABLES -t mangle -F blockcheck_input 2>/dev/null
$IPTABLES -t mangle -X blockcheck_input 2>/dev/null
IPT_DEL INPUT -t mangle -j $IPT_IN_CHAIN
$IPTABLES -t mangle -F $IPT_IN_CHAIN 2>/dev/null
$IPTABLES -t mangle -X $IPT_IN_CHAIN 2>/dev/null
;;
esac
}
@@ -939,7 +950,9 @@ pktws_start()
"$DVTWS2" --port=$IPFW_DIVERT_PORT --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
;;
CYGWIN)
"$WINWS2" $WF --ipset="$IPSET_FILE" --lua-init=@"$ZAPRET_BASE/lua/zapret-lib.lua" --lua-init=@"$ZAPRET_BASE/lua/zapret-antidpi.lua" "$@" >/dev/null &
# 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 &
;;
esac
PID=$!
@@ -990,7 +1003,7 @@ curl_test()
if [ "$PARALLEL" = 1 ]; then
rm -f "${PARALLEL_OUT}"*
for n in $(seq -s ' ' 1 $REPEATS); do
$1 "$IPV" $2 $3 "$4" >"${PARALLEL_OUT}_$n" &
$1 "$IPV" "$2" $3 "$4" >"${PARALLEL_OUT}_$n" &
pids="${pids:+$pids }$!"
done
n=1
@@ -1009,7 +1022,7 @@ curl_test()
while [ $n -lt $REPEATS ]; do
n=$(($n+1))
[ $REPEATS -gt 1 ] && printf "[attempt $n] "
if $1 "$IPV" $2 $3 "$4" ; then
if $1 "$IPV" "$2" $3 "$4" ; then
[ $REPEATS -gt 1 ] && echo 'AVAILABLE'
else
code=$?
@@ -1034,7 +1047,7 @@ ws_curl_test()
# $2 - test function
# $3 - domain
# $4,$5,$6, ... - ws params
local code ws_start=$1 testf=$2 dom=$3
local code ws_start=$1 testf=$2 dom="$3"
[ "$SIMULATE" = 1 ] && {
n=$(random 0 99)
@@ -1050,7 +1063,7 @@ ws_curl_test()
shift
shift
$ws_start "$@"
curl_test $testf $dom
curl_test $testf "$dom"
code=$?
ws_kill
return $code
@@ -1060,11 +1073,11 @@ pktws_curl_test()
# $1 - test function
# $2 - domain
# $3,$4,$5, ... - nfqws/dvtws params
local testf=$1 dom=$2 strategy code
local testf=$1 dom="$2" strategy code
shift; shift;
echo - $testf ipv$IPV $dom : $PKTWSD ${WF:+$WF }${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" }$@${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"}
ws_curl_test pktws_start $testf $dom ${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" }"$@"${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"}
ws_curl_test pktws_start $testf "$dom" ${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" }"$@"${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"}
code=$?
[ "$code" = 0 ] && {
@@ -1086,11 +1099,11 @@ xxxws_curl_test_update()
# $2 - test function
# $3 - domain
# $4,$5,$6, ... - nfqws2/dvtws2 params
local code xxxf=$1 testf=$2 dom=$3
local code xxxf=$1 testf=$2 dom="$3"
shift
shift
shift
$xxxf $testf $dom "$@"
$xxxf $testf "$dom" "$@"
code=$?
[ $code = 0 ] && strategy="${strategy:-$@}"
return $code
@@ -1314,7 +1327,6 @@ check_domain_http_tcp()
local ips
# in case was interrupted before
pktws_ipt_unprepare_tcp $2
ws_kill
check_domain_prolog $1 $2 $4 || return
@@ -1342,7 +1354,6 @@ check_domain_http_udp()
local ips
# in case was interrupted before
pktws_ipt_unprepare_udp $2
ws_kill
check_domain_prolog $1 $2 $3 || return

View File

@@ -95,7 +95,7 @@ end_with_newline()
}
trim()
{
awk '{gsub(/^ +| +$/,"")}1'
awk '{gsub(/^[ \t]+|[ \t]+$/,"")}1'
}
split_by_separator()
{
@@ -119,7 +119,7 @@ dir_is_not_empty()
# $1 - directory
local n
[ -d "$1" ] || return 1
n=$(ls "$1" | wc -c | xargs)
n=$(ls -A "$1" | wc -c | xargs)
[ "$n" != 0 ]
}
@@ -172,15 +172,23 @@ unique()
is_linked_to_busybox()
{
local IFS F P
local IFS F P BB
BB="$(which busybox)"
IFS=:
for path in $PATH; do
F=$path/$1
P="$(readlink $F)"
if [ -z "$P" ] && [ -x $F ] && [ ! -L $F ]; then return 1; fi
[ "${P%busybox*}" != "$P" ] && return
F="$path/$1"
if [ -L "$F" ]; then
P="$(readlink $F)"
if [ -z "$P" ] && [ -x $F ] && [ ! -L $F ]; then return 1; fi
[ "${P%busybox*}" != "$P" ] && return
elif [ -f "$F" -a -n "$BB" ]; then
# possible hardlink
[ $(get_dir_inode "$F") = $(get_dir_inode "$BB") ] && return
fi
done
return 1
}
get_dir_inode()
{
@@ -335,7 +343,7 @@ setup_md5()
{
[ -n "$MD5" ] && return
MD5=md5sum
exists $MD5 || MD5=md5
exists $MD5 || MD5="md5 -q"
}
md5f()
@@ -358,7 +366,7 @@ random()
local r rs
setup_random
if [ -c /dev/urandom ]; then
read rs </dev/urandom
rs=$(dd if=/dev/urandom count=1 bs=16 2>/dev/null | hexdump -e '1 "%02x"')
else
rs="$RANDOM$RANDOM$(date)"
fi
@@ -386,9 +394,9 @@ shell_name()
process_exists()
{
if exists pgrep; then
pgrep ^$1$ >/dev/null
pgrep "^$1$" >/dev/null
elif exists pidof; then
pidof $1 >/dev/null
pidof "$1" >/dev/null
else
return 1
fi
@@ -418,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

View File

@@ -36,9 +36,8 @@ ask_list()
# $3 - (optional) default value
local M_DEFAULT
eval M_DEFAULT="\$$1"
local M_ALL=$M_DEFAULT
local M=""
local m
local M_DEFAULT_VAR="$M_DEFAULT"
local M="" m
[ -n "$3" ] && { find_str_in_list "$M_DEFAULT" "$2" || M_DEFAULT="$3" ;}
@@ -54,5 +53,5 @@ ask_list()
echo selected : $M
eval $1="\"$M\""
[ "$M" != "$M_OLD" ]
[ "$M" != "$M_DEFAULT_VAR" ]
}

View File

@@ -256,7 +256,7 @@ check_system()
get_free_space_mb()
{
df -m $PWD | awk '/[0-9]%/{print $(NF-2)}'
df -m "$1" | awk '/[0-9]%/{print $(NF-2)}'
}
get_ram_kb()
{
@@ -522,11 +522,6 @@ install_openwrt_firewall()
{
echo \* installing firewall script $1
[ -n "MODE" ] || {
echo should specify MODE in $ZAPRET_CONFIG
exitp 7
}
echo "linking : $FW_SCRIPT_SRC => $OPENWRT_FW_INCLUDE"
ln -fs "$FW_SCRIPT_SRC" "$OPENWRT_FW_INCLUDE"
@@ -784,7 +779,9 @@ select_fwtype()
echo WARNING ! if you need large lists it may be necessary to fall back to iptables+ipset firewall
}
echo select firewall type :
ask_list FWTYPE "iptables nftables" "$FWTYPE" && write_config_var FWTYPE
ask_list FWTYPE "iptables nftables" "$FWTYPE"
# always write config var to prevent auto discovery every time
write_config_var FWTYPE
}
dry_run_nfqws_()

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()
{
@@ -41,7 +41,7 @@ ipt6_add_del()
}
ipt6a_add_del()
{
on_off_function ipt6 ipt6a_del "$@"
on_off_function ipt6a ipt6_del "$@"
}
is_ipt_flow_offload_avail()
@@ -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()

View File

@@ -25,7 +25,7 @@ filter_apply_hostlist_target()
{
# $1 - var name of nfqws params
local v parm parm1 parm2 parm3 parm4 parm5 parm6 parm7 parm8 parm9 parm10 param11 param12 param13 parmNA
local v parm parm1 parm2 parm3 parm4 parm5 parm6 parm7 parm8 parm9 parm10 parm11 parm12 parm13 parmNA
eval v="\$$1"
if contains "$v" "$HOSTLIST_MARKER" || contains "$v" "$HOSTLIST_NOAUTO_MARKER"; then
[ "$MODE_FILTER" = hostlist -o "$MODE_FILTER" = autohostlist ] &&

View File

@@ -3,7 +3,6 @@ nft_connbytes="ct original packets"
# required for : nft -f -
create_dev_stdin
std_ports
nft_create_table()
{
@@ -18,6 +17,18 @@ nft_list_table()
nft -t list table inet $ZAPRET_NFT_TABLE
}
nft_add_chain()
{
# $1 - chain
# $2 - params
nft add chain inet $ZAPRET_NFT_TABLE $1 "{ $2 }"
}
nft_del_chain()
{
# $1 - chain
nft delete chain inet $ZAPRET_NFT_TABLE $1
}
nft_create_set()
{
# $1 - set name
@@ -52,7 +63,7 @@ nft_flush_chain()
nft_chain_empty()
{
# $1 - chain name
local count=$(nft list chain inet $ZAPRET_NFT_TABLE prerouting | wc -l)
local count=$(nft list chain inet $ZAPRET_NFT_TABLE $1 | wc -l)
[ "$count" -le 4 ]
}
nft_rule_exists()
@@ -65,8 +76,7 @@ nft_rule_exists()
nft_add_rule ruletest "$2"
rule=$(nft list chain inet $ZAPRET_NFT_TABLE ruletest | sed -n '3s/\t//gp')
nft_flush_chain ruletest
local yes=$(nft list chain inet $ZAPRET_NFT_TABLE $1 | sed -n "s/^[\t]*$rule\$/1/p")
[ -n "$yes" ]
nft list chain inet $ZAPRET_NFT_TABLE $1 | trim | grep -qxF "$rule"
}
nft_del_all_chains_from_table()
@@ -163,10 +173,10 @@ cat << EOF | nft -f -
add chain inet $ZAPRET_NFT_TABLE postnat_hook { type filter hook postrouting priority 101; }
flush chain inet $ZAPRET_NFT_TABLE postnat_hook
add chain inet $ZAPRET_NFT_TABLE prerouting_hook { type filter hook prerouting priority -99; }
flush chain inet $ZAPRET_NFT_TABLE prerouting_hook
add chain inet $ZAPRET_NFT_TABLE prerouting
flush chain inet $ZAPRET_NFT_TABLE prerouting
add chain inet $ZAPRET_NFT_TABLE prerouting_hook { type filter hook prerouting priority -99; }
flush chain inet $ZAPRET_NFT_TABLE prerouting_hook
add chain inet $ZAPRET_NFT_TABLE prenat_hook { type filter hook prerouting priority -101; }
flush chain inet $ZAPRET_NFT_TABLE prenat_hook
@@ -185,6 +195,7 @@ cat << EOF | nft -f -
add set inet $ZAPRET_NFT_TABLE wanif { type ifname; }
add set inet $ZAPRET_NFT_TABLE wanif6 { type ifname; }
add set inet $ZAPRET_NFT_TABLE lanif { type ifname; }
add chain inet $ZAPRET_NFT_TABLE ruletest
flush chain inet $ZAPRET_NFT_TABLE ruletest
@@ -230,8 +241,6 @@ cat << EOF | nft -f - 2>/dev/null
delete chain inet $ZAPRET_NFT_TABLE flow_offload_always
delete chain inet $ZAPRET_NFT_TABLE ruletest
EOF
# unfortunately this approach breaks udp desync of the connection initiating packet (new, first one)
# delete chain inet $ZAPRET_NFT_TABLE predefrag
}
nft_del_flowtable()
{
@@ -257,14 +266,17 @@ nft_create_or_update_flowtable()
nft_flush_ifsets()
{
cat << EOF | nft -f - 2>/dev/null
flush set inet $ZAPRET_NFT_TABLE wanif
flush set inet $ZAPRET_NFT_TABLE wanif6
for set in wanif wanif6 lanif; do
flush set inet $ZAPRET_NFT_TABLE $set
done
EOF
}
nft_list_ifsets()
{
nft list set inet $ZAPRET_NFT_TABLE wanif
nft list set inet $ZAPRET_NFT_TABLE wanif6
for set in wanif wanif6 lanif; do
nft list set inet $ZAPRET_NFT_TABLE $set
done
nft list flowtable inet $ZAPRET_NFT_TABLE ft 2>/dev/null
}
@@ -402,7 +414,9 @@ nft_fill_ifsets()
# calling all in one shot helps not to waste cpu time many times
script="flush set inet $ZAPRET_NFT_TABLE wanif
flush set inet $ZAPRET_NFT_TABLE wanif6"
flush set inet $ZAPRET_NFT_TABLE wanif6
flush set inet $ZAPRET_NFT_TABLE lanif"
nft_script_add_ifset_element lanif "$1"
[ "$DISABLE_IPV4" = "1" ] || nft_script_add_ifset_element wanif "$2"
[ "$DISABLE_IPV6" = "1" ] || nft_script_add_ifset_element wanif6 "$3"

View File

@@ -41,6 +41,10 @@ AUTOHOSTLIST_DEBUGLOG=0
# number of parallel threads for domain list resolves
MDIG_THREADS=30
# EAI_AGAIN retries
MDIG_EAGAIN=10
# delay between EAI_AGAIN retries (ms)
MDIG_EAGAIN_DELAY=500
# ipset/*.sh can compress large lists
GZIP_LISTS=1
@@ -54,7 +58,7 @@ GZIP_LISTS=1
DESYNC_MARK=0x40000000
DESYNC_MARK_POSTNAT=0x20000000
# do not pass outgoing traffic to tpws/nfqws not marked with this bit
# do not pass outgoing traffic to nfqws not marked with this bit
# this setting allows to write your own rules to limit traffic that should be fooled
# for example based on source IP or incoming interface name
# no filter if not defined

View File

@@ -144,3 +144,123 @@ v0.8.0
* zapret-antidpi: tls_client_hello_clone
* zapret-antidpi: "optional" arg to blob taking functions
* nfqws2: support gzipped lua file. auto use script.lua.gz
v0.8.1
* nfqws2: fix bu48 crash and wrong results in bitset
* zapret-lib: http_reconstruct_req
* zapret-antidpi: http_unixeol
* blockcheck2: http_unixeol test
v0.8.2
* nfqws2: do not start if NFQWS2_COMPAT_VER unexpected
* nfqws2: cache dns response IP addresses if --ipcache-hostname enabled
* winws2: remove hardcoded filter for loopback
* init.d: ressurect @lanif in nft scheme
* init.d: fix broken @wanif/@wanif6 fill in sysv nft scheme
* init.d: 80-dns-intercept
* winws2: --wf-filter-loopback
* blockcheck2: NOTEST_MISC_HTTP[S], NOTEST_SYNDATA_HTTP[S]
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
v0.8.4
* winws2: fix loopback large packets processing (up to 64K)
* zapret-lib, zapret-antidpi: use numeric indexes in http dissects
* nfqws2: move ctx from lightuserdata to userdata. prevents crashes on specific ARM cpus
* nfqws2: alternative representation of payload filter in execution_plan item
* nfqws2: --payload-disable
* nfqws2: gracefully shutdown on SIGINT and SIGTERM
* nfqws2: harden wireguard detection. do not detect if reserved bytes 1..3 != 0
v0.8.5
* nfqws2: do not require / in the beginning of URI in http
* zapret-lib: rawsend_dissect_segmented support URG
* zapret-antidpi: oob
* blockcheck2: 17-oob.sh
* nfqws2: set desync.tcp_mss to minimum of both ends or default if at least one is unknown
* zapret-lib: tcp_nop_del
* blockcheck2: tcp_nop_del in SYN packets with md5 in openbsd
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
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
* github actions: lua 5.5
* nfqws2: enable dead reasm protection in wsize=0 case
* nfqws2: --intercept
* winws2: changed icon to multi-res png up to 256px
* nfqws2: support icmp and ipp
* nfqws2: VERDICT_PRESERVE_NEXT
* nfqws2: keepsum reconstruct option
* nfqws2: more helpers
* zapret-obfs: ippxor, udp2icmp, synhide
* nfqws2: LUA_COMPAT_VER=5
* winws2: --wf-raw-filter
* nfqws2: conntrack_feed
* winws2: use windivert bulk mode
* nfqws2: template free import
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

View File

@@ -1,16 +1,39 @@
debian,ubuntu :
* debian,ubuntu :
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libmnl-dev libsystemd-dev libluajit2-5.1-dev
make -C /opt/zapret2 systemd
FreeBSD :
* 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
# see what's the version available
pkg install luajit-2.1.0.20250728
make -C /opt/zapret2
OpenBSD :
* OpenBSD :
pkg_add luajit gmake bsd
gmake -C /opt/zapret2
pkg_add luajit gmake
gmake -C /opt/zapret2 bsd

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.

View File

@@ -0,0 +1,107 @@
#!/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 -Lo - https://www.netfilter.org/pub/libnfnetlink/libnfnetlink-1.0.2.tar.bz2 | tar -xj || exit 5
exists_dir libmnl-* ||
curl -Lo - https://www.netfilter.org/pub/libmnl/libmnl-1.0.5.tar.bz2 | tar -xj || exit 5
exists_dir libnetfilter_queue-* ||
curl -Lo - https://www.netfilter.org/pub/libnetfilter_queue/libnetfilter_queue-1.0.5.tar.bz2 | tar -xj || exit 5
exists_dir zlib-* ||
curl -Lo - https://zlib.net/fossils/zlib-1.3.1.tar.gz | tar -xz || exit 5
exists_dir luajit2-* ||
curl -Lo - https://github.com/openresty/luajit2/archive/refs/tags/v${LUAJIT_RELEASE}.tar.gz | tar -xz || exit 5
exists_dir lua-* ||
curl -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()
{
(
cd zlib-*
[ -f "Makefile" ] && make clean
CFLAGS="$OPTIMIZE $MINSIZE $CFLAGS" \
LDFLAGS="$LDMINSIZE $LDFLAGS" \
./configure --prefix= --static
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"
(
cd luajit2-*
CFLAGS="-Os"
make clean
make BUILDMODE=static XCFLAGS="-DLUAJIT_USE_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_netlink
build_zlib
build_lua
build_luajit_for_target $t
popd
buildenv_clear
done

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

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

View File

@@ -0,0 +1,307 @@
EXEDIR="$(dirname "$0")"
EXEDIR="$(cd "$EXEDIR"; pwd)"
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}
LUA_VER=${LUA_VER:-5.5}
LUA_RELEASE=${LUA_RELEASE:-5.5.0}
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 \
armv7-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| \
armv7-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
armv7-*)
CPU="-mcpu=cortex-a7 -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
;;
armv7-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
}

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 -Lo - "${BASEURL}/${t}.tar.xz" | tar -Jx
done
)

View File

@@ -26,7 +26,7 @@ define Package/nfqws2
CATEGORY:=Network
TITLE:=nfqws2
SUBMENU:=Zapret
DEPENDS:=+libnetfilter-queue +lmnl +libcap +zlib +$(LUA_DEP)
DEPENDS:=+libnetfilter-queue +libmnl +libcap +zlib +$(LUA_DEP)
endef
define Build/Prepare

5524
docs/manual.en.md Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,7 @@
## English
[Manual](manual.en.md)
## Зачем это нужно
Автономное средство противодействия DPI, которое не требует подключения каких-либо сторонних серверов. Может помочь
@@ -11,11 +15,15 @@ VPN. Может использоваться для частичной проз
[Полный мануал](manual.md)
## Поддержать разработчика
## Поддержать разработчика. Donations
Если вы считаете проект полезным и желаете поддержать разработку, направляйте ваши пожертвования на следующие адреса криптокошельков :
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E` (предпочительно сеть ERC-20)
If you find this project useful and wish to donate here are crypto wallets :
USDT ERC `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
USDT TRC `TEzAAtn4VhndqEaAyuCM78xh5W2gCjwWEo`
BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
@@ -40,7 +48,7 @@ zapret2 является дальнейшим развитием проекта
Lua код получает от C кода структурированное представление приходящих пакетов в виде дерева (диссекты), подобного тем, что вы видите в wireshark.
Туда же приходят результаты сборки или дешифровки частей некоторых протоколов (tls, quic).
С код предоставляет функции-хелперы, позволяющие отсылать пакеты, работать с двоичными данными, разбирать TLS, искать маркер-позции и т.д.
С код предоставляет функции-хелперы, позволяющие отсылать пакеты, работать с двоичными данными, разбирать TLS, искать маркер-позиции и т.д.
Имеется библиотека хелперов, написанных на Lua, а так же готовая библиотека программ атаки на DPI (стратегий), реализующая функции *nfqws1* в расширенном варианте
и с большей гибкостью.
@@ -53,8 +61,7 @@ zapret2 - инструмент для таких энтузиастов. Но э
## С чего начать
Хотелось бы избежать [талмуда](manual.md) на главной странице. Поэтому начнем со способа запуска *nfqws2* и описания способов портирования стратегий *nfqws1* - как в *nfqws2* сделать то же самое, что можно было в *nfqws1*.
Когда вы поймете как это работает, вы можете посмотреть Lua код, находящийся "под капотом". Разобрать как он работает, попробовать написать что-то свое.
"талмуд" обязательно будет, как он есть у любых более-менее сложных проектов. Он нужен как справочник.
Когда вы поймете как это работает, вы можете посмотреть Lua код, находящийся "под капотом". Разобрать как он работает, попробовать написать что-то свое, руководствуясь [талмудом](manual.md) как справочником.
### Механика обработки трафика
@@ -407,10 +414,87 @@ nfqws2 \
### Какие есть еще параметры
Как узнать какие есть еще функции и какие у них бывают параметры ? Смотрите `zapret-antidpi.lua`. Перед каждой функцией подробно описано какие параметры она берет.
Описание стандартных блоков параметров есть в начале. Позже - по мере сил и возможностей - будет писаться талмуд - справочник с руководством по программированию
*nfqws2* и описание стандартных библиотек.
Описание стандартных блоков параметров есть в начале.
Или сразу читайте [талмуд](manual.md) . Там все документировано.
### Очень важный совет
Научитесь пользоваться `--debug` логом. Без него будет очень сложно понять *nfqws2* на начальном этапе и приспособиться к новой схеме.
Ошибок будет много. Особенно, когда вы начнете писать свой Lua код. Их надо читать.
### Не только лишь автономный обман DPI
Рабочий тестовый пример icmp обфускатора udp от винды к серверу на vps.
Для теста используем wireguard. Ничего в конфигах менять не надо - wireguard будет думать, что он работает по udp, но на самом деле он преобразуется в пинги icmp, которые могут проходить NAT. Размер пакетов не изменяется, потому проблемы MTU нет.
Будем загонять исходящие с клиента в icmp type 8 (echo request) code 199 , исходящие с сервера в icmp type 0 (echo reply) code 199.
Код у обоих концов делаем одинаковый, иначе NAT не соотнесет. Без NAT можно коды делать разными для клиента и сервера.
Особый icmp code нужен для фильтрации от обычных пингов.
По стандарту код должен быть 0, но на практике с большой вероятностью работают любые коды.
Разные имплементации NAT теоретически могут фильтровать ненулевой код, соотносить или не соотносить код вместе с identifier. Linux NAT соотносит.
При любых проблемах убираем wireguard, ставим netcat с обоих концов и пробуем общаться, посматривая в wireshark.
Всегда можно откатиться на нулевой код, но тогда у сервера без фильтра по IP клиента будет плохая защита от обычных пингов - все они будут преобразовываться в udp и направляться в wireguard,
который будет их игнорировать, поскольку передается мусор. Сервер перестанет пингаться.
Другой способ избежать проблемы и уйти от стандартных пингов - использовать другие типы icmp. Работающие пары, пробрасываемые Linux NAT :
- `ctype=8:stype=0` - echo request - echo reply (используется по умолчанию)
- `ctype=13:stype=14` - timestamp - timestamp reply
- `ctype=15:stype=16` - information request - information reply
- `ctype=17:stype=18` - address mask request - address mask reply
На провайдерских NAT или на аппаратном ускорении роутера может быть другой расклад по работающим парам.
Нужно пробовать и смотреть что выходит в сеть после NAT и что приходит на сервер.
Например, Linux NAT вообще не пробрасывает type 42 - extended echo request. Но аппаратная железка может пробросить и провайдер тоже.
Кто знает, может быть DPI настроен сечь icmp тоннели на стандартных пингах, а на других типах icmp нет ?
wireguard server - `1.2.3.4:5555`
```
table ip ztest {
chain post {
type filter hook output priority mangle; policy accept;
meta mark & 0x40000000 == 0x00000000 udp sport 5555 queue flags bypass to 200
}
chain pre {
type filter hook input priority mangle; policy accept;
meta mark & 0x40000000 == 0x00000000 icmp type echo-request icmp code 199 queue flags bypass to 200
}
}
```
```
nfqws2 --qnum 200 --server
--lua-init=@/opt/zapret2/lua/zapret-lib.lua
--lua-init=@/opt/zapret2/lua/zapret-obfs.lua
--in-range=a
--lua-desync=udp2icmp:ccode=199:scode=199
```
Клиент на винде :
```
winws2
--wf-icmp-in=0:199 --wf-udp-out=5555
--wf-raw-filter="ip.SrcAddr=1.2.3.4 or ip.DstAddr=1.2.3.4"
--lua-init=@lua/zapret-lib.lua
--lua-init=@lua/zapret-obfs.lua
--in-range=a
--lua-desync=udp2icmp:ccode=199:scode=199
```
Все лишнее отсекается в ядре в windivert - проц зазря не грузит.
--wf-raw-filter сочетается со всем остальным собранным конструктором по AND. Отсекает по IP адресу сервера.
--wf-icmp-in отсекает входящие icmp типа 0 с кодом 199.
И включаем wireguard.
В шарке сплошняком пинги и реплаи с кодом 199
Если IP клиента постоянен, можно дополнительно на стороне сервера сделать фильтр по IP клиента.
Дополнительно можно сделать dataxor=blob на обоих концах, чтобы поксорить пейлоад.
blob растягивается на размер пакета как pattern. Можно использовать от 1 hex byte до специально нагенеренного рандома. На обоих концах должен быть одинаковый

Binary file not shown.

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

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}

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_DISCORD_MEDIA="${NFQWS_OPT_DESYNC_DISCORD_MEDIA:---payload discord_ip_discovery --lua-desync=fake:blob=0x00000000000000000000000000000000:repeats=2}"
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}"
alloc_dnum DNUM_DISCORD_MEDIA

View File

@@ -1,30 +1,30 @@
# this custom script demonstrates how to launch extra nfqws instance limited by ipset
# can override in config :
NFQWS_MY1_OPT="${NFQWS_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}"
NFQWS_MY1_SUBNETS4="${NFQWS_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}"
NFQWS_MY1_SUBNETS6="${NFQWS_MY1_SUBNETS6:-2a00:1450::/29}"
NFQWS_MY1_PORTS_TCP=${NFQWS_MY1_PORTS_TCP:-$NFQWS_PORTS_TCP}
NFQWS_MY1_PORTS_UDP=${NFQWS_MY1_PORTS_UDP:-$NFQWS_PORTS_UDP}
NFQWS_MY1_TCP_PKT_OUT=${NFQWS_MY1_TCP_PKT_OUT:-$NFQWS_TCP_PKT_OUT}
NFQWS_MY1_UDP_PKT_OUT=${NFQWS_MY1_UDP_PKT_OUT:-$NFQWS_UDP_PKT_OUT}
NFQWS_MY1_TCP_PKT_IN=${NFQWS_MY1_TCP_PKT_IN:-$NFQWS_TCP_PKT_IN}
NFQWS_MY1_UDP_PKT_IN=${NFQWS_MY1_UDP_PKT_IN:-$NFQWS_UDP_PKT_IN}
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}
NFQWS2_MY1_PORTS_UDP=${NFQWS2_MY1_PORTS_UDP:-$NFQWS2_PORTS_UDP}
NFQWS2_MY1_TCP_PKT_OUT=${NFQWS2_MY1_TCP_PKT_OUT:-$NFQWS2_TCP_PKT_OUT}
NFQWS2_MY1_UDP_PKT_OUT=${NFQWS2_MY1_UDP_PKT_OUT:-$NFQWS2_UDP_PKT_OUT}
NFQWS2_MY1_TCP_PKT_IN=${NFQWS2_MY1_TCP_PKT_IN:-$NFQWS2_TCP_PKT_IN}
NFQWS2_MY1_UDP_PKT_IN=${NFQWS2_MY1_UDP_PKT_IN:-$NFQWS2_UDP_PKT_IN}
NFQWS_MY1_IPSET_SIZE=${NFQWS_MY1_IPSET_SIZE:-4096}
NFQWS_MY1_IPSET_OPT="${NFQWS_MY1_IPSET_OPT:-hash:net hashsize 8192 maxelem $NFQWS_MY1_IPSET_SIZE}"
NFQWS2_MY1_IPSET_SIZE=${NFQWS2_MY1_IPSET_SIZE:-4096}
NFQWS2_MY1_IPSET_OPT="${NFQWS2_MY1_IPSET_OPT:-hash:net hashsize 8192 maxelem $NFQWS2_MY1_IPSET_SIZE}"
alloc_dnum DNUM_NFQWS_MY1
alloc_qnum QNUM_NFQWS_MY1
NFQWS_MY1_NAME4=my1nfqws4
NFQWS_MY1_NAME6=my1nfqws6
alloc_dnum DNUM_NFQWS2_MY1
alloc_qnum QNUM_NFQWS2_MY1
NFQWS2_MY1_NAME4=my1nfqws4
NFQWS2_MY1_NAME6=my1nfqws6
zapret_custom_daemons()
{
# $1 - 1 - run, 0 - stop
local opt="--qnum=$QNUM_NFQWS_MY1 $NFQWS_MY1_OPT"
do_nfqws $1 $DNUM_NFQWS_MY1 "$opt"
local opt="--qnum=$QNUM_NFQWS2_MY1 $NFQWS2_MY1_OPT"
do_nfqws $1 $DNUM_NFQWS2_MY1 "$opt"
}
zapret_custom_firewall()
@@ -32,103 +32,103 @@ zapret_custom_firewall()
# $1 - 1 - run, 0 - stop
local f4 f6 subnet
local NFQWS_MY1_PORTS_TCP=$(replace_char - : $NFQWS_MY1_PORTS_TCP)
local NFQWS_MY1_PORTS_UDP=$(replace_char - : $NFQWS_MY1_PORTS_UDP)
local NFQWS2_MY1_PORTS_TCP=$(replace_char - : $NFQWS2_MY1_PORTS_TCP)
local NFQWS2_MY1_PORTS_UDP=$(replace_char - : $NFQWS2_MY1_PORTS_UDP)
[ "$1" = 1 -a "$DISABLE_IPV4" != 1 ] && {
ipset create $NFQWS_MY1_NAME4 $NFQWS_MY1_IPSET_OPT family inet 2>/dev/null
ipset flush $NFQWS_MY1_NAME4
for subnet in $NFQWS_MY1_SUBNETS4; do
echo add $NFQWS_MY1_NAME4 $subnet
ipset create $NFQWS2_MY1_NAME4 $NFQWS2_MY1_IPSET_OPT family inet 2>/dev/null
ipset flush $NFQWS2_MY1_NAME4
for subnet in $NFQWS2_MY1_SUBNETS4; do
echo add $NFQWS2_MY1_NAME4 $subnet
done | ipset -! restore
}
[ "$1" = 1 -a "$DISABLE_IPV6" != 1 ] && {
ipset create $NFQWS_MY1_NAME6 $NFQWS_MY1_IPSET_OPT family inet6 2>/dev/null
ipset flush $NFQWS_MY1_NAME6
for subnet in $NFQWS_MY1_SUBNETS6; do
echo add $NFQWS_MY1_NAME6 $subnet
ipset create $NFQWS2_MY1_NAME6 $NFQWS2_MY1_IPSET_OPT family inet6 2>/dev/null
ipset flush $NFQWS2_MY1_NAME6
for subnet in $NFQWS2_MY1_SUBNETS6; do
echo add $NFQWS2_MY1_NAME6 $subnet
done | ipset -! restore
}
[ -n "$NFQWS_MY1_PORTS_TCP" ] && {
[ -n "$NFQWS_MY1_TCP_PKT_OUT" -a "$NFQWS_MY1_TCP_PKT_OUT" != 0 ] && {
f4="-p tcp -m multiport --dports $NFQWS_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS_MY1_TCP_PKT_OUT -m set --match-set"
f6="$f4 $NFQWS_MY1_NAME6 dst"
f4="$f4 $NFQWS_MY1_NAME4 dst"
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
[ -n "$NFQWS2_MY1_PORTS_TCP" ] && {
[ -n "$NFQWS2_MY1_TCP_PKT_OUT" -a "$NFQWS2_MY1_TCP_PKT_OUT" != 0 ] && {
f4="-p tcp -m multiport --dports $NFQWS2_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS2_MY1_TCP_PKT_OUT -m set --match-set"
f6="$f4 $NFQWS2_MY1_NAME6 dst"
f4="$f4 $NFQWS2_MY1_NAME4 dst"
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
}
[ -n "$NFQWS_MY1_TCP_PKT_IN" -a "$NFQWS_MY1_TCP_PKT_IN" != 0 ] && {
f4="-p tcp -m multiport --sports $NFQWS_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS_MY1_TCP_PKT_IN -m set --match-set"
f6="$f4 $NFQWS_MY1_NAME6 src"
f4="$f4 $NFQWS_MY1_NAME4 src"
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
[ -n "$NFQWS2_MY1_TCP_PKT_IN" -a "$NFQWS2_MY1_TCP_PKT_IN" != 0 ] && {
f4="-p tcp -m multiport --sports $NFQWS2_MY1_PORTS_TCP $ipt_connbytes 1:$NFQWS2_MY1_TCP_PKT_IN -m set --match-set"
f6="$f4 $NFQWS2_MY1_NAME6 src"
f4="$f4 $NFQWS2_MY1_NAME4 src"
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
}
}
[ -n "$NFQWS_MY1_PORTS_UDP" ] && {
[ -n "$NFQWS_MY1_UDP_PKT_OUT" -a "$NFQWS_MY1_UDP_PKT_OUT" != 0 ] && {
f4="-p udp -m multiport --dports $NFQWS_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS_MY1_UDP_PKT_OUT -m set --match-set"
f6="$f4 $NFQWS_MY1_NAME6 dst"
f4="$f4 $NFQWS_MY1_NAME4 dst"
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
[ -n "$NFQWS2_MY1_PORTS_UDP" ] && {
[ -n "$NFQWS2_MY1_UDP_PKT_OUT" -a "$NFQWS2_MY1_UDP_PKT_OUT" != 0 ] && {
f4="-p udp -m multiport --dports $NFQWS2_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS2_MY1_UDP_PKT_OUT -m set --match-set"
f6="$f4 $NFQWS2_MY1_NAME6 dst"
f4="$f4 $NFQWS2_MY1_NAME4 dst"
fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
}
[ -n "$NFQWS_MY1_UDP_PKT_IN" -a "$NFQWS_MY1_UDP_PKT_IN" != 0 ] && {
f4="-p udp -m multiport --sports $NFQWS_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS_MY1_UDP_PKT_IN -m set --match-set"
f6="$f4 $NFQWS_MY1_NAME6 src"
f4="$f4 $NFQWS_MY1_NAME4 src"
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
[ -n "$NFQWS2_MY1_UDP_PKT_IN" -a "$NFQWS2_MY1_UDP_PKT_IN" != 0 ] && {
f4="-p udp -m multiport --sports $NFQWS2_MY1_PORTS_UDP $ipt_connbytes 1:$NFQWS2_MY1_UDP_PKT_IN -m set --match-set"
f6="$f4 $NFQWS2_MY1_NAME6 src"
f4="$f4 $NFQWS2_MY1_NAME4 src"
fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
}
}
[ "$1" = 1 ] || {
ipset destroy $NFQWS_MY1_NAME4 2>/dev/null
ipset destroy $NFQWS_MY1_NAME6 2>/dev/null
ipset destroy $NFQWS2_MY1_NAME4 2>/dev/null
ipset destroy $NFQWS2_MY1_NAME6 2>/dev/null
}
}
zapret_custom_firewall_nft()
{
local f4 f6 subnets
local first_packets_only="$nft_connbytes 1-$NFQWS_MY1_PKT_OUT"
local first_packets_only="$nft_connbytes 1-$NFQWS2_MY1_PKT_OUT"
[ "$DISABLE_IPV4" != 1 ] && {
make_comma_list subnets $NFQWS_MY1_SUBNETS4
nft_create_set $NFQWS_MY1_NAME4 "type ipv4_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;"
nft_flush_set $NFQWS_MY1_NAME4
nft_add_set_element $NFQWS_MY1_NAME4 "$subnets"
make_comma_list subnets $NFQWS2_MY1_SUBNETS4
nft_create_set $NFQWS2_MY1_NAME4 "type ipv4_addr; size $NFQWS2_MY1_IPSET_SIZE; auto-merge; flags interval;"
nft_flush_set $NFQWS2_MY1_NAME4
nft_add_set_element $NFQWS2_MY1_NAME4 "$subnets"
}
[ "$DISABLE_IPV6" != 1 ] && {
make_comma_list subnets $NFQWS_MY1_SUBNETS6
nft_create_set $NFQWS_MY1_NAME6 "type ipv6_addr; size $NFQWS_MY1_IPSET_SIZE; auto-merge; flags interval;"
nft_flush_set $NFQWS_MY1_NAME6
nft_add_set_element $NFQWS_MY1_NAME6 "$subnets"
make_comma_list subnets $NFQWS2_MY1_SUBNETS6
nft_create_set $NFQWS2_MY1_NAME6 "type ipv6_addr; size $NFQWS2_MY1_IPSET_SIZE; auto-merge; flags interval;"
nft_flush_set $NFQWS2_MY1_NAME6
nft_add_set_element $NFQWS2_MY1_NAME6 "$subnets"
}
[ -n "$NFQWS_MY1_PORTS_TCP" ] && {
[ -n "$NFQWS_MY1_TCP_PKT_OUT" -a "$NFQWS_MY1_TCP_PKT_OUT" != 0 ] && {
f4="tcp dport {$NFQWS_MY1_PORTS_TCP} $(nft_first_packets $NFQWS_MY1_TCP_PKT_OUT)"
f6="$f4 ip6 daddr @$NFQWS_MY1_NAME6"
f4="$f4 ip daddr @$NFQWS_MY1_NAME4"
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
[ -n "$NFQWS2_MY1_PORTS_TCP" ] && {
[ -n "$NFQWS2_MY1_TCP_PKT_OUT" -a "$NFQWS2_MY1_TCP_PKT_OUT" != 0 ] && {
f4="tcp dport {$NFQWS2_MY1_PORTS_TCP} $(nft_first_packets $NFQWS2_MY1_TCP_PKT_OUT)"
f6="$f4 ip6 daddr @$NFQWS2_MY1_NAME6"
f4="$f4 ip daddr @$NFQWS2_MY1_NAME4"
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
}
[ -n "$NFQWS_MY1_TCP_PKT_IN" -a "$NFQWS_MY1_TCP_PKT_IN" != 0 ] && {
f4="tcp sport {$NFQWS_MY1_PORTS_TCP} $(nft_first_packets $NFQWS_MY1_TCP_PKT_IN)"
f6="$f4 ip6 saddr @$NFQWS_MY1_NAME6"
f4="$f4 ip saddr @$NFQWS_MY1_NAME4"
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
[ -n "$NFQWS2_MY1_TCP_PKT_IN" -a "$NFQWS2_MY1_TCP_PKT_IN" != 0 ] && {
f4="tcp sport {$NFQWS2_MY1_PORTS_TCP} $(nft_first_packets $NFQWS2_MY1_TCP_PKT_IN)"
f6="$f4 ip6 saddr @$NFQWS2_MY1_NAME6"
f4="$f4 ip saddr @$NFQWS2_MY1_NAME4"
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
}
}
[ -n "$NFQWS_MY1_PORTS_UDP" ] && {
[ -n "$NFQWS_MY1_UDP_PKT_OUT" -a "$NFQWS_MY1_UDP_PKT_OUT" != 0 ] && {
f4="udp dport {$NFQWS_MY1_PORTS_UDP} $(nft_first_packets $NFQWS_MY1_UDP_PKT_OUT)"
f6="$f4 ip6 daddr @$NFQWS_MY1_NAME6"
f4="$f4 ip daddr @$NFQWS_MY1_NAME4"
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS_MY1
[ -n "$NFQWS2_MY1_PORTS_UDP" ] && {
[ -n "$NFQWS2_MY1_UDP_PKT_OUT" -a "$NFQWS2_MY1_UDP_PKT_OUT" != 0 ] && {
f4="udp dport {$NFQWS2_MY1_PORTS_UDP} $(nft_first_packets $NFQWS2_MY1_UDP_PKT_OUT)"
f6="$f4 ip6 daddr @$NFQWS2_MY1_NAME6"
f4="$f4 ip daddr @$NFQWS2_MY1_NAME4"
nft_fw_nfqws_post $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
}
[ -n "$NFQWS_MY1_UDP_PKT_IN" -a "$NFQWS_MY1_UDP_PKT_IN" != 0 ] && {
f4="udp sport {$NFQWS_MY1_PORTS_UDP} $(nft_first_packets $NFQWS_MY1_UDP_PKT_IN)"
f6="$f4 ip6 saddr @$NFQWS_MY1_NAME6"
f4="$f4 ip saddr @$NFQWS_MY1_NAME4"
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS_MY1
[ -n "$NFQWS2_MY1_UDP_PKT_IN" -a "$NFQWS2_MY1_UDP_PKT_IN" != 0 ] && {
f4="udp sport {$NFQWS2_MY1_PORTS_UDP} $(nft_first_packets $NFQWS2_MY1_UDP_PKT_IN)"
f6="$f4 ip6 saddr @$NFQWS2_MY1_NAME6"
f4="$f4 ip saddr @$NFQWS2_MY1_NAME4"
nft_fw_nfqws_pre $1 "$f4" "$f6" $QNUM_NFQWS2_MY1
}
}
}
@@ -139,6 +139,6 @@ zapret_custom_firewall_nft_flush()
# this function is called after all nft fw rules are deleted
# however sets are not deleted. it's desired to clear sets here.
nft_del_set $NFQWS_MY1_NAME4 2>/dev/null
nft_del_set $NFQWS_MY1_NAME6 2>/dev/null
nft_del_set $NFQWS2_MY1_NAME4 2>/dev/null
nft_del_set $NFQWS2_MY1_NAME6 2>/dev/null
}

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

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

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

View File

@@ -0,0 +1,62 @@
# this custom script feeds dns response data to main nfqws2 instance
# DISABLE_IPV{4,6} filters are not used intentionally. despite of not having wan ipv6 it's possible to query LAN DNS server over local ipv6
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local filt="-p udp --sport 53"
local jump="-j NFQUEUE --queue-num $QNUM --queue-bypass"
local rule chain lan lanifs
get_lanif lanifs
# router
for lan in $lanifs; do
rule="-o $lan $filt $jump"
ipt_print_op $1 "$rule" "nfqws FORWARD (qnum $QNUM)"
ipt_add_del $1 FORWARD -t mangle $rule
ipt_print_op $1 "$rule" "nfqws FORWARD (qnum $QNUM)" 6
ipt6_add_del $1 FORWARD -t mangle $rule
done
# dns client server
for chain in INPUT OUTPUT ; do
rule="$filt $jump"
ipt_print_op $1 "$rule" "nfqws $chain (qnum $QNUM)"
ipt_add_del $1 $chain -t mangle $rule
ipt_print_op $1 "$rule" "nfqws $chain (qnum $QNUM)" 6
ipt6_add_del $1 $chain -t mangle $rule
done
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local rule="udp sport 53 queue num $QNUM bypass"
# router
nft_print_op "oifname @lanif $rule" "nfqws forward (qnum $QNUM)" "4+6"
nft_add_chain forward_dns_feed "type filter hook forward priority mangle;"
nft_flush_chain forward_dns_feed
nft_add_rule forward_dns_feed oifname @lanif $rule
# dns client
nft_print_op "$rule" "nfqws input (qnum $QNUM)" "4+6"
nft_add_chain input_dns_feed "type filter hook input priority mangle;"
nft_flush_chain input_dns_feed
nft_add_rule input_dns_feed $rule
# dns server
nft_print_op "$rule" "nfqws output (qnum $QNUM)" "4+6"
nft_add_chain output_dns_feed "type filter hook output priority mangle;"
nft_flush_chain output_dns_feed
nft_add_rule output_dns_feed $rule
}
zapret_custom_firewall_nft_flush()
{
local chain
for chain in forward_dns_feed input_dns_feed output_dns_feed; do
nft_del_chain $chain 2>/dev/null
done
}

View File

@@ -0,0 +1,145 @@
# this custom script sets FILTER_MARK to specified source ips
# NOTE !!! SCRIPT REQUIRES FILTER_MARK VAR IN CONFIG FILE !!!
# NOTE !!! WITHOUT FILTER_MARK IT DOES NOTHING !!!
# NOTE !!! ON NON-OPENWRT SYSTEMS SCRIPT REQUIRES IFACE_LAN VAR IN CONFIG FILE !!!
# can override in config :
# LAN ip/cidr list to be fooled. elements are space separated
FILTER_LAN_IP="${FILTER_LAN_IP:-192.168.0.0/16}"
FILTER_LAN_IP6="${FILTER_LAN_IP6:-fc00::/7}"
# allow fooling from local system (0|1) ?
FILTER_LAN_ALLOW_OUTPUT="${FILTER_LAN_ALLOW_OUTPUT:-1}"
FILTER_LAN_SET="lanfilter"
FILTER_LAN_SET6="${FILTER_LAN_SET}6"
FILTER_LAN_IPSET_SIZE=${FILTER_LAN_IPSET_SIZE:-256}
FILTER_LAN_IPSET_OPT="${FILTER_LAN_IPSET_OPT:-hash:net hashsize 8192 maxelem $FILTER_LAN_IPSET_SIZE}"
filter_mark_check()
{
[ -n "$FILTER_MARK" ] || {
echo "WARNING ! lan filter cannot work without FILTER_MARK set in config"
return 1
}
[ "$DISABLE_IPV4" = 1 -a "$DISABLE_IPV6" = 1 ] && return 1
return 0
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
filter_mark_check || return
local subnet lanifs rule
local setmark="-j MARK --set-mark $FILTER_MARK/$FILTER_MARK"
local filt4="-m set --match-set $FILTER_LAN_SET src"
local filt6="-m set --match-set $FILTER_LAN_SET6 src"
get_lanif lanifs
[ "$DISABLE_IPV4" != 1 ] && {
[ "$FILTER_LAN_ALLOW_OUTPUT" = 1 ] && {
ipt_print_op $1 "$setmark" "filter output"
ipt_add_del $1 OUTPUT -t mangle $setmark
}
[ -n "$lanifs" ] && {
[ "$1" = 1 ] && {
ipset create $FILTER_LAN_SET $FILTER_LAN_IPSET_OPT family inet 2>/dev/null
ipset flush $FILTER_LAN_SET
for subnet in $FILTER_LAN_IP; do
echo add $FILTER_LAN_SET $subnet
done | ipset -! restore
}
for lan in $lanifs; do
rule="-i $lan $filt4 $setmark"
ipt_print_op $1 "$rule" "filter forward"
ipt_add_del $1 FORWARD -t mangle $rule
done
}
}
[ "$DISABLE_IPV6" != 1 ] && {
[ "$FILTER_LAN_ALLOW_OUTPUT" = 1 ] && {
ipt_print_op $1 "$setmark" "filter output" 6
ipt6_add_del $1 OUTPUT -t mangle $setmark
}
[ -n "$lanifs" ] && {
[ "$1" = 1 ] && {
ipset create $FILTER_LAN_SET6 $FILTER_LAN_IPSET_OPT family inet6 2>/dev/null
ipset flush $FILTER_LAN_SET6
for subnet in $FILTER_LAN_IP6; do
echo add $FILTER_LAN_SET6 $subnet
done | ipset -! restore
}
for lan in $lanifs; do
rule="-i $lan $filt6 $setmark"
ipt_print_op $1 "$rule" "filter forward" 6
ipt6_add_del $1 FORWARD -t mangle $rule
done
}
}
[ "$1" = 1 ] || {
ipset destroy $FILTER_LAN_SET 2>/dev/null
ipset destroy $FILTER_LAN_SET6 2>/dev/null
}
}
zapret_custom_firewall_nft()
{
filter_mark_check || return
local subnets rule
local setmark="meta mark set meta mark or $FILTER_MARK"
local filt4="ip saddr == @$FILTER_LAN_SET"
local filt6="ip6 saddr == @$FILTER_LAN_SET6"
local lanif="iifname @lanif"
nft_add_chain forward_lan_filter "type filter hook forward priority mangle;"
nft_flush_chain forward_lan_filter
if [ "$FILTER_LAN_ALLOW_OUTPUT" = 1 ]; then
nft_add_chain output_lan_filter "type filter hook output priority mangle;"
nft_flush_chain output_lan_filter
nft_print_op "$setmark" "filter output" "4+6"
nft_add_rule output_lan_filter $setmark
else
nft_del_chain output_lan_filter 2>/dev/null
fi
[ "$DISABLE_IPV4" != 1 ] && {
make_comma_list subnets $FILTER_LAN_IP
nft_create_set $FILTER_LAN_SET "type ipv4_addr; size $FILTER_LAN_IPSET_SIZE; auto-merge; flags interval;"
nft_flush_set $FILTER_LAN_SET
nft_add_set_element $FILTER_LAN_SET "$subnets"
rule="$lanif $filt4 $setmark"
nft_print_op "$rule" "filter forward" "4"
nft_add_rule forward_lan_filter $rule
}
[ "$DISABLE_IPV6" != 1 ] && {
make_comma_list subnets $FILTER_LAN_IP6
nft_create_set $FILTER_LAN_SET6 "type ipv6_addr; size $FILTER_LAN_IPSET_SIZE; auto-merge; flags interval;"
nft_flush_set $FILTER_LAN_SET6
nft_add_set_element $FILTER_LAN_SET6 "$subnets"
rule="$lanif $filt6 $setmark"
nft_print_op "$rule" "filter forward" "6"
nft_add_rule forward_lan_filter $rule
}
}
zapret_custom_firewall_nft_flush()
{
# this function is called after all nft fw rules are deleted
# however sets are not deleted. it's desired to clear sets here.
nft_del_chain forward_lan_filter 2>/dev/null
nft_del_chain output_lan_filter 2>/dev/null
nft_del_set $FILTER_LAN_SET 2>/dev/null
nft_del_set $FILTER_LAN_SET6 2>/dev/null
}

View File

@@ -62,6 +62,20 @@ network_find_wanX_devices()
call_for_multiple_items network_get_device $2 "$ifaces"
}
get_wanif46()
{
# $1 - 4/6
# $2 - var to receive interface list
local ifaces
network_find_wan${1}_all ifaces
call_for_multiple_items network_get_device $2 "$ifaces"
}
get_lanif()
{
# $1 - var to receive interface list
call_for_multiple_items network_get_device $1 "$OPENWRT_LAN"
}
fw_nfqws_prepost_x()
{
@@ -71,10 +85,8 @@ fw_nfqws_prepost_x()
# $4 - 4/6
# $5 - post/pre
local ifaces DWAN
network_find_wan${4}_all ifaces
call_for_multiple_items network_get_device DWAN "$ifaces"
local DWAN
get_wanif46 $4 DWAN
[ -n "$DWAN" ] && _fw_nfqws_${5}${4} $1 "$2" $3 "$(unique $DWAN)"
}
fw_nfqws_post4()

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

View File

@@ -75,6 +75,26 @@ NFQWS2="${NFQWS2:-$ZAPRET_BASE/nfq2/nfqws2}"
LUAOPT="--lua-init=@$ZAPRET_BASE/lua/zapret-lib.lua --lua-init=@$ZAPRET_BASE/lua/zapret-antidpi.lua --lua-init=@$ZAPRET_BASE/lua/zapret-auto.lua"
NFQWS2_OPT_BASE="$USEROPT --fwmark=$DESYNC_MARK $LUAOPT"
get_wanif46()
{
# $1 - 4/6
# $2 - var to receive interface list
case $1 in
6)
eval $2="\${IFACE_WAN6:-$IFACE_WAN}"
;;
4)
eval $2="\$IFACE_WAN"
;;
*)
eval $2=
esac
}
get_lanif()
{
# $1 - var to receive interface list
eval $1="\$IFACE_LAN"
}
fw_nfqws_post4()
{
@@ -119,7 +139,7 @@ nft_wanif6_filter_present()
}
nft_fill_ifsets_overload()
{
nft_fill_ifsets "$IFACE_WAN" "${IFACE_WAN6:-$IFACE_WAN}" "$IFACE_LAN"
nft_fill_ifsets "$IFACE_LAN" "$IFACE_WAN" "${IFACE_WAN6:-$IFACE_WAN}"
}

View File

@@ -1,3 +1,3 @@
udp.PayloadLength=148 and udp.Payload[0]=0x01 or
udp.PayloadLength=92 and udp.Payload[0]=0x02 or
udp.PayloadLength=64 and udp.Payload[0]=0x03
udp.PayloadLength=148 and udp.Payload32[0]=0x01000000 or
udp.PayloadLength=92 and udp.Payload32[0]=0x02000000 or
udp.PayloadLength=64 and udp.Payload32[0]=0x03000000

View File

@@ -31,7 +31,7 @@ select_test_method()
elif exists zsh && [ "$UNAME" != CYGWIN ] ; then
TEST=zsh
elif [ "$UNAME" != CYGWIN ]; then
if exists hexdump and exists dd; then
if exists hexdump && exists dd; then
# macos does not use ELF
TEST=elf
ELF=
@@ -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)

View File

@@ -288,7 +288,7 @@ ask_config_tmpdir()
echo /tmp in openwrt is tmpfs. on low RAM systems there may be not enough RAM to store downloaded files
echo default tmpfs has size of 50% RAM
echo "RAM : $(get_ram_mb) Mb"
echo "DISK : $(get_free_space_mb) Mb"
echo "DISK : $(get_free_space_mb "$EXEDIR/tmp") Mb"
echo select temp file location
[ -z "$TMPDIR" ] && TMPDIR=/tmp
ask_list TMPDIR "/tmp $EXEDIR/tmp" && {
@@ -601,7 +601,7 @@ check_dns()
install_systemd()
{
INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret"
INIT_SCRIPT_SRC="$EXEDIR/init.d/sysv/zapret2"
CUSTOM_DIR="$ZAPRET_RW/init.d/sysv"
check_bins

View File

@@ -1,8 +1,12 @@
CC ?= cc
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
CFLAGS_PIC = -fPIC
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto $(CFLAGS_PIC)
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_WIN = -static
LDFLAGS_PIE = -pie
LDFLAGS += $(LDFLAGS_PIE)
LIBS =
LIBS_WIN = -lws2_32
SRC_FILES = ip2net.c qsort.c

View File

@@ -49,7 +49,7 @@ static int ucmp(const void * a, const void * b, void *arg)
}
static uint32_t mask_from_bitcount(uint32_t zct)
{
return zct<32 ? ~((1 << zct) - 1) : 0;
return zct<32 ? ~((1u << zct) - 1) : 0;
}
// make presorted array unique. return number of unique items.
// 1,1,2,3,3,0,0,0 (ct=8) => 1,2,3,0 (ct=4)
@@ -138,7 +138,7 @@ static void mask_from_bitcount6_make(uint32_t zct, struct in6_addr *a)
int32_t n = (127 - zct) >> 3;
memset(a->s6_addr,0xFF,n);
memset(a->s6_addr+n,0x00,16-n);
a->s6_addr[n] = ~((1 << (zct & 7)) - 1);
a->s6_addr[n] = ~((1u << (zct & 7)) - 1);
}
}
static struct in6_addr ip6_mask[129];

View File

@@ -68,7 +68,6 @@ ipset_restore()
{
# $1 - ipset name
# $2 - filename
zzexist "$2" || return
local fsize=$(zzsize "$2")
local svram=0
@@ -77,7 +76,7 @@ ipset_restore()
local T="Adding to ipset $1 "
[ "$svram" = "1" ] && T="$T (saveram)"
T="$T : $f"
T="$T : $2"
echo $T
if [ "$svram" = "1" ]; then

View File

@@ -44,7 +44,9 @@ ZUSERLIST_EXCLUDE="$IPSET_RW_DIR/zapret-hosts-user-exclude.txt"
[ -n "$IP2NET" ] || IP2NET="$ZAPRET_BASE/ip2net/ip2net"
[ -n "$MDIG" ] || MDIG="$ZAPRET_BASE/mdig/mdig"
[ -z "$MDIG_THREADS" ] && MDIG_THREADS=30
MDIG_THREADS=${MDIG_THREADS:-30}
MDIG_EAGAIN=${MDIG_EAGAIN:-10}
MDIG_EAGAIN_DELAY=${MDIG_EAGAIN_DELAY:-500}
@@ -124,7 +126,7 @@ zzcat()
zz()
{
if [ "$GZIP_LISTS" = "1" ]; then
gzip -c >"$1.gz"
gzip -9c >"$1.gz"
rm -f "$1"
else
cat >"$1"
@@ -161,7 +163,7 @@ digger()
if [ -x "$MDIG" ]; then
local cmd
[ "$2" = "s" ] && cmd=--stats=1000
"$MDIG" --family=$1 --threads=$MDIG_THREADS $cmd
"$MDIG" --family=$1 --threads=$MDIG_THREADS --eagain=$MDIG_EAGAIN --eagain-delay=$MDIG_EAGAIN_DELAY $cmd
else
local A=A
[ "$1" = "6" ] && A=AAAA
@@ -272,11 +274,10 @@ hup_zapret_daemons()
{
echo forcing zapret daemons to reload their hostlist
if exists killall; then
killall -HUP tpws nfqws dvtws 2>/dev/null
killall -HUP nfqws2 dvtws2 2>/dev/null
elif exists pkill; then
pkill -HUP ^tpws$
pkill -HUP ^nfqws$
pkill -HUP ^dvtws$
pkill -HUP ^nfqws2$
pkill -HUP ^dvtws2$
else
echo no mass killer available ! cant HUP zapret daemons
fi

View File

@@ -38,6 +38,7 @@ standard fooling :
* 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 present (workaround for badack without badseq fooling)
* tcp_nop_del - delete NOP tcp options to free space in tcp header
* fool=fool_function - custom fooling function : fool_func(dis, fooling_options)
@@ -53,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 :
@@ -64,8 +65,10 @@ standard ipfrag :
* ipfrag[=frag_function] - ipfrag function name. "ipfrag2" by default if empty
* ipfrag_disorder - send fragments from last to first
* ipfrag2 : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipb6: starting from fragmentable part. must be multiple of 8. default 8
* ipfrag2 : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipb6: starting from fragmentable part. must be multiple of 8. default 32
* ipfrag2 : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32
* ipfrag2 : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8
* ipfrag2 : ipfrag_pos_icmp - icmp frag position. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 8
* ipfrag2 : ipfrag_pos - frag position for other L4. ipv4 : starting from L4 header. ipv6: starting from fragmentable part. must be multiple of 8. default 32
* ipfrag2 : ipfrag_next - next protocol field in ipv6 fragment extenstion header of the second fragment. same as first by default.
]]
@@ -113,7 +116,8 @@ end
-- standard args : direction
function http_domcase(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -121,7 +125,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
@@ -139,7 +143,8 @@ end
-- arg : spell=<str> . spelling of the "Host" header. must be exactly 4 chars long
function http_hostcase(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -149,12 +154,17 @@ function http_hostcase(ctx, desync)
error("http_hostcase: invalid host spelling '"..spell.."'")
else
local hdis = http_dissect_req(desync.dis.payload)
if hdis.headers.host then
DLOG("http_hostcase: 'Host:' => '"..spell.."'")
desync.dis.payload = string.sub(desync.dis.payload,1,hdis.headers.host.pos_start-1)..spell..string.sub(desync.dis.payload,hdis.headers.host.pos_header_end+1)
return VERDICT_MODIFY
if hdis then
local idx_host = array_field_search(hdis.headers, "header_low", "host")
if idx_host then
DLOG("http_hostcase: 'Host:' => '"..spell.."'")
desync.dis.payload = string.sub(desync.dis.payload,1,hdis.headers[idx_host].pos_start-1)..spell..string.sub(desync.dis.payload,hdis.headers[idx_host].pos_header_end+1)
return VERDICT_MODIFY
else
DLOG("http_hostcase: 'Host:' header not found")
end
else
DLOG("http_hostcase: 'Host:' header not found")
DLOG("http_hostcase: http dissect error")
end
end
end
@@ -162,25 +172,68 @@ end
-- nfqws1 : "--methodeol"
-- standard args : direction
-- NOTE : if using with other http tampering methodeol should be the last !
function http_methodeol(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
if desync.l7payload=="http_req" and direction_check(desync) then
local hdis = http_dissect_req(desync.dis.payload)
local ua = hdis.headers["user-agent"]
if ua then
if (ua.pos_end - ua.pos_value_start) < 2 then
DLOG("http_methodeol: 'User-Agent:' header is too short")
if hdis then
local idx_ua = array_field_search(hdis.headers, "header_low", "user-agent")
if idx_ua then
local ua = hdis.headers[idx_ua]
if (ua.pos_end - ua.pos_value_start) < 2 then
DLOG("http_methodeol: 'User-Agent:' header is too short")
else
DLOG("http_methodeol: applied")
desync.dis.payload="\r\n"..string.sub(desync.dis.payload,1,ua.pos_end-2)..(string.sub(desync.dis.payload,ua.pos_end+1) or "");
return VERDICT_MODIFY
end
else
DLOG("http_methodeol: applied")
desync.dis.payload="\r\n"..string.sub(desync.dis.payload,1,ua.pos_end-2)..(string.sub(desync.dis.payload,ua.pos_end+1) or "");
return VERDICT_MODIFY
DLOG("http_methodeol: 'User-Agent:' header not found")
end
else
DLOG("http_methodeol: 'User-Agent:' header not found")
DLOG("http_methodeol: http dissect error")
end
end
end
-- nfqws1 : not available
-- tpws : --unixeol
-- standard args : direction
function http_unixeol(ctx, desync)
if not desync.dis.tcp then
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
if desync.l7payload=="http_req" and direction_check(desync) then
local hdis = http_dissect_req(desync.dis.payload)
if hdis then
local idx_ua = array_field_search(hdis.headers, "header_low", "user-agent")
if idx_ua then
local http = http_reconstruct_req(hdis, true)
if #http < #desync.dis.payload then
hdis.headers[idx_ua].value = hdis.headers[idx_ua].value .. string.rep(" ", #desync.dis.payload - #http)
end
http = http_reconstruct_req(hdis, true)
if #http==#desync.dis.payload then
desync.dis.payload = http
DLOG("http_unixeol: applied")
return VERDICT_MODIFY
else
DLOG("http_unixeol: reconstruct differs in size from original: "..#http.."!="..#desync.dis.payload)
end
else
DLOG("http_unixeol: 'User-Agent:' header absent")
end
else
DLOG("http_unixeol: could not dissect http")
end
end
end
@@ -224,7 +277,8 @@ function synack_split(ctx, desync)
instance_cutoff_shim(ctx, desync) -- mission complete
end
else
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
end
end
@@ -241,7 +295,8 @@ function synack(ctx, desync)
instance_cutoff_shim(ctx, desync) -- mission complete
end
else
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
end
end
@@ -259,7 +314,8 @@ function wsize(ctx, desync)
instance_cutoff_shim(ctx, desync) -- mission complete
end
else
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
end
end
@@ -270,7 +326,8 @@ end
-- arg : forced_cutoff=<list> - comma separated list of payloads that trigger forced wssize cutoff. by default - any non-empty payload
function wssize(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
local verdict = VERDICT_PASS
@@ -299,13 +356,14 @@ end
-- arg: sni_last - add name to the end
function tls_client_hello_clone(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
if direction_check(desync) then
if not desync.arg.blob then
error("fake: 'blob' arg required")
error("tls_client_hello_clone: 'blob' arg required")
end
if desync.l7payload=="tls_client_hello" then
desync[desync.arg.blob] = tls_client_hello_mod(desync.reasm_data or desync.dis.payload, desync.arg)
@@ -341,7 +399,8 @@ function syndata(ctx, desync)
instance_cutoff_shim(ctx, desync) -- mission complete
end
else
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
end
end
@@ -350,7 +409,8 @@ end
-- arg : rstack - send RST,ACK instead of RST
function rst(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -377,8 +437,8 @@ end
-- arg : tls_mod=<list> - comma separated list of tls mods : rnd,rndsni,sni=<str>,dupsid,padencap . sni=%var is supported
function fake(ctx, desync)
direction_cutoff_opposite(ctx, desync)
-- by default process only outgoing known payloads
if direction_check(desync) and payload_check(desync) then
-- by default process only outgoing known payloads. works only for tcp and udp
if (desync.dis.tcp or desync.dis.udp) and direction_check(desync) and payload_check(desync) then
if replay_first(desync) then
if not desync.arg.blob then
error("fake: 'blob' arg required")
@@ -410,7 +470,8 @@ end
-- arg : nodrop - do not drop current dissect
function multisplit(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -465,11 +526,10 @@ function multisplit(ctx, desync)
end
end
-- internal function for code deduplication. do not call directly
function pos_normalize(pos, low, hi)
return (pos>=low and pos<hi) and (pos-low+1) or nil
end
-- internal function for code deduplication. do not call directly
function pos_array_normalize(pos, low, hi)
-- remove positions outside of hi,low range. normalize others to low
local i=1
@@ -524,7 +584,8 @@ end
-- arg : nodrop - do not drop current dissect
function multidisorder(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -575,7 +636,8 @@ end
-- arg : optional - use zero pattern if seqovl_pattern blob is absent
function multidisorder_legacy(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -632,7 +694,8 @@ end
-- arg : nodrop - do not drop current dissect
function hostfakesplit(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -666,14 +729,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
@@ -749,7 +813,8 @@ end
-- arg : nodrop - do not drop current dissect
function fakedsplit(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -829,7 +894,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")
@@ -853,7 +918,8 @@ end
-- arg : nodrop - do not drop current dissect
function fakeddisorder(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -873,11 +939,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)
@@ -943,7 +1009,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")
@@ -964,7 +1030,8 @@ end
-- arg : optional - skip if blob is absent. use zero pattern if seqovl_pattern blob is absent
function tcpseg(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -1009,6 +1076,106 @@ function tcpseg(ctx, desync)
end
end
-- nfqws1 : not available
-- tpws : close analog is "--split-pos=.. --oob" but works not the same way
-- standard args : fooling, ip_id, rawsend, reconstruct, ipfrag
-- arg : char - oob char
-- arg : byte - oob byte
-- arg : urp - urgent pointer position marker, 'b' or 'e'. default - 0
function oob(ctx, desync)
if not desync.track then return end
if not desync.dis.tcp then
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
local key = desync.func_instance.."_syn"
if not desync.track.lua_state[key] then
if bitand(desync.dis.tcp.th_flags, TH_SYN+TH_ACK)~=TH_SYN then
DLOG("oob: must be applied since the very beginning of the tcp connection - SYN packet")
instance_cutoff_shim(ctx, desync)
return
end
desync.track.lua_state[key] = true
end
if desync.outgoing then
-- direct pos - outgoing
local pos = pos_get(desync, 's', false)
if pos<=1 then
local dseq = u32add(desync.dis.tcp.th_seq, -1)
DLOG("oob: decreasing outgoing seq : "..desync.dis.tcp.th_seq.." => "..dseq)
desync.dis.tcp.th_seq = dseq
end
if pos==0 then
return VERDICT_MODIFY
elseif pos==1 then
local data = desync.reasm_data or desync.dis.payload
if #data==0 then
-- empty ACK
return VERDICT_MODIFY
else
local oob = desync.arg.char or (desync.arg.byte and bu8(desync.arg.byte) or nil) or "\x00"
if #oob~=1 then
error("oob: OOB must be exactly one byte")
end
local dis_oob = deepcopy(desync.dis)
local urp
if not desync.arg.urp or desync.arg.urp=='b' then
urp = 1
dis_oob.tcp.th_urp = 0
elseif desync.arg.urp=='e' then
urp = #data+1
dis_oob.tcp.th_urp = urp
else
urp = resolve_pos(data, desync.l7payload, desync.arg.urp)
if not urp then
DLOG("oob: cannot resolve urp marker '"..desync.arg.urp.."'")
instance_cutoff_shim(ctx, desync)
return
end
DLOG("oob: resolved urp marker to "..urp-1)
dis_oob.tcp.th_urp = urp
end
DLOG("oob: th_urp "..dis_oob.tcp.th_urp)
-- one byte OOB payload
dis_oob.payload = string.sub(data, 1, urp-1) .. oob .. string.sub(data, urp)
dis_oob.tcp.th_flags = bitor(dis_oob.tcp.th_flags, TH_URG)
DLOG("oob: sending OOB")
if not rawsend_dissect_segmented(desync, dis_oob) then
instance_cutoff_shim(ctx, desync)
return
end
if not desync.replay then
instance_cutoff_shim(ctx, desync)
end
end
return VERDICT_DROP
else
-- drop replay and cutoff
if desync.replay then
DLOG("oob: dropping replay piece")
if desync.replay_piece_last then
instance_cutoff_shim(ctx, desync)
end
return VERDICT_DROP
end
instance_cutoff_shim(ctx, desync)
end
else
-- reverse pos - outgoing
local pos = pos_get(desync, 's', true)
if pos>1 then
DLOG("oob: unexpected outgoing position "..pos)
instance_cutoff_shim(ctx, desync)
return
end
local dack = u32add(desync.dis.tcp.th_ack, 1)
DLOG("oob: increasing incoming ack : "..desync.dis.tcp.th_ack.." => "..dack)
desync.dis.tcp.th_ack = dack
return VERDICT_MODIFY
end
end
-- nfqws1 : "--dpi-desync=udplen"
-- standard args : direction, payload
-- arg : min=N . do not act on payloads smaller than N bytes
@@ -1018,7 +1185,8 @@ end
-- arg : pattern_offset=N . offset in the pattern. 0 by default
function udplen(ctx, desync)
if not desync.dis.udp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)
@@ -1042,8 +1210,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
@@ -1054,7 +1222,8 @@ end
-- arg : dn=N - message starts from "dN". 3 by default
function dht_dn(ctx, desync)
if not desync.dis.udp then
instance_cutoff_shim(ctx, desync)
-- do not cutoff on related icmp
if not desync.dis.icmp then instance_cutoff_shim(ctx, desync) end
return
end
direction_cutoff_opposite(ctx, desync)

View File

@@ -58,6 +58,7 @@ function automate_host_record(desync)
end
-- per-connection storage
function automate_conn_record(desync)
if not desync.track then return nil end
if not desync.track.lua_state.automate then
desync.track.lua_state.automate = {}
end
@@ -106,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
@@ -180,13 +181,16 @@ function standard_failure_detector(desync, crec)
end
elseif not arg.no_http_redirect and desync.l7payload=="http_reply" and desync.track.hostname then
local hdis = http_dissect_reply(desync.dis.payload)
if hdis and (hdis.code==302 or hdis.code==307) and hdis.headers.location and hdis.headers.location then
trigger = is_dpi_redirect(desync.track.hostname, hdis.headers.location.value)
if b_debug then
if trigger then
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'. looks like DPI redirect.")
else
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers.location.value.."'. NOT a DPI redirect.")
if hdis and (hdis.code==302 or hdis.code==307) then
local idx_loc = array_field_search(hdis.headers, "header_low", "location")
if idx_loc then
trigger = is_dpi_redirect(desync.track.hostname, hdis.headers[idx_loc].value)
if b_debug then
if trigger then
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers[idx_loc].value.."'. looks like DPI redirect.")
else
DLOG("standard_failure_detector: http redirect "..hdis.code.." to '"..hdis.headers[idx_loc].value.."'. NOT a DPI redirect.")
end
end
end
end
@@ -309,7 +313,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)
@@ -399,8 +403,36 @@ function cond_payload_str(desync)
if not desync.arg.pattern then
error("cond_payload_str: missing 'pattern'")
end
return string.find(desync.dis.payload,desync.arg.pattern,1,true)
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 "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)
return
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
@@ -414,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 may have "cond" and "cond_neg" args.
-- "cond" - condition function. "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)
@@ -454,13 +525,17 @@ end
function repeater(ctx, desync)
local repeats = tonumber(desync.arg.repeats)
if not repeats then
error("repeat: missing 'repeats'")
error("repeater: missing 'repeats'")
end
local iff = desync.arg.iff or "cond_true"
if type(_G[iff])~="function" then
error(name..": invalid 'iff' function '"..iff.."'")
error("repeater: invalid 'iff' function '"..iff.."'")
end
orchestrate(ctx, desync)
if #desync.plan==0 then
DLOG("repeater: execution plan is empty - nothing to repeat")
return
end
local neg = desync.arg.neg
local stop = desync.arg.stop
local clear = desync.arg.clear

View File

@@ -1,3 +1,9 @@
NFQWS2_COMPAT_VER_REQUIRED=5
if NFQWS2_COMPAT_VER~=NFQWS2_COMPAT_VER_REQUIRED then
error("Incompatible NFQWS2_COMPAT_VER. Use pktws and lua scripts from the same release !")
end
HEXDUMP_DLOG_MAX = HEXDUMP_DLOG_MAX or 32
NOT3=bitnot(3)
NOT7=bitnot(7)
@@ -12,14 +18,22 @@ function luaexec(ctx, desync)
if not desync.arg.code then
error("luaexec: no 'code' parameter")
end
local fname = desync.func_instance.."_luaexec_code"
local fname = desync.func_instance.."_code"
if not _G[fname] then
_G[fname] = load(desync.arg.code, fname)
local err
_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, err = pcall(_G[fname])
_G.desync = nil
if not res then
error(err);
end
end
-- basic desync function
@@ -82,12 +96,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
@@ -139,7 +153,7 @@ function apply_arg_prefix(desync)
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
@@ -163,9 +177,12 @@ function apply_execution_plan(desync, instance)
end
-- produce resulting verdict from 2 verdicts
function verdict_aggregate(v1, v2)
local v
v1 = v1 or VERDICT_PASS
v2 = v2 or VERDICT_PASS
local vn = bitor(bitand(v1,VERDICT_PRESERVE_NEXT),bitand(v2,VERDICT_PRESERVE_NEXT))
local v
v1 = bitand(v1, VERDICT_MASK)
v2 = bitand(v2, VERDICT_MASK)
if v1==VERDICT_DROP or v2==VERDICT_DROP then
v=VERDICT_DROP
elseif v1==VERDICT_MODIFY or v2==VERDICT_MODIFY then
@@ -173,10 +190,9 @@ function verdict_aggregate(v1, v2)
else
v=VERDICT_PASS
end
return v
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
@@ -189,11 +205,20 @@ function plan_instance_execute(desync, verdict, instance)
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)
@@ -216,12 +241,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
@@ -236,9 +266,9 @@ end
-- if seq is over 2G s and p position comparision can be wrong
function pos_counter_overflow(desync, mode, reverse)
if not desync.track or not desync.track.tcp or (mode~='s' and mode~='p') then return false end
if not desync.track or (mode~='s' and mode~='p') then return false end
local track_pos = reverse and desync.track.pos.reverse or desync.track.pos.direct
return track_pos.tcp.rseq_over_2G
return track_pos.tcp and track_pos.tcp.rseq_over_2G
end
-- these functions duplicate range check logic from C code
-- mode must be n,d,b,s,x,a
@@ -304,17 +334,29 @@ function pos_str(desync, pos)
return pos.mode..pos_get(desync, pos.mode)
end
-- convert array a to packed string using 'packer' function
-- convert array a to packed string using 'packer' function. only numeric indexes starting from 1, order preserved
function barray(a, packer)
if a then
local s=""
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 sa={}
local i=1
for k,v in pairs(a) do
sa[i] = packer(v)
i=i+1
end
return table.concat(sa)
end
end
-- sequence comparision functions. they work only within 2G interval
-- seq1>=seq2
function seq_ge(seq1, seq2)
@@ -394,7 +436,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
@@ -505,6 +547,7 @@ function blob(desync, name, def)
error("blob '"..name.."' unavailable")
end
end
blob = tostring(blob)
end
return blob
end
@@ -553,7 +596,6 @@ function array_search(a, v)
return k
end
end
return nil
end
-- linear search array a for a[index].f==v. return index
function array_field_search(a, f, v)
@@ -562,7 +604,6 @@ function array_field_search(a, f, v)
return k
end
end
return nil
end
-- find pos of the next eol and pos of the next non-eol character after eol
@@ -603,18 +644,53 @@ 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
end
return f
end
end
-- get ip protocol from l3 headers
function ip_proto_l3(dis)
if dis.ip then
return dis.ip.ip_p
elseif dis.ip6 then
return #dis.ip6.exthdr==0 and dis.ip6.ip6_nxt or dis.ip6.exthdr[#dis.ip6.exthdr].next
end
end
-- get ip protocol from l4 headers
function ip_proto_l4(dis)
if dis.tcp then
return IPPROTO_TCP
elseif dis.udp then
return IPPROTO_UDP
elseif dis.ip then
return dis.icmp and IPPROTO_ICMP or nil
elseif dis.ip6 then
return dis.icmp and IPPROTO_ICMPV6 or nil
end
end
function ip_proto(dis)
return ip_proto_l4(dis) or ip_proto_l3(dis)
end
-- discover ip protocol and fix "next" fields
function fix_ip_proto(dis, proto)
local pr = proto or ip_proto(dis)
if pr then
if dis.ip then
dis.ip.ip_p = pr
elseif dis.ip6 then
fix_ip6_next(dis.ip6, pr)
end
end
end
-- find first tcp options of specified kind in dissect.tcp.options
function find_tcp_option(options, kind)
if options then
for i, opt in pairs(options) do
for i, opt in ipairs(options) do
if opt.kind==kind then return i end
end
end
@@ -624,7 +700,7 @@ end
-- find first ipv6 extension header of specified protocol in dissect.ip6.exthdr
function find_ip6_exthdr(exthdr, proto)
if exthdr then
for i, hdr in pairs(exthdr) do
for i, hdr in ipairs(exthdr) do
if hdr.type==proto then return i end
end
end
@@ -696,6 +772,14 @@ function dis_reverse(dis)
end
end
function dis_reconstruct_l3(dis, options)
if dis.ip then
return csum_ip4_fix(reconstruct_iphdr(dis.ip))
elseif dis.ip6 then
return reconstruct_ip6hdr(dis.ip6, options)
end
end
-- parse autottl : delta,min-max
function parse_autottl(s)
if s then
@@ -724,9 +808,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
@@ -774,6 +858,7 @@ end
-- 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.
-- tcp_nop_del - delete NOP tcp options to free space in tcp header
-- fool - custom fooling function : fool_func(dis, fooling_options)
function apply_fooling(desync, dis, fooling_options)
@@ -790,7 +875,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)
@@ -805,8 +894,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
@@ -823,11 +915,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)))
@@ -835,12 +935,23 @@ function apply_fooling(desync, dis, fooling_options)
if fooling_options.tcp_flags_set then
dis.tcp.th_flags = bitor(dis.tcp.th_flags, parse_tcp_flags(fooling_options.tcp_flags_set))
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_nop_del then
for i=#dis.tcp.options,1,-1 do
if dis.tcp.options[i].kind==TCP_KIND_NOOP then
table.remove(dis.tcp.options,i)
end
end
end
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
@@ -851,18 +962,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
@@ -952,7 +1063,7 @@ function l3_extra_len(dis, ip6_exthdr_last_idx)
end
elseif dis.ip6 and dis.ip6.exthdr then
local ct
if ip6_exthdr_last_idx and ip6_exthdr_last_idx<=#dis.ip6.exthdr then
if ip6_exthdr_last_idx and ip6_exthdr_last_idx>=0 and ip6_exthdr_last_idx<=#dis.ip6.exthdr then
ct = ip6_exthdr_last_idx
else
ct = #dis.ip6.exthdr
@@ -979,6 +1090,8 @@ function l4_base_len(dis)
return TCP_BASE_LEN
elseif dis.udp then
return UDP_BASE_LEN
elseif dis.icmp then
return ICMP_BASE_LEN
else
return 0
end
@@ -1018,7 +1131,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")
@@ -1038,7 +1151,7 @@ function rawsend_dissect_ipfrag(dis, options)
if not rawsend_dissect(fragments[i], options.rawsend, reconstruct_frag) then return false end
end
else
for i, d in pairs(fragments) do
for i, d in ipairs(fragments) do
DLOG("sending ip fragment "..i)
-- C function
if not rawsend_dissect(d, options.rawsend, reconstruct_frag) then return false end
@@ -1054,28 +1167,41 @@ end
-- send dissect with tcp segmentation based on mss value. appply specified rawsend options.
function rawsend_dissect_segmented(desync, dis, mss, options)
dis = dis or desync.dis
local discopy = deepcopy(dis)
options = options or desync_opts(desync)
apply_fooling(desync, discopy, options and options.fooling)
if dis.tcp then
mss = mss or desync.tcp_mss
local extra_len = l3l4_extra_len(discopy)
if extra_len >= mss then return false end
local max_data = mss - extra_len
local urp = dis.tcp.th_urp
local oob = bitand(dis.tcp.th_flags, TH_URG)~=0
if #discopy.payload > max_data then
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(discopy.tcp.th_flags, TH_URG)
discopy.tcp.th_urp = urp-pos+1
else
discopy.tcp.th_flags = bitand(discopy.tcp.th_flags, bitnot(TH_URG))
discopy.tcp.th_urp = 0
end
end
discopy.payload = string.sub(payload,pos,pos+len-1)
apply_ip_id(desync, discopy, options and options.ipid)
if not rawsend_dissect_ipfrag(discopy, options) then
-- stop if failed
return false
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
@@ -1088,20 +1214,20 @@ end
-- send specified payload based on existing L3/L4 headers in the dissect. add seq to tcp.th_seq.
function rawsend_payload_segmented(desync, payload, seq, options)
options = options or desync_opts(desync)
local dis = deepcopy(desync.dis)
-- save some cpu and ram
local dis = (payload or seq and seq~=0) and deepcopy(desync.dis) or desync.dis
if payload then dis.payload = payload end
if dis.tcp and seq then
dis.tcp.th_seq = dis.tcp.th_seq + seq
end
return rawsend_dissect_segmented(desync, dis, desync.tcp_mss, options)
return rawsend_dissect_segmented(desync, dis, nil, 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"
function direction_check(desync, def)
local dir = desync.arg.dir or def or "out"
return desync.outgoing and desync.arg.dir~="in" or not desync.outgoing and dir~="out"
return desync.outgoing and dir~="in" or not desync.outgoing and dir~="out"
end
-- if dir "in" or "out" cutoff current desync function from opposite direction
function direction_cutoff_opposite(ctx, desync, def)
@@ -1144,9 +1270,9 @@ function replay_drop_set(desync, v)
if v == nil then v=true end
local rdk = replay_drop_key(desync)
if v then
if desync.replay then desync.track.lua_state[replay_drop_key] = true end
if desync.replay then desync.track.lua_state[rdk] = true end
else
desync.track.lua_state[replay_drop_key] = nil
desync.track.lua_state[rdk] = nil
end
end
end
@@ -1154,7 +1280,7 @@ end
-- return true if the caller should return VERDICT_DROP
function replay_drop(desync)
if desync.track then
local drop = desync.replay and desync.track.lua_state[replay_drop_key]
local drop = desync.replay and desync.track.lua_state[replay_drop_key(desync)]
if not desync.replay or desync.replay_piece_last then
-- replay stopped or last piece of reasm
replay_drop_set(desync, false)
@@ -1211,6 +1337,31 @@ function host_or_ip(desync)
return host_ip(desync)
end
-- rate limited update of global ifaddrs
function update_ifaddrs()
if ifaddrs then
local now = os.time()
if not ifaddrs_last then ifaddrs_last = now end
if ifaddrs_last~=now then
ifaddrs = get_ifaddrs()
ifaddrs_last = now
end
else
ifaddrs = get_ifaddrs()
end
end
-- search ifaddrs for ip and return interface name or nil if not found
-- do not call get_ifaddrs too often to avoid overhead
function ip2ifname(ip)
update_ifaddrs()
if not ifaddrs then return nil end
for ifname,ifinfo in pairs(ifaddrs) do
if array_field_search(ifinfo.addr, "addr", ip) then
return ifname
end
end
end
function is_absolute_path(path)
if string.sub(path,1,1)=='/' then return true end
local un = uname()
@@ -1256,8 +1407,10 @@ end
-- standard fragmentation to 2 ip fragments
-- function returns 2 dissects with fragments
-- option : ipfrag_pos_udp - udp frag position. ipv4 : starting from L4 header. ipb6: starting from fragmentable part. must be multiple of 8. default 8
-- option : ipfrag_pos_tcp - tcp frag position. ipv4 : starting from L4 header. ipb6: starting from fragmentable part. must be multiple of 8. default 32
-- 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_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)
@@ -1291,6 +1444,8 @@ function ipfrag2(dis, ipfrag_options)
pos = ipfrag_options.ipfrag_pos_tcp or 32
elseif dis.udp then
pos = ipfrag_options.ipfrag_pos_udp or 8
elseif dis.icmp then
pos = ipfrag_options.ipfrag_pos_icmp or 8
else
pos = ipfrag_options.ipfrag_pos or 32
end
@@ -1307,12 +1462,8 @@ function ipfrag2(dis, ipfrag_options)
if (pos+l3)>0xFFFF then
error("ipfrag2: too high frag offset")
end
local plen = l3 + l4_len(dis) + #dis.payload
if (pos+l3)>=plen then
DLOG("ipfrag2: ip frag pos exceeds packet length. ipfrag cancelled.")
return nil
end
local plen = l3 + l4_len(dis) + #dis.payload
if dis.ip then
-- ipv4 frag is done by both lua and C part
-- lua code must correctly set ip_len, IP_MF and ip_off and provide full unfragmented payload
@@ -1320,6 +1471,11 @@ function ipfrag2(dis, ipfrag_options)
-- ip_off must be set to fragment offset and IP_MF bit must be set if it's not the last fragment
-- C code constructs unfragmented packet then moves everything after ip header according to ip_off and ip_len
if (pos+l3)>=plen then
DLOG("ipfrag2: ip frag pos "..pos.." exceeds packet length. ipfrag cancelled.")
return nil
end
-- ip_id must not be zero or fragment will be dropped
local ip_id = dis.ip.ip_id==0 and math.random(1,0xFFFF) or dis.ip.ip_id
dis1 = deepcopy(dis)
@@ -1340,7 +1496,15 @@ function ipfrag2(dis, ipfrag_options)
-- C code constructs unfragmented packet then moves fragmentable part as needed
local idxfrag = frag_idx(dis.ip6.exthdr)
local l3extra = l3_extra_len(dis, idxfrag-1) + 8 -- all ext headers before frag + 8 bytes for frag header
local l3extra = l3_extra_len(dis, idxfrag-1) -- all ext headers before frag
l3 = l3_base_len(dis) + l3extra
if (pos+l3)>=plen then
DLOG("ipfrag2: ip frag pos "..pos.." exceeds packet length. ipfrag cancelled.")
return nil
end
l3extra = l3extra + 8 -- + 8 bytes for frag header
local ident = math.random(1,0xFFFFFFFF)
dis1 = deepcopy(dis)
@@ -1356,7 +1520,6 @@ function ipfrag2(dis, ipfrag_options)
end
dis2.ip6.ip6_plen = plen - IP6_BASE_LEN + 8 - pos -- packet len without frag + 8 byte frag header - ipv6 base header
end
return {dis1,dis2}
end
@@ -1403,11 +1566,122 @@ 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
function is_gzip_file(filename)
local f, err = io.open(filename, "rb")
if not f then
error("is_gzip_file: "..err)
end
local hdr = f:read(2)
f:close()
return hdr and hdr=="\x1F\x8B"
end
-- ungzip file to raw string
-- expected_ratio = uncompressed_size/compressed_size (default 4)
function gunzip_file(filename, expected_ratio, read_block_size)
local f, err = io.open(filename, "rb")
if not f then
error("gunzip_file: "..err)
end
if not read_block_size then read_block_size=16384 end
if not expected_ratio then expected_ratio=4 end
local decompressed=""
local gz = gunzip_init()
if not gz then
error("gunzip_file: stream init error")
end
repeat
local compressed, err = f:read(read_block_size)
if not compressed then
f:close()
gunzip_end(gz)
if err then
error("gunzip_file: file read error : "..err)
else
return nil
end
end
local decomp, eof = gunzip_inflate(gz, compressed, #compressed * expected_ratio)
if not decomp then
f:close()
gunzip_end(gz)
return nil
end
decompressed = decompressed .. decomp
until eof
f:close()
gunzip_end(gz)
return decompressed
end
-- zip file to raw string
-- expected_ratio = uncompressed_size/compressed_size (default 2)
-- level : 1..9 (default 9)
-- memlevel : 1..8 (default 8)
function gzip_file(filename, data, expected_ratio, level, memlevel, compress_block_size)
local f, err = io.open(filename, "wb")
if not f then
error("gzip_file: "..err)
end
if not compress_block_size then compress_block_size=16384 end
if not expected_ratio then expected_ratio=2 end
local gz = gzip_init(nil, level, memlevel)
if not gz then
error("gzip_file: stream init error")
end
local off=1
repeat
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
f:close()
gzip_end(gz)
return nil
end
f:write(comp)
off = off + block_size
until eof
f:close()
gzip_end(gz)
end
-- reads the whole file
function readfile(filename)
local f, err = io.open(filename, "rb")
if not f then
error("readfile: "..err)
end
local s, err = f:read("*a")
f:close()
if err then
error("readfile: "..err)
end
return s
end
-- reads plain or gzipped file with transparent decompression
-- expected_ratio = uncompressed_size/compressed_size (default 4)
function z_readfile(filename, expected_ratio)
return is_gzip_file(filename) and gunzip_file(filename, expected_ratio) or readfile(filename)
end
-- write data to filename
function writefile(filename, data)
local f, err = io.open(filename, "wb")
if not f then
error("writefile: "..err)
end
local s, err = f:write(data)
f:close()
if not s then
error("writefile: "..err)
end
end
-- DISSECTORS
@@ -1423,19 +1697,22 @@ function http_dissect_header(header)
end
-- make table with structured http header representation
function http_dissect_headers(http, pos)
local eol,pnext,header,value,idx,headers,pos_endheader,pos_startvalue
local eol,pnext,header,value,headers,pos_endheader,pos_startvalue,pos_headers_end
headers={}
while pos do
eol,pnext = find_next_line(http,pos)
header = string.sub(http,pos,eol)
if #header == 0 then break end
if #header == 0 then
pos_headers_end = pnext
break
end
header,value,pos_endheader,pos_startvalue = http_dissect_header(header)
if header then
headers[string.lower(header)] = { header = header, value = value, pos_start = pos, pos_end = eol, pos_header_end = pos+pos_endheader-1, pos_value_start = pos+pos_startvalue-1 }
headers[#headers+1] = { header_low = string.lower(header), header = header, value = value, pos_start = pos, pos_end = eol, pos_header_end = pos+pos_endheader-1, pos_value_start = pos+pos_startvalue-1 }
end
pos=pnext
end
return headers
return headers, pos_headers_end
end
-- make table with structured http request representation
function http_dissect_req(http)
@@ -1457,9 +1734,21 @@ function http_dissect_req(http)
pos = string.find(req,"[^ \t]",pos+1)
if not pos then return nil end
pnext = string.find(req,"[ \t]",pos+1)
if not pnext then pnext = #http + 1 end
if not pnext then pnext = #req + 1 end
local uri = string.sub(req,pos,pnext-1)
return { method = method, uri = uri, headers = http_dissect_headers(http,hdrpos) }
pos = string.find(req,"[^ \t]",pnext)
local http_ver
if pos then
pnext = string.find(req,"[\r\n]",pos)
if not pnext then pnext = #req + 1 end
http_ver = string.sub(req,pos,pnext-1)
end
local hdis = { method = method, uri = uri, http_ver = http_ver }
hdis.headers, hdis.pos_headers_end = http_dissect_headers(http,hdrpos)
if hdis.pos_headers_end then
hdis.body = string.sub(http, hdis.pos_headers_end)
end
return hdis
end
function http_dissect_reply(http)
if not http then return nil; end
@@ -1467,10 +1756,24 @@ function http_dissect_reply(http)
s = string.sub(http,1,8)
if s~="HTTP/1.1" and s~="HTTP/1.0" then return nil end
pos = string.find(http,"[ \t\r\n]",10)
if not pos then return nil end
code = tonumber(string.sub(http,10,pos-1))
if not code then return nil end
pos = find_next_line(http,pos)
return { code = code, headers = http_dissect_headers(http,pos) }
s,pos = find_next_line(http,pos)
local hdis = { code = code }
hdis.headers, hdis.pos_headers_end = http_dissect_headers(http,pos)
if hdis.pos_headers_end then
hdis.body = string.sub(http, hdis.pos_headers_end)
end
return hdis
end
function http_reconstruct_headers(headers, unixeol)
local eol = unixeol and "\n" or "\r\n"
return headers and barray(headers, function(a) return a.header..": "..a.value..eol end) or ""
end
function http_reconstruct_req(hdis, unixeol)
local eol = unixeol and "\n" or "\r\n"
return hdis.method.." "..hdis.uri..(hdis.http_ver and (" "..hdis.http_ver) or "")..eol..http_reconstruct_headers(hdis.headers, unixeol)..eol..(hdis.body or "")
end
function dissect_url(url)
@@ -1843,7 +2146,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))
@@ -1882,12 +2185,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)
@@ -1958,7 +2261,8 @@ function tls_dissect_ext(ext)
return left, off
end
local dis={}, off, len, left
local dis={}
local off, len, left
ext.dis = nil
@@ -2166,6 +2470,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
@@ -2181,7 +2490,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)
@@ -2191,14 +2500,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)

482
lua/zapret-obfs.lua Normal file
View File

@@ -0,0 +1,482 @@
-- test case : --in-range=a --out-range=a --lua-desync=wgobfs:secret=mycoolpassword
-- encrypt standard wireguard messages - initiation, response, cookie - and change udp packet size
-- do not encrypt data messages and keepalives
-- wgobfs adds maximum of 30+padmax bytes to udp size
-- reduce MTU of wireguard interface to avoid ip fragmentation !
-- without knowing the secret encrypted packets should be crypto strong white noise with no signature
-- arg : secret - shared secret. any string. must be the same on both peers
-- arg : padmin - min random garbage bytes. 0 by default
-- arg : padmax - max random garbage bytes. 16 by default
-- NOTE : this function does not depend on zapret-lib.lua and should not be run under orchestrator (uses direct instance_cutoff)
function wgobfs(ctx, desync)
if not desync.dis.udp then
instance_cutoff_shim(ctx, desync)
return
end
local padmin = desync.arg.padmin and tonumber(desync.arg.padmin) or 0
local padmax = desync.arg.padmax and tonumber(desync.arg.padmax) or 16
local function genkey()
-- cache key in a global var bound to instance name
local key_cache_name = desync.func_instance.."_key"
local key = _G[key_cache_name]
if not key then
key = hkdf("sha256", "wgobfs_salt", desync.arg.secret, nil, 16)
_G[key_cache_name] = key
end
return key
end
local function maybe_encrypted_payload(payload)
for k,plsize in pairs({2+12+16+148, 2+12+16+92, 2+12+16+64}) do
if #payload>=(plsize+padmin) and #payload<=(plsize+padmax) then
return true
end
end
return false
end
local function wg_payload_from_size(payload)
if #payload==148 then return "wireguard_initiation"
elseif #payload==92 then return "wireguard_response"
elseif #payload==64 then return "wireguard_cookie"
else return nil
end
end
if not desync.arg.secret or #desync.arg.secret==0 then
error("wgobfs: secret required")
end
if padmin>padmax then
error("wgobfs: padmin>padmax")
end
if (desync.l7payload=="wireguard_initiation" or desync.l7payload=="wireguard_response" or desync.l7payload=="wireguard_cookie") and #desync.dis.payload<65506 then
DLOG("wgobfs: encrypting '"..desync.l7payload.."'. size "..#desync.dis.payload)
local key = genkey()
-- in aes-gcm every message require it's own crypto secure random iv
-- encrypting more than one message with the same iv is considered catastrophic failure
-- iv must be sent with encrypted message
local iv = bcryptorandom(12)
local encrypted, atag = aes_gcm(true, key, iv, bu16(#desync.dis.payload)..desync.dis.payload..brandom(math.random(padmin,padmax)), nil)
desync.dis.payload = iv..atag..encrypted
return VERDICT_MODIFY
end
if desync.l7payload=="unknown" and maybe_encrypted_payload(desync.dis.payload) then
local key = genkey()
local iv = string.sub(desync.dis.payload,1,12)
local atag = string.sub(desync.dis.payload,13,28)
local decrypted, atag2 = aes_gcm(false, key, iv, string.sub(desync.dis.payload,29))
if atag==atag2 then
local plen = u16(decrypted)
if plen>(#decrypted-2) then
DLOG("wgobfs: bad decrypted payload data")
else
desync.dis.payload = string.sub(decrypted, 3, 3+plen-1)
if b_debug then DLOG("wgobfs: decrypted '"..(wg_payload_from_size(desync.dis.payload) or "unknown").."' message. size "..plen) end
return VERDICT_MODIFY
end
else
DLOG("wgobfs: decrypt auth tag mismatch")
end
end
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: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: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
-- iperf -s
-- xor ip protocol number and optionally xor tcp,udp,icmp payload with supplied blob pattern
-- arg : ippxor - value to xor ip protocol number
-- arg : dataxor - blob to xor tcp, udp or icmp payload
-- arg : rebuild - always reconstruct desync.dis if after ippxor packet becomes tcp,udp or icmp
function ippxor(ctx, desync)
local dataxor
local function need_dxor(dis)
return dataxor and dis.payload and #dis.payload>0 and (dis.tcp or dis.udp or dis.icmp)
end
local function dxor(dis)
dis.payload = bxor(dis.payload, pattern(dataxor,1,#dis.payload))
end
if not desync.arg.ippxor then
error("ippxor: ippxor value required")
end
local ippxor = tonumber(desync.arg.ippxor)
if ippxor<0 or ippxor>0xFF then
error("ippxor: invalid ippxor value. should be 0..255")
end
if desync.arg.dataxor then
dataxor = blob(desync,desync.arg.dataxor)
if #dataxor==0 then
error("ippxor: empty dataxor value")
end
end
local bdxor = need_dxor(desync.dis)
if bdxor then
DLOG("ippxor: dataxor size="..#desync.dis.payload)
dxor(desync.dis)
end
local l3_from = ip_proto_l3(desync.dis)
local l3_to = bitxor(l3_from, ippxor)
DLOG("ippxor: "..l3_from.." => "..l3_to)
fix_ip_proto(desync.dis, l3_to)
if (not bdxor and dataxor or desync.arg.rebuild) and
(l3_to==IPPROTO_TCP and not desync.dis.tcp or
l3_to==IPPROTO_UDP and not desync.dis.udp or
l3_to==IPPROTO_ICMP and not (desync.dis.ip and desync.dis.icmp) or
l3_to==IPPROTO_ICMPV6 and not (desync.dis.ip6 and desync.dis.icmp))
then
DLOG("ippxor: packet rebuild")
local raw_ip = reconstruct_dissect(desync.dis, {ip6_preserve_next=true})
local dis = dissect(raw_ip)
if not dis.ip and not dis.ip6 then
DLOG_ERR("ippxor: could not rebuild packet")
return
end
desync.dis = dis
end
if not bdxor and need_dxor(desync.dis) then
DLOG("ippxor: dataxor size="..#desync.dis.payload)
dxor(desync.dis)
end
return VERDICT_MODIFY + VERDICT_PRESERVE_NEXT
end
-- test case:
-- endpoint1:
-- --in-range=a --lua-desync=udp2icmp
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp dport 12345 queue num 200 bypass
-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto "{icmp,icmpv6}" queue num 200 bypass
-- endpoint2:
-- --in-range=a --lua-desync=udp2icmp --server
-- nft add rule inet ztest post meta mark and 0x40000000 == 0 udp sport 12345 queue num 200 bypass
-- nft add rule inet ztest pre meta mark and 0x40000000 == 0 meta l4proto "{icmp,icmpv6}" queue num 200 bypass
-- packs udp datagram to icmp message without changing packet size
-- function keeps icmp identifier as (sport xor dport) to help traverse NAT (it won't help if NAT changes id)
-- one end must be in server mode, another - in client mode
-- arg : ctype - client icmp type
-- arg : ccode - client icmp code
-- arg : stype - server icmp type
-- 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
function udp2icmp(ctx, desync)
local dataxor
local bserver = desync.arg.server and (desync.arg.server~="0") or b_server
local function one_byte_arg(name)
if desync.arg[name] then
local v = tonumber(desync.arg[name])
if v<0 or v>0xFF then
error("udp2icmp: invalid type or code value. should be 0..255")
end
return v
end
end
local function ictype(send)
local ctype = one_byte_arg("ctype")
local stype = one_byte_arg("stype")
if logical_xor(ctype,stype) then
error("udp2icmp: ctype and stype must be both set or not set")
end
if not ctype then
ctype = desync.dis.ip6 and ICMP6_ECHO_REQUEST or ICMP_ECHO
stype = desync.dis.ip6 and ICMP6_ECHO_REPLY or ICMP_ECHOREPLY
end
return logical_xor(send,bserver) and ctype or stype
end
local function iccode(send)
local ccode = one_byte_arg("ccode")
local scode = one_byte_arg("scode")
if logical_xor(ccode,scode) then
error("udp2icmp: ccode and scode must be both set or not set")
end
if not ccode then
ccode = 0
scode = 0
end
return logical_xor(send,bserver) and ccode or scode
end
local function plxor()
if dataxor then
DLOG("udp2icmp: dataxor")
desync.dis.payload = bxor(desync.dis.payload, pattern(dataxor,1,#desync.dis.payload))
end
end
if desync.arg.dataxor then
dataxor = blob(desync,desync.arg.dataxor)
if #dataxor==0 then
error("udp2icmp: empty dataxor value")
end
end
if desync.dis.udp then
plxor()
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
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)))
}
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)
desync.dis.udp = {
uh_sport = bserver and pm or pl,
uh_dport = bserver and pl or pm,
uh_ulen = UDP_BASE_LEN + #desync.dis.payload
}
desync.dis.icmp = nil
fix_ip_proto(desync.dis)
if b_debug then -- save some cpu
DLOG("udp2icmp: icmp => udp sport="..desync.dis.udp.uh_sport.." dport="..desync.dis.udp.uh_dport.." size="..#desync.dis.payload)
end
plxor()
return VERDICT_MODIFY
end
end
--[[
test case :
both:
nft create table inet ztest
nft add chain inet ztest post "{type filter hook output priority mangle;}"
nft add chain inet ztest pre "{type filter hook input priority mangle;}"
nft add chain inet ztest predefrag "{type filter hook output priority -401;}"
nft add rule inet ztest predefrag "mark & 0x40000000 != 0x00000000 notrack"
client:
--in-range="<d1" --out-range="<d1" --lua-desync=synhide:synack:ghost=2
nft add rule inet ztest post "meta mark & 0x40000000 == 0x00000000 tcp dport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == syn queue flags bypass to 200"
nft add rule inet ztest pre meta "mark & 0x40000000 == 0x00000000 tcp sport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == (rst | ack) tcp urgptr != 0 queue flags bypass to 200"
nft add rule inet ztest pre meta "mark & 0x40000000 == 0x00000000 tcp sport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == (rst | ack) tcp option 172 exists queue flags bypass to 200"
nft add rule inet ztest pre meta "mark & 0x40000000 == 0x00000000 tcp sport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == (rst | ack) @th,100,4 != 0 queue flags bypass to 200"
server:
--in-range=a --lua-desync=synhide:synack
nft add rule inet ztest post "meta mark & 0x40000000 == 0x00000000 tcp sport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == (syn | ack) queue flags bypass to 200"
nft add rule inet ztest pre "meta mark & 0x40000000 == 0x00000000 tcp dport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == ack tcp urgptr != 0 queue flags bypass to 200"
nft add rule inet ztest pre "meta mark & 0x40000000 == 0x00000000 tcp dport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == ack tcp option 172 exists queue flags bypass to 200"
nft add rule inet ztest pre "meta mark & 0x40000000 == 0x00000000 tcp dport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == ack @th,100,4 != 0 queue flags bypass to 200"
nft add rule inet ztest pre "meta mark & 0x40000000 == 0x00000000 tcp dport { 80, 443 } tcp flags & (fin | syn | rst | ack | urg) == ack ct state new queue flags bypass to 200"
hides tcp handshake from DPI optionally using ghost SYN packet with low ttl to punch NAT hole
NOTE: linux conntrack treats packets without SYN in SYN_SENT state as INVALID ! NAT does not work !
NOTE: the only found workaround - put NFQUEUE handler to that packet. It should only return pass verdict.
NOTE: BSD and CGNAT should work
NOTE: won't likely pass home routers even with hardware offload enabled - SYN state is managed in netfilter before offload. but can work from router itself.
arg : ghost - ghost syn ttl for ipv4. must be hop_to_last_nat+1. syn is not ghosted if not supplied
arg : ghost6 - ghost syn hl for ipv6. must be hop_to_last_nat+1. syn is not ghosted if not supplied
arg : synack - also fake synack. NOTE: will likely not work with magic=tsecr on *nix clients because they expect valid echoed tsecr in SYN,ACK
arg : magic=[x2|urp|opt|tsecr] - where to put magic value to recognize modified packets
arg : x2=bit - th_x2 bit used for magic=x2 - 1,2,4,8
arg : kind - kind of tcp option for magic=opt
arg : opt=hex - tcp option value
arg : xorseq=hex - 4 hex bytes to xor seq
--]]
function synhide(ctx, desync)
if not desync.dis.tcp then
instance_cutoff_shim(ctx, desync)
return
end
local fl = bitand(desync.dis.tcp.th_flags, TH_SYN+TH_ACK+TH_FIN+TH_RST+TH_URG)
local tsidx = find_tcp_option(desync.dis.tcp.options, TCP_KIND_TS)
local magic
if desync.arg.magic then
if desync.arg.magic~="tsecr" and desync.arg.magic~="x2" and desync.arg.magic~="urp" and desync.arg.magic~="opt" then
error("synhide: invalid magic mode '"..desync.arg.magic.."'")
end
magic = desync.arg.magic
if magic=="tsecr" and not tsidx then
DLOG("synhide: cannot use tsecr magic because timestamp option is absent")
instance_cutoff_shim(ctx, desync)
return
end
else
magic = "x2"
end
DLOG("synhide: magic="..magic)
local x2
if desync.arg.x2 then
x2 = tonumber(desync.arg.x2)
if x2<1 or x2>0x0F then
error("synhide: invalid x2 value")
end
else
-- some firewalls allow only AECN bit (1). if reserved bits are !=0 => administratively prohibited
x2 = 1
end
local kind
if desync.arg.kind then
kind = tonumber(desync.arg.kind)
-- do not allow noop and end
if kind<2 or kind>0xFF then
error("synhide: invalid kind value")
end
else
kind = 172 -- accurate ecn
end
local opt
if desync.arg.opt then
opt = parse_hex(desync.arg.opt)
if not opt then
error("synhide: invalid opt value")
end
else
opt=""
end
local xorseq
if desync.arg.xorseq then
xorseq = parse_hex(desync.arg.xorseq)
if not xorseq or #xorseq~=4 then
error("synhide: invalid xorseq value")
end
xorseq = u32(xorseq)
end
local function make_magic(client)
local m
-- use client seq0
m = client and desync.dis.tcp.th_seq or desync.dis.tcp.th_ack-1
m = bitxor(bitrshift(m,16),bitand(m,0xFFFF))
if m==0 then
-- 0 is not acceptable
m = client and desync.dis.tcp.th_dport or desync.dis.tcp.th_sport
end
return m
end
local function xorhdr()
if xorseq then
desync.dis.tcp.th_ack = bitxor(desync.dis.tcp.th_ack, xorseq)
desync.dis.tcp.th_seq = bitxor(desync.dis.tcp.th_seq, xorseq)
end
end
local function ver_magic(client)
local r = false
xorhdr()
if magic=="tsecr" then
r = make_magic(client)==u16(string.sub(desync.dis.tcp.options[tsidx].data,7))
elseif magic=="x2" then
r = bitand(desync.dis.tcp.th_x2, x2)~=0
elseif magic=="urp" then
r = desync.dis.tcp.th_urp == make_magic(client)
elseif magic=="opt" then
local idx = find_tcp_option(desync.dis.tcp.options, kind)
r = idx and desync.dis.tcp.options[idx].data == opt
end
xorhdr()
return r
end
local function set_magic(client)
if magic=="tsecr" then
desync.dis.tcp.options[tsidx].data = string.sub(desync.dis.tcp.options[tsidx].data,1,6) .. bu16(make_magic(client))
elseif magic=="x2" then
desync.dis.tcp.th_x2 = bitor(desync.dis.tcp.th_x2, x2)
elseif magic=="urp" then
desync.dis.tcp.th_urp = make_magic(client)
elseif magic=="opt" then
table.insert(desync.dis.tcp.options, {kind=kind, data=opt})
end
xorhdr()
end
local function clear_magic()
xorhdr()
if magic=="tsecr" then
desync.dis.tcp.options[tsidx].data = string.sub(desync.dis.tcp.options[tsidx].data,1,6) .. "\x00\x00"
elseif magic=="x2" then
desync.dis.tcp.th_x2 = bitand(desync.dis.tcp.th_x2,bitnot(x2))
elseif magic=="urp" then
desync.dis.tcp.th_urp = 0
elseif magic=="opt" then
local idx = find_tcp_option(desync.dis.tcp.options, kind)
if idx then
table.remove(desync.dis.tcp.options, idx)
end
end
desync.track = conntrack_feed(desync.dis)
end
if fl==TH_SYN then
-- client sent
local ttl = tonumber(desync.dis.ip and desync.arg.ghost or desync.arg.ghost6)
if ttl then
DLOG("synhide: punch NAT hole with ttl="..ttl)
local dis = deepcopy(desync.dis)
if dis.ip then
dis.ip.ip_ttl = ttl
elseif dis.ip6 then
dis.ip6.ip6_hlim = ttl
end
if not rawsend_dissect(dis, rawsend_opts_base(desync)) then
instance_cutoff_shim(ctx, desync) -- failed
return
end
end
DLOG("synhide: client sends SYN. remove SYN")
set_magic(true)
-- remove SYN, set ACK
desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_SYN)), TH_ACK)
if not desync.arg.synack then
DLOG("synhide: mission complete")
instance_cutoff_shim(ctx, desync)
end
return VERDICT_MODIFY
elseif fl==(TH_SYN+TH_ACK) then
-- server sent
if desync.arg.synack then
DLOG("synhide: server sends SYN+ACK. remove SYN, set RST")
set_magic(false)
desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_SYN)), TH_RST)
return VERDICT_MODIFY
else
DLOG("synhide: server sends SYN+ACK. do not remove SYN because 'synack' arg is not set.")
instance_cutoff_shim(ctx, desync)
return -- do nothing
end
elseif fl==TH_ACK and ver_magic(true) then
DLOG("synhide: server received magic. restore SYN")
desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_ACK)), TH_SYN)
clear_magic()
if not desync.arg.synack then
DLOG("synhide: mission complete")
instance_cutoff_shim(ctx, desync)
end
return VERDICT_MODIFY
elseif fl==(TH_ACK+TH_RST) and ver_magic(false) then
DLOG("synhide: client received magic. restore SYN, remove RST")
desync.dis.tcp.th_flags = bitor(bitand(desync.dis.tcp.th_flags, bitnot(TH_RST)), TH_SYN)
clear_magic()
DLOG("synhide: mission complete")
instance_cutoff_shim(ctx, desync)
return VERDICT_MODIFY
end
DLOG("synhide: sequence failed")
instance_cutoff_shim(ctx, desync)
end

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();
@@ -30,10 +30,11 @@ function pcap(ctx, desync)
os.remove(_G[fn_cache_name])
end
end
local f = io.open(_G[fn_cache_name], "a")
local f = io.open(_G[fn_cache_name], "ab")
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

View File

@@ -13,15 +13,19 @@ end
function test_all(...)
test_run({test_crypto, test_bin, test_ipstr, test_dissect, test_csum, test_resolve, test_rawsend},...)
test_run({
test_crypto, test_bin, test_time, test_gzip, test_ipstr, test_dissect, test_csum, test_resolve,
test_get_source_ip, test_ifaddrs, test_rawsend},...)
end
function test_crypto(...)
test_run({test_random, test_aes, test_aes_gcm, test_aes_ctr, test_hkdf, test_hash},...)
test_run({test_random, test_bop, test_aes, test_aes_gcm, test_aes_ctr, test_hkdf, test_hash},...)
end
function test_random()
print("* random")
local rnds={}
for i=1,20 do
local rnd = bcryptorandom(math.random(10,20))
@@ -31,7 +35,35 @@ function test_random()
end
end
function test_bop()
print("* bop")
for n,test in ipairs(
{
{ fb = bxor, fbit = bitxor, nb = "bxor", nbit="bitxor" },
{ fb = bor, fbit = bitor, nb = "bor", nbit="bitor" },
{ fb = band, fbit = bitand, nb = "band", nbit="bitand" }
}) do
for k=1,5 do
local r = {}
for i=1,6 do r[i] = math.random(0,0xFFFFFFFFFFFF) end
local v1 = bu48(r[1])..bu48(r[2])..bu48(r[3])
local v2 = bu48(r[4])..bu48(r[5])..bu48(r[6])
print("x1 : "..string2hex(v1))
print("x2 : "..string2hex(v2))
local v3 = test.fb(v1,v2)
local v4 = bu48(test.fbit(r[1],r[4]))..bu48(test.fbit(r[2],r[5]))..bu48(test.fbit(r[3],r[6]))
print(test.nb.." : "..string2hex(v3))
print(test.nbit.." : "..string2hex(v4))
print("result : "..(v3==v4 and "OK" or "FAIL"))
test_assert(v3==v4)
end
end
end
function test_hash()
print("* hash")
local hashes={}
for i=1,5 do
local rnd = brandom(math.random(5,64))
@@ -48,6 +80,8 @@ function test_hash()
end
function test_hkdf()
print("* hkdf")
local nblob = 2
local okms = {}
for nsalt=1,nblob do
@@ -56,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))
@@ -73,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
@@ -84,8 +116,10 @@ function test_hkdf()
end
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)
@@ -93,7 +127,7 @@ function test_aes()
print()
print("* aes test key_size "..tostring(key_size))
print("clear text: "..clear_text);
print("clear text: "..clear_text)
print("* encrypting")
encrypted = aes(true, key, clear_text)
@@ -121,6 +155,8 @@ function test_aes()
end
function test_aes_gcm()
print("* aes_gcm")
local authenticated_data = "authenticated message "..brandom_az09(math.random(10,50))
local clear_text="test message "..brandom_az09(math.random(10,50))
local iv, key, encrypted, atag, decrypted, atag2
@@ -132,8 +168,8 @@ function test_aes_gcm()
print()
print("* aes_gcm test key_size "..tostring(key_size))
print("clear text: "..clear_text);
print("authenticated data: "..authenticated_data);
print("clear text: "..clear_text)
print("authenticated data: "..authenticated_data)
print("* encrypting")
encrypted, atag = aes_gcm(true, key, iv, clear_text, authenticated_data)
@@ -188,6 +224,8 @@ function test_aes_gcm()
end
function test_aes_ctr()
print("* aes_ctr")
local clear_text="test message "..brandom_az09(math.random(10,50))
local iv, key, encrypted, decrypted
@@ -198,7 +236,7 @@ function test_aes_ctr()
print()
print("* aes_ctr test key_size "..tostring(key_size))
print("clear text: "..clear_text);
print("clear text: "..clear_text)
print("* encrypting")
encrypted = aes_ctr(key, iv, clear_text)
@@ -251,6 +289,8 @@ function test_aes_ctr()
end
function test_ub()
print("* ub")
for k,f in pairs({{u8,bu8,0xFF,8}, {u16,bu16,0xFFFF,16}, {u24,bu24,0xFFFFFF,24}, {u32,bu32,0xFFFFFFFF,32}, {u48,bu48,0xFFFFFFFFFFFF,48}}) do
local v = math.random(0,f[3])
local pos = math.random(1,20)
@@ -262,6 +302,8 @@ function test_ub()
end
function test_bit()
print("* bit")
local v, v2, v3, v4, b1, b2, pow
for i=1,100 do
@@ -304,8 +346,46 @@ function test_bit()
end
end
function test_swap()
print("* swap")
local v1, v2, v3
v1 = math.random(0,0xFFFF)
v2 = swap16(v1)
v3 = divint(v1,0x100) + v1%0x100*0x100
print("swap16: "..(v2==v3 and "OK" or "FAIL"))
test_assert(v2==v3)
v1 = math.random(0,0xFFFFFF)
v2 = swap24(v1)
v3 = divint(v1,0x10000) + divint(v1,0x100)%0x100*0x100 + v1%0x100*0x10000
print("swap24: "..(v2==v3 and "OK" or "FAIL"))
test_assert(v2==v3)
v1 = math.random(0,0xFFFFFFFF)
v2 = swap32(v1)
v3 = divint(v1,0x1000000) + divint(v1,0x10000)%0x100*0x100 + divint(v1,0x100)%0x100*0x10000 + v1%0x100*0x1000000
print("swap32: "..(v2==v3 and "OK" or "FAIL"))
test_assert(v2==v3)
v1 = math.random(0,0xFFFFFFFFFFFF)
v2 = swap48(v1)
v3 = divint(v1,0x10000000000) +
divint(v1,0x100000000)%0x100*0x100 +
divint(v1,0x1000000)%0x100*0x10000 +
divint(v1,0x10000)%0x100*0x1000000 +
divint(v1,0x100)%0x100*0x100000000 +
v1%0x100*0x10000000000
print("swap48: "..(v2==v3 and "OK" or "FAIL"))
test_assert(v2==v3)
end
function test_ux()
print("* ux")
local v1, v2, v3, usum, sum
for k,test in pairs({
{ add=u8add, fname="u8add", max = 0xFF },
{ add=u16add, fname="u16add", max = 0xFFFF },
@@ -330,14 +410,83 @@ function test_ux()
end
function test_bin(...)
test_run({test_ub, test_bit, test_ux},...)
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")
local s=""
for i=1,math.random(2000,3000) do
local rnd=brandom(math.random(1,50))
s=s..rnd..string.rep(bu8(math.random(0,255)),100-#rnd)
end
local v=math.random(100001,199999)
local level=math.random(1,9)
local memlevel=math.random(1,8)
print("gzip: original size "..#s)
print("gzip: cut point "..(v+1))
print("gzip: level "..level)
print("gzip: memlevel "..memlevel)
local gz = gzip_init(nil, level, memlevel)
local zip = gzip_deflate(gz,string.sub(s,1,v))
zip = zip..gzip_deflate(gz,string.sub(s,v+1))
zip = zip..gzip_deflate(gz,nil) -- finalize
gzip_end(gz)
print("gzip: deflated size "..#zip)
local v=math.random(2,#zip-1)
print("gunzip: cut point "..(v+1))
gz = gunzip_init()
local unzip = gunzip_inflate(gz,string.sub(zip,1,v))
unzip = unzip..gunzip_inflate(gz,string.sub(zip,v+1))
gunzip_end(gz)
print("gunzip: inflated size "..#unzip)
print("gzip+gunzip: "..(s==unzip and "OK" or "FAIL"))
test_assert(s==unzip)
end
function test_ipstr()
print("* ipstr")
local s_ip, ip, s_ip2
s_ip = string.format("%u.%u.%u.%u", math.random(0,255), math.random(0,255), math.random(0,255), math.random(0,255));
s_ip = string.format("%u.%u.%u.%u", math.random(0,255), math.random(0,255), math.random(0,255), math.random(0,255))
ip = pton(s_ip)
s_ip2 = ntop(ip)
print("IP: "..s_ip)
@@ -345,7 +494,7 @@ function test_ipstr()
print("IP2: "..s_ip2)
test_assert(s_ip==s_ip2)
s_ip = string.format("%x:%x:%x:%x:%x:%x:%x:%x", math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF));
s_ip = string.format("%x:%x:%x:%x:%x:%x:%x:%x", math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF), math.random(1,0xFFFF))
ip = pton(s_ip)
s_ip2 = ntop(ip)
print("IP: "..s_ip)
@@ -356,7 +505,9 @@ end
function test_dissect()
local dis, raw1, raw2
print("* dissect")
local raw1, raw2
for i=1,20 do
print("* dissect test "..tostring(i))
@@ -393,13 +544,56 @@ function test_dissect()
}
raw1 = reconstruct_dissect(ip_tcp)
print("IP+TCP : "..string2hex(raw1))
dis1 = dissect(raw1);
dis1 = dissect(raw1)
raw2 = reconstruct_dissect(dis1)
dis2 = dissect(raw2);
dis2 = dissect(raw2)
print("IP+TCP2: "..string2hex(raw2))
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
test_assert(raw1==raw2)
print("IP standalone")
raw1 = reconstruct_iphdr(ip_tcp.ip)
print("IP1: "..string2hex(raw1))
dis1 = dissect_iphdr(raw1)
raw2 = reconstruct_iphdr(dis1)
print("IP2: "..string2hex(raw2))
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
test_assert(raw1==raw2)
print("TCP standalone")
raw1 = reconstruct_tcphdr(ip_tcp.tcp)
print("TCP1: "..string2hex(raw1))
dis1 = dissect_tcphdr(raw1)
raw2 = reconstruct_tcphdr(dis1)
print("TCP2: "..string2hex(raw2))
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
test_assert(raw1==raw2)
local ip_icmp = {
ip = {
ip_tos = math.random(0,255),
ip_id = math.random(0,0xFFFF),
ip_off = 0,
ip_ttl = math.random(0,255),
ip_p = IPPROTO_ICMP,
ip_src = brandom(4),
ip_dst = brandom(4),
options = brandom(math.random(0,40))
},
icmp = {
icmp_type = ICMP_DEST_UNREACH, icmp_code=ICMP_UNREACH_PORT,
icmp_data = math.random(1,0xFFFFFFFF)
}
}
print("ICMP standalone")
raw1 = reconstruct_icmphdr(ip_icmp.icmp)
print("ICMP1: "..string2hex(raw1))
dis1 = dissect_icmphdr(raw1)
raw2 = reconstruct_icmphdr(dis1)
print("ICMP2: "..string2hex(raw2))
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
test_assert(raw1==raw2)
local ip6_udp = {
ip6 = {
ip6_flow = 0x60000000 + math.random(0,0xFFFFFFF),
@@ -417,21 +611,59 @@ function test_dissect()
},
payload = brandom(math.random(0, 20))
}
raw1 = reconstruct_dissect(ip6_udp)
print("IP6+UDP : "..string2hex(raw1))
dis1 = dissect(raw1);
dis1 = dissect(raw1)
raw2 = reconstruct_dissect(dis1)
dis2 = dissect(raw2);
dis2 = dissect(raw2)
print("IP6+UDP2: "..string2hex(raw2))
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
test_assert(raw1==raw2)
raw1 = string.sub(reconstruct_dissect(ip6_udp),1,-4-#ip6_udp.payload)
dis1 = dissect(raw1, false)
dis2 = dissect(raw1, true)
local ok = not dis1.ip6 and dis2.ip6
print("IP6 partial : "..(ok and "OK" or "FAIL"))
test_assert(ok)
print("IP6+IPP")
dis1 = {ip6 = ip6_udp.ip6, payload=brandom(math.random(1,1))}
raw1 = reconstruct_dissect(dis1,{ip6_last_proto=IPPROTO_IPIP})
dis2 = dissect(raw1)
raw2 = reconstruct_dissect(dis2,{ip6_preserve_next=true})
print("IP6+IPP1: "..string2hex(raw1))
print("IP6+IPP2: "..string2hex(raw2))
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
test_assert(raw1==raw2)
print("UDP standalone")
raw1 = reconstruct_udphdr(ip6_udp.udp)
print("UDP1: "..string2hex(raw1))
dis1 = dissect_udphdr(raw1)
raw2 = reconstruct_udphdr(dis1)
print("UDP2: "..string2hex(raw2))
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
test_assert(raw1==raw2)
print("IP6 standalone")
ip6_udp.ip6.ip6_plen = nil
raw1 = reconstruct_ip6hdr(ip6_udp.ip6,{ip6_last_proto=IPPROTO_UDP})
print("IP1: "..string2hex(raw1))
dis1 = dissect_ip6hdr(raw1)
raw2 = reconstruct_ip6hdr(dis1,{ip6_last_proto=IPPROTO_UDP})
print("IP2: "..string2hex(raw2))
print( raw1==raw2 and "DISSECT OK" or "DISSECT FAILED" )
test_assert(raw1==raw2)
end
end
function test_csum()
print("* csum")
local payload = brandom(math.random(10,20))
local ip4b, ip6b, raw, tcpb, udpb, dis1, dis2
local ip4b, ip6b, raw, tcpb, udpb, icmpb, dis1, dis2
local ip = {
ip_tos = math.random(0,255),
ip_id = math.random(0,0xFFFF),
@@ -497,6 +729,8 @@ function test_csum()
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" )
@@ -532,12 +766,6 @@ function test_csum()
print( dis1.tcp.th_sum==dis2.tcp.th_sum and "TCP+IP6 CSUM OK" or "TCP+IP6 CSUM FAILED" )
test_assert(dis1.tcp.th_sum==dis2.tcp.th_sum)
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})
local udp = {
uh_sport = math.random(0,0xFFFF),
uh_dport = math.random(0,0xFFFF),
@@ -552,46 +780,136 @@ 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)
dis2 = dissect(ip6b..udpb..payload)
print( dis1.udp.uh_sum==dis2.udp.uh_sum and "UDP+IP6 CSUM OK" or "UDP+IP6 CSUM FAILED" )
test_assert(dis1.udp.uh_sum==dis2.udp.uh_sum)
local icmp = {
icmp_type = math.random(0,0xFF), icmp_code=math.random(0,0xFF),
icmp_data = math.random(0,0xFFFFFFFF)
}
ip.ip_p = IPPROTO_ICMP
ip4b = reconstruct_iphdr(ip)
ip6.ip6_plen = packet_len({ip6=ip6,icmp=icmp,payload=payload}) - IP6_BASE_LEN
ip6b = reconstruct_ip6hdr(ip6, {ip6_last_proto=IPPROTO_ICMPV6})
icmpb = reconstruct_icmphdr(icmp)
raw = bu8(icmp.icmp_type) ..
bu8(icmp.icmp_code) ..
bu16(0) ..
bu32(icmp.icmp_data)
print( raw==icmpb and "ICMP RECONSTRUCT OK" or "ICMP RECONSTRUCT FAILED" )
test_assert(raw==icmpb)
raw = reconstruct_dissect({ip=ip, icmp=icmp, payload=payload})
dis1 = dissect(raw)
icmpb = csum_icmp_fix(ip4b,icmpb,payload)
dis2 = dissect(ip4b..icmpb..payload)
print( dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum and "ICMP+IP4 CSUM OK" or "ICMP+IP4 CSUM FAILED" )
test_assert(dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum)
raw = reconstruct_dissect({ip6=ip6, icmp=icmp, payload=payload})
dis1 = dissect(raw)
icmpb = csum_icmp_fix(ip6b,icmpb,payload)
dis2 = dissect(ip6b..icmpb..payload)
print( dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum and "ICMP+IP6 CSUM OK" or "ICMP+IP6 CSUM FAILED" )
test_assert(dis1.icmp.icmp_cksum==dis2.icmp.icmp_cksum)
end
function test_resolve()
print("* resolve")
local pos
pos = zero_based_pos(resolve_multi_pos(fake_default_tls,"tls_client_hello","1,extlen,sniext,host,sld,midsld,endsld,endhost,-5"))
local tdis = tls_dissect(fake_default_tls)
local extlen_pos = 5 + 6 + 32 + 1 + 2 + 1 + #tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.session_id + #tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.cipher_suites*2 + #tdis.handshake[TLS_HANDSHAKE_TYPE_CLIENT].dis.compression_methods
print("fake_default_tls size "..#fake_default_tls.." extlen="..extlen_pos)
local m="1,extlen,sniext,host,sld,midsld,endsld,endhost,-5"
pos = resolve_multi_pos(fake_default_tls,"tls_client_hello",m,true)
test_assert(pos)
print("resolve_multi_pos tls : "..table.concat(pos," "))
pos = zero_based_pos(resolve_range(fake_default_tls,"tls_client_hello","host,endhost"))
print("resolve_multi_pos tls : "..m.." : "..table.concat(pos," "))
m = "host,endhost"
pos = resolve_range(fake_default_tls,"tls_client_hello",m,false,true)
test_assert(pos)
print("resolve_range tls : "..table.concat(pos," "))
pos = resolve_pos(fake_default_tls,"tls_client_hello","midsld")
print("resolve_range tls : "..m.." : "..table.concat(pos," "))
m = "1"
pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true)
test_assert(pos==1)
print("resolve_pos tls : "..m.." : "..pos)
m = "-1"
pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true)
test_assert(pos==(#fake_default_tls-1))
print("resolve_pos tls : "..m.." : "..pos)
m = "extlen"
pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true)
test_assert(pos==extlen_pos)
print("resolve_pos tls : "..m.." : "..pos)
m = "midsld"
pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true)
test_assert(pos)
print("resolve_pos tls : "..pos - 1)
pos = resolve_pos(fake_default_tls,"tls_client_hello","method")
print("resolve_pos tls : "..m.." : "..pos)
m = "method"
pos = resolve_pos(fake_default_tls,"tls_client_hello",m,true)
test_assert(not pos)
print("resolve_pos tls non-existent : "..tostring(pos))
print("resolve_pos tls non-existent : "..m.." : "..tostring(pos))
pos = zero_based_pos(resolve_multi_pos(fake_default_http,"http_req","method,host,sld,midsld,endsld,endhost,-5"))
local host_pos = string.find(fake_default_http,"Host: ")+6-1
print("fake_default_http size "..#fake_default_http.." host="..host_pos)
m = "method,host,sld,midsld,endsld,endhost,-5"
pos = resolve_multi_pos(fake_default_http,"http_req",m,true)
test_assert(pos)
print("resolve_multi_pos http : "..table.concat(pos," "))
pos = resolve_pos(fake_default_http,"http_req","sniext")
test_assert(pos[1]==0)
test_assert(pos[2]==host_pos)
print("resolve_multi_pos http : "..m.." : "..table.concat(pos," "))
m = "sniext"
pos = resolve_pos(fake_default_http,"http_req",m,true)
test_assert(not pos)
print("resolve_pos http non-existent : "..tostring(pos))
print("resolve_pos http non-existent : "..m.." : "..tostring(pos))
end
function test_get_source_ip(opts)
print("* get_source_ip")
for k,d in ipairs({
'127.0.0.1','192.168.1.1','10.1.1.1','1.1.1.1','255.255.255.255',
'::1','fc81::4','2a06::1','2001:470::1','2002:0101:0101::1','::1.1.1.1'})
do
local src = get_source_ip(pton(d))
print((src and ntop(src) or "?").." => "..d)
end
end
function test_ifaddrs(opts)
print("* ifaddrs")
local ifa = get_ifaddrs()
test_assert(ifa)
for ifname,ifinfo in pairs(ifa) do
print(ifname.." index="..tostring(ifinfo.index).." mtu="..tostring(ifinfo.mtu))
for i,addr in ipairs(ifinfo.addr) do
print(" "..ntop(addr.addr)..(addr.netmask and " mask "..tostring(ntop(addr.netmask)) or ""))
end
end
end
function test_rawsend(opts)
print("* rawsend")
local ifout = (opts and opts.ifout) and opts.ifout
local function rawsend_fail_warning()
if not opts or not opts.ifout or #opts.ifout==0 then
@@ -601,13 +919,13 @@ function test_rawsend(opts)
end
end
end
local function rawsend_dissect_print(dis, options)
local function rawsend_dissect_print(dis, options, reconstruct)
if options then
options.ifout = ifout
else
options = { ifout = ifout }
end
local b = rawsend_dissect(dis, options)
local b = rawsend_dissect(dis, options, reconstruct)
if not b then
print("rawsend_dissect failed")
rawsend_fail_warning()
@@ -630,17 +948,31 @@ 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
for k,v in pairs(ifinfo.addr) do
if #v.addr==4 and string.sub(v.addr,1,2)=="\xC0\xA8" then
target = string.sub(v.addr,1,3)..bu8(u8add(u8(v.addr,4),1))
break
end
end
end
target = target or pton("192.168.254.32")
print("ipv4 target is "..ntop(target))
ip = {
ip_tos = 0,
ip_id = math.random(0,0xFFFF),
ip_off = 0,
ip_ttl = 1,
ip_p = IPPROTO_UDP,
ip_src = pton("192.168.1.1"),
ip_dst = pton("192.168.1.2")
ip_src = get_source_ip(target),
ip_dst = target
}
if not ip.ip_src then
print("dest "..ntop(target).." unreachable")
test_assert(false)
end
udp = {
uh_sport = math.random(0,0xFFFF),
uh_dport = math.random(0,0xFFFF)
@@ -663,18 +995,41 @@ function test_rawsend(opts)
print("send ipv4 udp using pure rawsend without dissect")
test_assert(rawsend_print(raw, {repeats=5}))
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
target = string.sub(v.addr,1,1)..bu8(u8add(u8(v.addr,2),1))..string.sub(v.addr,3)
break
end
end
end
target = target or pton("fdce:3124:164a:5318::2")
print("ipv6 target is "..ntop(target))
ip6 = {
ip6_flow = 0x60000000,
ip6_hlim = 1,
ip6_src = pton("fdce:3124:164a:5318::1"),
ip6_dst = pton("fdce:3124:164a:5318::2")
ip6_src = get_source_ip(target),
ip6_dst = target
}
if not ip6.ip6_src then
print("dest "..ntop(target).." unreachable")
test_assert(false)
end
dis = {ip6 = ip6, udp = udp, payload = payload}
print("send ipv6 udp")
test_assert(rawsend_dissect_print(dis, {repeats=3}))
ip2 = deepcopy(ip6)
ip2.ip6_plen = UDP_BASE_LEN + #payload
raw_ip = reconstruct_ip6hdr(ip2, {ip6_last_proto = IPPROTO_UDP})
raw_udp = reconstruct_udphdr({uh_sport = udp.uh_sport, uh_dport = udp.uh_dport, uh_ulen = UDP_BASE_LEN + #payload})
raw_udp = csum_udp_fix(raw_ip,raw_udp,payload)
raw = raw_ip .. raw_udp .. payload
print("send ipv6 udp using pure rawsend without dissect")
test_assert(rawsend_print(raw, {repeats=7}))
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80})
for k,d in pairs(ddis) do
for k,d in ipairs(ddis) do
print("send ipv6 udp frag "..k)
test_assert(rawsend_dissect_print(d))
end
@@ -684,27 +1039,67 @@ function test_rawsend(opts)
test_assert(rawsend_dissect_print(dis, {repeats=3}))
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80})
for k,d in pairs(ddis) do
for k,d in ipairs(ddis) do
print("send ipv6 udp frag "..k.." with hopbyhop ext header")
test_assert(rawsend_dissect_print(d))
end
table.insert(ip6.exthdr, { type = IPPROTO_DSTOPTS, data = "\x00\x00\x00\x00\x00\x00" })
table.insert(ip6.exthdr, { type = IPPROTO_DSTOPTS, data = "\x00\x00\x00\x00\x00\x00" })
ip6.ip6_flow = 0x60001234;
insert_ip6_exthdr(ip6, nil, IPPROTO_DSTOPTS, "\x00\x00\x00\x00\x00\x00")
insert_ip6_exthdr(ip6, nil, IPPROTO_DSTOPTS, "\x00\x00\x00\x00\x00\x00")
ip6.ip6_flow = 0x60001234
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80})
for k,d in pairs(ddis) do
for k,d in ipairs(ddis) do
print("send ipv6 udp frag "..k.." with hopbyhop, destopt ext headers in unfragmentable part and another destopt ext header in fragmentable part")
test_assert(rawsend_dissect_print(d, {fwmark = 0x50EA}))
end
fix_ip6_next(ip6) -- required to forge next proto in the second fragment
ip6.ip6_flow = 0x6000AE38;
ddis = ipfrag2(dis, {ipfrag_pos_udp = 80, ipfrag_next = IPPROTO_TCP})
for k,d in pairs(ddis) do
fix_ip_proto(dis) -- ip6_preserve_next requires next fields in ip6.exthdr
ip6.ip6_flow = 0x6000AE38
ddis = ipfrag2(dis, {ipfrag_pos_udp = 72, ipfrag_next = IPPROTO_TCP})
for k,d in ipairs(ddis) do
print("send ipv6 udp frag "..k.." with hopbyhop, destopt ext headers in unfragmentable part and another destopt ext header in fragmentable part. forge next proto in fragment header of the second fragment to TCP")
-- reconstruct dissect using next proto fields in the dissect. do not auto fix next proto chain.
-- by default reconstruct fixes next proto chain
test_assert(rawsend_dissect_print(d, {fwmark = 0x409A, repeats=2}, {ip6_preserve_next = true}))
end
local icmp = {
icmp_type = ICMP_ECHO, icmp_code=0,
icmp_data = u32(bu16(math.random(1,0xFFFF))..bu16(1))
}
ip.ip_p = IPPROTO_ICMP
payload=brandom_az09(math.random(10,1100))
dis = {ip = ip, icmp = icmp, payload = payload}
print("send ipv4 icmp")
test_assert(rawsend_dissect_print(dis, {fwmark = 0xD133, repeats=3}))
ip6.exthdr={{ type = IPPROTO_HOPOPTS, data = "\x00\x00\x00\x00\x00\x00" }}
ip6.ip6_flow=0x60009E3B
icmp.icmp_type = ICMP6_ECHO_REQUEST
dis = {ip6 = ip6, icmp = icmp, payload = payload}
print("send ipv6 icmp")
test_assert(rawsend_dissect_print(dis, {fwmark = 0x8E10, repeats=3}))
ip2 = {
ip_tos = 0,
ip_id = math.random(0,0xFFFF),
ip_off = 0,
ip_ttl = 64,
ip_p = IPPROTO_UDP,
ip_src = pton("10.1.1.1"),
ip_dst = pton("10.1.1.2"),
}
dis = {ip = ip2, udp = udp, payload = payload}
raw_udp = reconstruct_dissect(dis)
ip6.ip6_flow=0x6000583F
dis = {ip6 = ip6, payload = raw_udp}
print("send ipv6 ipip")
test_assert(rawsend_dissect_print(dis, {fwmark = 0x8E10, repeats=3}, {ip6_last_proto=IPPROTO_IPIP}))
dis = {ip = ip, payload = raw_udp}
dis.ip.ip_p = IPPROTO_IPIP
print("send ipv4 ipip")
test_assert(rawsend_dissect_print(dis, {fwmark = 0x8E10, repeats=3}, {ip6_last_proto=IPPROTO_IPIP}))
end

View File

@@ -1,79 +0,0 @@
-- test case : --in-range=a --out-range=a --lua-desync=wgobfs:secret=mycoolpassword
-- encrypt standard wireguard messages - initiation, response, cookie - and change udp packet size
-- do not encrypt data messages and keepalives
-- wgobfs adds maximum of 30+padmax bytes to udp size
-- reduce MTU of wireguard interface to avoid ip fragmentation !
-- without knowing the secret encrypted packets should be crypto strong white noise with no signature
-- arg : secret - shared secret. any string. must be the same on both peers
-- arg : padmin - min random garbage bytes. 0 by default
-- arg : padmax - max random garbage bytes. 16 by default
function wgobfs(ctx, desync)
local padmin = desync.arg.padmin and tonumber(desync.arg.padmin) or 0
local padmax = desync.arg.padmax and tonumber(desync.arg.padmax) or 16
local function genkey()
-- cache key in a global var bound to instance name
local key_cache_name = desync.func_instance.."_key"
key = _G[key_cache_name]
if not key then
key = hkdf("sha256", "wgobfs_salt", desync.arg.secret, nil, 16)
_G[key_cache_name] = key
end
return key
end
local function maybe_encrypted_payload(payload)
for k,plsize in pairs({2+12+16+148, 2+12+16+92, 2+12+16+64}) do
if #payload>=(plsize+padmin) and #payload<=(plsize+padmax) then
return true
end
end
return false
end
local function wg_payload_from_size(payload)
if #payload==148 then return "wireguard_initiation"
elseif #payload==92 then return "wireguard_response"
elseif #payload==64 then return "wireguard_cookie"
else return nil
end
end
if not desync.dis.udp then
instance_cutoff(ctx)
return
end
if not desync.arg.secret or #desync.arg.secret==0 then
error("wgobfs requires secret")
end
if padmin>padmax then
error("wgobfs: padmin>padmax")
end
if desync.l7payload=="wireguard_initiation" or desync.l7payload=="wireguard_response" or desync.l7payload=="wireguard_cookie" and #desync.dis.payload<65506 then
DLOG("wgobfs: encrypting '"..desync.l7payload.."'. size "..#desync.dis.payload)
local key = genkey()
-- in aes-gcm every message require it's own crypto secure random iv
-- encrypting more than one message with the same iv is considered catastrophic failure
-- iv must be sent with encrypted message
local iv = bcryptorandom(12)
local encrypted, atag = aes_gcm(true, key, iv, bu16(#desync.dis.payload)..desync.dis.payload..brandom(math.random(padmin,padmax)), nil)
desync.dis.payload = iv..atag..encrypted
return VERDICT_MODIFY
end
if desync.l7payload=="unknown" and maybe_encrypted_payload(desync.dis.payload) then
local key = genkey()
local iv = string.sub(desync.dis.payload,1,12)
local atag = string.sub(desync.dis.payload,13,28)
local decrypted, atag2 = aes_gcm(false, key, iv, string.sub(desync.dis.payload,29))
if atag==atag2 then
local plen = u16(decrypted)
if plen>(#decrypted-2) then
DLOG("wgobfs: bad decrypted payload data")
else
desync.dis.payload = string.sub(decrypted, 3, 3+plen-1)
if b_debug then DLOG("wgobfs: decrypted '"..(wg_payload_from_size(desync.dis.payload) or "unknown").."' message. size "..plen) end
return VERDICT_MODIFY
end
else
DLOG("wgobfs: decrypt auth tag mismatch")
end
end
end

View File

@@ -1,8 +1,11 @@
CC ?= cc
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE)
CFLAGS_PIC = -fPIC
CFLAGS += -std=gnu99 $(OPTIMIZE) $(CFLAGS_PIC)
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_WIN = -static
LDFLAGS_PIE = -pie
LDFLAGS += $(LDFLAGS_PIE)
LIBS = -lpthread
LIBS_ANDROID =
LIBS_WIN = -lws2_32

View File

@@ -30,7 +30,8 @@
#endif
#include <time.h>
#define RESOLVER_EAGAIN_ATTEMPTS 2
#define RESOLVER_EAGAIN_ATTEMPTS 10
#define RESOLVER_EAGAIN_DELAY 500
static void trimstr(char *s)
{
@@ -79,15 +80,15 @@ static bool dom_valid(char *dom)
{
if (!dom || *dom=='.') return false;
for (; *dom; dom++)
if (*dom < 0x20 || (*dom & 0x80) || !(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z')))
return false;
if (!(*dom == '.' || *dom == '-' || *dom == '_' || (*dom >= '0' && *dom <= '9') || (*dom >= 'a' && *dom <= 'z') || (*dom >= 'A' && *dom <= 'Z')))
return false;
return true;
}
static void invalid_domain_beautify(char *dom)
{
for (int i = 0; *dom && i < 64; i++, dom++)
if (*dom < 0x20 || *dom>0x7F) *dom = '?';
if (*dom < 0x20 || (*dom & 0x80)) *dom = '?';
if (*dom) *dom = 0;
}
@@ -97,7 +98,7 @@ static struct
{
char verbose;
char family;
int threads;
int threads, eagain, eagain_delay;
time_t start_time;
pthread_mutex_t flock;
pthread_mutex_t slock; // stats lock
@@ -193,11 +194,12 @@ static void *t_resolver(void *arg)
int i, r;
char dom[256];
bool is_ok;
struct addrinfo hints;
struct addrinfo *result;
struct addrinfo hints, *result;
struct timespec ts_eagain = { .tv_sec = glob.eagain_delay/1000, .tv_nsec=glob.eagain_delay%1000*1000000 };
VLOG("started");
memset(&hints, 0, sizeof(struct addrinfo));
hints.ai_family = (glob.family == FAMILY4) ? AF_INET : (glob.family == FAMILY6) ? AF_INET6 : AF_UNSPEC;
hints.ai_socktype = SOCK_DGRAM;
@@ -218,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)
{
@@ -244,12 +246,16 @@ static void *t_resolver(void *arg)
else if (dom_valid(dom))
{
VLOG("resolving %s", dom);
for (i = 0; i < RESOLVER_EAGAIN_ATTEMPTS; i++)
for (i = 0; i < glob.eagain; i++)
{
if ((r = getaddrinfo(dom, NULL, &hints, &result)))
{
VLOG("failed to resolve %s : result %d (%s)", dom, r, eai_str(r));
if (r == EAI_AGAIN) continue; // temporary failure. should retry
if (r == EAI_AGAIN)
{
nanosleep(&ts_eagain, NULL);
continue; // temporary failure. should retry
}
}
else
{
@@ -430,7 +436,7 @@ int dns_parse_query()
_setmode(_fileno(stdin), _O_BINARY);
#endif
l = fread(a,1,sizeof(a),stdin);
if (!l || !feof(stdin))
if (!l || ferror(stdin))
{
fprintf(stderr, "could not read DNS reply blob from stdin\n");
return 10;
@@ -447,14 +453,18 @@ int dns_parse_query()
static void exithelp(void)
{
printf(
" --threads=<threads_number>\n"
" --family=<4|6|46>\t\t; ipv4, ipv6, ipv4+ipv6\n"
" --threads=<threads_number>\n"
" --eagain=<eagain_retries>\t; how many times to retry if EAI_AGAIN received. default %u\n"
" --eagain-delay=<ms>\t\t; time in msec to wait between EAI_AGAIN attempts. default %u\n"
" --verbose\t\t\t; print query progress to stderr\n"
" --stats=N\t\t\t; print resolve stats to stderr every N domains\n"
" --log-resolved=<file>\t\t; log successfully resolved domains to a file\n"
" --log-failed=<file>\t\t; log failed domains to a file\n"
" --dns-make-query=<domain>\t; output to stdout binary blob with DNS query. use --family to specify ip version.\n"
" --dns-parse-query\t\t; read from stdin binary DNS answer blob and parse it to ipv4/ipv6 addresses\n"
" --dns-parse-query\t\t; read from stdin binary DNS answer blob and parse it to ipv4/ipv6 addresses\n",
RESOLVER_EAGAIN_ATTEMPTS,
RESOLVER_EAGAIN_DELAY
);
exit(1);
}
@@ -469,6 +479,8 @@ static void exithelp(void)
enum opt_indices {
IDX_HELP,
IDX_EAGAIN,
IDX_EAGAIN_DELAY,
IDX_THREADS,
IDX_FAMILY,
IDX_VERBOSE,
@@ -483,6 +495,8 @@ enum opt_indices {
static const struct option long_options[] = {
[IDX_HELP] = {"help", no_argument, 0, 0},
[IDX_THREADS] = {"threads", required_argument, 0, 0},
[IDX_EAGAIN] = {"eagain", required_argument, 0, 0},
[IDX_EAGAIN_DELAY] = {"eagain-delay", required_argument, 0, 0},
[IDX_FAMILY] = {"family", required_argument, 0, 0},
[IDX_VERBOSE] = {"verbose", no_argument, 0, 0},
[IDX_STATS] = {"stats", required_argument, 0, 0},
@@ -503,6 +517,8 @@ int main(int argc, char **argv)
*fn1 = *fn2 = *dom = 0;
glob.family = FAMILY4;
glob.threads = 1;
glob.eagain = RESOLVER_EAGAIN_ATTEMPTS;
glob.eagain_delay = RESOLVER_EAGAIN_DELAY;
while ((v = getopt_long_only(argc, argv, "", long_options, &option_index)) != -1)
{
if (v) exithelp();
@@ -513,13 +529,29 @@ int main(int argc, char **argv)
exithelp();
break;
case IDX_THREADS:
glob.threads = optarg ? atoi(optarg) : 0;
glob.threads = atoi(optarg);
if (glob.threads <= 0 || glob.threads > 100)
{
fprintf(stderr, "thread number must be within 1..100\n");
return 1;
}
break;
case IDX_EAGAIN:
glob.eagain = atoi(optarg);
if (glob.eagain <= 0 || glob.eagain > 1000)
{
fprintf(stderr, "eagain must be within 1..1000\n");
return 1;
}
break;
case IDX_EAGAIN_DELAY:
glob.eagain_delay = atoi(optarg);
if (glob.eagain_delay < 0 || glob.eagain_delay > 100000)
{
fprintf(stderr, "eagain-delay must be within 0..100000\n");
return 1;
}
break;
case IDX_FAMILY:
if (!strcmp(optarg, "4"))
glob.family = FAMILY4;

View File

@@ -1,6 +1,12 @@
CC ?= cc
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 -s $(OPTIMIZE) -flto=auto -Wno-address-of-packed-member
PKG_CONFIG ?= pkg-config
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
@@ -14,7 +20,7 @@ LUA_PKG:=luajit
.else
LUA_VER ?= 5.4
LUA_VER ?= 5.5
LUA_VER_UNDOTTED!= echo $(LUA_VER) | sed 's/\.//g'
OSNAME!=uname
@@ -26,8 +32,8 @@ OSNAME!=uname
.endif
LUA_LIB!= pkg-config --libs $(LUA_PKG)
LUA_CFLAGS!= pkg-config --cflags $(LUA_PKG)
LUA_LIB!= $(PKG_CONFIG) --libs $(LUA_PKG)
LUA_CFLAGS!= $(PKG_CONFIG) --cflags $(LUA_PKG)
.if "${LUA_JIT}" == "1"
LUA_CFLAGS+=-DLUAJIT
@@ -36,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

View File

@@ -1,21 +1,31 @@
CC ?= cc
PKG_CONFIG ?= pkg-config
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
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
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
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lole32 -loleaut32 -liphlpapi -lntdll
LIBS_CYGWIN32 = -lwindivert32
LIBS_CYGWIN64 = -lwindivert64
RES_CYGWIN32 = windows/res/32/winmanifest.o windows/res/32/winicon.o
RES_CYGWIN64 = windows/res/64/winmanifest.o windows/res/64/winicon.o
RES_CYGWIN32 = windows/res/winws_res32.o
RES_CYGWIN64 = windows/res/winws_res64.o
SRC_FILES = *.c crypto/*.c
SRC_FILES_ANDROID = $(SRC_FILES) andr/*.c
LUA_JIT?=1
@@ -24,18 +34,19 @@ 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))
LUA_LIB_NAME=
ifeq ($(LUA_CFLAGS),)
LUA_CFLAGS := $(shell pkg-config --cflags $(LUA_PKG) 2>/dev/null)
LUA_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(LUA_PKG) 2>/dev/null)
ifeq ($(LUA_CFLAGS),)
LUA_CFLAGS := -I/usr/local/include/luajit-$(LUAJIT_VER) -I/usr/include/luajit-$(LUAJIT_VER)
endif
endif
ifeq ($(LUA_LIB),)
LUA_LIB := $(shell pkg-config --libs $(LUA_PKG) 2>/dev/null)
LUA_LIB := $(shell $(PKG_CONFIG) --libs $(LUA_PKG) 2>/dev/null)
LUA_LIB_DIR :=
ifeq ($(LUA_LIB),)
@@ -72,7 +83,7 @@ ifeq ($(LUA_LIB),)
# no success with luajit
LUA_VER?=5.4
LUA_VER?=5.5
LUA_VER_UNDOTTED:=$(shell echo $(LUA_VER) | sed 's/\.//g')
LUA_CFL :=
@@ -87,13 +98,13 @@ else
endif
ifeq ($(LUA_CFLAGS),)
LUA_CFLAGS := $(shell pkg-config --cflags $(LUA_PKG) 2>/dev/null)
LUA_CFLAGS := $(shell $(PKG_CONFIG) --cflags $(LUA_PKG) 2>/dev/null)
ifeq ($(LUA_CFLAGS),)
LUA_CFLAGS := -I/usr/local/include/lua$(LUA_VER) -I/usr/local/include/lua-$(LUA_VER) -I/usr/include/lua$(LUA_VER) -I/usr/include/lua-$(LUA_VER)
LUA_CFLAGS := -I/usr/local/include/lua$(LUA_VER) -I/usr/local/include/lua-$(LUA_VER) -I/usr/include/lua$(LUA_VER) -I/usr/include/lua-$(LUA_VER) -I/usr/local/include/lua -I/usr/local/include
endif
endif
ifeq ($(LUA_LIB),)
LUA_LIB := $(shell pkg-config --libs $(LUA_PKG) 2>/dev/null)
LUA_LIB := $(shell $(PKG_CONFIG) --libs $(LUA_PKG) 2>/dev/null)
LUA_LIB_DIR :=
ifeq ($(LUA_LIB),)
ifneq ($(wildcard /usr/local/lib/liblua-$(LUA_VER).*),)
@@ -131,21 +142,24 @@ LUA_CFL += $(LUA_CFLAGS)
all: nfqws2
nfqws2: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(LUA_CFL) -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_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)
$(CC) -s $(CFLAGS) $(LUA_CFL) -o nfqws2 $(SRC_FILES) $(LIBS) $(LUA_LIB) $(LIBS_LINUX) $(LDFLAGS) $(LDFLAGS_ANDROID)
android: $(SRC_FILES_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)
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)
cygwin: cygwin64
clean:

216
nfq2/andr/getifaddrs.c Normal file
View File

@@ -0,0 +1,216 @@
#define _GNU_SOURCE
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <ifaddrs.h>
#include <syscall.h>
#include <net/if.h>
#include <netinet/in.h>
#include "netlink.h"
#define IFADDRS_HASH_SIZE 64
/* getifaddrs() reports hardware addresses with PF_PACKET that implies
* struct sockaddr_ll. But e.g. Infiniband socket address length is
* longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct
* to extend ssl_addr - callers should be able to still use it. */
struct sockaddr_ll_hack {
unsigned short sll_family, sll_protocol;
int sll_ifindex;
unsigned short sll_hatype;
unsigned char sll_pkttype, sll_halen;
unsigned char sll_addr[24];
};
union sockany {
struct sockaddr sa;
struct sockaddr_ll_hack ll;
struct sockaddr_in v4;
struct sockaddr_in6 v6;
};
struct ifaddrs_storage {
struct ifaddrs ifa;
struct ifaddrs_storage *hash_next;
union sockany addr, netmask, ifu;
unsigned int index;
char name[IFNAMSIZ+1];
};
struct ifaddrs_ctx {
struct ifaddrs *first;
struct ifaddrs *last;
struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE];
};
void freeifaddrs(struct ifaddrs *ifp)
{
struct ifaddrs *n;
while (ifp) {
n = ifp->ifa_next;
free(ifp);
ifp = n;
}
}
static void copy_addr(struct sockaddr **r, int af, union sockany *sa, void *addr, size_t addrlen, int ifindex)
{
uint8_t *dst;
int len;
switch (af) {
case AF_INET:
dst = (uint8_t*) &sa->v4.sin_addr;
len = 4;
break;
case AF_INET6:
dst = (uint8_t*) &sa->v6.sin6_addr;
len = 16;
if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr))
sa->v6.sin6_scope_id = ifindex;
break;
default:
return;
}
if (addrlen < len) return;
sa->sa.sa_family = af;
memcpy(dst, addr, len);
*r = &sa->sa;
}
static void gen_netmask(struct sockaddr **r, int af, union sockany *sa, int prefixlen)
{
uint8_t addr[16] = {0};
int i;
if (prefixlen > 8*sizeof(addr)) prefixlen = 8*sizeof(addr);
i = prefixlen / 8;
memset(addr, 0xff, i);
if (i < sizeof(addr)) addr[i++] = 0xff << (8 - (prefixlen % 8));
copy_addr(r, af, sa, addr, sizeof(addr), 0);
}
static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, size_t addrlen, int ifindex, unsigned short hatype)
{
if (addrlen > sizeof(sa->ll.sll_addr)) return;
sa->ll.sll_family = AF_PACKET;
sa->ll.sll_ifindex = ifindex;
sa->ll.sll_hatype = hatype;
sa->ll.sll_halen = addrlen;
memcpy(sa->ll.sll_addr, addr, addrlen);
*r = &sa->sa;
}
static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h)
{
struct ifaddrs_ctx *ctx = pctx;
struct ifaddrs_storage *ifs, *ifs0;
struct ifinfomsg *ifi = NLMSG_DATA(h);
struct ifaddrmsg *ifa = NLMSG_DATA(h);
struct rtattr *rta;
int stats_len = 0;
if (h->nlmsg_type == RTM_NEWLINK) {
for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
if (rta->rta_type != IFLA_STATS) continue;
stats_len = RTA_DATALEN(rta);
break;
}
} else {
for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; ifs0 = ifs0->hash_next)
if (ifs0->index == ifa->ifa_index)
break;
if (!ifs0) return 0;
}
ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len);
if (ifs == 0) return -1;
if (h->nlmsg_type == RTM_NEWLINK) {
ifs->index = ifi->ifi_index;
ifs->ifa.ifa_flags = ifi->ifi_flags;
for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
switch (rta->rta_type) {
case IFLA_IFNAME:
if (RTA_DATALEN(rta) < sizeof(ifs->name)) {
memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta));
ifs->ifa.ifa_name = ifs->name;
}
break;
case IFLA_ADDRESS:
copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type);
break;
case IFLA_BROADCAST:
copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type);
break;
case IFLA_STATS:
ifs->ifa.ifa_data = (void*)(ifs+1);
memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta));
break;
}
}
if (ifs->ifa.ifa_name) {
unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE;
ifs->hash_next = ctx->hash[bucket];
ctx->hash[bucket] = ifs;
}
} else {
ifs->ifa.ifa_name = ifs0->ifa.ifa_name;
ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags;
for (rta = NLMSG_RTA(h, sizeof(*ifa)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
switch (rta->rta_type) {
case IFA_ADDRESS:
/* If ifa_addr is already set we, received an IFA_LOCAL before
* so treat this as destination address */
if (ifs->ifa.ifa_addr)
copy_addr(&ifs->ifa.ifa_dstaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
else
copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
break;
case IFA_BROADCAST:
copy_addr(&ifs->ifa.ifa_broadaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
break;
case IFA_LOCAL:
/* If ifa_addr is set and we get IFA_LOCAL, assume we have
* a point-to-point network. Move address to correct field. */
if (ifs->ifa.ifa_addr) {
ifs->ifu = ifs->addr;
ifs->ifa.ifa_dstaddr = &ifs->ifu.sa;
memset(&ifs->addr, 0, sizeof(ifs->addr));
}
copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
break;
case IFA_LABEL:
if (RTA_DATALEN(rta) < sizeof(ifs->name)) {
memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta));
ifs->ifa.ifa_name = ifs->name;
}
break;
}
}
if (ifs->ifa.ifa_addr)
gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen);
}
if (ifs->ifa.ifa_name) {
if (!ctx->first) ctx->first = &ifs->ifa;
if (ctx->last) ctx->last->ifa_next = &ifs->ifa;
ctx->last = &ifs->ifa;
} else {
free(ifs);
}
return 0;
}
int getifaddrs(struct ifaddrs **ifap)
{
struct ifaddrs_ctx _ctx, *ctx = &_ctx;
int r;
memset(ctx, 0, sizeof *ctx);
r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx);
if (r == 0) *ifap = ctx->first;
else freeifaddrs(ctx->first);
return r;
}

8
nfq2/andr/ifaddrs.h Normal file
View File

@@ -0,0 +1,8 @@
#pragma once
#include <ifaddrs.h>
#if __ANDROID_API__ < 24
void freeifaddrs(struct ifaddrs *);
int getifaddrs(struct ifaddrs **);
#endif

54
nfq2/andr/netlink.c Normal file
View File

@@ -0,0 +1,54 @@
#include <errno.h>
#include <string.h>
#include <syscall.h>
#include <sys/socket.h>
#include <unistd.h>
#include "netlink.h"
static int __netlink_enumerate(int fd, unsigned int seq, int type, int af,
int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
{
struct nlmsghdr *h;
union {
uint8_t buf[8192];
struct {
struct nlmsghdr nlh;
struct rtgenmsg g;
} req;
struct nlmsghdr reply;
} u;
int r, ret;
memset(&u.req, 0, sizeof(u.req));
u.req.nlh.nlmsg_len = sizeof(u.req);
u.req.nlh.nlmsg_type = type;
u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
u.req.nlh.nlmsg_seq = seq;
u.req.g.rtgen_family = af;
r = send(fd, &u.req, sizeof(u.req), 0);
if (r < 0) return r;
while (1) {
r = recv(fd, u.buf, sizeof(u.buf), 0);
if (r <= 0) return -1;
for (h = &u.reply; NLMSG_OK(h, (void*)&u.buf[r]); h = NLMSG_NEXT(h)) {
if (h->nlmsg_type == NLMSG_DONE) return 0;
if (h->nlmsg_type == NLMSG_ERROR) return -1;
ret = cb(ctx, h);
if (ret) return ret;
}
}
}
int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
{
int fd, r;
fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
if (fd < 0) return -1;
r = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx);
if (!r) r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx);
close(fd);
return r;
}

94
nfq2/andr/netlink.h Normal file
View File

@@ -0,0 +1,94 @@
#include <stdint.h>
/* linux/netlink.h */
#define NETLINK_ROUTE 0
struct nlmsghdr {
uint32_t nlmsg_len;
uint16_t nlmsg_type;
uint16_t nlmsg_flags;
uint32_t nlmsg_seq;
uint32_t nlmsg_pid;
};
#define NLM_F_REQUEST 1
#define NLM_F_MULTI 2
#define NLM_F_ACK 4
#define NLM_F_ROOT 0x100
#define NLM_F_MATCH 0x200
#define NLM_F_ATOMIC 0x400
#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
#define NLMSG_NOOP 0x1
#define NLMSG_ERROR 0x2
#define NLMSG_DONE 0x3
#define NLMSG_OVERRUN 0x4
/* linux/rtnetlink.h */
#define RTM_NEWLINK 16
#define RTM_GETLINK 18
#define RTM_NEWADDR 20
#define RTM_GETADDR 22
struct rtattr {
unsigned short rta_len;
unsigned short rta_type;
};
struct rtgenmsg {
unsigned char rtgen_family;
};
struct ifinfomsg {
unsigned char ifi_family;
unsigned char __ifi_pad;
unsigned short ifi_type;
int ifi_index;
unsigned ifi_flags;
unsigned ifi_change;
};
/* linux/if_link.h */
#define IFLA_ADDRESS 1
#define IFLA_BROADCAST 2
#define IFLA_IFNAME 3
#define IFLA_STATS 7
/* linux/if_addr.h */
struct ifaddrmsg {
uint8_t ifa_family;
uint8_t ifa_prefixlen;
uint8_t ifa_flags;
uint8_t ifa_scope;
uint32_t ifa_index;
};
#define IFA_ADDRESS 1
#define IFA_LOCAL 2
#define IFA_LABEL 3
#define IFA_BROADCAST 4
/* musl */
#define NETLINK_ALIGN(len) (((len)+3) & ~3)
#define NLMSG_DATA(nlh) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)))
#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len-sizeof(struct nlmsghdr))
#define NLMSG_DATAEND(nlh) ((char*)(nlh)+(nlh)->nlmsg_len)
#define NLMSG_NEXT(nlh) (struct nlmsghdr*)((char*)(nlh)+NETLINK_ALIGN((nlh)->nlmsg_len))
#define NLMSG_OK(nlh,end) ((char*)(end)-(char*)(nlh) >= sizeof(struct nlmsghdr))
#define RTA_DATA(rta) ((void*)((char*)(rta)+sizeof(struct rtattr)))
#define RTA_DATALEN(rta) ((rta)->rta_len-sizeof(struct rtattr))
#define RTA_DATAEND(rta) ((char*)(rta)+(rta)->rta_len)
#define RTA_NEXT(rta) (struct rtattr*)((char*)(rta)+NETLINK_ALIGN((rta)->rta_len))
#define RTA_OK(rta,end) ((char*)(end)-(char*)(rta) >= sizeof(struct rtattr))
#define NLMSG_RTA(nlh,len) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)+NETLINK_ALIGN(len)))
#define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh))
int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx);

View File

@@ -95,10 +95,7 @@ static uint16_t do_csum(const uint8_t *buff, size_t len)
return u16;
}
uint16_t csum_partial(const void *buff, size_t len)
{
return do_csum(buff, len);
}
#define csum_partial(buff, len) do_csum((const uint8_t*)buff,len)
uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t proto, uint16_t sum)
{
@@ -107,7 +104,7 @@ uint16_t csum_tcpudp_magic(uint32_t saddr, uint32_t daddr, size_t len, uint8_t p
uint16_t ip4_compute_csum(const void *buff, size_t len)
{
return ~from64to16(do_csum(buff, len));
return ~csum_partial(buff, len);
}
void ip4_fix_checksum(struct ip *ip)
{
@@ -158,3 +155,21 @@ void udp_fix_checksum(struct udphdr *udp, size_t len, const struct ip *ip, const
else if (ip6hdr)
udp6_fix_checksum(udp, len, &ip6hdr->ip6_src, &ip6hdr->ip6_dst);
}
void icmp4_fix_checksum(struct icmp46 *icmp, size_t len)
{
icmp->icmp_cksum = 0;
icmp->icmp_cksum = ~csum_partial(icmp, len);
}
void icmp6_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr)
{
icmp->icmp_cksum = 0;
icmp->icmp_cksum = csum_ipv6_magic(&ip6hdr->ip6_src, &ip6hdr->ip6_dst, len, IPPROTO_ICMPV6, csum_partial(icmp, len));
}
void icmp_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr)
{
if (ip6hdr)
icmp6_fix_checksum(icmp, len, ip6hdr);
else
icmp4_fix_checksum(icmp, len);
}

View File

@@ -11,7 +11,20 @@
#include <netinet/tcp.h>
#include <netinet/udp.h>
uint16_t csum_partial(const void *buff, size_t len);
// icmp 4 and 6 are basically compatible although checksums are calculated differently
// do not use version specific structs
struct icmp46
{
uint8_t icmp_type, icmp_code;
uint16_t icmp_cksum;
union
{
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);
uint16_t csum_ipv6_magic(const void *saddr, const void *daddr, size_t len, uint8_t proto, uint16_t sum);
@@ -25,3 +38,7 @@ void tcp_fix_checksum(struct tcphdr *tcp,size_t len,const struct ip *ip,const st
void udp4_fix_checksum(struct udphdr *udp,size_t len, const struct in_addr *src_addr, const struct in_addr *dest_addr);
void udp6_fix_checksum(struct udphdr *udp,size_t len, const struct in6_addr *src_addr, const struct in6_addr *dest_addr);
void udp_fix_checksum(struct udphdr *udp,size_t len,const struct ip *ip,const struct ip6_hdr *ip6hdr);
void icmp4_fix_checksum(struct icmp46 *icmp, size_t len);
void icmp6_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr);
void icmp_fix_checksum(struct icmp46 *icmp, size_t len, const struct ip6_hdr *ip6hdr);

View File

@@ -1,3 +1,4 @@
#define _GNU_SOURCE
#include "conntrack.h"
#include "darkmagic.h"
#include <arpa/inet.h>
@@ -66,11 +67,11 @@ void ConntrackPoolInit(t_conntrack *p, time_t purge_interval, uint32_t timeout_s
p->timeout_fin = timeout_fin;
p->timeout_udp = timeout_udp;
p->t_purge_interval = purge_interval;
time(&p->t_last_purge);
p->t_last_purge = boottime();
p->pool = NULL;
}
void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis)
bool ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis)
{
memset(c, 0, sizeof(*c));
if (dis->ip)
@@ -86,8 +87,9 @@ void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis)
c->src.ip6 = bReverse ? dis->ip6->ip6_dst : dis->ip6->ip6_src;
}
else
c->l3proto = -1;
return false;
extract_ports(dis->tcp, dis->udp, &c->l4proto, bReverse ? &c->dport : &c->sport, bReverse ? &c->sport : &c->dport);
return c->l4proto!=IPPROTO_NONE;
}
@@ -102,7 +104,7 @@ static void ConntrackInitTrack(t_ctrack *t)
{
memset(t, 0, sizeof(*t));
t->l7proto = L7_UNKNOWN;
t->pos.client.scale = t->pos.server.scale = SCALE_NONE;
t->pos.client.scale = t->pos.server.scale = 0;
rawpacket_queue_init(&t->delayed);
lua_newtable(params.L);
t->lua_state = luaL_ref(params.L, LUA_REGISTRYINDEX);
@@ -138,8 +140,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 = ntohs(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;
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;
@@ -152,11 +163,6 @@ static void ConntrackApplyPos(t_ctrack *t, bool bReverse, const struct dissect *
if (!((direct->pos - direct->uppos) & 0x80000000))
direct->uppos = direct->pos;
}
direct->winsize = ntohs(dis->tcp->th_win);
direct->winsize_calc = direct->winsize;
if (direct->scale != SCALE_NONE) direct->winsize_calc <<= direct->scale;
if (mss && !direct->mss) direct->mss = mss;
if (scale != SCALE_NONE) direct->scale = scale;
if (!direct->rseq_over_2G && ((direct->seq_last - direct->seq0) & 0x80000000))
direct->rseq_over_2G = true;
@@ -166,9 +172,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++;
@@ -215,7 +218,7 @@ static void ConntrackFeedPacket(t_ctrack *t, bool bReverse, const struct dissect
ConntrackApplyPos(t, bReverse, dis);
}
clock_gettime(CLOCK_REALTIME, &t->pos.t_last);
clock_gettime(CLOCK_BOOT_OR_UPTIME, &t->pos.t_last);
// make sure t_start gets exactly the same value as first t_last
if (!t->t_start.tv_sec) t->t_start = t->pos.t_last;
}
@@ -225,7 +228,7 @@ static bool ConntrackPoolDoubleSearchPool(t_conntrack_pool **pp, const struct di
t_conn conn, connswp;
t_conntrack_pool *ctr;
ConntrackExtractConn(&conn, false, dis);
if (!ConntrackExtractConn(&conn, false, dis)) return false;
if ((ctr = ConntrackPoolSearch(*pp, &conn)))
{
if (bReverse) *bReverse = false;
@@ -256,7 +259,7 @@ static bool ConntrackPoolFeedPool(t_conntrack_pool **pp, const struct dissect *d
bool b_rev;
uint8_t proto = dis->tcp ? IPPROTO_TCP : dis->udp ? IPPROTO_UDP : IPPROTO_NONE;
ConntrackExtractConn(&conn, false, dis);
if (!ConntrackExtractConn(&conn, false, dis)) return false;
if ((ctr = ConntrackPoolSearch(*pp, &conn)))
{
ConntrackFeedPacket(&ctr->track, (b_rev = false), dis);
@@ -282,7 +285,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;
@@ -296,7 +299,7 @@ static bool ConntrackPoolDropPool(t_conntrack_pool **pp, const struct dissect *d
{
t_conn conn, connswp;
t_conntrack_pool *t;
ConntrackExtractConn(&conn, false, dis);
if (!ConntrackExtractConn(&conn, false, dis)) return false;
if (!(t = ConntrackPoolSearch(*pp, &conn)))
{
connswap(&conn, &connswp);
@@ -314,14 +317,14 @@ bool ConntrackPoolDrop(t_conntrack *p, const struct dissect *dis)
void ConntrackPoolPurge(t_conntrack *p)
{
time_t tidle;
struct timespec tnow;
time_t tnow;
t_conntrack_pool *t, *tmp;
if (clock_gettime(CLOCK_REALTIME, &tnow)) return;
if ((tnow.tv_sec - p->t_last_purge) >= p->t_purge_interval)
if (!(tnow=boottime())) return;
if ((tnow - p->t_last_purge) >= p->t_purge_interval)
{
HASH_ITER(hh, p->pool, t, tmp) {
tidle = tnow.tv_sec - t->track.pos.t_last.tv_sec;
tidle = tnow - t->track.pos.t_last.tv_sec;
if (t->track.b_cutoff ||
(t->conn.l4proto == IPPROTO_TCP && (
(t->track.pos.state == SYN && tidle >= p->timeout_syn) ||
@@ -333,7 +336,7 @@ void ConntrackPoolPurge(t_conntrack *p)
HASH_DEL(p->pool, t); ConntrackFreeElem(t);
}
}
p->t_last_purge = tnow.tv_sec;
p->t_last_purge = tnow;
}
}
@@ -345,18 +348,18 @@ static void taddr2str(uint8_t l3proto, const t_addr *a, char *buf, size_t bufsiz
void ConntrackPoolDump(const t_conntrack *p)
{
t_conntrack_pool *t, *tmp;
struct timespec tnow;
char sa1[40], sa2[40];
time_t tnow;
char sa1[INET6_ADDRSTRLEN], sa2[INET6_ADDRSTRLEN];
if (clock_gettime(CLOCK_REALTIME, &tnow)) return;
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] : "-",
(unsigned long long)t->track.t_start.tv_sec, (unsigned long long)(t->track.pos.t_last.tv_sec - t->track.t_start.tv_sec), (unsigned long long)(tnow.tv_sec - t->track.pos.t_last.tv_sec),
(unsigned long long)t->track.t_start.tv_sec, (unsigned long long)(t->track.pos.t_last.tv_sec - t->track.t_start.tv_sec), (unsigned long long)(tnow - t->track.pos.t_last.tv_sec),
(unsigned long long)t->track.pos.client.pdcounter, (unsigned long long)t->track.pos.client.pcounter, (unsigned long long)t->track.pos.client.pbcounter,
(unsigned long long)t->track.pos.server.pdcounter, (unsigned long long)t->track.pos.server.pcounter, (unsigned long long)t->track.pos.server.pbcounter);
if (t->conn.l4proto == IPPROTO_TCP)
@@ -364,14 +367,14 @@ 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,
t->track.pos.server.seq_last, t->track.pos.server.pos);
printf(" req_retrans=%u cutoff=%u lua_in_cutoff=%u lua_out_cutoff=%u hostname=%s l7proto=%s\n",
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_lua_in_cutoff, t->track.b_lua_out_cutoff, t->track.hostname, l7proto_str(t->track.l7proto));
t->track.req_retrans_counter, t->track.b_cutoff, t->track.b_lua_in_cutoff, t->track.b_lua_out_cutoff, t->track.hostname ? t->track.hostname : "", l7proto_str(t->track.l7proto));
};
}
@@ -418,7 +421,7 @@ bool ReasmFeed(t_reassemble *reasm, uint32_t seq, const void *payload, size_t le
if ((reasm->size_present - neg_overlap + szcopy) > reasm->size)
return false; // buffer overflow
// in case of seq overlap new data replaces old - unix behavior
memcpy(reasm->packet + reasm->size_present - neg_overlap, payload + szignore, szcopy);
memcpy(reasm->packet + reasm->size_present - neg_overlap, (const uint8_t*)payload + szignore, szcopy);
if (szcopy>neg_overlap)
{
reasm->size_present += szcopy - neg_overlap;

View File

@@ -53,7 +53,6 @@ typedef struct {
typedef struct
{
bool bCheckDone, bCheckResult, bCheckExcluded; // hostlist check result cache
uint8_t ipproto;
struct timespec t_start;
@@ -105,7 +104,7 @@ bool ConntrackPoolFeed(t_conntrack *p, const struct dissect *dis, t_ctrack **ctr
// do not create, do not update. only find existing
bool ConntrackPoolDoubleSearch(t_conntrack *p, const struct dissect *dis, t_ctrack **ctrack, bool *bReverse);
bool ConntrackPoolDrop(t_conntrack *p, const struct dissect *dis);
void ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis);
bool ConntrackExtractConn(t_conn *c, bool bReverse, const struct dissect *dis);
void ConntrackPoolDump(const t_conntrack *p);
void ConntrackPoolPurge(t_conntrack *p);
void ConntrackClearHostname(t_ctrack *track);

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;

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;
}
/******************************************************************************

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

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);
}
/*
@@ -103,9 +103,6 @@ int hkdfExtract(SHAversion whichSha,
salt_len = USHAHashSize(whichSha);
memset(nullSalt, '\0', salt_len);
}
else if (salt_len < 0) {
return shaBadParam;
}
return hmac(whichSha, ikm, ikm_len, salt, salt_len, prk);
}
@@ -149,16 +146,13 @@ 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 *)"";
info_len = 0;
}
else if (info_len < 0) {
return shaBadParam;
}
if (okm_len <= 0) return shaBadParam;
if (!okm) return shaBadParam;
if (!okm || !okm_len) return shaBadParam;
hash_len = USHAHashSize(whichSha);
if (prk_len < hash_len) return shaBadParam;
@@ -171,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;
@@ -328,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;
}

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;

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

File diff suppressed because it is too large Load Diff

View File

@@ -25,6 +25,11 @@
#ifdef __CYGWIN__
#define INITGUID
#include "windivert/windivert.h"
#include "netinet/icmp6.h"
#include "netinet/ip_icmp.h"
#else
#include <netinet/icmp6.h>
#include <netinet/ip_icmp.h>
#endif
#ifndef IPPROTO_DIVERT
@@ -58,10 +63,38 @@
#ifndef IPPROTO_SHIM6
#define IPPROTO_SHIM6 140
#endif
#ifndef IPPROTO_SCTP
#define IPPROTO_SCTP 132
#endif
#ifndef ICMP_DEST_UNREACH
#define ICMP_DEST_UNREACH 3
#endif
#ifndef ICMP_TIME_EXCEEDED
#define ICMP_TIME_EXCEEDED 11
#endif
#ifndef ICMP_PARAMETERPROB
#define ICMP_PARAMETERPROB 12
#endif
#ifndef ICMP_TIMESTAMP
#define ICMP_TIMESTAMP 13
#endif
#ifndef ICMP_TIMESTAMPREPLY
#define ICMP_TIMESTAMPREPLY 14
#endif
#ifndef ICMP_INFO_REQUEST
#define ICMP_INFO_REQUEST 15
#endif
#ifndef ICMP_INFO_REPLY
#define ICMP_INFO_REPLY 16
#endif
#ifndef MLD_LISTENER_REDUCTION
#define MLD_LISTENER_REDUCTION 132
#endif
// 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)
@@ -69,8 +102,10 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
#define VERDICT_MODIFY 1
#define VERDICT_DROP 2
#define VERDICT_MASK 3
#define VERDICT_NOCSUM 4
#define VERDICT_MASK_VALID 7
#define VERDICT_PRESERVE_NEXT 4
#define VERDICT_MASK_VALID_LUA (VERDICT_MASK|VERDICT_PRESERVE_NEXT)
#define VERDICT_NOCSUM 8
#define VERDICT_MASK_VALID 15
#define IP4_TOS(ip_header) (ip_header ? ip_header->ip_tos : 0)
#define IP4_IP_ID(ip_header) (ip_header ? ip_header->ip_id : 0)
@@ -80,14 +115,11 @@ void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uin
void extract_endpoints(const struct ip *ip,const struct ip6_hdr *ip6hdr,const struct tcphdr *tcphdr,const struct udphdr *udphdr, struct sockaddr_storage *src, struct sockaddr_storage *dst);
bool extract_dst(const uint8_t *data, size_t len, struct sockaddr* dst);
uint8_t *tcp_find_option(struct tcphdr *tcp, uint8_t kind);
uint32_t *tcp_find_timestamps(struct tcphdr *tcp);
uint8_t tcp_find_scale_factor(const struct tcphdr *tcp);
uint16_t tcp_find_mss(const struct tcphdr *tcp);
bool tcp_synack_segment(const struct tcphdr *tcphdr);
bool tcp_syn_segment(const struct tcphdr *tcphdr);
bool ip_has_df(const struct ip *ip);
bool make_writeable_dir();
bool ensure_file_access(const char *filename);
@@ -98,12 +130,12 @@ 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_deinit(void);
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);
bool windivert_recv(uint8_t *packet, size_t *len, WINDIVERT_ADDRESS *wa, unsigned int *wa_count);
bool windivert_send(const uint8_t *packet, size_t len, const WINDIVERT_ADDRESS *wa);
#else
#define ensure_dir_access(dir) ensure_file_access(dir)
@@ -125,27 +157,37 @@ int socket_divert(sa_family_t family);
#endif
const char *proto_name(uint8_t proto);
void str_proto_name(char *s, size_t s_len, uint8_t proto);
const char *icmp_type_name(bool v6, uint8_t type);
void str_icmp_type_name(char *s, size_t s_len, bool v6, uint8_t type);
uint16_t family_from_proto(uint8_t l3proto);
void print_ip(const struct ip *ip);
void print_ip6hdr(const struct ip6_hdr *ip6hdr, uint8_t proto);
void print_tcphdr(const struct tcphdr *tcphdr);
void print_udphdr(const struct udphdr *udphdr);
void print_icmphdr(const struct icmp46 *icmp, bool v6);
void str_ip(char *s, size_t s_len, const struct ip *ip);
void str_ip6hdr(char *s, size_t s_len, const struct ip6_hdr *ip6hdr, uint8_t proto);
void str_srcdst_ip6(char *s, size_t s_len, const void *saddr,const void *daddr);
void str_tcphdr(char *s, size_t s_len, const struct tcphdr *tcphdr);
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);
void proto_skip_ipv6(const uint8_t **data, size_t *len, uint8_t *proto_type, const uint8_t **last_header_type);
bool proto_set_last_ip6_proto(struct ip6_hdr *ip6, size_t len, uint8_t proto);
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, 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);
bool proto_check_udp(const uint8_t *data, size_t len);
bool proto_check_udp_payload(const uint8_t *data, size_t len);
void proto_skip_udp(const uint8_t **data, size_t *len);
bool proto_check_icmp(const uint8_t *data, size_t len);
void proto_skip_icmp(const uint8_t **data, size_t *len);
struct dissect
{
const uint8_t *data_pkt;
@@ -156,19 +198,26 @@ struct dissect
uint8_t proto;
const struct tcphdr *tcp;
const struct udphdr *udp;
const struct icmp46 *icmp;
size_t len_l4;
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);
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);
void reverse_tcp(struct tcphdr *tcp);
uint8_t ttl46(const struct ip *ip, const struct ip6_hdr *ip6);
bool get_source_ip4(const struct in_addr *target, struct in_addr *source);
bool get_source_ip6(const struct in6_addr *target, struct in6_addr *source);
void verdict_tcp_csum_fix(uint8_t verdict, struct tcphdr *tcphdr, size_t transport_len, const struct ip *ip, const struct ip6_hdr *ip6hdr);
void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transport_len, const struct ip *ip, const struct ip6_hdr *ip6hdr);
void verdict_icmp_csum_fix(uint8_t verdict, struct icmp46 *icmphdr, size_t transport_len, const struct ip6_hdr *ip6hdr);
void dbgprint_socket_buffers(int fd);
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);

File diff suppressed because it is too large Load Diff

237
nfq2/filter.c Normal file
View File

@@ -0,0 +1,237 @@
#include "filter.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <arpa/inet.h>
#include <sys/socket.h>
bool pf_match(uint16_t port, const port_filter *pf)
{
return port && (((!pf->from && !pf->to) || (port>=pf->from && port<=pf->to)) ^ pf->neg);
}
bool pf_parse(const char *s, port_filter *pf)
{
unsigned int v1,v2;
char c;
if (!s) return false;
if (*s=='*' && s[1]==0)
{
pf->from=1; pf->to=0xFFFF;
pf->neg=false;
return true;
}
if (*s=='~')
{
pf->neg=true;
s++;
}
else
pf->neg=false;
if (sscanf(s,"%u-%u%c",&v1,&v2,&c)==2)
{
if (v1>65535 || v2>65535 || v1>v2) return false;
pf->from=(uint16_t)v1;
pf->to=(uint16_t)v2;
}
else if (sscanf(s,"%u%c",&v1,&c)==1)
{
if (v1>65535) return false;
pf->to=pf->from=(uint16_t)v1;
}
else
return false;
// deny all case
if (!pf->from && !pf->to) pf->neg=true;
return true;
}
static bool fltmode_parse(const char *s, uint8_t *mode)
{
if (*s=='*' && !s[1])
{
*mode = FLTMODE_ANY;
return true;
}
else if (*s=='-' && !s[1])
{
*mode = FLTMODE_SKIP;
return true;
}
*mode = FLTMODE_SKIP;
return false;
}
bool icf_match(uint8_t type, uint8_t code, const icmp_filter *icf)
{
return icf->mode==FLTMODE_ANY || icf->mode==FLTMODE_FILTER && icf->type==type && (!icf->code_valid || icf->code==code);
}
bool icf_parse(const char *s, icmp_filter *icf)
{
unsigned int u1,u2;
char c1,c2;
icf->type = icf->code = 0;
icf->code_valid = false;
if (fltmode_parse(s, &icf->mode)) return true;
switch(sscanf(s,"%u%c%u%c",&u1,&c1,&u2,&c2))
{
case 1:
if (u1>0xFF) return false;
icf->type = (uint8_t)u1;
icf->mode = FLTMODE_FILTER;
break;
case 3:
if (c1!=':' || (u1>0xFF) || (u2>0xFF)) return false;
icf->type = (uint8_t)u1;
icf->code = (uint8_t)u2;
icf->code_valid = true;
icf->mode = FLTMODE_FILTER;
break;
default:
icf->mode = FLTMODE_SKIP;
return false;
}
return true;
}
bool ipp_match(uint8_t proto, const ipp_filter *ipp)
{
return ipp->mode==FLTMODE_ANY || ipp->mode==FLTMODE_FILTER && ipp->proto==proto;
}
bool ipp_parse(const char *s, ipp_filter *ipp)
{
unsigned int u1;
char c;
ipp->proto = 0xFF;
if (fltmode_parse(s, &ipp->mode)) return true;
if (sscanf(s,"%u%c",&u1,&c)!=1 || u1>0xFF) return false;
ipp->proto = (uint8_t)u1;
ipp->mode = FLTMODE_FILTER;
return true;
}
bool packet_pos_parse(const char *s, struct packet_pos *pos)
{
if (*s!='n' && *s!='d' && *s!='s' && *s!='p' && *s!='b' && *s!='x' && *s!='a') return false;
pos->mode=*s;
if (pos->mode=='x' || pos->mode=='a')
{
pos->pos=0;
return true;
}
return sscanf(s+1,"%u",&pos->pos)==1;
}
bool packet_range_parse(const char *s, struct packet_range *range)
{
const char *p;
range->upper_cutoff = false;
if (*s=='-' || *s=='<')
{
range->from = PACKET_POS_ALWAYS;
range->upper_cutoff = *s=='<';
}
else
{
if (!packet_pos_parse(s,&range->from)) return false;
if (range->from.mode=='x')
{
range->to = range->from;
return true;
}
if (!(p = strchr(s,'-')))
p = strchr(s,'<');
if (p)
{
s = p;
range->upper_cutoff = *s=='<';
}
else
{
if (range->from.mode=='a')
{
range->to = range->from;
return true;
}
return false;
}
}
s++;
if (*s)
{
return packet_pos_parse(s,&range->to);
}
else
{
range->to = PACKET_POS_ALWAYS;
return true;
}
}
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr)
{
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[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[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[INET6_ADDRSTRLEN+4];
str_cidr6(s,sizeof(s),cidr);
printf("%s",s);
}
bool parse_cidr4(char *s, struct cidr4 *cidr)
{
char *p,d;
bool b;
unsigned int plen;
if ((p = strchr(s, '/')))
{
if (sscanf(p + 1, "%u", &plen)!=1 || plen>32)
return false;
cidr->preflen = (uint8_t)plen;
d=*p; *p=0; // backup char
}
else
cidr->preflen = 32;
b = (inet_pton(AF_INET, s, &cidr->addr)==1);
if (p) *p=d; // restore char
return b;
}
bool parse_cidr6(char *s, struct cidr6 *cidr)
{
char *p,d;
bool b;
unsigned int plen;
if ((p = strchr(s, '/')))
{
if (sscanf(p + 1, "%u", &plen)!=1 || plen>128)
return false;
cidr->preflen = (uint8_t)plen;
d=*p; *p=0; // backup char
}
else
cidr->preflen = 128;
b = (inet_pton(AF_INET6, s, &cidr->addr)==1);
if (p) *p=d; // restore char
return b;
}

64
nfq2/filter.h Normal file
View File

@@ -0,0 +1,64 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <netinet/in.h>
typedef struct
{
uint16_t from,to;
bool neg;
} port_filter;
bool pf_match(uint16_t port, const port_filter *pf);
bool pf_parse(const char *s, port_filter *pf);
#define FLTMODE_SKIP 0
#define FLTMODE_ANY 1
#define FLTMODE_FILTER 2
typedef struct
{
uint8_t mode, type, code;
bool code_valid;
} icmp_filter;
bool icf_match(uint8_t type, uint8_t code, const icmp_filter *icf);
bool icf_parse(const char *s, icmp_filter *icf);
typedef struct
{
uint8_t mode, proto;
} ipp_filter;
bool ipp_match(uint8_t proto, const ipp_filter *ipp);
bool ipp_parse(const char *s, ipp_filter *ipp);
struct packet_pos
{
char mode; // n - packets, d - data packets, s - relative sequence
unsigned int pos;
};
struct packet_range
{
struct packet_pos from, to;
bool upper_cutoff; // true - do not include upper limit, false - include upper limit
};
#define PACKET_POS_NEVER (struct packet_pos){'x',0}
#define PACKET_POS_ALWAYS (struct packet_pos){'a',0}
#define PACKET_RANGE_NEVER (struct packet_range){PACKET_POS_NEVER,PACKET_POS_NEVER}
#define PACKET_RANGE_ALWAYS (struct packet_range){PACKET_POS_ALWAYS,PACKET_POS_ALWAYS}
bool packet_range_parse(const char *s, struct packet_range *range);
struct cidr4
{
struct in_addr addr;
uint8_t preflen;
};
struct cidr6
{
struct in6_addr addr;
uint8_t preflen;
};
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr);
void print_cidr4(const struct cidr4 *cidr);
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr);
void print_cidr6(const struct cidr6 *cidr);
bool parse_cidr4(char *s, struct cidr4 *cidr);
bool parse_cidr6(char *s, struct cidr6 *cidr);

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,15 +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) break;
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)
{
@@ -48,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);

File diff suppressed because it is too large Load Diff

View File

@@ -9,6 +9,7 @@
#include <stdint.h>
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#define UNARY_PLUS(v) (v>0 ? "+" : "")
@@ -28,12 +29,15 @@ void qsort_ssize_t(ssize_t *array, int ct);
int str_index(const char **strs, int count, const char *str);
void rtrim(char *s);
void replace_char(char *s, char from, char to);
char *strncasestr(const char *s,const char *find, size_t slen);
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 load_file_nonempty(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);
@@ -45,8 +49,6 @@ void print_sockaddr(const struct sockaddr *sa);
void ntopa46(const struct in_addr *ip, const struct in6_addr *ip6,char *str, size_t len);
void ntop46(const struct sockaddr *sa, char *str, size_t len);
void ntop46_port(const struct sockaddr *sa, char *str, size_t len);
bool pton4_port(const char *s, struct sockaddr_in *sa);
bool pton6_port(const char *s, struct sockaddr_in6 *sa);
uint16_t saport(const struct sockaddr *sa);
bool sa_has_addr(const struct sockaddr *sa);
@@ -66,9 +68,9 @@ void phton48(uint8_t *p, uint64_t v);
uint64_t pntoh64(const uint8_t *p);
void phton64(uint8_t *p, uint64_t v);
uint16_t swap16(uint16_t u);
uint32_t swap24(uint32_t u);
uint64_t swap48(uint64_t u);
uint16_t bswap16(uint16_t u);
uint32_t bswap24(uint32_t u);
uint64_t bswap48(uint64_t u);
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size);
char hex_digit(uint8_t v);
@@ -87,67 +89,39 @@ 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);
typedef struct
{
uint16_t from,to;
bool neg;
} port_filter;
bool pf_in_range(uint16_t port, const port_filter *pf);
bool pf_parse(const char *s, port_filter *pf);
bool pf_is_empty(const port_filter *pf);
struct packet_pos
{
char mode; // n - packets, d - data packets, s - relative sequence
unsigned int pos;
};
struct packet_range
{
struct packet_pos from, to;
bool upper_cutoff; // true - do not include upper limit, false - include upper limit
};
#define PACKET_POS_NEVER (struct packet_pos){'x',0}
#define PACKET_POS_ALWAYS (struct packet_pos){'a',0}
#define PACKET_RANGE_NEVER (struct packet_range){PACKET_POS_NEVER,PACKET_POS_NEVER}
#define PACKET_RANGE_ALWAYS (struct packet_range){PACKET_POS_ALWAYS,PACKET_POS_ALWAYS}
bool packet_range_parse(const char *s, struct packet_range *range);
#if defined(__FreeBSD__) && __FreeBSD_version <= 1200000
int getentropy(void *buf, size_t len);
#endif
void fill_random_bytes(uint8_t *p,size_t sz);
void fill_random_az(uint8_t *p,size_t sz);
void fill_random_az09(uint8_t *p,size_t sz);
bool fill_crypto_random_bytes(uint8_t *p,size_t sz);
void bxor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz);
void band(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz);
void bor(const uint8_t *x1, const uint8_t *x2, uint8_t *result, size_t sz);
void set_console_io_buffering(void);
void close_std(void);
void close_std_and_exit(int code);
bool set_env_exedir(const char *argv0);
struct cidr4
{
struct in_addr addr;
uint8_t preflen;
};
struct cidr6
{
struct in6_addr addr;
uint8_t preflen;
};
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr);
void print_cidr4(const struct cidr4 *cidr);
void str_cidr6(char *s, size_t s_len, const struct cidr6 *cidr);
void print_cidr6(const struct cidr6 *cidr);
bool parse_cidr4(char *s, struct cidr4 *cidr);
bool parse_cidr6(char *s, struct cidr6 *cidr);
bool realpath_any(const char *file, char *pabs);
bool parse_int16(const char *p, int16_t *v);
static inline uint32_t mask_from_preflen(uint32_t preflen)
{
return preflen ? preflen<32 ? ~((1 << (32-preflen)) - 1) : 0xFFFFFFFF : 0;
}
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result);
extern struct in6_addr ip6_mask[129];
void mask_from_preflen6_prepare(void);
static inline const struct in6_addr *mask_from_preflen6(uint8_t preflen)
{
return ip6_mask+preflen;
}
#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_MONOTONIC
#endif
time_t boottime(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

View File

@@ -8,13 +8,10 @@ static bool addpool(hostlist_pool **hostlist, char **s, const char *end, int *ct
{
char *p=*s;
// comment line
if ( *p == '#' || *p == ';' || *p == '/' || *p == '\r' || *p == '\n')
{
// advance until eol
for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
}
else
for (; p<end && (*p==' ' || *p=='\t') ; p++);
*s = p;
// comment line ?
if (p<end && *p != '#' && *p != ';' && *p != '/' && *p != '\r' && *p != '\n')
{
// advance until eol lowering all chars
uint32_t flags = 0;
@@ -23,7 +20,7 @@ static bool addpool(hostlist_pool **hostlist, char **s, const char *end, int *ct
p = ++(*s);
flags |= HOSTLIST_POOL_FLAG_STRICT_MATCH;
}
for (; p<end && *p && *p!='\r' && *p != '\n'; p++) *p=tolower(*p);
for (; p<end && *p && *p!=' ' && *p!='\t' && *p!='\r' && *p != '\n'; p++) *p=tolower((unsigned char)*p);
if (!HostlistPoolAddStrLen(hostlist, *s, p-*s, flags))
{
HostlistPoolDestroy(hostlist);
@@ -32,6 +29,8 @@ static bool addpool(hostlist_pool **hostlist, char **s, const char *end, int *ct
}
if (ct) (*ct)++;
}
// skip remaining non-eol chars
for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
// advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
*s = p;
@@ -45,7 +44,7 @@ bool AppendHostlistItem(hostlist_pool **hostlist, char *s)
bool AppendHostList(hostlist_pool **hostlist, const char *filename)
{
char *p, *e, s[256], *zbuf;
char *p, *e, s[4096], *zbuf;
size_t zsize;
int ct = 0;
FILE *F;
@@ -63,26 +62,29 @@ 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
{
DLOG_ERR("zlib decompression failed : result %d\n",r);
DLOG_ERR("zlib decompression failed : result %d\n", r);
return false;
}
}
@@ -90,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))
@@ -100,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);
}
@@ -116,10 +124,18 @@ static bool LoadHostList(struct hostlist_file *hfile)
{
// stat() error
DLOG_PERROR("file_mod_signature");
DLOG_ERR("cannot access hostlist file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
goto unchanged;
}
if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date
// check if it's readable. do not destroy in-memory copy if not
if (!file_open_test(hfile->filename, O_RDONLY))
{
DLOG_PERROR("file_open_test");
goto unchanged;
}
// 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
HostlistPoolDestroy(&hfile->hostlist);
if (!AppendHostList(&hfile->hostlist, hfile->filename))
{
@@ -129,6 +145,9 @@ static bool LoadHostList(struct hostlist_file *hfile)
hfile->mod_sig=fsig;
}
return true;
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)
{
@@ -266,13 +285,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;
}
@@ -288,13 +309,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))
{
DLOG_ERR("cannot access hostlist file '%s'\n",filename);
return NULL;
}
*/
return RegisterHostlist_(
&params.hostlists,
bExclude ? &dp->hl_collection_exclude : &dp->hl_collection,

View File

@@ -4,7 +4,6 @@
#include "helpers.h"
// inplace tolower() and add to pool
static bool addpool(ipset *ips, char **s, const char *end, int *ct)
{
char *p, cidr[128];
@@ -12,40 +11,46 @@ static bool addpool(ipset *ips, char **s, const char *end, int *ct)
struct cidr4 c4;
struct cidr6 c6;
// advance until eol
for (p=*s; p<end && *p && *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;
rtrim(cidr);
// 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
for (; p<end && *p && *p!='\r' && *p != '\n'; p++);
// advance to the next line
for (; p<end && (!*p || *p=='\r' || *p=='\n') ; p++);
*s = p;
@@ -60,7 +65,7 @@ bool AppendIpsetItem(ipset *ips, char *ip)
static bool AppendIpset(ipset *ips, const char *filename)
{
char *p, *e, s[256], *zbuf;
char *p, *e, s[4096], *zbuf;
size_t zsize;
int ct = 0;
FILE *F;
@@ -78,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
{
@@ -105,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))
@@ -115,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);
}
@@ -131,10 +145,18 @@ static bool LoadIpset(struct ipset_file *hfile)
{
// stat() error
DLOG_PERROR("file_mod_signature");
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
goto unchanged;
}
if (FILE_MOD_COMPARE(&hfile->mod_sig,&fsig)) return true; // up to date
// check if it's readable. do not destroy in-memory copy if not
if (!file_open_test(hfile->filename, O_RDONLY))
{
DLOG_PERROR("file_open_test");
goto unchanged;
}
// don't want to keep backup copy in memory - it will require *2 RAM. Problem on low-ram devices. It's better to fail ipset 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
ipsetDestroy(&hfile->ipset);
if (!AppendIpset(&hfile->ipset, hfile->filename))
{
@@ -144,6 +166,9 @@ static bool LoadIpset(struct ipset_file *hfile)
hfile->mod_sig=fsig;
}
return true;
unchanged:
DLOG_ERR("cannot access ipset file '%s'. in-memory content remains unchanged.\n",hfile->filename);
return true;
}
static bool LoadIpsets(struct ipset_files_head *list)
{
@@ -166,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)
@@ -205,7 +230,11 @@ bool IpsetsReloadCheckForProfile(const struct desync_profile *dp)
return IpsetsReloadCheck(&dp->ips_collection) && IpsetsReloadCheck(&dp->ips_collection_exclude);
}
static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ipset_collection_head *ips_exclude, const struct in_addr *ipv4, const struct in6_addr *ipv6)
static bool IpsetCheck_(
const struct ipset_collection_head *ips, const struct ipset_collection_head *ips_exclude,
const struct in_addr *ipv4, const struct in6_addr *ipv6,
const struct in_addr *ipv4r, const struct in6_addr *ipv6r
)
{
struct ipset_item *item;
@@ -217,6 +246,12 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip
DLOG("[%s] exclude ",item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchIpset(&item->hfile->ipset, ipv4, ipv6))
return false;
if (ipv4r || ipv6r)
{
DLOG("[%s] exclude ",item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchIpset(&item->hfile->ipset, ipv4r, ipv6r))
return false;
}
}
// old behavior compat: all include lists are empty means check passes
if (!ipset_collection_is_empty(ips))
@@ -226,29 +261,41 @@ static bool IpsetCheck_(const struct ipset_collection_head *ips, const struct ip
DLOG("[%s] include ",item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchIpset(&item->hfile->ipset, ipv4, ipv6))
return true;
if (ipv4r || ipv6r)
{
DLOG("[%s] include ",item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchIpset(&item->hfile->ipset, ipv4r, ipv6r))
return true;
}
}
return false;
}
return true;
}
bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6)
bool IpsetCheck(
const struct desync_profile *dp,
const struct in_addr *ipv4, const struct in6_addr *ipv6,
const struct in_addr *ipv4r, const struct in6_addr *ipv6r)
{
if (PROFILE_IPSETS_ABSENT(dp)) return true;
DLOG("* ipset check for profile %u (%s)\n",dp->n,PROFILE_NAME(dp));
return IpsetCheck_(&dp->ips_collection,&dp->ips_collection_exclude,ipv4,ipv6);
return IpsetCheck_(&dp->ips_collection,&dp->ips_collection_exclude,ipv4,ipv6,ipv4r,ipv6r);
}
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;
}

View File

@@ -6,7 +6,10 @@
#include "pools.h"
bool LoadAllIpsets();
bool IpsetCheck(const struct desync_profile *dp, const struct in_addr *ipv4, const struct in6_addr *ipv6);
bool IpsetCheck(
const struct desync_profile *dp,
const struct in_addr *ipv4, const struct in6_addr *ipv6,
const struct in_addr *ipv4r, const struct in6_addr *ipv6r);
struct ipset_file *RegisterIpset(struct desync_profile *dp, bool bExclude, const char *filename);
void IpsetsDebug();
bool AppendIpsetItem(ipset *ips, char *ip);

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

Some files were not shown because too many files have changed in this diff Show More