Compare commits

...
322 Commits
Author SHA1 Message Date
bol-van 87e058624c update docs 2026-07-21 09:17:51 +03:00
bol-van 906665d9a5 nfqws: fix minor compile warning 2026-07-21 09:14:01 +03:00
bol-van f97c22e96f init.d: discord media add port range 2026-07-21 09:10:49 +03:00
bol-van 9fb1f24808 init.d: remove KillMode=none in systemd unit 2026-07-21 09:08:52 +03:00
bol-van 1a1fc38c8e minor static analyzer fixes 2026-06-06 10:09:35 +03:00
bol-van 42a9b8e330 update docs 2026-05-09 08:14:30 +03:00
bol-van 363fbe6943 github: remove sdiv crash on old armv7 2026-03-12 20:55:17 +03:00
bol-van 5cc46a9815 update changes.txt 2026-03-12 14:36:58 +03:00
bol-van ef637c482c github: use 16K page size for android arm64 build 2026-03-05 19:37:57 +03:00
bol-van acccfc75e9 nfqws: backport QUICDefragCrypto 2026-03-05 10:32:26 +03:00
bol-van a92b4a543e nfqws: backport QUICDefragCrypto 2026-03-04 22:49:53 +03:00
bol-van 24e3b53165 github: move arm to armv6 2026-03-01 20:35:00 +03:00
bol-van 63e6215be0 github: use thumb in android armv7 build 2026-03-01 18:32:26 +03:00
bol-van cb382036f4 winws: -Wl,--gc-sections 2026-03-01 14:38:11 +03:00
bol-van 928134ca36 update docs 2026-03-01 14:15:36 +03:00
bol-van e5c3e4c706 optimize binaries size 2026-03-01 14:14:28 +03:00
bol-van 378411443f minor fixes 2026-03-01 09:50:52 +03:00
bol-van 74c5b58a1b AI fixes 2026-02-28 10:10:12 +03:00
bol-van 934903dfdf nfqws: cosmetic 2026-02-27 14:35:38 +03:00
bol-van 6cb394de4d Merge pull request #2096 from a1batross/master
Fix build on e2k
2026-02-26 16:30:36 +03:00
Alibek Omarov 003c540f24 tpws: fix building on e2k 2026-02-26 13:33:30 +00:00
Alibek Omarov 0870120cce nfqws: fix building on e2k 2026-02-26 13:33:08 +00:00
bol-van f0b0d89f02 nfqws: relax stun detector 2026-02-24 10:13:53 +03:00
bol-van a08a358342 nfqws: fix broken wifi ssid update 2026-02-24 10:12:38 +03:00
bol-van 61edd29b7e Revert "nfqws: fix broken wifi ssid update"
This reverts commit 7eb195e533.
2026-02-24 10:11:45 +03:00
bol-van 7eb195e533 nfqws: fix broken wifi ssid update 2026-02-24 10:11:11 +03:00
bol-van 3d567b0ac4 nfqws: optimize nfq buffers 2026-02-22 17:32:49 +03:00
bol-van 53eba046ce nfqws: fix quicv2 recognition 2026-02-19 10:05:09 +03:00
bol-van 5ef01d14a9 nfqws: fixes backport from z2 2026-02-16 12:50:52 +03:00
bol-van 0f0e748adb nfqws2: ensure old toolchains do not break 2026-02-16 12:03:42 +03:00
bol-van e0a2116880 Merge pull request #2083 from k0tran/master
Enable seccomp on loongarch64
2026-02-16 11:44:46 +03:00
Ilya Sorochan 3d12e32ee9 enable seccomp on loongarch64 2026-02-16 11:29:02 +03:00
bol-van be57475eee nfqws: fix possible OOB read 2026-02-06 16:14:04 +03:00
bol-van e59efa39db mdig: minor change 2026-02-05 18:51:47 +03:00
bol-van aa8b96d601 nfqws: some protocol.c fixes 2026-02-04 22:10:00 +03:00
bol-van 2d1858ebae update docs 2026-01-29 13:38:05 +03:00
bol-van 119e243b36 blockcheck: fix missing quic fake escape 2026-01-20 09:36:50 +03:00
bol-van c849e55ef0 ask_list default value fix 2026-01-16 14:18:06 +03:00
bol-van ec55c6f551 install_easy: always write FWTYPE 2026-01-16 12:53:55 +03:00
bol-van 6ca597c89c blockcheck: fix suspicious redirection with URI 2026-01-16 12:46:08 +03:00
bol-van 6ac51a4300 nfqws: fix wrong ipfrag help text 2026-01-16 11:01:54 +03:00
bol-van 76764ad6b0 nfqws: fix breaking tcp if ts fooling is enabled but no timestamps present 2026-01-13 17:58:41 +03:00
bol-van 75d2f1195d AI inspired fixes 2026-01-12 20:37:37 +03:00
bol-van c8cb9faf27 AI inspired fix 2026-01-12 16:51:24 +03:00
bol-van a3ba4baa02 update docs 2026-01-12 10:46:58 +03:00
bol-van 2d19ab82d8 update docs 2026-01-12 10:46:25 +03:00
bol-van a775aa7aaa AI inspired fixes 2026-01-10 19:23:42 +03:00
bol-van 0cdbf089cd AI inspired fixes 2026-01-10 18:54:56 +03:00
bol-van 91c747b4e1 mdig: --eagain, --eagain-delay 2026-01-09 11:43:17 +03:00
bol-van 16ac0587a4 tpws: memleak fix 2026-01-08 18:06:33 +03:00
bol-van cfddd55a6f Merge pull request #2027 from GlazovYuri/master
Fix some mistakes
2026-01-08 07:52:44 +00:00
GlazovYuri 82697e6ebf Fix some mistakes 2026-01-08 02:51:23 +03:00
bol-van 409579512c AI inspired fixes 2026-01-07 13:45:53 +03:00
bol-van 6ac8ed4c3f AI inspired fixes 2026-01-07 13:41:17 +03:00
bol-van 3e35fb9025 nfqws: memleak fix 2026-01-07 13:21:30 +03:00
bol-van b17da98fc4 install_bin: fix and 2026-01-03 00:44:29 +03:00
bol-van 1f46e91342 blockcheck: fix tpws test regression 2026-01-02 22:12:20 +03:00
bol-van d6f929ee5c Merge pull request #2000 from dzokha-true/master
Typo fixes in eng and ru readme
2025-12-28 08:18:32 +00:00
Zhakhangir 6bdec3f87c Typo fixes in eng and ru readme 2025-12-28 08:13:12 +00:00
bol-van 1a6a2b702e BypassESU info 2025-12-27 12:28:06 +03:00
bol-van e95a06c7ee 50-dht4all fixes 2025-12-25 16:15:28 +03:00
bol-van afce40981c ipset: reestr reduce file size limit 2025-12-20 15:26:15 +03:00
bol-van 33720dee60 ipset: remove zapret-info based scripts because it's gone 2025-12-20 15:03:02 +03:00
bol-van 994e9c3488 nfqws: fix missing fclose 2025-12-17 21:55:26 +03:00
bol-van d4cfb6800f remove version from readme 2025-12-17 11:48:48 +03:00
bol-van a36e6ee60e update docs 2025-12-17 11:09:00 +03:00
bol-van 813fe416f8 nfqws: backport from nfqws2 nl80211 ssid discovery fix for newer kernels 2025-12-17 10:59:07 +03:00
bol-van 8e766744b6 nfqws2: fix broken l7proto profile rediscovery 2025-12-17 10:49:06 +03:00
bol-van 0bc0997191 update ver in readme.en 2025-12-12 09:29:08 +03:00
bol-van b056ba95a1 Merge pull request #1944 from Chris-Kyarov/patch-1
Update version from v72.3 to v72.4 in README
2025-12-12 09:27:16 +03:00
Chris bae45abfbf Update version from v72.3 to v72.4 in README 2025-12-12 05:01:03 +09:00
bol-van 21fc356476 blockcheck: fix brokern http3 test 2025-12-07 14:00:14 +03:00
bol-van 88b6b791e9 nfqws: add missing ssid_filter list init 2025-12-04 19:28:58 +03:00
bol-van 48185174cf update changes.txt 2025-12-04 14:56:29 +03:00
bol-van aa8d903bb1 blockcheck: fix broken DNS cache 2025-12-04 14:54:19 +03:00
bol-van cb653bedd6 blockcheck: check existense instead of curl 2025-12-02 08:54:10 +03:00
bol-van 534c88c96a fix 'which' function behavior with absolute paths 2025-12-02 08:53:38 +03:00
bol-van 7be9790839 remove obsolete file 2025-12-01 09:33:15 +03:00
bol-van 14d7f27b6a github: delete windivert filters from embedded build 2025-11-24 20:57:38 +03:00
bol-van 97cefbace9 update .gitattributes 2025-11-21 17:07:44 +03:00
bol-van 43cea80619 nfqws: fix crypto code 2025-11-18 15:14:42 +03:00
bol-van ce7d91a7ca blockcheck: fix broken ip block tests 2025-11-15 00:22:44 +03:00
bol-van 105ac57655 add 100.64.0.0/10 to default exclude 2025-11-11 14:55:38 +03:00
bol-van 06f5305617 nfqws: remove unneeded code 2025-11-11 09:42:48 +03:00
bol-van 45c3f00539 nfqws: do not increase retrans counter every reasm piece 2025-11-11 09:39:59 +03:00
bol-van 0c0c2547db blockcheck: shield curl 2025-11-10 12:48:44 +03:00
bol-van 60d182b97e update en WSL info 2025-11-08 22:12:23 +03:00
bol-van 907b530068 update WSL info 2025-11-08 22:11:15 +03:00
bol-van 8763768180 update WSL info 2025-11-08 22:06:48 +03:00
bol-van 793cd76621 update WSL info 2025-11-08 22:05:21 +03:00
bol-van 9b47b21918 nfqws: ipv6 ah header length is in 32-bit words, not 64-bit 2025-11-08 20:46:09 +03:00
bol-van caa364e0ed blockcheck: fix doh resolve failure if spaces in the path 2025-11-06 22:14:47 +03:00
bol-van 76992dc3d9 nfqws: remove duplicate defines 2025-11-05 17:08:34 +03:00
bol-van 0b8e0dc97d blockcheck: replace ipv6 only ntc.party to ej.ru 2025-10-30 16:19:52 +03:00
bol-van 1408c38522 blockcheck: fix - sign regression 2025-10-28 21:50:46 +03:00
bol-van cea968d259 blockcheck: filter out : 2025-10-28 18:24:32 +03:00
bol-van f91bca170a blockcheck: support URIs, support disabling HEAD for https 2025-10-28 14:45:15 +03:00
bol-van 9d5c9191be Merge pull request #1834 from ooovlad/fix-readme-typo
Fix the annoying typo that got me confused on my attempt to set up
2025-10-27 07:27:40 +03:00
Vlad f4ce79a97c Fix the annoying typo that got me confused when I was trying to set up the program
Please correct this typo in the file name, as it caused me to stumble twice when setting up zapret. I took the file name directly from the readme, and then I found out that it was incorrect. Then after a while I forgot about it and took the file name from the readme again. So I decided to make a pull request.
2025-10-27 00:02:33 +03:00
bol-van 845b9edf85 Merge pull request #1821 from ilyuXer/patch-1
Update readme.md
2025-10-25 08:47:11 +03:00
ilyuXer 5ec5ce8246 Update readme.md 2025-10-24 21:01:01 +03:00
bol-van 29935b0934 update docs 2025-10-17 15:11:08 +03:00
bol-van fe12b55181 update docs 2025-10-17 15:07:10 +03:00
bol-van 2cafc7ddeb nfqws: optimize 2025-10-17 14:35:42 +03:00
bol-van 2daf764760 nfqws: optimize 2025-10-17 14:20:54 +03:00
bol-van 078022bccf nfqws: minor bug 2025-10-17 14:15:36 +03:00
bol-van 57778b6249 nfqws: --dup-ip-id, --*-tcp-flags-*, --wssize-forced-cutoff 2025-10-17 14:10:30 +03:00
bol-van 845f4b43ef remove bad comments from custom scripts 2025-10-13 16:43:52 +03:00
bol-van a485030423 50-quic4all 2025-10-13 16:42:59 +03:00
bol-van 6821093493 50-quic4all 2025-10-13 16:41:49 +03:00
bol-van 0dea2d6ad0 blockcheck: MIN/MAX_AUTOTTL_DELTA 2025-10-13 16:14:19 +03:00
bol-van 16e71fc5fc nfqws: fix --ip-id when changing profiles 2025-10-13 15:52:16 +03:00
bol-van b2795989b7 update docs 2025-10-13 15:29:57 +03:00
bol-van dbfc20a5bc nfqws: ip_id improvements 2025-10-13 14:51:42 +03:00
bol-van 2aa301bf0b update docs 2025-10-13 12:55:04 +03:00
bol-van 324aa12ecf update docs 2025-10-13 12:35:43 +03:00
bol-van af5cf623be update docs 2025-10-13 12:35:07 +03:00
bol-van 9556eff091 update docs 2025-10-13 12:34:41 +03:00
bol-van ca42c88ce0 update docs 2025-10-13 12:33:54 +03:00
bol-van 62cdc8bf13 nfqws: random ip_id not zero 2025-10-12 20:15:52 +03:00
bol-van 643c254fab nfqws: --ip-id 2025-10-12 20:08:08 +03:00
bol-van 3f2ef1feee windivert_part.quic_initial_ietf.txt 2025-10-12 15:23:11 +03:00
bol-van 3c8e4ed15d update docs 2025-10-12 14:35:27 +03:00
bol-van 8c06a6335d update docs 2025-10-12 14:34:49 +03:00
bol-van f12cae3674 update docs 2025-10-12 14:34:21 +03:00
bol-van 170281bfa6 update docs 2025-10-12 14:33:16 +03:00
bol-van 5d4747458f update docs 2025-10-12 14:30:05 +03:00
bol-van 5774e883d6 update docs 2025-10-12 14:19:04 +03:00
bol-van 80b801c1ca nfqws: fix seqovl>=split_pos message 2025-10-10 17:53:14 +03:00
bol-van 9d8ee398c3 Revert "blockcheck: enable ECN in windows"
This reverts commit 4d35d8d1ec.
2025-10-08 16:32:56 +03:00
bol-van 4d35d8d1ec blockcheck: enable ECN in windows 2025-10-07 10:19:02 +03:00
bol-van 977d117417 nfqws: prevent memleak if multiple fakedsplit pattern options 2025-10-04 20:45:24 +03:00
bol-van cc8313db51 nfqws: optimize default fakedsplit pattern 2025-10-04 20:18:39 +03:00
bol-van 1e51f90130 nfqws: fix fakedsplit-pattern if not specified 2025-10-04 19:59:19 +03:00
bol-van da6b89e739 blockcheck: print some OPENWRT_xxx from /etc/os-release 2025-10-04 18:31:48 +03:00
bol-van 90470440a7 blockcheck: print PRETTY_NAME from /etc/os-release 2025-10-04 18:26:07 +03:00
bol-van a5c9d79417 update docs 2025-10-04 11:58:59 +03:00
bol-van c003ef2a7b update docs 2025-10-04 11:58:35 +03:00
bol-van 42541fcab8 update docs 2025-10-04 11:57:53 +03:00
bol-van 20b5952978 update docs 2025-10-04 11:56:07 +03:00
bol-van 4b6aa1b5f9 nfqws: help text for more altorders 2025-10-04 11:43:06 +03:00
bol-van 9e141dcefd update docs 2025-10-04 11:30:38 +03:00
bol-van b1b992eb3f update docs 2025-10-04 11:28:29 +03:00
bol-van 2d061c911a update docs 2025-10-04 11:27:31 +03:00
bol-van a213084188 update docs 2025-10-04 11:26:42 +03:00
bol-van 1c7ec32b96 update docs 2025-10-04 11:26:00 +03:00
bol-van dcd9cfbb2b nfqws: ip_id fixes, more altorder support 2025-10-04 11:02:23 +03:00
bol-van beb0692d28 quick_start: minor change 2025-10-03 10:48:23 +03:00
bol-van 140af2b741 quick_start: remove easy option 2025-10-03 10:47:40 +03:00
bol-van f8cc109f0b nfqws: remove "file containing" from help text 2025-09-24 16:32:48 +03:00
bol-van b4a2f44d56 remove -2b fakes 2025-09-24 16:26:39 +03:00
bol-van 14d05d8012 update docs 2025-09-24 16:25:08 +03:00
bol-van 71d5afeaf4 update docs 2025-09-24 16:24:36 +03:00
bol-van 45df8bfb09 update docs 2025-09-24 16:21:59 +03:00
bol-van 784058cf66 nfqws: support +offset@filename fake/pattern loading 2025-09-24 16:08:25 +03:00
bol-van ce367b1a91 nfqws: optimize ip_id behavior 2025-09-24 10:31:06 +03:00
bol-van a832c19974 blockcheck: test --dpi-desync-fakedsplit-mod=altorder=1 2025-09-23 14:20:23 +03:00
bol-van 2c14109163 update docs 2025-09-23 14:13:39 +03:00
bol-van c467e696e3 nfqws: --dpi-desync-fakedsplit-mod=altorder 2025-09-23 14:06:23 +03:00
bol-van 528c27a01a update docs 2025-09-23 13:16:18 +03:00
bol-van c2f1e708fc blockcheck: test split fake 2025-09-23 12:21:47 +03:00
bol-van 211a4f4673 update docs 2025-09-23 11:54:59 +03:00
bol-van fd81053d79 nfqws: --dpi-desync-fake-tls=!+offset 2025-09-23 11:52:46 +03:00
bol-van 1bb9f260dd -2b tls fakes 2025-09-23 10:52:38 +03:00
bol-van 26f3cbd06f update docs 2025-09-23 10:52:16 +03:00
bol-van e384f88931 nfqws: --dpi-desync-fake-tcp-mod=seq 2025-09-23 10:51:49 +03:00
bol-van 59bce0036b update docs 2025-09-22 17:39:00 +03:00
bol-van 0a48c923b8 update docs 2025-09-22 17:37:58 +03:00
bol-van ed4782887f update docs 2025-09-22 17:37:21 +03:00
bol-van 80b6b75934 blockcheck: test hostfakesplit altorder 2025-09-22 17:18:23 +03:00
bol-van 245ce41550 nfqws: altorder mod for hostfakesplit 2025-09-22 17:06:30 +03:00
bol-van db5dca28b0 nfqws: fix clang warnings 2025-09-22 15:06:52 +03:00
bol-van 6dad239fe3 blockcheck: fix infinite recursion on mac/bsd 2025-09-22 14:58:51 +03:00
bol-van aa4982a526 blockcheck: working strategies intersection print for multiple domains 2025-09-22 14:49:33 +03:00
bol-van 61808b37d8 base.sh quote parameters in replace_char 2025-09-22 13:05:35 +03:00
bol-van 4b90ee920c update docs 2025-09-22 10:11:06 +03:00
bol-van 170e9d7ffd nfqws: --dpi-desync-hostfakesplit-mod 2025-09-22 09:51:25 +03:00
bol-van d8f9ba29c3 update docs 2025-09-21 19:44:31 +03:00
bol-van 4914b813e7 update docs 2025-09-21 19:42:38 +03:00
bol-van c3fdec9bf0 update docs 2025-09-21 18:54:38 +03:00
bol-van 1cbdf9b891 nfqws: hostfakesplit fix use-after-free 2025-09-21 18:36:49 +03:00
bol-van 706dd7b2d9 nfqws: hostfakesplit send second fake 2025-09-21 18:31:09 +03:00
bol-van b2468a9095 blockcheck: change nft postnat hook from output to postrouting to fix some issues 2025-09-21 17:53:50 +03:00
bol-van acfbbc58ac blockcheck: new strategies 2025-09-21 14:54:31 +03:00
bol-van fd506dfe08 nfqws: print sessionID lengths if dupsid cannot be applied 2025-09-21 13:17:52 +03:00
bol-van 1ee25e01ea nfqws: generate random host with a-z at the first position 2025-09-21 12:51:06 +03:00
bol-van 521c385adb nfqws: --dpi-desync=hostfakesplit 2025-09-21 12:32:53 +03:00
bol-van 17971e87b4 update docs 2025-09-20 15:25:37 +03:00
bol-van 4dc1d035d8 update docs 2025-09-20 15:24:32 +03:00
bol-van 07eee8af25 winws: --wf-raw-part 2025-09-20 13:59:54 +03:00
bol-van 06e7818240 quick_start: traditional linux separate link 2025-09-04 10:12:09 +03:00
bol-van 00b0f3c940 quick_start: typo 2025-09-04 10:09:48 +03:00
bol-van 17df2adbe0 quick_start: curl/wget to stdout info 2025-09-04 10:09:01 +03:00
bol-van 40342745f7 quick_start: curl/wget to stdout info 2025-09-04 10:06:42 +03:00
bol-van 54d4cdb2d5 50-dht4all fix space/tabs 2025-09-03 17:19:35 +03:00
bol-van b251ea839c custom scripts increase repeats 2025-09-03 12:24:00 +03:00
bol-van 595cf863fc put old kernel ver note for @ih to customs 2025-09-01 22:00:55 +03:00
bol-van 91d5b90ded install_easy: install iptables-mod-u32 2025-09-01 21:29:00 +03:00
bol-van 33a7132920 50-dht4all move from @th to @ih 2025-09-01 21:25:30 +03:00
bol-van d9b23f14a2 docs works 2025-08-22 19:13:41 +03:00
bol-van 06613b4fd5 docs: windows server note 2025-08-22 19:10:56 +03:00
bol-van 7364bab8a7 docs works 2025-08-22 18:58:29 +03:00
bol-van 1f48453989 docs works 2025-08-22 18:56:28 +03:00
bol-van dc5efebee2 docs works 2025-08-22 18:55:06 +03:00
bol-van 10c9499647 update changes 2025-08-22 18:51:31 +03:00
bol-van a50082df92 readme: hardware details 2025-08-22 18:49:09 +03:00
bol-van 0c33bbfb37 readme.en: 6.17 kernel iptables notice 2025-08-22 18:38:01 +03:00
bol-van ea1be413a6 readme.en: 6.17 kernel iptables notice 2025-08-22 18:37:03 +03:00
bol-van 850d4023fb readme: 6.17 kernel iptables notice 2025-08-22 18:33:08 +03:00
bol-van 4872b8e4e8 doc fix 2025-08-21 17:05:48 +03:00
bol-van 75eaefa950 Merge pull request #1686 from ekungurov/update-readme
doc fix
2025-08-21 17:05:08 +03:00
bol-van 582ade3190 doc fix 2025-08-21 17:00:08 +03:00
Yevgeny Kungurov efd369bb0e doc fix 2025-08-19 18:51:35 +04:00
bol-van 784465bdcf add windivert lang desc link 2025-08-13 10:00:07 +03:00
bol-van 40a80cd328 update changes 2025-08-12 12:41:49 +03:00
bol-van 73f21b0524 discord only ipv4 2025-08-12 12:38:42 +03:00
bol-van 34698479d0 minor improve stun windivert filter 2025-08-12 11:29:27 +03:00
bol-van 0830633f42 windivert: --filter-l7 in readme.txt 2025-08-12 11:00:27 +03:00
bol-van fc837e14fa windivert filter examples 2025-08-12 10:53:45 +03:00
bol-van 0e288262b5 wg4all note 2025-08-12 09:57:08 +03:00
bol-van dce049d6b8 discord custom 2025-08-12 09:41:55 +03:00
bol-van d103602d86 stun4all fix length check 2025-08-12 09:41:44 +03:00
bol-van aaf8f18a7d optimize 50-stun4all 2025-08-12 08:48:33 +03:00
bol-van de19cc3cd4 replace spaces with tab 2025-08-11 20:44:27 +03:00
bol-van 1e56703d4b replace spaces with tab 2025-08-11 20:43:07 +03:00
bol-van cd0f1c4bdf stun4all, wg4all improve 2025-08-11 20:27:39 +03:00
bol-van 135b152497 stun4all, wg4all improve 2025-08-11 20:23:38 +03:00
bol-van 56456c1e0c nfqws,tpws: fix possible crashes or high memory usage if hostlist has duplicate hostnames 2025-08-08 11:35:13 +03:00
bol-van d6a8d1dc33 lame issue warning in english 2025-08-06 08:25:23 +03:00
bol-van 04b3b6abcb update issue warning 2025-08-04 10:59:41 +03:00
bol-van fd58ecf8a5 update issue warning 2025-08-04 10:58:41 +03:00
bol-van a560e251a1 update changes.txt 2025-08-01 13:28:19 +03:00
bol-van 2ff0f9c0ff tpws: minor update 2025-08-01 13:23:05 +03:00
bol-van 4dbd673eaa update changes.txt 2025-08-01 12:52:06 +03:00
bol-van 497810ab4e tpws: special case for ip looking hostnames 2025-08-01 12:48:16 +03:00
bol-van 4cfed1db7e nfqws: print hostname_is_ip in ipv6 ipcache 2025-08-01 12:12:24 +03:00
bol-van fd6b7a2b7f nfqws: optimize code 2025-08-01 12:03:53 +03:00
bol-van 6d865ad790 nfqws: comment 2025-08-01 11:31:48 +03:00
bol-van dfe36aee4c nfqws: special case for ip looking hostnames 2025-08-01 11:21:23 +03:00
bol-van 2d704a859d blockcheck: display timestamp enable message 2025-07-31 13:57:13 +03:00
bol-van 8026d11f71 blockcheck: test ts fooling, silently enable timestamps in windows 2025-07-31 13:49:30 +03:00
bol-van 2f77cec863 doc works 2025-07-31 13:11:18 +03:00
bol-van ba7954f068 doc works 2025-07-31 13:09:44 +03:00
bol-van 8b5c951451 nfqws: ts fooling 2025-07-31 12:51:31 +03:00
bol-van 84e75b0f28 doc works 2025-07-30 15:08:09 +03:00
bol-van c4e5db309f doc works 2025-07-30 15:06:24 +03:00
bol-van 769f7b60c8 doc works 2025-07-30 15:02:08 +03:00
bol-van b0578c5e9f doc works 2025-07-30 15:00:41 +03:00
bol-van 40362bfb5b doc works 2025-07-30 15:00:05 +03:00
bol-van 10eb9050a1 doc works 2025-07-30 14:59:28 +03:00
bol-van b63e598085 FILTER_MARK support 2025-07-30 14:42:30 +03:00
bol-van c60f9c9027 doc update ver 2025-07-08 10:01:58 +03:00
bol-van 951c980bec typo 2025-07-07 17:33:36 +03:00
bol-van 5eaec085dd install_easy: warn about --ipset 2025-07-07 15:53:46 +03:00
bol-van 721b353776 doc works 2025-07-07 15:38:51 +03:00
bol-van e6d2051c87 doc works 2025-07-07 15:37:40 +03:00
bol-van e665794ac4 doc works 2025-07-07 15:33:41 +03:00
bol-van 7db14a07c5 tpws: openbsd no more inits /dev/pf by default 2025-07-07 15:33:02 +03:00
bol-van c14554c1f3 Merge pull request #1585 from artur-intech/patch-1
Fix filename
2025-06-30 07:46:10 +03:00
Artur ced1682003 Fix filename 2025-06-29 21:45:50 +03:00
Artur 4701f27372 Fix filename
It is `zapret-hosts-user.txt`, not `*-users*`.
2025-06-29 20:18:37 +03:00
bol-van a1699067b3 Merge pull request #1575 from dass79zh/ipv6less-curl-fix
Support curl compiled without IPv6 support.
2025-06-27 21:57:08 +03:00
Andrew Danshin 643fc0c456 Support curl compiled without IPv6 support.
modified:   blockcheck.sh
2025-06-27 21:07:32 +03:00
bol-van 09c07f6d21 winws: decrease wf-save buf 2025-06-23 08:17:52 +03:00
bol-van dd72c68ae6 winws: increase windivert filter buffers 2025-06-23 08:14:36 +03:00
bol-van 9c1a3e77cc Makefiles: CC=cc 2025-06-22 21:39:27 +03:00
bol-van ae957e9a73 doc fix 2025-06-22 19:27:20 +03:00
bol-van bc47a13ba4 install_bin: no help text if getarch 2025-06-16 09:13:40 +03:00
bol-van 20b69cb63d install_bin: minor improve help text 2025-06-16 07:15:08 +03:00
bol-van ef4f8a2b86 install_bin: display help text if no bins found 2025-06-16 07:11:59 +03:00
bol-van d00d341505 blockcheck: display kernel ver 2025-06-15 16:22:38 +03:00
bol-van 0738d3980f blockcheck: curl version display 2025-06-15 15:56:25 +03:00
bol-van 34ff4630bf blockcheck: curl version display 2025-06-15 15:55:03 +03:00
bol-van f8b5f602a4 nfqws: allow desync of replayed udp with reasm offset !=0 2025-06-15 09:18:25 +03:00
bol-van 8dacb57a86 OPTIMIZE in makefiles 2025-06-13 22:17:32 +03:00
bol-van 9776d5d8a9 nfqws: old gcc 4.x compat 2025-06-13 11:44:11 +03:00
bol-van f88c9a662d nfqws: allow linux build without ssid 2025-06-13 11:31:50 +03:00
bol-van 97bcb9740d update docs 2025-06-13 11:12:37 +03:00
bol-van b6e9fa3434 nfqws: check wext ssid len not zero 2025-06-12 13:22:54 +03:00
bol-van 32cfee705a nfqws: optimize wext 2025-06-12 11:58:20 +03:00
bol-van 1303bf0fef update changes.txt 2025-06-12 11:46:34 +03:00
bol-van 2417d4ee76 nfqws: use wireless ext in case nl80211 does not return ssid 2025-06-12 11:45:14 +03:00
bol-van 64280cbf3d doc works 2025-06-12 09:08:21 +03:00
bol-van 54dd06056e doc works 2025-06-12 09:06:06 +03:00
bol-van 0be4cbf8a4 rename windows bin dirs 2025-06-11 21:28:18 +03:00
bol-van acf888c493 rename android bin dir 2025-06-11 21:26:32 +03:00
bol-van f3d90d4e00 rename freebsd bin dir 2025-06-11 21:25:14 +03:00
bol-van ceec80a8ed openwrt makefile -lmnl 2025-06-11 20:52:12 +03:00
bol-van e876096072 rename bin dirs 2025-06-11 20:49:46 +03:00
bol-van 796e4a40b6 rename bin dirs 2025-06-11 20:48:51 +03:00
bol-van 5b7c4a4318 rename bin dirs 2025-06-11 20:46:53 +03:00
bol-van f09d918b40 nfqws,tpws: use initgroups() if --user specified 2025-06-11 20:15:43 +03:00
bol-van f3d48b7160 nfqws: debug wlan info init 2025-06-04 10:05:42 +03:00
bol-van 58d306b552 nfqws: --filter-ssid (linux only) 2025-06-04 09:26:38 +03:00
bol-van 30a947b42b install_bin.sh : minor bug 2025-06-01 19:16:37 +03:00
bol-van 9fe26c92a5 install_bin: remove quarantine xattr on macos 2025-06-01 15:30:51 +03:00
bol-van ab0d16f4e1 install_easy: fix broken compile on mac 2025-06-01 09:11:33 +03:00
bol-van c37c39996d static 2025-05-31 13:42:36 +03:00
bol-van 87a0cf0797 nfqws,tpws: --debug=android for NDK builds 2025-05-31 10:34:03 +03:00
bol-van 893a133f86 install_easy: rephrase 2025-05-30 10:54:20 +03:00
bol-van fa9e3c09f1 install_easy: ask MODE_FILTER before daemon test 2025-05-29 19:14:35 +03:00
bol-van 2edf6bee34 install_easy: minor fix 2025-05-29 19:05:50 +03:00
bol-van 468d293b46 install_easy: run daemon test under proper user 2025-05-29 19:02:50 +03:00
bol-van fd698d801b nfqws,tpws: check list files accessibility with dropped privs in --dry-run mode 2025-05-29 15:43:27 +03:00
bol-van 38a3833351 install_bin: do exec test after elf test 2025-05-28 23:06:12 +03:00
bol-van 6c9ff2010b install_bin: fix TEST=run 2025-05-28 22:46:55 +03:00
bol-van 06f57e27ed install_bin: fix minor problems 2025-05-28 20:40:26 +03:00
bol-van 06921bdbee install_bin: read elf detection method 2025-05-28 20:27:34 +03:00
bol-van 3999e0b350 install_bin: read elf detection method 2025-05-28 20:22:09 +03:00
bol-van 1301aca25b Upx 5.0.1 still has bugs on mips
This reverts commit f0a8a35c12.
2025-05-28 19:37:57 +03:00
bol-van bf4244809f install_easy: stop if running embedded release on traditional linux 2025-05-28 14:37:32 +03:00
bol-van 99b5406905 redsocks: shell /bin/false 2025-05-27 22:24:58 +03:00
bol-van ebd01868ee redsocks: no bash for su 2025-05-27 22:20:46 +03:00
bol-van c451addd86 redsocks: shadow-su 2025-05-27 21:53:44 +03:00
bol-van 4c8ea084d7 redsocks.txt: remove obsolete 2025-05-27 21:46:46 +03:00
bol-van 02badb3c4c nfqws,tpws: move --ipset to kavl 2025-05-27 16:03:28 +03:00
bol-van 323307cbfa Merge pull request #1464 from Dronatar/patch-1
Omission fix in readme.md
2025-05-26 09:38:57 +03:00
Dronatar 00560719bd Omission fix in readme.md 2025-05-26 06:15:29 +02:00
bol-van 56c96df47b remove seccomp from systemd units 2025-05-25 20:07:52 +03:00
bol-van f0a8a35c12 They fixed problems
This reverts commit 58e73d0331.
2025-05-25 09:49:01 +03:00
bol-van d566f48f94 blockcheck: display ip version every test 2025-05-24 13:35:11 +03:00
bol-van 3513cbb65e winws: fix trash flood warning message 2025-05-24 10:51:01 +03:00
98 changed files with 6889 additions and 3422 deletions
+2
View File
@@ -1,3 +1,5 @@
* text=auto eol=lf
*.cmd eol=crlf
*.bat eol=crlf
init.d/windivert.filter.examples/** eol=crlf
files/** binary
+15 -9
View File
@@ -7,13 +7,19 @@ assignees: ''
---
1. Здесь не место для вопросов, касающихся компьютерной грамотности и навыков использования ОС
2. Здесь не место для вопросов "у меня не работает" без технических подробностей
3. Здесь не место для вопросов "как мне открыть ютуб", "что писать в ...", "перестало открываться".
4. Здесь не место для обсуждения сборок
5. Вирусов здесь нет. У вас либо чья-то сборка, либо ваш антивирус давно пора отправить на покой. Антивирусы в основном жалуются на upx и windivert, которые убраны НЕ будут. upx - это паковщик для сокращения требуемого места на openwrt, windivert - замена iptables для windows, потенциальный инструмент хакера или компонент зловредной программы, но сам по себе вирусом не является. Не согласны - удаляйте софт. За агрессивные наезды "почему автор распространяет вирусы" молча схватите бан.
Issues - это место для обращений к разработчику.
Discussions - место для обсуждения вопросов между пользователями.
Не тратьте время разработчика на ерунду. Вам не будут здесь объяснять как скопировать, что "писать в", почему сразу же закрывается окно, почему не открывается сайт или госуслуги. Здесь не место обсуждению любых шаманств, т.е. манипуляций без понимания, в стиле 4pda.
Пишите только конкретные проблемы на техническом уровне в оригинальном zapret (не в сборках), которые вы заметили, и которые являются или могут являться багами в софте.
Или если вы считаете, что ваше обращение обосновано, технически грамотно и по адресу.
Все, что будет нарушать эти критерии, может быть молча удалено, закрыто или перенесено в дискуссии на усмотрение разработчика.
Если сомневаетесь - пишите лучше сразу в дискуссии.
Все означенное обсуждать в дискуссиях или на форумах.
При нарушении будет закрываться или конвертироваться в дискуссии.
Issue только для обсуждения проблем самого софта. Неработа стратегии или ваше неумение настроить - это ваша проблема, а не проблема софта.
Однокнопочные решения дают только сборщики, поэтому "открытие сайта" не является функцией программы, и нет смысла жаловаться, что он не открывается. Но можно это обсудить в дискуссиях. Не захламляйте issues !
Прочитайте для начала docs/quick_start.md или docs/quick_start_windows.md.
Там объясняется для кого этот софт, какие требуются знания, почему это не простая волшебная таблетка.
Вирусов здесь нет. У вас либо чья-то сборка, либо ваш антивирус давно пора отправить на покой. Антивирусы в основном жалуются на upx и windivert, которые убраны НЕ будут. upx - это паковщик для сокращения требуемого места на openwrt, windivert - замена iptables для windows, потенциальный инструмент хакера или компонент зловредной программы, но сам по себе вирусом не является. Не согласны - удаляйте софт. За агрессивные наезды "почему автор распространяет вирусы" молча схватите бан.
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.
+40 -37
View File
@@ -25,27 +25,13 @@ jobs:
- arch: arm64
tool: aarch64-unknown-linux-musl
- arch: arm
tool: arm-unknown-linux-musleabi
# - arch: armhf
# tool: arm-unknown-linux-musleabihf
# - arch: armv7
# tool: armv7-unknown-linux-musleabi
# - arch: armv7hf
# tool: armv7-unknown-linux-musleabihf
# - arch: mips64el
# tool: mips64el-unknown-linux-musl
tool: armv6-unknown-linux-musleabi
- arch: mips64
tool: mips64-unknown-linux-musl
# - arch: mipsel
# tool: mipsel-unknown-linux-musl
- arch: mipselsf
tool: mipsel-unknown-linux-muslsf
# - arch: mips
# tool: mips-unknown-linux-musl
- arch: mipssf
tool: mips-unknown-linux-muslsf
# - arch: ppc64
# tool: powerpc64-unknown-linux-musl
- arch: ppc
tool: powerpc-unknown-linux-musl
- arch: x86
@@ -69,7 +55,7 @@ jobs:
env:
ARCH: ${{ matrix.arch }}
TOOL: ${{ matrix.tool }}
REPO: ${{ matrix.arch == 'lexra' && matrix.repo || 'spvkgn/musl-cross' }}
REPO: ${{ matrix.arch == 'lexra' && matrix.repo || 'bol-van/musl-cross' }}
DIR: ${{ matrix.arch == 'lexra' && matrix.dir || matrix.tool }}
run: |
if [[ "$ARCH" == lexra ]]; then
@@ -102,6 +88,15 @@ 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=arm1176jzf-s -mthumb"
;;
esac
# netfilter libs
wget -qO- https://www.netfilter.org/pub/libnfnetlink/libnfnetlink-1.0.2.tar.bz2 | tar -xj
@@ -111,7 +106,7 @@ jobs:
for i in libmnl libnfnetlink libnetfilter_queue ; do
(
cd $i-*
CFLAGS="-Os -flto=auto $CFLAGS" \
CFLAGS="$OPTIMIZE $CPU -flto=auto $CFLAGS" \
./configure --prefix= --host=$TARGET --enable-static --disable-shared --disable-dependency-tracking
make install -j$(nproc) DESTDIR=$DEPS_DIR
)
@@ -123,7 +118,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="$OPTIMIZE $CPU -flto=auto $CFLAGS" \
./configure --prefix= --static
make install -j$(nproc) DESTDIR=$DEPS_DIR
)
@@ -134,7 +129,8 @@ jobs:
install -Dm644 -t $DEPS_DIR/include/sys /usr/include/x86_64-linux-gnu/sys/queue.h /usr/include/sys/capability.h
# zapret
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 -static $CPU -I$DEPS_DIR/include $CFLAGS" \
LDFLAGS="-L$DEPS_DIR/lib $LDFLAGS" \
make -C zapret -j$(nproc)
tar -C zapret/binaries/my -cJf zapret-linux-$ARCH.tar.xz .
@@ -340,6 +336,14 @@ jobs:
export RANLIB=$TOOLCHAIN/bin/llvm-ranlib
export STRIP=$TOOLCHAIN/bin/llvm-strip
export PKG_CONFIG_PATH=$DEPS_DIR/lib/pkgconfig
case "$ABI" in
armeabi-v7a)
CPU="-mthumb"
;;
arm64-v8a)
PAGESIZE="-Wl,-z,max-page-size=16384"
;;
esac
# netfilter libs
wget -qO- https://www.netfilter.org/pub/libnfnetlink/libnfnetlink-1.0.2.tar.bz2 | tar -xj
@@ -350,7 +354,7 @@ jobs:
for i in libmnl libnfnetlink libnetfilter_queue ; do
(
cd $i-*
CFLAGS="-Os -flto=auto -Wno-implicit-function-declaration" \
CFLAGS="$CPU -Os -flto=auto -Wno-implicit-function-declaration" \
./configure --prefix= --host=$TARGET --enable-static --disable-shared --disable-dependency-tracking
make install -j$(nproc) DESTDIR=$DEPS_DIR
)
@@ -358,8 +362,8 @@ jobs:
done
# zapret
CFLAGS="-DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -I$DEPS_DIR/include" \
LDFLAGS="-L$DEPS_DIR/lib" \
CFLAGS="$CPU -DZAPRET_GH_VER=${{ github.ref_name }} -DZAPRET_GH_HASH=${{ github.sha }} -I$DEPS_DIR/include" \
LDFLAGS="-L$DEPS_DIR/lib $PAGESIZE" \
make -C zapret android -j$(nproc)
# strip unwanted ELF sections to prevent warnings on old Android versions
@@ -427,7 +431,6 @@ jobs:
unzip $f -d $dir && rm $f
if [[ $dir =~ win ]]; then
chmod -x $dir/*
run_upx --force $dir/cygwin1.dll
fi
;;
esac
@@ -438,23 +441,23 @@ jobs:
if [ -d $dir ]; then
echo "Processing $dir"
case $dir in
*-android-arm64-v8a ) run_dir android-aarch64 ;;
*-android-arm64-v8a ) run_dir android-arm64 ;;
*-android-armeabi-v7a ) run_dir android-arm ;;
*-android-x86 ) run_dir android-x86 ;;
*-android-x86_64 ) run_dir android-x86_64 ;;
*-freebsd-x86_64 ) run_dir freebsd-x64 ;;
*-linux-arm ) run_dir arm ;;
*-linux-arm64 ) run_dir aarch64 ;;
*-linux-mips64 ) run_dir mips64r2-msb ;;
*-linux-mipselsf ) run_dir mips32r1-lsb ;;
*-linux-mipssf ) run_dir mips32r1-msb ;;
*-linux-ppc ) run_dir ppc ;;
*-linux-x86 ) run_dir x86 ;;
*-linux-x86_64 ) run_dir x86_64 ;;
*-linux-lexra ) run_dir lexra ;;
*-freebsd-x86_64 ) run_dir freebsd-x86_64 ;;
*-linux-arm ) run_dir linux-arm ;;
*-linux-arm64 ) run_dir linux-arm64 ;;
*-linux-mips64 ) run_dir linux-mips64 ;;
*-linux-mipselsf ) run_dir linux-mipsel ;;
*-linux-mipssf ) run_dir linux-mips ;;
*-linux-ppc ) run_dir linux-ppc ;;
*-linux-x86 ) run_dir linux-x86 ;;
*-linux-x86_64 ) run_dir linux-x86_64 ;;
*-linux-lexra ) run_dir linux-lexra ;;
*-mac-x64 ) run_dir mac64 ;;
*-win-x86 ) run_dir win32 ;;
*-win-x86_64 ) run_dir win64 ;;
*-win-x86 ) run_dir windows-x86 ;;
*-win-x86_64 ) run_dir windows-x86_64 ;;
esac
fi
done
@@ -469,7 +472,7 @@ jobs:
(
cd ${{ env.repo_dir }}
rm -rf binaries/{android*,freebsd*,mac*,win*,x86_64/tpws_wsl.tgz} \
init.d/{openrc,macos,pfsense,runit,s6,systemd} \
init.d/{openrc,macos,pfsense,runit,s6,systemd,windivert.filter.examples} \
tpws nfq ip2net mdig docs files/huawei Makefile
)
tar --owner=0 --group=0 -czf ${{ env.repo_dir }}-openwrt-embedded.tar.gz ${{ env.repo_dir }}
+248 -94
View File
@@ -41,19 +41,22 @@ CURL_MAX_TIME_QUIC=${CURL_MAX_TIME_QUIC:-$CURL_MAX_TIME}
CURL_MAX_TIME_DOH=${CURL_MAX_TIME_DOH:-2}
MIN_TTL=${MIN_TTL:-1}
MAX_TTL=${MAX_TTL:-12}
MIN_AUTOTTL_DELTA=${MIN_AUTOTTL_DELTA:-1}
MAX_AUTOTTL_DELTA=${MAX_AUTOTTL_DELTA:-5}
USER_AGENT=${USER_AGENT:-Mozilla}
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
NFT_TABLE=blockcheck
DNSCHECK_DNS=${DNSCHECK_DNS:-8.8.8.8 1.1.1.1 77.88.8.1}
DNSCHECK_DOM=${DNSCHECK_DOM:-pornhub.com ntc.party rutracker.org www.torproject.org bbc.com}
DNSCHECK_DOM=${DNSCHECK_DOM:-pornhub.com ej.ru rutracker.org www.torproject.org bbc.com}
DOH_SERVERS=${DOH_SERVERS:-"https://cloudflare-dns.com/dns-query https://dns.google/dns-query https://dns.quad9.net/dns-query https://dns.adguard.com/dns-query https://common.dot.dns.yandex.net/dns-query"}
DNSCHECK_DIG1=/tmp/dig1.txt
DNSCHECK_DIG2=/tmp/dig2.txt
@@ -216,7 +219,7 @@ doh_resolve()
# $1 - ip version 4/6
# $2 - hostname
# $3 - doh server URL. use $DOH_SERVER if empty
$MDIG --family=$1 --dns-make-query=$2 | $CURL --max-time $CURL_MAX_TIME_DOH -s --data-binary @- -H "Content-Type: application/dns-message" "${3:-$DOH_SERVER}" | $MDIG --dns-parse-query
"$MDIG" --family=$1 --dns-make-query=$2 | "$CURL" --max-time $CURL_MAX_TIME_DOH -s --data-binary @- -H "Content-Type: application/dns-message" "${3:-$DOH_SERVER}" | "$MDIG" --dns-parse-query
}
doh_find_working()
{
@@ -244,7 +247,7 @@ mdig_vars()
# $1 - ip version 4/6
# $2 - hostname
hostvar=$(echo $2 | sed -e 's/[\.-]/_/g')
hostvar=$(echo $2 | sed -e 's/[\./?&#@%*$^:~=!()+-]/_/g')
cachevar=DNSCACHE_${hostvar}_$1
countvar=${cachevar}_COUNT
eval count=\$${countvar}
@@ -275,41 +278,45 @@ mdig_cache()
mdig_resolve()
{
# $1 - ip version 4/6
# $2 - hostname
# $2 - var to receive result
# $3 - hostname, possibly with uri : rutracker.org/xxx/xxxx
local hostvar cachevar countvar count n sdom
local hostvar cachevar countvar count ip n
mdig_vars "$@"
split_by_separator "$3" / sdom
mdig_vars "$1" "$sdom"
if [ -n "$count" ]; then
n=$(random 0 $(($count-1)))
eval ip=\$${cachevar}_$n
echo $ip
eval $2=\$${cachevar}_$n
return 0
else
mdig_cache "$@" && mdig_resolve "$@"
mdig_cache "$1" "$sdom" && mdig_resolve "$1" "$2" "$sdom"
fi
}
mdig_resolve_all()
{
# $1 - ip version 4/6
# $2 - hostname
# $2 - var to receive result
# $3 - hostname
local hostvar cachevar countvar count ip ips n
mdig_vars "$@"
local hostvar cachevar countvar count ip__ ips__ n sdom
split_by_separator "$3" / sdom
mdig_vars "$1" "$sdom"
if [ -n "$count" ]; then
n=0
while [ "$n" -le $count ]; do
eval ip=\$${cachevar}_$n
if [ -n "$ips" ]; then
ips="$ips $ip"
eval ip__=\$${cachevar}_$n
if [ -n "$ips__" ]; then
ips__="$ips__ $ip__"
else
ips="$ip"
ips__="$ip__"
fi
n=$(($n + 1))
done
echo "$ips"
eval $2="\$ips__"
return 0
else
mdig_cache "$@" && mdig_resolve_all "$@"
mdig_cache "$1" "$sdom" && mdig_resolve_all "$1" "$2" "$sdom"
fi
}
@@ -396,13 +403,31 @@ check_system()
PKTWS="$WINWS"
PKTWSD=winws
FWTYPE=windivert
# ts fooling requires timestamps. they are disabled by default in windows.
echo enabling tcp timestamps
netsh interface tcp set global timestamps=enabled >/dev/null
;;
*)
echo $UNAME not supported
exitp 5
esac
echo $UNAME${SUBSYS:+/$SUBSYS} detected
echo -n 'kernel: '
if [ -f "/proc/version" ]; then
cat /proc/version
else
uname -a
fi
[ -f /etc/os-release ] && {
. /etc/os-release
[ -n "$PRETTY_NAME" ] && echo "distro: $PRETTY_NAME"
[ -n "$OPENWRT_RELEASE" ] && echo "openwrt release: $OPENWRT_RELEASE"
[ -n "$OPENWRT_BOARD" ] && echo "openwrt board: $OPENWRT_BOARD"
[ -n "$OPENWRT_ARCH" ] && echo "openwrt arch: $OPENWRT_ARCH"
}
echo firewall type is $FWTYPE
echo CURL=$CURL
"$CURL" --version
}
zp_already_running()
@@ -458,7 +483,7 @@ check_prerequisites()
exitp 6
}
local prog progs='curl'
local prog progs="$CURL"
[ "$SKIP_PKTWS" = 1 ] || {
case "$UNAME" in
Linux)
@@ -574,12 +599,12 @@ curl_translate_code()
curl_supports_tls13()
{
local r
$CURL --tlsv1.3 -Is -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null
"$CURL" --tlsv1.3 -Is -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null
# return code 2 = init failed. likely bad command line options
[ $? = 2 ] && return 1
# curl can have tlsv1.3 key present but ssl library without TLS 1.3 support
# this is online test because there's no other way to trigger library incompatibility case
$CURL --tlsv1.3 --max-time 1 -Is -o /dev/null https://iana.org 2>/dev/null
"$CURL" --tlsv1.3 --max-time 1 -Is -o /dev/null https://iana.org 2>/dev/null
r=$?
[ $r != 4 -a $r != 35 ]
}
@@ -587,16 +612,16 @@ curl_supports_tls13()
curl_supports_tlsmax()
{
# supported only in OpenSSL and LibreSSL
$CURL --version | grep -Fq -e OpenSSL -e LibreSSL -e BoringSSL -e GnuTLS -e quictls || return 1
"$CURL" --version | grep -Fq -e OpenSSL -e LibreSSL -e BoringSSL -e GnuTLS -e quictls || return 1
# supported since curl 7.54
$CURL --tls-max 1.2 -Is -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null
"$CURL" --tls-max 1.2 -Is -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null
# return code 2 = init failed. likely bad command line options
[ $? != 2 ]
}
curl_supports_connect_to()
{
$CURL --connect-to 127.0.0.1:: -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null
"$CURL" --connect-to 127.0.0.1:: -o /dev/null --max-time 1 http://127.0.0.1:65535 2>/dev/null
[ "$?" != 2 ]
}
@@ -604,7 +629,7 @@ curl_supports_http3()
{
# if it has http3 : curl: (3) HTTP/3 requested for non-HTTPS URL
# otherwise : curl: (2) option --http3-only: is unknown
$CURL --connect-to 127.0.0.1:: -o /dev/null --max-time 1 --http3-only http://127.0.0.1:65535 2>/dev/null
"$CURL" --connect-to 127.0.0.1:: -o /dev/null --max-time 1 --http3-only http://127.0.0.1:65535 2>/dev/null
[ "$?" != 2 ]
}
@@ -627,11 +652,15 @@ curl_with_subst_ip()
# $2 - port
# $3 - ip
# $4+ - curl params
local connect_to="--connect-to $1::[$3]${2:+:$2}" arg
shift ; shift ; shift
local ip="$3"
case "$ip" in
*:*) ip="[$ip]" ;;
esac
local connect_to="--connect-to $1::$ip${2:+:$2}" arg
shift ; shift ; shift;
[ "$CURL_VERBOSE" = 1 ] && arg="-v"
[ "$CURL_CMD" = 1 ] && echo $CURL ${arg:+$arg }$connect_to "$@"
ALL_PROXY="$ALL_PROXY" $CURL ${arg:+$arg }$connect_to "$@"
ALL_PROXY="$ALL_PROXY" "$CURL" ${arg:+$arg }$connect_to "$@"
}
curl_with_dig()
{
@@ -639,11 +668,14 @@ curl_with_dig()
# $2 - domain name
# $3 - port
# $4+ - curl params
local dom=$2 port=$3
local ip=$(mdig_resolve $1 $dom)
local dom="$2" port=$3
local sdom suri ip
split_by_separator "$dom" / sdom suri
mdig_resolve $1 ip $sdom
shift ; shift ; shift
if [ -n "$ip" ]; then
curl_with_subst_ip $dom $port $ip "$@"
curl_with_subst_ip "$sdom" "$port" "$ip" "$@"
else
return 6
fi
@@ -655,12 +687,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()
@@ -670,8 +702,8 @@ curl_test_http()
# $3 - subst ip
# $4 - "detail" - detail info
local code loc hdrt="${HDRTEMP}_${!:-$$}.txt"
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 || {
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 || {
code=$?
rm -f "$hdrt"
return $code
@@ -683,8 +715,9 @@ curl_test_http()
code=$(hdrfile_http_code "$hdrt")
[ "$code" = 301 -o "$code" = 302 -o "$code" = 307 -o "$code" = 308 ] && {
loc=$(hdrfile_location "$hdrt")
echo "$loc" | grep -qE "^https?://.*$2(/|$)" ||
echo "$loc" | grep -vqE '^https?://' || {
split_by_separator "$dom" / dom
tolower "$loc" | grep -qE "^https?://.*$dom(/|$)" ||
tolower "$loc" | grep -vqE '^https?://' || {
echo suspicious redirection $code to : $loc
rm -f "$hdrt"
return 254
@@ -706,7 +739,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" -ISs -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()
{
@@ -715,7 +748,7 @@ curl_test_https_tls13()
# $3 - subst ip
# force TLS1.3 mode
curl_probe $1 $2 $HTTPS_PORT "$3" -ISs -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()
@@ -724,7 +757,7 @@ curl_test_http3()
# $2 - domain name
# force QUIC only mode without tcp
curl_with_dig $1 $2 $QUIC_PORT -ISs -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()
@@ -788,7 +821,7 @@ nft_scheme()
make_comma_list iplist $3
nft add table inet $NFT_TABLE
nft "add chain inet $NFT_TABLE postnat { type filter hook output priority 102; }"
nft "add chain inet $NFT_TABLE postnat { type filter hook postrouting priority 102; }"
nft "add rule inet $NFT_TABLE postnat meta nfproto ipv${IPV} $1 dport $2 mark and $DESYNC_MARK == 0 ip${ipver} daddr {$iplist} ct mark set ct mark or $DESYNC_MARK queue num $QNUM"
# for strategies with incoming packets involved (autottl)
nft "add chain inet $NFT_TABLE prenat { type filter hook prerouting priority -102; }"
@@ -974,7 +1007,7 @@ check_domain_port_block()
echo
echo \* port block tests ipv$IPV $1:$2
if netcat_setup; then
ips=$(mdig_resolve_all $IPV $1)
mdig_resolve_all $IPV ips $1
if [ -n "$ips" ]; then
for ip in $ips; do
if netcat_test $ip $2; then
@@ -1047,12 +1080,23 @@ 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)
if [ "$n" -lt "$SIM_SUCCESS_RATE" ]; then
echo "SUCCESS"
return 0
else
echo "FAILED"
return 7
fi
}
shift
shift
shift
$ws_start "$@"
curl_test $testf $dom
curl_test $testf "$dom"
code=$?
ws_kill
return $code
@@ -1062,15 +1106,15 @@ tpws_curl_test()
# $1 - test function
# $2 - domain
# $3,$4,$5, ... - tpws params
echo - $1 $2 : tpws $3 $4 $5 $6 $7 $8 $9${TPWS_EXTRA:+ $TPWS_EXTRA}${TPWS_EXTRA_1:+ "$TPWS_EXTRA_1"}${TPWS_EXTRA_2:+ "$TPWS_EXTRA_2"}${TPWS_EXTRA_3:+ "$TPWS_EXTRA_3"}${TPWS_EXTRA_4:+ "$TPWS_EXTRA_4"}${TPWS_EXTRA_5:+ "$TPWS_EXTRA_5"}${TPWS_EXTRA_6:+ "$TPWS_EXTRA_6"}${TPWS_EXTRA_7:+ "$TPWS_EXTRA_7"}${TPWS_EXTRA_8:+ "$TPWS_EXTRA_8"}${TPWS_EXTRA_9:+ "$TPWS_EXTRA_9"}
echo - $1 ipv$IPV $2 : tpws $3 $4 $5 $6 $7 $8 $9${TPWS_EXTRA:+ $TPWS_EXTRA}${TPWS_EXTRA_1:+ "$TPWS_EXTRA_1"}${TPWS_EXTRA_2:+ "$TPWS_EXTRA_2"}${TPWS_EXTRA_3:+ "$TPWS_EXTRA_3"}${TPWS_EXTRA_4:+ "$TPWS_EXTRA_4"}${TPWS_EXTRA_5:+ "$TPWS_EXTRA_5"}${TPWS_EXTRA_6:+ "$TPWS_EXTRA_6"}${TPWS_EXTRA_7:+ "$TPWS_EXTRA_7"}${TPWS_EXTRA_8:+ "$TPWS_EXTRA_8"}${TPWS_EXTRA_9:+ "$TPWS_EXTRA_9"}
local ALL_PROXY="socks5://127.0.0.1:$SOCKS_PORT"
ws_curl_test tpws_start "$@"${TPWS_EXTRA:+ $TPWS_EXTRA}${TPWS_EXTRA_1:+ "$TPWS_EXTRA_1"}${TPWS_EXTRA_2:+ "$TPWS_EXTRA_2"}${TPWS_EXTRA_3:+ "$TPWS_EXTRA_3"}${TPWS_EXTRA_4:+ "$TPWS_EXTRA_4"}${TPWS_EXTRA_5:+ "$TPWS_EXTRA_5"}${TPWS_EXTRA_6:+ "$TPWS_EXTRA_6"}${TPWS_EXTRA_7:+ "$TPWS_EXTRA_7"}${TPWS_EXTRA_8:+ "$TPWS_EXTRA_8"}${TPWS_EXTRA_9:+ "$TPWS_EXTRA_9"}
local testf=$1 dom=$2 strategy code=$?
local testf=$1 dom="$2" strategy code=$?
[ "$code" = 0 ] && {
shift; shift;
strategy="$@"
strategy_append_extra_tpws
report_append "ipv${IPV} $dom $testf : tpws ${WF:+$WF }$strategy"
report_append "$dom" "$testf ipv${IPV}" "tpws ${WF:+$WF }$strategy"
}
return $code
}
@@ -1079,17 +1123,17 @@ 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 $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:+ $PKTWS_EXTRA}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_1"}${PKTWS_EXTRA_2:+ "$PKTWS_EXTRA_2"}${PKTWS_EXTRA_3:+ "$PKTWS_EXTRA_3"}${PKTWS_EXTRA_4:+ "$PKTWS_EXTRA_4"}${PKTWS_EXTRA_5:+ "$PKTWS_EXTRA_5"}${PKTWS_EXTRA_6:+ "$PKTWS_EXTRA_6"}${PKTWS_EXTRA_7:+ "$PKTWS_EXTRA_7"}${PKTWS_EXTRA_8:+ "$PKTWS_EXTRA_8"}${PKTWS_EXTRA_9:+ "$PKTWS_EXTRA_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:+ $PKTWS_EXTRA}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_1"}${PKTWS_EXTRA_2:+ "$PKTWS_EXTRA_2"}${PKTWS_EXTRA_3:+ "$PKTWS_EXTRA_3"}${PKTWS_EXTRA_4:+ "$PKTWS_EXTRA_4"}${PKTWS_EXTRA_5:+ "$PKTWS_EXTRA_5"}${PKTWS_EXTRA_6:+ "$PKTWS_EXTRA_6"}${PKTWS_EXTRA_7:+ "$PKTWS_EXTRA_7"}${PKTWS_EXTRA_8:+ "$PKTWS_EXTRA_8"}${PKTWS_EXTRA_9:+ "$PKTWS_EXTRA_9"}
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:+ $PKTWS_EXTRA}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_1"}${PKTWS_EXTRA_2:+ "$PKTWS_EXTRA_2"}${PKTWS_EXTRA_3:+ "$PKTWS_EXTRA_3"}${PKTWS_EXTRA_4:+ "$PKTWS_EXTRA_4"}${PKTWS_EXTRA_5:+ "$PKTWS_EXTRA_5"}${PKTWS_EXTRA_6:+ "$PKTWS_EXTRA_6"}${PKTWS_EXTRA_7:+ "$PKTWS_EXTRA_7"}${PKTWS_EXTRA_8:+ "$PKTWS_EXTRA_8"}${PKTWS_EXTRA_9:+ "$PKTWS_EXTRA_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:+ $PKTWS_EXTRA}${PKTWS_EXTRA_1:+ "$PKTWS_EXTRA_1"}${PKTWS_EXTRA_2:+ "$PKTWS_EXTRA_2"}${PKTWS_EXTRA_3:+ "$PKTWS_EXTRA_3"}${PKTWS_EXTRA_4:+ "$PKTWS_EXTRA_4"}${PKTWS_EXTRA_5:+ "$PKTWS_EXTRA_5"}${PKTWS_EXTRA_6:+ "$PKTWS_EXTRA_6"}${PKTWS_EXTRA_7:+ "$PKTWS_EXTRA_7"}${PKTWS_EXTRA_8:+ "$PKTWS_EXTRA_8"}${PKTWS_EXTRA_9:+ "$PKTWS_EXTRA_9"}
code=$?
[ "$code" = 0 ] && {
strategy="$@"
strategy_append_extra_pktws
report_append "ipv${IPV} $dom $testf : $PKTWSD ${WF:+$WF }$strategy"
report_append "$dom" "$testf ipv${IPV}" "$PKTWSD ${WF:+$WF }$strategy"
}
return $code
}
@@ -1109,11 +1153,11 @@ xxxws_curl_test_update()
# $2 - test function
# $3 - domain
# $4,$5,$6, ... - nfqws/dvtws 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
@@ -1129,8 +1173,35 @@ tpws_curl_test_update()
report_append()
{
# $1 - domain
# $2 - test function + ipver
# $3 - value
local hashstr hash hashvar hashcountvar val ct
# save resources if only one domain
[ "$DOMAINS_COUNT" -gt 1 ] && {
hashstr="$2 : $3"
hash="$(echo -n "$hashstr" | md5f)"
hashvar=RESHASH_${hash}
hashcountvar=${hashvar}_COUNTER
NRESHASH=${NRESHASH:-0}
eval val="\$$hashvar"
if [ -n "$val" ]; then
eval ct="\$$hashcountvar"
ct=$(($ct + 1))
eval $hashcountvar="\$ct"
else
eval $hashvar=\"$hashstr\"
eval $hashcountvar=1
eval RES_$NRESHASH="\$hash"
NRESHASH=$(($NRESHASH+1))
fi
}
NREPORT=${NREPORT:-0}
eval REPORT_${NREPORT}=\"$@\"
eval REPORT_${NREPORT}=\"$2 $1 : $3\"
NREPORT=$(($NREPORT+1))
}
report_print()
@@ -1143,6 +1214,22 @@ report_print()
n=$(($n+1))
done
}
result_intersection_print()
{
local n=0 hash hashvar hashcountvar ct val
while : ; do
eval hash=\"\$RES_$n\"
[ -n "$hash" ] || break
hashvar=RESHASH_${hash}
hashcountvar=${hashvar}_COUNTER
eval ct=\"\$$hashcountvar\"
[ "$ct" = "$DOMAINS_COUNT" ] && {
eval val=\"\$$hashvar\"
echo "$val"
}
n=$(($n + 1))
done
}
report_strategy()
{
# $1 - test function
@@ -1154,23 +1241,26 @@ report_strategy()
strategy="$(echo "$strategy" | xargs)"
echo "!!!!! $1: working strategy found for ipv${IPV} $2 : $3 $strategy !!!!!"
echo
# report_append "ipv${IPV} $2 $1 : $3 ${WF:+$WF }$strategy"
return 0
else
echo "$1: $3 strategy for ipv${IPV} $2 not found"
echo
report_append "ipv${IPV} $2 $1 : $3 not working"
report_append "$2" "$1 ipv${IPV}" "$3 not working"
return 1
fi
}
test_has_split()
{
contains "$1" split || contains "$1" disorder
}
test_has_fakedsplit()
{
contains "$1" fakedsplit || contains "$1" fakeddisorder
}
test_has_split()
{
contains "$1" multisplit || contains "$1" multidisorder || test_has_fakedsplit "$1"
}
test_has_hostfakesplit()
{
contains "$1" hostfakesplit
}
test_has_fake()
{
[ "$1" = fake ] || starts_with "$1" fake,
@@ -1183,6 +1273,7 @@ warn_fool()
echo "WARNING ! fakedsplit/fakeddisorder with md5sig fooling and low split position causes MTU overflow with multi-segment TLS (kyber)"
;;
datanoack) echo 'WARNING ! although datanoack fooling worked it may break NAT and may only work with external IP. Additionally it may require nftables to work correctly.' ;;
ts) echo 'WARNING ! although ts fooling worked it will not work without timestamps being enabled in the client OS. In windows timestamps are DISABLED by default.'
esac
}
pktws_curl_test_update_vary()
@@ -1194,7 +1285,7 @@ pktws_curl_test_update_vary()
# $5,$6,... - strategy
local testf=$1 sec=$2 domain=$3 desync=$4 proto splits= pos fake ret=1
local fake1=- fake2=- fake3=-
local fake1=- fake2=- fake3=- fake4=-
shift; shift; shift; shift
@@ -1203,28 +1294,37 @@ pktws_curl_test_update_vary()
test_has_fake $desync && {
fake1="--dpi-desync-fake-$proto=0x00000000"
[ "$sec" = 0 ] || {
fake2="--dpi-desync-fake-tls=0x00000000 --dpi-desync-fake-tls=! --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid"
fake3="--dpi-desync-fake-tls-mod=rnd,dupsid,rndsni,padencap"
fake2='--dpi-desync-fake-tls=0x00000000 --dpi-desync-fake-tls=! --dpi-desync-fake-tls-mod=rnd,rndsni,dupsid'
# this splits actual fake to '1603' and modified standard fake from offset 2
fake3='--dpi-desync-fake-tls=0x1603 --dpi-desync-fake-tls=!+2 --dpi-desync-fake-tls-mod=rnd,dupsid,rndsni --dpi-desync-fake-tcp-mod=seq'
fake4='--dpi-desync-fake-tls-mod=rnd,dupsid,rndsni,padencap'
}
}
if test_has_fakedsplit $desync ; then
splits="method+2 midsld"
[ "$sec" = 0 ] || splits="1 midsld"
# do not send fake first
fake1='--dpi-desync-fakedsplit-mod=altorder=1'
elif test_has_split $desync ; then
splits="method+2 midsld"
[ "$sec" = 0 ] || splits="1 midsld 1,midsld"
fi
for fake in '' "$fake1" "$fake2" "$fake3" ; do
test_has_hostfakesplit $desync && {
fake1="--dpi-desync-hostfakesplit-mod=altorder=1"
fake2="--dpi-desync-hostfakesplit-midhost=midsld"
fake3="--dpi-desync-hostfakesplit-mod=altorder=1 --dpi-desync-hostfakesplit-midhost=midsld"
}
for fake in '' "$fake1" "$fake2" "$fake3" "$fake4" ; do
[ "$fake" = "-" ] && continue
if [ -n "$splits" ]; then
for pos in $splits ; do
pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" --dpi-desync-split-pos=$pos $fake && {
pktws_curl_test_update $testf "$domain" --dpi-desync=$desync "$@" --dpi-desync-split-pos=$pos $fake && {
[ "$SCANLEVEL" = force ] || return 0
ret=0
}
done
else
pktws_curl_test_update $testf $domain --dpi-desync=$desync "$@" $fake && {
pktws_curl_test_update $testf "$domain" --dpi-desync=$desync "$@" $fake && {
[ "$SCANLEVEL" = force ] || return 0
ret=0
}
@@ -1240,8 +1340,8 @@ pktws_check_domain_http_bypass_()
# $2 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk
# $3 - domain
local ok ttls s f f2 e desync pos fooling frag sec="$2" delta orig splits
local need_split need_disorder need_fakedsplit need_fakeddisorder need_fake need_wssize
local ok ttls attls s f f2 e desync pos fooling frag sec="$2" delta orig splits
local need_split need_disorder need_fakedsplit need_hostfakesplit need_fakeddisorder need_fake need_wssize
local splits_http='method+2 midsld method+2,midsld'
local splits_tls='2 1 sniext+1 sniext+4 host+1 midsld 1,midsld 1,sniext+1,host+1,midsld-2,midsld,midsld+2,endhost-1'
@@ -1252,6 +1352,7 @@ pktws_check_domain_http_bypass_()
}
ttls=$(seq -s ' ' $MIN_TTL $MAX_TTL)
attls=$(seq -s ' ' $MIN_AUTOTTL_DELTA $MAX_AUTOTTL_DELTA)
need_wssize=1
for e in '' '--wssize 1:6'; do
need_split=
@@ -1286,39 +1387,56 @@ pktws_check_domain_http_bypass_()
done
need_fakedsplit=1
need_hostfakesplit=1
need_fakeddisorder=1
need_fake=1
for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do
for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit hostfakesplit fake,hostfakesplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do
[ "$need_fake" = 0 ] && test_has_fake "$desync" && continue
[ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue
[ "$need_hostfakesplit" = 0 ] && contains "$desync" hostfakesplit && continue
[ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue
ok=0
for ttl in $ttls; do
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=$ttl $e && {
[ "$SCANLEVEL" = quick ] && return
ok=1
need_wssize=0
break
}
# orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
for f in '' '--orig-ttl=1 --orig-mod-start=s1 --orig-mod-cutoff=d1'; do
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=$ttl $f $e && {
[ "$SCANLEVEL" = quick ] && return
ok=1
need_wssize=0
[ "$SCANLEVEL" = force ] || break
}
done
[ "$ok" = 1 ] && break
done
# only skip tests if TTL succeeded. do not skip if TTL failed but fooling succeeded
[ $ok = 1 -a "$SCANLEVEL" != force ] && {
[ "$desync" = fake ] && need_fake=0
[ "$desync" = fakedsplit ] && need_fakedsplit=0
[ "$desync" = hostfakesplit ] && need_hostfakesplit=0
[ "$desync" = fakeddisorder ] && need_fakeddisorder=0
}
f=
[ "$UNAME" = "OpenBSD" ] || f="badsum"
f="$f badseq datanoack md5sig"
f="$f badseq datanoack ts md5sig"
[ "$IPV" = 6 ] && f="$f hopbyhop hopbyhop2"
for fooling in $f; do
ok=0
f2=
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling $e && {
warn_fool $fooling $desync
[ "$SCANLEVEL" = quick ] && return
need_wssize=0
ok=1
}
[ "$fooling" = badseq ] && {
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && continue
# --dpi-desync-badseq-increment=0 leaves modified by default ack increment
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling --dpi-desync-badseq-increment=0 $e && {
[ "$SCANLEVEL" = quick ] && return
need_wssize=0
}
}
[ "$fooling" = md5sig ] && {
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && continue
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-fooling=$fooling --dup=1 --dup-cutoff=n2 --dup-fooling=md5sig $e && {
@@ -1383,18 +1501,30 @@ pktws_check_domain_http_bypass_()
need_fakedsplit=1
need_fakeddisorder=1
need_hostfakesplit=1
need_fake=1
for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do
for desync in fake ${need_split:+fakedsplit fake,multisplit fake,fakedsplit hostfakesplit fake,hostfakesplit} ${need_disorder:+fakeddisorder fake,multidisorder fake,fakeddisorder}; do
[ "$need_fake" = 0 ] && test_has_fake "$desync" && continue
[ "$need_fakedsplit" = 0 ] && contains "$desync" fakedsplit && continue
[ "$need_hostfakesplit" = 0 ] && contains "$desync" hostfakesplit && continue
[ "$need_fakeddisorder" = 0 ] && contains "$desync" fakeddisorder && continue
ok=0
for orig in '' 1 2 3; do
for delta in 1 2 3 4 5; do
pktws_curl_test_update_vary $1 $2 $3 $desync ${orig:+--orig-autottl=+$orig} --dpi-desync-ttl=1 --dpi-desync-autottl=-$delta $e && ok=1
# orig-ttl=1 with start/cutoff limiter drops empty ACK packet in response to SYN,ACK. it does not reach DPI or server.
# missing ACK is transmitted in the first data packet of TLS/HTTP proto
for delta in $attls; do
for f in '' '--orig-ttl=1 --orig-mod-start=s1 --orig-mod-cutoff=d1'; do
pktws_curl_test_update_vary $1 $2 $3 $desync --dpi-desync-ttl=1 --dpi-desync-autottl=-$delta $f $e && ok=1
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
done
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
done
[ "$SCANLEVEL" = force ] && {
for orig in 1 2 3; do
for delta in $attls; do
pktws_curl_test_update_vary $1 $2 $3 $desync ${orig:+--orig-autottl=+$orig} --dpi-desync-ttl=1 --dpi-desync-autottl=-$delta $e && ok=1
done
[ "$ok" = 1 -a "$SCANLEVEL" != force ] && break
done
}
[ "$ok" = 1 ] &&
{
echo "WARNING ! although autottl worked it requires testing on multiple domains to find out reliable delta"
@@ -1404,6 +1534,7 @@ pktws_check_domain_http_bypass_()
[ "$SCANLEVEL" = force ] || {
[ "$desync" = fake ] && need_fake=0
[ "$desync" = fakedsplit ] && need_fakedsplit=0
[ "$desync" = hostfakesplit ] && need_hostfakesplit=0
[ "$desync" = fakeddisorder ] && need_fakeddisorder=0
}
}
@@ -1442,7 +1573,7 @@ pktws_check_domain_http3_bypass_()
for fake in '' "--dpi-desync-fake-quic=$ZAPRET_BASE/files/fake/quic_initial_www_google_com.bin"; do
for rep in '' 2 5 10 20; do
pktws_curl_test_update $1 $2 --dpi-desync=fake ${fake:+$fake }${rep:+--dpi-desync-repeats=$rep} && [ "$SCANLEVEL" != force ] && {
pktws_curl_test_update $1 $2 --dpi-desync=fake ${fake:+"$fake" }${rep:+--dpi-desync-repeats=$rep} && [ "$SCANLEVEL" != force ] && {
[ "$SCANLEVEL" = quick ] && return
break
}
@@ -1568,7 +1699,7 @@ check_dpi_ip_block()
# $1 - test function
# $2 - domain
local blocked_dom=$2
local blocked_dom="$2"
local blocked_ip blocked_ips unblocked_ip
echo
@@ -1576,7 +1707,7 @@ check_dpi_ip_block()
echo "> testing $UNBLOCKED_DOM on it's original ip"
if curl_test $1 $UNBLOCKED_DOM; then
unblocked_ip=$(mdig_resolve $IPV $UNBLOCKED_DOM)
mdig_resolve $IPV unblocked_ip $UNBLOCKED_DOM
[ -n "$unblocked_ip" ] || {
echo $UNBLOCKED_DOM does not resolve. tests not possible.
return 1
@@ -1585,7 +1716,7 @@ check_dpi_ip_block()
echo "> testing $blocked_dom on $unblocked_ip ($UNBLOCKED_DOM)"
curl_test $1 $blocked_dom $unblocked_ip detail
blocked_ips=$(mdig_resolve_all $IPV $blocked_dom)
mdig_resolve_all $IPV blocked_ips $blocked_dom
for blocked_ip in $blocked_ips; do
echo "> testing $UNBLOCKED_DOM on $blocked_ip ($blocked_dom)"
curl_test $1 $UNBLOCKED_DOM $blocked_ip detail
@@ -1612,17 +1743,19 @@ check_domain_prolog()
local code
[ "$SIMULATE" = 1 ] && return 0
echo
echo \* $1 ipv$IPV $3
echo "- checking without DPI bypass"
curl_test $1 $3 && {
report_append "ipv${IPV} $3 $1 : working without bypass"
report_append "$3" "$1 ipv${IPV}" "working without bypass"
[ "$SCANLEVEL" = force ] || return 1
}
code=$?
curl_has_reason_to_continue $code || {
report_append "ipv${IPV} $3 $1 : test aborted, no reason to continue. curl code $(curl_translate_code $code)"
report_append "$3" "$1 ipv${IPV}" "test aborted, no reason to continue. curl code $(curl_translate_code $code)"
return 1
}
return 0
@@ -1634,6 +1767,8 @@ check_domain_http_tcp()
# $3 - encrypted test : 0 = plain, 1 - encrypted with server reply risk, 2 - encrypted without server reply risk
# $4 - domain
local ips
# in case was interrupted before
pktws_ipt_unprepare_tcp $2
ws_kill
@@ -1650,7 +1785,8 @@ check_domain_http_tcp()
[ "$SKIP_PKTWS" = 1 ] || {
echo
echo preparing $PKTWSD redirection
pktws_ipt_prepare_tcp $2 "$(mdig_resolve_all $IPV $4)"
mdig_resolve_all $IPV ips $4
pktws_ipt_prepare_tcp $2 "$ips"
pktws_check_domain_http_bypass $1 $3 $4
@@ -1664,6 +1800,8 @@ check_domain_http_udp()
# $2 - port
# $3 - domain
local ips
# in case was interrupted before
pktws_ipt_unprepare_udp $2
ws_kill
@@ -1673,7 +1811,8 @@ check_domain_http_udp()
[ "$SKIP_PKTWS" = 1 ] || {
echo
echo preparing $PKTWSD redirection
pktws_ipt_prepare_udp $2 "$(mdig_resolve_all $IPV $3)"
mdig_resolve_all $IPV ips $3
pktws_ipt_prepare_udp $2 "$ips"
pktws_check_domain_http3_bypass $1 $3
@@ -1732,6 +1871,9 @@ configure_curl_opt()
curl_supports_tls13 && TLS13=1
HTTP3=
curl_supports_http3 && HTTP3=1
HTTPS_HEAD=-I
[ "$CURL_HTTPS_GET" = 1 ] && HTTPS_HEAD=
}
linux_ipv6_defrag_can_be_disabled()
@@ -1792,7 +1934,7 @@ ask_params()
curl_supports_connect_to || {
echo "installed curl does not support --connect-to option. pls install at least curl 7.49"
echo "current curl version:"
$CURL --version
"$CURL" --version
exitp 1
}
@@ -1800,12 +1942,13 @@ ask_params()
[ -n "$DOMAINS" ] || {
DOMAINS="$DOMAINS_DEFAULT"
[ "$BATCH" = 1 ] || {
echo "specify domain(s) to test. multiple domains are space separated."
echo "specify domain(s) to test. multiple domains are space separated. URIs are supported (rutracker.org/forum/index.php)"
printf "domain(s) (default: $DOMAINS) : "
read dom
[ -n "$dom" ] && DOMAINS="$dom"
}
}
DOMAINS_COUNT="$(echo "$DOMAINS" | wc -w | trim)"
local IPVS_def=4
[ -n "$IPVS" ] || {
@@ -2046,7 +2189,7 @@ check_dns_()
if find_working_public_dns ; then
echo comparing system resolver to public DNS : $PUBDNS
for dom in $DNSCHECK_DOM; do
if check_dns_spoof $dom $PUBDNS ; then
if check_dns_spoof "$dom" $PUBDNS ; then
echo $dom : MISMATCH
echo -- system resolver :
cat "$DNSCHECK_DIG1"
@@ -2142,7 +2285,6 @@ sigsilent()
exit 1
}
fsleep_setup
fix_sbin_path
check_system
@@ -2185,6 +2327,18 @@ cleanup
echo
echo \* SUMMARY
report_print
[ "$DOMAINS_COUNT" -gt 1 ] && {
echo
echo \* COMMON
result_intersection_print
echo
[ "$SCANLEVEL" = force ] || {
echo "blockcheck optimizes test sequence. To save time some strategies can be skipped if their test is considered useless."
echo "That's why COMMON intersection can miss strategies that would work for all domains."
echo "Use \"force\" scan level to test all strategies and generate trustable intersection."
echo "Current scan level was \"$SCANLEVEL\"".
}
}
echo
echo "Please note this SUMMARY does not guarantee a magic pill for you to copy/paste and be happy."
echo "Understanding how strategies work is very desirable."
+40 -15
View File
@@ -4,6 +4,10 @@ which()
# '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"
@@ -93,6 +97,22 @@ trim()
{
awk '{gsub(/^ +| +$/,"")}1'
}
split_by_separator()
{
# $1 - string
# $2 - separator
# $3 - var name to get "before" part
# $4 - var name to get "after" part
local before="${1%%$2*}"
local after="${1#*$2}"
[ "$after" = "$1" ] && after=
[ -n "$3" ] && eval $3="\$before"
[ -n "$4" ] && eval $4="\$after"
}
tolower()
{
echo "$@" | tr 'A-Z' 'a-z'
}
dir_is_not_empty()
{
@@ -297,10 +317,10 @@ minsleep()
replace_char()
{
local a=$1
local b=$2
local a="$1"
local b="$2"
shift; shift
echo "$@" | tr $a $b
echo "$@" | tr "$a" "$b"
}
replace_str()
@@ -318,6 +338,12 @@ setup_md5()
exists $MD5 || MD5=md5
}
md5f()
{
setup_md5
$MD5 | cut -d ' ' -f1
}
setup_random()
{
[ -n "$RCUT" ] && return
@@ -330,7 +356,6 @@ random()
{
# $1 - min, $2 - max
local r rs
setup_md5
setup_random
if [ -c /dev/urandom ]; then
read rs </dev/urandom
@@ -338,7 +363,7 @@ random()
rs="$RANDOM$RANDOM$(date)"
fi
# shells use signed int64
r=1$(echo $rs | $MD5 | sed 's/[^0-9]//g' | $RCUT)
r=1$(echo $rs | md5f | sed 's/[^0-9]//g' | $RCUT)
echo $(( ($r % ($2-$1+1)) + $1 ))
}
@@ -406,12 +431,15 @@ has_bad_ws_options()
{
# $1 - nfqws/tpws opts
# kernel or user mode ipset usage should be wise
# if all traffic is already intercepted it would be OK to use ip-based specialized profiles
# but if all traffic is intercepted only to filter a group of ip its BAD. kernel ipset should be used.
# I cannot insert brain to copy-pasters, I know they will misuse. But it's their problem.
# zapret is not made for newbies
#contains "$1" "--ipset"
contains "$1" "--ipset" && {
echo
echo "WARNING !!! --ipset parameter is present"
echo "It's OK if you only specialize already redirected traffic and also process the rest."
echo "If you redirect port X to process several IPs from the list and do nothing with the rest - IT'S VERY INEFFECTIVE !"
echo "Kernel ipsets should be used instead. Write custom scripts and filter IPs in kernel."
echo
}
return 1
}
check_bad_ws_options()
@@ -428,8 +456,5 @@ check_bad_ws_options()
}
help_bad_ws_options()
{
echo "WARNING ! you have specified --ipset option"
echo "WARNING ! it would work but on ${UNAME:-$(uname)} it's not the best option"
echo "WARNING ! you should use kernel mode sets. they are much more efficient."
echo "WARNING ! to use ipsets you have to write your own custom script"
echo "WARNING ! BAD options detected"
}
+6 -7
View File
@@ -36,12 +36,11 @@ 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" ;}
n=1
for m in $2; do
echo $n : $m
@@ -53,6 +52,6 @@ ask_list()
[ -z "$M" ] && M="$M_DEFAULT"
echo selected : $M
eval $1="\"$M\""
[ "$M" != "$M_OLD" ]
[ "$M" != "$M_DEFAULT_VAR" ]
}
+14 -12
View File
@@ -187,7 +187,7 @@ check_system()
SYSTEM=
SUBSYS=
SYSTEMCTL=$(whichq systemctl)
SYSTEMCTL="$(whichq systemctl)"
get_fwtype
OPENWRT_FW3=
@@ -203,6 +203,7 @@ check_system()
# some distros include systemctl without systemd
if [ -d "$SYSTEMD_DIR" ] && [ -x "$SYSTEMCTL" ] && [ "$INIT" = "systemd" ]; then
SYSTEM=systemd
[ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions"
elif [ -f "/etc/openwrt_release" ] && exists opkg || exists apk && exists uci && [ "$INIT" = "procd" ] ; then
SYSTEM=openwrt
OPENWRT_PACKAGER=opkg
@@ -226,8 +227,10 @@ check_system()
OPENWRT_FW4=1
info="${info}firewall fw4. flow offloading requires nftables."
fi
[ -f "$EXEDIR/init.d/openwrt/functions" ] && . "$EXEDIR/init.d/openwrt/functions"
elif openrc_test; then
SYSTEM=openrc
[ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions"
else
echo system is not either systemd, openrc or openwrt based
echo easy installer can set up config settings but can\'t configure auto start
@@ -237,10 +240,12 @@ check_system()
else
exitp 5
fi
[ -f "$EXEDIR/init.d/sysv/functions" ] && . "$EXEDIR/init.d/sysv/functions"
fi
linux_get_subsys
elif [ "$UNAME" = "Darwin" ]; then
SYSTEM=macos
[ -f "$EXEDIR/init.d/macos/functions" ] && . "$EXEDIR/init.d/macos/functions"
else
echo easy installer only supports Linux and MacOS. check readme.md for supported systems and manual setup info.
exitp 5
@@ -251,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()
{
@@ -517,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"
@@ -698,7 +698,7 @@ removable_pkgs_openwrt()
for pkg in $PKGS2; do
check_package_exists_openwrt $pkg && PKGS="${PKGS:+$PKGS }$pkg"
done
PKGS="ipset iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra ip6tables-mod-nat ip6tables-extra kmod-nft-queue gzip coreutils-sort coreutils-sleep curl $PKGS"
PKGS="ipset iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra iptables-mod-u32 ip6tables-mod-nat ip6tables-extra kmod-nft-queue gzip coreutils-sort coreutils-sleep curl $PKGS"
}
openwrt_fix_broken_apk_uninstall_scripts()
@@ -739,7 +739,7 @@ check_prerequisites_openwrt()
iptables)
pkg_iptables=iptables
check_package_exists_openwrt iptables-zz-legacy && pkg_iptables=iptables-zz-legacy
PKGS="$PKGS ipset $pkg_iptables iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra"
PKGS="$PKGS ipset $pkg_iptables iptables-mod-extra iptables-mod-nfqueue iptables-mod-filter iptables-mod-ipopt iptables-mod-conntrack-extra iptables-mod-u32"
check_package_exists_openwrt ip6tables-zz-legacy && pkg_iptables=ip6tables-zz-legacy
[ "$DISABLE_IPV6" = 1 ] || PKGS="$PKGS $pkg_iptables ip6tables-mod-nat ip6tables-extra"
;;
@@ -827,20 +827,22 @@ 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_tpws_()
{
local TPWS="$ZAPRET_BASE/tpws/tpws"
echo verifying tpws options
"$TPWS" --dry-run "$@"
"$TPWS" --dry-run ${WS_USER:+--user=$WS_USER} "$@"
}
dry_run_nfqws_()
{
local NFQWS="$ZAPRET_BASE/nfq/nfqws"
echo verifying nfqws options
"$NFQWS" --dry-run "$@"
"$NFQWS" --dry-run ${WS_USER:+--user=$WS_USER} "$@"
}
dry_run_tpws()
{
+9 -5
View File
@@ -43,7 +43,7 @@ ipt6_add_del()
}
ipt6a_add_del()
{
on_off_function ipt6 ipt6a_del "$@"
on_off_function ipt6a ipt6_del "$@"
}
is_ipt_flow_offload_avail()
@@ -112,6 +112,10 @@ unprepare_tpws_fw()
unprepare_tpws_fw4
}
ipt_mark_filter()
{
[ -n "$FILTER_MARK" ] && echo "-m mark --mark $FILTER_MARK/$FILTER_MARK"
}
ipt_print_op()
{
@@ -136,7 +140,7 @@ _fw_tpws4()
ipt_print_op $1 "$2" "tpws (port $3)"
rule="$2 $IPSET_EXCLUDE dst $IPBAN_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3"
rule="$(ipt_mark_filter) $2 $IPSET_EXCLUDE dst $IPBAN_EXCLUDE dst -j DNAT --to $TPWS_LOCALHOST4:$3"
for i in $4 ; do
ipt_add_del $1 PREROUTING -t nat -i $i $rule
done
@@ -164,7 +168,7 @@ _fw_tpws6()
ipt_print_op $1 "$2" "tpws (port $3)" 6
rule="$2 $IPSET_EXCLUDE6 dst $IPBAN_EXCLUDE6 dst"
rule="$(ipt_mark_filter) $2 $IPSET_EXCLUDE6 dst $IPBAN_EXCLUDE6 dst"
for i in $4 ; do
_dnat6_target $i DNAT6
[ -n "$DNAT6" -a "$DNAT6" != "-" ] && ipt6_add_del $1 PREROUTING -t nat -i $i $rule -j DNAT --to [$DNAT6]:$3
@@ -202,7 +206,7 @@ _fw_nfqws_post4()
ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)"
rule="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK $2 $IPSET_EXCLUDE dst -j NFQUEUE --queue-num $3 --queue-bypass"
rule="$(ipt_mark_filter) -m mark ! --mark $DESYNC_MARK/$DESYNC_MARK $2 $IPSET_EXCLUDE dst -j NFQUEUE --queue-num $3 --queue-bypass"
if [ -n "$4" ] ; then
for i in $4; do
ipt_add_del $1 POSTROUTING -t mangle -o $i $rule
@@ -223,7 +227,7 @@ _fw_nfqws_post6()
ipt_print_op $1 "$2" "nfqws postrouting (qnum $3)" 6
rule="-m mark ! --mark $DESYNC_MARK/$DESYNC_MARK $2 $IPSET_EXCLUDE6 dst -j NFQUEUE --queue-num $3 --queue-bypass"
rule="$(ipt_mark_filter) -m mark ! --mark $DESYNC_MARK/$DESYNC_MARK $2 $IPSET_EXCLUDE6 dst -j NFQUEUE --queue-num $3 --queue-bypass"
if [ -n "$4" ] ; then
for i in $4; do
ipt6_add_del $1 POSTROUTING -t mangle -o $i $rule
+14 -8
View File
@@ -312,6 +312,10 @@ nft_filter_apply_ipset_target()
nft_filter_apply_ipset_target6 $2
}
nft_mark_filter()
{
[ -n "$FILTER_MARK" ] && echo "mark and $FILTER_MARK != 0"
}
nft_script_add_ifset_element()
{
@@ -403,9 +407,10 @@ _nft_fw_tpws4()
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
local filter="$1" port="$2"
local mark_filter=$(nft_mark_filter)
nft_print_op "$filter" "tpws (port $2)" 4
nft_insert_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif }$filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
nft_insert_rule dnat_pre iifname @lanif $filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
nft_insert_rule dnat_output skuid != $WS_USER ${3:+oifname @wanif} $mark_filter $filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
nft_insert_rule dnat_pre iifname @lanif $mark_filter $filter ip daddr != @nozapret ip daddr != @ipban $FW_EXTRA_POST dnat ip to $TPWS_LOCALHOST4:$port
prepare_route_localnet
}
}
@@ -418,10 +423,11 @@ _nft_fw_tpws6()
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" DNAT6 i
local mark_filter=$(nft_mark_filter)
nft_print_op "$filter" "tpws (port $port)" 6
nft_insert_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6 }$filter ip6 daddr != @nozapret6 ip6 daddr != @ipban6 $FW_EXTRA_POST dnat ip6 to [::1]:$port
nft_insert_rule dnat_output skuid != $WS_USER ${4:+oifname @wanif6} $mark_filter $filter ip6 daddr != @nozapret6 ip6 daddr != @ipban6 $FW_EXTRA_POST dnat ip6 to [::1]:$port
[ -n "$3" ] && {
nft_insert_rule dnat_pre $filter ip6 daddr != @nozapret6 ip6 daddr != @ipban6 $FW_EXTRA_POST dnat ip6 to iifname map @link_local:$port
nft_insert_rule dnat_pre $mark_filter $filter ip6 daddr != @nozapret6 ip6 daddr != @ipban6 $FW_EXTRA_POST dnat ip6 to iifname map @link_local:$port
for i in $3; do
_dnat6_target $i DNAT6
# can be multiple tpws processes on different ports
@@ -468,7 +474,7 @@ _nft_fw_nfqws_post4()
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" rule chain=$(get_postchain) setmark
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 4
rule="${3:+oifname @wanif }$filter ip daddr != @nozapret"
rule="${3:+oifname @wanif} $(nft_mark_filter) $filter ip daddr != @nozapret"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_insert_rule $chain $rule $setmark $CONNMARKER $FW_EXTRA_POST queue num $port bypass
nft_add_nfqws_flow_exempt_rule "$rule"
@@ -483,7 +489,7 @@ _nft_fw_nfqws_post6()
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" rule chain=$(get_postchain) setmark
nft_print_op "$filter" "nfqws postrouting (qnum $port)" 6
rule="${3:+oifname @wanif6 }$filter ip6 daddr != @nozapret6"
rule="${3:+oifname @wanif6} $(nft_mark_filter) $filter ip6 daddr != @nozapret6"
is_postnat && setmark="meta mark set meta mark or $DESYNC_MARK_POSTNAT"
nft_insert_rule $chain $rule $setmark $CONNMARKER $FW_EXTRA_POST queue num $port bypass
nft_add_nfqws_flow_exempt_rule "$rule"
@@ -508,7 +514,7 @@ _nft_fw_nfqws_pre4()
[ "$DISABLE_IPV4" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 4
rule="${3:+iifname @wanif }$filter ip saddr != @nozapret"
rule="${3:+iifname @wanif} $filter ip saddr != @nozapret"
nft_insert_rule $(get_prechain) $rule $CONNMARKER $FW_EXTRA_POST queue num $port bypass
}
}
@@ -521,7 +527,7 @@ _nft_fw_nfqws_pre6()
[ "$DISABLE_IPV6" = "1" -o -z "$1" ] || {
local filter="$1" port="$2" rule
nft_print_op "$filter" "nfqws prerouting (qnum $port)" 6
rule="${3:+iifname @wanif6 }$filter ip6 saddr != @nozapret6"
rule="${3:+iifname @wanif6} $filter ip6 saddr != @nozapret6"
nft_insert_rule $(get_prechain) $rule $CONNMARKER $FW_EXTRA_POST queue num $port bypass
}
}
-85
View File
@@ -1,85 +0,0 @@
apply_unspecified_desync_modes()
{
NFQWS_OPT_DESYNC_HTTP="${NFQWS_OPT_DESYNC_HTTP:-$NFQWS_OPT_DESYNC}"
NFQWS_OPT_DESYNC_HTTP_SUFFIX="${NFQWS_OPT_DESYNC_HTTP_SUFFIX:-$NFQWS_OPT_DESYNC_SUFFIX}"
NFQWS_OPT_DESYNC_HTTPS="${NFQWS_OPT_DESYNC_HTTPS:-$NFQWS_OPT_DESYNC}"
NFQWS_OPT_DESYNC_HTTPS_SUFFIX="${NFQWS_OPT_DESYNC_HTTPS_SUFFIX:-$NFQWS_OPT_DESYNC_SUFFIX}"
NFQWS_OPT_DESYNC_HTTP6="${NFQWS_OPT_DESYNC_HTTP6:-$NFQWS_OPT_DESYNC_HTTP}"
NFQWS_OPT_DESYNC_HTTP6_SUFFIX="${NFQWS_OPT_DESYNC_HTTP6_SUFFIX:-$NFQWS_OPT_DESYNC_HTTP_SUFFIX}"
NFQWS_OPT_DESYNC_HTTPS6="${NFQWS_OPT_DESYNC_HTTPS6:-$NFQWS_OPT_DESYNC_HTTPS}"
NFQWS_OPT_DESYNC_HTTPS6_SUFFIX="${NFQWS_OPT_DESYNC_HTTPS6_SUFFIX:-$NFQWS_OPT_DESYNC_HTTPS_SUFFIX}"
NFQWS_OPT_DESYNC_QUIC6="${NFQWS_OPT_DESYNC_QUIC6:-$NFQWS_OPT_DESYNC_QUIC}"
NFQWS_OPT_DESYNC_QUIC6_SUFFIX="${NFQWS_OPT_DESYNC_QUIC6_SUFFIX:-$NFQWS_OPT_DESYNC_QUIC_SUFFIX}"
}
get_nfqws_qnums()
{
# $1 - var name for ipv4 http
# $2 - var name for ipv4 https
# $3 - var name for ipv6 http
# $4 - var name for ipv6 https
local _qn _qns _qn6 _qns6
[ "$DISABLE_IPV4" = "1" ] || {
_qn=$QNUM
_qns=$_qn
[ "$NFQWS_OPT_DESYNC_HTTP $NFQWS_OPT_DESYNC_HTTP_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTPS $NFQWS_OPT_DESYNC_HTTPS_SUFFIX" ] || _qns=$(($QNUM+1))
}
[ "$DISABLE_IPV6" = "1" ] || {
_qn6=$(($QNUM+2))
_qns6=$(($QNUM+3))
[ "$DISABLE_IPV4" = "1" ] || {
if [ "$NFQWS_OPT_DESYNC_HTTP6 $NFQWS_OPT_DESYNC_HTTP6_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTP $NFQWS_OPT_DESYNC_HTTP_SUFFIX" ]; then
_qn6=$_qn;
elif [ "$NFQWS_OPT_DESYNC_HTTP6 $NFQWS_OPT_DESYNC_HTTP6_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTPS $NFQWS_OPT_DESYNC_HTTPS_SUFFIX" ]; then
_qn6=$_qns;
fi
if [ "$NFQWS_OPT_DESYNC_HTTPS6 $NFQWS_OPT_DESYNC_HTTPS6_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTP $NFQWS_OPT_DESYNC_HTTP_SUFFIX" ]; then
_qns6=$_qn;
elif [ "$NFQWS_OPT_DESYNC_HTTPS6 $NFQWS_OPT_DESYNC_HTTPS6_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTPS $NFQWS_OPT_DESYNC_HTTPS_SUFFIX" ]; then
_qns6=$_qns;
fi
}
[ "$NFQWS_OPT_DESYNC_HTTPS6 $NFQWS_OPT_DESYNC_HTTPS6_SUFFIX" = "$NFQWS_OPT_DESYNC_HTTP6 $NFQWS_OPT_DESYNC_HTTP6_SUFFIX" ] && _qns6=$_qn6;
}
if [ "$MODE_HTTP" = 1 ]; then
eval $1=$_qn
eval $3=$_qn6
else
eval $1=
eval $3=
fi
if [ "$MODE_HTTPS" = 1 ]; then
eval $2=$_qns
eval $4=$_qns6
else
eval $2=
eval $4=
fi
}
get_nfqws_qnums_quic()
{
# $1 - var name for ipv4 quic
# $2 - var name for ipv6 quic
local _qn _qn6
[ "$DISABLE_IPV4" = "1" ] || {
_qn=$(($QNUM+10))
}
[ "$DISABLE_IPV6" = "1" ] || {
_qn6=$(($QNUM+11))
[ "$DISABLE_IPV4" = "1" ] || {
if [ "$NFQWS_OPT_DESYNC_QUIC $NFQWS_OPT_DESYNC_QUIC_SUFFIX" = "$NFQWS_OPT_DESYNC_QUIC6 $NFQWS_OPT_DESYNC_QUIC6_SUFFIX" ]; then
_qn6=$_qn;
fi
}
}
if [ "$MODE_QUIC" = 1 ]; then
eval $1=$_qn
eval $2=$_qn6
else
eval $1=
eval $2=
fi
}
+6
View File
@@ -47,6 +47,12 @@ GZIP_LISTS=1
DESYNC_MARK=0x40000000
DESYNC_MARK_POSTNAT=0x20000000
# do not pass outgoing traffic to tpws/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
#FILTER_MARK=0x10000000
TPWS_SOCKS_ENABLE=0
# tpws socks listens on this port on localhost and LAN interfaces
TPPORT_SOCKS=987
+20 -2
View File
@@ -312,7 +312,7 @@ In OpenBSD default `tpws` bind is ipv6 only. To bind to ipv4 specify
Use `--bind-addr=0.0.0.0 --bind-addr=::` to achieve the same default bind as in
others OSes.
`tpws` for forwarded traffic only :
`tpws` for forwarded traffic only (OLDER OS versions):
`/etc/pf.conf`:
```
@@ -323,13 +323,31 @@ pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988
Then:
```
pfctl -f /etc/pf.conf
tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 --enable-pf
```
Its not clear how to do rdr-to outgoing traffic. I could not make route-to
scheme work. rdr-to support is done using /dev/pf, that's why transparent mode
requires root.
`tpws` for forwarded traffic only (NEWER OS versions):
```
pass on em1 inet proto tcp to port {80,443} divert-to 127.0.0.1 port 989
pass on em1 inet6 proto tcp to port {80,443} divert-to ::1 port 989
```
Then:
```
pfctl -f /etc/pf.conf
tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
```
tpws must be bound exactly to diverted IPs, not `0.0.0.0` or `::`.
It's also not clear how to divert connections from local system.
`dvtws` for all traffic:
`/etc/pf.conf`:
+30 -5
View File
@@ -19,7 +19,8 @@
* [pfsense](#pfsense)
* [OpenBSD](#openbsd)
* [tpws bind на ipv4](#tpws-bind-на-ipv4)
* [tpws для проходящего трафика](#tpws-для-проходящего-трафика)
* [tpws для проходящего трафика (старые системы)](#tpws-для-проходящего-трафика-старая-схема-не-работает-в-новых-версиях))
* [tpws для проходящего трафика (новые системы)](#tpws-для-проходящего-трафика-новые-системы))
* [Запуск dvtws](#запуск-dvtws)
* [Проблемы с badsum](#проблемы-с-badsum)
* [Особенность отправки fake пакетов](#особенность-отправки-fake-пакетов)
@@ -87,7 +88,7 @@ PF. Если в фаерволе есть правило divert, но на diver
отдельно для ipv4 и ipv6 и работают только с одной версией `ip` каждый. На
**MacOS** похоже, что divert сокеты из ядра вырезаны. См подробнее раздел про
**MacOS**. Отсылка в divert сокет работает аналогично отсылке через raw socket
на linux. Передается полностью IP фрейм, начиная с ip загловка. Эти особенности
на linux. Передается полностью IP фрейм, начиная с ip заголовка. Эти особенности
учитываются в `dvtws`.
### Lookup Tables
@@ -392,7 +393,11 @@ rdr pass on em1 inet6 proto tcp from any to any port = https -> fe80::20c:29ff:5
Но лучше все же так не делать, а сажать на определенные внутренние адреса или интерфейсы.
### tpws для проходящего трафика
### tpws для проходящего трафика (старая схема не работает в новых версиях)
В этом варианте tpws обращается явно к редиректору pf и пытается от него получить оригинальный адрес назначения.
Как показывает практика, это не работает на новых версиях OpenBSD. Возвращается ошибка ioctl.
Последняя проверенная версия, где это работает, - 6.8 . Между 6.8 и 7.4 разработчики сломали этот механизм.
`/etc/pf.conf`:
```
@@ -402,15 +407,35 @@ pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988
```sh
$ pfctl -f /etc/pf.conf
$ tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
$ tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 --enable-pf
```
> [!NOTE]
> [!NOTE]
> В PF не выходит делать rdr-to с той же системы, где работает proxy.
> Вариант с route-to не сохраняет мета информацию. Адрес назначения теряется.
> Поэтому этот вариант годится для squid, берущего адрес из протокола прикладного уровня, но не годится для tpws, полагающегося на метаданные ОС.
> Поддержка rdr-to реализована через `/dev/pf`, поэтому прозрачный режим **требует root**.
### tpws для проходящего трафика (новые системы)
В новых версиях предлагается использовать divert-to вместо rdr-to.
Минимально проверенная версия, где это работает, 7.4. Может работать или не работать на более старых - исследование не проводилось.
`/etc/pf.conf`:
```
pass on em1 inet proto tcp to port {80,443} divert-to 127.0.0.1 port 989
pass on em1 inet6 proto tcp to port {80,443} divert-to ::1 port 989
```
tpws должен иметь бинд на точно такой адрес, который указан в правилах pf. `0.0.0.0` или `::` не работает.
```sh
$ pfctl -f /etc/pf.conf
$ tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
```
> [!NOTE]
> Так же не понятно как делать divert с самой системы, где работает tpws.
### Запуск dvtws
+13
View File
@@ -56,14 +56,27 @@ sysctl net.inet6.ip6.forwarding=1
OpenBSD PF :
(OLD OpenBSD versions)
; dont know how to rdr-to from local system. doesn't seem to work. only works for routed traffic.
/etc/pf.conf
pass in quick on em1 inet proto tcp to port {80,443} rdr-to 127.0.0.1 port 988
pass in quick on em1 inet6 proto tcp to port {80,443} rdr-to ::1 port 988
pfctl -f /etc/pf.conf
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1 --enable-pf
(NEW OpenBSD versions)
; dont know how to divert-to from local system
/etc/pf.conf
pass on em1 inet proto tcp to port {80,443} divert-to 127.0.0.1 port 989
pass on em1 inet6 proto tcp to port {80,443} divert-to ::1 port 989
pfctl -f /etc/pf.conf
/opt/zapret/tpws/tpws --port=988 --user=daemon --bind-addr=::1 --bind-addr=127.0.0.1
; dvtws works both for routed and local
pass in quick on em0 proto tcp from port {80,443} flags SA/SA divert-packet port 989 no state
+116
View File
@@ -502,3 +502,119 @@ init.d, blockcheck: drop time exceeded icmp for nfqws-related connections
blockcheck: some dup and orig-ttl mods
blockcheck: PKTWS_EXTRA_PRE
blockcheck: report test function and domain every test
v71.1
nfqws,tpws: much faster ipset implementation. move from hash to avl tree
nfqws,tpws: check list files accessibility with dropped privs in --dry-run mode
nfqws,tpws: --debug=android for NDK builds
nfqws,tpws: use initgroups instead of setgroups if --user specified
nfqws: --filter-ssid (linux-only)
install_easy: stop if running embedded release on traditional linux system (some files missing)
install_bin: add "read elf" arch detection method
binaries: renamed arch dirs in binaries
v71.1.1
nfqws: use wireless ext in case nl80211 does not return SSID
v71.2
nfqws: apply udp desync to replayed packets with non-zero reasm offset (except fake)
blockcheck: display curl version and kernel version
install_bin: stop if no binaries found. display help text.
winws: increase buffers for port filter
tpws: tpws no more opens /dev/pf in OpenBSD by default. requires --enable-pf like in FreeBSD. this is migration from rdr-to to divert-to redirection scheme.
install_easy: warn if --ipset parameter is specified
v71.3
init.d: FILTER_MARK
nfqws: ts fooling
blockcheck: test ts fooling
blockcheck: auto enable tcp timestamps in windows
tpws,nfqws: special handling of IP-like hostnames. strip :port from hostname:port
v71.4
nfqws,tpws: fix possible crashes or high memory usage if hostlist has duplicate hostnames
init.d: custom scripts 50-discord-media, 50-stun4all
init.d: windivert filters for discord media, stun, wireguard
readme: hardware problems description
v72
winws: --wf-raw-part
nfqws: --dpi-desync=hostfakesplit
nfqws: --dpi-desync-fake-tcp-mod=seq
nfqws: --dpi-desync-fake-tls=!+offset , --dpi-desync-fake-xxx=[+offset]@filename
nfqws: --dpi-desync-fakedsplit-mod=altorder for fakedsplit/fakeddisorder
nfqws: --dpi-desync-hostfakesplit-mod=altorder
nfqws: fakedsplit/fakeddisorder normalize fake split pattern offset to reasm offset
nfqws: optimize ipv4 ip_id. apply ip_id on all OS the same way.
blockcheck: print PRETTY_NAME and some OPENWRT_xxx from /etc/os-release
blockcheck: new strategies
blockcheck: curl test simulation : SIMULATE=1
v72.1
nfqws: --ip-id=seq|seqgroup|rnd|zero
blockcheck: MIN_AUTOTTL_DELTA,MAX_AUTOTTL_DELTA
init.d: 50-quic4all custom
72.2
nfqws: --wssize-forced-cutoff
nfqws: --orig-tcp-flags, --dup-tcp-flags, --dpi-desync-tcp-flags
nfqws: --dup-ip-id
72.3
blockcheck: support URIs
blockcheck: CURL_HTTPS_GET=1 suppresses -I curl option for https (HEAD -> GET)
72.4
blockcheck: fix broken dns cache
72.5
nfqws: fix broken l7proto profile rediscovery
nfqws: backport from nfqws2 nl80211 ssid discovery fix for newer kernels
72.6
ipset: remove zapret-info based scripts because it's gone
blockcheck: fix tpws test regression
72.7
nfqws,tpws: memleak fix
mdig: --eagain, --eagain-delay
72.8
nfqws: fix breaking tcp if ts fooling is enabled but no timestamps present
72.9
blockcheck: fix detection of http redirection if domain/URI specified
install_easy: fix writing of ask_list variables
72.10
* nfqws2: fix broken wifi ssid update
* minor AI fixes
72.12
* github: reduce binaries size
* github: use 16K page size for android arm64 build
* nfqws: join fragments in quic CRYPTO reconstruction. allow intersections.
72.13
* github: compile armv6. fix idiv illegal instruction on early armv7
* init.d: add port range for discord media
* init.d: remove KillMode=none in systemd unit
+1 -1
View File
@@ -1,6 +1,6 @@
debian,ubuntu :
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libsystemd-dev
apt install make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libmnl-dev libsystemd-dev
make -C /opt/zapret systemd
FreeBSD :
@@ -12,7 +12,7 @@ define Package/nfqws
CATEGORY:=Network
TITLE:=nfqws
SUBMENU:=Zapret
DEPENDS:=+libnetfilter-queue +libcap +zlib
DEPENDS:=+libnetfilter-queue +lmnl +libcap +zlib
endef
define Build/Prepare
+2 -2
View File
@@ -35,7 +35,7 @@ Swap позволяет немного сгладить проблему, но
Например, есть 1 большой set на 100000 элементов и 1 маленький на 2 элемента.
Чтобы просто пролистать мелкий set или добавить туда еще что-то nft будет мусолить несколько секунд.
Что он делает за это время ? Тащит из ядра огромный блоб, в котором все в куче, и разбирает его, чтобы выделить искомую мелочь ?
В какой-то мере удается это сгладить, обьединяя несколько команд в единый скрипт.
В какой-то мере удается это сгладить, объединяя несколько команд в единый скрипт.
Боль N3
@@ -100,7 +100,7 @@ zapret может работать в другой таблице и не тро
Плюс N5
Пишут, что nftables работают быстрее. Но это не точно и зависит от много чего.
В целом - чем меньше правил, тем выше скорость. Но в nftables правил можно писать меньше, значит скрость тоже может быть выше.
В целом - чем меньше правил, тем выше скорость. Но в nftables правил можно писать меньше, значит скорость тоже может быть выше.
У разработчиков есть идея перевести backend nftables на BPF, а это наверняка будет существенно быстрее.
+35 -22
View File
@@ -16,7 +16,7 @@
в простыню [readme.md](readme.md).
Обход DPI является хакерской методикой. Под этим словом понимается метод,
которому сопротивляется окружающая среда, которому автоматически не
которому оказывается активное противодействие и поэтому автоматически не
гарантирована работоспособность в любых условиях и на любых ресурсах, требуется
настройка под специфические условия у вашего провайдера. Условия могут меняться
со временем, и методика может начинать или переставать работать, может
@@ -52,6 +52,18 @@
1. Скачайте последний [tar.gz релиз](https://github.com/bol-van/zapret/releases) в /tmp, распакуйте его, затем удалите архив.
Для openwrt и прошивок используйте вариант `openwrt-embedded`.
Для экономия места в /tmp можно качать через curl в stdout и сразу распаковывать.
Пример под openwrt для версии zapret 71.4 (для других URL отличается) :
```
$ curl -Lo - https://github.com/bol-van/zapret/releases/download/v71.4/zapret-v71.4-openwrt-embedded.tar.gz | tar -zx
$ wget -O - https://github.com/bol-van/zapret/releases/download/v71.4/zapret-v71.4-openwrt-embedded.tar.gz | tar -zx
```
Пример под традиционный linux для версии zapret 71.4 (для других URL отличается) :
```
$ curl -Lo - https://github.com/bol-van/zapret/releases/download/v71.4/zapret-v71.4.tar.gz | tar -zx
$ wget -O - https://github.com/bol-van/zapret/releases/download/v71.4/zapret-v71.4.tar.gz | tar -zx
```
curl должен быть предварительно установлен. Но он в любом случае понадобится далее.
Вариант с wget будет работать только если установленный wget поддерживает https.
2. Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и
сам zapret. Гарантированно уберет zapret скрипт `uninstall_easy.sh`.
@@ -129,10 +141,14 @@
или `tpws` и запомнить найденные стратегии для дальнейшего применения.
Следует понимать, что скрипт проверяет доступность только конкретного
домена, который вы вводите в начале. Вероятно, все остальные домены
блокированы подобным образом, **но не факт**. В большинстве случаев можно
объединить несколько стратегий в одну универсальную, и это **крайне
желательно**. Необходимо понимать как работают стратегии. zapret **не может
домена, который вы вводите в начале, конкретной программой curl.
У разных клиентов есть свой фингерпринт. У броузеров один, у curl другой.
Может применяться или не применяться многопакетный TLS с постквантовой криптографией (kyber).
От этого может зависеть работоспособность стратегий.
Обычно остальные домены блокированы подобным образом, **но не факт**.
Бывают специальные блокировки. Некоторые параметры требуют тюнинга под "общий знаменатель".
В большинстве случаев можно объединить несколько стратегий в одну универсальную, и это **крайне
желательно**, но это требует понимания как работают стратегии. zapret **не может
пробить блокировку по IP адресу**. Для проверки нескольких доменов вводите
их через пробел.
@@ -143,19 +159,7 @@
> направления (IP сервера). скрипт не всегда может выдать вам в итогах
> оптимальную стратегию, которую надо просто переписать в настройки. В
> некоторых случаях надо реально думать что происходит, анализируя результат
> на разных стратегиях. Если вы применяете большой TTL, чтобы достать до
> магистрала, то не лишним будет добавить дополнительный ограничитель
> `--dpi-desync-fooling`, чтобы не сломать сайты на более коротких
> дистанциях. `md5sig` наиболее совместим, но работает **только** на linux
> серверах. `badseq` может работать только на https и не работать на http.
> Чтобы выяснить какие дополнительные ограничители работают, смотрите
> результат теста аналогичных стратегий без TTL с каждым из этих
> ограничителей.
>
> При использовании `autottl` следует протестировать как можно больше разных
> доменов. Эта техника может на одних провайдерах работать стабильно, на
> других потребуется выяснить при каких параметрах она стабильна, на третьих
> полный хаос, и проще отказаться.
> на разных стратегиях.
>
> Далее, имея понимание что работает на http, https, quic нужно
> сконструировать параметры запуска `tpws` и/или `nfqws` с использованием
@@ -189,9 +193,9 @@
> профилях автоматически отражаются во всех остальных.
>
> Если стратегии отличаются по версии ip протокола, и вы не можете их
> обьединить, фильтр пишется так:
> объединить, фильтр пишется так:
> ```sh
> "--filter-l3=ipv4 --filter-udp=443 lпараметры для quic ipv4' <HOSTLIST_NOAUTO> --new
> "--filter-l3=ipv4 --filter-udp=443 'параметры для quic ipv4' <HOSTLIST_NOAUTO> --new
> --filter-l3=ipv4 --filter-tcp=80 'параметры для http ipv4' <HOSTLIST> --new
> --filter-l3=ipv4 --filter-tcp=443 'параметры для https ipv4' <HOSTLIST> --new
> --filter-l3=ipv6 --filter-udp=443 'параметры для quic ipv6' <HOSTLIST_NOAUTO> --new
@@ -202,8 +206,8 @@
> Но здесь совсем "копи-пастный" вариант. Чем больше вы объедините стратегий и
> сократите их общее количество, тем будет лучше.
>
> Если вам не нужно дурение отдельных протоколов, лучше всего будет их
> убрать из системы перехвата трафика через параметры `TPWS_PORTS`,
> Если вам не нужно дурение отдельных протоколов, лучше всего будет убрать
> лишние порты из системы перехвата трафика через параметры `TPWS_PORTS`,
> `NFQWS_PORTS_TCP`, `NFQWS_PORTS_UDP` и убрать соответствующие им профили
> мультистратегии.
>
@@ -230,6 +234,15 @@
> В этом примере `wssize` будет применяться всегда к порту tcp `443` вне
> зависимости от параметра `MODE_FILTER`. Хостлист будет игнорироваться,
> если таковой имеется. К http применять `wssize` вредно и бессмысленно.
>
> Иногда требуется дописать к стратегиям свои собственные параметры.
> Например, нужно изменить количество повторов фейков или задать свой фейк.
> Это делается через шелл-переменные `PKTWS_EXTRA`, `TPWS_EXTRA`.
>
> ```PKTWS_EXTRA="--dpi-desync-repeats=10 --dpi-desync-fake-tls=/tmp/tls.bin" ./blockcheck.sh```
>
> Перебор всех комбинаций может привести к ожиданию неделями, поэтому выбран разумный
> костяк проверки, на который вы можете навешивать свои кустомизации.
7. Запустите скрипт облегченной установки - `install_easy.sh` Выберите `nfqws`
и/или `tpws`, затем согласитесь на редактирование параметров. Откроется
+60 -71
View File
@@ -11,8 +11,8 @@
## Немного разъяснений
Обход DPI является хакерской методикой. Под этим словом понимается метод, которому сопротивляется окружающая среда,
которому автоматически не гарантирована работоспособность в любых условиях и на любых ресурсах,
Обход DPI является хакерской методикой. Под этим словом понимается метод, которому оказывается активное противодействие и поэтому
автоматически не гарантирована работоспособность в любых условиях и на любых ресурсах,
требуется настройка под специфические условия у вашего провайдера. Условия могут меняться со временем,
и методика может начинать или переставать работать, может потребоваться повторный анализ ситуации.
Могут обнаруживаться отдельные ресурсы, которые заблокированы иначе, и которые не работают или перестали работать.
@@ -30,24 +30,7 @@
Будем считать, что у вас есть windows 7 или выше. Задача - обойти блокировки с самой системы.
> [!NOTE]
> Есть решение самое простое, а есть "как положено".
## САМОЕ ПРОСТОЕ РЕШЕНИЕ
_"Совсем ничего не могу, все очень сложно, дайте мне таблетку."_ ©Простой пользователь
1) Скачайте и распакуйте архив https://github.com/bol-van/zapret-win-bundle/archive/refs/heads/master.zip.
2) Запустите `zapret-winws/preset_russia.cmd` от имени администратора. Возможно, заведется сразу.
> То же самое с ограничителем по автоматически создаваемому хост-листу `preset_russia_autohostlist.cmd`.
> Что такое `autohostlist` - читайте [readme.md](./readme.md). Проще говоря, мы обходим только то, что долго и упорно не хочет открываться.
> Сначала не будет, но надо пытаться много раз, и тогда сработает, а дальше будет всегда срабатывать.
> Остальное не будет ломаться. Использовать только, если первый вариант тоже работает.
Не помогла _"таблетка"_ ? Это вовсе не значит, что ничего не получится. Но придется делать по нормальному.
## НЕ ПОМОГЛО, КАК ТЕПЕРЬ ЭТО УДАЛИТЬ
## Я ЧТО-ТО ДЕЛАЛ, НЕ ПОМОГЛО, КАК ТЕПЕРЬ ЭТО УДАЛИТЬ
Если вы не устанавливали zapret как службу или запланированную задачу (а это требует редактирования cmd файлов),
достаточно закрыть окно с winws и запустить windivert_delete.cmd.
@@ -55,14 +38,17 @@ _"Совсем ничего не могу, все очень сложно, да
После чего можно удалить папку с zapret. На этом деинсталляция закончена.
Если же вы устанавливали zapret как службу, то вы наверняка знаете как ее удалить.
## РЕШЕНИЕ "КАК ПОЛОЖЕНО"
Если вдруг среди того, на что вы нажимали, есть слова "general", "alt", ".bat", "автозапуск", или же есть файлы, которые отсутствуют
в оригинальных репозиториях, то это сборка. Вы не получите ответа как ее удалить от разработчика zapret.
Спрашивайте самих сборщиков. Разработчик не предоставляет простого решения, этим занимаются сборщики, но они и сами отвечают за свои продукты.
1) Скачайте и распакуйте архив https://github.com/bol-van/zapret-win-bundle/archive/refs/heads/master.zip.
## Настройка
2) Если у вас Windows 7 x64, однократно запустите `win7/install_win7.cmd`. Батник заменит файлы windivert на совместимую с Windows 7 версию.
1. Скачайте и распакуйте архив https://github.com/bol-van/zapret-win-bundle/archive/refs/heads/master.zip.
> [!WARNING]
> Для 32-битных систем Windows нет готового полного варианта.
2. Если у вас Windows 7 x64, однократно запустите `win7/install_win7.cmd`. Батник заменит файлы windivert на совместимую с Windows 7 версию.
> Для 32-битных систем Windows нет готового полного варианта.
> На windows 11 arm64 выполните `arm64/install_arm64.cmd` от имени администратора и перезагрузите компьютер.
> Читайте [docs/windows.md](./windows.md)
@@ -72,15 +58,15 @@ _"Совсем ничего не могу, все очень сложно, да
> более-менее научились с ним дружить.
> Если проблема имеет место , используйте исключения. Если не помогает - отключайте антивирус совсем.
3) Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и сам zapret.
3. Убедитесь, что у вас отключены все средства обхода блокировок, в том числе и сам zapret.
4) Если вы работаете в виртуальной машине, необходимо использовать соединение с сетью в режиме bridge. nat не подходит
4. Если вы работаете в виртуальной машине, необходимо использовать соединение с сетью в режиме bridge. nat не подходит
5) Запустите `blockcheck\blockcheck.cmd`. blockcheck в начале проверяет **DNS**.
Если выводятся сообщения о подмене адресов, то нужно будет решить проблему с **DNS**.
blockcheck перейдет в этом случае на **DoH** _(DNS over HTTPS)_ и будет пытаться получить и использовать реальные IP адреса.
Но если вы не настроите решение этой проблемы, обход будет работать только для тех программ,
которые сами реализуют механизмы SecureDNS. Для других программ обход работать не будет.
5. Запустите `blockcheck\blockcheck.cmd`. blockcheck в начале проверяет **DNS**.
Если выводятся сообщения о подмене адресов, то нужно будет решить проблему с **DNS**.
blockcheck перейдет в этом случае на **DoH** _(DNS over HTTPS)_ и будет пытаться получить и использовать реальные IP адреса.
Но если вы не настроите решение этой проблемы, обход будет работать только для тех программ,
которые сами реализуют механизмы SecureDNS. Для других программ обход работать не будет.
> Решение проблемы DNS выходит за рамки проекта. Обычно она решается либо заменой DNS серверов
> от провайдера на публичные (`1.1.1.1`, `8.8.8.8`), либо в случае перехвата провайдером обращений
@@ -92,35 +78,29 @@ blockcheck перейдет в этом случае на **DoH** _(DNS over HTT
>
> Тут все разжевано как и где это включается : https://hackware.ru/?p=13707
6) blockcheck позволяет выявить рабочую стратегию обхода блокировок.
Лог скрипта будет сохранен в `blockcheck\blockcheck.log`.
Запомните/перепишите найденные стратегии.
6. blockcheck позволяет выявить рабочую стратегию обхода блокировок.
Лог скрипта будет сохранен в `blockcheck\blockcheck.log`.
Запомните/перепишите найденные стратегии.
> [!WARNING]
> Следует понимать, что blockcheck проверяет доступность только конкретного домена, который вы вводите в начале.
> Вероятно, все остальные домены блокированы подобным образом, но не факт.
Следует понимать, что скрипт проверяет доступность только конкретного
домена, который вы вводите в начале, конкретной программой curl.
У разных клиентов есть свой фингерпринт. У броузеров один, у curl другой.
Может применяться или не применяться многопакетный TLS с постквантовой криптографией (kyber).
От этого может зависеть работоспособность стратегий.
Обычно остальные домены блокированы подобным образом, **но не факт**.
Бывают специальные блокировки. Некоторые параметры требуют тюнинга под "общий знаменатель".
В большинстве случаев можно объединить несколько стратегий в одну универсальную, и это **крайне
желательно**, но это требует понимания как работают стратегии. zapret **не может
пробить блокировку по IP адресу**. Для проверки нескольких доменов вводите их через пробел.
> [!TIP]
> В большинстве случаев можно обьединить несколько стратегий в одну универсальную, и это крайне желательно.
> Необходимо понимать [как работают стратегии](./readme.md/#nfqws).
> zapret не может пробить блокировку по IP адресу. Для проверки нескольких доменов вводите их через пробел.
>
> Сейчас блокираторы ставят на магистральных каналах. В сложных случаях у вас может быть несколько маршрутов
> с различной длиной по ХОПам, с DPI на разных хопах. Приходится преодолевать целый зоопарк DPI,
> которые еще и включаются в работу хаотичным образом или образом, зависящим от направления (IP сервера).
> blockcheck не всегда может выдать вам в итогах оптимальную стратегию, которую надо просто переписать в настройки.
> В некоторых случаях надо реально думать что происходит, анализируя результат на разных стратегиях.
> Если вы применяете большой TTL, чтобы достать до магистрала, то не лишним будет добавить дополнительный ограничитель
> `--dpi-desync-fooling`, чтобы не сломать сайты на более коротких дистанциях.
> _md5sig_ наиболее совместим, но работатет только на linux серверах.
> badseq может работать только на https и не работать на http.
> Чтобы выяснить какие дополнительные ограничители работают, смотрите результат теста аналогичных стратегий без TTL
> с каждым из этих ограничителей.
>
> При использовании autottl следует протестировать как можно больше разных доменов. Эта техника
> может на одних провайдерах работать стабильно, на других потребуется выяснить при каких параметрах
> она стабильна, на третьих полный хаос, и проще отказаться.
> Сейчас блокираторы ставят на магистральных каналах. В сложных случаях у
> вас может быть несколько маршрутов с различной длиной по ХОПам, с DPI на
> разных хопах. Приходится преодолевать целый зоопарк DPI, которые еще и
> включаются в работу хаотичным образом или образом, зависящим от
> направления (IP сервера). скрипт не всегда может выдать вам в итогах
> оптимальную стратегию, которую надо просто переписать в настройки. В
> некоторых случаях надо реально думать что происходит, анализируя результат
> на разных стратегиях.
>
> Далее, имея понимание что работает на http, https, quic, нужно сконструировать параметры запуска winws
> с использованием мультистратегии. Как работают мультистратегии описано в [readme.md](./readme.md#множественные-стратегии).
@@ -137,7 +117,7 @@ blockcheck перейдет в этом случае на **DoH** _(DNS over HTT
> Если кратко по мультистратегии, то обычно параметры конструируются так :
> ```
> --filter-udp=443 'параметры для quic' --new
> --filter-tcp=80,443 'обьединенные параметры для http и https'
> --filter-tcp=80,443 'объединенные параметры для http и https'
> ```
>
> Или так :
@@ -147,7 +127,7 @@ blockcheck перейдет в этом случае на **DoH** _(DNS over HTT
> --filter-tcp=443 'параметры для https'
> ```
>
> Если стратегии отличаются по версии ip протокола, и вы не можете их обьединить, фильтр пишется так :
> Если стратегии отличаются по версии ip протокола, и вы не можете их объединить, фильтр пишется так :
> ```
> --filter-l3=ipv4 --filter-udp=443 "параметры для quic ipv4" --new
> --filter-l3=ipv4 --filter-tcp=80 'параметры для http ipv4' --new
@@ -183,12 +163,21 @@ blockcheck перейдет в этом случае на **DoH** _(DNS over HTT
>
> В этих примерах wssize будет применяться всегда к порту tcp 443, а хостлист будет игнорироваться.
> К http применять wssize вредно и бессмысленно.
>
> Иногда требуется дописать к стратегиям свои собственные параметры.
> Например, нужно изменить количество повторов фейков или задать свой фейк.
> Это делается через шелл-переменные `PKTWS_EXTRA`, `TPWS_EXTRA`. Пользуйтесь шеллом `cygwin/cygwin-admin.cmd`.
>
> ```PKTWS_EXTRA="--dpi-desync-repeats=10 --dpi-desync-fake-tls=/tmp/tls.bin" blockcheck```
>
> Перебор всех комбинаций может привести к ожиданию неделями, поэтому выбран разумный
> костяк проверки, на который вы можете навешивать свои кустомизации.
7) Протестируйте найденные стратегии на winws. Winws следует брать из zapret-winws.
Для этого откройте командную строку windows от имени администратора в директории zapret-winws.
Проще всего это сделать через `_CMD_ADMIN.cmd`. Он сам поднимет права и зайдет в нужную директорию.
7. Протестируйте найденные стратегии на winws. Winws следует брать из zapret-winws.
Для этого откройте командную строку windows от имени администратора в директории zapret-winws.
Проще всего это сделать через `_CMD_ADMIN.cmd`. Он сам поднимет права и зайдет в нужную директорию.
8) Обеспечьте удобную загрузку обхода блокировок.
8. Обеспечьте удобную загрузку обхода блокировок.
> Есть 2 варианта. Ручной запуск через ярлык или автоматический при старте системы, вне контекста текущего пользователя.
> Последний вариант разделяется на запуск через планировщик задач и через службы windows.
@@ -203,14 +192,14 @@ blockcheck перейдет в этом случае на **DoH** _(DNS over HTT
>
> Аналогично настраиваются и службы windows. Смотрите `service_*.cmd`
9) Если ломаются отдельные незаблокированные ресурсы, нужно пользоваться ограничивающим
ipset или хост листом. Читайте основной талмуд [readme.md](./readme.md) ради подробностей.
Но еще лучше будет подбирать такие стратегии, которые ломают минимум.
Есть стратегии довольно безобидные, а есть сильно ломающие, которые подходят только для точечного пробития отдельных ресурсов,
когда ничего лучше нет. Хорошая стратегия может сильно ломать из-за плохо подобранных ограничителей для фейков - ttl, fooling.
9. Если ломаются отдельные незаблокированные ресурсы, нужно пользоваться ограничивающим
ipset или хост листом. Читайте основной талмуд [readme.md](./readme.md) ради подробностей.
Но еще лучше будет подбирать такие стратегии, которые ломают минимум.
Есть стратегии довольно безобидные, а есть сильно ломающие, которые подходят только для точечного пробития отдельных ресурсов,
когда ничего лучше нет. Хорошая стратегия может сильно ломать из-за плохо подобранных ограничителей для фейков - ttl, fooling.
> [!CAUTION]
> Это минимальная инструкция, чтобы соориентироваться с чего начать. Однако, это - не панацея.
> Это минимальная инструкция, чтобы сориентироваться с чего начать. Однако, это - не панацея.
> В некоторых случаях вы не обойдетесь без знаний и основного "талмуда".
Подробности и полное техническое описание расписаны в [readme.md](./readme.md)
+252 -107
View File
@@ -1,11 +1,14 @@
# zapret v71
# SCAMMER WARNING
This software is free and open source under [MIT license](./LICENSE.txt).
If anyone demands you to download this software only from their webpage, telegram channel, forces you to delete links, videos, makes copyright claims, you are dealing with scammers.
However, [donations](#donations) are welcome.
# zapret2
zapret 1 is EOL (End-Of-Life). Will be no more new features, no PR will be accepted.
Current version is [zapret2](https://github.com/bol-van/zapret2).
# Multilanguage/Мультиязычный README
___
[![en](https://img.shields.io/badge/lang-en-red.svg)](https://github.com/bol-van/zapret/tree/master/docs/readme.en.md)
@@ -23,6 +26,7 @@ ___
- [Fake mods](#fake-mods)
- [TCP segmentation](#tcp-segmentation)
- [Sequence numbers overlap](#sequence-numbers-overlap)
- [IP_ID assignment](#ip_id-assignment)
- [ipv6 specific modes](#ipv6-specific-modes)
- [Original modding](#original-modding)
- [Duplicates](#duplicates)
@@ -35,6 +39,7 @@ ___
- [UDP support](#udp-support)
- [IP fragmentation](#ip-fragmentation)
- [Multiple strategies](#multiple-strategies)
- [WIFI filtering](#wifi-filtering)
- [Virtual machines](#virtual-machines)
- [IPTABLES for nfqws](#iptables-for-nfqws)
- [NFTABLES for nfqws](#nftables-for-nfqws)
@@ -135,106 +140,126 @@ For BSD systems there is dvtws. Its built from the same source and has almost th
nfqws takes the following parameters:
```
@<config_file> ; read file for options. must be the only argument. other options are ignored.
@<config_file> ; read file for options. must be the only argument. other options are ignored.
--debug=0|1
--dry-run ; verify parameters and exit with code 0 if successful
--version ; print version and exit
--comment ; any text (ignored)
--dry-run ; verify parameters and exit with code 0 if successful
--version ; print version and exit
--comment ; any text (ignored)
--qnum=<nfqueue_number>
--daemon ; daemonize
--pidfile=<filename> ; write pid to file
--user=<username> ; drop root privs
--uid=uid[:gid1,gid2,...] ; drop root privs
--bind-fix4 ; apply outgoing interface selection fix for generated ipv4 packets
--bind-fix6 ; apply outgoing interface selection fix for generated ipv6 packets
--wsize=<window_size>[:<scale_factor>] ; set window size. 0 = do not modify. OBSOLETE !
--wssize=<window_size>[:<scale_factor>] ; set window size for server. 0 = do not modify. default scale_factor = 0.
--wssize-cutoff=[n|d|s]N ; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--ctrack-timeouts=S:E:F[:U] ; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default 60:300:60:60
--ctrack-disable=[0|1] ; 1 or no argument disables conntrack
--ipcache-lifetime=<int> ; time in seconds to keep cached hop count and domain name (default 7200). 0 = no expiration
--ipcache-hostname=[0|1] ; 1 or no argument enables ip->hostname caching
--hostcase ; change Host: => host:
--hostspell ; exact spelling of "Host" header. must be 4 chars. default is "host"
--hostnospace ; remove space after Host: and add it to User-Agent: to preserve packet size
--domcase ; mix domain case : Host: TeSt.cOm
--methodeol ; add '\n' before method and remove space after Host:
--synack-split=[syn|synack|acksyn] ; perform TCP split handshake : send SYN only, SYN+ACK or ACK+SYN
--orig-ttl=<int> ; set TTL for original packets
--orig-ttl6=<int> ; set ipv6 hop limit for original packets. by default ttl value is used
--orig-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: +5:3-64. "0:0-0" or "-" disables autottl.
--orig-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --orig-autottl for ipv6 only
--orig-mod-start=[n|d|s]N ; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
--orig-mod-cutoff=[n|d|s]N ; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--dup=<int> ; duplicate original packets. send N dups before original.
--dup-replace=[0|1] ; 1 or no argument means do not send original, only dups
--dup-ttl=<int> ; set TTL for dups
--dup-ttl6=<int> ; set ipv6 hop limit for dups. by default ttl value is used
--dup-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: -1:3-64. "0:0-0" or "-" disables autottl.
--dup-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --dup-autottl for ipv6 only
--dup-fooling=<mode>[,<mode>] ; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2
--dup-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment for dup. default -10000
--dup-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment for dup. default -66000
--dup-start=[n|d|s]N ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
--dup-cutoff=[n|d|s]N ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; override fwmark for desync packet. default = 0x40000000 (1073741824)
--dpi-desync-ttl=<int> ; set ttl for desync packet
--dpi-desync-ttl6=<int> ; set ipv6 hop limit for desync packet. by default ttl value is used.
--dpi-desync-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: -1:3-20. "0:0-0" or "-" disables autottl.
--dpi-desync-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --dpi-desync-autottl for ipv6 only
--dpi-desync-fooling=<mode>[,<mode>] ; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2
--dpi-desync-repeats=<N> ; send every desync packet N times
--dpi-desync-skip-nosni=0|1 ; 1(default)=do not act on ClientHello without SNI (ESNI ?)
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; comma separated list of split positions
; markers: method,host,endhost,sld,endsld,midsld,sniext
; full list is only used by multisplit and multidisorder
; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; use sequence overlap before first sent original split segment
--dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; pattern for the fake part of overlap
--dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder
--dpi-desync-ipfrag-pos-tcp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 8.
--dpi-desync-ipfrag-pos-udp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 32.
--dpi-desync-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default -10000
--dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default -66000
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
--dpi-desync-fake-http=<filename>|0xHEX ; file containing fake http request
--dpi-desync-fake-tls=<filename>|0xHEX|! ; file containing fake TLS ClientHello (for https). '!' = standard fake
--dpi-desync-fake-tls-mod=mod[,mod] ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=<sni>,dupsid,padencap
--dpi-desync-fake-unknown=<filename>|0xHEX ; file containing unknown protocol fake payload
--dpi-desync-fake-syndata=<filename>|0xHEX ; file containing SYN data payload
--dpi-desync-fake-quic=<filename>|0xHEX ; file containing fake QUIC Initial
--dpi-desync-fake-wireguard=<filename>|0xHEX ; file containing fake wireguard handshake initiation
--dpi-desync-fake-dht=<filename>|0xHEX ; file containing fake DHT (d1..e)
--dpi-desync-fake-discord=<filename>|0xHEX ; file containing fake Discord voice connection initiation packet (IP Discovery)
--dpi-desync-fake-stun=<filename>|0xHEX ; file containing fake STUN message
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; file containing unknown udp protocol fake payload
--dpi-desync-udplen-increment=<int> ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length.
--dpi-desync-udplen-pattern=<filename>|0xHEX ; udp tail fill pattern
--dpi-desync-start=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
--dpi-desync-cutoff=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--hostlist=<filename> ; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply if not prefixed with `^`, gzip supported, multiple hostlists allowed)
--hostlist-domains=<domain_list> ; comma separated fixed domain list
--hostlist-exclude=<filename> ; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply if not prefixed with `^`, gzip supported, multiple hostlists allowed)
--hostlist-exclude-domains=<domain_list> ; comma separated fixed domain list
--hostlist-auto=<filename> ; detect DPI blocks and build hostlist automatically
--hostlist-auto-fail-threshold=<int> ; how many failed attempts cause hostname to be added to auto hostlist (default : 3)
--hostlist-auto-fail-time=<int> ; all failed attemps must be within these seconds (default : 60)
--hostlist-auto-retrans-threshold=<int> ; how many request retransmissions cause attempt to fail (default : 3)
--hostlist-auto-debug=<logfile> ; debug auto hostlist positives
--new ; begin new strategy (new profile)
--skip ; do not use this profile
--filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
--filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported.
--filter-udp=[~]port1[-port2]|* ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported.
--filter-l7=<proto> ; L6-L7 protocol filter. multiple comma separated values allowed. proto: http tls quic wireguard dht discord stun unknown
--ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
--ipset-ip=<ip_list> ; comma separated fixed subnet list
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
--ipset-exclude-ip=<ip_list> ; comma separated fixed subnet list
--daemon ; daemonize
--pidfile=<filename> ; write pid to file
--user=<username> ; drop root privs
--uid=uid[:gid1,gid2,...] ; drop root privs
--bind-fix4 ; apply outgoing interface selection fix for generated ipv4 packets
--bind-fix6 ; apply outgoing interface selection fix for generated ipv6 packets
--wsize=<window_size>[:<scale_factor>] ; set window size. 0 = do not modify. OBSOLETE !
--wssize=<window_size>[:<scale_factor>] ; set window size for server. 0 = do not modify. default scale_factor = 0.
--wssize-cutoff=[n|d|s]N ; apply server wsize only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--wssize-forced-cutoff=0|1 ; 1(default)=auto cutoff wssize on known protocol
--ctrack-timeouts=S:E:F[:U] ; internal conntrack timeouts for TCP SYN, ESTABLISHED, FIN stages, UDP timeout. default 60:300:60:60
--ctrack-disable=[0|1] ; 1 or no argument disables conntrack
--ipcache-lifetime=<int> ; time in seconds to keep cached hop count and domain name (default 7200). 0 = no expiration
--ipcache-hostname=[0|1] ; 1 or no argument enables ip->hostname caching
--hostcase ; change Host: => host:
--hostspell ; exact spelling of "Host" header. must be 4 chars. default is "host"
--hostnospace ; remove space after Host: and add it to User-Agent: to preserve packet size
--domcase ; mix domain case : Host: TeSt.cOm
--methodeol ; add '\n' before method and remove space after Host:
--synack-split=[syn|synack|acksyn] ; perform TCP split handshake : send SYN only, SYN+ACK or ACK+SYN
--orig-ttl=<int> ; set TTL for original packets
--orig-ttl6=<int> ; set ipv6 hop limit for original packets. by default ttl value is used
--orig-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: +5:3-64. "0:0-0" or "-" disables autottl.
--orig-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --orig-autottl for ipv6 only
--orig-tcp-flags-set=<int|0xHEX|flaglist> ; set these tcp flags (flags |= value). value can be int, hex or comma separated list : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3
--orig-tcp-flags-unset=<int|0xHEX|flaglist> ; unset these tcp flags (flags &= ~value)
--orig-mod-start=[n|d|s]N ; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
--orig-mod-cutoff=[n|d|s]N ; apply orig TTL mod to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--dup=<int> ; duplicate original packets. send N dups before original.
--dup-replace=[0|1] ; 1 or no argument means do not send original, only dups
--dup-ttl=<int> ; set TTL for dups
--dup-ttl6=<int> ; set ipv6 hop limit for dups. by default ttl value is used
--dup-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: -1:3-64. "0:0-0" or "-" disables autottl.
--dup-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --dup-autottl for ipv6 only
--dup-tcp-flags-set=<int|0xHEX|flaglist> ; set these tcp flags (flags |= value). value can be int, hex or comma separated list : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3
--dup-tcp-flags-unset=<int|0xHEX|flaglist> ; unset these tcp flags (flags &= ~value)
--dup-fooling=<mode>[,<mode>] ; can use multiple comma separated values. modes : none md5sig badseq badsum datanoack hopbyhop hopbyhop2
--dup-ts-increment=<int|0xHEX> ; ts fooling TSval signed increment for dup. default -600000
--dup-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment for dup. default -10000
--dup-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment for dup. default -66000
--dup-ip-id=same|zero|seq|rnd ; ipv4 ip_id mode for dupped packets
--dup-start=[n|d|s]N ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
--dup-cutoff=[n|d|s]N ; apply dup to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--ip-id=zero|seq|seqgroup|rnd ; ipv4 ip_id assignment scheme
--dpi-desync=[<mode0>,]<mode>[,<mode2>] ; try to desync dpi state. modes : synack fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit hostfakesplit fakeddisorder ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; override fwmark for desync packet. default = 0x40000000 (1073741824)
--dpi-desync-ttl=<int> ; set ttl for desync packet
--dpi-desync-ttl6=<int> ; set ipv6 hop limit for desync packet. by default ttl value is used.
--dpi-desync-autottl=[<delta>[:<min>[-<max>]]|-] ; auto ttl mode for both ipv4 and ipv6. default: -1:3-20. "0:0-0" or "-" disables autottl.
--dpi-desync-autottl6=[<delta>[:<min>[-<max>]]|-] ; overrides --dpi-desync-autottl for ipv6 only
--dpi-desync-tcp-flags-set=<int|0xHEX|flaglist> ; set these tcp flags (flags |= value). value can be int, hex or comma separated list : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3
--dpi-desync-tcp-flags-unset=<int|0xHEX|flaglist> ; unset these tcp flags (flags &= ~value)
--dpi-desync-fooling=<mode>[,<mode>] ; can use multiple comma separated values. modes : none md5sig ts badseq badsum datanoack hopbyhop hopbyhop2
--dpi-desync-repeats=<N> ; send every desync packet N times
--dpi-desync-skip-nosni=0|1 ; 1(default)=do not act on ClientHello without SNI (ESNI ?)
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; comma separated list of split positions
; markers: method,host,endhost,sld,endsld,midsld,sniext
; full list is only used by multisplit and multidisorder
; fakedsplit/fakeddisorder use first l7-protocol-compatible parameter if present, first abs value otherwise
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; use sequence overlap before first sent original split segment
--dpi-desync-split-seqovl-pattern=[+ofs]@<filename>|0xHEX ; pattern for the fake part of overlap
--dpi-desync-fakedsplit-pattern=[+ofs]@<filename>|0xHEX ; fake pattern for fakedsplit/fakeddisorder
--dpi-desync-fakedsplit-mod=mod[,mod] ; mods can be none,altorder=0|1|2|3 + 0|8|16
--dpi-desync-hostfakesplit-midhost=marker+N|marker-N ; additionally split real hostname at specified marker. must be within host..endhost or won't be splitted.
--dpi-desync-hostfakesplit-mod=mod[,mod] ; can be none, host=<hostname>, altorder=0|1
--dpi-desync-ipfrag-pos-tcp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 32.
--dpi-desync-ipfrag-pos-udp=<8..9216> ; ip frag position starting from the transport header. multiple of 8, default 8.
--dpi-desync-ts-increment=<int|0xHEX> ; ts fooling TSval signed increment. default -600000
--dpi-desync-badseq-increment=<int|0xHEX> ; badseq fooling seq signed increment. default -10000
--dpi-desync-badack-increment=<int|0xHEX> ; badseq fooling ackseq signed increment. default -66000
--dpi-desync-any-protocol=0|1 ; 0(default)=desync only http and tls 1=desync any nonempty data packet
--dpi-desync-fake-tcp-mod=mod[,mod] ; comma separated list of tcp fake mods. available mods : none,seq
--dpi-desync-fake-http=[+ofs]@<filename>|0xHEX ; file containing fake http request
--dpi-desync-fake-tls=[+ofs]@<filename>|0xHEX|![+offset] ; file containing fake TLS ClientHello (for https). '!' = standard fake
--dpi-desync-fake-tls-mod=mod[,mod] ; comma separated list of TLS fake mods. available mods : none,rnd,rndsni,sni=<sni>,dupsid,padencap
--dpi-desync-fake-unknown=[+ofs]@<filename>|0xHEX ; file containing unknown protocol fake payload
--dpi-desync-fake-syndata=[+ofs]@<filename>|0xHEX ; file containing SYN data payload
--dpi-desync-fake-quic=[+ofs]@<filename>|0xHEX ; file containing fake QUIC Initial
--dpi-desync-fake-wireguard=[+ofs]@<filename>|0xHEX ; file containing fake wireguard handshake initiation
--dpi-desync-fake-dht=[+ofs]@<filename>|0xHEX ; file containing fake DHT (d1..e)
--dpi-desync-fake-discord=[+ofs]@<filename>|0xHEX ; file containing fake Discord voice connection initiation packet (IP Discovery)
--dpi-desync-fake-stun=[+ofs]@<filename>|0xHEX ; file containing fake STUN message
--dpi-desync-fake-unknown-udp=[+ofs]@<filename>|0xHEX ; file containing unknown udp protocol fake payload
--dpi-desync-udplen-increment=<int> ; increase or decrease udp packet length by N bytes (default 2). negative values decrease length.
--dpi-desync-udplen-pattern=[+ofs]@<filename>|0xHEX ; udp tail fill pattern
--dpi-desync-start=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) greater or equal than N
--dpi-desync-cutoff=[n|d|s]N ; apply dpi desync only to packet numbers (n, default), data packet numbers (d), relative sequence (s) less than N
--hostlist=<filename> ; apply dpi desync only to the listed hosts (one host per line, subdomains auto apply if not prefixed with `^`, gzip supported, multiple hostlists allowed)
--hostlist-domains=<domain_list> ; comma separated fixed domain list
--hostlist-exclude=<filename> ; do not apply dpi desync to the listed hosts (one host per line, subdomains auto apply if not prefixed with `^`, gzip supported, multiple hostlists allowed)
--hostlist-exclude-domains=<domain_list> ; comma separated fixed domain list
--hostlist-auto=<filename> ; detect DPI blocks and build hostlist automatically
--hostlist-auto-fail-threshold=<int> ; how many failed attempts cause hostname to be added to auto hostlist (default : 3)
--hostlist-auto-fail-time=<int> ; all failed attemps must be within these seconds (default : 60)
--hostlist-auto-retrans-threshold=<int> ; how many request retransmissions cause attempt to fail (default : 3)
--hostlist-auto-debug=<logfile> ; debug auto hostlist positives
--new ; begin new strategy (new profile)
--skip ; do not use this profile
--filter-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
--filter-tcp=[~]port1[-port2]|* ; TCP port filter. ~ means negation. setting tcp and not setting udp filter denies udp. comma separated list supported.
--filter-udp=[~]port1[-port2]|* ; UDP port filter. ~ means negation. setting udp and not setting tcp filter denies tcp. comma separated list supported.
--filter-l7=<proto> ; L6-L7 protocol filter. multiple comma separated values allowed. proto: http tls quic wireguard dht discord stun unknown
--filter-ssid=ssid1[,ssid2,ssid3,...] ; per profile wifi SSID filter
--ipset=<filename> ; ipset include filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
--ipset-ip=<ip_list> ; comma separated fixed subnet list
--ipset-exclude=<filename> ; ipset exclude filter (one ip/CIDR per line, ipv4 and ipv6 accepted, gzip supported, multiple ipsets allowed)
--ipset-exclude-ip=<ip_list> ; comma separated fixed subnet list
```
Many parameters dealing with binary data support loading from hex string prefixed by "0x" or from a file.
Filename can be "as is" or prefixed with "@". If there's "+number" prefix before "@" it means offset of data inside the file.
Offset must be less that data size.
### DPI desync attack
The idea is to take original message, modify it, add additional fake information in such a way that the server OS accepts original data only
@@ -253,7 +278,7 @@ Fakes are separate generated by nfqws packets carrying false information for DPI
`nfqws` cannot redistribute data between original TCP segments. The error displayed is 'message too long'.
* **badsum** doesn't work if your device is behind NAT which does not pass invalid packets.
The most common Linux NAT router configuration does not pass them. Most home routers are Linux based.
The default sysctl configuration `net.netfilter.nf_conntrack_checksum=1` causes contrack to verify tcp and udp checksums
The default sysctl configuration `net.netfilter.nf_conntrack_checksum=1` causes conntrack to verify tcp and udp checksums
and set INVALID state for packets with invalid checksum.
Typically, iptables rules include a rule for dropping packets with INVALID state in the FORWARD chain.
The combination of these factors does not allow badsum packets to pass through the router.
@@ -284,6 +309,16 @@ Fakes are separate generated by nfqws packets carrying false information for DPI
* **datanoack** sends tcp fakes without ACK flag. Servers do not accept this but DPI may accept.
This mode may break NAT and may not work with iptables if masquerade is used, even from the router itself.
Works with nftables properly. Likely requires external IP address (some ISPs pass these packets through their NAT).
* Manipulate **tcp flags** with `--dpi-desync-tcp-flags-set` and `--dpi-desync-tcp-flags-unset`.
Invalid tcp flags combination may cause server to drop the packet but DPI can accept it.
For example, set SYN in fakes. This may not work with all servers.
`datanoack` can be replaced to `--dpi-desync-tcp-flags-unset=ACK`.
* **ts** adds to TSval ts increment value (-600000 by default). Servers discard packets with TSval in some range.
Practical tests suggest increment between -100 and -0x80000000.
Timestamps are generated by client OS. In linux timestamps are enabled by default. In windows by default timestamps are disabled.
They can be enabled with this command : `netsh interface tcp set global timestamps=enabled` .
ts fooling requires that timestamps are enabled. They must be enabled on every client OS.
TSecr is left unmodified.
* **autottl** tries to automatically guess hop count to the server and compute TTL by adding some delta value that can be positive or negative.
Positive deltas must be preceeded by unary `+` sign. Deltas without any unary sign are treated negative for old versions compatibility reasons.
This tech relies on well known TTL default values used by OS : 64,128,255.
@@ -305,6 +340,9 @@ Resulting order would be : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake
### FAKE mods
By default all tcp fakes are sent with the same sequence as original packet.
This can be changed by `--dpi-desync-fake-tcp-mod=seq`. In the latter case all fakes are sent as if they would be tcp segments of a single fake.
**nfqws** has built-in TLS fake. It can be customized with `--dpi-desync-fake-tls` option.
Customized fake data can be anything - valid TLS Client Hello or arbitrary data.
It's possible to use TLS Client Hello with any fingerprint and any SNI.
@@ -333,8 +371,37 @@ Example : `--dpi-desync-fake-tls=iana_org.bin --dpi-desync-fake-tls-mod=rndsni -
* `multisplit`. split request at specified in `--dpi-desync-split-pos` positions
* `multidisorder`. same as `multisplit` but send in reverse order
* `fakedsplit`. split request into 2 segments adding fakes in the middle of them : fake 1st segment, 1st segment, fake 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment
* `fakeddisorder`. same as `fakedsplit` but with another order : fake 2nd segment, 2nd segment, fake 2nd segment, fake 1st segment, 1st segment, fake 1st segment
* `fakedsplit`. sequental one position split with fake mix
* `hostfakesplit` (altorder=0). fake host part of the request : before host, random fake host, real host (optionally split this part), random fake host repeat, after host
* `hostfakesplit` (altorder=1). fake host part of the request : before host, random fake host, after host, real host (optionally split this part)
* `fakedsplit`. reverse one position split with fake mix
`--dpi-desync-fakedsplit-mod=altorder=N` specifies number which influence to the presence of individual fakes in `fakedsplit`/`fakeddisorder`.
`fakedsplit` TCP segments of multi-packet messages with split pos :
* `altorder=0`. fake 1st segment, 1st segment, fake 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment
* `altorder=1`. 1st segment, fake 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment
* `altorder=2`. 1st segment, fake 2nd segment, 2nd segment, fake 2nd segment
* `altorder=3`. 1st segment, fake 2nd segment, 2nd segment
`fakeddisorder` TCP segments of multi-packet messages with split pos :
* `altorder=0`. fake 2nd segment, 2nd segment, fake 2nd segment, fake 1st segment, 1st segment, fake 1st segment
* `altorder=1`. 2nd segment, fake 2nd segment, fake 1st segment, 1st segment, fake 1st segment
* `altorder=2`. 2nd segment, fake 1st segment, 1st segment, fake 1st segment
* `altorder=3`. 1st segment, fake 1st segment, 1st segment
`fakedsplit`/`fakeddisorder` TCP segments of multi-packet messages without split pos :
* `altorder=0`. fake, original, fake
* `altorder=8`. original, fake
* `altorder=16`. original
Resulting `altorder=N` is the sum of two `altorder` parts mentioned above.
`--dpi-desync-fakedsplit-pattern` defines data payload of fakes in `fakedsplit`/`fakeddisorder`. By default pattern is simple `0x00`.
Offset of split part + offset of current packet in multi-packet message define offset in the pattern.
Positions are defined by markers.
@@ -363,6 +430,22 @@ First relative markers are searched. If no suitable found absolute markers are s
For example, `--dpi-desync-split-pos=method+2,midsld,5` means `method+2` for http, `midsld` for TLS and 5 for others.
`--dpi-desync-fakedsplit-mod=altorder=N` switches `fakedsplit` to alternate segment ordering.
`hostfakesplit` only fakes hostname part of the request making it hard to destinguish between real and fake host names.
It works for tcp protocols with host : TLS and HTTP. Real hostname can be additionally split using `--dpi-desync-hostfakesplit-midhost` marker.
For example, `--dpi-desync-hostfakesplit-midhost=midsld`. Position must be within host range or split won't happen.
Multi-packet queries are supported if hostname part is not already split. If it is fooling is cancelled.
By default fake host names are generated randomly on the fly using `[0-9a-z]` pattern. If host length is >= 7 dot is placed to simulate 3-char TLD and last 3 chars are replaces with a random known 3-char TLD.
It's possible to set fake host template : `--dpi-desync-hostfakesplit-mod=host=<hostname>`.
Template hostname will be expanded to the left to original hostname size with random characters from `[0-9a-z]` pattern : "www.networksolutions.com" -> "h8xmdba4tv7a8.google.com".
If original hostname size is less than template size it will be cut : "habr.com" -> "ogle.com".
If original hostname size is larger than template size by one, dot will be appended to the left : "www.xxx.com" => ".google.com"..
That's why it's a good idea to use short hostnames in template : "ya.ru", "vk.com", "x.com".
`--dpi-desync-hostfakesplit-mod=altorder=1` switches `hostfakesplit` to alternate segment ordering. `altorder=1` sends the whole request with faked host sequentally, then real host segment.
### Sequence numbers overlap
`seqovl` adds to one of the original segment `seqovl` bytes to the beginning and decreases sequence number. For `split` - to the first segment, for `disorder` - to the beginning of the penultimate segment sent (second in the original sequence).
@@ -373,6 +456,21 @@ All unix OS except Solaris preserve last received data. This is not the case for
Disorder requires `seqovl` to be less than split position. Otherwise `seqovl` is not possible and will be cancelled.
Method allows to avoid separate fakes. Fakes and real data are mixed.
### IP_ID assignment
Some DPIs check ipv4 ip_id value. OS normally increment ip_id value every packet. Some anti-DPI software may send fakes or tcp segments with the same ip_id as original causing block trigger.
Sequental ip_id will be broken in case of sending fakes or additional tcp segments because OS knows nothing about them. But still there are options how to assignt ip_id to generated packets.
`ip-id` parameter sets ip_id assignment scheme for a desync profile :
* `seq` (default) : increment ip_id for every next packet. in `multidisorder` case increase ip_id for the number of tcp segments then decrease by 1 every packet.
* `seqgroup` : same as `seq` but send fake replacements with the same ip_id as original parts. related only to fake tcp segments with the same size and same sequence as originals.
* `rnd` : assign random ip_id
* `zero` : always set zero. Linux and BSD will send zero, Windows will replace zero with it's own counter.
ipv6 header lacks ip_id field, `ip-id` parameter ignored for ipv6.
### ipv6 specific modes
`hopbyhop`, `destopt` and `ipfrag1` desync modes (they're not the same as `hopbyhop` fooling !) are ipv6 only. One `hop-by-hop`,
@@ -430,7 +528,7 @@ There are DPIs that analyze responses from the server, particularly the certific
In the disorder variant, a selective acknowledgement (SACK) usually arrives first, then a full ACK.
If, instead of ACK or SACK, there is an RST packet with minimal delay, DPI cuts you off at the request stage.
If the RST is after a full ACK after a delay of about ping to the server, then probably DPI acts on the server response. The DPI may be satisfied with good ClientHello and stop monitoring the TCP session without checking ServerHello. Then you were lucky. 'fake' option could work.
If it does not stop monitoring and persistently checks the ServerHello, --wssize parameter may help (see [CONNTRACK](#conntrack)).
If it does not stop monitoring and persistently checks the ServerHello, `--wssize` parameter may help (see [CONNTRACK](#conntrack)).
Otherwise it is hardly possible to overcome this without the help of the server.
The best solution is to enable TLS 1.3 support on the server. TLS 1.3 sends the server certificate in encrypted form.
This is recommendation to all admins of blocked sites. Enable TLS 1.3. You will give more opportunities to overcome DPI.
@@ -493,7 +591,7 @@ That's why conntrack is required to know when to stop applying low window size.
If you do not stop and set the low wssize all the time, the speed will drop catastrophically.
Linux can overcome this using connbytes filter but other OS may not include similar filter.
In http(s) case wssize stops after the first http request or TLS ClientHello.
In http(s) case wssize stops after the first http request or TLS ClientHello unless `--wssize-forced-cutoff=0` is specified.
If you deal with a non-http(s) protocol you need `--wssize-cutoff`. It sets the threshold where wssize stops.
@@ -501,6 +599,7 @@ Threshold can be prefixed with 'n' (packet number starting from 1), 'd' (data pa
's' (relative sequence number - sent by client bytes + 1).
If a http request or TLS ClientHello packet is detected wssize stops immediately ignoring wssize-cutoff option.
This action is called "forced wssize cutoff" and can disabled using `--wssize-forced-cutoff=0`.
If your protocol is prone to long inactivity, you should increase ESTABLISHED phase timeout using `--ctrack-timeouts`.
@@ -554,9 +653,9 @@ There is special support for all tcp split options for multi segment TLS. Split
### UDP support
UDP attacks are limited. Its not possible to fragment UDP on transport level, only on network (ip) level.
Only desync modes `fake`,`hopbyhop`,`destopt`,`ipfrag1` and `ipfrag2` are applicable.
`fake`,`hopbyhop`,`destopt` can be used in combo with `ipfrag2`.
`fake` can be used in combo with `udplen` and `tamper`.
Only desync modes `fake`,`fakeknown`,`hopbyhop`,`destopt`,`ipfrag1`,`ipfrag2`,`udplen` and `tamper` are applicable.
`fake`,`fakeknown`,`hopbyhop`,`destopt`,`ipfrag1` are 1st phase modes, others - 2nd phase.
As always it's possible to combine one mode from 1st phase with one mode from 2nd phase but not possible to mix same phase modes.
`udplen` increases udp payload size by `--dpi-desync-udplen-increment` bytes. Padding is filled with zeroes by default but can be overriden with a pattern.
This option can resist DPIs that track outgoing UDP packet sizes.
@@ -659,6 +758,30 @@ This way you may never unblock all resources and only confuse yourself.
IMPORTANT : user-mode ipset implementation was not designed as a kernel version replacement. Kernel version is much more effective.
It's for the systems that lack ipset support : Windows and Linux without nftables and ipset kernel modules (Android, for example).
### WIFI filtering
Wifi interface name is not related to connected SSID.
It's possible to connect interface to different SSIDs.
They may require different strategies. How to solve this problem ?
You can run and stop nfqws instances manually. But you can also automate this.
Windows version `winws` has global filter `--ssid-filter`.
It connects or disconnects `winws` depending on connected SSIDs.
Routing is not take into account. This approach is possible because windivert can have multiple handlers with intersecting filter.
If SSID changes one `winws` connects and others disconnect.
`winws` solution is hard to implement in Linux because one nfqueue can have only one handler and it's impossible to pass same traffic to multiple queues.
One must connect when others have already disconnected.
Instead, `nfqws` has per-profile `--filter-ssid` parameter. Like `--ssid-filter` it takes comma separated SSID list.
`nfqws` maintains ifname->SSID list which is updated not faster than once a second.
When a packet comes incoming or outgoing interface name is matched to the SSID and then used in profile selection algorithm.
SSID info is taken the same way as `iw dev <ifname> info` does (nl80211).
Unfortunately it's broken since kernel 5.19 and still unfixed in 6.14.
In the latter case `iwgetid` way is used (wireless extensions).
Wireless extensions are deprecated. Some kernels can be built without wext support.
Before using `--filter-ssid` check that any of the mentioned commands can return SSID.
### Virtual machines
Most of nfqws packet magic does not work from VMs powered by virtualbox and vmware when network is NATed.
@@ -667,6 +790,9 @@ Set up bridge networking.
### IPTABLES for nfqws
> [!CAUTION]
> Starting from Linux kernel 6.17 there's CONFIG_NETFILTER_XTABLES_LEGACY parameter which is not set by default. Many distributions will likely not turn it on making iptables-legacy non working. This is part of iptables deprecation. However iptables-nft still works because their backend is based on nftables.
This is the common way to redirect some traffic to nfqws :
```
@@ -1111,7 +1237,7 @@ If `MODE_FILTER=hostlist` all present lists are passed to **nfqws** or **tpws**.
If all include lists are empty it works like no include lists exist at all.
If you need "all except" mode you dont have to delete zapret-hosts-users.txt. Just make it empty.
Subdomains auto apply. For example, "ru" in the list affects "*.ru" .
Subdomains auto apply. For example, "ru" in the list affects "\*.ru" .
`^` prefix symbol disables subdomain match.
**tpws** and **nfqws** automatically reload lists if their modification time or file size is changed.
@@ -1199,6 +1325,23 @@ Don't use `<HOSTLIST>` in highly specialized profiles. Use your own filter or ho
`<HOSTLIST_NOAUTO>` marker uses standard autohostlist as usual hostlist thus disabling auto additions in this profile.
If any other profile adds something this profile accepts the change automatically.
Change loop prevention mark bit
`DESYNC_MARK=0x40000000`
Change postnat scheme mark bit
`DESYNC_MARK_POSTNAT=0x20000000`
If uncommented pass to zapret only packets marked with this bit
`#FILTER_MARK=0x10000000`
Bit must be set in your own rules.
* iptables - in mangle PREROUTING and mangle OUTPUT before zapret rules (iptables -I _after_ zapret rules application).
* nftables - in output and prerouting hooks with priority -102 or lower.
Mark criterias can be any. For example, source IP or source interface name.
**tpws** socks proxy mode switch
@@ -1564,7 +1707,9 @@ If this is the case then run another script in background and add some delay the
Are welcome here :
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
USDT ERC `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
USDT TRC `TEzAAtn4VhndqEaAyuCM78xh5W2gCjwWEo`
BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
+344 -113
View File
@@ -1,11 +1,15 @@
# zapret v71
# ВНИМАНИЕ, остерегайтесь мошенников
zapret является свободным и open source.
Всякий, кто понуждает вас скачивать zapret только с его ресурса, требует удалить ссылки, видео, файлы, обосновывая эти требования авторскими правами, сам нарушает [лицензию](./LICENSE.txt).
Однако, это не исключает [добровольные пожертвования](#поддержать-разработчика).
# zapret2
Эта версия zapret более не развивается и находится в режиме EOL (End-Of-Life). Никаких новых функций больше не будет. Только багфиксы. Pull реквесты с новыми фичами не принимаются.
[Актуальная версия - zapret 2](https://github.com/bol-van/zapret2)
# Multilanguage README
[![en](https://img.shields.io/badge/lang-en-red.svg)](./readme.en.md)
@@ -25,6 +29,7 @@ zapret является свободным и open source.
- [МОДИФИКАЦИЯ ФЕЙКОВ](#модификация-фейков)
- [TCP СЕГМЕНТАЦИЯ](#tcp-сегментация)
- [ПЕРЕКРЫТИЕ SEQUENCE NUMBERS](#перекрытие-sequence-numbers)
- [НАЗНАЧЕНИЕ IP_ID](#назначение-ip_id)
- [СПЕЦИФИЧЕСКИЕ РЕЖИМЫ IPV6](#специфические-режимы-ipv6)
- [МОДИФИКАЦИЯ ОРИГИНАЛА](#модификация-оригинала)
- [ДУБЛИКАТЫ](#дубликаты)
@@ -39,9 +44,11 @@ zapret является свободным и open source.
- [ПОДДЕРЖКА UDP](#поддержка-udp)
- [IP ФРАГМЕНТАЦИЯ](#ip-фрагментация)
- [МНОЖЕСТВЕННЫЕ СТРАТЕГИИ](#множественные-стратегии)
- [ФИЛЬТРАЦИЯ ПО WIFI](#фильтрация-по-wifi)
- [IPTABLES ДЛЯ NFQWS](#iptables-для-nfqws)
- [NFTABLES ДЛЯ NFQWS](#nftables-для-nfqws)
- [FLOW OFFLOADING](#flow-offloading)
- [ОСОБЕННОСТИ ЖЕЛЕЗОК](#особенности-железок)
- [ДУРЕНИЕ СО СТОРОНЫ СЕРВЕРА](#дурение-со-стороны-сервера)
- [tpws](#tpws)
- [TCP СЕГМЕНТАЦИЯ В TPWS](#tcp-сегментация-в-tpws)
@@ -152,7 +159,7 @@ DPI. Все больше становится внереестровых бло
* Если блокировка осуществляется по IP.
* Если соединение проходит через фильтр, способный реконструировать TCP соединение, и который следует всем стандартам.
Например, нас заворачивают на squid. Соединение идет через полноценный стек tcpip операционной системы.
Проект нацелен на обман DPI, который всилу ограниченности ресурсов и большого трафика вынужден интерпретировать его лишь ограниченно.
Проект нацелен на обман DPI, который в силу ограниченности ресурсов и большого трафика вынужден интерпретировать его лишь ограниченно.
Обмануть полноценный стек ОС и полноценные серверные приложения не получится.
## nfqws
@@ -161,104 +168,123 @@ DPI. Все больше становится внереестровых бло
dvtws, собираемый из тех же исходников (см. [документация BSD](./bsd.md)).
```
@<config_file>|$<config_file> ; читать конфигурацию из файла. опция должна быть первой. остальные опции игнорируются.
@<config_file>|$<config_file> ; читать конфигурацию из файла. опция должна быть первой. остальные опции игнорируются.
--debug=0|1 ; 1=выводить отладочные сообщения
--dry-run ; проверить опции командной строки и выйти. код 0 - успешная проверка.
--version ; вывести версию и выйти
--comment ; любой текст (игнорируется)
--daemon ; демонизировать прогу
--pidfile=<file> ; сохранить PID в файл
--user=<username> ; менять uid процесса
--uid=uid[:gid] ; менять uid процесса
--qnum=N ; номер очереди N
--bind-fix4 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv4 пакетов
--bind-fix6 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv6 пакетов
--ctrack-timeouts=S:E:F[:U] ; таймауты внутреннего conntrack в состояниях SYN, ESTABLISHED, FIN, таймаут udp. по умолчанию 60:300:60:60
--ctrack-disable=[0|1] ; 1 или остутствие аргумента отключает conntrack
--ipcache-lifetime=<int> ; время жизни записей кэша IP в секундах. 0 - без ограничений.
--ipcache-hostname=[0|1] ; 1 или отсутствие аргумента включают кэширование имен хостов для применения в стратегиях нулевой фазы
--wsize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !)
--wssize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !)
--wssize-cutoff=[n|d|s]N ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--synack-split=[syn|synack|acksyn] ; выполнить tcp split handshake. вместо SYN,ACK отсылать только SYN, SYN+ACK или ACK+SYN
--orig-ttl=<int> ; модифицировать TTL оригинального пакета
--orig-ttl6=<int> ; модифицировать ipv6 hop limit оригинальных пакетов. если не указано, используется значение --orig-ttl
--orig-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +5:3-64. "0:0-0" или "-" отключает функцию
--orig-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
--orig-mod-start=[n|d|s]N ; применять orig-mod только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--orig-mod-cutoff=[n|d|s]N ; применять orig-mod только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--dup=<int> ; высылать N дубликатов до оригинала
--dup-replace=[0|1] ; 1 или отсутствие аргумента блокирует отправку оригинала. отправляются только дубликаты.
--dup-ttl=<int> ; модифицировать TTL дубликатов
--dup-ttl6=<int> ; модифицировать ipv6 hop limit дубликатов. если не указано, используется значение --dup-ttl
--dup-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +1:3-64. "0:0-0" или "-" отключает функцию
--dup-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
--dup-fooling=<fooling> ; дополнительные методики как сделать, чтобы дубликат не дошел до сервера. none md5sig badseq badsum datanoack hopbyhop hopbyhop2
--dup-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
--dup-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
--dup-start=[n|d|s]N ; применять dup только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--dup-cutoff=[n|d|s]N ; применять dup только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--hostcase ; менять регистр заголовка "Host:" по умолчанию на "host:".
--hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
--methodeol ; добавить перевод строки в unix стиле ('\n') перед методом и убрать пробел из Host: : "GET / ... Host: domain.com" => "\nGET / ... Host:domain.com"
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--domcase ; домен после Host: сделать таким : TeSt.cOm
--dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit fakeddisorder ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
--dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение --dpi-desync-ttl
--dpi-desync-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: 1:3-20. "0:0-0" или "-" отключает функцию
--dpi-desync-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
--dpi-desync-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack hopbyhop hopbyhop2
--dpi-desync-repeats=<N> ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты)
--dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации в режимах split и disorder
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число.
--dpi-desync-split-seqovl-pattern=<filename>|0xHEX ; чем заполнять фейковую часть overlap
--dpi-desync-fakedsplit-pattern=<filename>|0xHEX ; чем заполнять фейки в fakedsplit/fakeddisorder
--dpi-desync-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
--dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
--dpi-desync-fake-http=<filename>|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org
--dpi-desync-fake-tls=<filename>|0xHEX|! ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному. '!' = стандартный фейк
--dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,sni=<sni>,dupsid,padencap
--dpi-desync-fake-unknown=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-syndata=<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
--dpi-desync-fake-quic=<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
--dpi-desync-fake-dht=<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-discord=<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-stun=<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-unknown-udp=<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-udplen-increment=<int> ; насколько увеличивать длину udp пейлоада в режиме udplen
--dpi-desync-udplen-pattern=<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
--dpi-desync-start=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--dpi-desync-cutoff=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются, если хост не начинается с '^'.
; в файле должен быть хост на каждой строке.
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
; при изменении времени модификации файла он перечитывается автоматически по необходимости
; список может быть запакован в gzip. формат автоматически распознается и разжимается
; списков может быть множество. пустой общий лист = его отсутствие
; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.
--hostlist-domains=<domain_list> ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-exclude=<filename> ; не применять дурение к доменам из листа. может быть множество листов. схема аналогична include листам.
--hostlist-exclude-domains=<domain_list> ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-auto=<filename> ; обнаруживать автоматически блокировки и заполнять автоматический hostlist (требует перенаправления входящего трафика)
--hostlist-auto-fail-threshold=<int> ; сколько раз нужно обнаружить ситуацию, похожую на блокировку, чтобы добавить хост в лист (по умолчанию: 3)
--hostlist-auto-fail-time=<int> ; все эти ситуации должны быть в пределах указанного количества секунд (по умолчанию: 60)
--hostlist-auto-retrans-threshold=<int> ; сколько ретрансмиссий запроса считать блокировкой (по умолчанию: 3)
--hostlist-auto-debug=<logfile> ; лог положительных решений по autohostlist. позволяет разобраться почему там появляются хосты.
--new ; начало новой стратегии (новый профиль)
--skip ; не использовать этот профиль . полезно для временной деактивации профиля без удаления параметров.
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
--filter-l7=<proto> ; фильтр протокола L6-L7. поддерживается несколько значений через запятую. proto : http tls quic wireguard dht discord stun unknown
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-exclude-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
--debug=0|1 ; 1=выводить отладочные сообщения
--dry-run ; проверить опции командной строки и выйти. код 0 - успешная проверка.
--version ; вывести версию и выйти
--comment ; любой текст (игнорируется)
--daemon ; демонизировать прогу
--pidfile=<file> ; сохранить PID в файл
--user=<username> ; менять uid процесса
--uid=uid[:gid] ; менять uid процесса
--qnum=N ; номер очереди N
--bind-fix4 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv4 пакетов
--bind-fix6 ; пытаться решить проблему неверного выбора исходящего интерфейса для сгенерированных ipv6 пакетов
--ctrack-timeouts=S:E:F[:U] ; таймауты внутреннего conntrack в состояниях SYN, ESTABLISHED, FIN, таймаут udp. по умолчанию 60:300:60:60
--ctrack-disable=[0|1] ; 1 или отсутствие аргумента отключает conntrack
--ipcache-lifetime=<int> ; время жизни записей кэша IP в секундах. 0 - без ограничений.
--ipcache-hostname=[0|1] ; 1 или отсутствие аргумента включают кэширование имен хостов для применения в стратегиях нулевой фазы
--wsize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в SYN,ACK. если не задан scale_factor, то он не меняется (устарело !)
--wssize=<winsize>[:<scale_factor>] ; менять tcp window size на указанный размер в исходящих пакетах. scale_factor по умолчанию 0. (см. conntrack !)
--wssize-cutoff=[n|d|s]N ; изменять server window size в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--wssize-forced-cutoff=0|1 ; 1(default)=автоматически отключать wssize в случае обнаружения известного протокола
--synack-split=[syn|synack|acksyn] ; выполнить tcp split handshake. вместо SYN,ACK отсылать только SYN, SYN+ACK или ACK+SYN
--orig-ttl=<int> ; модифицировать TTL оригинального пакета
--orig-ttl6=<int> ; модифицировать ipv6 hop limit оригинальных пакетов. если не указано, используется значение --orig-ttl
--orig-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +5:3-64. "0:0-0" или "-" отключает функцию
--orig-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
--orig-tcp-flags-set=<int|0xHEX|flaglist> ; устанавливать указанные tcp флаги (flags |= value). число , либо список через запятую : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3
--orig-tcp-flags-unset=<int|0xHEX|flaglist> ; удалять указанные tcp флаги (flags &= ~value)
--orig-mod-start=[n|d|s]N ; применять orig-mod только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--orig-mod-cutoff=[n|d|s]N ; применять orig-mod только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--dup=<int> ; высылать N дубликатов до оригинала
--dup-replace=[0|1] ; 1 или отсутствие аргумента блокирует отправку оригинала. отправляются только дубликаты.
--dup-ttl=<int> ; модифицировать TTL дубликатов
--dup-ttl6=<int> ; модифицировать ipv6 hop limit дубликатов. если не указано, используется значение --dup-ttl
--dup-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: +1:3-64. "0:0-0" или "-" отключает функцию
--dup-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
--dup-tcp-flags-set=<int|0xHEX|flaglist> ; устанавливать указанные tcp флаги (flags |= value). число , либо список через запятую : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3
--dup-tcp-flags-unset=<int|0xHEX|flaglist> ; удалять указанные tcp флаги (flags &= ~value)
--dup-fooling=<fooling> ; дополнительные методики как сделать, чтобы дубликат не дошел до сервера. none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2
--dup-ts-increment=<int|0xHEX> ; инкремент TSval для ts. по умолчанию -600000
--dup-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
--dup-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
--dup-ip-id=same|zero|seq|rnd ; режим назначения ip_id для пакетов dup
--dup-start=[n|d|s]N ; применять dup только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--dup-cutoff=[n|d|s]N ; применять dup только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--hostcase ; менять регистр заголовка "Host:" по умолчанию на "host:".
--hostnospace ; убрать пробел после "Host:" и переместить его в конец значения "User-Agent:" для сохранения длины пакета
--methodeol ; добавить перевод строки в unix стиле ('\n') перед методом и убрать пробел из Host: : "GET / ... Host: domain.com" => "\nGET / ... Host:domain.com"
--hostspell=HoST ; точное написание заголовка Host (можно "HOST" или "HoSt"). автоматом включает --hostcase
--domcase ; домен после Host: сделать таким : TeSt.cOm
--ip-id=seq|seqgroup|rnd|zero ; режим назначения ip_id для генерированных пакетов
--dpi-desync=[<mode0>,]<mode>[,<mode2] ; атака по десинхронизации DPI. mode : synack syndata fake fakeknown rst rstack hopbyhop destopt ipfrag1 multisplit multidisorder fakedsplit hostfakesplit fakeddisorder ipfrag2 udplen tamper
--dpi-desync-fwmark=<int|0xHEX> ; бит fwmark для пометки десинхронизирующих пакетов, чтобы они повторно не падали в очередь. default = 0x40000000
--dpi-desync-ttl=<int> ; установить ttl для десинхронизирующих пакетов
--dpi-desync-ttl6=<int> ; установить ipv6 hop limit для десинхронизирующих пакетов. если не указано, используется значение --dpi-desync-ttl
--dpi-desync-autottl=[<delta>[:<min>[-<max>]]|-] ; режим auto ttl для ipv4 и ipv6. по умолчанию: 1:3-20. "0:0-0" или "-" отключает функцию
--dpi-desync-autottl6=[<delta>[:<min>[-<max>]]|-] ; переопределение предыдущего параметра для ipv6
--dpi-desync-tcp-flags-set=<int|0xHEX|flaglist> ; устанавливать указанные tcp флаги (flags |= value). число , либо список через запятую : FIN,SYN,RST,PSH,ACK,URG,ECE,CWR,AE,R1,R2,R3
--dpi-desync-tcp-flags-unset=<int|0xHEX|flaglist> ; удалять указанные tcp флаги (flags &= ~value)
--dpi-desync-fooling=<fooling> ; дополнительные методики как сделать, чтобы фейковый пакет не дошел до сервера. none md5sig badseq badsum datanoack ts hopbyhop hopbyhop2
--dpi-desync-repeats=<N> ; посылать каждый генерируемый в nfqws пакет N раз (не влияет на остальные пакеты)
--dpi-desync-skip-nosni=0|1 ; 1(default)=не применять dpi desync для запросов без hostname в SNI, в частности для ESNI
--dpi-desync-split-pos=N|-N|marker+N|marker-N ; список через запятую маркеров для tcp сегментации в режимах split и disorder
--dpi-desync-split-seqovl=N|-N|marker+N|marker-N ; единичный маркер, определяющий величину перекрытия sequence в режимах split и disorder. для split поддерживается только положительное число.
--dpi-desync-split-seqovl-pattern=[+ofs]@<filename>|0xHEX ; чем заполнять фейковую часть overlap
--dpi-desync-fakedsplit-pattern=[+ofs]@<filename>|0xHEX ; чем заполнять фейки в fakedsplit/fakeddisorder
--dpi-desync-fakedsplit-mod=mod[,mod] ; может быть none, altorder=0|1|2|3 + 0|8|16
--dpi-desync-hostfakesplit-midhost=marker+N|marker-N ; маркер дополнительного разреза сегмента с оригинальным хостом. должен попадать в пределы хоста.
--dpi-desync-hostfakesplit-mod=mod[,mod] ; может быть none, host=<hostname>, altorder=0|1
--dpi-desync-ipfrag-pos-tcp=<8..9216> ; позиция ip фрагментации tcp, начиная с транспортного заголовка. должно быть кратно 8, по умолчанию - 32.
--dpi-desync-ipfrag-pos-udp=<8..9216> ; позиция ip фрагментации udp, начиная с транспортного заголовка. должно быть кратно 8, по умолчанию - 8.
--dpi-desync-ts-increment=<int|0xHEX> ; инкремент TSval для ts. по умолчанию -600000
--dpi-desync-badseq-increment=<int|0xHEX> ; инкремент sequence number для badseq. по умолчанию -10000
--dpi-desync-badack-increment=<int|0xHEX> ; инкремент ack sequence number для badseq. по умолчанию -66000
--dpi-desync-any-protocol=0|1 ; 0(default)=работать только по http request и tls clienthello 1=по всем непустым пакетам данных
--dpi-desync-fake-tcp-mod=mod[,mod] ; список через запятую режимов runtime модификации tcp фейков (любых) : none, seq
--dpi-desync-fake-http=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый http запрос для dpi-desync=fake, на замену стандартному www.iana.org
--dpi-desync-fake-tls=[+ofs]@<filename>|0xHEX|![+offset] ; файл, содержащий фейковый tls clienthello для dpi-desync=fake, на замену стандартному. '!' = стандартный фейк
--dpi-desync-fake-tls-mod=mod[,mod] ; список через запятую режимов runtime модификации фейков : none,rnd,rndsni,sni=<sni>,dupsid,padencap
--dpi-desync-fake-unknown=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного протокола для dpi-desync=fake, на замену стандартным нулям 256 байт
--dpi-desync-fake-syndata=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад пакета SYN для режима десинхронизации syndata
--dpi-desync-fake-quic=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый QUIC Initial
--dpi-desync-fake-wireguard=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый wireguard handshake initiation
--dpi-desync-fake-dht=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад DHT протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-discord=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад Discord протокола нахождения IP адреса для голосовых чатов для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-stun=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад STUN протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-fake-unknown-udp=[+ofs]@<filename>|0xHEX ; файл, содержащий фейковый пейлоад неизвестного udp протокола для dpi-desync=fake, на замену стандартным нулям 64 байт
--dpi-desync-udplen-increment=<int> ; на сколько увеличивать длину udp пейлоада в режиме udplen
--dpi-desync-udplen-pattern=[+ofs]@<filename>|0xHEX ; чем добивать udp пакет в режиме udplen. по умолчанию - нули
--dpi-desync-start=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру больше или равно N
--dpi-desync-cutoff=[n|d|s]N ; применять dpi desync только в исходящих пакетах (n), пакетах данных (d), относительных sequence (s) по номеру меньше N
--hostlist=<filename> ; действовать только над доменами, входящими в список из filename. поддомены автоматически учитываются, если хост не начинается с '^'.
; в файле должен быть хост на каждой строке.
; список читается при старте и хранится в памяти в виде иерархической структуры для быстрого поиска.
; при изменении времени модификации файла он перечитывается автоматически по необходимости
; список может быть запакован в gzip. формат автоматически распознается и разжимается
; списков может быть множество. пустой общий лист = его отсутствие
; хосты извлекаются из Host: хедера обычных http запросов и из SNI в TLS ClientHello.
--hostlist-domains=<domain_list> ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-exclude=<filename> ; не применять дурение к доменам из листа. может быть множество листов. схема аналогична include листам.
--hostlist-exclude-domains=<domain_list> ; фиксированный список доменов через зяпятую. можно использовать # в начале для комментирования отдельных доменов.
--hostlist-auto=<filename> ; обнаруживать автоматически блокировки и заполнять автоматический hostlist (требует перенаправления входящего трафика)
--hostlist-auto-fail-threshold=<int> ; сколько раз нужно обнаружить ситуацию, похожую на блокировку, чтобы добавить хост в лист (по умолчанию: 3)
--hostlist-auto-fail-time=<int> ; все эти ситуации должны быть в пределах указанного количества секунд (по умолчанию: 60)
--hostlist-auto-retrans-threshold=<int> ; сколько ретрансмиссий запроса считать блокировкой (по умолчанию: 3)
--hostlist-auto-debug=<logfile> ; лог положительных решений по autohostlist. позволяет разобраться почему там появляются хосты.
--new ; начало новой стратегии (новый профиль)
--skip ; не использовать этот профиль . полезно для временной деактивации профиля без удаления параметров.
--filter-l3=ipv4|ipv6 ; фильтр версии ip для текущей стратегии
--filter-tcp=[~]port1[-port2]|* ; фильтр портов tcp для текущей стратегии. ~ означает инверсию. установка фильтра tcp и неустановка фильтра udp запрещает udp. поддерживается список через запятую.
--filter-udp=[~]port1[-port2]|* ; фильтр портов udp для текущей стратегии. ~ означает инверсию. установка фильтра udp и неустановка фильтра tcp запрещает tcp. поддерживается список через запятую.
--filter-l7=<proto> ; фильтр протокола L6-L7. поддерживается несколько значений через запятую. proto : http tls quic wireguard dht discord stun unknown
--filter-ssid=ssid1[,ssid2,ssid3,...] ; фильтр по имени wifi сети (только для linux)
--ipset=<filename> ; включающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
--ipset-exclude=<filename> ; исключающий ip list. на каждой строчке ip или cidr ipv4 или ipv6. поддерживается множество листов и gzip. перечитка автоматическая.
--ipset-exclude-ip=<ip_list> ; фиксированный список подсетей через запятую. можно использовать # в начале для комментирования отдельных подсетей.
```
`--debug` позволяет выводить подробный лог действий на консоль, в syslog или в файл. Может быть важен порядок следования
@@ -270,6 +296,13 @@ dvtws, собираемый из тех же исходников (см. [док
невозможна. Если вы потом удалите файл, и у процесса не будет прав на создание файла в его директории, лог больше не
будет вестись. Вместо удаления лучше использовать truncate. В шелле это можно сделать через команду ": >filename"
Многие параметры, загружающие двоичные данные из файлов, поддерживают загрузку из hex-строки или из файла.
hex строка начинается с "0x". Имя файла можно писать как есть или использовать префикс "@".
Если перед префиксом "@" указано "+<число>", то это означает смещение полезных данных внутри файла.
Файл может загружаться целиком с нулевой позиции, к нему могут применяться модификации, требующие полного файла (TLS),
но передача пойдет с позиции offset. offset должен быть меньше длины файла. Если к блоку данных применяется мод,
который уменьшает размер данных, и offset окажется не меньше новой длины данных, будет ошибка.
### АТАКА ДЕСИНХРОНИЗАЦИИ DPI
Суть ее в следующем. Берется оригинальный запрос, модифицируется, добавляется поддельная информация (фейки)
@@ -336,6 +369,16 @@ dvtws, собираемый из тех же исходников (см. [док
выяснено, что многие провайдерские NAT не отбрасывают эти пакеты, потому работает даже с внутренним провайдерским IP.
Но linux NAT оно не пройдет, так что за домашним роутером эта техника скорее всего не сработает, но может сработать с него.
Может сработать и через роутер, если подключение по проводу, и на роутере включено аппаратное ускорение.
* Манипуляция tcp флагами с помощью `--dpi-desync-tcp-flags-set` и `--dpi-desync-tcp-flags-unset`. Можно сделать инвалидное
сочетание флагов, которое сервер не примет, а DPI - примет. Например, установить SYN в фейках. Но это может работать не на всех серверах.
`datanoack` может быть заменен `--dpi-desync-tcp-flags-unset=ACK`.
Пакеты с инвалидными флагами могут отбрасываться, проходя через NAT.
* `ts` прибавляет к значению TSval таймштампа tcp значение ts increment (по умолчанию -600000). Сервера отбрасывают пакеты
с TSval в определенных пределах. По практическим тестам инкремент должен быть где-то от -100 до -0x80000000.
timestamps генерирует клиентская ОС. В linux таймштампы включены по умолчанию, в windows выключены по умолчанию.
Можно включить через команду `netsh interface tcp set global timestamps=enabled`.
ts fooling требует, чтобы таймштампы были включены, иначе работать не будет. Включать надо на каждом клиентском устройстве.
TSecr оставляется без изменений. Так же требуется, чтобы сервер понимал timestamps, но это в большинстве случаев так.
* `autottl`. Суть режима в автоматическом определении TTL, чтобы пакет почти наверняка прошел DPI и немного не дошел до
сервера (`--dpi-desync-autottl`). Или наоборот - TTL едва хватило, чтобы он все-таки дошел до сервера (см `--dup-autottl`, `--orig-autottl`).
Берутся базовые значения TTL 64,128,255, смотрится входящий пакет (да, требуется направить первый входящий пакет на nfqws !).
@@ -353,12 +396,16 @@ dvtws, собираемый из тех же исходников (см. [док
Режимы дурения могут сочетаться в любых комбинациях. `--dpi-desync-fooling` берет множество значений через запятую.
Возможно задание множества фейков через повторение парамеров `--dpi-desync-fake-???`, кроме `--dpi-desync-fake-syndata`.
Возможно задание множества фейков через повторение параметров `--dpi-desync-fake-???`, кроме `--dpi-desync-fake-syndata`.
Фейки будут отосланы в указанном порядке. `--dpi-desync-repeats` повторяет каждый отосланный фейк.
Итоговый порядок будет такой : `fake1 fake1 fake1 fake2 fake2 fake2 fake3 fake3 fake3 .....`
### МОДИФИКАЦИЯ ФЕЙКОВ
Любые tcp фейки отправляются с исходным sequence по умолчанию, даже если их несколько.
Если задать `--dpi-desync-fake-tcp-mod=seq`, то несколько фейков будут отправлены с увеличением sequence number таким образом,
как будто они являются tcp сегментами одного фейка.
В nfqws зашит базовый вариант фейка для TLS. Его можно переопределить опцией `--dpi-desync-fake-tls`.
Переопределение фейков дает возможность использовать любые данные в качестве фейка для TLS.
Можно использовать фейковый Client Hello с любым фингерпринтом и с любым SNI.
@@ -391,17 +438,61 @@ dvtws, собираемый из тех же исходников (см. [док
* `multisplit`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях.
* `multidisorder`. нарезаем запрос на указанных в `--dpi-desync-split-pos` позициях и отправляем в обратном порядке.
* `fakedsplit`. нарезаем запрос на 2 части, обрамляя каждую часть фейками : фейк 1-й части, 1 часть, фейк 1-й части, фейк 2-й части, 2 часть, фейк 2-й части
* `fakedsplit`. различные варианты замешивания фейков и оригиналов в прямом порядке
* `fakeddisorder`. различные варианты замешивания фейков и оригиналов в обратном порядке
* `hostfakesplit` (altorder=0). фейкование части запроса с хостом : оригинал до хоста, фейк хоста, оригинал хоста (+ опционально нарезка маркером midhost), фейк хоста, оригинал после хоста
* `hostfakesplit` (altorder=1). фейкование части запроса с хостом : оригинал до хоста, фейк хоста, оригинал после хоста, оригинал хоста (+опционально нарезка маркером midhost)
* `fakeddisorder`. аналогично `fakedsplit`, только в обратном порядке : фейк 2-й части, 2 часть, фейк 2-й части, фейк 1-й части, 1 часть, фейк 1 части.
Для `fakedsplit` и `fakeddisorder` предусмотрены вариации порядка следования сегментов.
Параметр `--dpi-desync-fakedsplit-mod=altorder=N` задает число, влияющее на наличие отдельных фейков :
Режимы altorder для `fakedsplit` для части многопакетного запроса, где есть сплит-позиция :
* `altorder=0`. фейк 1-й части, 1 часть, фейк 1-й части, фейк 2-й части, 2 часть, фейк 2-й части
* `altorder=1`. 1 часть, фейк 1-й части, фейк 2-й части, 2 часть, фейк 2-й части
* `altorder=2`. 1 часть, фейк 2-й части, 2 часть, фейк 2-й части
* `altorder=3`. 1 часть, фейк 2-й части, 2 часть
Режимы altorder для `fakeddisorder` для части многопакетного запроса, где есть сплит-позиция :
* `altorder=0`. фейк 2-й части, 2 часть, фейк 2-й части, фейк 1-й части, 1 часть, фейк 1-й части
* `altorder=1`. 2 часть, фейк 2-й части, фейк 1-й части, 1 часть, фейк 1-й части
* `altorder=2`. 2 часть, фейк 1-й части, 1 часть, фейк 1-й части
* `altorder=3`. 2 часть, фейк 1-й части, 1 часть
Режимы altorder для `fakedsplit` и `fakeddisorder` для части многопакетного запроса, где нет сплит-позиции :
* `altorder=0`. фейк, оригинал, фейк
* `altorder=8`. оригинал, фейк
* `altorder=16`. оригинал
Итоговое число `altorder=N` вычисляется как сумма чисел из этих двух групп. По умолчанию `altorder=0`.
Содержимое фейков в `fakedsplit`/`fakeddisorder` определяется параметром `--dpi-desync-fakedsplit-pattern` (по умолчанию 0x00).
Данные фейков берутся из паттерна со смещением, соответствующим смещению отсылаемых частей.
Данные фейков берутся из паттерна со смещением, соответствующим смещению отсылаемых частей, учитывая смещения пакетов в многопакетных запросах.
Размеры фейков соответствуют длинам отсылаемых частей.
Цель этих режимов - максимально усложнить выявление оригинальных данных среди фейков.
Использование `fakedsplit` или `fakeddisorder` на TLS kyber с md5sig fooling может привести к ошибкам "message too long", если позиция сплита мала,
поскольку будет превышение MTU из-за md5 tcp option.
Режим 'hostfakesplit' имеет задачу минимального вмешательства фейком - как раз по той части запроса, на основании которой DPI принимает решение о блокировке. Конкретно - имени хоста.
По умолчанию фейк хоста генерируется каждый раз случайно из набора `[a-z0-9]`. При длине более 7 символов за 3 символа до конца ставится точка, имитируя TLD, а последние 3 символа заполняются одним из нескольких известных TLD.
Можно переопределить шаблон генерации с помощью `--dpi-desync-hostfakesplit-mod=host=<hostname>`. В последнем случае справа всегда будет указанный hostname.
Слева он будет дополнен до размера оригинального хоста как поддомен со случайными символами. Пример : "www.networksolutions.com" -> "h8xmdba4tv7a8.google.com".
Если размер оригинального хоста меньше шаблона, шаблон будет порезан : "habr.com" -> "ogle.com".
Если размер оригинального хоста больше шаблона на 1, получится инвалидный пустой поддомен : "www.xxx.com" => ".google.com".
Поэтому стоит использовать максимально короткие хосты из разрешенных : "ya.ru", "vk.com".
`--dpi-desync-hostfakesplit-mod=altorder=1` позволяет сменить порядок следования частей на альтернативный вариант.
`altorder=1` шлет фрагменты в таком порядке, чтобы при последовательной сборке сегментов на DPI он получил полностью собранный оригинал запроса с подмененным хостом.
Реальный хост идет отдельным сегментом уже после. То есть в этом варианте применяется разновидность disorder. Сервер принимает фрагменты с нарушенным порядком sequence.
Опционально можно разрезать оригинальный хост. Например, `--dpi-desync-hostfakesplit-midhost=midsld`. Позиция нарезки должна попадать внутрь хоста.
Многопакетные запросы поддерживаются только, если исходная нарезка пакетов не включает позиции имени хоста. В последнем случае дурение отменяется.
Вариант `fakedsplit` имеет несколько альтернативных порядков нарезки - от 0 до 3. Режим задается в параметре `--dpi-desync-fakedsplit-mod=altorder=N`.
Каждый следующий altorder убирает часть фейков.
Для определения позиций нарезки используются маркеры.
* **Абсолютный положительный маркер** - числовое смещение внутри пакета или группы пакетов от начала.
@@ -466,6 +557,27 @@ Windows оставляет старые данные, поэтому disorder с
В варианте `disorder` допустимо применение всех вариантов маркеров.
Они автоматически нормализуются к текущему пакету в серии. Можно сплитать на `midsld` и делать seqovl на `midsld-1`.
### НАЗНАЧЕНИЕ IP_ID
Некоторые DPI секут поле ipv4 заголовка ip_id. Защита заключается в распознавании нехарактерного для разных ОС порядка назначения ip_id,
но характерного для некоторого anti-DPI софта. Обычно ОС инкрементируют ip_id для каждого следующего пакета.
Например, на ТСПУ повторение ненулевых ip_id фейка и не фейка вызывает триггер блока на диапазонах IP `googlevideo.com`.
Если отсылаются фейки или дополнительные tcp сегменты, то в любом случае последовательность будет нарушена, поскольку ОС ничего не будет знать о всунутых фейках
и не увеличит свой счетчик ip_id на количество фейков или дополнительных tcp сегментов.
Чтобы сохранить последовательность, потребовалось бы перехватывать все соединение до конца, что очень затратно по ресурсам.
Поэтому после отработки серии генерированных пакетов ip_id возвращается к тому значению, о котором знает ОС.
Параметр `ip-id` относится к профилю и задает режим назначения ip_id при отсылке генерированных в nfqws пакетов.
* `seq` (по умолчанию) : взять последний ip_id реального пакета. последующие генерированыне пакеты получают увеличенные на 1 ip_id, кроме случая `multidisorder`.
для `multidisorder` в пределах сегментов, где есть сплит-позиции, значение ip_id увеличивается на количество частей, затем уменьшается на 1 с каждой отосланной частью.
* `seqgroup` : то же, что и `seq`, но фейки того же размера, что и оригинальные сегменты, маскирующиеся под оригинал получают те же ip_id.
* `rnd` : всем генерированным пакетам назначать случайный ip_id
* `zero` : всем генерированным пакетам назначать ip_id=0 . в этом случае Linux и BSD отошлют 0, Windows назначит последовательные ip_id всем пакетам (тем самым автоматически решается проблема сбоя счетчика пакетов).
В заголовках ipv6 поле ip_id отсутствует, параметр игнорируется для ipv6.
### СПЕЦИФИЧЕСКИЕ РЕЖИМЫ IPV6
Режимы десинхронизации `hopbyhop`, `destopt` и `ipfrag1` (не путать с fooling !) относятся только к ipv6 и заключается
@@ -555,7 +667,7 @@ ipcache представляет собой структуру в памяти
DPI может отстать от потока, если ClientHello его удовлетворил и не проверять ServerHello.
Тогда вам повезло. Вариант fake может сработать.
Если же он не отстает и упорно проверяет ServerHello, то можно попробовать заставить сервер высылать ServerHello частями
через параметр --wssize (см. conntrack).
через параметр `--wssize` (см. conntrack).
Если и это не помогает, то сделать с этим что-либо вряд ли возможно без помощи со стороны сервера.
Лучшее решение - включить на сервере поддержку TLS 1.3. В нем сертификат сервера передается в зашифрованном виде.
Это рекомендация ко всем админам блокируемых сайтов. Включайте TLS 1.3. Так вы дадите больше возможностей преодолеть DPI.
@@ -608,7 +720,8 @@ conntrack - простенький, он не писался с учетом в
Если вы имеете дело с не http(s), то вам потребуется параметр `--wssize-cutoff`. Он устанавливает предел, с которого действие
wssize прекращается. Префикс d перед номером означает учитывать только пакеты с data payload, префикс s - relative sequence number,
проще говоря количество переданных клиентом байтов + 1.
Если проскочит пакет с http request или TLS ClientHello, действие wssize прекращается сразу же, не дожидаясь wssize-cutoff.
Если проскочит пакет с http request или TLS ClientHello, действие wssize прекращается сразу же, не дожидаясь wssize-cutoff,
если не указан параметр `--wssize-forced-cutoff=0`.
Если ваш протокол склонен к долгому бездействию, следует увеличить таймаут фазы ESTABLISHED через параметр `--ctrack-timeouts`.
Таймаут по умолчанию низкий - всего 5 минут.
Не забывайте, что nfqws кормится приходящими на него пакетами. Если вы ограничили поступление пакетов через connbytes,
@@ -659,8 +772,11 @@ chrome рандомизирует фингерпринт TLS. SNI может о
### ПОДДЕРЖКА UDP
Атаки на udp более ограничены в возможностях. udp нельзя фрагментировать иначе, чем на уровне ip.
Для UDP действуют только режимы десинхронизации `fake`, `hopbyhop`, `destopt`, `ipfrag1`, `ipfrag2`, `udplen`, `tamper`.
Возможно сочетание `fake`, `hopbyhop`, `destopt` с `ipfrag2`, `fake`, `fakeknown` с udplen и tamper.
Для UDP действуют только режимы десинхронизации `fake`, `fakeknown`, `hopbyhop`, `destopt`, `ipfrag1`, `ipfrag2`, `udplen`, `tamper`.
Режимами первой фазы являются `fake`, `fakeknown`, `hopbyhop`, `destopt`, `ipfrag1`. Второй фазы - `ipfrag2`, `udplen`, `tamper`.
Как обычно, возможно сочетание режимов первой и второй фазы, но не двух режимов одной фазы.
`udplen` увеличивает размер udp пакета на указанное в `--dpi-desync-udplen-increment` количество байтов.
Паддинг заполняется нулями по умолчанию, но можно задать свой паттерн.
Предназначено для обмана DPI, ориентирующегося на размеры пакетов.
@@ -768,11 +884,37 @@ L7 протокол становится известен обычно посл
> [!IMPORTANT]
> user-mode реализация ipset создавалась не как удобная замена *nix версии, реализованной в ядре.
> Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без подд3ержки ipset в ядре.
> Вариант в ядре работает гораздо эффективнее. Это создавалось для систем без поддержки ipset в ядре.
> Конкретно - Windows и ядра Linux, собранные без nftables и ipset модулей ядра. Например, в android нет ipset.
### ФИЛЬТРАЦИЯ ПО WIFI
Имя wifi сети никак не связано с сетевым интерфейсом адаптера wifi.
Интерфейс один, подключиться можно к любой сети. Для разных сетей разные стратегии.
Стратегия от сети A не работает или ломает сеть B. Что делать ?
Можно вручную запускать и снимать инстансы nfqws. Но можно поступить иначе.
В windows версии winws есть глобальный фильтр `--ssid-filter`.
Он включает или отключает инстанс winws в зависимости от подключенности любого адаптера к конкретной wifi сети.
При этом не учитывается маршрутизация. Такой подход возможен потому, что к windivert можно прицепить несколько инстансов winws на пересекающихся фильтрах.
При смене wifi сети одни будут включаться, другие выключаться.
Для linux применяется иное решение. Фильтр `--filter-ssid` относится к конкретному профилю.
Невозможно повесить несколько инстансов nfqws на одну и ту же очередь или направить один и тот же трафик на несколько очередей.
Подключение и отключение от очереди разных инстансов сопряжено со сложностями синхронизации между ними.
Поэтому обрабатывать трафик должен один инстанс, и он должен уметь работать с разными wifi сетями.
Это и реализовано в параметре `--filter-ssid`. Он берет список имен wifi сетей (SSID) через запятую аналогично `--ssid-filter` для winws.
При выборе профиля имеет значение куда идет конкретный обрабатываемый пакет. На какой интерфейс. Или с какого интерфейса пакет пришел, если он считается входящим.
Поэтому даже если у вас часть трафика идет на одну сеть, часть на другую, а часть вообще не идет по wifi, то все это можно настроить.
Сканируются все wifi интерфейсы, составляется список interface->SSID. Он обновляется по мере поступления
пакетов, но не чаще 1 раза в секунду.
### IPTABLES ДЛЯ NFQWS
> [!CAUTION]
> Начиная с ядер Linux 6.17 присутствует параметр конфигурации ядра CONFIG_NETFILTER_XTABLES_LEGACY, который по умолчанию в дистрибутиве может быть "not set". Отсутствие этой настройки выключает iptables-legacy. Это часть процесса депрекации iptables. Тем не менее iptables-nft будут работать, поскольку используют backend nftables.
iptables для задействования атаки на первые пакеты данных в tcp соединении :
```
@@ -887,6 +1029,73 @@ iptables target `FLOWOFFLOAD` - это проприетарное изобрет
Управление offload в nftables реализовано в базовом ядре linux без патчей.
nftables - единственный способ включения offload на классическом Linux.
### ОСОБЕННОСТИ ЖЕЛЕЗОК
На устройствах mediatek замечены 2 проблемы.
Драйвер mediatek ethernet отбрасывает tcp и udp пакеты с неверной чексуммой на аппаратном уровне, это не отключается.
Как следствие не будет работать fooling badsum через роутер, но будет с него.
Другая проблема mediatek, затрагивающая как ethernet, так и wireless, проявляется на udp, когда включен offload rx-gro-list.
Пока отсутствует nfqueue, все хорошо. Как только nfqueue появляется, часть пакетов выпадает.
Особенно заметно это проявляется на дурении QUIC с kyber.
<details>
<summary><b>shell код лечения</b></summary>
```
append_separator_list()
{
# $1 - var name to receive result
# $2 - separator
# $3 - quoter
# $4,$5,... - elements
local _var="$1" sep="$2" quo="$3" i
eval i="\$$_var"
shift; shift; shift
while [ -n "$1" ]; do
if [ -n "$i" ] ; then
i="$i$sep$quo$1$quo"
else
i="$quo$1$quo"
fi
shift
done
eval $_var="\$i"
}
resolve_lower_devices()
{
# $1 - bridge interface name
[ -d "/sys/class/net/$1" ] && {
find "/sys/class/net/$1" -follow -maxdepth 1 -name "lower_*" |
{
local l lower lowers
while read lower; do
lower="$(basename "$lower")"
l="${lower#lower_*}"
[ "$l" != "$lower" ] && append_separator_list lowers ' ' '' "$l"
done
printf "$lowers"
}
}
}
# it breaks nfqueue
lans=$(resolve_lower_devices br-lan)
for int in $lans; do
ethtool -K $int rx-gro-list off
done
```
</details>
Этот код нужно вызывать после вставания интерфейса LAN, когда все bridge members уже занесены в bridge.
Можно использовать хук в `/etc/hotplug.d/iface`. Должен быть установлен `ethtool`.
Проблемы mediatek были подтверждены на MT7621 (TP-Link Archer C6U v1) и MT7981 (Xiaomi AX3000T).
Другие чипсеты могут быть так же подвержены проблеме, а могут и не быть. Более широкой статистики нет.
### ДУРЕНИЕ СО СТОРОНЫ СЕРВЕРА
Это тоже возможно.
@@ -1455,10 +1664,10 @@ LISTS_RELOAD=- отключает перезагрузку листов.
В системе запуска это обыграно следующим образом.
Присутствуют 2 include списка :
`ipset/zapret-hosts-users.txt.gz` или `ipset/zapret-hosts-users.txt`,
`ipset/zapret-hosts-user.txt.gz` или `ipset/zapret-hosts-user.txt`,
`ipset/zapret-hosts.txt.gz` или `ipset/zapret-hosts.txt`
и 1 exclude список
`ipset/zapret-hosts-users-exclude.txt.gz` или `ipset/zapret-hosts-users-exclude.txt`
`ipset/zapret-hosts-user-exclude.txt.gz` или `ipset/zapret-hosts-user-exclude.txt`
При режимах фильтрации `MODE_FILTER=hostlist` или `MODE_FILTER=autohostlist` система запуска передает **nfqws** или **tpws** все листы, файлы которых присутствуют.
Передача происходит через замену маркеров `<HOSTLIST>` и `<HOSTLIST_NOAUTO>` на реальные параметры `--hostlist`, `--hostlist-exclude`, `--hostlist-auto`.
@@ -1466,7 +1675,7 @@ LISTS_RELOAD=- отключает перезагрузку листов.
Файл есть, но несмотря на это дурится все, кроме exclude.
Если вам нужен именно такой режим - не обязательно удалять `zapret-hosts-users.txt`. Достаточно сделать его пустым.
Поддомены учитываются автоматически. Например, строчка "ru" вносит в список "*.ru". Строчка "*.ru" в списке не сработает.
Поддомены учитываются автоматически. Например, строчка "ru" вносит в список "\*.ru". Строчка "\*.ru" в списке не сработает.
Можно использовать символ `^` в начале хоста, чтобы отказаться от автоматического учета поддоменов.
Список доменов РКН может быть получен скриптами
@@ -1606,6 +1815,7 @@ CURL_MAX_TIME_QUIC - время таймаута curl для quic. если не
CURL_MAX_TIME_DOH - время таймаута curl для DoH серверов
CURL_CMD=1 - показывать команды curl
CURL_OPT - дополнительные параметры curl. `-k` - игнор сертификатов. `-v` - подробный вывод протокола
CURL_HTTPS_GET=1 - использовать метод GET вместо HEAD для https
DOMAINS - список тестируемых доменов через пробел
IPVS=4|6|46 - тестируемые версии ip протокола
ENABLE_HTTP=0|1 - включить тест plain http
@@ -1629,6 +1839,10 @@ SECURE_DNS=0|1 - принудительно выключить или включ
DOH_SERVERS - список URL DoH через пробел для автоматического выбора работающего сервера
DOH_SERVER - конкретный DoH URL, отказ от поиска
UNBLOCKED_DOM - незаблокированный домен, который используется для тестов IP block
MIN_TTL,MAX_TTL - пределы тестов с TTL. MAX_TTL=0 отключает тесты.
MIN_AUTOTTL_DELTA,MAX_AUTOTTL_DELTA - пределы тестов с autottl по дельте. MAX_AUTOTTL_DELTA=0 отключает тесты.
SIMULATE=1 - включить режим симуляции для отладки логики скрипта. отключаются реальные запросы через curl, заменяются рандомным результатом.
SIM_SUCCESS_RATE=<percent> - вероятность успеха симуляции в процентах
```
Пример запуска с переменными:\
@@ -1797,6 +2011,21 @@ nfqws начнет получать адреса пакетов из локал
То есть на этом профиле не происходит автоматическое добавление заблокированных доменов.
Но если на другом профиле что-то будет добавлено, то этот профиль примет изменения автоматически.
***Изменение бита mark для предотвращения зацикливания***\
`DESYNC_MARK=0x40000000`
***Изменение бита mark для пометки пакетов, проходящих по POSTNAT схеме (только nftables)***\
`DESYNC_MARK_POSTNAT=0x20000000`
***Если раскоментировано, пометка пакетов, которые должны быть обработаны zapret.***\
`#FILTER_MARK=0x10000000`
Бит должен быть установлен вашими собственными правилами.
* Для iptables - в цепочках mangle PREROUTING и mangle OUTPUT перед правилами zapret (iptables -I _после_ применения правил zapret).
* Для nftables - в хуках output и prerouting с приоритетом -102 или ниже.
Критерии пометки любые. Например, IP адрес или интерфейс источника. Это ответ на вопрос "как мне сделать, чтобы телик не ходил через zapret или чтобы через него ходил только мой комп".
***Включение стандартной опции tpws в режиме socks***\
`TPWS_SOCKS_ENABLE=0`
@@ -2286,7 +2515,7 @@ chcon u:object_r:system_file:s0 /data/local/tmp/zapret/tpws
Если компа нет, то развертка chroot - единственный вариант, хотя и неудобный.
Подойдет что-то легковесное, например, alpine или даже OpenWrt.
Если это не эмулятор android, то универсальная архитектура - arm (любой вариант).
Если вы точно знаете, что ОС у вас 64-разрядная, то лучше вместо arm - aarch64.
Если вы точно знаете, что ОС у вас 64-разрядная, то лучше вместо arm - arm64.
Выяснить архитектуру можно командой `uname -a`.
```
@@ -2495,7 +2724,9 @@ VPS можно приобрести в множестве мест. Сущест
## Поддержать разработчика
USDT `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
USDT ERC `0x3d52Ce15B7Be734c53fc9526ECbAB8267b63d66E`
USDT TRC `TEzAAtn4VhndqEaAyuCM78xh5W2gCjwWEo`
BTC `bc1qhqew3mrvp47uk2vevt5sctp7p2x9m7m5kkchve`
+6 -8
View File
@@ -1,6 +1,6 @@
Данный мануал пишется не как копипастная инструкция, а как помощь уже соображающему.
Если вы не знаете основ сетей, linux, openwrt, а пытаетесь что-то скопипастить отсюда без малейшего
понимания смысла, то маловероятно, что у вас что-то заработает. Не тратье свое время напрасно.
понимания смысла, то маловероятно, что у вас что-то заработает. Не тратьте свое время напрасно.
Цель - донести принципы как это настраивается вообще, а не указать какую буковку где вписать.
@@ -24,17 +24,15 @@ Tor поддерживает "из коробки" режим transparent proxy.
Устанавливать их нужно с опцией opkg --force-overwrite, поскольку они перепишут ssh клиент от dropbear.
После установки пакетов расслабим неоправданно жестокие права : chmod 755 /etc/ssh.
Следует создать пользователя, под которым будем крутить ssh client. Допустим, это будет 'proxy'.
Сначала установить пакет shadow-useradd.
Сначала установить пакеты shadow-useradd и shadow-su.
------------------
useradd -d /home/proxy proxy
useradd -s /bin/false -d /home/proxy proxy
mkdir -p /home/proxy
chown proxy:proxy /home/proxy
------------------
Openssh ловит разные глюки, если у него нет доступа к /dev/tty.
Добавим в /etc/rc.local строчку : "chmod 666 /dev/tty"
Сгенерируем для него ключ RSA для доступа к ssh серверу.
Сгенерируем ключ RSA для доступа к ssh серверу.
------------------
su proxy
su -s /bin/ash proxy
cd
mkdir -m 700 .ssh
cd .ssh
@@ -149,7 +147,7 @@ nfset является частью таблицы nftable и принадлеж
Чтобы использовать эти nfset-ы в своих правилах, необходимо синхронизироваться с их созданием и вносить свои цепочки в nftable "zapret".
Для этого существуют хуки - скрипты, вызываемые из zapret на определенных стадиях инициализации фаервола.
Раскоментируейте в /opt/zapret/config строчку
Раскомментируйте в /opt/zapret/config строчку
INIT_FW_POST_UP_HOOK="/etc/firewall.zapret.hook.post_up"
Создайте файл /etc/firewall.zapret.hook.post_up и присвойте ему chmod 755.
+30 -17
View File
@@ -7,7 +7,7 @@ tpws is static binary. It doesn't need a distribution.
Install `WSL` : `dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all`
Copy `binaries/x86_64/tpws_wsl.tgz` to the target system.
From release copy `binaries/linux-x86_64/tpws_wsl.tgz` to the target system.
Run : `wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz`
Run tpws : `wsl -d tpws --exec /tpws --uid=1 --no-resolve --socks --bind-addr=127.0.0.1 --port=1080 <fooling_options>`
@@ -16,7 +16,7 @@ Configure socks as `127.0.0.1:1080` in a browser or another program.
Cleanup : `wsl --unregister tpws`
Tested in windows 10 build 19041 (20.04).
Tested in windows 10 build 19041 (20.04) with WSL1.
`--oob` , `--mss` and `--disorder` do not work.
RST detection in autohostlist scheme may not work.
@@ -47,7 +47,9 @@ Task of `iptables` is done inside `winws` through `windivert` filters. `Windiver
--wf-l3=ipv4|ipv6 ; L3 protocol filter. multiple comma separated values allowed.
--wf-tcp=[~]port1[-port2] ; TCP port filter. ~ means negation. multiple comma separated values allowed.
--wf-udp=[~]port1[-port2] ; UDP port filter. ~ means negation. multiple comma separated values allowed.
--wf-raw=<filter>|@<filename> ; raw windivert filter string or filename
--wf-raw-part=<filter>|@<filename> ; partial raw windivert filter string or filename
--wf-filter-lan=0|1 ; add excluding filter for non-global IP (default : 1)
--wf-raw=<filter>|@<filename> ; full raw windivert filter string or filename. replaces --wf-tcp,--wf-udp,--wf-raw-part
--wf-save=<filename> ; save windivert filter string to a file and exit
--ssid-filter=ssid1[,ssid2,ssid3,...] ; enable winws only if any of specified wifi SSIDs connected
--nlm-filter=net1[,net2,net3,...] ; enable winws only if any of specified NLM network is connected. names and GUIDs are accepted.
@@ -60,6 +62,12 @@ Interface indexes can be discovered using this command : `netsh int ip show int`
If you can't find index this way use `winws --debug` to see index there. Subinterface index is almost always 0 and you can omit it.
`--wf-raw-part` specifies partial windivert filter. Multiple filter parts are supported. They can also be combined with `--wf-tcp`,`--wf-udp`.
`--wf-raw` specifies full windivert filter that replaces `--wf-tcp`,`--wf-udp`,`--wf-raw-part`.
Kernel filtering with windivert language is much more effective than passing massive amount of traffic to winws. Use it if possible to save CPU resources.
Multiple `winws` processes are allowed. However, it's discouraged to intersect their filters.
`--ssid-filter` allows to enable `winws` only if specified wifi networks are connected. `winws` auto detects SSID appearance and disappearance.
@@ -83,7 +91,7 @@ You must choose to install `curl`. To compile from sources install `gcc-core`,`m
Make from directory `nfq` using `make cygwin64` or `make cygwin32` for 64 and 32 bit versions.
`winws` requires `cygwin1.dll`, `windivert.dll`, `windivert64.sys` or `windivert32.sys`.
You can take them from `binaries/win64` or `binaries/win32`.
You can take them from `binaries/windows-x86_64` or `binaries/windows-x86`.
There's no `arm64` signed `windivert` driver and no `cygwin`.
But it's possible to use unsigned driver version in test mode and user mode components with x64 emulation.
@@ -128,19 +136,6 @@ If you want to run `winws` from `cygwin` delete, rename or move `cygwin1.dll`.
To simplify things it's advised to use `zapret-win-bundle`.
### auto start
To start `winws` with windows use windows task scheduler. There are `task_*.cmd` batch files in `binaries/win64/zapret-winws`.
They create, remove, start and stop scheduled task `winws1`. They must be run as administrator.
Edit `task_create.cmd` and write your `winws` parameters to `%WINWS1%` variable. If you need multiple `winws` instances
clone the code in all cmd files to support multiple tasks `winws1,winws2,winws3,...`.
Tasks can also be controlled from GUI `taskschd.msc`.
Also you can use windows services the same way with `service_*.cmd`.
### zapret-win-bundle
To make your life easier there's ready to use [bundle](https://github.com/bol-van/zapret-win-bundle) with `cygwin`,`blockcheck` and `winws`.
@@ -166,3 +161,21 @@ unix2dos winws.log
`winws.log` will be in `cygwin/home/<username>`. `unix2dos` helps with `windows 7` notepad. It's not necessary in `Windows 10` and later.
Because 32-bit systems are rare nowadays `zapret-win-bundle` exists only for `Windows x64/arm64`.
### auto start
To start `winws` with windows use windows task scheduler. There are `task_*.cmd` batch files in `binaries/windows-x86-64/zapret-winws`.
They create, remove, start and stop scheduled task `winws1`. They must be run as administrator.
Edit `task_create.cmd` and write your `winws` parameters to `%WINWS1%` variable. If you need multiple `winws` instances
clone the code in all cmd files to support multiple tasks `winws1,winws2,winws3,...`.
Tasks can also be controlled from GUI `taskschd.msc`.
Also you can use windows services the same way with `service_*.cmd`.
### Windows Server
winws is linked against wlanapi.dll which is absent by default.
To solve this problem run power shell as administrator and execute command `Install-WindowsFeature -Name Wireless-Networking`.
Then reboot the system.
+59 -37
View File
@@ -12,7 +12,7 @@ tpws в режиме socks можно запускать под более-ме
Установить WSL :
`dism.exe /online /enable-feature /featurename:Microsoft-Windows-Subsystem-Linux /all`
Скопировать на целевую систему `binaries/x86_64/tpws_wsl.tgz`.
Из релиза скопировать на целевую систему `binaries/linux-x86_64/tpws_wsl.tgz`.
Выполнить :
`wsl --import tpws "%USERPROFILE%\tpws" tpws_wsl.tgz`
@@ -24,8 +24,12 @@ tpws в режиме socks можно запускать под более-ме
Удаление : `wsl --unregister tpws`
> [!NOTE]
> Проверено на windows 10 build 19041 (20.04).
> Проверено на windows 10 build 19041 (20.04) под WSL1. На WSL2 эти команды могут не сработать.
Если у вас есть WSL2, значит у вас есть работающая виртуалка с linux.
Если вы умеете с ней обращаться, tpws на ней запустить возможно без всяких проблем.
Возможные проблемы:
- Не работают функции `--oob` и `--mss` из-за ограничений реализации WSL.
@@ -44,7 +48,7 @@ tpws в режиме socks можно запускать под более-ме
Это вариант пакетного фильтра nfqws для Windows, построенный на базе windivert.
Все функции работоспособны, однако функционал ipset в ядре отсутствует. Он реализован в user mode. Фильтры по большому количеству IP адресов невозможны.
Работа с проходящим трафиком, например в случае "расшаривания" соединения, не проверялась и не гарантируется.
Работа с проходящим трафиком, например в случае "расшаривания" соединения, невозможна.
Для работы с windivert требуются права администратора.
Специфические для unix параметры, такие как `--uid`, `--user` и тд, исключены. Все остальные параметры аналогичны nfqws и dvtws.
@@ -63,15 +67,17 @@ secure boot могут быть проблемы из-за подписи дра
Чтобы не писать сложные фильтры вручную, предусмотрены различные упрощенные варианты автоматического построения фильтров.
```
--wf-iface=<int>[.<int>] ; числовые индексы интерфейса и суб-интерфейса
--wf-l3=ipv4|ipv6 ; фильтр L3 протоколов. по умолчанию включены ipv4 и ipv6.
--wf-tcp=[~]port1[-port2] ; фильтр портов для tcp. ~ означает отрицание
--wf-udp=[~]port1[-port2] ; фильтр портов для udp. ~ означает отрицание
--wf-raw=<filter>|@<filename> ; задать напрямую фильтр windivert из параметра или из файла. имени файла предшествует символ @.
--wf-save=<filename> ; сохранить сконструированный фильтр windivert в файл для последующей правки вручную
--wf-iface=<int>[.<int>] ; числовые индексы интерфейса и суб-интерфейса
--wf-l3=ipv4|ipv6 ; фильтр L3 протоколов. по умолчанию включены ipv4 и ipv6.
--wf-tcp=[~]port1[-port2] ; фильтр портов для tcp. ~ означает отрицание
--wf-udp=[~]port1[-port2] ; фильтр портов для udp. ~ означает отрицание
--wf-raw-part=<filter>|@<filename> ; частичный windivert фильтр из параметра или из файла. имени файла предшествует символ @. может быть множество частей. сочетается с --wf-tcp,--wf-udp.
--wf-filter-lan=0|1 ; отфильтровывать адреса назначения, не являющиеся глобальными inet адресами ipv4 или ipv6. по умолчанию - 1.
--wf-raw=<filter>|@<filename> ; полный windivert фильтр из параметра или из файла. имени файла предшествует символ @. замещает --wf-raw-part,--wf-tcp,--wf-udp.
--wf-save=<filename> ; сохранить сконструированный фильтр windivert в файл для последующей правки вручную
--ssid-filter=ssid1[,ssid2,ssid3,...] ; включать winws только когда подключена любая из указанных wifi сетей
--nlm-filter=net1[,net2,net3,...] ; включать winws только когда подключена любая из указанных сетей NLM
--nlm-list[=all] ; вывести список сетей NLM. по умолчанию только подключенных, all - всех.
--nlm-filter=net1[,net2,net3,...] ; включать winws только когда подключена любая из указанных сетей NLM
--nlm-list[=all] ; вывести список сетей NLM. по умолчанию только подключенных, all - всех.
```
Параметры `--wf-l3`, `--wf-tcp`, `--wf-udp` могут брать несколько значений через запятую.
@@ -80,11 +86,19 @@ secure boot могут быть проблемы из-за подписи дра
Некоторых типы соединений там не увидеть. В этом случае запускайте **winws** с параметром `--debug` и смотрите IfIdx там.
SubInterface используется windivert, но практически всегда **0**, его можно не указывать. Вероятно, он нужен в редких случаях.
Конструктор фильтров автоматически включает входящие tcp пакеты с tcp synack и tcp rst для корректной работы функций
Конструктор стандартных фильтров автоматически включает входящие tcp пакеты с tcp synack и tcp rst для корректной работы функций
autottl и autohostlist. При включении autohostlist так же перенаправляются пакеты данных с http redirect с кодами 302 и 307.
Всегда добавляется фильтр на исключение не-интернет адресов ipv4 и ipv6.
Для сложных нестандартных сценариев могут потребоваться свои фильтры. Логично будет начать со стандартного шаблона,
сохраненного через `--wf-save`. Нужно править файл и подсовывать его в параметре `--wf-raw`. Максимальный размер фильтра - **8 Kb**.
Если не указаное иное, добавляется фильтр на исключение не-интернет адресов ipv4 и ipv6.
Для сложных нестандартных сценариев могут потребоваться свои фильтры. Полный фильтр --wf-raw замещает все остальное.
Частичные фильтры `--wf-raw-part` совместимы друг с другом и `--wf-tcp` и `--wf-udp`. Они позволяют исключить написание
громоздких полных фильтров, сосредоточившись лишь на добавлении какого-то особенного пейлоада.
`--wf-save` позволяет записать итоговый windivert фильтр в файл. Максимальный размер фильтра - **16 Kb**.
Фильтрация windivert производится в ядре. Это несравнимо легче по ресурсам, чем перенаправлять пакеты в пространство user mode,
чтобы winws принимал решение. Поэтому пользуйтесь по максимуму возможностями windivert.
Например, если вам нужно дурить wireguard на все порты, вам придется перенаправить все порты на winws. Или же написать windivert фильтр, который отсечет wireguard по содержимому пакета.
Разница в нагрузке на процессор колоссальна. В первом случае - до 100% одного ядра cpu в зависимости от объема исходящего udp трафика (привет, торрент и uTP), во втором - близко к 0.
Кроме нагрузки на процессор еще можете порезать себе скорость, тк одно ядро не будет справляться с обработкой вашего гигабитного интернета. А на старых ноутах еще и получите самолетный вой системы охлаждения, приводящий к ее износу.
Можно запускать несколько процессов **winws** с разными стратегиями. Однако, не следует делать пересекающиеся фильтры.
@@ -106,14 +120,14 @@ winws включается. Это нужно, чтобы можно было п
NLM абстрагирует типы сетевых адаптеров. Он работает как с wifi, так и с ethernet и любыми другими.
Поэтому это более универсальный метод, чем **SSID** фильтр.
Однако, есть и неприятная сторона. В windows 7 вы легко могли ткнуть на иконку сети и выбрать тип : private или public.
Там же вы могли посмотреть список сетей и обьединить их. Чтобы, допустим, вы могли подключаться по кабелю и wifi
Там же вы могли посмотреть список сетей и объединить их. Чтобы, допустим, вы могли подключаться по кабелю и wifi
к одному роутеру, и система эти подключения воспринимала как одну сеть.
В следующих версиях windows они эти возможности сильно порезали. Похоже нет встроенных средств полноценно управлять
network locations в win10/11. Кое-что есть в **powershell**.
Можно поковыряться напрямую в реестре здесь :
`HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\NetworkList`
Нужно менять ProfileGUID в `Signatures\Unmanaged`. Имена можно поменять в Profiles.
Есть кое-какие сторонние утилиты. Кое-что находится, позволяющее посмотреть и удалить network profiles, но не обьединить.
Есть кое-какие сторонние утилиты. Кое-что находится, позволяющее посмотреть и удалить network profiles, но не объединить.
Факт, что в ms они это сильно испортили. Движок network list все тот же, и он способен на все то, что было в win7.
Можно не бороться с этой проблемой, а просто указывать через запятую те названия сетей или GUIDы, которые выбрала система.
Или если у вас только wifi, то использовать `--ssid-filter`. Там хотя бы есть гарантия, что **SSID** соответствуют реальности,
@@ -123,9 +137,9 @@ network locations в win10/11. Кое-что есть в **powershell**.
Для русского языка это 866. Пути с пробелами нужно брать в кавычки.
При использовании опции @<config_file> кодировка в файле должна быть **UTF-8** без **BOM mark**.
Существует неочевидный момент, каcаемый запуска **winws** из cygwin shell\`а. Если в директории, где находится winws, находится
Существует неочевидный момент, касаемый запуска **winws** из cygwin shell\`а. Если в директории, где находится winws, находится
копия `cygwin1.dll`, **winws** не запустится.
Если нужен запуск под cygwin, то следует удалить или переместить `cygwin1.dll` из `binaries/win64`. Это нужно для работы blockcheck.
Если нужен запуск под cygwin, то следует удалить или переместить `cygwin1.dll` из `binaries/windows-x86_64`. Это нужно для работы blockcheck.
Из cygwin шелла можно посылать winws сигналы через `kill` точно так же, как в `*nix`.
Как получить совместимый с windows 7 и winws cygwin :
@@ -151,7 +165,7 @@ network locations в win10/11. Кое-что есть в **powershell**.
Требования к подписи драйверов windows изменились в 2021 году.
Официальные бесплатные обновления windows 7 закончились в 2020.
После этого несколько лет продолжали идти платные обновления по программе **ESU**.
Именно в этих **ESU** обновлениях находится обновление ядра windows 7, позволяющиее загрузить драйвер
Именно в этих **ESU** обновлениях находится обновление ядра windows 7, позволяющее загрузить драйвер
_windivert 2.2.2-A_, который идет в поставке zapret.
Поэтому варианты следующие :
@@ -169,7 +183,9 @@ https://hackandpwn.com/windows-7-esu-patching/
http://www.bifido.net/tweaks-and-scripts/8-extended-security-updates-installer.html
и обновить систему
3) Использовать UpdatePack7R2 от simplix : https://blog.simplix.info
3) Использовать готовый патчер-взламыватель ESU - "BypassESU". Его надо искать по названию.
4) Использовать UpdatePack7R2 от simplix : https://blog.simplix.info
> [!WARNING]
> Но с этим паком есть проблема. Автор из Украины, он очень обиделся на русских.
> Если в панели управления стоит регион RU или BY, появляется неприятный диалог.
@@ -203,22 +219,6 @@ _cygwin_ для обычной работы **winws** не нужен.
Однако, хотя такой способ и работает, использование **winws** сильно облегчает [zapret-win-bundle](https://github.com/bol-van/zapret-win-bundle).
Там нет проблемы с `cygwin.dll`.
## Автозапуск winws
Для запуска **winws** вместе с windows есть 2 варианта. Планировщик задач или службы windows.
Можно создавать задачи и управлять ими через консольную программу schtasks.
В директории `binaries/win64/winws` подготовлены файлы `task_*.cmd` .
В них реализовано создание, удаление, старт и стоп одной копии процесса winws с параметрами из переменной `%WINWS1%`.
Исправьте параметры на нужную вам стратегию. Если для разных фильтров применяется разная стратегия, размножьте код
для задач _winws1_,_winws2_,_winws3_,_..._
Аналогично настраивается вариант запуска через службы windows. Смотрите `service_*.cmd`.
Все батники требуется запускать от имени администратора.
Управлять задачами можно так же из графической программы управления планировщиком `taskschd.msc`
## Zapret-win-bundle
Можно не возиться с _cygwin_, а взять готовый пакет, включающий в себя _cygwin_ и _blockcheck_ : https://github.com/bol-van/zapret-win-bundle
@@ -257,3 +257,25 @@ _zapret-winws_ - это отдельный комплект для повсед
> [!CAUTION]
> Поскольку 32-битные windows мало востребованы, _zapret-win-bundle_ существует только в варианте для windows _x64/arm64_.
## Автозапуск winws
Для запуска **winws** вместе с windows есть 2 варианта. Планировщик задач или службы windows.
Можно создавать задачи и управлять ими через консольную программу schtasks.
В директории `binaries/windows-x86_64/winws` подготовлены файлы `task_*.cmd` .
В них реализовано создание, удаление, старт и стоп одной копии процесса winws с параметрами из переменной `%WINWS1%`.
Исправьте параметры на нужную вам стратегию. Если для разных фильтров применяется разная стратегия, размножьте код
для задач _winws1_,_winws2_,_winws3_,_..._
Аналогично настраивается вариант запуска через службы windows. Смотрите `service_*.cmd`.
Все батники требуется запускать от имени администратора.
Управлять задачами можно так же из графической программы управления планировщиком `taskschd.msc`
## Особенности Windows Server
winws слинкован с wlanapi.dll, который по умолчанию не установлен в windows server.
Для решения этой проблемы запустите power shell под администратором и выполните команду `Install-WindowsFeature -Name Wireless-Networking`.
После чего перезагрузите систему.
+6 -6
View File
@@ -104,11 +104,11 @@ Endpoint должен быть прописан хотя бы на одном п
менять ip и быть за nat. Endpoint пира настраивается динамически после успешной фазы
проверки ключа.
Включаем маршрутизцию :
Включаем маршрутизацию :
# echo net.ipv4.ip_forward = 1 >>/etc/sysctl.conf
# sysctl -p
Интерфейс конфигурится стандартно для дебианоподобных систем :
Интерфейс конфигурируется стандартно для дебианоподобных систем :
--/etc/network/interfaces.d/wgvps-------------
auto wgvps
@@ -203,7 +203,7 @@ config rule
Что тут было сделано :
*) Настроен интерфейс wireguard. Указан собственный приватный ключ.
*) Настроен пир-партнер с указанием его публичнго ключа и endpoint (ip:port нашего сервера)
*) Настроен пир-партнер с указанием его публичного ключа и endpoint (ip:port нашего сервера)
такая настройка заставит периодически долбиться на сервер по указанному ip
route_allowed_ip '0' запрещает автоматическое создание маршрута
allowed_ips '0.0.0.0/0' разрешает пакеты с любым адресом источника.
@@ -275,7 +275,7 @@ for ext_iface in $wan_iface; do
ipt OUTPUT -t mangle -o $DEVICE -m set --match-set ipban dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
done
network_get_device DEVICE lan
network_get_device DEVICE lan
ipt PREROUTING -t mangle -i $DEVICE -p tcp --dport 443 -m set --match-set zapret dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
ipt PREROUTING -t mangle -i $DEVICE -m set --match-set ipban dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
------------------------------------------------
@@ -429,8 +429,8 @@ for ext_iface in $wan_iface; do
ipt OUTPUT -t mangle -o $DEVICE -m set --match-set ipban dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
ipt OUTPUT -t mangle -o $DEVICE -j MARK --set-mark 0x1000/0x1000
done
network_get_device DEVICE lan
network_get_device DEVICE lan
ipt PREROUTING -t mangle -i $DEVICE -p tcp --dport 443 -m set --match-set zapret dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
ipt PREROUTING -t mangle -i $DEVICE -m set --match-set ipban dst -m set ! --match-set nozapret dst -j MARK --set-mark 0x800/0x800
+12 -11
View File
@@ -1,4 +1,5 @@
# this custom script runs desync to DHT packets with udp payload length 101..399 , without ipset/hostlist filtering
# this custom script runs desync to DHT packets with udp payload length >=5 , without ipset/hostlist filtering
# 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:---dpi-desync=tamper}"
@@ -10,28 +11,28 @@ zapret_custom_daemons()
{
# $1 - 1 - add, 0 - stop
local opt="--qnum=$QNUM_DHT4ALL $NFQWS_OPT_DESYNC_DHT"
local opt="--qnum=$QNUM_DHT4ALL $NFQWS_OPT_DESYNC_DHT"
do_nfqws $1 $DNUM_DHT4ALL "$opt"
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
# $1 - 1 - run, 0 - stop
local f uf4 uf6
local first_packet_only="$ipt_connbytes 1:1"
local f uf4 uf6
local first_packet_only="$ipt_connbytes 1:1"
f='-p udp -m length --length 109:407 -m u32 --u32'
uf4='0>>22&0x3C@8>>16=0x6431'
uf6='48>>16=0x6431'
fw_nfqws_post $1 "$f $uf4 $first_packet_only" "$f $uf6 $first_packet_only" $QNUM_DHT4ALL
f='-p udp -m u32 --u32'
uf4='0>>22&0x3C@4>>16=13:0xFFFF&&0>>22&0x3C@8>>16=0x6431:0x6432'
uf6='44>>16=13:0xFFFF&&48>>16=0x6431:0x6432'
fw_nfqws_post $1 "$f $uf4 $first_packet_only" "$f $uf6 $first_packet_only" $QNUM_DHT4ALL
}
zapret_custom_firewall_nft()
{
# stop logic is not required
# stop logic is not required
local f
local first_packet_only="$nft_connbytes 1"
f="meta length 109-407 meta l4proto udp @th,64,16 0x6431"
f="udp length ge 13 meta l4proto udp @ih,0,16 0x6431-0x6432"
nft_fw_nfqws_post "$f $first_packet_only" "$f $first_packet_only" $QNUM_DHT4ALL
}
@@ -0,0 +1,36 @@
# this custom script runs desync to all discord media packets
# 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:---dpi-desync=fake --dpi-desync-repeats=2}"
DISCORD_MEDIA_PORT_RANGE="${DISCORD_MEDIA_PORT_RANGE:-50000-50099,19294-19344}"
alloc_dnum DNUM_DISCORD_MEDIA
alloc_qnum QNUM_DISCORD_MEDIA
zapret_custom_daemons()
{
# $1 - 1 - add, 0 - stop
local opt="--qnum=$QNUM_DISCORD_MEDIA $NFQWS_OPT_DESYNC_DISCORD_MEDIA"
do_nfqws $1 $DNUM_DISCORD_MEDIA "$opt"
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local DISABLE_IPV6=1
local port_range=$(replace_char - : $DISCORD_MEDIA_PORT_RANGE)
local f="-p udp -m multiport --dports $port_range -m u32 --u32"
# this is simplified test to skip writing monstrous rule. instead of checking 64 bytes for zeroes only check 2 dwords for zero
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=0x52&&0>>22&0x3C@8=0x00010046&&0>>22&0x3C@16=0&&0>>22&0x3C@76=0" '' $QNUM_DISCORD_MEDIA
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local DISABLE_IPV6=1
local f="udp dport {$DISCORD_MEDIA_PORT_RANGE} udp length == 82 @ih,0,32 0x00010046 @ih,64,128 0x00000000000000000000000000000000 @ih,192,128 0x00000000000000000000000000000000 @ih,320,128 0x00000000000000000000000000000000 @ih,448,128 0x00000000000000000000000000000000"
nft_fw_nfqws_post "$f" '' $QNUM_DISCORD_MEDIA
}
@@ -0,0 +1,30 @@
# this custom script runs desync to all IETF QUIC initials
# 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:---dpi-desync=fake --dpi-desync-repeats=2}"
alloc_dnum DNUM_QUIC4ALL
alloc_qnum QNUM_QUIC4ALL
zapret_custom_daemons()
{
# $1 - 1 - add, 0 - stop
local opt="--qnum=$QNUM_QUIC4ALL $NFQWS_OPT_DESYNC_QUIC"
do_nfqws $1 $DNUM_QUIC4ALL "$opt"
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local f='-p udp -m u32 --u32'
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=264:65535&&0>>22&0x3C@8>>28=0xC&&0>>22&0x3C@9=0x00000001" "$f 44>>16=264:65535&&48>>28=0xC&&49=0x00000001" $QNUM_QUIC4ALL
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local f="udp length >= 264 @ih,0,4 0xC @ih,8,32 0x00000001"
nft_fw_nfqws_post "$f" "$f" $QNUM_QUIC4ALL
}
@@ -0,0 +1,30 @@
# this custom script runs desync to all stun packets
# 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:---dpi-desync=fake --dpi-desync-repeats=2}"
alloc_dnum DNUM_STUN4ALL
alloc_qnum QNUM_STUN4ALL
zapret_custom_daemons()
{
# $1 - 1 - add, 0 - stop
local opt="--qnum=$QNUM_STUN4ALL $NFQWS_OPT_DESYNC_STUN"
do_nfqws $1 $DNUM_STUN4ALL "$opt"
}
zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local f='-p udp -m u32 --u32'
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=28:65535&&0>>22&0x3C@12=0x2112A442&&0>>22&0x3C@8&0xC0000003=0" "$f 44>>16=28:65535&&52=0x2112A442&&48&0xC0000003=0" $QNUM_STUN4ALL
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local f="udp length >= 28 @ih,32,32 0x2112A442 @ih,0,2 0 @ih,30,2 0"
nft_fw_nfqws_post "$f" "$f" $QNUM_STUN4ALL
}
+8 -6
View File
@@ -1,7 +1,9 @@
# this custom script runs desync to all wireguard handshake initiation packets
# NOTE: this works for original wireguard and may not work for 3rd party implementations such as xray
# 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:---dpi-desync=fake}"
NFQWS_OPT_DESYNC_WG="${NFQWS_OPT_DESYNC_WG:---dpi-desync=fake --dpi-desync-repeats=2}"
alloc_dnum DNUM_WG4ALL
alloc_qnum QNUM_WG4ALL
@@ -10,7 +12,7 @@ zapret_custom_daemons()
{
# $1 - 1 - add, 0 - stop
local opt="--qnum=$QNUM_WG4ALL $NFQWS_OPT_DESYNC_WG"
local opt="--qnum=$QNUM_WG4ALL $NFQWS_OPT_DESYNC_WG"
do_nfqws $1 $DNUM_WG4ALL "$opt"
}
# size = 156 (8 udp header + 148 payload) && payload starts with 0x01000000
@@ -18,13 +20,13 @@ zapret_custom_firewall()
{
# $1 - 1 - run, 0 - stop
local f='-p udp -m u32 --u32'
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=0x9c&&0>>22&0x3C@8=0x01000000" "$f 44>>16=0x9c&&48=0x01000000" $QNUM_WG4ALL
local f='-p udp -m u32 --u32'
fw_nfqws_post $1 "$f 0>>22&0x3C@4>>16=0x9c&&0>>22&0x3C@8=0x01000000" "$f 44>>16=0x9c&&48=0x01000000" $QNUM_WG4ALL
}
zapret_custom_firewall_nft()
{
# stop logic is not required
local f="udp length 156 @th,64,32 0x01000000"
nft_fw_nfqws_post "$f" "$f" $QNUM_WG4ALL
local f="udp length 156 @ih,0,32 0x01000000"
nft_fw_nfqws_post "$f" "$f" $QNUM_WG4ALL
}
-3
View File
@@ -56,9 +56,6 @@ RemoveIPC=true
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
SystemCallArchitectures=native
SystemCallFilter=@system-service
SystemCallFilter=~@resources
UMask=0077
[Install]
-2
View File
@@ -55,8 +55,6 @@ RemoveIPC=true
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
SystemCallArchitectures=native
SystemCallFilter=@system-service
UMask=0077
[Install]
-1
View File
@@ -7,7 +7,6 @@ Type=forking
Restart=no
TimeoutSec=30sec
IgnoreSIGPIPE=no
KillMode=none
GuessMainPID=no
RemainAfterExit=no
ExecStart=/opt/zapret/init.d/sysv/zapret start
@@ -0,0 +1,14 @@
Цель этих фильтров - отсекать полезную нагрузку в режиме ядра, не насилуя процессор перенаправлением целого потока на winws.
Задействуются через `winws --wf-raw-part=@filename`. Может быть несколько частичных фильтров. Они могут сочетаться с --wf-tcp и --wf-udp.
Однако, язык фильтров windivert не содержит операций с битовыми полями, сдвигов и побитовой логики.
Поэтому фильтры получились более слабыми, способными передавать неправильную нагрузку.
Дофильтрация производится силами winws.
Описание языка фильтров : https://reqrypt.org/windivert-doc.html#filter_language
Пример инстанса для пробития медиапотоков в discord : `winws --wf-raw-part=@windivert_part.discord_media.txt --wf-raw-part=@windivert_part.stun.txt --filter-l7=stun,discord --dpi-desync=fake`
These filters are invoked using `winws --wf-raw-part=@filename`. Multiple filter parts are supported. They can be combined with --wf-tcp and --wf-udp.
Filters are kernel mode and save great amount of CPU.
However windivert cannot filter by bit fields, lacks shift and bitwise logic operations.
Filters are relaxed and can pass wrong payloads. Finer filtering is done by winws.
@@ -0,0 +1,20 @@
outbound and ip and
(udp.DstPort>=50000 and udp.DstPort<=50099 or udp.DstPort>=19294 and udp.DstPort<=19344) and
udp.PayloadLength=74 and
udp.Payload32[0]=0x00010046 and
udp.Payload32[2]=0 and
udp.Payload32[3]=0 and
udp.Payload32[4]=0 and
udp.Payload32[5]=0 and
udp.Payload32[6]=0 and
udp.Payload32[7]=0 and
udp.Payload32[8]=0 and
udp.Payload32[9]=0 and
udp.Payload32[10]=0 and
udp.Payload32[11]=0 and
udp.Payload32[12]=0 and
udp.Payload32[13]=0 and
udp.Payload32[14]=0 and
udp.Payload32[15]=0 and
udp.Payload32[16]=0 and
udp.Payload32[17]=0
@@ -0,0 +1,4 @@
outbound and
udp.PayloadLength>=256 and
udp.Payload[0]>=0xC0 and udp.Payload[0]<0xD0 and
udp.Payload[1]=0 and udp.Payload16[1]=0 and udp.Payload[4]=1
@@ -0,0 +1,3 @@
outbound and
udp.PayloadLength>=20 and
udp.Payload32[1]=0x2112A442 and udp.Payload[0]<0x40
@@ -0,0 +1,3 @@
outbound and
udp.PayloadLength=148 and
udp.Payload[0]=0x01
+133 -20
View File
@@ -8,6 +8,68 @@ BINDIR="$EXEDIR/$BINS"
ZAPRET_BASE=${ZAPRET_BASE:-"$EXEDIR"}
. "$ZAPRET_BASE/common/base.sh"
read_elf_arch()
{
# $1 - elf file
local arch=$(dd if="$1" count=2 bs=1 skip=18 2>/dev/null | hexdump -e '2/1 "%02x"')
local bit=$(dd if="$1" count=1 bs=1 skip=4 2>/dev/null | hexdump -e '1/1 "%02x"')
echo $bit$arch
}
select_test_method()
{
local f ELF
TEST=run
# ash and dash try to execute invalid executables as a script. they interpret binary garbage with possible negative consequences
# bash and zsh do not do this
if exists bash; then
TEST=bash
elif exists zsh && [ "$UNAME" != CYGWIN ] ; then
TEST=zsh
elif [ "$UNAME" != Darwin -a "$UNAME" != CYGWIN ]; then
if exists hexdump && exists dd; then
# macos does not use ELF
TEST=elf
ELF=
ELF_ARCH=
for f in /bin/sh /system/bin/sh; do
[ -x "$f" ] && {
ELF=$f
break
}
done
[ -n "$ELF" ] && ELF_ARCH=$(read_elf_arch "$ELF")
[ -n "$ELF_ARCH" ] && return
fi
# find does not use its own shell exec
# it uses execvp(). in musl libc it does not call shell, in glibc it DOES call /bin/sh
# that's why prefer bash or zsh if present. otherwise it's our last chance
if exists find; then
TEST=find
FIND=find
elif exists busybox; then
busybox find /jGHUa3fh1A 2>/dev/null
# 127 - command not found
[ "$?" = 127 ] || {
TEST=find
FIND="busybox find"
}
fi
fi
}
disable_antivirus()
{
# $1 - dir
[ "$UNAME" = Darwin ] && find "$1" -maxdepth 1 -type f -perm +111 -exec xattr -d com.apple.quarantine {} \; 2>/dev/null
}
check_dir()
{
local dir="$BINDIR/$1"
@@ -15,23 +77,36 @@ check_dir()
local out
if [ -f "$exe" ]; then
if [ -x "$exe" ]; then
# ash and dash try to execute invalid executables as a script. they interpret binary garbage with possible negative consequences
# bash and zsh do not do this
if exists bash; then
out=$(echo 0.0.0.0 | bash -c "\"$exe"\" 2>/dev/null)
elif exists zsh; then
out=$(echo 0.0.0.0 | zsh -c "\"$exe\"" 2>/dev/null)
else
# find does not use its own shell exec
# it uses execvp(). in musl libc it does not call shell, in glibc it DOES call /bin/sh
# that's why prefer bash or zsh if present. otherwise it's our last chance
local FIND=find
if ! exists find && exists busybox; then
FIND="busybox find"
fi
out=$(echo 0.0.0.0 | $FIND "$dir" -maxdepth 1 -name ip2net -exec {} \; 2>/dev/null)
fi
[ -n "$out" ]
disable_antivirus "$dir"
case $TEST in
bash)
out=$(echo 0.0.0.0 | bash -c "\"$exe"\" 2>/dev/null)
[ -n "$out" ]
;;
zsh)
out=$(echo 0.0.0.0 | zsh -c "\"$exe\"" 2>/dev/null)
[ -n "$out" ]
;;
elf)
out=$(read_elf_arch "$exe")
[ "$ELF_ARCH" = "$out" ] && {
# exec test to verify it actually works. no illegal instruction or crash.
out=$(echo 0.0.0.0 | "$exe" 2>/dev/null)
[ -n "$out" ]
}
;;
find)
out=$(echo 0.0.0.0 | $FIND "$dir" -maxdepth 1 -name ip2net -exec {} \; 2>/dev/null)
[ -n "$out" ]
;;
run)
out=$(echo 0.0.0.0 | "$exe" 2>/dev/null)
[ -n "$out" ]
;;
*)
false
;;
esac
else
echo >&2 "$exe is not executable. set proper chmod."
return 1
@@ -52,29 +127,65 @@ ccp()
#cp -f "../$BINS/$1" "$ZAPRET_BASE/$2" && echo copying : "../$BINS/$1" =\> "$ZAPRET_BASE/$2"
}
UNAME=$(uname)
[ "$1" = getarch ] ||
if [ ! -d "$BINDIR" ] || ! dir_is_not_empty "$BINDIR" ]; then
echo "no binaries found"
case $UNAME in
Linux)
echo "you need to download release from github or build binaries from source"
echo "building from source requires debian/ubuntu packages : make gcc zlib1g-dev libcap-dev libnetfilter-queue-dev libmnl-dev libsystemd-dev"
echo "libsystemd-dev required only on systemd based systems"
echo "on distributions with other package manager find dev package analogs"
echo "to compile on systems with systemd : make systemd"
echo "to compile on other systems : make"
;;
Darwin)
echo "you need to download release from github or build binaries from source"
echo "to compile : make mac"
;;
FreeBSD)
echo "you need to download release from github or build binaries from source"
echo "to compile : make"
;;
OpenBSD)
echo "to compile : make bsd"
;;
CYGWIN*)
echo "you need to download release from github or build binaries from source"
echo "to compile : read docs"
echo "to make things easier use zapret-win-bundle"
;;
esac
exit 1
fi
unset PKTWS
case $UNAME in
Linux)
ARCHLIST="my x86_64 x86 aarch64 arm mips64r2-msb mips32r1-lsb mips32r1-msb lexra ppc"
ARCHLIST="my linux-x86_64 linux-x86 linux-arm64 linux-arm linux-mips64 linux-mipsel linux-mips linux-lexra linux-ppc"
PKTWS=nfqws
;;
Darwin)
ARCHLIST="my mac64"
;;
FreeBSD)
ARCHLIST="my freebsd-x64"
ARCHLIST="my freebsd-x86_64"
PKTWS=dvtws
;;
CYGWIN*)
UNAME=CYGWIN
ARCHLIST="win64 win32"
ARCHLIST="windows-x86_64 windows-x86"
PKTWS=winws
;;
*)
ARCHLIST="my"
esac
select_test_method
if [ "$1" = "getarch" ]; then
for arch in $ARCHLIST
do
@@ -85,6 +196,8 @@ if [ "$1" = "getarch" ]; then
fi
done
else
echo "using arch detect method : $TEST${ELF_ARCH:+ $ELF_ARCH}"
for arch in $ARCHLIST
do
[ -d "$BINDIR/$arch" ] || continue
+31 -7
View File
@@ -50,6 +50,29 @@ check_readonly_system()
}
}
check_source()
{
local bad=0
echo \* checking source files
case $SYSTEM in
systemd)
[ -f "$EXEDIR/init.d/systemd/zapret.service" ] || bad=1
;;
openrc)
[ -f "$EXEDIR/init.d/openrc/zapret" ] || bad=1
;;
macos)
[ -f "$EXEDIR/init.d/macos/zapret" ] || bad=1
;;
esac
[ "$bad" = 1 ] && {
echo 'some critical files are missing'
echo 'are you sure you are not using embedded release ? you need full version for traditional systems'
exitp 5
}
}
check_bins()
{
echo \* checking executables
@@ -57,6 +80,7 @@ check_bins()
fix_perms_bin_test "$EXEDIR"
local arch="$(get_bin_arch)"
local make_target
local cf="-march=native"
[ "$FORCE_BUILD" = "1" ] && {
echo forced build mode
if [ "$arch" = "my" ]; then
@@ -72,12 +96,13 @@ check_bins()
case $SYSTEM in
macos)
make_target=mac
cf=
;;
systemd)
make_target=systemd
;;
esac
CFLAGS="-march=native ${CFLAGS}" make -C "$EXEDIR" $make_target || {
CFLAGS="${cf:+$cf }${CFLAGS}" OPTIMIZE=-O2 make -C "$EXEDIR" $make_target || {
echo could not compile
make -C "$EXEDIR" clean
exitp 8
@@ -230,9 +255,9 @@ select_mode_filter()
select_mode()
{
select_mode_filter
select_mode_mode
select_mode_iface
select_mode_filter
}
select_getlist()
@@ -243,10 +268,10 @@ select_getlist()
echo
if ask_yes_no $D "do you want to auto download ip/host list"; then
if [ "$MODE_FILTER" = "hostlist" -o "$MODE_FILTER" = "autohostlist" ] ; then
GETLISTS="get_refilter_domains.sh get_antizapret_domains.sh get_reestr_resolvable_domains.sh get_reestr_hostlist.sh"
GETLISTS="get_refilter_domains.sh get_antizapret_domains.sh get_reestr_resolvable_domains.sh"
GETLIST_DEF="get_antizapret_domains.sh"
else
GETLISTS="get_user.sh get_refilter_ipsum.sh get_antifilter_ip.sh get_antifilter_ipsmart.sh get_antifilter_ipsum.sh get_antifilter_ipresolve.sh get_antifilter_allyouneed.sh get_reestr_resolve.sh get_reestr_preresolved.sh get_reestr_preresolved_smart.sh"
GETLISTS="get_user.sh get_refilter_ipsum.sh get_antifilter_ip.sh get_antifilter_ipsmart.sh get_antifilter_ipsum.sh get_antifilter_ipresolve.sh get_antifilter_allyouneed.sh get_reestr_preresolved.sh get_reestr_preresolved_smart.sh"
GETLIST_DEF="get_antifilter_allyouneed.sh"
fi
ask_list GETLIST "$GETLISTS" "$GETLIST_DEF" && write_config_var GETLIST
@@ -298,7 +323,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" && {
@@ -883,8 +908,7 @@ umask 0022
fix_sbin_path
fsleep_setup
check_system
[ "$SYSTEM" = "macos" ] && . "$EXEDIR/init.d/macos/functions"
check_source
case $SYSTEM in
systemd)
+3 -2
View File
@@ -1,5 +1,6 @@
CC ?= gcc
CFLAGS += -std=gnu99 -Os -flto=auto
CC ?= cc
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_WIN = -static
LIBS =
+2 -2
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];
-65
View File
@@ -1,65 +0,0 @@
#!/bin/sh
IPSET_DIR="$(dirname "$0")"
IPSET_DIR="$(cd "$IPSET_DIR"; pwd)"
. "$IPSET_DIR/def.sh"
ZREESTR="$TMPDIR/zapret.txt.gz"
IPB="$TMPDIR/ipb.txt"
ZURL_REESTR=https://raw.githubusercontent.com/zapret-info/z-i/master/dump.csv.gz
dl_checked()
{
# $1 - url
# $2 - file
# $3 - minsize
# $4 - maxsize
# $5 - maxtime
curl -k --fail --max-time $5 --connect-timeout 10 --retry 4 --max-filesize $4 -o "$2" "$1" ||
{
echo list download failed : $1
return 2
}
dlsize=$(LC_ALL=C LANG=C wc -c "$2" | xargs | cut -f 1 -d ' ')
if test $dlsize -lt $3; then
echo list is too small : $dlsize bytes. can be bad.
return 2
fi
return 0
}
reestr_list()
{
LC_ALL=C LANG=C gunzip -c "$ZREESTR" | cut -s -f2 -d';' | LC_ALL=C LANG=C nice -n 5 sed -Ee 's/^\*\.(.+)$/\1/' -ne 's/^[a-z0-9A-Z._-]+$/&/p' | $AWK '{ print tolower($0) }'
}
reestr_extract_ip()
{
LC_ALL=C LANG=C gunzip -c | nice -n 5 $AWK -F ';' '($1 ~ /^([0-9]{1,3}\.){3}[0-9]{1,3}/) && (($2 == "" && $3 == "") || ($1 == $2)) {gsub(/ \| /, RS); print $1}' | LC_ALL=C LANG=C $AWK '{split($1, a, /\|/); for (i in a) {print a[i]}}'
}
ipban_fin()
{
getipban
"$IPSET_DIR/create_ipset.sh"
}
dl_checked "$ZURL_REESTR" "$ZREESTR" 204800 251658240 600 || {
ipban_fin
exit 2
}
reestr_list | sort -u | zz "$ZHOSTLIST"
reestr_extract_ip <"$ZREESTR" >"$IPB"
rm -f "$ZREESTR"
[ "$DISABLE_IPV4" != "1" ] && $AWK '/^([0-9]{1,3}\.){3}[0-9]{1,3}($|(\/[0-9]{2}$))/' "$IPB" | cut_local | ip2net4 | zz "$ZIPLIST_IPBAN"
[ "$DISABLE_IPV6" != "1" ] && $AWK '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}($|(\/[0-9]{2,3}$))/' "$IPB" | cut_local6 | ip2net6 | zz "$ZIPLIST_IPBAN6"
rm -f "$IPB"
hup_zapret_daemons
ipban_fin
exit 0
+6 -6
View File
@@ -10,8 +10,8 @@ TMPLIST="$TMPDIR/list.txt"
BASEURL="https://raw.githubusercontent.com/bol-van/rulist/main"
URL4="$BASEURL/reestr_resolved4.txt"
URL6="$BASEURL/reestr_resolved6.txt"
IPB4="$BASEURL/reestr_ipban4.txt"
IPB6="$BASEURL/reestr_ipban6.txt"
#IPB4="$BASEURL/reestr_ipban4.txt"
#IPB6="$BASEURL/reestr_ipban6.txt"
dl()
{
@@ -35,12 +35,12 @@ dl()
getuser && {
[ "$DISABLE_IPV4" != "1" ] && {
dl "$URL4" "$ZIPLIST" 32768 4194304
dl "$IPB4" "$ZIPLIST_IPBAN" 8192 1048576
dl "$URL4" "$ZIPLIST" 4096 4194304
# dl "$IPB4" "$ZIPLIST_IPBAN" 8192 1048576
}
[ "$DISABLE_IPV6" != "1" ] && {
dl "$URL6" "$ZIPLIST6" 8192 4194304
dl "$IPB6" "$ZIPLIST_IPBAN6" 128 1048576
dl "$URL6" "$ZIPLIST6" 2048 4194304
# dl "$IPB6" "$ZIPLIST_IPBAN6" 128 1048576
}
}
+6 -6
View File
@@ -10,8 +10,8 @@ TMPLIST="$TMPDIR/list.txt"
BASEURL="https://raw.githubusercontent.com/bol-van/rulist/main"
URL4="$BASEURL/reestr_smart4.txt"
URL6="$BASEURL/reestr_smart6.txt"
IPB4="$BASEURL/reestr_ipban4.txt"
IPB6="$BASEURL/reestr_ipban6.txt"
#IPB4="$BASEURL/reestr_ipban4.txt"
#IPB6="$BASEURL/reestr_ipban6.txt"
dl()
{
@@ -35,12 +35,12 @@ dl()
getuser && {
[ "$DISABLE_IPV4" != "1" ] && {
dl "$URL4" "$ZIPLIST" 32768 4194304
dl "$IPB4" "$ZIPLIST_IPBAN" 8192 1048576
dl "$URL4" "$ZIPLIST" 4096 4194304
# dl "$IPB4" "$ZIPLIST_IPBAN" 8192 1048576
}
[ "$DISABLE_IPV6" != "1" ] && {
dl "$URL6" "$ZIPLIST6" 8192 4194304
dl "$IPB6" "$ZIPLIST_IPBAN6" 128 1048576
dl "$URL6" "$ZIPLIST6" 2048 4194304
# dl "$IPB6" "$ZIPLIST_IPBAN6" 128 1048576
}
}
+4 -4
View File
@@ -9,8 +9,8 @@ TMPLIST="$TMPDIR/list_nethub.txt"
BASEURL="https://raw.githubusercontent.com/bol-van/rulist/main"
URL="$BASEURL/reestr_hostname_resolvable.txt"
IPB4="$BASEURL/reestr_ipban4.txt"
IPB6="$BASEURL/reestr_ipban6.txt"
#IPB4="$BASEURL/reestr_ipban4.txt"
#IPB6="$BASEURL/reestr_ipban6.txt"
dl()
{
@@ -36,8 +36,8 @@ dl "$URL" "$ZHOSTLIST" 65536 67108864
hup_zapret_daemons
[ "$DISABLE_IPV4" != "1" ] && dl "$IPB4" "$ZIPLIST_IPBAN" 8192 1048576
[ "$DISABLE_IPV6" != "1" ] && dl "$IPB6" "$ZIPLIST_IPBAN6" 128 1048576
#[ "$DISABLE_IPV4" != "1" ] && dl "$IPB4" "$ZIPLIST_IPBAN" 8192 1048576
#[ "$DISABLE_IPV6" != "1" ] && dl "$IPB6" "$ZIPLIST_IPBAN6" 128 1048576
getipban
"$IPSET_DIR/create_ipset.sh"
-83
View File
@@ -1,83 +0,0 @@
#!/bin/sh
IPSET_DIR="$(dirname "$0")"
IPSET_DIR="$(cd "$IPSET_DIR"; pwd)"
. "$IPSET_DIR/def.sh"
ZREESTR="$TMPDIR/zapret.txt.gz"
ZDIG="$TMPDIR/zapret-dig.txt"
IPB="$TMPDIR/ipb.txt"
ZIPLISTTMP="$TMPDIR/zapret-ip.txt"
#ZURL=https://reestr.rublacklist.net/api/current
ZURL_REESTR=https://raw.githubusercontent.com/zapret-info/z-i/master/dump.csv.gz
dl_checked()
{
# $1 - url
# $2 - file
# $3 - minsize
# $4 - maxsize
# $5 - maxtime
curl -k --fail --max-time $5 --connect-timeout 10 --retry 4 --max-filesize $4 -o "$2" "$1" ||
{
echo list download failed : $1
return 2
}
dlsize=$(LC_ALL=C LANG=C wc -c "$2" | xargs | cut -f 1 -d ' ')
if test $dlsize -lt $3; then
echo list is too small : $dlsize bytes. can be bad.
return 2
fi
return 0
}
reestr_list()
{
LC_ALL=C LANG=C gunzip -c "$ZREESTR" | cut -s -f2 -d';' | LC_ALL=C LANG=C nice -n 5 sed -Ee 's/^\*\.(.+)$/\1/' -ne 's/^[a-z0-9A-Z._-]+$/&/p' | $AWK '{ print tolower($0) }'
}
reestr_extract_ip()
{
LC_ALL=C LANG=C gunzip -c | nice -n 5 $AWK -F ';' '($1 ~ /^([0-9]{1,3}\.){3}[0-9]{1,3}/) && (($2 == "" && $3 == "") || ($1 == $2)) {gsub(/ \| /, RS); print $1}' | LC_ALL=C LANG=C $AWK '{split($1, a, /\|/); for (i in a) {print a[i]}}'
}
getuser && {
# both disabled
[ "$DISABLE_IPV4" = "1" ] && [ "$DISABLE_IPV6" = "1" ] && exit 0
dl_checked "$ZURL_REESTR" "$ZREESTR" 204800 251658240 600 || exit 2
echo preparing ipban list ..
reestr_extract_ip <"$ZREESTR" >"$IPB"
[ "$DISABLE_IPV4" != "1" ] && $AWK '/^([0-9]{1,3}\.){3}[0-9]{1,3}($|(\/[0-9]{2}$))/' "$IPB" | cut_local | ip2net4 | zz "$ZIPLIST_IPBAN"
[ "$DISABLE_IPV6" != "1" ] && $AWK '/^([0-9a-fA-F]{0,4}:){1,7}[0-9a-fA-F]{0,4}($|(\/[0-9]{2,3}$))/' "$IPB" | cut_local6 | ip2net6 | zz "$ZIPLIST_IPBAN6"
rm -f "$IPB"
echo preparing dig list ..
reestr_list | sort -u >"$ZDIG"
rm -f "$ZREESTR"
echo digging started. this can take long ...
[ "$DISABLE_IPV4" != "1" ] && {
filedigger "$ZDIG" 4 | cut_local >"$ZIPLISTTMP" || {
rm -f "$ZDIG"
exit 1
}
ip2net4 <"$ZIPLISTTMP" | zz "$ZIPLIST"
rm -f "$ZIPLISTTMP"
}
[ "$DISABLE_IPV6" != "1" ] && {
filedigger "$ZDIG" 6 | cut_local6 >"$ZIPLISTTMP" || {
rm -f "$ZDIG"
exit 1
}
ip2net6 <"$ZIPLISTTMP" | zz "$ZIPLIST6"
rm -f "$ZIPLISTTMP"
}
rm -f "$ZDIG"
}
"$IPSET_DIR/create_ipset.sh"
@@ -3,6 +3,7 @@
172.16.0.0/12
192.168.0.0/16
169.254.0.0/16
100.64.0.0/10
::1
fc00::/7
fe80::/10
+3 -2
View File
@@ -1,5 +1,6 @@
CC ?= gcc
CFLAGS += -std=gnu99 -Os
CC ?= cc
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE)
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_WIN = -static
LIBS = -lpthread
+46 -14
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;
+2 -1
View File
@@ -1,5 +1,6 @@
CC ?= cc
CFLAGS += -std=gnu99 -s -Os -Wno-address-of-packed-member -flto=auto
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 -s $(OPTIMIZE) -flto=auto -Wno-address-of-packed-member
LIBS = -lz
SRC_FILES = *.c crypto/*.c
+19 -11
View File
@@ -1,9 +1,16 @@
CC ?= gcc
CFLAGS += -std=gnu99 -Os -flto=auto
CC ?= cc
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto -ffunction-sections -fdata-sections
CFLAGS_SYSTEMD = -DUSE_SYSTEMD
CFLAGS_BSD = -Wno-address-of-packed-member
CFLAGS_CYGWIN = -Wno-address-of-packed-member -static
LIBS_LINUX = -lnetfilter_queue -lnfnetlink -lz
LDFLAGS += -flto=auto
LDFLAGS_ANDROID = -Wl,--gc-sections -llog
LDFLAGS_BSD = -Wl,--gc-sections
LDFLAGS_LINUX = -Wl,--gc-sections
LDFLAGS_MAC = -Wl,-dead_strip
LDFLAGS_WIN = -Wl,--gc-sections
LIBS_LINUX = -lz -lnetfilter_queue -lnfnetlink -lmnl
LIBS_SYSTEMD = -lsystemd
LIBS_BSD = -lz
LIBS_CYGWIN = -lz -Lwindows/windivert -Iwindows -lwlanapi -lole32 -loleaut32
@@ -16,27 +23,28 @@ SRC_FILES = *.c crypto/*.c
all: nfqws
nfqws: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LDFLAGS)
$(CC) -s $(CFLAGS) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LDFLAGS) $(LDFLAGS_LINUX)
systemd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LIBS_SYSTEMD) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LIBS_SYSTEMD) $(LDFLAGS) $(LDFLAGS_LINUX)
android: nfqws
android: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o nfqws $(SRC_FILES) $(LIBS_LINUX) $(LDFLAGS) $(LDFLAGS_ANDROID)
bsd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_BSD) -o dvtws $(SRC_FILES) $(LIBS_BSD) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_BSD) -o dvtws $(SRC_FILES) $(LIBS_BSD) $(LDFLAGS) $(LDFLAGS_BSD)
mac: $(SRC_FILES)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -o dvtwsa $(SRC_FILES) -target arm64-apple-macos10.8 $(LIBS_BSD) $(LDFLAGS)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -o dvtwsx $(SRC_FILES) -target x86_64-apple-macos10.8 $(LIBS_BSD) $(LDFLAGS)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -o dvtwsa $(SRC_FILES) -target arm64-apple-macos10.8 $(LIBS_BSD) $(LDFLAGS) $(LDFLAGS_MAC)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -o dvtwsx $(SRC_FILES) -target x86_64-apple-macos10.8 $(LIBS_BSD) $(LDFLAGS) $(LDFLAGS_MAC)
strip dvtwsa dvtwsx
lipo -create -output dvtws dvtwsx dvtwsa
rm -f dvtwsx dvtwsa
cygwin64:
$(CC) -s $(CFLAGS) $(CFLAGS_CYGWIN) -o winws $(SRC_FILES) $(LIBS_CYGWIN) $(LIBS_CYGWIN64) $(RES_CYGWIN64) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_CYGWIN) -o winws $(SRC_FILES) $(LIBS_CYGWIN) $(LIBS_CYGWIN64) $(RES_CYGWIN64) $(LDFLAGS) $(LDFLAGS_WIN)
cygwin32:
$(CC) -s $(CFLAGS) $(CFLAGS_CYGWIN) -o winws $(SRC_FILES) $(LIBS_CYGWIN) $(LIBS_CYGWIN32) $(RES_CYGWIN32) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_CYGWIN) -o winws $(SRC_FILES) $(LIBS_CYGWIN) $(LIBS_CYGWIN32) $(RES_CYGWIN32) $(LDFLAGS) $(LDFLAGS_WIN)
cygwin: cygwin64
clean:
+1
View File
@@ -29,6 +29,7 @@ void ConntrackClearHostname(t_ctrack *track)
{
free(track->hostname);
track->hostname = NULL;
track->hostname_is_ip = false;
}
static void ConntrackClearTrack(t_ctrack *track)
{
+4 -1
View File
@@ -83,12 +83,15 @@ typedef struct
bool b_cutoff; // mark for deletion
bool b_wssize_cutoff, b_desync_cutoff, b_dup_cutoff, b_orig_mod_cutoff;
uint16_t ip_id;
t_l7proto l7proto;
bool l7proto_discovered;
char *hostname;
bool hostname_is_ip;
bool hostname_discovered;
bool hostname_ah_check; // should perform autohostlist checks
t_reassemble reasm_orig;
struct rawpacket_tailhead delayed;
} t_ctrack;
+7 -3
View File
@@ -5,9 +5,13 @@ int aes_gcm_crypt(int mode, uint8_t *output, const uint8_t *input, size_t input_
int ret = 0;
gcm_context ctx;
gcm_setkey(&ctx, key, (const uint)key_len);
ret = gcm_crypt_and_tag(&ctx, mode, iv, iv_len, adata, adata_len, input, output, input_length, atag, atag_len);
gcm_zero_ctx(&ctx);
gcm_initialize();
if (!(ret = gcm_setkey(&ctx, key, (const uint)key_len)))
{
ret = gcm_crypt_and_tag(&ctx, mode, iv, iv_len, adata, adata_len, input, output, input_length, atag, atag_len);
gcm_zero_ctx(&ctx);
}
return ret;
}
+2 -2
View File
@@ -367,7 +367,7 @@ int aes_setkey(aes_context *ctx, // AES context provided by our caller
}
#if AES_DECRYPTION
if (mode == DECRYPT) // expand our key for encryption or decryption
if (mode == AES_DECRYPT) // expand our key for encryption or decryption
return(aes_set_decryption_key(ctx, key, keysize));
else /* ENCRYPT */
#endif /* AES_DECRYPTION */
@@ -399,7 +399,7 @@ int aes_cipher(aes_context *ctx,
#if AES_DECRYPTION // whether AES decryption is supported
if (ctx->mode == DECRYPT)
if (ctx->mode == AES_DECRYPT)
{
for (i = (ctx->rounds >> 1) - 1; i > 0; i--)
{
+21 -11
View File
@@ -246,7 +246,7 @@ int gcm_setkey(gcm_context *ctx, // pointer to caller-provided gcm context
*
******************************************************************************/
int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
int mode, // GCM_ENCRYPT or GCM_DECRYPT
int mode, // AES_ENCRYPT or AES_DECRYPT
const uchar *iv, // pointer to initialization vector
size_t iv_len, // IV length in bytes (should == 12)
const uchar *add, // ptr to additional AEAD data (NULL if none)
@@ -288,6 +288,7 @@ int gcm_start(gcm_context *ctx, // pointer to user-provided GCM context
for (i = 0; i < 16; i++) ctx->y[i] ^= work_buf[i];
gcm_mult(ctx, ctx->y, ctx->y);
}
if ((ret = aes_cipher(&ctx->aes_ctx, ctx->y, ctx->base_ectr)) != 0)
return(ret);
@@ -390,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);
@@ -427,7 +430,7 @@ int gcm_finish(gcm_context *ctx, // pointer to user-provided GCM context
******************************************************************************/
int gcm_crypt_and_tag(
gcm_context *ctx, // gcm context with key already setup
int mode, // cipher direction: GCM_ENCRYPT or GCM_DECRYPT
int mode, // cipher direction: AES_ENCRYPT or AES_DECRYPT
const uchar *iv, // pointer to the 12-byte initialization vector
size_t iv_len, // byte length if the IV. should always be 12
const uchar *add, // pointer to the non-ciphered additional data
@@ -442,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);
}
@@ -476,23 +481,28 @@ int gcm_auth_decrypt(
uchar check_tag[16]; // the tag generated and returned by decryption
int diff; // an ORed flag to detect authentication errors
size_t i; // our local iterator
int ret;
if (tag_len>16) return -1;
/*
we use GCM_DECRYPT_AND_TAG (above) to perform our decryption
(which is an identical XORing to reverse the previous one)
and also to re-generate the matching authentication tag
*/
gcm_crypt_and_tag(ctx, AES_DECRYPT, iv, iv_len, add, add_len,
input, output, length, check_tag, tag_len);
if ((ret = gcm_crypt_and_tag(ctx, AES_DECRYPT, iv, iv_len, add, add_len, input, output, length, check_tag, tag_len))) return ret;
// now we verify the authentication tag in 'constant time'
for (diff = 0, i = 0; i < tag_len; i++)
diff |= tag[i] ^ check_tag[i];
if (diff != 0) { // see whether any bits differed?
if (diff)
{
// see whether any bits differed?
memset(output, 0, length); // if so... wipe the output data
return(GCM_AUTH_FAILURE); // return GCM_AUTH_FAILURE
}
return(0);
return 0;
}
/******************************************************************************
-1
View File
@@ -29,7 +29,6 @@
#if defined(_MSC_VER)
#include <basetsd.h>
typedef unsigned int size_t;// use the right type for length declarations
typedef UINT32 uint32_t;
typedef UINT64 uint64_t;
#else
+12 -20
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;
}
+14 -21
View File
@@ -49,9 +49,10 @@ int hmac(SHAversion whichSha,
uint8_t digest[USHAMaxHashSize])
{
HMACContext context;
return hmacReset(&context, whichSha, key, key_len) ||
hmacInput(&context, message_array, length) ||
hmacResult(&context, digest);
int ret;
if ((ret=hmacReset(&context, whichSha, key, key_len))) return ret;
if ((ret=hmacInput(&context, message_array, length))) return ret;
return hmacResult(&context, digest);
}
/*
@@ -101,10 +102,8 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
*/
if (key_len > blocksize) {
USHAContext tcontext;
int err = USHAReset(&tcontext, whichSha) ||
USHAInput(&tcontext, key, key_len) ||
USHAResult(&tcontext, tempkey);
if (err != shaSuccess) return err;
if ((ret=USHAReset(&tcontext, whichSha)) || (ret=USHAInput(&tcontext, key, key_len)) || (ret=USHAResult(&tcontext, tempkey)))
return ret;
key = tempkey;
key_len = hashsize;
@@ -134,9 +133,9 @@ int hmacReset(HMACContext *context, enum SHAversion whichSha,
/* perform inner hash */
/* init context for 1st pass */
ret = USHAReset(&context->shaContext, whichSha) ||
if (!(ret = USHAReset(&context->shaContext, whichSha)))
/* and start with inner pad */
USHAInput(&context->shaContext, k_ipad, blocksize);
ret = USHAInput(&context->shaContext, k_ipad, blocksize);
return context->Corrupted = ret;
}
@@ -197,8 +196,7 @@ int hmacFinalBits(HMACContext *context,
if (context->Corrupted) return context->Corrupted;
if (context->Computed) return context->Corrupted = shaStateError;
/* then final bits of datagram */
return context->Corrupted =
USHAFinalBits(&context->shaContext, bits, bit_count);
return context->Corrupted = USHAFinalBits(&context->shaContext, bits, bit_count);
}
/*
@@ -229,21 +227,16 @@ int hmacResult(HMACContext *context, uint8_t *digest)
/* finish up 1st pass */
/* (Use digest here as a temporary buffer.) */
ret =
USHAResult(&context->shaContext, digest) ||
if (!(ret=USHAResult(&context->shaContext, digest)) &&
/* perform outer SHA */
/* init context for 2nd pass */
USHAReset(&context->shaContext, context->whichSha) ||
!(ret=USHAReset(&context->shaContext, context->whichSha)) &&
/* start with outer pad */
USHAInput(&context->shaContext, context->k_opad,
context->blockSize) ||
!(ret=USHAInput(&context->shaContext, context->k_opad, context->blockSize)) &&
/* then results of 1st hash */
USHAInput(&context->shaContext, digest, context->hashSize) ||
!(ret=USHAInput(&context->shaContext, digest, context->hashSize)))
/* finish up 2nd pass */
USHAResult(&context->shaContext, digest);
ret=USHAResult(&context->shaContext, digest);
context->Computed = 1;
return context->Corrupted = ret;
+6 -6
View File
@@ -64,12 +64,12 @@
* Add "length" to the length.
* Set Corrupted when overflow has occurred.
*/
static uint32_t addTemp;
#define SHA224_256AddLength(context, length) \
(addTemp = (context)->Length_Low, (context)->Corrupted = \
(((context)->Length_Low += (length)) < addTemp) && \
(++(context)->Length_High == 0) ? shaInputTooLong : \
(context)->Corrupted )
static int SHA224_256AddLength(SHA256Context *context, uint32_t length)
{
uint32_t addTemp = context->Length_Low;
if (((context->Length_Low += length) < addTemp) && (++(context)->Length_High == 0)) context->Corrupted = shaInputTooLong;
return context->Corrupted;
}
/* Local Function Prototypes */
static int SHA224_256Reset(SHA256Context *context, uint32_t *H0);
+389 -17
View File
@@ -29,6 +29,16 @@
#endif
#ifdef __linux__
#include <linux/nl80211.h>
#include <linux/genetlink.h>
#include <libmnl/libmnl.h>
#include <net/if.h>
#define _LINUX_IF_H // prevent conflict between linux/if.h and net/if.h in old gcc 4.x
#include <linux/wireless.h>
#include <sys/ioctl.h>
#endif
uint32_t net32_add(uint32_t netorder_value, uint32_t cpuorder_increment)
{
return htonl(ntohl(netorder_value)+cpuorder_increment);
@@ -101,13 +111,14 @@ bool tcp_has_sack(struct tcphdr *tcp)
// n prefix (nsport, nwsize) means network byte order
static void fill_tcphdr(
struct tcphdr *tcp, uint32_t fooling, uint8_t tcp_flags,
struct tcphdr *tcp, uint32_t fooling, uint16_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq,
uint16_t nsport, uint16_t ndport,
uint16_t nwsize, uint8_t scale_factor,
uint32_t *timestamps,
uint32_t ts_increment,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
uint16_t data_len)
@@ -131,7 +142,8 @@ static void fill_tcphdr(
tcp->th_off = 5;
if ((fooling & FOOL_DATANOACK) && !(tcp_flags & (TH_SYN|TH_RST)) && data_len)
tcp_flags &= ~TH_ACK;
*((uint8_t*)tcp+13)= tcp_flags;
tcp->th_flags = (uint8_t)tcp_flags;
tcp->th_x2 = (tcp_flags>>8) & 0xF;
tcp->th_win = nwsize;
if (nmss)
{
@@ -155,13 +167,13 @@ static void fill_tcphdr(
*(uint32_t*)(tcpopt+t+14)=random();
t+=18;
}
if (timestamps || (fooling & FOOL_TS))
if (timestamps)
{
tcpopt[t] = 8; // kind
tcpopt[t+1] = 10; // len
// forge only TSecr if orig timestamp is present
*(uint32_t*)(tcpopt+t+2) = timestamps ? timestamps[0] : -1;
*(uint32_t*)(tcpopt+t+6) = (timestamps && !(fooling & FOOL_TS)) ? timestamps[1] : -1;
memcpy(tcpopt+t+2,timestamps,8);
// forge TSval, keep TSecr
if (fooling & FOOL_TS) *(uint32_t*)(tcpopt+t+2) = net32_add(*(uint32_t*)(tcpopt+t+2),ts_increment);
t+=10;
}
if (scale_factor!=SCALE_NONE)
@@ -180,7 +192,7 @@ static uint16_t tcpopt_len(bool sack, bool mss, uint32_t fooling, const uint32_t
if (sack) t+=2;
if (mss) t+=4;
if (fooling & FOOL_MD5SIG) t+=18;
if ((fooling & FOOL_TS) || timestamps) t+=10;
if (timestamps) t+=10;
if (scale_factor!=SCALE_NONE) t+=3;
return (t+3)&~3;
}
@@ -220,7 +232,7 @@ static void fill_ip6hdr(struct ip6_hdr *ip6, const struct in6_addr *src, const s
bool prepare_tcp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t tcp_flags,
uint16_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq,
@@ -232,6 +244,7 @@ bool prepare_tcp_segment4(
uint8_t tos,
uint16_t ip_id,
uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
@@ -247,7 +260,7 @@ bool prepare_tcp_segment4(
uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
fill_iphdr(ip, &src->sin_addr, &dst->sin_addr, pktlen, IPPROTO_TCP, DF, ttl, tos, ip_id);
fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len);
fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin_port,dst->sin_port,nwsize,scale_factor,timestamps,ts_increment,badseq_increment,badseq_ack_increment,len);
memcpy(payload,data,len);
tcp4_fix_checksum(tcp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
@@ -259,7 +272,7 @@ bool prepare_tcp_segment4(
bool prepare_tcp_segment6(
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
uint8_t tcp_flags,
uint16_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq,
@@ -269,6 +282,7 @@ bool prepare_tcp_segment6(
uint8_t ttl,
uint32_t flow_label,
uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
@@ -333,7 +347,7 @@ bool prepare_tcp_segment6(
uint8_t *payload = (uint8_t*)(tcp+1)+tcpoptlen;
fill_ip6hdr(ip6, &src->sin6_addr, &dst->sin6_addr, ip_payload_len, proto, ttl, flow_label);
fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,badseq_increment,badseq_ack_increment,len);
fill_tcphdr(tcp,fooling,tcp_flags,sack,nmss,nseq,nack_seq,src->sin6_port,dst->sin6_port,nwsize,scale_factor,timestamps,ts_increment,badseq_increment,badseq_ack_increment,len);
memcpy(payload,data,len);
tcp6_fix_checksum(tcp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst);
@@ -345,7 +359,7 @@ bool prepare_tcp_segment6(
bool prepare_tcp_segment(
const struct sockaddr *src, const struct sockaddr *dst,
uint8_t tcp_flags,
uint16_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq,
@@ -358,15 +372,16 @@ bool prepare_tcp_segment(
uint16_t ip_id,
uint32_t flow_label,
uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen)
{
return (src->sa_family==AF_INET && dst->sa_family==AF_INET) ?
prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,DF,ttl,tos,ip_id,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
prepare_tcp_segment4((struct sockaddr_in *)src,(struct sockaddr_in *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,DF,ttl,tos,ip_id,fooling,ts_increment,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
(src->sa_family==AF_INET6 && dst->sa_family==AF_INET6) ?
prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,flow_label,fooling,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
prepare_tcp_segment6((struct sockaddr_in6 *)src,(struct sockaddr_in6 *)dst,tcp_flags,sack,nmss,nseq,nack_seq,nwsize,scale_factor,timestamps,ttl,flow_label,fooling,ts_increment,badseq_increment,badseq_ack_increment,data,len,buf,buflen) :
false;
}
@@ -406,7 +421,7 @@ bool prepare_udp_segment4(
memcpy(payload,data,len);
if (padding)
fill_pattern(payload+len,padlen,padding,padding_size);
fill_pattern(payload+len,padlen,padding,padding_size,0);
else
memset(payload+len,0,padlen);
udp4_fix_checksum(udp,ip_payload_len,&ip->ip_src,&ip->ip_dst);
@@ -495,7 +510,7 @@ bool prepare_udp_segment6(
memcpy(payload,data,len);
if (padding)
fill_pattern(payload+len,padlen,padding,padding_size);
fill_pattern(payload+len,padlen,padding,padding_size,0);
else
memset(payload+len,0,padlen);
udp6_fix_checksum(udp,transport_payload_len,&ip6->ip6_src,&ip6->ip6_dst);
@@ -667,6 +682,20 @@ bool rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl)
return false;
}
void apply_tcp_flags(struct tcphdr *tcp, uint16_t fl)
{
if (tcp)
{
tcp->th_flags = (uint8_t)fl;
tcp->th_x2 = (fl>>8) & 0xF;
}
}
uint16_t get_tcp_flags(const struct tcphdr *tcp)
{
return tcp->th_flags | (tcp->th_x2<<8);
}
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport)
{
@@ -899,6 +928,7 @@ void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type, uint8_t *
if (proto_type) *proto_type = 0; // put error in advance
HeaderType = (*data)[6]; // NextHeader field
if (proto_type) *proto_type = HeaderType;
if (last_header_type) *last_header_type = (*data)+6;
*data += 40; *len -= 40; // skip ipv6 base header
while (*len > 0) // need at least one byte for NextHeader field
@@ -907,7 +937,6 @@ void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type, uint8_t *
{
case 0: // Hop-by-Hop Options
case 43: // routing
case 51: // authentication
case 60: // Destination Options
case 135: // mobility
case 139: // Host Identity Protocol Version v2
@@ -918,6 +947,11 @@ void proto_skip_ipv6(uint8_t **data, size_t *len, uint8_t *proto_type, uint8_t *
case 44: // fragment. length fixed to 8, hdrlen field defined as reserved
hdrlen = 8;
break;
case 51: // authentication
// special case. length in ah header is in 32-bit words minus 2
if (*len < 2) return; // error
hdrlen = 8 + ((*data)[1] << 2);
break;
case 59: // no next header
return; // error
default:
@@ -1832,6 +1866,344 @@ bool rawsend_queue(struct rawpacket_tailhead *q)
}
#if defined(HAS_FILTER_SSID) && defined(__linux__)
// linux-specific wlan retrieval implementation
typedef void netlink_prepare_nlh_cb_t(struct nlmsghdr *nlh, void *param);
static bool netlink_genl_simple_transact(struct mnl_socket* nl, uint16_t type, uint16_t flags, uint8_t cmd, uint8_t version, netlink_prepare_nlh_cb_t cb_prepare_nlh, void *prepare_data, mnl_cb_t cb_data, void *data)
{
char buf[MNL_SOCKET_BUFFER_SIZE];
struct nlmsghdr *nlh;
struct genlmsghdr *genl;
ssize_t rd;
nlh = mnl_nlmsg_put_header(buf);
nlh->nlmsg_type = type;
nlh->nlmsg_flags = flags;
genl = mnl_nlmsg_put_extra_header(nlh, sizeof(struct genlmsghdr));
genl->cmd = cmd;
genl->version = version;
if (cb_prepare_nlh) cb_prepare_nlh(nlh, prepare_data);
if (mnl_socket_sendto(nl, nlh, nlh->nlmsg_len) < 0)
{
DLOG_PERROR("mnl_socket_sendto");
return false;
}
while ((rd=mnl_socket_recvfrom(nl, buf, sizeof(buf))) > 0)
{
switch(mnl_cb_run(buf, rd, 0, 0, cb_data, data))
{
case MNL_CB_STOP:
return true;
case MNL_CB_OK:
break;
default:
return false;
}
}
return false;
}
static void wlan_id_prepare(struct nlmsghdr *nlh, void *param)
{
mnl_attr_put_strz(nlh, CTRL_ATTR_FAMILY_NAME, "nl80211");
}
static int wlan_id_attr_cb(const struct nlattr *attr, void *data)
{
if (mnl_attr_type_valid(attr, CTRL_ATTR_MAX) < 0)
{
DLOG_PERROR("mnl_attr_type_valid");
return MNL_CB_ERROR;
}
switch(mnl_attr_get_type(attr))
{
case CTRL_ATTR_FAMILY_ID:
if (mnl_attr_validate(attr, MNL_TYPE_U16) < 0)
{
DLOG_PERROR("mnl_attr_validate(family_id)");
return MNL_CB_ERROR;
}
*((uint16_t*)data) = mnl_attr_get_u16(attr);
break;
}
return MNL_CB_OK;
}
static int wlan_id_cb(const struct nlmsghdr *nlh, void *data)
{
return mnl_attr_parse(nlh, sizeof(struct genlmsghdr), wlan_id_attr_cb, data);
}
static uint16_t wlan_get_family_id(struct mnl_socket* nl)
{
uint16_t id;
return netlink_genl_simple_transact(nl, GENL_ID_CTRL, NLM_F_REQUEST | NLM_F_ACK, CTRL_CMD_GETFAMILY, 1, wlan_id_prepare, NULL, wlan_id_cb, &id) ? id : 0;
}
static int wlan_info_attr_cb(const struct nlattr *attr, void *data)
{
struct wlan_interface *wlan = (struct wlan_interface *)data;
switch(mnl_attr_get_type(attr))
{
case NL80211_ATTR_IFINDEX:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
{
DLOG_PERROR("mnl_attr_validate(ifindex)");
return MNL_CB_ERROR;
}
wlan->ifindex = mnl_attr_get_u32(attr);
break;
case NL80211_ATTR_SSID:
if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
{
DLOG_PERROR("mnl_attr_validate(ssid)");
return MNL_CB_ERROR;
}
snprintf(wlan->ssid,sizeof(wlan->ssid),"%s",mnl_attr_get_str(attr));
break;
case NL80211_ATTR_IFNAME:
if (mnl_attr_validate(attr, MNL_TYPE_STRING) < 0)
{
DLOG_PERROR("mnl_attr_validate(ifname)");
return MNL_CB_ERROR;
}
snprintf(wlan->ifname,sizeof(wlan->ifname),"%s",mnl_attr_get_str(attr));
break;
}
return MNL_CB_OK;
}
struct wlan_info_req
{
struct wlan_interface_collection *wc;
bool bReqSSID;
};
static int wlan_info_cb(const struct nlmsghdr *nlh, void *data)
{
int ret;
struct wlan_info_req *wr = (struct wlan_info_req*)data;
if (wr->wc->count>=WLAN_INTERFACE_MAX) return MNL_CB_OK;
memset(wr->wc->wlan + wr->wc->count,0,sizeof(struct wlan_interface));
ret = mnl_attr_parse(nlh, sizeof(struct genlmsghdr), wlan_info_attr_cb, wr->wc->wlan + wr->wc->count);
if (ret>=0 && (!wr->bReqSSID || *wr->wc->wlan[wr->wc->count].ssid) && *wr->wc->wlan[wr->wc->count].ifname && wr->wc->wlan[wr->wc->count].ifindex)
wr->wc->count++;
return ret;
}
static bool wlan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w, bool bReqSSID)
{
struct wlan_info_req req = { .bReqSSID = bReqSSID, .wc = w };
return netlink_genl_simple_transact(nl, wlan_family_id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, NL80211_CMD_GET_INTERFACE, 0, NULL, NULL, wlan_info_cb, &req);
}
static void scan_prepare(struct nlmsghdr *nlh, void *param)
{
mnl_attr_put_u32(nlh, NL80211_ATTR_IFINDEX, *(int*)param);
}
static uint8_t *find_ie(uint8_t *buf, size_t len, uint8_t ie)
{
while (len>=2)
{
if (len<(2+buf[1])) break;
if (buf[0]==ie) return buf;
buf+=buf[1]+2;
len-=buf[1]+2;
}
return NULL;
}
static int scan_info_attr_cb(const struct nlattr *attr, void *data)
{
struct wlan_interface *wlan = (struct wlan_interface *)data;
const struct nlattr *nested;
uint8_t *payload, *ie;
uint16_t payload_len;
bool ok;
switch(mnl_attr_get_type(attr))
{
case NL80211_ATTR_IFINDEX:
if (mnl_attr_validate(attr, MNL_TYPE_U32) < 0)
{
DLOG_PERROR("mnl_attr_validate");
return MNL_CB_ERROR;
}
wlan->ifindex = mnl_attr_get_u32(attr);
if (!if_indextoname(wlan->ifindex, wlan->ifname))
DLOG_PERROR("if_indextoname");
break;
case NL80211_ATTR_BSS:
if (mnl_attr_validate(attr, MNL_TYPE_NESTED) < 0)
{
DLOG_PERROR("mnl_attr_validate");
return MNL_CB_ERROR;
}
ok = false;
mnl_attr_for_each_nested(nested, attr)
{
if (mnl_attr_get_type(nested)==NL80211_BSS_STATUS)
{
uint32_t status = mnl_attr_get_u32(nested);
if (status==NL80211_BSS_STATUS_ASSOCIATED || status==NL80211_BSS_STATUS_AUTHENTICATED || status==NL80211_BSS_STATUS_IBSS_JOINED)
{
ok=1;
break;
}
}
}
if (!ok) break;
mnl_attr_for_each_nested(nested, attr)
{
switch(mnl_attr_get_type(nested))
{
case NL80211_BSS_INFORMATION_ELEMENTS:
payload_len = mnl_attr_get_payload_len(nested);
payload = mnl_attr_get_payload(nested);
ie = find_ie(payload,payload_len,0);
if (ie)
{
uint8_t l = ie[1];
if (l>=(sizeof(wlan->ssid))) l=sizeof(wlan->ssid)-1;
memcpy(wlan->ssid,ie+2,l);
wlan->ssid[l]=0;
}
break;
}
}
break;
}
return MNL_CB_OK;
}
static int scan_info_cb(const struct nlmsghdr *nlh, void *data)
{
int ret;
struct wlan_interface_collection *wc = (struct wlan_interface_collection*)data;
if (wc->count>=WLAN_INTERFACE_MAX) return MNL_CB_OK;
memset(wc->wlan+wc->count,0,sizeof(wc->wlan[0]));
ret = mnl_attr_parse(nlh, sizeof(struct genlmsghdr), scan_info_attr_cb, wc->wlan+wc->count);
if (ret>=0 && *wc->wlan[wc->count].ssid && *wc->wlan[wc->count].ifname && wc->wlan[wc->count].ifindex)
wc->count++;
return ret;
}
static bool scan_info(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w)
{
struct wlan_interface_collection wc_all = { .count = 0 };
// wlan_info does not return ssid since kernel 5.19
// it's used to enumerate all wifi interfaces then call scan_info on each
if (!wlan_info(nl, wlan_family_id, &wc_all, false)) return false;
w->count=0;
for(int i=0;i<wc_all.count;i++)
if (!netlink_genl_simple_transact(nl, wlan_family_id, NLM_F_REQUEST | NLM_F_ACK | NLM_F_DUMP, NL80211_CMD_GET_SCAN, 0, scan_prepare, (void*)&wc_all.wlan[i].ifindex, scan_info_cb, w))
return false;
return true;
}
static bool wlan_init80211(struct mnl_socket** nl)
{
if (!(*nl = mnl_socket_open(NETLINK_GENERIC)))
{
DLOG_PERROR("mnl_socket_open");
return false;
}
if (mnl_socket_bind(*nl, 0, MNL_SOCKET_AUTOPID))
{
DLOG_PERROR("mnl_socket_bind");
return false;
}
return true;
}
static void wlan_deinit80211(struct mnl_socket** nl)
{
if (*nl)
{
mnl_socket_close(*nl);
*nl = NULL;
}
}
static time_t wlan_info_last = 0;
static bool wlan_info_rate_limited(struct mnl_socket* nl, uint16_t wlan_family_id, struct wlan_interface_collection* w)
{
bool bres = true;
time_t now = time(NULL);
// do not purge too often to save resources
if (wlan_info_last != now)
{
bres = scan_info(nl,wlan_family_id,w);
wlan_info_last = now;
}
return bres;
}
static struct mnl_socket* nl_wifi = NULL;
static uint16_t id_nl80211;
struct wlan_interface_collection wlans = { .count = 0 };
void wlan_info_deinit(void)
{
wlan_deinit80211(&nl_wifi);
}
bool wlan_info_init(void)
{
wlan_info_deinit();
if (!wlan_init80211(&nl_wifi)) return false;
if (!(id_nl80211 = wlan_get_family_id(nl_wifi)))
{
wlan_info_deinit();
return false;
}
return true;
}
bool wlan_info_get_rate_limited(void)
{
return wlan_info_rate_limited(nl_wifi, id_nl80211, &wlans);
}
#endif
#ifdef HAS_FILTER_SSID
const char *wlan_ifname2ssid(const struct wlan_interface_collection *w, const char *ifname)
{
int i;
if (ifname)
{
for (i=0;i<w->count;i++)
if (!strcmp(w->wlan[i].ifname,ifname))
return w->wlan[i].ssid;
}
return NULL;
}
const char *wlan_ifidx2ssid(const struct wlan_interface_collection *w,int ifidx)
{
int i;
for (i=0;i<w->count;i++)
if (w->wlan[i].ifindex == ifidx)
return w->wlan[i].ssid;
return NULL;
}
const char *wlan_ssid_search_ifname(const char *ifname)
{
return wlan_ifname2ssid(&wlans,ifname);
}
const char *wlan_ssid_search_ifidx(int ifidx)
{
return wlan_ifidx2ssid(&wlans,ifidx);
}
#endif
uint8_t hop_count_guess(uint8_t ttl)
{
// 18.65.168.125 ( cloudfront ) 255
+34 -3
View File
@@ -1,5 +1,6 @@
#pragma once
#include "nfqws.h"
#include "checksum.h"
#include "packet_queue.h"
#include "pools.h"
@@ -68,7 +69,7 @@ uint32_t net16_add(uint16_t netorder_value, uint16_t cpuorder_increment);
// seq and wsize have network byte order
bool prepare_tcp_segment4(
const struct sockaddr_in *src, const struct sockaddr_in *dst,
uint8_t tcp_flags,
uint16_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq,
@@ -80,13 +81,14 @@ bool prepare_tcp_segment4(
uint8_t tos,
uint16_t ip_id,
uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);
bool prepare_tcp_segment6(
const struct sockaddr_in6 *src, const struct sockaddr_in6 *dst,
uint8_t tcp_flags,
uint16_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq,
@@ -96,13 +98,14 @@ bool prepare_tcp_segment6(
uint8_t ttl,
uint32_t flow_label,
uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
uint8_t *buf, size_t *buflen);
bool prepare_tcp_segment(
const struct sockaddr *src, const struct sockaddr *dst,
uint8_t tcp_flags,
uint16_t tcp_flags,
bool sack,
uint16_t nmss,
uint32_t nseq, uint32_t nack_seq,
@@ -115,6 +118,7 @@ bool prepare_tcp_segment(
uint16_t ip_id,
uint32_t flow_label,
uint32_t fooling,
uint32_t ts_increment,
uint32_t badseq_increment,
uint32_t badseq_ack_increment,
const void *data, uint16_t len,
@@ -174,6 +178,8 @@ bool ip_frag(
uint8_t *pkt2, size_t *pkt2_size);
bool rewrite_ttl(struct ip *ip, struct ip6_hdr *ip6, uint8_t ttl);
uint16_t get_tcp_flags(const struct tcphdr *tcp);
void apply_tcp_flags(struct tcphdr *tcp, uint16_t fl);
void extract_ports(const struct tcphdr *tcphdr, const struct udphdr *udphdr, uint8_t *proto, uint16_t *sport, uint16_t *dport);
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);
@@ -272,3 +278,28 @@ void verdict_udp_csum_fix(uint8_t verdict, struct udphdr *udphdr, size_t transpo
void dbgprint_socket_buffers(int fd);
bool set_socket_buffers(int fd, int rcvbuf, int sndbuf);
#ifdef HAS_FILTER_SSID
struct wlan_interface
{
int ifindex;
char ifname[IFNAMSIZ], ssid[33];
};
#define WLAN_INTERFACE_MAX 16
struct wlan_interface_collection
{
int count;
struct wlan_interface wlan[WLAN_INTERFACE_MAX];
};
extern struct wlan_interface_collection wlans;
void wlan_info_deinit(void);
bool wlan_info_init(void);
bool wlan_info_get_rate_limited(void);
const char *wlan_ssid_search_ifname(const char *ifname);
const char *wlan_ssid_search_ifidx(int ifidx);
#endif
+1533 -1099
View File
File diff suppressed because it is too large Load Diff
+1
View File
@@ -32,6 +32,7 @@ enum dpi_desync_mode {
DESYNC_FAKEDDISORDER,
DESYNC_MULTISPLIT,
DESYNC_MULTIDISORDER,
DESYNC_HOSTFAKESPLIT,
DESYNC_IPFRAG2,
DESYNC_HOPBYHOP,
DESYNC_DESTOPT,
+80 -35
View File
@@ -13,7 +13,7 @@
int unique_size_t(size_t *pu, int ct)
{
int i, j, u;
size_t i, j, u;
for (i = j = 0; j < ct; i++)
{
u = pu[j++];
@@ -113,6 +113,71 @@ bool append_to_list_file(const char *filename, const char *s)
return bOK;
}
void expand_bits(void *target, const void *source, unsigned int source_bitlen, unsigned int target_bytelen)
{
unsigned int target_bitlen = target_bytelen<<3;
unsigned int bitlen = target_bitlen<source_bitlen ? target_bitlen : source_bitlen;
unsigned int bytelen = bitlen>>3;
if ((target_bytelen-bytelen)>=1) memset(target+bytelen,0,target_bytelen-bytelen);
memcpy(target,source,bytelen);
if ((bitlen &= 7)) ((uint8_t*)target)[bytelen] = ((uint8_t*)source)[bytelen] & (~((1 << (8-bitlen)) - 1));
}
// " [fd00::1]" => "fd00::1"
// "[fd00::1]:8000" => "fd00::1"
// "127.0.0.1" => "127.0.0.1"
// " 127.0.0.1:8000" => "127.0.0.1"
// " vk.com:8000" => "vk.com"
// return value: true - host is ip addr
bool strip_host_to_ip(char *host)
{
size_t l;
char *h,*p;
uint8_t addr[16];
for (h = host ; *h==' ' || *h=='\t' ; h++);
l = strlen(h);
if (l>=2)
{
if (*h=='[')
{
// ipv6 ?
for (p=++h ; *p && *p!=']' ; p++);
if (*p==']')
{
l = p-h;
memmove(host,h,l);
host[l]=0;
return inet_pton(AF_INET6, host, addr)>0;
}
}
else
{
if (inet_pton(AF_INET6, h, addr)>0)
{
// ipv6 ?
if (host!=h)
{
l = strlen(h);
memmove(host,h,l);
host[l]=0;
}
return true;
}
else
{
// ipv4 ?
for (p=h ; *p && *p!=':' ; p++);
l = p-h;
if (host!=h) memmove(host,h,l);
host[l]=0;
return inet_pton(AF_INET, host, addr)>0;
}
}
}
return false;
}
void ntop46(const struct sockaddr *sa, char *str, size_t len)
{
@@ -156,7 +221,8 @@ void print_sockaddr(const struct sockaddr *sa)
bool pton4_port(const char *s, struct sockaddr_in *sa)
{
char ip[16],*p;
char ip[16];
const char *p;
size_t l;
unsigned int u;
@@ -176,7 +242,8 @@ bool pton4_port(const char *s, struct sockaddr_in *sa)
}
bool pton6_port(const char *s, struct sockaddr_in6 *sa)
{
char ip[40],*p;
char ip[40];
const char *p;
size_t l;
unsigned int u;
@@ -273,10 +340,18 @@ bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size)
return true;
}
void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize)
void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize,size_t offset)
{
size_t size;
if (offset%=patsize)
{
size = patsize-offset;
size = bufsize>size ? size : bufsize;
memcpy(buf,pattern+offset,size);
buf += size;
bufsize -= size;
}
while (bufsize)
{
size = bufsize>patsize ? patsize : bufsize;
@@ -404,43 +479,13 @@ bool set_env_exedir(const char *argv0)
if ((s = strdup(argv0)))
{
if ((d = dirname(s)))
setenv("EXEDIR",s,1);
bOK = !setenv("EXEDIR",d,1);
free(s);
}
return bOK;
}
static void mask_from_preflen6_make(uint8_t plen, struct in6_addr *a)
{
if (plen >= 128)
memset(a->s6_addr,0xFF,16);
else
{
uint8_t n = plen >> 3;
memset(a->s6_addr,0xFF,n);
memset(a->s6_addr+n,0x00,16-n);
a->s6_addr[n] = (uint8_t)(0xFF00 >> (plen & 7));
}
}
struct in6_addr ip6_mask[129];
void mask_from_preflen6_prepare(void)
{
for (int plen=0;plen<=128;plen++) mask_from_preflen6_make(plen, ip6_mask+plen);
}
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize ("no-strict-aliasing")))
#endif
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result)
{
// int128 requires 16-bit alignment. in struct sockaddr_in6.sin6_addr is 8-byte aligned.
// it causes segfault on x64 arch with latest compiler. it can cause misalign slowdown on other archs
// use 64-bit AND
((uint64_t*)result->s6_addr)[0] = ((uint64_t*)a->s6_addr)[0] & ((uint64_t*)b->s6_addr)[0];
((uint64_t*)result->s6_addr)[1] = ((uint64_t*)a->s6_addr)[1] & ((uint64_t*)b->s6_addr)[1];
}
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr)
{
char s_ip[16];
+5 -13
View File
@@ -31,6 +31,10 @@ bool load_file_nonempty(const char *filename,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);
void expand_bits(void *target, const void *source, unsigned int source_bitlen, unsigned int target_bytelen);
bool strip_host_to_ip(char *host);
void print_sockaddr(const struct sockaddr *sa);
void ntop46(const struct sockaddr *sa, char *str, size_t len);
void ntop46_port(const struct sockaddr *sa, char *str, size_t len);
@@ -66,7 +70,7 @@ static inline uint32_t pntoh32(const uint8_t *p) {
}
bool parse_hex_str(const char *s, uint8_t *pbuf, size_t *size);
void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize);
void fill_pattern(uint8_t *buf,size_t bufsize,const void *pattern,size_t patsize,size_t offset);
int fprint_localtime(FILE *F);
@@ -114,15 +118,3 @@ 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);
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;
}
+7 -6
View File
@@ -170,7 +170,7 @@ bool LoadAllHostLists()
static bool SearchHostList(hostlist_pool *hostlist, const char *host)
static bool SearchHostList(hostlist_pool *hostlist, const char *host, bool no_match_subdomains)
{
if (hostlist)
{
@@ -195,6 +195,7 @@ static bool SearchHostList(hostlist_pool *hostlist, const char *host)
}
else
DLOG("negative\n");
if (no_match_subdomains) break;
p = strchr(p, '.');
if (p) p++;
bHostFull = false;
@@ -220,7 +221,7 @@ bool HostlistsReloadCheckForProfile(const struct desync_profile *dp)
return HostlistsReloadCheck(&dp->hl_collection) && HostlistsReloadCheck(&dp->hl_collection_exclude);
}
// return : true = apply fooling, false = do not apply
static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, const struct hostlist_collection_head *hostlists_exclude, const char *host, bool *excluded, bool bSkipReloadCheck)
static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, const struct hostlist_collection_head *hostlists_exclude, const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck)
{
struct hostlist_item *item;
@@ -233,7 +234,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
LIST_FOREACH(item, hostlists_exclude, next)
{
DLOG("[%s] exclude ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host))
if (SearchHostList(item->hfile->hostlist, host, no_match_subdomains))
{
if (excluded) *excluded = true;
return false;
@@ -245,7 +246,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
LIST_FOREACH(item, hostlists, next)
{
DLOG("[%s] include ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host))
if (SearchHostList(item->hfile->hostlist, host, no_match_subdomains))
return true;
}
return false;
@@ -255,10 +256,10 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
// return : true = apply fooling, false = do not apply
bool HostlistCheck(const struct desync_profile *dp, const char *host, bool *excluded, bool bSkipReloadCheck)
bool HostlistCheck(const struct desync_profile *dp, const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck)
{
DLOG("* hostlist check for profile %d\n",dp->n);
return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, excluded, bSkipReloadCheck);
return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, no_match_subdomains, excluded, bSkipReloadCheck);
}
+1 -1
View File
@@ -9,7 +9,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename);
bool LoadAllHostLists();
bool NonEmptyHostlist(hostlist_pool **hostlist);
// return : true = apply fooling, false = do not apply
bool HostlistCheck(const struct desync_profile *dp,const char *host, bool *excluded, bool bSkipReloadCheck);
bool HostlistCheck(const struct desync_profile *dp,const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck);
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename);
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp);
void HostlistsDebug();
+400
View File
@@ -0,0 +1,400 @@
/* The MIT License
Copyright (c) 2018 by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/* An example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "kavl.h"
struct my_node {
char key;
KAVL_HEAD(struct my_node) head;
};
#define my_cmp(p, q) (((q)->key < (p)->key) - ((p)->key < (q)->key))
KAVL_INIT(my, struct my_node, head, my_cmp)
int main(void) {
const char *str = "MNOLKQOPHIA"; // from wiki, except a duplicate
struct my_node *root = 0;
int i, l = strlen(str);
for (i = 0; i < l; ++i) { // insert in the input order
struct my_node *q, *p = malloc(sizeof(*p));
p->key = str[i];
q = kavl_insert(my, &root, p, 0);
if (p != q) free(p); // if already present, free
}
kavl_itr_t(my) itr;
kavl_itr_first(my, root, &itr); // place at first
do { // traverse
const struct my_node *p = kavl_at(&itr);
putchar(p->key);
free((void*)p); // free node
} while (kavl_itr_next(my, &itr));
putchar('\n');
return 0;
}
*/
#ifndef KAVL_H
#define KAVL_H
#ifdef __STRICT_ANSI__
#define inline __inline__
#endif
#define KAVL_MAX_DEPTH 64
#define kavl_size(head, p) ((p)? (p)->head.size : 0)
#define kavl_size_child(head, q, i) ((q)->head.p[(i)]? (q)->head.p[(i)]->head.size : 0)
#define KAVL_HEAD(__type) \
struct { \
__type *p[2]; \
signed char balance; /* balance factor */ \
unsigned size; /* #elements in subtree */ \
}
#define __KAVL_FIND(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_find_##suf(const __type *root, const __type *x, unsigned *cnt_) { \
const __type *p = root; \
unsigned cnt = 0; \
while (p != 0) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp >= 0) cnt += kavl_size_child(__head, p, 0) + 1; \
if (cmp < 0) p = p->__head.p[0]; \
else if (cmp > 0) p = p->__head.p[1]; \
else break; \
} \
if (cnt_) *cnt_ = cnt; \
return (__type*)p; \
}
#define __KAVL_ROTATE(suf, __type, __head) \
/* one rotation: (a,(b,c)q)p => ((a,b)p,c)q */ \
static inline __type *kavl_rotate1_##suf(__type *p, int dir) { /* dir=0 to left; dir=1 to right */ \
int opp = 1 - dir; /* opposite direction */ \
__type *q = p->__head.p[opp]; \
unsigned size_p = p->__head.size; \
p->__head.size -= q->__head.size - kavl_size_child(__head, q, dir); \
q->__head.size = size_p; \
p->__head.p[opp] = q->__head.p[dir]; \
q->__head.p[dir] = p; \
return q; \
} \
/* two consecutive rotations: (a,((b,c)r,d)q)p => ((a,b)p,(c,d)q)r */ \
static inline __type *kavl_rotate2_##suf(__type *p, int dir) { \
int b1, opp = 1 - dir; \
__type *q = p->__head.p[opp], *r = q->__head.p[dir]; \
unsigned size_x_dir = kavl_size_child(__head, r, dir); \
r->__head.size = p->__head.size; \
p->__head.size -= q->__head.size - size_x_dir; \
q->__head.size -= size_x_dir + 1; \
p->__head.p[opp] = r->__head.p[dir]; \
r->__head.p[dir] = p; \
q->__head.p[dir] = r->__head.p[opp]; \
r->__head.p[opp] = q; \
b1 = dir == 0? +1 : -1; \
if (r->__head.balance == b1) q->__head.balance = 0, p->__head.balance = -b1; \
else if (r->__head.balance == 0) q->__head.balance = p->__head.balance = 0; \
else q->__head.balance = b1, p->__head.balance = 0; \
r->__head.balance = 0; \
return r; \
}
#define __KAVL_INSERT(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_insert_##suf(__type **root_, __type *x, unsigned *cnt_) { \
unsigned char stack[KAVL_MAX_DEPTH]; \
__type *path[KAVL_MAX_DEPTH]; \
__type *bp, *bq; \
__type *p, *q, *r = 0; /* _r_ is potentially the new root */ \
int i, which = 0, top, b1, path_len; \
unsigned cnt = 0; \
bp = *root_, bq = 0; \
/* find the insertion location */ \
for (p = bp, q = bq, top = path_len = 0; p; q = p, p = p->__head.p[which]) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp >= 0) cnt += kavl_size_child(__head, p, 0) + 1; \
if (cmp == 0) { \
if (cnt_) *cnt_ = cnt; \
return p; \
} \
if (p->__head.balance != 0) \
bq = q, bp = p, top = 0; \
stack[top++] = which = (cmp > 0); \
path[path_len++] = p; \
} \
if (cnt_) *cnt_ = cnt; \
x->__head.balance = 0, x->__head.size = 1, x->__head.p[0] = x->__head.p[1] = 0; \
if (q == 0) *root_ = x; \
else q->__head.p[which] = x; \
if (bp == 0) return x; \
for (i = 0; i < path_len; ++i) ++path[i]->__head.size; \
for (p = bp, top = 0; p != x; p = p->__head.p[stack[top]], ++top) /* update balance factors */ \
if (stack[top] == 0) --p->__head.balance; \
else ++p->__head.balance; \
if (bp->__head.balance > -2 && bp->__head.balance < 2) return x; /* no re-balance needed */ \
/* re-balance */ \
which = (bp->__head.balance < 0); \
b1 = which == 0? +1 : -1; \
q = bp->__head.p[1 - which]; \
if (q->__head.balance == b1) { \
r = kavl_rotate1_##suf(bp, which); \
q->__head.balance = bp->__head.balance = 0; \
} else r = kavl_rotate2_##suf(bp, which); \
if (bq == 0) *root_ = r; \
else bq->__head.p[bp != bq->__head.p[0]] = r; \
return x; \
}
#define __KAVL_ERASE(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_erase_##suf(__type **root_, const __type *x, unsigned *cnt_) { \
__type *p, *path[KAVL_MAX_DEPTH], fake; \
unsigned char dir[KAVL_MAX_DEPTH]; \
int i, d = 0, cmp; \
unsigned cnt = 0; \
fake.__head.p[0] = *root_, fake.__head.p[1] = 0; \
if (cnt_) *cnt_ = 0; \
if (x) { \
for (cmp = -1, p = &fake; cmp; cmp = __cmp(x, p)) { \
int which = (cmp > 0); \
if (cmp > 0) cnt += kavl_size_child(__head, p, 0) + 1; \
dir[d] = which; \
path[d++] = p; \
p = p->__head.p[which]; \
if (p == 0) { \
if (cnt_) *cnt_ = 0; \
return 0; \
} \
} \
cnt += kavl_size_child(__head, p, 0) + 1; /* because p==x is not counted */ \
} else { \
for (p = &fake, cnt = 1; p; p = p->__head.p[0]) \
dir[d] = 0, path[d++] = p; \
p = path[--d]; \
} \
if (cnt_) *cnt_ = cnt; \
for (i = 1; i < d; ++i) --path[i]->__head.size; \
if (p->__head.p[1] == 0) { /* ((1,.)2,3)4 => (1,3)4; p=2 */ \
path[d-1]->__head.p[dir[d-1]] = p->__head.p[0]; \
} else { \
__type *q = p->__head.p[1]; \
if (q->__head.p[0] == 0) { /* ((1,2)3,4)5 => ((1)2,4)5; p=3 */ \
q->__head.p[0] = p->__head.p[0]; \
q->__head.balance = p->__head.balance; \
path[d-1]->__head.p[dir[d-1]] = q; \
path[d] = q, dir[d++] = 1; \
q->__head.size = p->__head.size - 1; \
} else { /* ((1,((.,2)3,4)5)6,7)8 => ((1,(2,4)5)3,7)8; p=6 */ \
__type *r; \
int e = d++; /* backup _d_ */\
for (;;) { \
dir[d] = 0; \
path[d++] = q; \
r = q->__head.p[0]; \
if (r->__head.p[0] == 0) break; \
q = r; \
} \
r->__head.p[0] = p->__head.p[0]; \
q->__head.p[0] = r->__head.p[1]; \
r->__head.p[1] = p->__head.p[1]; \
r->__head.balance = p->__head.balance; \
path[e-1]->__head.p[dir[e-1]] = r; \
path[e] = r, dir[e] = 1; \
for (i = e + 1; i < d; ++i) --path[i]->__head.size; \
r->__head.size = p->__head.size - 1; \
} \
} \
while (--d > 0) { \
__type *q = path[d]; \
int which, other, b1 = 1, b2 = 2; \
which = dir[d], other = 1 - which; \
if (which) b1 = -b1, b2 = -b2; \
q->__head.balance += b1; \
if (q->__head.balance == b1) break; \
else if (q->__head.balance == b2) { \
__type *r = q->__head.p[other]; \
if (r->__head.balance == -b1) { \
path[d-1]->__head.p[dir[d-1]] = kavl_rotate2_##suf(q, which); \
} else { \
path[d-1]->__head.p[dir[d-1]] = kavl_rotate1_##suf(q, which); \
if (r->__head.balance == 0) { \
r->__head.balance = -b1; \
q->__head.balance = b1; \
break; \
} else r->__head.balance = q->__head.balance = 0; \
} \
} \
} \
*root_ = fake.__head.p[0]; \
return p; \
}
#define kavl_free(__type, __head, __root, __free) do { \
__type *_p, *_q; \
for (_p = __root; _p; _p = _q) { \
if (_p->__head.p[0] == 0) { \
_q = _p->__head.p[1]; \
__free(_p); \
} else { \
_q = _p->__head.p[0]; \
_p->__head.p[0] = _q->__head.p[1]; \
_q->__head.p[1] = _p; \
} \
} \
} while (0)
#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 */ \
}; \
__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; \
cmp = __cmp(x, p); \
if (cmp < 0) *++itr->top = p, 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; \
} \
__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]) \
*++itr->top = p; \
if (itr->top < itr->stack) return 0; \
itr->right = (*itr->top)->__head.p[1]; \
return 1; \
} \
}
/**
* Insert a node to the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param proot pointer to the root of the tree (in/out: root may change)
* @param x node to insert (in)
* @param cnt number of nodes smaller than or equal to _x_; can be NULL (out)
*
* @return _x_ if not present in the tree, or the node equal to x.
*/
#define kavl_insert(suf, proot, x, cnt) kavl_insert_##suf(proot, x, cnt)
/**
* Find a node in the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param x node value to find (in)
* @param cnt number of nodes smaller than or equal to _x_; can be NULL (out)
*
* @return node equal to _x_ if present, or NULL if absent
*/
#define kavl_find(suf, root, x, cnt) kavl_find_##suf(root, x, cnt)
/**
* Delete a node from the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param proot pointer to the root of the tree (in/out: root may change)
* @param x node value to delete; if NULL, delete the first node (in)
*
* @return node removed from the tree if present, or NULL if absent
*/
#define kavl_erase(suf, proot, x, cnt) kavl_erase_##suf(proot, x, cnt)
#define kavl_erase_first(suf, proot) kavl_erase_##suf(proot, 0, 0)
#define kavl_itr_t(suf) struct kavl_itr_##suf
/**
* Place the iterator at the smallest object
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param itr iterator
*/
#define kavl_itr_first(suf, root, itr) kavl_itr_first_##suf(root, itr)
/**
* Place the iterator at the object equal to or greater than the query
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param x query (in)
* @param itr iterator (out)
*
* @return 1 if find; 0 otherwise. kavl_at(itr) is NULL if and only if query is
* larger than all objects in the tree
*/
#define kavl_itr_find(suf, root, x, itr) kavl_itr_find_##suf(root, x, itr)
/**
* Move to the next object in order
*
* @param itr iterator (modified)
*
* @return 1 if there is a next object; 0 otherwise
*/
#define kavl_itr_next(suf, itr) kavl_itr_next_##suf(itr)
/**
* Return the pointer at the iterator
*
* @param itr iterator
*
* @return pointer if present; NULL otherwise
*/
#define kavl_at(itr) ((itr)->top < (itr)->stack? 0 : *(itr)->top)
#define KAVL_INIT2(suf, __scope, __type, __head, __cmp) \
__KAVL_FIND(suf, __scope, __type, __head, __cmp) \
__KAVL_ROTATE(suf, __type, __head) \
__KAVL_INSERT(suf, __scope, __type, __head, __cmp) \
__KAVL_ERASE(suf, __scope, __type, __head, __cmp) \
__KAVL_ITR(suf, __scope, __type, __head, __cmp)
#define KAVL_INIT(suf, __type, __head, __cmp) \
KAVL_INIT2(suf,, __type, __head, __cmp)
#endif
+1270 -757
View File
File diff suppressed because it is too large Load Diff
+4
View File
@@ -2,6 +2,10 @@
#include <stdbool.h>
#ifdef __linux__
#define HAS_FILTER_SSID 1
#endif
#ifdef __CYGWIN__
extern bool bQuit;
#endif
+96 -16
View File
@@ -3,6 +3,9 @@
#include <stdarg.h>
#include <syslog.h>
#include <errno.h>
#ifdef __ANDROID__
#include <android/log.h>
#endif
#include "pools.h"
#include "desync.h"
@@ -17,6 +20,7 @@ const char *progname = "nfqws";
#error UNKNOWN_SYSTEM_TIME
#endif
const char * tld[6] = { "com","org","net","edu","gov","biz" };
int DLOG_FILE(FILE *F, const char *format, va_list args)
{
@@ -40,18 +44,47 @@ int DLOG_FILENAME(const char *filename, const char *format, va_list args)
return r;
}
static char syslog_buf[1024];
static size_t syslog_buf_sz=0;
static void syslog_buffered(int priority, const char *format, va_list args)
typedef void (*f_log_function)(int priority, const char *line);
static char log_buf[1024];
static size_t log_buf_sz=0;
static void syslog_log_function(int priority, const char *line)
{
if (vsnprintf(syslog_buf+syslog_buf_sz,sizeof(syslog_buf)-syslog_buf_sz,format,args)>0)
syslog(priority,"%s",line);
}
#ifdef __ANDROID__
static enum android_LogPriority syslog_priority_to_android(int priority)
{
enum android_LogPriority ap;
switch(priority)
{
syslog_buf_sz=strlen(syslog_buf);
case LOG_INFO:
case LOG_NOTICE: ap=ANDROID_LOG_INFO; break;
case LOG_ERR: ap=ANDROID_LOG_ERROR; break;
case LOG_WARNING: ap=ANDROID_LOG_WARN; break;
case LOG_EMERG:
case LOG_ALERT:
case LOG_CRIT: ap=ANDROID_LOG_FATAL; break;
case LOG_DEBUG: ap=ANDROID_LOG_DEBUG; break;
default: ap=ANDROID_LOG_UNKNOWN;
}
return ap;
}
static void android_log_function(int priority, const char *line)
{
__android_log_print(syslog_priority_to_android(priority), progname, "%s", line);
}
#endif
static void log_buffered(f_log_function log_function, int syslog_priority, const char *format, va_list args)
{
if (vsnprintf(log_buf+log_buf_sz,sizeof(log_buf)-log_buf_sz,format,args)>0)
{
log_buf_sz=strlen(log_buf);
// log when buffer is full or buffer ends with \n
if (syslog_buf_sz>=(sizeof(syslog_buf)-1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz-1]=='\n'))
if (log_buf_sz>=(sizeof(log_buf)-1) || (log_buf_sz && log_buf[log_buf_sz-1]=='\n'))
{
syslog(priority,"%s",syslog_buf);
syslog_buf_sz = 0;
log_function(syslog_priority,log_buf);
log_buf_sz = 0;
}
}
}
@@ -79,9 +112,16 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, va_list
break;
case LOG_TARGET_SYSLOG:
// skip newlines
syslog_buffered(syslog_priority,format,args);
log_buffered(syslog_log_function,syslog_priority,format,args);
r = 1;
break;
#ifdef __ANDROID__
case LOG_TARGET_ANDROID:
// skip newlines
log_buffered(android_log_function,syslog_priority,format,args);
r = 1;
break;
#endif
default:
break;
}
@@ -179,6 +219,9 @@ void dp_init(struct desync_profile *dp)
LIST_INIT(&dp->ips_collection_exclude);
LIST_INIT(&dp->pf_tcp);
LIST_INIT(&dp->pf_udp);
#ifdef HAS_FILTER_SSID
LIST_INIT(&dp->filter_ssid);
#endif
memcpy(dp->hostspell, "host", 4); // default hostspell
dp->desync_skip_nosni = true;
@@ -188,6 +231,7 @@ void dp_init(struct desync_profile *dp)
dp->fake_syndata_size = 16;
dp->wscale=-1; // default - dont change scale factor (client)
dp->desync_ttl6 = dp->dup_ttl6 = dp->orig_mod_ttl6 = 0xFF; // unused
dp->desync_ts_increment = dp->dup_ts_increment = TS_INCREMENT_DEFAULT;
dp->desync_badseq_increment = dp->dup_badseq_increment = BADSEQ_INCREMENT_DEFAULT;
dp->desync_badseq_ack_increment = dp->dup_badseq_ack_increment = BADSEQ_ACK_INCREMENT_DEFAULT;
dp->wssize_cutoff_mode = dp->desync_start_mode = dp->desync_cutoff_mode = dp->dup_start_mode = dp->dup_cutoff_mode = dp->orig_mod_start_mode = dp->orig_mod_cutoff_mode = 'n'; // packet number by default
@@ -196,16 +240,17 @@ void dp_init(struct desync_profile *dp)
dp->hostlist_auto_fail_time = HOSTLIST_AUTO_FAIL_TIME_DEFAULT;
dp->hostlist_auto_retrans_threshold = HOSTLIST_AUTO_RETRANS_THRESHOLD_DEFAULT;
dp->filter_ipv4 = dp->filter_ipv6 = true;
dp->dup_ip_id_mode = IPID_SAME;
}
bool dp_fake_defaults(struct desync_profile *dp)
{
struct blob_item *item;
if (blob_collection_empty(&dp->fake_http))
if (!blob_collection_add_blob(&dp->fake_http,fake_http_request_default,strlen(fake_http_request_default),0))
if (!blob_collection_add_blob(&dp->fake_http,fake_http_request_default,strlen(fake_http_request_default),0,0))
return false;
if (blob_collection_empty(&dp->fake_tls))
{
if (!(item=blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4+sizeof(((struct fake_tls_mod*)0)->sni))))
if (!(item=blob_collection_add_blob(&dp->fake_tls,fake_tls_clienthello_default,sizeof(fake_tls_clienthello_default),4+sizeof(((struct fake_tls_mod*)0)->sni),0)))
return false;
if (!(item->extra2 = malloc(sizeof(struct fake_tls_mod))))
return false;
@@ -213,13 +258,13 @@ bool dp_fake_defaults(struct desync_profile *dp)
}
if (blob_collection_empty(&dp->fake_unknown))
{
if (!(item=blob_collection_add_blob(&dp->fake_unknown,NULL,256,0)))
if (!(item=blob_collection_add_blob(&dp->fake_unknown,NULL,256,0,0)))
return false;
memset(item->data,0,item->size);
}
if (blob_collection_empty(&dp->fake_quic))
{
if (!(item=blob_collection_add_blob(&dp->fake_quic,NULL,620,0)))
if (!(item=blob_collection_add_blob(&dp->fake_quic,NULL,620,0,0)))
return false;
memset(item->data,0,item->size);
item->data[0] = 0x40;
@@ -229,7 +274,7 @@ bool dp_fake_defaults(struct desync_profile *dp)
{
if (blob_collection_empty(*fake))
{
if (!(item=blob_collection_add_blob(*fake,NULL,64,0)))
if (!(item=blob_collection_add_blob(*fake,NULL,64,0,0)))
return false;
memset(item->data,0,item->size);
}
@@ -244,25 +289,30 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
dp_init(&entry->dp);
// add to the tail
struct desync_profile_list *dpn,*dpl=LIST_FIRST(&params.desync_profiles);
struct desync_profile_list *dpn,*dpl=LIST_FIRST(head);
if (dpl)
{
while ((dpn=LIST_NEXT(dpl,next))) dpl = dpn;
LIST_INSERT_AFTER(dpl, entry, next);
}
else
LIST_INSERT_HEAD(&params.desync_profiles, entry, next);
LIST_INSERT_HEAD(head, entry, next);
return entry;
}
static void dp_clear_dynamic(struct desync_profile *dp)
{
free(dp->fsplit_pattern);
hostlist_collection_destroy(&dp->hl_collection);
hostlist_collection_destroy(&dp->hl_collection_exclude);
ipset_collection_destroy(&dp->ips_collection);
ipset_collection_destroy(&dp->ips_collection_exclude);
port_filters_destroy(&dp->pf_tcp);
port_filters_destroy(&dp->pf_udp);
#ifdef HAS_FILTER_SSID
strlist_destroy(&dp->filter_ssid);
#endif
HostFailPoolDestroy(&dp->hostlist_auto_fail_counters);
struct blob_collection_head **fake,*fakes[] = {&dp->fake_http, &dp->fake_tls, &dp->fake_unknown, &dp->fake_unknown_udp, &dp->fake_quic, &dp->fake_wg, &dp->fake_dht, &dp->fake_discord, &dp->fake_stun, NULL};
for(fake=fakes;*fake;fake++) blob_collection_destroy(*fake);
@@ -303,3 +353,33 @@ bool dp_list_need_all_out(struct desync_profile_list_head *head)
return true;
return false;
}
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
void cleanup_args(struct params_s *params)
{
wordfree(&params->wexp);
}
#endif
void cleanup_params(struct params_s *params)
{
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
cleanup_args(params);
#endif
ConntrackPoolDestroy(&params->conntrack);
dp_list_destroy(&params->desync_profiles);
hostlist_files_destroy(&params->hostlists);
ipset_files_destroy(&params->ipsets);
ipcacheDestroy(&params->ipcache);
#ifdef __CYGWIN__
strlist_destroy(&params->ssid_filter);
strlist_destroy(&params->nlm_filter);
strlist_destroy(&params->wf_raw_part);
#else
free(params->user); params->user=NULL;
#endif
}
+61 -10
View File
@@ -1,5 +1,6 @@
#pragma once
#include "nfqws.h"
#include "pools.h"
#include "conntrack.h"
#include "desync.h"
@@ -22,11 +23,14 @@
#define RAW_SNDBUF (64*1024) // in bytes
#define Q_MAXLEN 1024 // in packets
#define Q_MAXLEN 4986 // in packets
#define Q_RCVBUF (1024*1024) // in bytes
#define BADSEQ_INCREMENT_DEFAULT -10000
#define BADSEQ_ACK_INCREMENT_DEFAULT -66000
#define TS_INCREMENT_DEFAULT -600000
#define IPFRAG_UDP_DEFAULT 8
#define IPFRAG_TCP_DEFAULT 32
@@ -65,7 +69,9 @@
#define MAX_GIDS 64
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
extern const char * tld[6];
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG, LOG_TARGET_ANDROID };
struct fake_tls_mod_cache
{
@@ -73,11 +79,26 @@ struct fake_tls_mod_cache
};
struct fake_tls_mod
{
char sni[64];
char sni[128];
uint32_t mod;
};
struct hostfakesplit_mod
{
char host[128];
size_t host_size;
int ordering;
};
struct fakedsplit_mod
{
int ordering;
};
struct tcp_mod
{
bool seq;
};
typedef enum {SS_NONE=0,SS_SYN,SS_SYNACK,SS_ACKSYN} t_synack_split;
typedef enum {IPID_SEQ=0,IPID_SEQ_GROUP,IPID_RND,IPID_ZERO,IPID_SAME} t_ip_id_mode;
struct desync_profile
{
@@ -86,10 +107,13 @@ struct desync_profile
uint16_t wsize,wssize;
uint8_t wscale,wsscale;
char wssize_cutoff_mode; // n - packets, d - data packets, s - relative sequence
bool wssize_no_forced_cutoff;
unsigned int wssize_cutoff;
t_synack_split synack_split;
t_ip_id_mode ip_id_mode;
bool hostcase, hostnospace, domcase, methodeol;
char hostspell[4];
enum dpi_desync_mode desync_mode0,desync_mode,desync_mode2;
@@ -99,7 +123,7 @@ struct desync_profile
// multisplit
struct proto_pos splits[MAX_SPLITS];
int split_count;
struct proto_pos seqovl;
struct proto_pos seqovl,hostfakesplit_midhost;
char dup_start_mode, dup_cutoff_mode; // n - packets, d - data packets, s - relative sequence
bool dup_replace;
@@ -107,34 +131,50 @@ struct desync_profile
unsigned int dup_repeats;
uint8_t dup_ttl, dup_ttl6;
uint32_t dup_fooling_mode;
uint32_t dup_badseq_increment, dup_badseq_ack_increment;
uint32_t dup_ts_increment, dup_badseq_increment, dup_badseq_ack_increment;
autottl dup_autottl, dup_autottl6;
uint16_t dup_tcp_flags_set, dup_tcp_flags_unset;
t_ip_id_mode dup_ip_id_mode;
char orig_mod_start_mode, orig_mod_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int orig_mod_start, orig_mod_cutoff;
uint8_t orig_mod_ttl, orig_mod_ttl6;
autottl orig_autottl, orig_autottl6;
uint16_t orig_tcp_flags_set, orig_tcp_flags_unset;
char desync_start_mode, desync_cutoff_mode; // n - packets, d - data packets, s - relative sequence
unsigned int desync_start, desync_cutoff;
uint8_t desync_ttl, desync_ttl6;
autottl desync_autottl, desync_autottl6;
uint32_t desync_fooling_mode;
uint32_t desync_badseq_increment, desync_badseq_ack_increment;
uint32_t desync_ts_increment, desync_badseq_increment, desync_badseq_ack_increment;
uint16_t desync_tcp_flags_set, desync_tcp_flags_unset;
struct blob_collection_head fake_http,fake_tls,fake_unknown,fake_unknown_udp,fake_quic,fake_wg,fake_dht,fake_discord,fake_stun;
uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],fsplit_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP];
size_t fake_syndata_size;
uint8_t fake_syndata[FAKE_MAX_TCP],seqovl_pattern[FAKE_MAX_TCP],udplen_pattern[FAKE_MAX_UDP];
uint8_t *fsplit_pattern;
size_t fake_syndata_size, fsplit_pattern_size;
struct fake_tls_mod tls_mod_last;
struct blob_item *tls_fake_last;
struct hostfakesplit_mod hfs_mod;
struct fakedsplit_mod fs_mod;
struct tcp_mod tcp_mod;
int udplen_increment;
bool filter_ipv4,filter_ipv6;
struct port_filters_head pf_tcp,pf_udp;
uint32_t filter_l7; // L7_PROTO_* bits
#ifdef HAS_FILTER_SSID
// per profile ssid filter
// annot use global filter because it's not possible to bind multiple instances to a single queue
// it's possible to run multiple winws instances on the same windivert filter, but it's not the case for linux
struct str_list_head filter_ssid;
#endif
// list of pointers to ipsets
struct ipset_collection_head ips_collection, ips_collection_exclude;
@@ -150,7 +190,7 @@ struct desync_profile
#define PROFILE_IPSETS_ABSENT(dp) (!LIST_FIRST(&(dp)->ips_collection) && !LIST_FIRST(&(dp)->ips_collection_exclude))
#define PROFILE_IPSETS_EMPTY(dp) (ipset_collection_is_empty(&(dp)->ips_collection) && ipset_collection_is_empty(&(dp)->ips_collection_exclude))
#define PROFILE_HOSTLISTS_EMPTY(dp) (hostlist_collection_is_empty(&(dp)->hl_collection) && hostlist_collection_is_empty(&(dp)->hl_collection_exclude))
#define PROFILE_HAS_ORIG_MOD(dp) ((dp)->orig_mod_ttl || (dp)->orig_mod_ttl6)
#define PROFILE_HAS_ORIG_MOD(dp) ((dp)->orig_mod_ttl || (dp)->orig_mod_ttl6 || (dp)->orig_tcp_flags_set || (dp)->orig_tcp_flags_unset)
struct desync_profile_list {
struct desync_profile dp;
@@ -190,8 +230,10 @@ struct params_s
#ifdef __CYGWIN__
struct str_list_head ssid_filter,nlm_filter;
struct str_list_head wf_raw_part;
#else
bool droproot;
char *user;
uid_t uid;
gid_t gid[MAX_GIDS];
int gid_count;
@@ -209,13 +251,22 @@ struct params_s
t_conntrack conntrack;
bool ctrack_disable;
bool autottl_present,cache_hostname;
bool autottl_present;
#ifdef HAS_FILTER_SSID
bool filter_ssid_present;
#endif
bool cache_hostname;
unsigned int ipcache_lifetime;
ip_cache ipcache;
};
extern struct params_s params;
extern const char *progname;
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
void cleanup_args(struct params_s *params);
#endif
void cleanup_params(struct params_s *params);
int DLOG(const char *format, ...);
int DLOG_ERR(const char *format, ...);
+150 -109
View File
@@ -12,7 +12,7 @@
HASH_DEL(*ppool, elem); \
free(elem); \
}
#define ADD_STR_POOL(etype, ppool, keystr, keystr_len) \
etype *elem; \
if (!(elem = (etype*)malloc(sizeof(etype)))) \
@@ -25,7 +25,7 @@
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, keystr_len, elem); \
if (oom) \
{ \
free(elem->str); \
@@ -33,9 +33,12 @@
return false; \
}
#define ADD_HOSTLIST_POOL(etype, ppool, keystr, keystr_len, flg) \
ADD_STR_POOL(etype,ppool,keystr,keystr_len); \
elem->flags = flg;
etype *elem_find; \
HASH_FIND(hh, *ppool, keystr, keystr_len, elem_find); \
if (!elem_find) { \
ADD_STR_POOL(etype,ppool,keystr,keystr_len); \
elem->flags = flg; \
}
#undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
@@ -95,6 +98,7 @@ hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s)
}
void HostFailPoolDel(hostfail_pool **p, hostfail_pool *elem)
{
free(elem->str);
HASH_DEL(*p, elem);
free(elem);
}
@@ -105,11 +109,7 @@ void HostFailPoolPurge(hostfail_pool **pp)
HASH_ITER(hh, *pp, elem, tmp)
{
if (now >= elem->expire)
{
free(elem->str);
HASH_DEL(*pp, elem);
free(elem);
}
HostFailPoolDel(pp, elem);
}
}
static time_t host_fail_purge_prev=0;
@@ -159,6 +159,19 @@ void strlist_destroy(struct str_list_head *head)
strlist_entry_destroy(entry);
}
}
bool strlist_search(const struct str_list_head *head, const char *str)
{
struct str_list *entry;
if (str)
{
LIST_FOREACH(entry, head, next)
{
if (!strcmp(entry->str, str))
return true;
}
}
return false;
}
@@ -260,121 +273,146 @@ bool hostlist_collection_is_empty(const struct hostlist_collection_head *head)
}
void ipset4Destroy(ipset4 **ipset)
static int kavl_bit_cmp(const struct kavl_bit_elem *p, const struct kavl_bit_elem *q)
{
ipset4 *elem, *tmp;
HASH_ITER(hh, *ipset, elem, tmp)
unsigned int bitlen = q->bitlen < p->bitlen ? q->bitlen : p->bitlen;
unsigned int df = bitlen & 7, bytes = bitlen >> 3;
int cmp = memcmp(p->data, q->data, bytes);
if (cmp || !df) return cmp;
uint8_t c1 = p->data[bytes] >> (8 - df);
uint8_t c2 = q->data[bytes] >> (8 - df);
return c1<c2 ? -1 : c1==c2 ? 0 : 1;
}
KAVL_INIT(kavl_bit, struct kavl_bit_elem, head, kavl_bit_cmp)
static void kavl_bit_destroy_elem(struct kavl_bit_elem *e)
{
if (e)
{
HASH_DEL(*ipset, elem);
free(elem);
free(e->data);
free(e);
}
}
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen)
void kavl_bit_delete(struct kavl_bit_elem **hdr, const void *data, unsigned int bitlen)
{
uint32_t ip = ntohl(a->s_addr);
struct cidr4 cidr;
ipset4 *ips_found;
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
do
{
cidr.preflen--;
cidr.addr.s_addr = htonl(ip & mask_from_preflen(cidr.preflen));
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
if (ips_found) return true;
} while(cidr.preflen);
return false;
struct kavl_bit_elem temp = {
.bitlen = bitlen, .data = (uint8_t*)data
};
kavl_bit_destroy_elem(kavl_erase(kavl_bit, hdr, &temp, 0));
}
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen)
void kavl_bit_destroy(struct kavl_bit_elem **hdr)
{
while (*hdr)
{
struct kavl_bit_elem *e = kavl_erase_first(kavl_bit, hdr);
if (!e) break;
kavl_bit_destroy_elem(e);
}
free(*hdr);
}
struct kavl_bit_elem *kavl_bit_add(struct kavl_bit_elem **hdr, void *data, unsigned int bitlen, size_t struct_size)
{
if (!struct_size) struct_size=sizeof(struct kavl_bit_elem);
struct kavl_bit_elem *v, *e = calloc(1, struct_size);
if (!e) return 0;
e->bitlen = bitlen;
e->data = data;
v = kavl_insert(kavl_bit, hdr, e, 0);
while (e != v && e->bitlen < v->bitlen)
{
kavl_bit_delete(hdr, v->data, v->bitlen);
v = kavl_insert(kavl_bit, hdr, e, 0);
}
if (e != v) kavl_bit_destroy_elem(e);
return v;
}
struct kavl_bit_elem *kavl_bit_get(const struct kavl_bit_elem *hdr, const void *data, unsigned int bitlen)
{
struct kavl_bit_elem temp = {
.bitlen = bitlen, .data = (uint8_t*)data
};
return kavl_find(kavl_bit, hdr, &temp, 0);
}
static bool ipset_kavl_add(struct kavl_bit_elem **ipset, const void *a, uint8_t preflen)
{
uint8_t bytelen = (preflen+7)>>3;
uint8_t *abuf = malloc(bytelen);
if (!abuf) return false;
memcpy(abuf,a,bytelen);
if (!kavl_bit_add(ipset,abuf,preflen,0))
{
free(abuf);
return false;
}
return true;
}
bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen)
{
return !!kavl_bit_get(ipset,a,preflen);
}
bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen)
{
if (preflen>32) return false;
// avoid dups
if (ipset4Check(*ipset, a, preflen)) return true; // already included
struct ipset4 *entry = calloc(1,sizeof(ipset4));
if (!entry) return false;
entry->cidr.addr.s_addr = htonl(ntohl(a->s_addr) & mask_from_preflen(preflen));
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
return ipset_kavl_add(ipset,a,preflen);
}
void ipset4Print(ipset4 *ipset)
void ipset4Print(struct kavl_bit_elem *ipset)
{
ipset4 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr4(&ips->cidr);
printf("\n");
}
}
if (!ipset) return;
void ipset6Destroy(ipset6 **ipset)
{
ipset6 *elem, *tmp;
HASH_ITER(hh, *ipset, elem, tmp)
{
HASH_DEL(*ipset, elem);
free(elem);
}
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen)
{
struct cidr6 cidr;
ipset6 *ips_found;
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
struct cidr4 c;
const struct kavl_bit_elem *elem;
kavl_itr_t(kavl_bit) itr;
kavl_itr_first(kavl_bit, ipset, &itr);
do
{
cidr.preflen--;
ip6_and(a, mask_from_preflen6(cidr.preflen), &cidr.addr);
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
if (ips_found) return true;
} while(cidr.preflen);
return false;
}
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen)
{
if (preflen>128) return false;
// avoid dups
if (ipset6Check(*ipset, a, preflen)) return true; // already included
struct ipset6 *entry = calloc(1,sizeof(ipset6));
if (!entry) return false;
ip6_and(a, mask_from_preflen6(preflen), &entry->cidr.addr);
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
}
void ipset6Print(ipset6 *ipset)
{
ipset6 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr6(&ips->cidr);
elem = kavl_at(&itr);
c.preflen = elem->bitlen;
expand_bits(&c.addr, elem->data, elem->bitlen, sizeof(c.addr));
print_cidr4(&c);
printf("\n");
}
while (kavl_itr_next(kavl_bit, &itr));
}
bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen)
{
return !!kavl_bit_get(ipset,a,preflen);
}
bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen)
{
if (preflen>128) return false;
return ipset_kavl_add(ipset,a,preflen);
}
void ipset6Print(struct kavl_bit_elem *ipset)
{
if (!ipset) return;
struct cidr6 c;
const struct kavl_bit_elem *elem;
kavl_itr_t(kavl_bit) itr;
kavl_itr_first(kavl_bit, ipset, &itr);
do
{
elem = kavl_at(&itr);
c.preflen = elem->bitlen;
expand_bits(&c.addr, elem->data, elem->bitlen, sizeof(c.addr));
print_cidr6(&c);
printf("\n");
}
while (kavl_itr_next(kavl_bit, &itr));
}
void ipsetDestroy(ipset *ipset)
{
ipset4Destroy(&ipset->ips4);
ipset6Destroy(&ipset->ips6);
kavl_bit_destroy(&ipset->ips4);
kavl_bit_destroy(&ipset->ips6);
}
void ipsetPrint(ipset *ipset)
{
@@ -538,8 +576,9 @@ struct blob_item *blob_collection_add(struct blob_collection_head *head)
}
return entry;
}
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve)
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve, size_t offset)
{
if (offset>=size) return NULL;
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
if (!entry) return NULL;
if (!(entry->data = malloc(size+size_reserve)))
@@ -550,6 +589,7 @@ struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, co
if (data) memcpy(entry->data,data,size);
entry->size = size;
entry->size_buf = size+size_reserve;
entry->offset = offset;
// insert to the end
struct blob_item *itemc,*iteml=LIST_FIRST(head);
@@ -591,6 +631,7 @@ static void ipcache_item_init(ip_cache_item *item)
{
ipcache_item_touch(item);
item->hostname = NULL;
item->hostname_is_ip = false;
item->hops = 0;
}
static void ipcache_item_destroy(ip_cache_item *item)
@@ -652,7 +693,7 @@ static void ipcache4Print(ip_cache4 *ipcache)
{
*s_ip=0;
inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip));
printf("%s iface=%s : hops %u hostname=%s now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last));
printf("%s iface=%s : hops %u hostname=%s hostname_is_ip=%u now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, ipc->data.hostname ? ipc->data.hostname : "", ipc->data.hostname_is_ip, (unsigned long long)(now-ipc->data.last));
}
}
@@ -710,7 +751,7 @@ static void ipcache6Print(ip_cache6 *ipcache)
{
*s_ip=0;
inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip));
printf("%s iface=%s : hops %u hostname=%s now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last));
printf("%s iface=%s : hops %u hostname=%s hostname_is_ip=%u now=last+%llu\n", s_ip, ipc->key.iface, ipc->data.hops, ipc->data.hostname ? ipc->data.hostname : "", ipc->data.hostname_is_ip, (unsigned long long)(now-ipc->data.last));
}
}
+31 -25
View File
@@ -13,6 +13,8 @@
#define HASH_FUNCTION HASH_BER
#include "uthash.h"
#include "kavl.h"
#define HOSTLIST_POOL_FLAG_STRICT_MATCH 1
typedef struct hostlist_pool {
@@ -32,6 +34,11 @@ struct str_list {
};
LIST_HEAD(str_list_head, str_list);
bool strlist_add(struct str_list_head *head, const char *filename);
void strlist_destroy(struct str_list_head *head);
bool strlist_search(const struct str_list_head *head, const char *str);
typedef struct hostfail_pool {
char *str; /* key */
int counter; /* value */
@@ -47,10 +54,6 @@ void HostFailPoolPurge(hostfail_pool **pp);
void HostFailPoolPurgeRateLimited(hostfail_pool **pp);
void HostFailPoolDump(hostfail_pool *p);
bool strlist_add(struct str_list_head *head, const char *filename);
void strlist_destroy(struct str_list_head *head);
struct hostlist_file {
char *filename;
@@ -76,39 +79,40 @@ struct hostlist_item *hostlist_collection_search(struct hostlist_collection_head
bool hostlist_collection_is_empty(const struct hostlist_collection_head *head);
typedef struct ipset4 {
struct cidr4 cidr; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} ipset4;
typedef struct ipset6 {
struct cidr6 cidr; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} ipset6;
struct kavl_bit_elem
{
unsigned int bitlen;
uint8_t *data;
KAVL_HEAD(struct kavl_bit_elem) head;
};
struct kavl_bit_elem *kavl_bit_get(const struct kavl_bit_elem *hdr, const void *data, unsigned int bitlen);
struct kavl_bit_elem *kavl_bit_add(struct kavl_bit_elem **hdr, void *data, unsigned int bitlen, size_t struct_size);
void kavl_bit_delete(struct kavl_bit_elem **hdr, const void *data, unsigned int bitlen);
void kavl_bit_destroy(struct kavl_bit_elem **hdr);
// combined ipset ipv4 and ipv6
typedef struct ipset {
ipset4 *ips4;
ipset6 *ips6;
struct kavl_bit_elem *ips4,*ips6;
} ipset;
#define IPSET_EMPTY(ips) (!(ips)->ips4 && !(ips)->ips6)
void ipset4Destroy(ipset4 **ipset);
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen);
static inline bool ipset4AddCidr(ipset4 **ipset, const struct cidr4 *cidr)
bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen);
static inline bool ipset4AddCidr(struct kavl_bit_elem **ipset, const struct cidr4 *cidr)
{
return ipset4Add(ipset,&cidr->addr,cidr->preflen);
}
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen);
void ipset4Print(ipset4 *ipset);
bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen);
void ipset4Print(struct kavl_bit_elem *ipset);
void ipset6Destroy(ipset6 **ipset);
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen);
static inline bool ipset6AddCidr(ipset6 **ipset, const struct cidr6 *cidr)
bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen);
static inline bool ipset6AddCidr(struct kavl_bit_elem **ipset, const struct cidr6 *cidr)
{
return ipset6Add(ipset,&cidr->addr,cidr->preflen);
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen);
void ipset6Print(ipset6 *ipset);
bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen);
void ipset6Print(struct kavl_bit_elem *ipset);
void ipsetDestroy(ipset *ipset);
void ipsetPrint(ipset *ipset);
@@ -153,13 +157,14 @@ struct blob_item {
uint8_t *data; // main data blob
size_t size; // main data blob size
size_t size_buf;// main data blob allocated size
size_t offset; // optional offset to useful data
void *extra; // any data without size
void *extra2; // any data without size
LIST_ENTRY(blob_item) next;
};
LIST_HEAD(blob_collection_head, blob_item);
struct blob_item *blob_collection_add(struct blob_collection_head *head);
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve);
struct blob_item *blob_collection_add_blob(struct blob_collection_head *head, const void *data, size_t size, size_t size_reserve, size_t offset);
void blob_collection_destroy(struct blob_collection_head *head);
bool blob_collection_empty(const struct blob_collection_head *head);
@@ -178,6 +183,7 @@ typedef struct ip_cache_item
{
time_t last;
char *hostname;
bool hostname_is_ip;
uint8_t hops;
} ip_cache_item;
typedef struct ip_cache4
+72 -72
View File
@@ -52,14 +52,6 @@ bool l7_proto_match(t_l7proto l7proto, uint32_t filter_l7)
(l7proto==STUN && (filter_l7 & L7_PROTO_STUN));
}
#define PM_ABS 0
#define PM_HOST 1
#define PM_HOST_END 2
#define PM_HOST_SLD 3
#define PM_HOST_MIDSLD 4
#define PM_HOST_ENDSLD 5
#define PM_HTTP_METHOD 6
#define PM_SNI_EXT 7
bool IsHostMarker(uint8_t posmarker)
{
switch(posmarker)
@@ -318,7 +310,7 @@ size_t HttpPos(uint8_t posmarker, int16_t pos, const uint8_t *data, size_t sz)
if (sz<10) break;
if (*method=='\n' || *method=='\r') method++;
if (*method=='\n' || *method=='\r') method++;
for (p=method,i=0;i<7;i++) if (*p>='A' && *p<='Z') p++;
for (p=method,i=0; i<9 && *p>='A' && *p<='Z'; i++,p++);
if (i<3 || *p!=' ') break;
return CheckPos(sz,method-data+pos);
case PM_HOST:
@@ -595,7 +587,7 @@ static uint8_t tvb_get_varint(const uint8_t *tvb, uint64_t *value)
return 8;
}
// impossible case
if (*value) *value = 0;
if (value) *value = 0;
return 0;
}
static uint8_t tvb_get_size(uint8_t tvb)
@@ -623,24 +615,18 @@ bool IsQUICCryptoHello(const uint8_t *data, size_t len, size_t *hello_offset, si
uint8_t QUICDraftVersion(uint32_t version)
{
/* IETF Draft versions */
if ((version >> 8) == 0xff0000) {
if ((version >> 8) == 0xff0000)
return (uint8_t)version;
}
/* Facebook mvfst, based on draft -22. */
if (version == 0xfaceb001) {
if (version == 0xfaceb001)
return 22;
}
/* Facebook mvfst, based on draft -27. */
if (version == 0xfaceb002 || version == 0xfaceb00e) {
if (version == 0xfaceb002 || version == 0xfaceb00e)
return 27;
}
/* GQUIC Q050, T050 and T051: they are not really based on any drafts,
* but we must return a sensible value */
if (version == 0x51303530 ||
version == 0x54303530 ||
version == 0x54303531) {
if (version == 0x51303530 || version == 0x54303530 || version == 0x54303531)
return 27;
}
/* https://tools.ietf.org/html/draft-ietf-quic-transport-32#section-15
"Versions that follow the pattern 0x?a?a?a?a are reserved for use in
forcing version negotiation to be exercised"
@@ -648,19 +634,17 @@ uint8_t QUICDraftVersion(uint32_t version)
used to select a proper salt (which depends on the version itself), but
we don't have a real version here! Let's hope that we need to handle
only latest drafts... */
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a) {
if ((version & 0x0F0F0F0F) == 0x0a0a0a0a)
return 29;
}
/* QUIC (final?) constants for v1 are defined in draft-33, but draft-34 is the
final draft version */
if (version == 0x00000001) {
if (version == 0x00000001)
return 34;
}
/* QUIC Version 2 */
/* TODO: for the time being use 100 as a number for V2 and let see how v2 drafts evolve */
if (version == 0x709A50C4) {
if ((version == 0x709A50C4) || (version == 0x6b3343cf))
return 100;
}
return 0;
}
@@ -670,7 +654,7 @@ static bool is_quic_draft_max(uint32_t draft_version, uint8_t max_version)
}
static bool is_quic_v2(uint32_t version)
{
return version == 0x6b3343cf;
return (version == 0x709A50C4) || (version == 0x6b3343cf);
}
static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, const char *label, uint8_t *out, size_t out_len)
@@ -811,20 +795,19 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
return false;
}
uint64_t payload_len,token_len;
size_t pn_offset;
uint64_t payload_len,token_len,pn_offset;
pn_offset = 1 + 4 + 1 + data[5];
if (pn_offset >= data_len) return false;
// SCID length
pn_offset += 1 + data[pn_offset];
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
if (pn_offset >= data_len || (pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
// token length
pn_offset += tvb_get_varint(data + pn_offset, &token_len);
pn_offset += token_len;
if ((pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
if (pn_offset >= data_len || (pn_offset + tvb_get_size(data[pn_offset])) >= data_len) return false;
pn_offset += tvb_get_varint(data + pn_offset, &payload_len);
if (payload_len<20 || (pn_offset + payload_len)>data_len) return false;
aes_init_keygen_tables();
uint8_t sample_enc[16];
aes_context ctx;
if (aes_setkey(&ctx, 1, aeshp, sizeof(aeshp)) || aes_cipher(&ctx, data + pn_offset + 4, sample_enc)) return false;
@@ -842,13 +825,13 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
phton64(aesiv + sizeof(aesiv) - 8, pntoh64(aesiv + sizeof(aesiv) - 8) ^ pkn);
size_t cryptlen = payload_len - pkn_len - 16;
uint64_t cryptlen = payload_len - pkn_len - 16;
if (cryptlen > *clean_len) return false;
*clean_len = cryptlen;
*clean_len = (size_t)cryptlen;
const uint8_t *decrypt_begin = data + pn_offset + pkn_len;
uint8_t atag[16],header[256];
size_t header_len = pn_offset + pkn_len;
uint8_t atag[16],header[2048];
uint64_t header_len = pn_offset + pkn_len;
if (header_len > sizeof(header)) return false; // not likely header will be so large
memcpy(header, data, header_len);
header[0] = packet0;
@@ -883,7 +866,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
uint64_t offset,sz,szmax=0,zeropos=0,pos=0;
bool found=false;
struct range64 ranges[MAX_DEFRAG_PIECES];
int i,range=0;
int i,j,range=0;
while(pos<clean_len)
{
@@ -905,24 +888,54 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
if ((pos+sz)>clean_len) return false;
if ((offset+sz)>defrag_data_len) return false; // defrag buf overflow
// remove exact duplicates early to save cpu
for(i=0;i<range;i++)
if (ranges[i].offset==offset && ranges[i].len==sz)
goto skip_range;
if (zeropos < offset)
// make sure no uninitialized gaps exist in case of not full fragment coverage
memset(defrag_data+zeropos,0,offset-zeropos);
if ((offset+sz) > zeropos)
zeropos=offset+sz;
memcpy(defrag_data+offset,clean+pos,sz);
if ((offset+sz) > szmax) szmax = offset+sz;
found=true;
pos+=sz;
if ((offset+sz) > szmax) szmax = offset+sz;
memcpy(defrag_data+offset,clean+pos,sz);
ranges[range].offset = offset;
ranges[range].len = sz;
range++;
skip_range:
pos+=sz;
}
}
if (found)
{
qsort(ranges, range, sizeof(*ranges), cmp_range64);
// for(i=0 ; i<range ; i++)
// printf("range1 %llu-%llu\n",ranges[i].offset,ranges[i].offset+ranges[i].len);
if (range>0)
{
for (j=0,i=1; i < range; i++)
{
uint64_t current_end = ranges[j].offset + ranges[j].len;
uint64_t next_start = ranges[i].offset;
uint64_t next_end = ranges[i].offset + ranges[i].len;
if (next_start <= current_end)
ranges[j].len = MAX(next_end,current_end) - ranges[j].offset;
else
ranges[++j] = ranges[i];
}
range = j+1;
}
// for(i=0 ; i<range ; i++)
// printf("range2 %llu-%llu\n",ranges[i].offset,ranges[i].offset+ranges[i].len);
defrag[0] = 6;
defrag[1] = 0; // offset
// 2..9 - length 64 bit
@@ -931,21 +944,7 @@ bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,siz
defrag[2] |= 0xC0; // 64 bit value
*defrag_len = (size_t)(szmax+10);
qsort(ranges, range, sizeof(*ranges), cmp_range64);
//for(i=0 ; i<range ; i++)
// printf("RANGE %zu len %zu\n",ranges[i].offset,ranges[i].len);
for(i=0,offset=0,*bFull=true ; i<range ; i++)
{
if (ranges[i].offset!=offset)
{
*bFull = false;
break;
}
offset += ranges[i].len;
}
*bFull = range==1 && !ranges[0].offset;
//printf("bFull=%u\n",*bFull);
}
return found;
@@ -977,40 +976,41 @@ bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host
bool IsQUICInitial(const uint8_t *data, size_t len)
{
// too small packets are not likely to be initials with client hello
// too small packets are not likely to be initials
// long header, fixed bit
if (len < 256 || (data[0] & 0xC0)!=0xC0) return false;
if (len < 128) return false;
uint32_t ver = QUICExtractVersion(data,len);
if (QUICDraftVersion(ver) < 11) return false;
// quic v1 : initial packets are 00b
// quic v2 : initial packets are 01b
if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00)) return false;
if ((data[0] & 0xF0) != (is_quic_v2(ver) ? 0xD0 : 0xC0)) return false;
uint64_t offset=5, sz;
uint64_t offset=5, sz, sz2;
// DCID. must be present
if (!data[offset] || data[offset] > QUIC_MAX_CID_LENGTH) return false;
// DCID
if (data[offset] > QUIC_MAX_CID_LENGTH) return false;
offset += 1 + data[offset];
if (offset>=len) return false;
// SCID
if (data[offset] > QUIC_MAX_CID_LENGTH) return false;
offset += 1 + data[offset];
// token length
if (offset>=len || (offset + tvb_get_size(data[offset])) > len) return false;
offset += tvb_get_varint(data + offset, &sz);
offset += sz;
if (offset >= len) return false;
// payload length
if ((offset + tvb_get_size(data[offset])) > len) return false;
sz2 = tvb_get_size(data[offset]);
if ((offset + sz2) > len) return false;
tvb_get_varint(data + offset, &sz);
offset += sz;
offset += sz2 + sz;
if (offset > len) return false;
// client hello cannot be too small. likely ACK
return sz>=96;
return true;
}
@@ -1035,7 +1035,7 @@ bool IsStunMessage(const uint8_t *data, size_t len)
{
return len>=20 && // header size
(data[0]&0xC0)==0 && // 2 most significant bits must be zeroes
(data[3]&0b11)==0 && // length must be a multiple of 4
ntohl(*(uint32_t*)(&data[4]))==0x2112A442 && // magic cookie
ntohs(*(uint16_t*)(&data[2]))==len-20;
(data[3]&3)==0 && // length must be a multiple of 4
pntoh32(data+4)==0x2112A442 && // magic cookie
pntoh16(data+2)<=(len-20);
}
+17 -5
View File
@@ -295,7 +295,7 @@ bool can_drop_root(void)
#endif
}
bool droproot(uid_t uid, gid_t *gid, int gid_count)
bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count)
{
if (gid_count<1)
{
@@ -309,11 +309,23 @@ bool droproot(uid_t uid, gid_t *gid, int gid_count)
return false;
}
#endif
// drop all SGIDs
if (setgroups(gid_count,gid))
if (user)
{
DLOG_PERROR("setgroups");
return false;
// macos has strange supp gid handling. they cache only 16 groups and fail setgroups if more than 16 gids specified.
// better to leave it to the os
if (initgroups(user,gid[0]))
{
DLOG_PERROR("initgroups");
return false;
}
}
else
{
if (setgroups(gid_count,gid))
{
DLOG_PERROR("setgroups");
return false;
}
}
if (setgid(gid[0]))
{
+28 -1
View File
@@ -18,6 +18,25 @@ bool dropcaps(void);
#define arch_nr (offsetof(struct seccomp_data, arch))
#define syscall_arg(x) (offsetof(struct seccomp_data, args[x]))
#ifndef __AUDIT_ARCH_64BIT
#define __AUDIT_ARCH_64BIT 0x80000000
#endif
#ifndef __AUDIT_ARCH_LE
#define __AUDIT_ARCH_LE 0x40000000
#endif
#ifndef EM_RISCV
#define EM_RISCV 243
#endif
#ifndef AUDIT_ARCH_RISCV64
#define AUDIT_ARCH_RISCV64 (EM_RISCV | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE)
#endif
#ifndef EM_LOONGARCH
#define EM_LOONGARCH 258
#endif
#ifndef AUDIT_ARCH_LOONGARCH64
#define AUDIT_ARCH_LOONGARCH64 (EM_LOONGARCH | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE)
#endif
#if defined(__aarch64__)
# define ARCH_NR AUDIT_ARCH_AARCH64
@@ -72,6 +91,14 @@ bool dropcaps(void);
# define ARCH_NR AUDIT_ARCH_RISCV64
#elif defined(__loongarch__) && __loongarch_grlen == 64
# define ARCH_NR AUDIT_ARCH_LOONGARCH64
#elif defined(__e2k__)
# define ARCH_NR AUDIT_ARCH_E2K
#else
# error "Platform does not support seccomp filter yet"
@@ -84,7 +111,7 @@ bool dropcaps(void);
#ifndef __CYGWIN__
bool sec_harden(void);
bool can_drop_root(void);
bool droproot(uid_t uid, gid_t *gid, int gid_count);
bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count);
void print_id(void);
#endif
+1 -1
View File
@@ -4,7 +4,7 @@
#include <stdbool.h>
bool service_run();
bool service_run(int argc, char *argv[]);
#endif
+2 -1
View File
@@ -1,5 +1,6 @@
CC ?= cc
CFLAGS += -std=gnu99 -s -Os -flto=auto
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 -s $(OPTIMIZE) -flto=auto
LIBS = -lz -lpthread
SRC_FILES = *.c
+14 -8
View File
@@ -1,7 +1,13 @@
CC ?= gcc
CFLAGS += -std=gnu99 -Os -flto=auto
CC ?= cc
OPTIMIZE ?= -Os
CFLAGS += -std=gnu99 $(OPTIMIZE) -flto=auto -ffunction-sections -fdata-sections
CFLAGS_SYSTEMD = -DUSE_SYSTEMD
CFLAGS_BSD = -Wno-address-of-packed-member
LDFLAGS += -flto=auto
LDFLAGS_ANDROID = -Wl,--gc-sections -llog
LDFLAGS_BSD = -Wl,--gc-sections
LDFLAGS_LINUX = -Wl,--gc-sections
LDFLAGS_MAC = -Wl,-dead_strip
LIBS = -lz -lpthread
LIBS_SYSTEMD = -lsystemd
LIBS_ANDROID = -lz
@@ -11,20 +17,20 @@ SRC_FILES_ANDROID = $(SRC_FILES) andr/*.c
all: tpws
tpws: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES) $(LIBS) $(LDFLAGS)
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES) $(LIBS) $(LDFLAGS) $(LDFLAGS_LINUX)
systemd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o tpws $(SRC_FILES) $(LIBS) $(LIBS_SYSTEMD) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_SYSTEMD) -o tpws $(SRC_FILES) $(LIBS) $(LIBS_SYSTEMD) $(LDFLAGS) $(LDFLAGS_LINUX)
android: $(SRC_FILES)
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES_ANDROID) $(LIBS_ANDROID) $(LDFLAGS)
$(CC) -s $(CFLAGS) -o tpws $(SRC_FILES_ANDROID) $(LIBS_ANDROID) $(LDFLAGS) $(LDFLAGS_ANDROID)
bsd: $(SRC_FILES)
$(CC) -s $(CFLAGS) $(CFLAGS_BSD) -Iepoll-shim/include -o tpws $(SRC_FILES) epoll-shim/src/*.c $(LIBS) $(LDFLAGS)
$(CC) -s $(CFLAGS) $(CFLAGS_BSD) -Iepoll-shim/include -o tpws $(SRC_FILES) epoll-shim/src/*.c $(LIBS) $(LDFLAGS) $(LDFLAGS_BSD)
mac: $(SRC_FILES)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -Iepoll-shim/include -Imacos -o tpwsa -target arm64-apple-macos10.8 $(SRC_FILES) epoll-shim/src/*.c $(LIBS) $(LDFLAGS)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -Iepoll-shim/include -Imacos -o tpwsx -target x86_64-apple-macos10.8 $(SRC_FILES) epoll-shim/src/*.c $(LIBS) $(LDFLAGS)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -Iepoll-shim/include -Imacos -o tpwsa -target arm64-apple-macos10.8 $(SRC_FILES) epoll-shim/src/*.c $(LIBS) $(LDFLAGS) $(LDFLAGS_MAC)
$(CC) $(CFLAGS) $(CFLAGS_BSD) -Iepoll-shim/include -Imacos -o tpwsx -target x86_64-apple-macos10.8 $(SRC_FILES) epoll-shim/src/*.c $(LIBS) $(LDFLAGS) $(LDFLAGS_MAC)
strip tpwsa tpwsx
lipo -create -output tpws tpwsx tpwsa
rm -f tpwsx tpwsa
+67 -29
View File
@@ -27,7 +27,7 @@
int unique_size_t(size_t *pu, int ct)
{
int i, j, u;
size_t i, j, u;
for (i = j = 0; j < ct; i++)
{
u = pu[j++];
@@ -112,6 +112,72 @@ bool append_to_list_file(const char *filename, const char *s)
return bOK;
}
void expand_bits(void *target, const void *source, unsigned int source_bitlen, unsigned int target_bytelen)
{
unsigned int target_bitlen = target_bytelen<<3;
unsigned int bitlen = target_bitlen<source_bitlen ? target_bitlen : source_bitlen;
unsigned int bytelen = bitlen>>3;
if ((target_bytelen-bytelen)>=1) memset(target+bytelen,0,target_bytelen-bytelen);
memcpy(target,source,bytelen);
if ((bitlen &= 7)) ((uint8_t*)target)[bytelen] = ((uint8_t*)source)[bytelen] & (~((1 << (8-bitlen)) - 1));
}
// " [fd00::1]" => "fd00::1"
// "[fd00::1]:8000" => "fd00::1"
// "127.0.0.1" => "127.0.0.1"
// " 127.0.0.1:8000" => "127.0.0.1"
// " vk.com:8000" => "vk.com"
// return value: true - host is ip addr
bool strip_host_to_ip(char *host)
{
size_t l;
char *h,*p;
uint8_t addr[16];
for (h = host ; *h==' ' || *h=='\t' ; h++);
l = strlen(h);
if (l>=2)
{
if (*h=='[')
{
// ipv6 ?
for (p=++h ; *p && *p!=']' ; p++);
if (*p==']')
{
l = p-h;
memmove(host,h,l);
host[l]=0;
return inet_pton(AF_INET6, host, addr)>0;
}
}
else
{
if (inet_pton(AF_INET6, h, addr)>0)
{
// ipv6 ?
if (host!=h)
{
l = strlen(h);
memmove(host,h,l);
host[l]=0;
}
return true;
}
else
{
// ipv4 ?
for (p=h ; *p && *p!=':' ; p++);
l = p-h;
if (host!=h) memmove(host,h,l);
host[l]=0;
return inet_pton(AF_INET, host, addr)>0;
}
}
}
return false;
}
void ntop46(const struct sockaddr *sa, char *str, size_t len)
{
if (!len) return;
@@ -410,34 +476,6 @@ bool set_env_exedir(const char *argv0)
}
static void mask_from_preflen6_make(uint8_t plen, struct in6_addr *a)
{
if (plen >= 128)
memset(a->s6_addr, 0xFF, 16);
else
{
uint8_t n = plen >> 3;
memset(a->s6_addr, 0xFF, n);
memset(a->s6_addr + n, 0x00, 16 - n);
a->s6_addr[n] = (uint8_t)(0xFF00 >> (plen & 7));
}
}
struct in6_addr ip6_mask[129];
void mask_from_preflen6_prepare(void)
{
for (int plen = 0; plen <= 128; plen++) mask_from_preflen6_make(plen, ip6_mask + plen);
}
#if defined(__GNUC__) && !defined(__llvm__)
__attribute__((optimize("no-strict-aliasing")))
#endif
void ip6_and(const struct in6_addr * restrict a, const struct in6_addr * restrict b, struct in6_addr * restrict result)
{
// int 128 can cause alignment segfaults because sin6_addr in struct sockaddr_in6 is 8-byte aligned, not 16-byte
((uint64_t*)result->s6_addr)[0] = ((uint64_t*)a->s6_addr)[0] & ((uint64_t*)b->s6_addr)[0];
((uint64_t*)result->s6_addr)[1] = ((uint64_t*)a->s6_addr)[1] & ((uint64_t*)b->s6_addr)[1];
}
void str_cidr4(char *s, size_t s_len, const struct cidr4 *cidr)
{
char s_ip[16];
+4 -12
View File
@@ -29,6 +29,10 @@ bool str_ends_with(const char *s, const char *suffix);
bool load_file(const char *filename,void *buffer,size_t *buffer_size);
bool append_to_list_file(const char *filename, const char *s);
void expand_bits(void *target, const void *source, unsigned int source_bitlen, unsigned int target_bytelen);
bool strip_host_to_ip(char *host);
void ntop46(const struct sockaddr *sa, char *str, size_t len);
void ntop46_port(const struct sockaddr *sa, char *str, size_t len);
void print_sockaddr(const struct sockaddr *sa);
@@ -120,18 +124,6 @@ void print_cidr6(const struct cidr6 *cidr);
bool parse_cidr4(char *s, struct cidr4 *cidr);
bool parse_cidr6(char *s, struct cidr6 *cidr);
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;
}
void msleep(unsigned int ms);
#ifdef __linux__
bool socket_supports_notsent();
+7 -6
View File
@@ -170,7 +170,7 @@ bool LoadAllHostLists()
static bool SearchHostList(hostlist_pool *hostlist, const char *host)
static bool SearchHostList(hostlist_pool *hostlist, const char *host, bool no_match_subdomains)
{
if (hostlist)
{
@@ -195,6 +195,7 @@ static bool SearchHostList(hostlist_pool *hostlist, const char *host)
}
else
VPRINT("negative\n");
if (no_match_subdomains) break;
p = strchr(p, '.');
if (p) p++;
bHostFull = false;
@@ -220,7 +221,7 @@ bool HostlistsReloadCheckForProfile(const struct desync_profile *dp)
return HostlistsReloadCheck(&dp->hl_collection) && HostlistsReloadCheck(&dp->hl_collection_exclude);
}
// return : true = apply fooling, false = do not apply
static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, const struct hostlist_collection_head *hostlists_exclude, const char *host, bool *excluded, bool bSkipReloadCheck)
static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, const struct hostlist_collection_head *hostlists_exclude, const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck)
{
struct hostlist_item *item;
@@ -233,7 +234,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
LIST_FOREACH(item, hostlists_exclude, next)
{
VPRINT("[%s] exclude ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host))
if (SearchHostList(item->hfile->hostlist, host, no_match_subdomains))
{
if (excluded) *excluded = true;
return false;
@@ -245,7 +246,7 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
LIST_FOREACH(item, hostlists, next)
{
VPRINT("[%s] include ", item->hfile->filename ? item->hfile->filename : "fixed");
if (SearchHostList(item->hfile->hostlist, host))
if (SearchHostList(item->hfile->hostlist, host, no_match_subdomains))
return true;
}
return false;
@@ -255,10 +256,10 @@ static bool HostlistCheck_(const struct hostlist_collection_head *hostlists, con
// return : true = apply fooling, false = do not apply
bool HostlistCheck(const struct desync_profile *dp, const char *host, bool *excluded, bool bSkipReloadCheck)
bool HostlistCheck(const struct desync_profile *dp, const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck)
{
VPRINT("* hostlist check for profile %d\n",dp->n);
return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, excluded, bSkipReloadCheck);
return HostlistCheck_(&dp->hl_collection, &dp->hl_collection_exclude, host, no_match_subdomains, excluded, bSkipReloadCheck);
}
+1 -1
View File
@@ -9,7 +9,7 @@ bool AppendHostList(hostlist_pool **hostlist, const char *filename);
bool LoadAllHostLists();
bool NonEmptyHostlist(hostlist_pool **hostlist);
// return : true = apply fooling, false = do not apply
bool HostlistCheck(const struct desync_profile *dp,const char *host, bool *excluded, bool bSkipReloadCheck);
bool HostlistCheck(const struct desync_profile *dp,const char *host, bool no_match_subdomains, bool *excluded, bool bSkipReloadCheck);
struct hostlist_file *RegisterHostlist(struct desync_profile *dp, bool bExclude, const char *filename);
bool HostlistsReloadCheckForProfile(const struct desync_profile *dp);
void HostlistsDebug();
+400
View File
@@ -0,0 +1,400 @@
/* The MIT License
Copyright (c) 2018 by Attractive Chaos <attractor@live.co.uk>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
/* An example:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "kavl.h"
struct my_node {
char key;
KAVL_HEAD(struct my_node) head;
};
#define my_cmp(p, q) (((q)->key < (p)->key) - ((p)->key < (q)->key))
KAVL_INIT(my, struct my_node, head, my_cmp)
int main(void) {
const char *str = "MNOLKQOPHIA"; // from wiki, except a duplicate
struct my_node *root = 0;
int i, l = strlen(str);
for (i = 0; i < l; ++i) { // insert in the input order
struct my_node *q, *p = malloc(sizeof(*p));
p->key = str[i];
q = kavl_insert(my, &root, p, 0);
if (p != q) free(p); // if already present, free
}
kavl_itr_t(my) itr;
kavl_itr_first(my, root, &itr); // place at first
do { // traverse
const struct my_node *p = kavl_at(&itr);
putchar(p->key);
free((void*)p); // free node
} while (kavl_itr_next(my, &itr));
putchar('\n');
return 0;
}
*/
#ifndef KAVL_H
#define KAVL_H
#ifdef __STRICT_ANSI__
#define inline __inline__
#endif
#define KAVL_MAX_DEPTH 64
#define kavl_size(head, p) ((p)? (p)->head.size : 0)
#define kavl_size_child(head, q, i) ((q)->head.p[(i)]? (q)->head.p[(i)]->head.size : 0)
#define KAVL_HEAD(__type) \
struct { \
__type *p[2]; \
signed char balance; /* balance factor */ \
unsigned size; /* #elements in subtree */ \
}
#define __KAVL_FIND(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_find_##suf(const __type *root, const __type *x, unsigned *cnt_) { \
const __type *p = root; \
unsigned cnt = 0; \
while (p != 0) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp >= 0) cnt += kavl_size_child(__head, p, 0) + 1; \
if (cmp < 0) p = p->__head.p[0]; \
else if (cmp > 0) p = p->__head.p[1]; \
else break; \
} \
if (cnt_) *cnt_ = cnt; \
return (__type*)p; \
}
#define __KAVL_ROTATE(suf, __type, __head) \
/* one rotation: (a,(b,c)q)p => ((a,b)p,c)q */ \
static inline __type *kavl_rotate1_##suf(__type *p, int dir) { /* dir=0 to left; dir=1 to right */ \
int opp = 1 - dir; /* opposite direction */ \
__type *q = p->__head.p[opp]; \
unsigned size_p = p->__head.size; \
p->__head.size -= q->__head.size - kavl_size_child(__head, q, dir); \
q->__head.size = size_p; \
p->__head.p[opp] = q->__head.p[dir]; \
q->__head.p[dir] = p; \
return q; \
} \
/* two consecutive rotations: (a,((b,c)r,d)q)p => ((a,b)p,(c,d)q)r */ \
static inline __type *kavl_rotate2_##suf(__type *p, int dir) { \
int b1, opp = 1 - dir; \
__type *q = p->__head.p[opp], *r = q->__head.p[dir]; \
unsigned size_x_dir = kavl_size_child(__head, r, dir); \
r->__head.size = p->__head.size; \
p->__head.size -= q->__head.size - size_x_dir; \
q->__head.size -= size_x_dir + 1; \
p->__head.p[opp] = r->__head.p[dir]; \
r->__head.p[dir] = p; \
q->__head.p[dir] = r->__head.p[opp]; \
r->__head.p[opp] = q; \
b1 = dir == 0? +1 : -1; \
if (r->__head.balance == b1) q->__head.balance = 0, p->__head.balance = -b1; \
else if (r->__head.balance == 0) q->__head.balance = p->__head.balance = 0; \
else q->__head.balance = b1, p->__head.balance = 0; \
r->__head.balance = 0; \
return r; \
}
#define __KAVL_INSERT(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_insert_##suf(__type **root_, __type *x, unsigned *cnt_) { \
unsigned char stack[KAVL_MAX_DEPTH]; \
__type *path[KAVL_MAX_DEPTH]; \
__type *bp, *bq; \
__type *p, *q, *r = 0; /* _r_ is potentially the new root */ \
int i, which = 0, top, b1, path_len; \
unsigned cnt = 0; \
bp = *root_, bq = 0; \
/* find the insertion location */ \
for (p = bp, q = bq, top = path_len = 0; p; q = p, p = p->__head.p[which]) { \
int cmp; \
cmp = __cmp(x, p); \
if (cmp >= 0) cnt += kavl_size_child(__head, p, 0) + 1; \
if (cmp == 0) { \
if (cnt_) *cnt_ = cnt; \
return p; \
} \
if (p->__head.balance != 0) \
bq = q, bp = p, top = 0; \
stack[top++] = which = (cmp > 0); \
path[path_len++] = p; \
} \
if (cnt_) *cnt_ = cnt; \
x->__head.balance = 0, x->__head.size = 1, x->__head.p[0] = x->__head.p[1] = 0; \
if (q == 0) *root_ = x; \
else q->__head.p[which] = x; \
if (bp == 0) return x; \
for (i = 0; i < path_len; ++i) ++path[i]->__head.size; \
for (p = bp, top = 0; p != x; p = p->__head.p[stack[top]], ++top) /* update balance factors */ \
if (stack[top] == 0) --p->__head.balance; \
else ++p->__head.balance; \
if (bp->__head.balance > -2 && bp->__head.balance < 2) return x; /* no re-balance needed */ \
/* re-balance */ \
which = (bp->__head.balance < 0); \
b1 = which == 0? +1 : -1; \
q = bp->__head.p[1 - which]; \
if (q->__head.balance == b1) { \
r = kavl_rotate1_##suf(bp, which); \
q->__head.balance = bp->__head.balance = 0; \
} else r = kavl_rotate2_##suf(bp, which); \
if (bq == 0) *root_ = r; \
else bq->__head.p[bp != bq->__head.p[0]] = r; \
return x; \
}
#define __KAVL_ERASE(suf, __scope, __type, __head, __cmp) \
__scope __type *kavl_erase_##suf(__type **root_, const __type *x, unsigned *cnt_) { \
__type *p, *path[KAVL_MAX_DEPTH], fake; \
unsigned char dir[KAVL_MAX_DEPTH]; \
int i, d = 0, cmp; \
unsigned cnt = 0; \
fake.__head.p[0] = *root_, fake.__head.p[1] = 0; \
if (cnt_) *cnt_ = 0; \
if (x) { \
for (cmp = -1, p = &fake; cmp; cmp = __cmp(x, p)) { \
int which = (cmp > 0); \
if (cmp > 0) cnt += kavl_size_child(__head, p, 0) + 1; \
dir[d] = which; \
path[d++] = p; \
p = p->__head.p[which]; \
if (p == 0) { \
if (cnt_) *cnt_ = 0; \
return 0; \
} \
} \
cnt += kavl_size_child(__head, p, 0) + 1; /* because p==x is not counted */ \
} else { \
for (p = &fake, cnt = 1; p; p = p->__head.p[0]) \
dir[d] = 0, path[d++] = p; \
p = path[--d]; \
} \
if (cnt_) *cnt_ = cnt; \
for (i = 1; i < d; ++i) --path[i]->__head.size; \
if (p->__head.p[1] == 0) { /* ((1,.)2,3)4 => (1,3)4; p=2 */ \
path[d-1]->__head.p[dir[d-1]] = p->__head.p[0]; \
} else { \
__type *q = p->__head.p[1]; \
if (q->__head.p[0] == 0) { /* ((1,2)3,4)5 => ((1)2,4)5; p=3 */ \
q->__head.p[0] = p->__head.p[0]; \
q->__head.balance = p->__head.balance; \
path[d-1]->__head.p[dir[d-1]] = q; \
path[d] = q, dir[d++] = 1; \
q->__head.size = p->__head.size - 1; \
} else { /* ((1,((.,2)3,4)5)6,7)8 => ((1,(2,4)5)3,7)8; p=6 */ \
__type *r; \
int e = d++; /* backup _d_ */\
for (;;) { \
dir[d] = 0; \
path[d++] = q; \
r = q->__head.p[0]; \
if (r->__head.p[0] == 0) break; \
q = r; \
} \
r->__head.p[0] = p->__head.p[0]; \
q->__head.p[0] = r->__head.p[1]; \
r->__head.p[1] = p->__head.p[1]; \
r->__head.balance = p->__head.balance; \
path[e-1]->__head.p[dir[e-1]] = r; \
path[e] = r, dir[e] = 1; \
for (i = e + 1; i < d; ++i) --path[i]->__head.size; \
r->__head.size = p->__head.size - 1; \
} \
} \
while (--d > 0) { \
__type *q = path[d]; \
int which, other, b1 = 1, b2 = 2; \
which = dir[d], other = 1 - which; \
if (which) b1 = -b1, b2 = -b2; \
q->__head.balance += b1; \
if (q->__head.balance == b1) break; \
else if (q->__head.balance == b2) { \
__type *r = q->__head.p[other]; \
if (r->__head.balance == -b1) { \
path[d-1]->__head.p[dir[d-1]] = kavl_rotate2_##suf(q, which); \
} else { \
path[d-1]->__head.p[dir[d-1]] = kavl_rotate1_##suf(q, which); \
if (r->__head.balance == 0) { \
r->__head.balance = -b1; \
q->__head.balance = b1; \
break; \
} else r->__head.balance = q->__head.balance = 0; \
} \
} \
} \
*root_ = fake.__head.p[0]; \
return p; \
}
#define kavl_free(__type, __head, __root, __free) do { \
__type *_p, *_q; \
for (_p = __root; _p; _p = _q) { \
if (_p->__head.p[0] == 0) { \
_q = _p->__head.p[1]; \
__free(_p); \
} else { \
_q = _p->__head.p[0]; \
_p->__head.p[0] = _q->__head.p[1]; \
_q->__head.p[1] = _p; \
} \
} \
} while (0)
#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 */ \
}; \
__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; \
cmp = __cmp(x, p); \
if (cmp < 0) *++itr->top = p, 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; \
} \
__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]) \
*++itr->top = p; \
if (itr->top < itr->stack) return 0; \
itr->right = (*itr->top)->__head.p[1]; \
return 1; \
} \
}
/**
* Insert a node to the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param proot pointer to the root of the tree (in/out: root may change)
* @param x node to insert (in)
* @param cnt number of nodes smaller than or equal to _x_; can be NULL (out)
*
* @return _x_ if not present in the tree, or the node equal to x.
*/
#define kavl_insert(suf, proot, x, cnt) kavl_insert_##suf(proot, x, cnt)
/**
* Find a node in the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param x node value to find (in)
* @param cnt number of nodes smaller than or equal to _x_; can be NULL (out)
*
* @return node equal to _x_ if present, or NULL if absent
*/
#define kavl_find(suf, root, x, cnt) kavl_find_##suf(root, x, cnt)
/**
* Delete a node from the tree
*
* @param suf name suffix used in KAVL_INIT()
* @param proot pointer to the root of the tree (in/out: root may change)
* @param x node value to delete; if NULL, delete the first node (in)
*
* @return node removed from the tree if present, or NULL if absent
*/
#define kavl_erase(suf, proot, x, cnt) kavl_erase_##suf(proot, x, cnt)
#define kavl_erase_first(suf, proot) kavl_erase_##suf(proot, 0, 0)
#define kavl_itr_t(suf) struct kavl_itr_##suf
/**
* Place the iterator at the smallest object
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param itr iterator
*/
#define kavl_itr_first(suf, root, itr) kavl_itr_first_##suf(root, itr)
/**
* Place the iterator at the object equal to or greater than the query
*
* @param suf name suffix used in KAVL_INIT()
* @param root root of the tree
* @param x query (in)
* @param itr iterator (out)
*
* @return 1 if find; 0 otherwise. kavl_at(itr) is NULL if and only if query is
* larger than all objects in the tree
*/
#define kavl_itr_find(suf, root, x, itr) kavl_itr_find_##suf(root, x, itr)
/**
* Move to the next object in order
*
* @param itr iterator (modified)
*
* @return 1 if there is a next object; 0 otherwise
*/
#define kavl_itr_next(suf, itr) kavl_itr_next_##suf(itr)
/**
* Return the pointer at the iterator
*
* @param itr iterator
*
* @return pointer if present; NULL otherwise
*/
#define kavl_at(itr) ((itr)->top < (itr)->stack? 0 : *(itr)->top)
#define KAVL_INIT2(suf, __scope, __type, __head, __cmp) \
__KAVL_FIND(suf, __scope, __type, __head, __cmp) \
__KAVL_ROTATE(suf, __type, __head) \
__KAVL_INSERT(suf, __scope, __type, __head, __cmp) \
__KAVL_ERASE(suf, __scope, __type, __head, __cmp) \
__KAVL_ITR(suf, __scope, __type, __head, __cmp)
#define KAVL_INIT(suf, __type, __head, __cmp) \
KAVL_INIT2(suf,, __type, __head, __cmp)
#endif
+73 -11
View File
@@ -2,6 +2,11 @@
#include <stdarg.h>
#include <syslog.h>
#include <errno.h>
#ifdef __ANDROID__
#include <android/log.h>
#endif
const char *progname = "tpws";
int DLOG_FILE(FILE *F, const char *format, va_list args)
{
@@ -25,18 +30,47 @@ int DLOG_FILENAME(const char *filename, const char *format, va_list args)
return r;
}
static char syslog_buf[1024];
static size_t syslog_buf_sz=0;
static void syslog_buffered(int priority, const char *format, va_list args)
typedef void (*f_log_function)(int priority, const char *line);
static char log_buf[1024];
static size_t log_buf_sz=0;
static void syslog_log_function(int priority, const char *line)
{
if (vsnprintf(syslog_buf+syslog_buf_sz,sizeof(syslog_buf)-syslog_buf_sz,format,args)>0)
syslog(priority,"%s",log_buf);
}
#ifdef __ANDROID__
static enum android_LogPriority syslog_priority_to_android(int priority)
{
enum android_LogPriority ap;
switch(priority)
{
syslog_buf_sz=strlen(syslog_buf);
case LOG_INFO:
case LOG_NOTICE: ap=ANDROID_LOG_INFO; break;
case LOG_ERR: ap=ANDROID_LOG_ERROR; break;
case LOG_WARNING: ap=ANDROID_LOG_WARN; break;
case LOG_EMERG:
case LOG_ALERT:
case LOG_CRIT: ap=ANDROID_LOG_FATAL; break;
case LOG_DEBUG: ap=ANDROID_LOG_DEBUG; break;
default: ap=ANDROID_LOG_UNKNOWN;
}
return ap;
}
static void android_log_function(int priority, const char *line)
{
__android_log_print(syslog_priority_to_android(priority), progname, "%s", line);
}
#endif
static void log_buffered(f_log_function log_function, int syslog_priority, const char *format, va_list args)
{
if (vsnprintf(log_buf+log_buf_sz,sizeof(log_buf)-log_buf_sz,format,args)>0)
{
log_buf_sz=strlen(log_buf);
// log when buffer is full or buffer ends with \n
if (syslog_buf_sz>=(sizeof(syslog_buf)-1) || (syslog_buf_sz && syslog_buf[syslog_buf_sz-1]=='\n'))
if (log_buf_sz>=(sizeof(log_buf)-1) || (log_buf_sz && log_buf[log_buf_sz-1]=='\n'))
{
syslog(priority,"%s",syslog_buf);
syslog_buf_sz = 0;
log_function(syslog_priority,log_buf);
log_buf_sz = 0;
}
}
}
@@ -64,9 +98,16 @@ static int DLOG_VA(const char *format, int syslog_priority, bool condup, int lev
break;
case LOG_TARGET_SYSLOG:
// skip newlines
syslog_buffered(syslog_priority,format,args);
log_buffered(syslog_log_function,syslog_priority,format,args);
r = 1;
break;
#ifdef __ANDROID__
case LOG_TARGET_ANDROID:
// skip newlines
log_buffered(android_log_function,syslog_priority,format,args);
r = 1;
break;
#endif
default:
break;
}
@@ -178,14 +219,14 @@ struct desync_profile_list *dp_list_add(struct desync_profile_list_head *head)
dp_init(&entry->dp);
// add to the tail
struct desync_profile_list *dpn,*dpl=LIST_FIRST(&params.desync_profiles);
struct desync_profile_list *dpn,*dpl=LIST_FIRST(head);
if (dpl)
{
while ((dpn=LIST_NEXT(dpl,next))) dpl = dpn;
LIST_INSERT_AFTER(dpl, entry, next);
}
else
LIST_INSERT_HEAD(&params.desync_profiles, entry, next);
LIST_INSERT_HEAD(head, entry, next);
return entry;
}
@@ -217,3 +258,24 @@ void dp_list_destroy(struct desync_profile_list_head *head)
dp_entry_destroy(entry);
}
}
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
void cleanup_args(struct params_s *params)
{
wordfree(&params->wexp);
}
#endif
void cleanup_params(struct params_s *params)
{
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
cleanup_args(params);
#endif
dp_list_destroy(&params->desync_profiles);
hostlist_files_destroy(&params->hostlists);
ipset_files_destroy(&params->ipsets);
ipcacheDestroy(&params->ipcache);
free(params->user); params->user=NULL;
}
+10 -3
View File
@@ -11,6 +11,7 @@
#include <wordexp.h>
#endif
#include "tpws.h"
#include "pools.h"
#include "helpers.h"
@@ -38,7 +39,7 @@ struct bind_s
#define MAX_SPLITS 16
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG };
enum log_target { LOG_TARGET_CONSOLE=0, LOG_TARGET_FILE, LOG_TARGET_SYSLOG, LOG_TARGET_ANDROID };
struct desync_profile
{
@@ -73,7 +74,7 @@ struct desync_profile
struct hostlist_collection_head hl_collection, hl_collection_exclude;
// pointer to autohostlist. NULL if no autohostlist for the profile.
struct hostlist_file *hostlist_auto;
int hostlist_auto_fail_threshold, hostlist_auto_fail_time, hostlist_auto_retrans_threshold;
int hostlist_auto_fail_threshold, hostlist_auto_fail_time;
hostfail_pool *hostlist_auto_fail_counters;
};
@@ -116,8 +117,9 @@ struct params_s
bool fix_seg_avail;
bool no_resolve;
bool skip_nodelay;
bool droproot;
bool daemon;
bool droproot;
char *user;
uid_t uid;
gid_t gid[MAX_GIDS];
int gid_count;
@@ -153,6 +155,11 @@ struct params_s
};
extern struct params_s params;
extern const char *progname;
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
void cleanup_args(struct params_s *params);
#endif
void cleanup_params(struct params_s *params);
int DLOG(const char *format, int level, ...);
int DLOG_CONDUP(const char *format, ...);
+134 -108
View File
@@ -25,7 +25,7 @@
memcpy(elem->str, keystr, keystr_len); \
elem->str[keystr_len] = 0; \
oom = false; \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, strlen(elem->str), elem); \
HASH_ADD_KEYPTR(hh, *ppool, elem->str, keystr_len, elem); \
if (oom) \
{ \
free(elem->str); \
@@ -33,9 +33,12 @@
return false; \
}
#define ADD_HOSTLIST_POOL(etype, ppool, keystr, keystr_len, flg) \
ADD_STR_POOL(etype,ppool,keystr,keystr_len); \
elem->flags = flg;
etype *elem_find; \
HASH_FIND(hh, *ppool, keystr, keystr_len, elem_find); \
if (!elem_find) { \
ADD_STR_POOL(etype,ppool,keystr,keystr_len); \
elem->flags = flg; \
}
#undef uthash_nonfatal_oom
#define uthash_nonfatal_oom(elt) ut_oom_recover(elt)
@@ -95,6 +98,7 @@ hostfail_pool *HostFailPoolFind(hostfail_pool *p,const char *s)
}
void HostFailPoolDel(hostfail_pool **p, hostfail_pool *elem)
{
free(elem->str);
HASH_DEL(*p, elem);
free(elem);
}
@@ -105,11 +109,7 @@ void HostFailPoolPurge(hostfail_pool **pp)
HASH_ITER(hh, *pp, elem, tmp)
{
if (now >= elem->expire)
{
free(elem->str);
HASH_DEL(*pp, elem);
free(elem);
}
HostFailPoolDel(pp, elem);
}
}
static time_t host_fail_purge_prev=0;
@@ -260,121 +260,146 @@ bool hostlist_collection_is_empty(const struct hostlist_collection_head *head)
}
void ipset4Destroy(ipset4 **ipset)
static int kavl_bit_cmp(const struct kavl_bit_elem *p, const struct kavl_bit_elem *q)
{
ipset4 *elem, *tmp;
HASH_ITER(hh, *ipset, elem, tmp)
unsigned int bitlen = q->bitlen < p->bitlen ? q->bitlen : p->bitlen;
unsigned int df = bitlen & 7, bytes = bitlen >> 3;
int cmp = memcmp(p->data, q->data, bytes);
if (cmp || !df) return cmp;
uint8_t c1 = p->data[bytes] >> (8 - df);
uint8_t c2 = q->data[bytes] >> (8 - df);
return c1<c2 ? -1 : c1==c2 ? 0 : 1;
}
KAVL_INIT(kavl_bit, struct kavl_bit_elem, head, kavl_bit_cmp)
static void kavl_bit_destroy_elem(struct kavl_bit_elem *e)
{
if (e)
{
HASH_DEL(*ipset, elem);
free(elem);
free(e->data);
free(e);
}
}
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen)
void kavl_bit_delete(struct kavl_bit_elem **hdr, const void *data, unsigned int bitlen)
{
uint32_t ip = ntohl(a->s_addr);
struct cidr4 cidr;
ipset4 *ips_found;
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
do
{
cidr.preflen--;
cidr.addr.s_addr = htonl(ip & mask_from_preflen(cidr.preflen));
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
if (ips_found) return true;
} while(cidr.preflen);
return false;
struct kavl_bit_elem temp = {
.bitlen = bitlen, .data = (uint8_t*)data
};
kavl_bit_destroy_elem(kavl_erase(kavl_bit, hdr, &temp, 0));
}
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen)
void kavl_bit_destroy(struct kavl_bit_elem **hdr)
{
while (*hdr)
{
struct kavl_bit_elem *e = kavl_erase_first(kavl_bit, hdr);
if (!e) break;
kavl_bit_destroy_elem(e);
}
free(*hdr);
}
struct kavl_bit_elem *kavl_bit_add(struct kavl_bit_elem **hdr, void *data, unsigned int bitlen, size_t struct_size)
{
if (!struct_size) struct_size=sizeof(struct kavl_bit_elem);
struct kavl_bit_elem *v, *e = calloc(1, struct_size);
if (!e) return 0;
e->bitlen = bitlen;
e->data = data;
v = kavl_insert(kavl_bit, hdr, e, 0);
while (e != v && e->bitlen < v->bitlen)
{
kavl_bit_delete(hdr, v->data, v->bitlen);
v = kavl_insert(kavl_bit, hdr, e, 0);
}
if (e != v) kavl_bit_destroy_elem(e);
return v;
}
struct kavl_bit_elem *kavl_bit_get(const struct kavl_bit_elem *hdr, const void *data, unsigned int bitlen)
{
struct kavl_bit_elem temp = {
.bitlen = bitlen, .data = (uint8_t*)data
};
return kavl_find(kavl_bit, hdr, &temp, 0);
}
static bool ipset_kavl_add(struct kavl_bit_elem **ipset, const void *a, uint8_t preflen)
{
uint8_t bytelen = (preflen+7)>>3;
uint8_t *abuf = malloc(bytelen);
if (!abuf) return false;
memcpy(abuf,a,bytelen);
if (!kavl_bit_add(ipset,abuf,preflen,0))
{
free(abuf);
return false;
}
return true;
}
bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen)
{
return !!kavl_bit_get(ipset,a,preflen);
}
bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen)
{
if (preflen>32) return false;
// avoid dups
if (ipset4Check(*ipset, a, preflen)) return true; // already included
struct ipset4 *entry = calloc(1,sizeof(ipset4));
if (!entry) return false;
entry->cidr.addr.s_addr = htonl(ntohl(a->s_addr) & mask_from_preflen(preflen));
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
return ipset_kavl_add(ipset,a,preflen);
}
void ipset4Print(ipset4 *ipset)
void ipset4Print(struct kavl_bit_elem *ipset)
{
ipset4 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr4(&ips->cidr);
printf("\n");
}
}
if (!ipset) return;
void ipset6Destroy(ipset6 **ipset)
{
ipset6 *elem, *tmp;
HASH_ITER(hh, *ipset, elem, tmp)
{
HASH_DEL(*ipset, elem);
free(elem);
}
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen)
{
struct cidr6 cidr;
ipset6 *ips_found;
// zero alignment bytes
memset(&cidr,0,sizeof(cidr));
cidr.preflen = preflen+1;
struct cidr4 c;
const struct kavl_bit_elem *elem;
kavl_itr_t(kavl_bit) itr;
kavl_itr_first(kavl_bit, ipset, &itr);
do
{
cidr.preflen--;
ip6_and(a, mask_from_preflen6(cidr.preflen), &cidr.addr);
HASH_FIND(hh, ipset, &cidr, sizeof(cidr), ips_found);
if (ips_found) return true;
} while(cidr.preflen);
return false;
}
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen)
{
if (preflen>128) return false;
// avoid dups
if (ipset6Check(*ipset, a, preflen)) return true; // already included
struct ipset6 *entry = calloc(1,sizeof(ipset6));
if (!entry) return false;
ip6_and(a, mask_from_preflen6(preflen), &entry->cidr.addr);
entry->cidr.preflen = preflen;
oom = false;
HASH_ADD(hh, *ipset, cidr, sizeof(entry->cidr), entry);
if (oom) { free(entry); return false; }
return true;
}
void ipset6Print(ipset6 *ipset)
{
ipset6 *ips, *tmp;
HASH_ITER(hh, ipset , ips, tmp)
{
print_cidr6(&ips->cidr);
elem = kavl_at(&itr);
c.preflen = elem->bitlen;
expand_bits(&c.addr, elem->data, elem->bitlen, sizeof(c.addr));
print_cidr4(&c);
printf("\n");
}
while (kavl_itr_next(kavl_bit, &itr));
}
bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen)
{
return !!kavl_bit_get(ipset,a,preflen);
}
bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen)
{
if (preflen>128) return false;
return ipset_kavl_add(ipset,a,preflen);
}
void ipset6Print(struct kavl_bit_elem *ipset)
{
if (!ipset) return;
struct cidr6 c;
const struct kavl_bit_elem *elem;
kavl_itr_t(kavl_bit) itr;
kavl_itr_first(kavl_bit, ipset, &itr);
do
{
elem = kavl_at(&itr);
c.preflen = elem->bitlen;
expand_bits(&c.addr, elem->data, elem->bitlen, sizeof(c.addr));
print_cidr6(&c);
printf("\n");
}
while (kavl_itr_next(kavl_bit, &itr));
}
void ipsetDestroy(ipset *ipset)
{
ipset4Destroy(&ipset->ips4);
ipset6Destroy(&ipset->ips6);
kavl_bit_destroy(&ipset->ips4);
kavl_bit_destroy(&ipset->ips6);
}
void ipsetPrint(ipset *ipset)
{
@@ -520,7 +545,7 @@ bool port_filters_deny_if_empty(struct port_filters_head *head)
}
struct blob_item *blob_collection_add(struct blob_collection_head *head)
{
struct blob_item *entry = calloc(1,sizeof(struct blob_item));
@@ -591,6 +616,7 @@ static void ipcache_item_init(ip_cache_item *item)
{
ipcache_item_touch(item);
item->hostname = NULL;
item->hostname_is_ip = false;
}
static void ipcache_item_destroy(ip_cache_item *item)
{
@@ -650,7 +676,7 @@ static void ipcache4Print(ip_cache4 *ipcache)
{
*s_ip=0;
inet_ntop(AF_INET, &ipc->key.addr, s_ip, sizeof(s_ip));
printf("%s : hostname=%s now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last));
printf("%s : hostname=%s hostname_is_ip=%u now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", ipc->data.hostname_is_ip, (unsigned long long)(now-ipc->data.last));
}
}
@@ -707,7 +733,7 @@ static void ipcache6Print(ip_cache6 *ipcache)
{
*s_ip=0;
inet_ntop(AF_INET6, &ipc->key.addr, s_ip, sizeof(s_ip));
printf("%s : hostname=%s now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", (unsigned long long)(now-ipc->data.last));
printf("%s : hostname=%s hostname_is_ip=%u now=last+%llu\n", s_ip, ipc->data.hostname ? ipc->data.hostname : "", ipc->data.hostname_is_ip, (unsigned long long)(now-ipc->data.last));
}
}
+24 -20
View File
@@ -13,6 +13,8 @@
#define HASH_FUNCTION HASH_BER
#include "uthash.h"
#include "kavl.h"
#define HOSTLIST_POOL_FLAG_STRICT_MATCH 1
typedef struct hostlist_pool {
@@ -76,39 +78,40 @@ struct hostlist_item *hostlist_collection_search(struct hostlist_collection_head
bool hostlist_collection_is_empty(const struct hostlist_collection_head *head);
typedef struct ipset4 {
struct cidr4 cidr; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} ipset4;
typedef struct ipset6 {
struct cidr6 cidr; /* key */
UT_hash_handle hh; /* makes this structure hashable */
} ipset6;
struct kavl_bit_elem
{
unsigned int bitlen;
uint8_t *data;
KAVL_HEAD(struct kavl_bit_elem) head;
};
struct kavl_bit_elem *kavl_bit_get(const struct kavl_bit_elem *hdr, const void *data, unsigned int bitlen);
struct kavl_bit_elem *kavl_bit_add(struct kavl_bit_elem **hdr, void *data, unsigned int bitlen, size_t struct_size);
void kavl_bit_delete(struct kavl_bit_elem **hdr, const void *data, unsigned int bitlen);
void kavl_bit_destroy(struct kavl_bit_elem **hdr);
// combined ipset ipv4 and ipv6
typedef struct ipset {
ipset4 *ips4;
ipset6 *ips6;
struct kavl_bit_elem *ips4,*ips6;
} ipset;
#define IPSET_EMPTY(ips) (!(ips)->ips4 && !(ips)->ips6)
void ipset4Destroy(ipset4 **ipset);
bool ipset4Add(ipset4 **ipset, const struct in_addr *a, uint8_t preflen);
static inline bool ipset4AddCidr(ipset4 **ipset, const struct cidr4 *cidr)
bool ipset4Add(struct kavl_bit_elem **ipset, const struct in_addr *a, uint8_t preflen);
static inline bool ipset4AddCidr(struct kavl_bit_elem **ipset, const struct cidr4 *cidr)
{
return ipset4Add(ipset,&cidr->addr,cidr->preflen);
}
bool ipset4Check(ipset4 *ipset, const struct in_addr *a, uint8_t preflen);
void ipset4Print(ipset4 *ipset);
bool ipset4Check(const struct kavl_bit_elem *ipset, const struct in_addr *a, uint8_t preflen);
void ipset4Print(struct kavl_bit_elem *ipset);
void ipset6Destroy(ipset6 **ipset);
bool ipset6Add(ipset6 **ipset, const struct in6_addr *a, uint8_t preflen);
static inline bool ipset6AddCidr(ipset6 **ipset, const struct cidr6 *cidr)
bool ipset6Add(struct kavl_bit_elem **ipset, const struct in6_addr *a, uint8_t preflen);
static inline bool ipset6AddCidr(struct kavl_bit_elem **ipset, const struct cidr6 *cidr)
{
return ipset6Add(ipset,&cidr->addr,cidr->preflen);
}
bool ipset6Check(ipset6 *ipset, const struct in6_addr *a, uint8_t preflen);
void ipset6Print(ipset6 *ipset);
bool ipset6Check(const struct kavl_bit_elem *ipset, const struct in6_addr *a, uint8_t preflen);
void ipset6Print(struct kavl_bit_elem *ipset);
void ipsetDestroy(ipset *ipset);
void ipsetPrint(ipset *ipset);
@@ -176,6 +179,7 @@ typedef struct ip_cache_item
{
time_t last;
char *hostname;
bool hostname_is_ip;
} ip_cache_item;
typedef struct ip_cache4
{
+17 -5
View File
@@ -269,7 +269,7 @@ bool can_drop_root(void)
#endif
}
bool droproot(uid_t uid, gid_t *gid, int gid_count)
bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count)
{
if (gid_count<1)
{
@@ -283,11 +283,23 @@ bool droproot(uid_t uid, gid_t *gid, int gid_count)
return false;
}
#endif
// drop all SGIDs
if (setgroups(gid_count,gid))
if (user)
{
DLOG_PERROR("setgroups");
return false;
// macos has strange supp gid handling. they cache only 16 groups and fail setgroups if more than 16 gids specified.
// better to leave it to the os
if (initgroups(user,gid[0]))
{
DLOG_PERROR("initgroups");
return false;
}
}
else
{
if (setgroups(gid_count,gid))
{
DLOG_PERROR("setgroups");
return false;
}
}
if (setgid(gid[0]))
{
+28 -1
View File
@@ -20,6 +20,25 @@ bool dropcaps(void);
#define arch_nr (offsetof(struct seccomp_data, arch))
#define syscall_arg(x) (offsetof(struct seccomp_data, args[x]))
#ifndef __AUDIT_ARCH_64BIT
#define __AUDIT_ARCH_64BIT 0x80000000
#endif
#ifndef __AUDIT_ARCH_LE
#define __AUDIT_ARCH_LE 0x40000000
#endif
#ifndef EM_RISCV
#define EM_RISCV 243
#endif
#ifndef AUDIT_ARCH_RISCV64
#define AUDIT_ARCH_RISCV64 (EM_RISCV | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE)
#endif
#ifndef EM_LOONGARCH
#define EM_LOONGARCH 258
#endif
#ifndef AUDIT_ARCH_LOONGARCH64
#define AUDIT_ARCH_LOONGARCH64 (EM_LOONGARCH | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE)
#endif
#if defined(__aarch64__)
# define ARCH_NR AUDIT_ARCH_AARCH64
@@ -74,6 +93,14 @@ bool dropcaps(void);
# define ARCH_NR AUDIT_ARCH_RISCV64
#elif defined(__loongarch__) && __loongarch_grlen == 64
# define ARCH_NR AUDIT_ARCH_LOONGARCH64
#elif defined(__e2k__)
# define ARCH_NR AUDIT_ARCH_E2K
#else
# error "Platform does not support seccomp filter yet"
@@ -84,7 +111,7 @@ bool dropcaps(void);
bool sec_harden(void);
bool can_drop_root();
bool droproot(uid_t uid, gid_t *gid, int gid_count);
bool droproot(uid_t uid, const char *user, const gid_t *gid, int gid_count);
void print_id(void);
void daemonize(void);
bool writepid(const char *filename);
+22 -18
View File
@@ -91,7 +91,7 @@ static void TLSDebug(const uint8_t *tls,size_t sz)
TLSDebugHandshake(tls+5,sz-5);
}
bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname)
bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname, bool hostname_is_ip)
{
if (!params.cache_hostname) return true;
@@ -109,11 +109,12 @@ bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, c
DLOG_ERR("ipcache_put_hostname: out of memory\n");
return false;
}
VPRINT("hostname cached: %s\n", hostname);
ipc->hostname_is_ip = hostname_is_ip;
VPRINT("hostname cached (is_ip=%u): %s\n", hostname_is_ip, hostname);
}
return true;
}
static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr *a6, char *hostname, size_t hostname_buf_len)
static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr *a6, char *hostname, size_t hostname_buf_len, bool *hostname_is_ip)
{
if (!params.cache_hostname)
{
@@ -128,15 +129,16 @@ static bool ipcache_get_hostname(const struct in_addr *a4, const struct in6_addr
}
if (ipc->hostname)
{
VPRINT("got cached hostname: %s\n", ipc->hostname);
VPRINT("got cached hostname (is_ip=%u): %s\n", ipc->hostname_is_ip, ipc->hostname);
snprintf(hostname,hostname_buf_len,"%s",ipc->hostname);
if (hostname_is_ip) *hostname_is_ip = ipc->hostname_is_ip;
}
else
*hostname = 0;
return true;
}
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, const char *hostname, bool bNoSubdom, t_l7proto l7proto)
{
bool bHostlistsEmpty;
@@ -167,11 +169,11 @@ static bool dp_match(struct desync_profile *dp, const struct sockaddr *dest, con
return true;
else if (hostname)
// if hostlists are present profile matches only if hostname is known and satisfy profile hostlists
return HostlistCheck(dp, hostname, NULL, true);
return HostlistCheck(dp, hostname, bNoSubdom, NULL, true);
return false;
}
static struct desync_profile *dp_find(struct desync_profile_list_head *head, const struct sockaddr *dest, const char *hostname, t_l7proto l7proto)
static struct desync_profile *dp_find(struct desync_profile_list_head *head, const struct sockaddr *dest, const char *hostname, bool bNoSubdom, t_l7proto l7proto)
{
struct desync_profile_list *dpl;
if (params.debug)
@@ -182,7 +184,7 @@ static struct desync_profile *dp_find(struct desync_profile_list_head *head, con
}
LIST_FOREACH(dpl, head, next)
{
if (dp_match(&dpl->dp,dest,hostname,l7proto))
if (dp_match(&dpl->dp,dest,hostname,bNoSubdom,l7proto))
{
VPRINT("desync profile %d matches\n",dpl->dp.n);
return &dpl->dp;
@@ -198,11 +200,11 @@ void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest)
if (!ctrack->hostname)
{
char host[256];
if (ipcache_get_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , host, sizeof(host)) && *host)
if (ipcache_get_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , host, sizeof(host), &ctrack->hostname_is_ip) && *host)
if (!(ctrack->hostname=strdup(host)))
DLOG_ERR("hostname dup : out of memory");
}
ctrack->dp = dp_find(&params.desync_profiles, dest, ctrack->hostname, ctrack->l7proto);
ctrack->dp = dp_find(&params.desync_profiles, dest, ctrack->hostname, ctrack->hostname_is_ip, ctrack->l7proto);
}
@@ -213,7 +215,7 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
uint8_t *p, *pp, *pHost = NULL;
size_t method_len = 0, pos, tpos, orig_size=*size;
const char *method;
bool bHaveHost = false;
bool bHaveHost = false, bHostIsIp = false;
char *pc, Host[256];
t_l7proto l7proto;
@@ -271,8 +273,9 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
if (bHaveHost)
{
bHostIsIp = strip_host_to_ip(Host);
VPRINT("request hostname: %s\n", Host);
if (!ipcache_put_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , Host))
if (!ipcache_put_hostname(dest->sa_family==AF_INET ? &((struct sockaddr_in*)dest)->sin_addr : NULL, dest->sa_family==AF_INET6 ? &((struct sockaddr_in6*)dest)->sin6_addr : NULL , Host, bHostIsIp))
DLOG_ERR("ipcache_put_hostname: out of memory");
}
@@ -293,6 +296,7 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
DLOG_ERR("strdup hostname : out of memory\n");
return;
}
ctrack->hostname_is_ip = bHostIsIp;
ctrack->hostname_discovered = true;
}
@@ -312,7 +316,7 @@ void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,
if (bHaveHost && !ctrack->b_host_checked)
{
bool bHostExcluded;
ctrack->b_host_matches = HostlistCheck(ctrack->dp, Host, &bHostExcluded, false);
ctrack->b_host_matches = HostlistCheck(ctrack->dp, Host, bHostIsIp, &bHostExcluded, false);
ctrack->b_host_checked = true;
if (!ctrack->b_host_matches)
ctrack->b_ah_check = !bHostExcluded;
@@ -542,7 +546,7 @@ static void auto_hostlist_reset_fail_counter(struct desync_profile *dp, const ch
}
}
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, const char *client_ip_port, t_l7proto l7proto)
static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname, bool bNoSubdom, const char *client_ip_port, t_l7proto l7proto)
{
hostfail_pool *fail_counter;
@@ -566,7 +570,7 @@ static void auto_hostlist_failed(struct desync_profile *dp, const char *hostname
VPRINT("auto hostlist (profile %d) : rechecking %s to avoid duplicates\n", dp->n, hostname);
bool bExcluded=false;
if (!HostlistCheck(dp, hostname, &bExcluded, false) && !bExcluded)
if (!HostlistCheck(dp, hostname, bNoSubdom, &bExcluded, false) && !bExcluded)
{
VPRINT("auto hostlist (profile %d) : adding %s to %s\n", dp->n, hostname, dp->hostlist_auto->filename);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : adding to %s", hostname, dp->n, client_ip_port, l7proto_str(l7proto), dp->hostlist_auto->filename);
@@ -626,7 +630,7 @@ void tamper_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment
// received not http reply. do not monitor this connection anymore
VPRINT("incoming unknown HTTP data detected for hostname %s\n", ctrack->hostname);
}
if (bFail) auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
if (bFail) auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
}
if (!bFail) auto_hostlist_reset_fail_counter(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
}
@@ -651,7 +655,7 @@ void rst_in(t_ctrack *ctrack, const struct sockaddr *client)
{
VPRINT("incoming RST detected for hostname %s\n", ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : incoming RST", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
}
}
}
@@ -674,7 +678,7 @@ void hup_out(t_ctrack *ctrack, const struct sockaddr *client)
// local leg dropped connection after first request. probably due to timeout.
VPRINT("local leg closed connection after first request (timeout ?). hostname: %s\n", ctrack->hostname);
HOSTLIST_DEBUGLOG_APPEND("%s : profile %d : client %s : proto %s : client closed connection without server reply", ctrack->hostname, ctrack->dp->n, client_ip_port, l7proto_str(ctrack->l7proto));
auto_hostlist_failed(ctrack->dp, ctrack->hostname, client_ip_port, ctrack->l7proto);
auto_hostlist_failed(ctrack->dp, ctrack->hostname, ctrack->hostname_is_ip, client_ip_port, ctrack->l7proto);
}
}
}
+2 -1
View File
@@ -16,12 +16,13 @@ typedef struct
bool bTamperInCutoff;
bool b_host_checked,b_host_matches,b_ah_check;
bool hostname_discovered;
bool hostname_is_ip;
char *hostname;
struct desync_profile *dp; // desync profile cache
} t_ctrack;
void apply_desync_profile(t_ctrack *ctrack, const struct sockaddr *dest);
bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname);
bool ipcache_put_hostname(const struct in_addr *a4, const struct in6_addr *a6, const char *hostname, bool hostname_is_ip);
void tamper_out(t_ctrack *ctrack, const struct sockaddr *dest, uint8_t *segment,size_t segment_buffer_size,size_t *size, size_t *multisplit_pos, int *multisplit_count, uint8_t *split_flags);
void tamper_in(t_ctrack *ctrack, const struct sockaddr *client, uint8_t *segment,size_t segment_buffer_size,size_t *size);
+49 -47
View File
@@ -216,7 +216,7 @@ static void exithelp(void)
" --pidfile=<filename>\t\t\t; write pid to file\n"
" --user=<username>\t\t\t; drop root privs\n"
" --uid=uid[:gid1,gid2,...]\t\t; drop root privs\n"
#if defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__OpenBSD__)
" --enable-pf\t\t\t\t; enable PF redirector support. required in FreeBSD when used with PF firewall.\n"
#endif
#if defined(__linux__)
@@ -224,7 +224,11 @@ static void exithelp(void)
#endif
" --ipcache-lifetime=<int>\t\t; time in seconds to keep cached domain name (default %u). 0 = no expiration\n"
" --ipcache-hostname=[0|1]\t\t; 1 or no argument enables ip->hostname caching\n"
#ifdef __ANDROID__
" --debug=0|1|2|syslog|android|@<filename> ; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n"
#else
" --debug=0|1|2|syslog|@<filename>\t; 1 and 2 means log to console and set debug level. for other targets use --debug-level.\n"
#endif
" --debug-level=0|1|2\t\t\t; specify debug level\n"
" --dry-run\t\t\t\t; verify parameters and exit with code 0 if successful\n"
" --version\t\t\t\t; print version and exit\n"
@@ -286,32 +290,14 @@ static void exithelp(void)
);
exit(1);
}
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
static void cleanup_args()
{
wordfree(&params.wexp);
}
#endif
static void cleanup_params(void)
{
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
cleanup_args();
#endif
dp_list_destroy(&params.desync_profiles);
hostlist_files_destroy(&params.hostlists);
ipset_files_destroy(&params.ipsets);
ipcacheDestroy(&params.ipcache);
}
static void exithelp_clean(void)
{
cleanup_params();
cleanup_params(&params);
exithelp();
}
static void exit_clean(int code)
{
cleanup_params();
cleanup_params(&params);
exit(code);
}
static void nextbind_clean(void)
@@ -725,7 +711,7 @@ enum opt_indices {
IDX_IPSET_EXCLUDE,
IDX_IPSET_EXCLUDE_IP,
#if defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__OpenBSD__)
IDX_ENABLE_PF,
#elif defined(__APPLE__)
IDX_LOCAL_TCP_USER_TIMEOUT,
@@ -818,7 +804,7 @@ static const struct option long_options[] = {
[IDX_IPSET_EXCLUDE] = {"ipset-exclude", required_argument, 0, 0},
[IDX_IPSET_EXCLUDE_IP] = {"ipset-exclude-ip", required_argument, 0, 0},
#if defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__OpenBSD__)
[IDX_ENABLE_PF] = {"enable-pf", no_argument, 0, 0},
#elif defined(__APPLE__)
[IDX_LOCAL_TCP_USER_TIMEOUT] = {"local-tcp-user-timeout", required_argument, 0, 0},
@@ -854,7 +840,7 @@ void parse_params(int argc, char *argv[])
params.tcp_user_timeout_remote = DEFAULT_TCP_USER_TIMEOUT_REMOTE;
#endif
#if defined(__OpenBSD__) || defined(__APPLE__)
#if defined(__APPLE__)
params.pf_enable = true; // OpenBSD and MacOS have no other choice
#endif
@@ -978,6 +964,7 @@ void parse_params(int argc, char *argv[])
break;
case IDX_USER:
{
free(params.user); params.user=NULL;
struct passwd *pwd = getpwnam(optarg);
if (!pwd)
{
@@ -985,27 +972,18 @@ void parse_params(int argc, char *argv[])
exit_clean(1);
}
params.uid = pwd->pw_uid;
params.gid_count=MAX_GIDS;
#ifdef __APPLE__
// silence warning
if (getgrouplist(optarg,pwd->pw_gid,(int*)params.gid,&params.gid_count)<0)
#else
if (getgrouplist(optarg,pwd->pw_gid,params.gid,&params.gid_count)<0)
#endif
params.gid[0]=pwd->pw_gid;
params.gid_count=1;
if (!(params.user=strdup(optarg)))
{
DLOG_ERR("getgrouplist failed. too much groups ?\n");
DLOG_ERR("strdup: out of memory\n");
exit_clean(1);
}
if (!params.gid_count)
{
params.gid[0] = pwd->pw_gid;
params.gid_count = 1;
}
params.droproot = true;
break;
}
case IDX_UID:
params.droproot = true;
free(params.user); params.user=NULL;
if (!parse_uid(optarg,&params.uid,params.gid,&params.gid_count,MAX_GIDS))
{
DLOG_ERR("--uid should be : uid[:gid,gid,...]\n");
@@ -1016,6 +994,7 @@ void parse_params(int argc, char *argv[])
params.gid[0] = 0x7FFFFFFF;
params.gid_count = 1;
}
params.droproot = true;
break;
case IDX_MAXCONN:
params.maxconn = atoi(optarg);
@@ -1294,7 +1273,7 @@ void parse_params(int argc, char *argv[])
params.tamper = true; // need to detect blocks and update autohostlist. cannot just slice.
break;
case IDX_HOSTLIST_AUTO_FAIL_THRESHOLD:
dp->hostlist_auto_fail_threshold = (uint8_t)atoi(optarg);
dp->hostlist_auto_fail_threshold = atoi(optarg);
if (dp->hostlist_auto_fail_threshold<1 || dp->hostlist_auto_fail_threshold>20)
{
DLOG_ERR("auto hostlist fail threshold must be within 1..20\n");
@@ -1302,7 +1281,7 @@ void parse_params(int argc, char *argv[])
}
break;
case IDX_HOSTLIST_AUTO_FAIL_TIME:
dp->hostlist_auto_fail_time = (uint8_t)atoi(optarg);
dp->hostlist_auto_fail_time = atoi(optarg);
if (dp->hostlist_auto_fail_time<1)
{
DLOG_ERR("auto hostlist fail time is not valid\n");
@@ -1345,13 +1324,25 @@ void parse_params(int argc, char *argv[])
{
if (!params.debug) params.debug = 1;
params.debug_target = LOG_TARGET_SYSLOG;
openlog("tpws",LOG_PID,LOG_USER);
openlog(progname,LOG_PID,LOG_USER);
}
else
#ifdef __ANDROID__
else if (!strcmp(optarg,"android"))
{
if (!params.debug) params.debug = 1;
params.debug_target = LOG_TARGET_ANDROID;
}
#endif
else if (optarg[0]>='0' && optarg[0]<='2')
{
params.debug = atoi(optarg);
params.debug_target = LOG_TARGET_CONSOLE;
}
else
{
fprintf(stderr, "invalid debug mode : %s\n", optarg);
exit_clean(1);
}
}
else
{
@@ -1563,7 +1554,7 @@ void parse_params(int argc, char *argv[])
params.tamper = true;
break;
#if defined(__FreeBSD__)
#if defined(__FreeBSD__) || defined(__OpenBSD__)
case IDX_ENABLE_PF:
params.pf_enable = true;
break;
@@ -1711,10 +1702,22 @@ void parse_params(int argc, char *argv[])
#if !defined( __OpenBSD__) && !defined(__ANDROID__)
// do not need args from file anymore
cleanup_args();
cleanup_args(&params);
#endif
if (bDry)
{
if (params.droproot)
{
if (!droproot(params.uid,params.user,params.gid,params.gid_count))
exit_clean(1);
#ifdef __linux__
if (!dropcaps())
exit_clean(1);
#endif
print_id();
if (!test_list_files())
exit_clean(1);
}
DLOG_CONDUP("command line parameters verified\n");
exit_clean(0);
}
@@ -1894,7 +1897,6 @@ int main(int argc, char *argv[])
set_console_io_buffering();
set_env_exedir(argv[0]);
srand(time(NULL));
mask_from_preflen6_prepare();
PRINT_VER;
@@ -2143,7 +2145,7 @@ int main(int argc, char *argv[])
}
set_ulimit();
if (params.droproot && !droproot(params.uid,params.gid,params.gid_count))
if (params.droproot && !droproot(params.uid,params.user,params.gid,params.gid_count))
goto exiterr;
#ifdef __linux__
if (!dropcaps())
@@ -2187,6 +2189,6 @@ exiterr:
if (Fpid) fclose(Fpid);
redir_close();
for(i=0;i<=params.binds_last;i++) if (listen_fd[i]!=-1) close(listen_fd[i]);
cleanup_params();
cleanup_params(&params);
return exit_v;
}
+3 -6
View File
@@ -495,7 +495,7 @@ static bool connect_remote_conn(tproxy_conn_t *conn)
int mss=0;
if (conn->track.hostname)
if (!ipcache_put_hostname(conn->dest.sa_family==AF_INET ? &((struct sockaddr_in*)&conn->dest)->sin_addr : NULL, conn->dest.sa_family==AF_INET6 ? &((struct sockaddr_in6*)&conn->dest)->sin6_addr : NULL , conn->track.hostname))
if (!ipcache_put_hostname(conn->dest.sa_family==AF_INET ? &((struct sockaddr_in*)&conn->dest)->sin_addr : NULL, conn->dest.sa_family==AF_INET6 ? &((struct sockaddr_in6*)&conn->dest)->sin6_addr : NULL , conn->track.hostname, conn->track.hostname_is_ip))
DLOG_ERR("ipcache_put_hostname: out of memory");
apply_desync_profile(&conn->track, (struct sockaddr *)&conn->dest);
@@ -507,7 +507,7 @@ static bool connect_remote_conn(tproxy_conn_t *conn)
if (conn->track.hostname)
{
bool bHostExcluded;
conn->track.b_host_matches = HostlistCheck(conn->track.dp, conn->track.hostname, &bHostExcluded, false);
conn->track.b_host_matches = HostlistCheck(conn->track.dp, conn->track.hostname, conn->track.hostname_is_ip, &bHostExcluded, false);
conn->track.b_host_checked = true;
if (!conn->track.b_host_matches)
{
@@ -835,8 +835,6 @@ static bool handle_unsent(tproxy_conn_t *conn)
static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn_list)
{
int remote_fd;
if (params.debug>=1)
{
char ip_port[48];
@@ -850,9 +848,8 @@ static bool proxy_mode_connect_remote(tproxy_conn_t *conn, struct tailhead *conn
return false;
}
if (!(conn->partner = new_conn(remote_fd, true)))
if (!(conn->partner = new_conn(0, true)))
{
close(remote_fd);
DLOG_ERR("socks out-of-memory (1)\n");
socks_send_rep(conn->socks_ver, conn->fd, S5_REP_GENERAL_FAILURE);
return false;